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;