[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

in.tftpd: Missing a critical feature



Package: netstd
Version: 3.07-1

(Specifically, in.tftpd)

Hello,

This is going to be a rather long message, so please bear with me.
I'm going to describe a missing feature from Debian's in.tftpd, why we 
need it, and give you a patch to implement it.

Sun's tftpd has an option, -s.  Basically, this option chroot's to the 
specified directory, than set[ug]id's itself to nobody.  After that,
it starts serving files.

Why is this important?  Well, we have a number of NCD X terminals.
These terminals try to get files with absolute pathnames like
/usr/lib/X11/ncd/configs.  The tftp server should really serve this
file from an appropriate subdirectory below the tftpboot directory --
NOT the system's /usr/lib/X11 directory.  That is, the server should
actually hand the client the file
/usr/local/ncdroot/usr/lib/X11/ncd/configs in our case.

The Sun tftpd allows one to start in with "-s /usr/local/ncdroot".
This will chroot and then serve files as normal.  This method doesn't
work with Debian -- any directory specified with Debian's in.tftpd is
only used for permission checking when the client gives an absolute
method.  So all Debian's will do is say that the client has no
permission to access that particular file (it is looking under the
system's /usr/lib/X11 area instead of the tree for the NCD), and
things will fail.  The client cannot be changed to use other files.

The net result is that Debian's tftp renders those clients useless
when they try to boot using it.

I really don't know why there is this omission from Debian's tftp
program.  I have made a patch to add it in, included below.

Sun's manpage describes the -s option as:


     -s   Secure.  When  specified,  the  directory  change  must
          succeed; and the daemon also changes its root directory
          to  homedir.   This  option  is  set  in  the   default
          /etc/inetd.conf file.

          The use of tftp does not require an account or password
          on  the  remote system.  Due to the lack of authentica-
          tion information, tftpd will allow only publicly  read-
          able  files  to be accessed.  Files may be written only
          if they already exist and are publicly writable.  Note:
          this  extends  the  concept  of "public" to include all
          users on all hosts that can be reached through the net-
          work;  this  may not be appropriate on all systems, and
          its implications should be considered  before  enabling
          this service.

Below is my patch to fix the problem.  I was unable to find any
upstream maintainer e-mail; please forward it upstream.

A few notes.  When using -s, in.tftpd must be started as root from
inetd.conf.  It will subsequently change its uid,gid to 65534 (nobody, 
nogroup).  This value is hardcoded.  Should it be?  The root access is 
necessary to be able to call chroot(2).

I have not modified the manpage.  This ought to be done.

One cannot use a line in inetd.conf like
"chroot /usr/local/ncdroot /usr/sbin/in.tftpd " because the system
then looks for the in.tftpd program in
/usr/local/ncdroot/usr/sbin/in.tftpd, and of course doesn't find it.
(Worse -- in some cases it could find a binary for a different
platform.)  So the -s support cannot be emulated by other means.

I would apprreciate it if you would integrate this patch into future
releases.  This will save us the effort of having to patch tftpd each
time netstd (or tftpd, C libraries, or whatever) is updated.  Also,
I'm sure there are others that use the -s in the Sun version.

Here, then, is the patch against tftpd 8.1 in netstd 3.07:

--- tftpd.c.orig	Thu Jun 25 17:26:53 1998
+++ tftpd.c	Thu Jun 25 18:29:55 1998
@@ -47,6 +47,11 @@
  * This version includes many modifications by Jim Guyton
  * <guyton@rand-unix>.
  */
+ 
+/*
+ * -s support added by John Goerzen <jgoerzen@complete.org>
+ *
+ */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -117,9 +122,10 @@
 	register int n;
 	int ch, on;
 	struct sockaddr_in sin;
+	int usingchroot = 0, chrootdirfound = 0, res;
 
 	openlog("tftpd", LOG_PID, LOG_DAEMON);
-	while ((ch = getopt(argc, argv, "ln")) != EOF) {
+	while ((ch = getopt(argc, argv, "lns")) != EOF) {
 		switch (ch) {
 		case 'l':
 			logging = 1;
@@ -127,6 +133,9 @@
 		case 'n':
 			suppress_naks = 1;
 			break;
+		case 's':
+			usingchroot = 1;
+			break;
 		default:
 			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
 		}
@@ -138,11 +147,36 @@
 		for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
 		     optind++) {
 			if (argv[optind][0] == '/') {
-				dirp->name = argv[optind];
-				dirp->len  = strlen(dirp->name);
-				dirp++;
+				if (usingchroot) {
+					if (!chrootdirfound) {
+						res = chroot(argv[optind]);
+						chrootdirfound = 1;
+						setreuid(65534, 65534);
+						setregid(65534, 65534);
+					} else {
+						syslog(LOG_WARNING,
+							"Ignoring extra "
+							"directory %s",
+							argv[optind]);
+					}
+				} else {
+					dirp->name = argv[optind];
+					dirp->len  = strlen(dirp->name);
+					dirp++;
+				}
 			}
 		}
+	}
+	
+	if (usingchroot && (!chrootdirfound)) {
+		syslog(LOG_NOTICE, "-s specified but no valid directory "
+				   "found; aborting.");
+		exit(21);
+	}
+	
+	if (res == -1) {
+		syslog(LOG_NOTICE, "error: chroot failed; aborting.");
+		exit(20);
 	}
 
 	on = 1;


-- 
John Goerzen   Linux, Unix consulting & programming   jgoerzen@complete.org |
Developer, Debian GNU/Linux (Free powerful OS upgrade)       www.debian.org |
----------------------------------------------------------------------------+
Visit the Air Capitol Linux Users Group on the web at http://www.aclug.org


--  
To UNSUBSCRIBE, email to debian-devel-request@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org


Reply to: