From c04f619292e13248b5eac368266aee4d54699b51 Mon Sep 17 00:00:00 2001 From: imp Date: Sun, 22 Sep 1996 04:19:27 +0000 Subject: Reviewed by: Bill Fenner Reviewed by: Garrett Wollman Submitted by: Warner Losh 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. --- libexec/tftpd/tftpd.8 | 15 +++++++++++++++ libexec/tftpd/tftpd.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'libexec/tftpd') diff --git a/libexec/tftpd/tftpd.8 b/libexec/tftpd/tftpd.8 index 430c1c4..4a9004d 100644 --- a/libexec/tftpd/tftpd.8 +++ b/libexec/tftpd/tftpd.8 @@ -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 , diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c index 7500abf..9ab7778 100644 --- a/libexec/tftpd/tftpd.c +++ b/libexec/tftpd/tftpd.c @@ -52,6 +52,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; #include #include #include +#include #include #include @@ -68,6 +69,7 @@ static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; #include #include #include +#include #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); -- cgit v1.1