Reviewed by: Bill Fenner <fennder@parc.xerox.com>

Reviewed by:	Garrett Wollman <wollman@freebsd.org>
Submitted by:	Warner Losh <imp@village.org>
Close PR bin/1145:
	Add -s flag to tftpd.  This enables the so-called secure mode
of tftpd where it chroots to a given directory before allowing access
to the files.  In addition, it runs as nobody when in this mode.
Reviewed a long time ago by Bill and Garrett.  Apply my patch from the
pr, and close the PR.
This commit is contained in:
Warner Losh 1996-09-22 04:19:27 +00:00
parent 6bf3beb134
commit 8ea3178507
2 changed files with 47 additions and 1 deletions

View File

@ -42,6 +42,7 @@ Internet Trivial File Transfer Protocol server
.Nm tftpd
.Op Fl l
.Op Fl n
.Op Fl s Ar directory
.Op Ar directory ...
.Sh DESCRIPTION
.Nm Tftpd
@ -87,6 +88,15 @@ names are prefixed by the one of the given directories.
The given directories are also treated as a search path for
relative filename requests.
.Pp
The chroot option provides additional security by restricting access
of tftpd to only a chroot'd file system. This is useful when moving
from an OS that supported
.Nm -s
as a boot server. Because chroot is restricted to root, you must run
tftpd as root. However, if you chroot, then
.Nm tftpd
will set its user id to nobody.
.Pp
The options are:
.Bl -tag -width Ds
.It Fl l
@ -95,6 +105,11 @@ Logs all requests using
.It Fl n
Suppresses negative acknowledgement of requests for nonexistent
relative filenames.
.It Fl s Ar directory
Causes tftpd to chroot to
.Pa directory
before accepting commands. In addition, the user id is set to
nobody.
.El
.Sh SEE ALSO
.Xr tftp 1 ,

View File

@ -52,6 +52,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/tftp.h>
@ -68,6 +69,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <pwd.h>
#include "tftpsubs.h"
@ -113,9 +115,11 @@ main(argc, argv)
register int n;
int ch, on;
struct sockaddr_in sin;
char *chroot_dir = NULL;
struct passwd *nobody;
openlog("tftpd", LOG_PID, LOG_FTP);
while ((ch = getopt(argc, argv, "ln")) != EOF) {
while ((ch = getopt(argc, argv, "lns:")) != EOF) {
switch (ch) {
case 'l':
logging = 1;
@ -123,6 +127,9 @@ main(argc, argv)
case 'n':
suppress_naks = 1;
break;
case 's':
chroot_dir = optarg;
break;
default:
syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
}
@ -140,6 +147,10 @@ main(argc, argv)
}
}
}
else if (chroot_dir) {
dirs->name = "/";
dirs->len = 1;
}
on = 1;
if (ioctl(0, FIONBIO, &on) < 0) {
@ -203,6 +214,26 @@ main(argc, argv)
exit(0);
}
}
/*
* Since we exit here, we should do that only after the above
* recvfrom to keep inetd from constantly forking should there
* be a problem. See the above comment about system clogging.
*/
if (chroot_dir) {
/* Must get this before chroot because /etc might go away */
if ((nobody = getpwnam("nobody")) == NULL) {
syslog(LOG_ERR, "nobody: no such user");
exit(1);
}
if (chroot(chroot_dir)) {
syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
exit(1);
}
chdir( "/" );
setuid(nobody->pw_uid);
}
from.sin_family = AF_INET;
alarm(0);
close(0);