Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 9/5/84; site unmvax.UUCP
Path: utzoo!watmath!clyde!bonnie!akgua!sdcsvax!sdcrdcf!hplabs!hao!seismo!cmcl2!lanl-a!unm-cvax!unmvax!lee
From: lee@unmvax.UUCP
Newsgroups: net.bugs.4bsd
Subject: SECURITY HOLE IN tftpd (fix for a fix, sigh..)
Message-ID: <449@unmvax.UUCP>
Date: Thu, 27-Sep-84 18:41:57 EDT
Article-I.D.: unmvax.449
Posted: Thu Sep 27 18:41:57 1984
Date-Received: Sun, 30-Sep-84 04:54:34 EDT
Distribution: net
Organization: Univ. of New Mexico, Albuquerque
Lines: 109


 The last "fix" I posted neglected to account for symlinks. I still
live in a 4.1 world, I guess.... This one gets the symlinks too.

RCS file: RCS/tftpd.c,v
retrieving revision 1.1
diff -c -r1.1 tftpd.c
*** /tmp/,RCSt1013277	Thu Sep 27 16:40:55 1984
--- tftpd.c	Thu Sep 27 16:34:50 1984
***************
*** 188,193
  	int mode;
  {
  	struct stat stbuf;
  
  	if (*file != '/')
  		return (EACCESS);

--- 188,200 -----
  	int mode;
  {
  	struct stat stbuf;
+ 	char	*ptr,
+ 		*lsptr,
+ 		*eptr,
+ 		buf[BUFSIZ],
+ 		tbuf[BUFSIZ];
+ 	int	sret,
+ 		cc;
  
  	(void )chdir("/");
  	if (*file != '/')
***************
*** 189,194
  {
  	struct stat stbuf;
  
  	if (*file != '/')
  		return (EACCESS);
  	if (stat(file, &stbuf) < 0)

--- 196,202 -----
  	int	sret,
  		cc;
  
+ 	(void )chdir("/");
  	if (*file != '/')
  		return (EACCESS);
  	/* Check path first */
***************
*** 191,196
  
  	if (*file != '/')
  		return (EACCESS);
  	if (stat(file, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);
  	if (mode == RRQ) {

--- 199,245 -----
  	(void )chdir("/");
  	if (*file != '/')
  		return (EACCESS);
+ 	/* Check path first */
+ 	eptr = file + strlen(file);
+ 	lsptr = ptr = file;
+ 	ptr++;
+ 	while (ptr < eptr) {
+ 		if (*ptr++ != '/' && *ptr)
+ 			continue;
+ 		if (*ptr) {
+ 			ptr--;
+ 			*ptr = NULL;
+ 		}
+ 		sret = lstat(file, &stbuf);
+ 		if (ptr != eptr)
+ 			*ptr++ = '/';
+ 		else
+ 			ptr++;
+ 		if (sret < 0)
+ 			return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ 		if ((stbuf.st_mode&S_IFMT) == S_IFDIR) {
+ 			if((stbuf.st_mode&(S_IEXEC >> 6)) == 0)
+ 				return (EACCESS);
+ 		} else if ((stbuf.st_mode&S_IFMT) == S_IFLNK) {
+ 			*--ptr = NULL;
+ 			cc = readlink(file, tbuf, sizeof(tbuf));
+ 			if (cc < 0)
+ 				return(errno);
+ 			tbuf[cc] = NULL;
+ 			strncat(tbuf, ptr, sizeof(tbuf) - 1 - cc);
+ 			if (tbuf[0] != '/') {
+ 				*lsptr = NULL;
+ 				(void )chdir(file);
+ 				ptr = buf;
+ 			} else
+ 				ptr = &buf[1];
+ 			strcpy(buf, tbuf);
+ 			file = buf;
+ 			eptr = file + strlen(file);
+ 		} else
+ 			break;
+ 		lsptr = ptr - 1;
+ 	}
  	if (stat(file, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);
  	if (mode == RRQ) {
-- 
			--Lee (Ward)
			{ucbvax,convex,gatech,pur-ee}!unmvax!lee