forked from mirrors/tftp-hpa-google
Add the -p option for using regular Unix permissions.
This commit is contained in:
parent
93e86de7a2
commit
78fd7348ea
6 changed files with 116 additions and 44 deletions
4
CHANGES
4
CHANGES
|
@ -10,6 +10,10 @@ Changes in 0.27:
|
|||
Allow replacement patterns to include the IP address of the
|
||||
requesting host (\i).
|
||||
|
||||
Allow relying on Unix permissions rather than o+r magic if the
|
||||
-p option is specified. As part of this, set all groups if
|
||||
initgroups() is specified on the platform.
|
||||
|
||||
|
||||
Changes in 0.26:
|
||||
Fix the configuration process so tftpd doesn't end up
|
||||
|
|
4
config.h
4
config.h
|
@ -85,6 +85,10 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GRP_H
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ AC_HEADER_STDC
|
|||
AC_CHECK_HEADERS(inttypes.h)
|
||||
AC_CHECK_HEADERS(stdint.h)
|
||||
PA_CHECK_INTTYPES_H_SANE
|
||||
AC_CHECK_HEADERS(grp.h)
|
||||
AC_CHECK_HEADERS(libgen.h)
|
||||
AC_CHECK_HEADERS(memory.h)
|
||||
AC_CHECK_HEADERS(setjmp.h)
|
||||
|
@ -83,6 +84,8 @@ AC_CHECK_TYPES(u_short)
|
|||
AC_CHECK_TYPES(u_long)
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
AC_SEARCH_LIBS(socket, socket, , [AC_MSG_ERROR(socket library not found)])
|
||||
AC_SEARCH_LIBS(gethostbyname, [nsl resolv], , [AC_MSG_ERROR(gethostbyname not found)])
|
||||
|
@ -91,8 +94,12 @@ AC_SEARCH_LIBS(herror, [nsl resolv], , [AC_MSG_ERROR(herror not found)])
|
|||
|
||||
AC_CHECK_FUNCS(setsid)
|
||||
AC_CHECK_FUNCS(recvmsg)
|
||||
AC_CHECK_FUNCS(ftruncate)
|
||||
AC_CHECK_FUNCS(setreuid)
|
||||
AC_CHECK_FUNCS(setregid)
|
||||
AC_CHECK_FUNCS(initgroups)
|
||||
AC_CHECK_FUNCS(setgroups)
|
||||
|
||||
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
|
||||
AC_CHECK_FUNCS(strtoumax)
|
||||
AC_CHECK_FUNCS(strtoull)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\"----------------------------------------------------------------------- */
|
||||
.TH TFTPD 8 "16 November 2001" "tftp-hpa 0.27-pre1" "UNIX System Manager's Manual"
|
||||
.TH TFTPD 8 "16 November 2001" "tftp-hpa 0.27-pre2" "UNIX System Manager's Manual"
|
||||
.SH NAME
|
||||
.B tftpd
|
||||
\- IPv4 Trivial File Transfer Protocol server
|
||||
|
@ -225,7 +225,7 @@ The IP address of the requesting host, in dotted-quad notation
|
|||
The IP address of the requesting host, in hexadecimal notation
|
||||
(e.g. C00002A9).
|
||||
.TP
|
||||
\fB\\\fP
|
||||
\fB\\\\\fP
|
||||
Literal backslash.
|
||||
.TP
|
||||
\fB\\\fP\fIwhitespace\fP
|
||||
|
|
|
@ -92,7 +92,23 @@ which cannot be easily made to include a directory name in its request.
|
|||
\fB\-u\fP \fIusername\fP
|
||||
Specify the username which
|
||||
.B tftpd
|
||||
will run as; the default is "nobody".
|
||||
will run as; the default is "nobody". The user ID, group ID, and (if
|
||||
possible on the platform) the supplementary group IDs will be set to
|
||||
the ones specified in the system permission database for this
|
||||
username.
|
||||
.TP
|
||||
\fB\-U\fP \fIumask\fP
|
||||
Sets the \fIumask\fP to the specified value. The default is zero
|
||||
if the
|
||||
.B \-p
|
||||
option is not specified, or unchanged if
|
||||
.B \-p is specified.
|
||||
.TP
|
||||
.B \-p
|
||||
Indicate that no permissions checks beyond the normal system-provided
|
||||
permission check for the user specified via the
|
||||
.B \-u
|
||||
option.
|
||||
.TP
|
||||
\fB\-t\fP \fItimeout\fP
|
||||
When run from
|
||||
|
@ -243,9 +259,10 @@ process.
|
|||
The use of TFTP services does not require an account or password on
|
||||
the server system. Due to the lack of authentication information,
|
||||
.B tftpd
|
||||
will allow only publicly readable files (o+r) to be accessed. Files
|
||||
may be written only if they already exist and are publicly writable,
|
||||
unless the
|
||||
will allow only publicly readable files (o+r) to be accessed, unless the
|
||||
.B \-p
|
||||
option is specified. Files may be written only if they already exist
|
||||
and are publicly writable, unless the
|
||||
.B \-c
|
||||
option is specified. Note that this extends the concept of ``public''
|
||||
to include all users on all hosts that can be reached through the
|
||||
|
@ -261,7 +278,7 @@ database for access control information. This may be slow; sites
|
|||
requiring maximum performance may want to compile without this option
|
||||
and rely on firewalling or kernel-based packet filters instead.
|
||||
.PP
|
||||
The server should be set to have the user ID with the lowest possible
|
||||
The server should be set to run as the user with the lowest possible
|
||||
privilege; please see the
|
||||
.B \-u
|
||||
flag.
|
||||
|
@ -304,6 +321,7 @@ added patches by Markus Gutschke and Gero Kulhman.
|
|||
.SH "SEE ALSO"
|
||||
.BR tftp (1),
|
||||
.BR egrep (1),
|
||||
.BR umask (2),
|
||||
.BR hosts_access (5),
|
||||
.BR regex (7),
|
||||
.BR inetd (8).
|
||||
|
|
113
tftpd/tftpd.c
113
tftpd/tftpd.c
|
@ -103,6 +103,7 @@ const char **dirs;
|
|||
|
||||
int secure = 0;
|
||||
int cancreate = 0;
|
||||
int unixperms = 0;
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
|
@ -184,11 +185,13 @@ main(int argc, char **argv)
|
|||
int standalone = 0; /* Standalone (listen) mode */
|
||||
char *address = NULL; /* Address to listen to */
|
||||
pid_t pid;
|
||||
mode_t my_umask = 0;
|
||||
int spec_umask = 0;
|
||||
int c;
|
||||
int setrv;
|
||||
int waittime = 900; /* Default time to wait for a connect*/
|
||||
const char *user = "nobody"; /* Default user */
|
||||
char *p;
|
||||
char *p, *ep;
|
||||
#ifdef WITH_REGEX
|
||||
char *rewrite_file = NULL;
|
||||
#endif
|
||||
|
@ -200,7 +203,7 @@ main(int argc, char **argv)
|
|||
|
||||
openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
|
||||
|
||||
while ((c = getopt(argc, argv, "csvVla:u:r:t:m:")) != -1)
|
||||
while ((c = getopt(argc, argv, "cspvVla:u:U:r:t:m:")) != -1)
|
||||
switch (c) {
|
||||
case 'c':
|
||||
cancreate = 1;
|
||||
|
@ -208,6 +211,9 @@ main(int argc, char **argv)
|
|||
case 's':
|
||||
secure = 1;
|
||||
break;
|
||||
case 'p':
|
||||
unixperms = 1;
|
||||
break;
|
||||
case 'l':
|
||||
standalone = 1;
|
||||
break;
|
||||
|
@ -220,6 +226,14 @@ main(int argc, char **argv)
|
|||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'U':
|
||||
my_umask = strtoul(optarg, &ep, 8);
|
||||
if ( *ep ) {
|
||||
syslog(LOG_ERR, "Invalid umask: %s", optarg);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
spec_umask = 1;
|
||||
break;
|
||||
case 'r':
|
||||
for ( opt = options ; opt->o_opt ; opt++ ) {
|
||||
if ( !strcasecmp(optarg, opt->o_opt) ) {
|
||||
|
@ -280,6 +294,9 @@ main(int argc, char **argv)
|
|||
syslog(LOG_ERR, "no user %s: %m", user);
|
||||
exit(EX_NOUSER);
|
||||
}
|
||||
|
||||
if ( spec_umask || !unixperms )
|
||||
umask(my_umask);
|
||||
|
||||
if (ioctl(fd, FIONBIO, &on) < 0) {
|
||||
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
||||
|
@ -474,13 +491,29 @@ main(int argc, char **argv)
|
|||
exit(EX_IOERR);
|
||||
}
|
||||
|
||||
/* Set up the supplementary group access list if possible */
|
||||
/* /etc/group still need to be accessible at this point */
|
||||
#ifdef HAVE_INITGROUPS
|
||||
setrv = initgroups(user, pw->pw_gid);
|
||||
if ( setrv ) {
|
||||
syslog(LOG_ERR, "cannot set groups for user %s", user);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
#else
|
||||
#ifdef HAVE_SETGROUPS
|
||||
if ( setgroups(0, NULL) ) {
|
||||
syslog(LOG_ERR, "cannot clear group list");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Chroot and drop privileges */
|
||||
|
||||
if (secure && chroot(".")) {
|
||||
syslog(LOG_ERR, "chroot: %m");
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_SETREGID
|
||||
setrv = setregid(pw->pw_gid, pw->pw_gid);
|
||||
#else
|
||||
|
@ -885,47 +918,53 @@ validate_access(char *filename, int mode, struct formats *pf)
|
|||
* We use different a different permissions scheme if `cancreate' is
|
||||
* set.
|
||||
*/
|
||||
wmode = O_TRUNC;
|
||||
if (stat(filename, &stbuf) < 0) {
|
||||
if (!cancreate)
|
||||
return (errno == ENOENT ? ENOTFOUND : EACCESS);
|
||||
else {
|
||||
if ((errno == ENOENT) && (mode != RRQ))
|
||||
wmode |= O_CREAT;
|
||||
else
|
||||
return(EACCESS);
|
||||
wmode = O_WRONLY |
|
||||
(cancreate ? O_CREAT : 0) |
|
||||
(unixperms ? O_TRUNC : 0);
|
||||
|
||||
fd = open(filename, mode == RRQ ? O_RDONLY : wmode, 0666);
|
||||
if (fd < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
return ENOTFOUND;
|
||||
case ENOSPC:
|
||||
return ENOSPACE;
|
||||
case EEXIST:
|
||||
return EEXISTS;
|
||||
default:
|
||||
return EACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if ( fstat(fd, &stbuf) < 0 )
|
||||
exit(EX_OSERR); /* This shouldn't happen */
|
||||
|
||||
if (mode == RRQ) {
|
||||
if ( !unixperms && (stbuf.st_mode & (S_IREAD >> 6)) == 0 )
|
||||
return (EACCESS);
|
||||
tsize = stbuf.st_size;
|
||||
/* We don't know the tsize if conversion is needed */
|
||||
tsize_ok = !pf->f_convert;
|
||||
} else {
|
||||
if (mode == RRQ) {
|
||||
if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
|
||||
if ( !unixperms ) {
|
||||
if ( (stbuf.st_mode & (S_IWRITE >> 6)) == 0 )
|
||||
return (EACCESS);
|
||||
tsize = stbuf.st_size;
|
||||
/* We don't know the tsize if conversion is needed */
|
||||
tsize_ok = !pf->f_convert;
|
||||
} else {
|
||||
if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
|
||||
return (EACCESS);
|
||||
tsize = 0;
|
||||
tsize_ok = 1;
|
||||
|
||||
/* We didn't get to truncate the file at open() time */
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if ( ftruncate(fd, (off_t)0) )
|
||||
return(EACCESS);
|
||||
#endif
|
||||
}
|
||||
tsize = 0;
|
||||
tsize_ok = 1;
|
||||
}
|
||||
fd = open(filename, mode == RRQ ? O_RDONLY : (O_WRONLY|wmode), 0666);
|
||||
if (fd < 0)
|
||||
return (errno + 100);
|
||||
/*
|
||||
* If the file was created, set default permissions.
|
||||
*/
|
||||
if ((wmode & O_CREAT) && fchmod(fd, 0666) < 0) {
|
||||
int serrno = errno;
|
||||
|
||||
close(fd);
|
||||
unlink(filename);
|
||||
|
||||
return (serrno + 100);
|
||||
}
|
||||
|
||||
file = fdopen(fd, (mode == RRQ)? "r":"w");
|
||||
if (file == NULL)
|
||||
return (errno + 100);
|
||||
exit(EX_OSERR); /* Internal error */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue