svn commit: r207614 - head/libexec/tftpd
Warner Losh
imp at FreeBSD.org
Tue May 4 13:07:40 UTC 2010
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 ***
More information about the svn-src-head
mailing list