$NetBSD: patch-ad,v 1.2 2003/09/21 09:15:31 jmc Exp $ --- tftpd.c.orig Mon Mar 20 21:14:39 1995 +++ tftpd.c @@ -56,6 +56,8 @@ #include #include +#include + #define TIMEOUT 5 extern int errno; @@ -66,9 +68,9 @@ int rexmtval = TIMEOUT; int maxtimeout = 5*TIMEOUT; -#define PKTSIZE SEGSIZE+4 -char buf[PKTSIZE]; -char ackbuf[PKTSIZE]; +#define BUF_PKTSIZE SEGSIZE+4 +char buf[BUF_PKTSIZE]; +char ackbuf[BUF_PKTSIZE]; struct sockaddr_in from; int fromlen; @@ -105,6 +107,8 @@ if (argc > 1 && strcmp (argv[1], "-d") == 0) { setUpForDebugging(); + argc--; + argv++; } if (ioctl(0, FIONBIO, &on) < 0) { syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); @@ -202,7 +206,7 @@ awaitInput(chan) int chan; { - int imask; + fd_set imask; int nready; struct timeval tv; extern int maxInputWait; @@ -212,8 +216,9 @@ else tv.tv_sec = 5*60; /* default: wait for 5 minutes */ tv.tv_usec = 0; - imask = 1< 0) { - char buf[1024]; - buf[0] = '\0'; - getwd(buf); + char* buf; + buf = getcwd(NULL, 0); syslog(LOG_DEBUG, "request %s '%s' from %s; cwd='%s'", (tp->th_opcode == RRQ ? "read" : "write"), filename, inet_ntoa(from.sin_addr), buf); + free(buf); } ecode = (*pf->f_validate)(filename, tp->th_opcode); if (ecode) { @@ -459,17 +467,25 @@ /* Rule 2: */ - if (tftpRootDirectory != 0 && IS_ROOTED(filename)) { + if ((tftpRootDirectory != 0 && IS_ROOTED(filename)) || + (tftpDefaultDirectory != 0 && IS_ROOTED(filename))) { char _tmp[1024]; + char* realRootDir; int maxPath; int rootLen; - rootLen = strlen (tftpRootDirectory); + if (tftpRootDirectory != 0 ) { + realRootDir = tftpRootDirectory; + } + else { + realRootDir = tftpDefaultDirectory; + } + + rootLen = strlen (realRootDir); /* make sure the pathname doesn't already contain * the virtual root. */ - if (strncmp(filename,tftpRootDirectory,rootLen) != 0) { /* Insure our temporary space is big enough */ maxPath = ((sizeof _tmp) - 1) - rootLen; @@ -481,6 +497,8 @@ return EACCESS; } + if (strncmp(filename,realRootDir,rootLen) != 0) { + /* Squeeze out any '.' or '..' components */ strcpy (tmpPath, filename); if (realPath (tmpPath, _tmp) < 0) { @@ -492,21 +510,54 @@ /* Create the full pathname, prefixed by the * virtual root. */ - strcpy (tmpPath, tftpRootDirectory); + strcpy (tmpPath, realRootDir); strcat (tmpPath, _tmp); filename = tmpPath; } + else { + /* Squeeze out any '.' or '..' components */ + strcpy (tmpPath, filename); + if (realPath (tmpPath, _tmp) < 0) { + if (tftpDebugLevel > 1) + syslog (LOG_DEBUG, "realPath fails"); + return EACCESS; + } + /* Create the full pathname */ + strcpy (tmpPath,_tmp); + filename = tmpPath; + if (strncmp(filename,realRootDir,rootLen) != 0) { + if (tftpDebugLevel > 1) { + syslog(LOG_DEBUG, "file=%s; invalid access denied", filename); + return EACCESS; + } + } + } } /* Rule 3: */ - if (!IS_ROOTED(filename) && tftpDefaultDirectory == 0) { - strcpy (tmpPath, tftpRootDirectory); - strcat (tmpPath, "/"); + if ((!IS_ROOTED(filename) && tftpRootDirectory != 0) || + (!IS_ROOTED(filename) && tftpDefaultDirectory != 0)) { + char _tmp[1024]; strcat (tmpPath, filename); + /* Squeeze out any '.' or '..' components */ + strcpy (tmpPath, filename); + if (realPath (tmpPath, _tmp) < 0) { + if (tftpDebugLevel > 1) + syslog (LOG_DEBUG, "realPath fails"); + return EACCESS; + } + if ( tftpDefaultDirectory == 0 ) { + strcpy (tmpPath, tftpRootDirectory); + } + else { + strcpy (tmpPath, tftpDefaultDirectory); + } + strcat (tmpPath, _tmp); filename = tmpPath; } + /* Check access lists */ /* Rules 4&5: */ @@ -593,7 +644,7 @@ /* * Send the requested file. */ -sendfile(pf) +tftpsendfile(pf) struct formats *pf; { struct tftphdr *dp, *r_init(); @@ -664,7 +715,7 @@ /* * Receive a file. */ -recvfile(pf) +tftprecvfile(pf) struct formats *pf; { struct tftphdr *dp, *w_init(); @@ -739,7 +739,7 @@ write_behind(file, pf->f_convert); for ( ; ; ) { alarm(rexmtval); - n = recv(peer, dp, PKTSIZE, 0); + n = recv(peer, dp, BUF_PKTSIZE, 0); alarm(0); if (n < 0) { /* really? */ syslog(LOG_ERR, "tftpd: read: %m\n");