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