Module Name: src Committed By: riz Date: Wed Nov 2 19:58:23 UTC 2011
Modified Files: src/libexec/tftpd [netbsd-5]: tftpd.8 tftpd.c Log Message: Pull up following revision(s) (requested by bouyer in ticket #1677): libexec/tftpd/tftpd.c: revision 1.32 libexec/tftpd/tftpd.8: revision 1.22 libexec/tftpd/tftpd.c: revision 1.33 libexec/tftpd/tftpd.8: revision 1.23 libexec/tftpd/tftpd.c: revision 1.34 libexec/tftpd/tftpd.8: revision 1.24 fix shadowed variable Patrick Welche <prlw1%cam.ac.uk@localhost> - add -p pathsep option - make wrap to zero work, but produce a warning While here: - fix gcc warnings, in particular variable clobbered warnings (compiling with fewer warnings does not really fix the problem) Sort options in SYNOPSIS. New sentence, new line. Use only mdoc markup. Make HTML-ready. Sync usage with man page. To generate a diff of this commit: cvs rdiff -u -r1.21 -r1.21.38.1 src/libexec/tftpd/tftpd.8 cvs rdiff -u -r1.31 -r1.31.4.1 src/libexec/tftpd/tftpd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/tftpd/tftpd.8 diff -u src/libexec/tftpd/tftpd.8:1.21 src/libexec/tftpd/tftpd.8:1.21.38.1 --- src/libexec/tftpd/tftpd.8:1.21 Thu Aug 7 09:46:53 2003 +++ src/libexec/tftpd/tftpd.8 Wed Nov 2 19:58:23 2011 @@ -1,4 +1,4 @@ -.\" $NetBSD: tftpd.8,v 1.21 2003/08/07 09:46:53 agc Exp $ +.\" $NetBSD: tftpd.8,v 1.21.38.1 2011/11/02 19:58:23 riz Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93 .\" -.Dd June 11, 2003 +.Dd January 8, 2010 .Dt TFTPD 8 .Os .Sh NAME @@ -39,10 +39,9 @@ Internet Trivial File Transfer Protocol server .Sh SYNOPSIS .Nm -.Op Fl d +.Op Fl dln .Op Fl g Ar group -.Op Fl l -.Op Fl n +.Op Fl p Ar pathsep .Op Fl s Ar directory .Op Fl u Ar user .Op Ar directory ... @@ -66,8 +65,11 @@ does not require an account or password Due to the lack of authentication information, .Nm will allow only publicly readable files to be accessed. -Filenames beginning in ``\|\fB.\|.\fP\|/'' or -containing ``/\|\fB.\|.\fP\|/'' are not allowed. +Filenames beginning in +.Dq Pa ../ +or containing +.Dq Pa /../ +are not allowed. Files may be written to only if they already exist and are publicly writable. .Pp Note that this extends the concept of @@ -89,7 +91,7 @@ The given directories are also treated a relative filename requests. .Pp The options are: -.Bl -tag -width "directory" +.Bl -tag -width "XsXdirectoryX" .It Fl d Enable verbose debugging messages to .Xr syslogd 8 . @@ -107,6 +109,11 @@ Logs all requests using .It Fl n Suppresses negative acknowledgement of requests for nonexistent relative filenames. +.It Fl p Ar pathsep +All occurances of the single character +.Ar pathsep +(path separator) in the requested filename are replaced with +.Sq / . .It Fl s Ar directory .Nm will @@ -193,11 +200,16 @@ TFTP options were implemented by Wasabi and first appeared in .Nx 2.0 . .Sh BUGS -Files larger than 33488896 octets (65535 blocks) cannot be transferred -without client and server supporting blocksize negotiation (RFCs -2347 and 2348). -.Pp -Many tftp clients will not transfer files over 16744448 octets (32767 blocks). +Files larger than 33,553,919 octets (65535 blocks, last one less than 512 +octets) cannot be correctly transferred without client and server +supporting blocksize negotiation (RFCs 2347 and 2348). +As a kludge, +.Nm +accepts a sequence of block numbers which wrap to zero after 65535. +.Pp +Many tftp clients will not transfer files over 16,776,703 octets +(32767 blocks), as they incorrectly count the block number using +a signed rather than unsigned 16-bit integer. .Sh SECURITY CONSIDERATIONS You are .Em strongly Index: src/libexec/tftpd/tftpd.c diff -u src/libexec/tftpd/tftpd.c:1.31 src/libexec/tftpd/tftpd.c:1.31.4.1 --- src/libexec/tftpd/tftpd.c:1.31 Mon Jul 21 13:25:47 2008 +++ src/libexec/tftpd/tftpd.c Wed Nov 2 19:58:23 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: tftpd.c,v 1.31 2008/07/21 13:25:47 lukem Exp $ */ +/* $NetBSD: tftpd.c,v 1.31.4.1 2011/11/02 19:58:23 riz Exp $ */ /* * Copyright (c) 1983, 1993 @@ -36,7 +36,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19 #if 0 static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: tftpd.c,v 1.31 2008/07/21 13:25:47 lukem Exp $"); +__RCSID("$NetBSD: tftpd.c,v 1.31.4.1 2011/11/02 19:58:23 riz Exp $"); #endif #endif /* not lint */ @@ -77,20 +77,20 @@ __RCSID("$NetBSD: tftpd.c,v 1.31 2008/07 #define TIMEOUT 5 -int peer; -int rexmtval = TIMEOUT; -int maxtimeout = 5*TIMEOUT; - -char buf[MAXPKTSIZE]; -char ackbuf[PKTSIZE]; -char oackbuf[PKTSIZE]; -struct sockaddr_storage from; -socklen_t fromlen; -int debug; - -int tftp_opt_tsize = 0; -int tftp_blksize = SEGSIZE; -int tftp_tsize = 0; +static int peer; +static int rexmtval = TIMEOUT; +static int maxtimeout = 5*TIMEOUT; + +static char buf[MAXPKTSIZE]; +static char ackbuf[PKTSIZE]; +static char oackbuf[PKTSIZE]; +static struct sockaddr_storage from; +static socklen_t fromlen; +static int debug; + +static int tftp_opt_tsize = 0; +static int tftp_blksize = SEGSIZE; +static int tftp_tsize = 0; /* * Null-terminated directory prefix list for absolute pathname requests and @@ -107,24 +107,24 @@ static struct dirlist { static int suppress_naks; static int logging; static int secure; +static char pathsep = '\0'; static char *securedir; struct formats; static const char *errtomsg(int); -static void nak(int); -static void tftp(struct tftphdr *, int); -static void usage(void); +static void nak(int); +static void tftp(struct tftphdr *, int); +static void usage(void) __attribute__((__noreturn__)); static char *verifyhost(struct sockaddr *); -void justquit(int); -int main(int, char **); -void recvfile(struct formats *, int, int); -void sendfile(struct formats *, int, int); -void timer(int); +static void justquit(int); +static void recvfile(struct formats *, int, int); +static void sendfile(struct formats *, int, int); +static void timer(int); static const char *opcode(int); -int validate_access(char **, int); +static int validate_access(char **, int); -struct formats { +static struct formats { const char *f_mode; int (*f_validate)(char **, int); void (*f_send)(struct formats *, int, int); @@ -133,7 +133,7 @@ struct formats { } formats[] = { { "netascii", validate_access, sendfile, recvfile, 1 }, { "octet", validate_access, sendfile, recvfile, 0 }, - { 0 } + { .f_mode = NULL } }; static void @@ -141,7 +141,7 @@ usage(void) { syslog(LOG_ERR, - "Usage: %s [-dln] [-u user] [-g group] [-s directory] [directory ...]", + "Usage: %s [-dln] [-g group] [-p pathsep] [-s directory] [-u user] [directory ...]", getprogname()); exit(1); } @@ -153,7 +153,8 @@ main(int argc, char *argv[]) struct passwd *pwent; struct group *grent; struct tftphdr *tp; - char *tgtuser, *tgtgroup, *ep; + const char *tgtuser, *tgtgroup; + char *ep; int n, ch, on, fd; int soopt; socklen_t len; @@ -170,7 +171,7 @@ main(int argc, char *argv[]) curuid = getuid(); curgid = getgid(); - while ((ch = getopt(argc, argv, "dg:lns:u:")) != -1) + while ((ch = getopt(argc, argv, "dg:lnp:s:u:w:")) != -1) switch (ch) { case 'd': debug++; @@ -188,6 +189,12 @@ main(int argc, char *argv[]) suppress_naks = 1; break; + case 'p': + if (optarg[0] == '\0' || optarg[1] != '\0') + usage(); + pathsep = optarg[0]; + break; + case 's': secure = 1; securedir = optarg; @@ -536,15 +543,15 @@ tsize_handler(struct tftphdr *tp, char * return 0; } -struct tftp_options { - char *o_name; +static const struct tftp_options { + const char *o_name; int (*o_handler)(struct tftphdr *, char *, char *, char *, int *, int *); } options[] = { { "blksize", blk_handler }, { "timeout", timeout_handler }, { "tsize", tsize_handler }, - { NULL, NULL } + { .o_name = NULL } }; /* @@ -555,7 +562,7 @@ static int get_options(struct tftphdr *tp, char *cp, int size, char *ackb, int *alen, int *err) { - struct tftp_options *op; + const struct tftp_options *op; char *option, *value, *endp; int r, rv=0, ec=0; @@ -609,7 +616,7 @@ tftp(struct tftphdr *tp, int size) struct formats *pf; char *cp; char *filename, *mode; - int first, ecode, alen, etftp=0, r; + int first, ecode, alen, etftp = 0, r; ecode = 0; /* XXX gcc */ first = 1; @@ -662,6 +669,16 @@ again: exit(1); } } + /* + * Globally replace the path separator given in the -p option + * with / to cope with clients expecting a non-unix path separator. + */ + if (pathsep != '\0') { + for (cp = filename; *cp != '\0'; ++cp) { + if (*cp == pathsep) + *cp = '/'; + } + } ecode = (*pf->f_validate)(&filename, tp->th_opcode); if (logging) { syslog(LOG_INFO, "%s: %s request for %s: %s", @@ -821,10 +838,10 @@ validate_access(char **filep, int mode) return (0); } -int timeout; -jmp_buf timeoutbuf; +static int timeout; +static jmp_buf timeoutbuf; -void +static void timer(int dummy) { @@ -837,7 +854,7 @@ timer(int dummy) static const char * opcode(int code) { - static char buf[64]; + static char obuf[64]; switch (code) { case RRQ: @@ -853,21 +870,22 @@ opcode(int code) case OACK: return "OACK"; default: - (void)snprintf(buf, sizeof(buf), "*code %d*", code); - return buf; + (void)snprintf(obuf, sizeof(obuf), "*code 0x%x*", code); + return obuf; } } /* * Send the requested file. */ -void -sendfile(struct formats *pf, int etftp, int acklength) +static void +sendfile(struct formats *pf, volatile int etftp, int acklength) { volatile unsigned int block; struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ - int size, n; + volatile int size; + int n; signal(SIGALRM, timer); ap = (struct tftphdr *)ackbuf; @@ -918,20 +936,20 @@ send_data: goto abort; case ACK: - if (ap->th_block == 0) { + if (etftp && ap->th_block == 0) { etftp = 0; acklength = 0; dp = r_init(); goto done; } - if (ap->th_block == block) + if (ap->th_block == (u_short)block) goto done; if (debug) syslog(LOG_DEBUG, "Resync ACK %u != %u", (unsigned int)ap->th_block, block); /* Re-synchronize with the other side */ (void) synchnet(peer, tftp_blksize); - if (ap->th_block == (block -1)) + if (ap->th_block == (u_short)(block - 1)) goto send_data; default: syslog(LOG_INFO, "Received %s in sendfile\n", @@ -942,13 +960,16 @@ send_data: done: if (debug) syslog(LOG_DEBUG, "Received ACK for block %u", block); + if (block == UINT16_MAX && size == tftp_blksize) + syslog(LOG_WARNING, + "Block number wrapped (hint: increase block size)"); block++; } while (size == tftp_blksize || block == 1); abort: (void) fclose(file); } -void +static void justquit(int dummy) { @@ -958,13 +979,14 @@ justquit(int dummy) /* * Receive a file. */ -void -recvfile(struct formats *pf, int etftp, int acklength) +static void +recvfile(struct formats *pf, volatile int etftp, volatile int acklength) { volatile unsigned int block; struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ - int n, size; + volatile int size; + int n; signal(SIGALRM, timer); dp = w_init(); @@ -980,9 +1002,13 @@ recvfile(struct formats *pf, int etftp, } if (debug) syslog(LOG_DEBUG, "Sending ACK for block %u\n", block); + if (block == UINT16_MAX) + syslog(LOG_WARNING, + "Block number wrapped (hint: increase block size)"); block++; (void) setjmp(timeoutbuf); send_ack: + ap = (struct tftphdr *) (etftp ? oackbuf : ackbuf); if (send(peer, ap, acklength, 0) != acklength) { syslog(LOG_ERR, "tftpd: write: %m"); goto abort;