$NetBSD: patch-ad,v 1.7 2012/01/25 09:56:08 he Exp $ A number of changes to make this build with no warnings under -Wall. --- tftpd.c.orig 1995-03-20 20:14:39.000000000 +0000 +++ tftpd.c @@ -24,7 +24,7 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)tftpd.c 5.12 (Berkeley) 6/1/90"; +char tftpd_sccsid[] = "@(#)tftpd.c 5.12 (Berkeley) 6/1/90"; #endif /* not lint */ /* @@ -43,9 +43,13 @@ static char sccsid[] = "@(#)tftpd.c 5.12 #include #include #include +#ifdef __sun +#include +#endif #include +#include #include #include @@ -56,19 +60,45 @@ static char sccsid[] = "@(#)tftpd.c 5.12 #include #include +#include +#include +#ifdef __STDC__ +#include +#endif + #define TIMEOUT 5 -extern int errno; +extern int readConfigFile(int, char**); +extern int realPath(char *, char*); +extern int validateAccessToFile(char *, unsigned long, int); +extern int isConfigFile(struct stat*); + +extern int readit(FILE *, struct tftphdr **, int); +extern void read_ahead(FILE *, int); +extern int synchnet(int); +extern int write_behind(FILE *, int); +extern int writeit(FILE *, struct tftphdr **, int, int); + + +static void setUpForDebugging(); +static void reapChildren(); +static int awaitInput(int); +static int createChild(); +static void runChild(struct tftphdr*, int); +static void tftp(struct tftphdr *, int); +static void nak(int); +static int validate_access(char *, int); + 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; +socklen_t fromlen; extern int tftpDebugLevel; extern char* tftpDefaultDirectory; @@ -92,6 +122,7 @@ int n; } #endif +int main(argc, argv) int argc; char **argv; @@ -105,6 +136,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"); @@ -165,6 +198,7 @@ char **argv; /* Run directly, rather than called from inetd. */ +static void setUpForDebugging() { int peer; @@ -182,7 +216,7 @@ setUpForDebugging() listenSock.sin_family = AF_INET; listenSock.sin_addr.s_addr = htonl(INADDR_ANY); - if (serv = getservbyname("tftpd", "udp")) + if ((serv = getservbyname("tftpd", "udp")) != 0) listenSock.sin_port = serv->s_port; else listenSock.sin_port = htons(69); @@ -199,10 +233,11 @@ setUpForDebugging() * wait for seconds, or a default * of 5 minutes if that is not set. */ +static int awaitInput(chan) int chan; { - int imask; + fd_set imask; int nready; struct timeval tv; extern int maxInputWait; @@ -212,8 +247,9 @@ int chan; else tv.tv_sec = 5*60; /* default: wait for 5 minutes */ tv.tv_usec = 0; - imask = 1<th_stuff; #else @@ -345,8 +390,8 @@ again: goto again; } for (cp = mode; *cp; cp++) - if (isupper(*cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; @@ -355,13 +400,13 @@ again: exit(1); } if (tftpDebugLevel > 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) { @@ -438,6 +483,7 @@ FILE *file; * */ #define IS_ROOTED(S) (*(S) == '/') +static int validate_access(filename, mode) char *filename; int mode; @@ -459,17 +505,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 +535,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 +548,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 +654,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 +682,8 @@ void timer() /* * Send the requested file. */ -sendfile(pf) +int +tftpsendfile(pf) struct formats *pf; { struct tftphdr *dp, *r_init(); @@ -664,7 +754,8 @@ void justquit() /* * Receive a file. */ -recvfile(pf) +int +tftprecvfile(pf) struct formats *pf; { struct tftphdr *dp, *w_init(); @@ -688,7 +779,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"); @@ -758,6 +849,7 @@ struct errmsg { * standard TFTP codes, or a UNIX errno * offset by 100. */ +static void nak(error) int error; {