Module Name:    src
Committed By:   christos
Date:           Fri Jan  8 21:05:14 UTC 2010

Modified Files:
        src/libexec/tftpd: Makefile tftpd.8 tftpd.c

Log Message:
Patrick Welche <[email protected]>
    - 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)


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/libexec/tftpd/Makefile
cvs rdiff -u -r1.21 -r1.22 src/libexec/tftpd/tftpd.8
cvs rdiff -u -r1.32 -r1.33 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/Makefile
diff -u src/libexec/tftpd/Makefile:1.12 src/libexec/tftpd/Makefile:1.13
--- src/libexec/tftpd/Makefile:1.12	Sun Mar 15 22:24:57 2009
+++ src/libexec/tftpd/Makefile	Fri Jan  8 16:05:14 2010
@@ -1,7 +1,7 @@
-#	$NetBSD: Makefile,v 1.12 2009/03/16 02:24:57 lukem Exp $
+#	$NetBSD: Makefile,v 1.13 2010/01/08 21:05:14 christos Exp $
 #	from: @(#)Makefile	8.1 (Berkeley) 6/4/93
 
-WARNS?=	2		# XXX: setjmp clobber warnings
+WARNS?=	5
 
 .include <bsd.own.mk>
 

Index: src/libexec/tftpd/tftpd.8
diff -u src/libexec/tftpd/tftpd.8:1.21 src/libexec/tftpd/tftpd.8:1.22
--- src/libexec/tftpd/tftpd.8:1.21	Thu Aug  7 05:46:53 2003
+++ src/libexec/tftpd/tftpd.8	Fri Jan  8 16:05:14 2010
@@ -1,4 +1,4 @@
-.\"	$NetBSD: tftpd.8,v 1.21 2003/08/07 09:46:53 agc Exp $
+.\"	$NetBSD: tftpd.8,v 1.22 2010/01/08 21:05:14 christos 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
@@ -43,6 +43,7 @@
 .Op Fl g Ar group
 .Op Fl l
 .Op Fl n
+.Op Fl p Ar path separator
 .Op Fl s Ar directory
 .Op Fl u Ar user
 .Op Ar directory ...
@@ -107,6 +108,11 @@
 .It Fl n
 Suppresses negative acknowledgement of requests for nonexistent
 relative filenames.
+.It Fl p Ar path separator
+All occurances of the single character
+.Ar path separator
+in the requested filename are replaced with
+.Sq / .
 .It Fl s Ar directory
 .Nm
 will
@@ -193,11 +199,15 @@
 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 <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.32 src/libexec/tftpd/tftpd.c:1.33
--- src/libexec/tftpd/tftpd.c:1.32	Sun Mar 15 21:56:21 2009
+++ src/libexec/tftpd/tftpd.c	Fri Jan  8 16:05:14 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: tftpd.c,v 1.32 2009/03/16 01:56:21 lukem Exp $	*/
+/*	$NetBSD: tftpd.c,v 1.33 2010/01/08 21:05:14 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -36,7 +36,7 @@
 #if 0
 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: tftpd.c,v 1.32 2009/03/16 01:56:21 lukem Exp $");
+__RCSID("$NetBSD: tftpd.c,v 1.33 2010/01/08 21:05:14 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -77,20 +77,20 @@
 
 #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 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 @@
 } formats[] = {
 	{ "netascii",	validate_access,	sendfile,	recvfile, 1 },
 	{ "octet",	validate_access,	sendfile,	recvfile, 0 },
-	{ 0 }
+	{ .f_mode = NULL }
 };
 
 static void
@@ -141,7 +141,7 @@
 {
 
 	syslog(LOG_ERR,
-    "Usage: %s [-dln] [-u user] [-g group] [-s directory] [directory ...]",
+    "Usage: %s [-dln] [-u user] [-g group] [-s directory] [-p pathsep] [directory ...]",
 		    getprogname());
 	exit(1);
 }
@@ -153,7 +153,8 @@
 	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 @@
 	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 @@
 			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 @@
 	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 @@
 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 @@
 	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 @@
 			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 @@
 	return (0);
 }
 
-int	timeout;
-jmp_buf	timeoutbuf;
+static int	timeout;
+static jmp_buf	timeoutbuf;
 
-void
+static void
 timer(int dummy)
 {
 
@@ -853,7 +870,7 @@
 	case OACK:
 		return "OACK";
 	default:
-		(void)snprintf(obuf, sizeof(obuf), "*code %d*", code);
+		(void)snprintf(obuf, sizeof(obuf), "*code 0x%x*", code);
 		return obuf;
 	}
 }
@@ -861,13 +878,14 @@
 /*
  * 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 @@
 				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 @@
 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 @@
 /*
  * 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 @@
 		}
 		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;

Reply via email to