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