Add the -p option for using regular Unix permissions.

This commit is contained in:
hpa 2001-11-17 01:55:08 +00:00
parent 93e86de7a2
commit 78fd7348ea
6 changed files with 116 additions and 44 deletions

View file

@ -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

View file

@ -85,6 +85,10 @@
#endif
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
#include <errno.h>
#include <signal.h>

View file

@ -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)

View file

@ -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

View file

@ -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).

View file

@ -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);
}