tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: tftp protocol
On Thu, Jan 07, 2010 at 06:28:06AM -0800, John Nemeth wrote:
> On May 29, 1:18pm, Patrick Welche wrote:
> Whilst I think the client should be fixed, this option is
> non-contentious. The only thing is I would check to see if any of the
> other BSDs supports and use the same option letter.
Free/Open don't use 'p', and don't offer similar functionality.
> The block counter should wrap as is done by both FreeBSD and
> OpenBSD. This is most likely necessary to support downloading large
> files on certain devices (i.e. Cisco devices running IOS). I need to
> further investigate this, but will most likely be implementing this
> change.
The attached patch does wrap to zero (successfully booted a vista image, and
the wrap warning appeared in the logs.
Cheers,
Patrick
Index: tftpd.8
===================================================================
RCS file: /cvsroot/src/libexec/tftpd/tftpd.8,v
retrieving revision 1.21
diff -u -r1.21 tftpd.8
--- tftpd.8 7 Aug 2003 09:46:53 -0000 1.21
+++ tftpd.8 8 Jan 2010 17:16:46 -0000
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93
.\"
-.Dd June 11, 2003
+.Dd November 13, 2009
.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: tftpd.c
===================================================================
RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
retrieving revision 1.32
diff -u -r1.32 tftpd.c
--- tftpd.c 16 Mar 2009 01:56:21 -0000 1.32
+++ tftpd.c 8 Jan 2010 17:16:47 -0000
@@ -107,6 +107,7 @@
static int suppress_naks;
static int logging;
static int secure;
+static char pathsep = '\0';
static char *securedir;
struct formats;
@@ -141,7 +142,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);
}
@@ -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,11 @@
suppress_naks = 1;
break;
+ case 'p':
+ pathsep = optarg[0];
+ if (optarg[1] != '\0' || optarg[0] == '\0') usage();
+ break;
+
case 's':
secure = 1;
securedir = optarg;
@@ -662,6 +668,15 @@
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",
@@ -853,7 +868,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;
}
}
@@ -918,20 +933,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,6 +957,9 @@
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:
@@ -980,6 +998,9 @@
}
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:
Home |
Main Index |
Thread Index |
Old Index