Author: imp
Date: Tue May  4 13:07:40 2010
New Revision: 207614
URL: http://svn.freebsd.org/changeset/base/207614

Log:
  Bring in new files from edwin's tftp

Added:
  head/libexec/tftpd/tftp-file.c   (contents, props changed)
  head/libexec/tftpd/tftp-file.h   (contents, props changed)
  head/libexec/tftpd/tftp-io.c   (contents, props changed)
  head/libexec/tftpd/tftp-io.h   (contents, props changed)
  head/libexec/tftpd/tftp-options.c   (contents, props changed)
  head/libexec/tftpd/tftp-options.h   (contents, props changed)
  head/libexec/tftpd/tftp-transfer.c   (contents, props changed)
  head/libexec/tftpd/tftp-transfer.h   (contents, props changed)
  head/libexec/tftpd/tftp-utils.c   (contents, props changed)
  head/libexec/tftpd/tftp-utils.h   (contents, props changed)

Added: head/libexec/tftpd/tftp-file.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/libexec/tftpd/tftp-file.c      Tue May  4 13:07:40 2010        
(r207614)
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "tftp-file.h"
+#include "tftp-utils.h"
+
+static FILE    *file;
+static int     convert;
+
+static char    convbuffer[66000];
+static int     gotcr = 0;
+
+static size_t
+convert_from_net(char *buffer, size_t count)
+{
+       size_t i, n;
+
+       /*
+        * Convert all CR/LF to LF and all CR,NUL to CR
+        */
+
+       n = 0;
+       for (i = 0; i < count; i++) {
+
+               if (gotcr == 0) {
+                       convbuffer[n++] = buffer[i];
+                       gotcr = (buffer[i] == '\r');
+                       continue;
+               }
+
+               /* CR, NULL -> CR */
+               if (buffer[i] == '\0') {
+                       gotcr = 0;
+                       continue;
+               }
+
+               /* CR, LF -> LF */
+               if (buffer[i] == '\n') {
+                       if (n == 0) {
+                               if (ftell(file) != 0) {
+                                       fseek(file, -1, SEEK_END);
+                                       convbuffer[n++] = '\n';
+                               } else {
+                                       /* This shouldn't happen */
+                                       tftp_log(LOG_ERR,
+                                           "Received LF as first character");
+                                       abort();
+                               }
+                       } else
+                               convbuffer[n-1] = '\n';
+                       gotcr = 0;
+                       continue;
+               }
+
+               /* Everything else just accept as is */
+               convbuffer[n++] = buffer[i];
+               gotcr = (buffer[i] == '\r');
+               continue;
+       }
+
+       return fwrite(convbuffer, 1, n, file);
+}
+
+static size_t
+convert_to_net(char *buffer, size_t count, int init)
+{
+       size_t i;
+       static size_t n = 0, read = 0;
+       static int newline = 0;
+
+       if (init) {
+               newline = 0;
+               n = 0;
+               read = 0;
+               return 0 ;
+       }
+
+       /*
+        * Convert all LF to CR,LF and all CR to CR,NUL
+        */
+       i = 0;
+
+       if (newline) {
+               buffer[i++] = newline;
+               newline = 0;
+       }
+
+       while (i < count) {
+               if (n == read) {
+                       /* When done we're done */
+                       if (feof(file)) break;
+
+                       /* Otherwise read another bunch */
+                       read = fread(convbuffer, 1, count, file);
+                       if (read == 0) break;
+                       n = 0;
+               }
+
+               /* CR -> CR,NULL */
+               if (convbuffer[n] == '\r') {
+                       buffer[i++] = '\r';
+                       buffer[i++] = '\0';
+                       n++;
+                       continue;
+               }
+
+               /* LF -> CR,LF */
+               if (convbuffer[n] == '\n') {
+                       buffer[i++] = '\r';
+                       buffer[i++] = '\n';
+                       n++;
+                       continue;
+               }
+
+               buffer[i++] = convbuffer[n++];
+       }
+
+       if (i > count) {
+               /*
+                * Whoops... that isn't alllowed (but it will happen
+                * when there is a CR or LF at the end of the buffer)
+                */
+               newline = buffer[i-1];
+       }
+
+       if (i < count) {
+               /* We are done! */
+               return i;
+       } else
+               return count;
+
+}
+
+int
+write_init(int fd, FILE *f, const char *mode)
+{
+
+       if (f == NULL) {
+               file = fdopen(fd, "w");
+               if (file == NULL) {
+                       int en = errno;
+                       tftp_log(LOG_ERR, "fdopen() failed: %s",
+                           strerror(errno));
+                       return en;
+               }
+       } else
+               file = f;
+       convert = !strcmp(mode, "netascii");
+       return 0;
+}
+
+size_t
+write_file(char *buffer, int count)
+{
+
+       if (convert == 0)
+               return fwrite(buffer, 1, count, file);
+
+       return convert_from_net(buffer, count);
+}
+
+int
+write_close(void)
+{
+
+       if (fclose(file) != 0) {
+               tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
+               return 1;
+       }
+       return 0;
+}
+
+int
+read_init(int fd, FILE *f, const char *mode)
+{
+
+       convert_to_net(NULL, 0, 1);
+       if (f == NULL) {
+               file = fdopen(fd, "r");
+               if (file == NULL) {
+                       int en = errno;
+                       tftp_log(LOG_ERR, "fdopen() failed: %s",
+                           strerror(errno));
+                       return en;
+               }
+       } else
+               file = f;
+       convert = !strcmp(mode, "netascii");
+       return 0;
+}
+
+size_t
+read_file(char *buffer, int count)
+{
+
+       if (convert == 0)
+               return fread(buffer, 1, count, file);
+
+       return convert_to_net(buffer, count, 0);
+}
+
+int
+read_close(void)
+{
+
+       if (fclose(file) != 0) {
+               tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
+               return 1;
+       }
+       return 0;
+}
+
+
+int
+synchnet(int peer)
+{
+
+       return 0;
+}

Added: head/libexec/tftpd/tftp-file.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/libexec/tftpd/tftp-file.h      Tue May  4 13:07:40 2010        
(r207614)
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+int    write_init(int fd, FILE *f, const char *mode);
+size_t write_file(char *buffer, int count);
+int    write_close(void);
+
+int    read_init(int fd, FILE *f, const char *mode);
+size_t read_file(char *buffer, int count);
+int    read_close(void);
+
+int    synchnet(int peer);

Added: head/libexec/tftpd/tftp-io.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/libexec/tftpd/tftp-io.c        Tue May  4 13:07:40 2010        
(r207614)
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "tftp-file.h"
+#include "tftp-io.h"
+#include "tftp-utils.h"
+#include "tftp-options.h"
+
+struct sockaddr_storage peer_sock;
+struct sockaddr_storage me_sock;
+
+static int send_packet(int peer, uint16_t block, char *pkt, int size);
+
+struct errmsg {
+       int     e_code;
+       const char      *e_msg;
+} errmsgs[] = {
+       { EUNDEF,       "Undefined error code" },
+       { ENOTFOUND,    "File not found" },
+       { EACCESS,      "Access violation" },
+       { ENOSPACE,     "Disk full or allocation exceeded" },
+       { EBADOP,       "Illegal TFTP operation" },
+       { EBADID,       "Unknown transfer ID" },
+       { EEXISTS,      "File already exists" },
+       { ENOUSER,      "No such user" },
+       { EOPTNEG,      "Option negotiation" },
+       { -1,           NULL }
+};
+
+#define DROPPACKET(s)                                                  \
+       if (packetdroppercentage != 0 &&                                \
+           random()%100 < packetdroppercentage) {                      \
+               tftp_log(LOG_DEBUG, "Artifical packet drop in %s", s);  \
+               return;                                                 \
+       }
+#define DROPPACKETn(s,n)                                               \
+       if (packetdroppercentage != 0 &&                                \
+           random()%100 < packetdroppercentage) {                      \
+               tftp_log(LOG_DEBUG, "Artifical packet drop in %s", s);  \
+               return (n);                                             \
+       }
+
+const char *
+errtomsg(int error)
+{
+       static char ebuf[40];
+       struct errmsg *pe;
+       char buf[MAXPKTSIZE];
+
+       if (error == 0)
+               return ("success");
+       for (pe = errmsgs; pe->e_code >= 0; pe++)
+               if (pe->e_code == error)
+                       return (pe->e_msg);
+       snprintf(ebuf, sizeof(buf), "error %d", error);
+       return (ebuf);
+}
+
+static int
+send_packet(int peer, uint16_t block, char *pkt, int size)
+{
+       int i;
+       int t = 1;
+
+       for (i = 0; i < 12 ; i++) {
+               DROPPACKETn("send_packet", 0);
+
+               if (sendto(peer, pkt, size, 0,
+                       (struct sockaddr *)&peer_sock, peer_sock.ss_len)
+                       == size) {
+                       if (i)
+                               tftp_log(LOG_ERR,
+                                   "%s block %d, attempt %d successful",
+                                   block, i);
+                       return (0);
+               }
+               tftp_log(LOG_ERR,
+                   "%s block %d, attempt %d failed (Error %d: %s)", 
+                   packettype(ntohs(((struct tftphdr *)(pkt))->th_opcode)),
+                   block, i, errno, strerror(errno));
+               sleep(t);
+               if (t < 32)
+                       t <<= 1;
+       }
+       tftp_log(LOG_ERR, "send_packet: %s", strerror(errno));
+       return (1);
+}
+
+/*
+ * Send an ERROR packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+void
+send_error(int peer, int error)
+{
+       struct tftphdr *tp;
+       int length;
+       struct errmsg *pe;
+       char buf[MAXPKTSIZE];
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error);
+
+       DROPPACKET("send_error");
+
+       tp = (struct tftphdr *)buf;
+       tp->th_opcode = htons((u_short)ERROR);
+       tp->th_code = htons((u_short)error);
+       for (pe = errmsgs; pe->e_code >= 0; pe++)
+               if (pe->e_code == error)
+                       break;
+       if (pe->e_code < 0) {
+               pe->e_msg = strerror(error - 100);
+               tp->th_code = EUNDEF;   /* set 'undef' errorcode */
+       }
+       strcpy(tp->th_msg, pe->e_msg);
+       length = strlen(pe->e_msg);
+       tp->th_msg[length] = '\0';
+       length += 5;
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
+
+       if (sendto(peer, buf, length, 0,
+               (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
+               tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
+}
+
+/*
+ * Send an WRQ packet (write request).
+ */
+int
+send_wrq(int peer, char *filename, char *mode)
+{
+       int n;
+       struct tftphdr *tp;
+       char *bp;
+       char buf[MAXPKTSIZE];
+       int size;
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending WRQ: filename: '%s', mode '%s'",
+                       filename, mode
+               );
+
+       DROPPACKETn("send_wrq", 1);
+
+       tp = (struct tftphdr *)buf;
+       tp->th_opcode = htons((u_short)WRQ);
+       size = 2;
+
+       bp = tp->th_stuff;
+       strcpy(bp, filename);
+       bp += strlen(filename);
+       *bp = 0;
+       bp++;
+       size += strlen(filename) + 1;
+
+       strcpy(bp, mode);
+       bp += strlen(mode);
+       *bp = 0;
+       bp++;
+       size += strlen(mode) + 1;
+
+       if (options_rfc_enabled)
+               size += make_options(peer, bp, sizeof(buf) - size);
+
+       n = sendto(peer, buf, size, 0,
+           (struct sockaddr *)&peer_sock, peer_sock.ss_len);
+       if (n != size) {
+               tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * Send an RRQ packet (write request).
+ */
+int
+send_rrq(int peer, char *filename, char *mode)
+{
+       int n;
+       struct tftphdr *tp;
+       char *bp;
+       char buf[MAXPKTSIZE];
+       int size;
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending RRQ: filename: '%s', mode '%s'",
+                       filename, mode
+               );
+
+       DROPPACKETn("send_rrq", 1);
+
+       tp = (struct tftphdr *)buf;
+       tp->th_opcode = htons((u_short)RRQ);
+       size = 2;
+
+       bp = tp->th_stuff;
+       strcpy(bp, filename);
+       bp += strlen(filename);
+       *bp = 0;
+       bp++;
+       size += strlen(filename) + 1;
+
+       strcpy(bp, mode);
+       bp += strlen(mode);
+       *bp = 0;
+       bp++;
+       size += strlen(mode) + 1;
+
+       if (options_rfc_enabled) {
+               options[OPT_TSIZE].o_request = strdup("0");
+               size += make_options(peer, bp, sizeof(buf) - size);
+       }
+
+       n = sendto(peer, buf, size, 0,
+           (struct sockaddr *)&peer_sock, peer_sock.ss_len);
+       if (n != size) {
+               tftp_log(LOG_ERR, "send_rrq: %s", n, strerror(errno));
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * Send an OACK packet (option acknowledgement).
+ */
+int
+send_oack(int peer)
+{
+       struct tftphdr *tp;
+       int size, i, n;
+       char *bp;
+       char buf[MAXPKTSIZE];
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending OACK");
+
+       DROPPACKETn("send_oack", 0);
+
+       /*
+        * Send back an options acknowledgement (only the ones with
+        * a reply for)
+        */
+       tp = (struct tftphdr *)buf;
+       bp = buf + 2;
+       size = sizeof(buf) - 2;
+       tp->th_opcode = htons((u_short)OACK);
+       for (i = 0; options[i].o_type != NULL; i++) {
+               if (options[i].o_reply != NULL) {
+                       n = snprintf(bp, size, "%s%c%s", options[i].o_type,
+                                    0, options[i].o_reply);
+                       bp += n+1;
+                       size -= n+1;
+                       if (size < 0) {
+                               tftp_log(LOG_ERR, "oack: buffer overflow");
+                               exit(1);
+                       }
+               }
+       }
+       size = bp - buf;
+
+       if (sendto(peer, buf, size, 0,
+               (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
+               tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
+               return (1);
+       }
+
+       return (0);
+}
+
+/*
+ * Send an ACK packet (acknowledgement).
+ */
+int
+send_ack(int fp, uint16_t block)
+{
+       struct tftphdr *tp;
+       int size;
+       char *bp;
+       char buf[MAXPKTSIZE];
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending ACK for block %d", block);
+
+       DROPPACKETn("send_ack", 0);
+
+       tp = (struct tftphdr *)buf;
+       bp = buf + 2;
+       size = sizeof(buf) - 2;
+       tp->th_opcode = htons((u_short)ACK);
+       tp->th_block = htons((u_short)block);
+       size = 4;
+
+       if (sendto(fp, buf, size, 0,
+           (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
+               tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
+               return (1);
+       }
+
+       return (0);
+}
+
+/*
+ * Send a DATA packet
+ */
+int
+send_data(int peer, uint16_t block, char *data, int size)
+{
+       char buf[MAXPKTSIZE];
+       struct tftphdr *pkt;
+       int n;
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Sending DATA packet %d of %d bytes",
+                       block, size);
+
+       DROPPACKETn("send_data", 0);
+
+       pkt = (struct tftphdr *)buf;
+
+       pkt->th_opcode = htons((u_short)DATA);
+       pkt->th_block = htons((u_short)block);
+       memcpy(pkt->th_data, data, size);
+
+       n = send_packet(peer, block, (char *)pkt, size + 4);
+       return (n);
+}
+
+
+/*
+ * Receive a packet
+ */
+jmp_buf        timeoutbuf;
+
+static void
+timeout(int sig __unused)
+{
+
+       /* tftp_log(LOG_DEBUG, "Timeout\n");    Inside a signal handler... */
+       longjmp(timeoutbuf, 1);
+}
+
+int
+receive_packet(int peer, char *data, int size, struct sockaddr_storage *from,
+    int thistimeout)
+{
+       struct tftphdr *pkt;
+       struct sockaddr_storage from_local;
+       struct sockaddr_storage *pfrom;
+       socklen_t fromlen;
+       int n;
+       static int waiting;
+
+       pfrom = (from == NULL) ? &from_local : from;
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG,
+                   "Waiting %d seconds for packet", timeoutpacket);
+
+       pkt = (struct tftphdr *)data;
+
+       waiting = 0;
+       signal(SIGALRM, timeout);
+       setjmp(timeoutbuf);
+       alarm(thistimeout);
+
+       if (waiting > 0) {
+               alarm(0);
+               return (RP_TIMEOUT);
+       }
+
+       if (waiting > 0) {
+               tftp_log(LOG_ERR, "receive_packet: timeout");
+               alarm(0);
+               return (RP_TIMEOUT);
+       }
+
+       waiting++;
+       fromlen = sizeof(*pfrom);
+       n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
+
+       alarm(0);
+
+       DROPPACKETn("receive_packet", RP_TIMEOUT);
+
+       if (n < 0) {
+               tftp_log(LOG_ERR, "receive_packet: timeout");
+               return (RP_TIMEOUT);
+       }
+
+       alarm(0);
+
+       if (n < 0) {
+               /* No idea what could have happened if it isn't a timeout */
+               tftp_log(LOG_ERR, "receive_packet: %s", strerror(errno));
+               return (RP_RECVFROM);
+       }
+       if (n < 4) {
+               tftp_log(LOG_ERR,
+                   "receive_packet: packet too small (%d bytes)", n);
+               return (RP_TOOSMALL);
+       }
+
+       pkt->th_opcode = ntohs((u_short)pkt->th_opcode);
+       if (pkt->th_opcode == DATA ||
+           pkt->th_opcode == ACK)
+               pkt->th_block = ntohs((u_short)pkt->th_block);
+
+       if (pkt->th_opcode == DATA && n > pktsize) {
+               tftp_log(LOG_ERR, "receive_packet: packet too big");
+               return (RP_TOOBIG);
+       }
+
+       if (((struct sockaddr_in *)(pfrom))->sin_addr.s_addr !=
+           ((struct sockaddr_in *)(&peer_sock))->sin_addr.s_addr) {
+               tftp_log(LOG_ERR,
+                       "receive_packet: received packet from wrong source");
+               return (RP_WRONGSOURCE);
+       }
+
+       if (pkt->th_opcode == ERROR) {
+               tftp_log(LOG_ERR, "Got ERROR packet: %s", pkt->th_msg);
+               return (RP_ERROR);
+       }
+
+       if (debug&DEBUG_PACKETS)
+               tftp_log(LOG_DEBUG, "Received %d bytes in a %s packet",
+                       n, packettype(pkt->th_opcode));
+
+       return n - 4;
+}

Added: head/libexec/tftpd/tftp-io.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/libexec/tftpd/tftp-io.h        Tue May  4 13:07:40 2010        
(r207614)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define RP_NONE                0
+#define        RP_RECVFROM     -1
+#define        RP_TOOSMALL     -2
+#define RP_ERROR       -3
+#define RP_WRONGSOURCE -4
+#define        RP_TIMEOUT      -5
+#define        RP_TOOBIG       -6
+
+const char *errtomsg(int);
+void   send_error(int peer, int);
+int    send_wrq(int peer, char *, char *);
+int    send_rrq(int peer, char *, char *);
+int    send_oack(int peer);
+int    send_ack(int peer, unsigned short);
+int    send_data(int peer, uint16_t, char *, int);
+int    receive_packet(int peer, char *, int, struct sockaddr_storage *, int);
+
+extern struct sockaddr_storage peer_sock;
+extern struct sockaddr_storage me_sock;

Added: head/libexec/tftpd/tftp-options.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/libexec/tftpd/tftp-options.c   Tue May  4 13:07:40 2010        
(r207614)
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "tftp-utils.h"
+#include "tftp-io.h"
+#include "tftp-options.h"
+
+/*
+ * Option handlers
+ */
+
+struct options options[] = {
+       { "tsize",      NULL, NULL, NULL /* option_tsize */, 1 },
+       { "timeout",    NULL, NULL, option_timeout, 1 },
+       { "blksize",    NULL, NULL, option_blksize, 1 },
+       { "blksize2",   NULL, NULL, option_blksize2, 0 },
+       { "rollover",   NULL, NULL, option_rollover, 0 },
+       { NULL,         NULL, NULL, NULL, 0 }
+};
+
+/* By default allow them */
+int options_rfc_enabled = 1;
+int options_extra_enabled = 1;
+
+/*
+ * Rules for the option handlers:
+ * - If there is no o_request, there will be no processing.
+ *
+ * For servers
+ * - Logging is done as warnings.
+ * - The handler exit()s if there is a serious problem with the
+ *   values submitted in the option.
+ *
+ * For clients
+ * - Logging is done as errors. After all, the server shouldn't
+ *   return rubbish.
+ * - The handler returns if there is a serious problem with the
+ *   values submitted in the option.
+ * - Sending the EBADOP packets is done by the handler.
+ */
+
+int
+option_tsize(int peer, struct tftphdr *tp, int mode, struct stat *stbuf)
+{
+
+       if (options[OPT_TSIZE].o_request == NULL)
+               return (0);
+
+       if (mode == RRQ) 
+               asprintf(&options[OPT_TSIZE].o_reply,
+                       "%ju", stbuf->st_size);
+       else
+               /* XXX Allows writes of all sizes. */
+               options[OPT_TSIZE].o_reply =
+                       strdup(options[OPT_TSIZE].o_request);
+       return (0);
+}
+
+int
+option_timeout(int peer)
+{
+
+       if (options[OPT_TIMEOUT].o_request == NULL)
+               return (0);
+
+       int to = atoi(options[OPT_TIMEOUT].o_request);
+       if (to < TIMEOUT_MIN || to > TIMEOUT_MAX) {
+               tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING,
+                   "Received bad value for timeout. "
+                   "Should be between %d and %d, received %s",
+                   TIMEOUT_MIN, TIMEOUT_MAX);
+               send_error(peer, EBADOP);
+               if (acting_as_client)
+                       return (1);
+               exit(1);
+       } else {
+               timeoutpacket = to;
+               options[OPT_TIMEOUT].o_reply =
+                       strdup(options[OPT_TIMEOUT].o_request);
+       }
+       settimeouts(timeoutpacket, timeoutnetwork, maxtimeouts);
+
+       if (debug&DEBUG_OPTIONS)
+               tftp_log(LOG_DEBUG, "Setting timeout to '%s'",
+                       options[OPT_TIMEOUT].o_reply);
+
+       return (0);
+}
+
+int
+option_rollover(int peer)
+{
+
+       if (options[OPT_ROLLOVER].o_request == NULL)
+               return (0);
+
+       if (strcmp(options[OPT_ROLLOVER].o_request, "0") != 0
+        && strcmp(options[OPT_ROLLOVER].o_request, "1") != 0) {
+               tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING,
+                   "Bad value for rollover, "
+                   "should be either 0 or 1, received '%s', "
+                   "ignoring request",
+                   options[OPT_ROLLOVER].o_request);
+               if (acting_as_client) {
+                       send_error(peer, EBADOP);
+                       return (1);
+               }
+               return (0);
+       }
+       options[OPT_ROLLOVER].o_reply =
+               strdup(options[OPT_ROLLOVER].o_request);
+
+       if (debug&DEBUG_OPTIONS)
+               tftp_log(LOG_DEBUG, "Setting rollover to '%s'",
+                       options[OPT_ROLLOVER].o_reply);
+
+       return (0);
+}
+
+int
+option_blksize(int peer)
+{
+       int *maxdgram;
+       char maxbuffer[100];
+       size_t len;
+
+       if (options[OPT_BLKSIZE].o_request == NULL)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to