From imp@village.org  Mon Apr 15 17:10:07 1996
Received: from rover.village.org (rover.village.org [204.144.255.49])
          by freefall.freebsd.org (8.7.3/8.7.3) with ESMTP id RAA19235
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 15 Apr 1996 17:10:01 -0700 (PDT)
Received: (from imp@localhost) by rover.village.org (8.7.5/8.6.6) id SAA02721; Mon, 15 Apr 1996 18:09:36 -0600 (MDT)
Message-Id: <199604160009.SAA02721@rover.village.org>
Date: Mon, 15 Apr 1996 18:09:36 -0600 (MDT)
From: Warner Losh <imp@village.org>
Reply-To: imp@village.org
To: FreeBSD-gnats-submit@freebsd.org
Subject: tftpd should support -s
X-Send-Pr-Version: 3.2

>Number:         1145
>Category:       bin
>Synopsis:       tftpd should support -s
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Apr 15 17:20:01 PDT 1996
>Closed-Date:    Tue Sep 24 17:52:28 PDT 1996
>Last-Modified:  Tue Sep 24 17:54:51 PDT 1996
>Originator:     Warner Losh
>Release:        FreeBSD 2.1.0-RELEASE i386
>Organization:
	The village
>Environment:
>Description:

tftpd doesn't support -s.

>How-To-Repeat:
>Fix:

Apply the following patch:


Index: tftpd.8
===================================================================
RCS file: /home/imp/FreeBSD/CVS/src/libexec/tftpd/tftpd.8,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 tftpd.8
--- tftpd.8	1994/05/27 12:39:25	1.1.1.1
+++ tftpd.8	1996/04/15 23:56:55
@@ -42,6 +42,7 @@
 .Nm tftpd
 .Op Fl l
 .Op Fl n
+.Op Fl s Ar directory
 .Op Ar directory ...
 .Sh DESCRIPTION
 .Nm Tftpd
@@ -87,6 +88,15 @@
 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 @@
 .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 ,
Index: tftpd.c
===================================================================
RCS file: /home/imp/FreeBSD/CVS/src/libexec/tftpd/tftpd.c,v
retrieving revision 1.2
diff -u -r1.2 tftpd.c
--- tftpd.c	1995/02/26 23:28:00	1.2
+++ tftpd.c	1996/04/15 23:38:57
@@ -113,9 +113,10 @@
 	register int n;
 	int ch, on;
 	struct sockaddr_in sin;
+	char *chroot_dir = NULL;
 
 	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,10 +124,26 @@
 		case 'n':
 			suppress_naks = 1;
 			break;
+		case 's':
+			chroot_dir = optarg;
+			break;
 		default:
 			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
 		}
 	}
+
+	if (chroot_dir) {
+		if (getuid())
+			syslog(LOG_WARNING, "-s works only when run as root");
+		else {
+			if (chroot(chroot_dir))
+				syslog(LOG_ERR, "chroot: %s",
+				       strerror(errno));
+			chdir( "/" );
+			setuid( 32767 ); /* Revert to running as nobody */
+		}
+	}
+
 	if (optind < argc) {
 		struct dirlist *dirp;
 
@@ -139,6 +156,14 @@
 				dirp++;
 			}
 		}
+	}
+	/* Only allow no d */
+	else if (chroot_dir) {
+		dirs->name = "/";
+		dirs->len = 1;
+	}
+	else {
+		syslog(LOG_WARNING, "Access to theentire system graned");
 	}
 
 	on = 1;
>Release-Note:
>Audit-Trail:

From: Bill Fenner <fenner@parc.xerox.com>
To: imp@village.org
Cc: FreeBSD-gnats-submit@freebsd.org, fenner@parc.xerox.com
Subject: Re: bin/1145: tftpd should support -s 
Date: Tue, 16 Apr 1996 08:53:26 PDT

 In message <199604160009.SAA02721@rover.village.org>you write:
 >+			setuid( 32767 ); /* Revert to running as nobody */
 
 Careful!  On my FreeBSD boxes, nobody is uid 65534.  I think what you really 
 want to do is
 
 			if ((nobody = getpwnam("nobody")) == NULL) {
 				syslog(LOG_ERROR, "nobody: no such user");
 				exit(1);
 			}
 			setuid(nobody->pw_uid);
 
 >+		syslog(LOG_WARNING, "Access to theentire system graned");
 
 I'm not sure that logging a warning is the right thing to do; this opens the 
 door for logfile spamming.  How about just failing to run if no path arguments 
 are specified, and requiring an explicit "/" argument to allow granting access 
 to the entire system?
 
   Bill
 

From: Warner Losh <imp@village.org>
To: Bill Fenner <fenner@parc.xerox.com>
Cc: FreeBSD-gnats-submit@freebsd.org
Subject: Re: bin/1145: tftpd should support -s 
Date: Tue, 16 Apr 1996 14:53:20 -0600

 I've taken Bill's and Garrett's suggestions and made those changes.
 I've also moved the chroot to *AFTER* the recvfrom because if it is
 before and there is a problem with the chroot then inetd would loop
 very quickly...  Here's the whole patch, please ignore the first patch
 I submitted.  Comments?
 
 Warner
 
 Index: tftpd.8
 ===================================================================
 RCS file: /home/imp/FreeBSD/CVS/src/libexec/tftpd/tftpd.8,v
 retrieving revision 1.1.1.1
 diff -u -r1.1.1.1 tftpd.8
 --- tftpd.8	1994/05/27 12:39:25	1.1.1.1
 +++ tftpd.8	1996/04/15 23:56:55
 @@ -42,6 +42,7 @@
  .Nm tftpd
  .Op Fl l
  .Op Fl n
 +.Op Fl s Ar directory
  .Op Ar directory ...
  .Sh DESCRIPTION
  .Nm Tftpd
 @@ -87,6 +88,15 @@
  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 @@
  .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 ,
 Index: tftpd.c
 ===================================================================
 RCS file: /home/imp/FreeBSD/CVS/src/libexec/tftpd/tftpd.c,v
 retrieving revision 1.2
 diff -u -r1.2 tftpd.c
 --- tftpd.c	1995/02/26 23:28:00	1.2
 +++ tftpd.c	1996/04/16 20:47:27
 @@ -52,6 +52,7 @@
  #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 @@
  #include <string.h>
  #include <syslog.h>
  #include <unistd.h>
 +#include <pwd.h>
  
  #include "tftpsubs.h"
  
 @@ -113,9 +115,11 @@
  	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,10 +127,14 @@
  		case 'n':
  			suppress_naks = 1;
  			break;
 +		case 's':
 +			chroot_dir = optarg;
 +			break;
  		default:
  			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
  		}
  	}
 +
  	if (optind < argc) {
  		struct dirlist *dirp;
  
 @@ -140,6 +148,10 @@
  			}
  		}
  	}
 +	else if (chroot_dir) {
 +		dirs->name = "/";
 +		dirs->len = 1;
 +	}
  
  	on = 1;
  	if (ioctl(0, FIONBIO, &on) < 0) {
 @@ -203,6 +215,27 @@
  			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);
State-Changed-From-To: open->closed 
State-Changed-By: wosch 
State-Changed-When: Tue Sep 24 17:52:28 PDT 1996 
State-Changed-Why:  
fixed in tftpd.c, revision 1.3 

>Unformatted:

