$NetBSD: patch-ad,v 1.5 2007/10/02 20:23:08 heinz Exp $ --- tftpd.c.orig 1995-03-20 21:14:39.000000000 +0100 +++ tftpd.c @@ -43,6 +43,9 @@ static char sccsid[] = "@(#)tftpd.c 5.12 #include #include #include +#ifdef __sun +#include +#endif #include @@ -56,17 +59,22 @@ static char sccsid[] = "@(#)tftpd.c 5.12 #include #include +#include +#include +#ifdef __STDC__ +#include +#endif + #define TIMEOUT 5 -extern int errno; struct sockaddr_in sock_in = { AF_INET }; int peer; 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 +113,8 @@ char **argv; 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 +212,7 @@ setUpForDebugging() awaitInput(chan) int chan; { - int imask; + fd_set imask; int nready; struct timeval tv; extern int maxInputWait; @@ -212,8 +222,9 @@ int chan; 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 +473,25 @@ validate_access(filename, mode) /* 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 +503,8 @@ validate_access(filename, mode) return EACCESS; } + if (strncmp(filename,realRootDir,rootLen) != 0) { + /* Squeeze out any '.' or '..' components */ strcpy (tmpPath, filename); if (realPath (tmpPath, _tmp) < 0) { @@ -492,21 +516,54 @@ validate_access(filename, mode) /* 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: */ @@ -565,7 +622,7 @@ validate_access(filename, mode) * This will be done with the effective permissions of the TFTPD * process. */ - fd = open(filename, mode == RRQ ? 0 : 1); + fd = open(filename, mode == RRQ ? (O_RDONLY) : (O_WRONLY|O_TRUNC)); if (fd < 0) { syslog (LOG_DEBUG, "open fails; errno = %d", errno); return errno+100; @@ -593,7 +650,7 @@ void timer() /* * Send the requested file. */ -sendfile(pf) +tftpsendfile(pf) struct formats *pf; { struct tftphdr *dp, *r_init(); @@ -664,7 +721,7 @@ void justquit() /* * Receive a file. */ -recvfile(pf) +tftprecvfile(pf) struct formats *pf; { struct tftphdr *dp, *w_init(); @@ -688,7 +745,7 @@ send_ack: 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");