[comp.unix.wizards] tftp in 4.3BSD

haynes@ucbarpa.Berkeley.EDU.UUCP (03/21/87)

I notice that tftp is commented out in /etc/inetd.conf in 4.3BSD as distributed.
Is this because of some really horrid security hole, or just that you might not
want every site in the world to be able to read all your publicly-readable
files?

Jim Haynes
haynes@arpa.berkeley.edu
...ucbvax!ucscc!haynes
haynes@ucscc.bitnet

matt@oddjob.UUCP (03/22/87)

The fact that all your public-read files become universe-read is
the security hole.  Certain people with more free time than
manners will fetch your password file and run encryption
programs until they crack some passwords.  Since we need a tftp
server to download our gateways, here's how I changed it.

revision 1.3        
date: 87/01/27 14:32:32;  author: root;  state: Exp;  lines added/del: 11/6
Allow non-rooted pathnames if we have chroot()'d.
This means we must chdir() as well as chroot().
----------------------------
revision 1.2        
date: 86/12/13 14:47:09;  author: root;  state: Exp;  lines added/del: 7/1
If given an arg, do chroot(argv[1]).
=============================================================================
RCS file: RCS/tftpd.c,v
retrieving revision 1.1
retrieving revision 1.3
diff -c -r1.1 -r1.3
*** /tmp/,RCSt1029298	Sat Mar 21 16:11:45 1987
--- /tmp/,RCSt2029298	Sat Mar 21 16:11:47 1987
***************
*** 53,59 ****
  struct	sockaddr_in from;
  int	fromlen;
  
! main()
  {
  	register struct tftphdr *tp;
  	register int n;
--- 53,63 ----
  struct	sockaddr_in from;
  int	fromlen;
  
! int	chrooted = 0;
! 
! main(argc, argv)
! 	int	argc;
! 	char	*argv[];
  {
  	register struct tftphdr *tp;
  	register int n;
***************
*** 125,130 ****
--- 129,140 ----
  	alarm(0);
  	close(0);
  	close(1);
+ 	if (argc > 1 && *argv[1] != '\0')
+ 		if (chdir(argv[1]) < 0 || chroot(argv[1]) < 0) {
+ 			syslog(LOG_ERR, "chroot(%s): %m\n", argv[1]);
+ 			exit(1);
+ 		} else
+ 			chrooted = 1;
  	peer = socket(AF_INET, SOCK_DGRAM, 0);
  	if (peer < 0) {
  		syslog(LOG_ERR, "socket: %m\n");
***************
*** 221,227 ****
   * have no uid or gid, for now require
   * file to exist and be publicly
   * readable/writable.
!  * Note also, full path name must be
   * given as we have no login directory.
   */
  validate_access(filename, mode)
--- 231,238 ----
   * have no uid or gid, for now require
   * file to exist and be publicly
   * readable/writable.
!  * Note also that unless we have done chroot(),
!  * full path name must be
   * given as we have no login directory.
   */
  validate_access(filename, mode)
***************
*** 231,237 ****
  	struct stat stbuf;
  	int	fd;
  
! 	if (*filename != '/')
  		return (EACCESS);
  	if (stat(filename, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);
--- 242,248 ----
  	struct stat stbuf;
  	int	fd;
  
! 	if (!chrooted && *filename != '/')
  		return (EACCESS);
  	if (stat(filename, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);

________________________________________________________
Matt	     University		matt@oddjob.uchicago.edu
Crawford     of Chicago     {astrovax,ihnp4}!oddjob!matt
(Footnote to correspondants: Our NSFnet connection has been
dead since Wed. night.)

guyton%condor@rand-unix.arpa (03/22/87)

Before you install tftpd, read and understand the routine

	tftpd.c: validate_access()

in /usr/src/etc/tftpd/tftpd.c.  The default is to allow anonymous
reading of all publically readable files (not too bad), and
anonymous writing of any publically writable file (ugh!).  It
also won't create a file for you.

Here's my replacement for that code.  Read it and agree with it
before installing.  Basically it chroot's to a directory of your
choice and so restricts file i/o to that directory.  Due to the
chroot call, the tftpd will have to be run as root.  It also
won't create the TROOT directory, do that by hand.

-- Jim Guyton, guyton@rand-unix.arpa

p.s. this code is still far from ideal, but then so is tftp.


#define TROOT   "/tmp/tftp"     /* Home for all tftp files */

FILE    *file;           /* opened by validate_access */
extern	int errno;


/*
 * Validate file access.
 *
 * This version changes root to TROOT and lets the client munge files
 * only within that directory.  It should be fairly safe, though somewhat
 * inconvenient to use.  Before changing, remember that this code is
 * run as root and there is *no* user validatation at all!  Within
 * the /tmp/tftp directory, the rules are:
 *
 *    FOR READING:    File must exist and be publicly readable
 *    FOR WRITING:    If the file exists, it must be publicly writeable.
 *                    If it does not exist, it is created and made publicly
 *                            writeable by default.
 *
 *
 * ToDo:  add logging of transfers
 * ToDo:  act less paranoid if connection from known friendly host
 *
 */

validate_access(filename, client, mode)
	char *filename;
	struct sockaddr_in *client;
	int mode;
{
	struct stat stbuf;

	if (restrict())                 /* chdir and chroot */
		return EACCESS;         /* err out if not there */

	if (mode == RRQ) {              /* Check access if reading */
		if (stat(filename, &stbuf) < 0)
			return (errno == ENOENT ? ENOTFOUND : EACCESS);
		if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
			return (EACCESS);
		file = fopen(filename, "r");
	}
	else {                          /* write request */
		if (restrict()) return EACCESS;
		if (stat(filename, &stbuf) == 0) {
			if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
				return (EACCESS);
		}
		file = fopen(filename, "w");
	}
	if (file == NULL)
		return (errno + 100);
	return (0);
}

restrict()
{
	if (chdir(TROOT)  != 0 ||       /* must go there and */
	    chroot(TROOT) != 0)         /* also set root ... */
		return -1;
	return 0;                       /* return zero if worked */
}

lear@aramis.RUTGERS.EDU (eliot lear) (03/23/87)

One way to close up tftpd for gateway purposes is to validate access
on a "per host" basis through a file (like .rhosts).  This is what is
done at Rutgers as we do not wish the download files in question to
be publicly readable.

					...eliot
-- 

[lear@rutgers.rutgers.edu]
[{harvard|pyrnj|seismo|ihnp4}!rutgers!lear]