Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 May 2010 08:08:21 GMT
From:      Gabor Pali <pgj@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 177699 for review
Message-ID:  <201005040808.o4488LZV063120@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@177699?ac=10

Change 177699 by pgj@csupor on 2010/05/04 08:07:48

	IFC

Affected files ...

.. //depot/projects/soc2009/pgj_libstat/src/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/contrib/tzcode/zic/private.h#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/etc/network.subr#4 integrate
.. //depot/projects/soc2009/pgj_libstat/src/lib/libc/sys/getrusage.2#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/Makefile#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/tftpd.8#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/tftpd.c#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/share/man/man4/cas.4#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/dev/cas/if_cas.c#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/dev/cas/if_casreg.h#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/dev/isp/isp_pci.c#4 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/dev/isp/isp_sbus.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/dev/md/md.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/fs/nfsclient/nfs_clbio.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/fs/nwfs/nwfs_io.c#4 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/fs/smbfs/smbfs_io.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/kern/kern_proc.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/kern/kern_resource.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/kern/kern_thread.c#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/nfsclient/nfs_bio.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/sys/proc.h#7 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/sys/resource.h#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/sys/resourcevar.h#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/vm/phys_pager.c#3 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/vm/uma_core.c#5 integrate
.. //depot/projects/soc2009/pgj_libstat/src/sys/vm/vm_page.c#7 integrate
.. //depot/projects/soc2009/pgj_libstat/src/usr.bin/tftp/Makefile#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/usr.bin/tftp/main.c#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/usr.bin/tftp/tftp.1#2 integrate
.. //depot/projects/soc2009/pgj_libstat/src/usr.bin/tftp/tftp.c#3 integrate

Differences ...

==== //depot/projects/soc2009/pgj_libstat/src/cddl/contrib/opensolaris/tools/ctf/cvt/ctf.c#2 (text+ko) ====

@@ -355,14 +355,21 @@
 		for (i = 0, ep = tp->t_emem; ep != NULL; ep = ep->el_next)
 			i++; /* count up enum members */
 
+		if (i > CTF_MAX_VLEN) {
+			warning("enum %s has too many values: %d > %d\n",
+			    tdesc_name(tp), i, CTF_MAX_VLEN);
+			i = CTF_MAX_VLEN;
+		}
+
 		ctt.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, isroot, i);
 		write_sized_type_rec(b, &ctt, tp->t_size);
 
-		for (ep = tp->t_emem; ep != NULL; ep = ep->el_next) {
+		for (ep = tp->t_emem; ep != NULL && i > 0; ep = ep->el_next) {
 			offset = strtab_insert(&b->ctb_strtab, ep->el_name);
 			cte.cte_name = CTF_TYPE_NAME(CTF_STRTAB_0, offset);
 			cte.cte_value = ep->el_number;
 			ctf_buf_write(b, &cte, sizeof (cte));
+			i--;
 		}
 		break;
 

==== //depot/projects/soc2009/pgj_libstat/src/contrib/tzcode/zic/private.h#2 (text+ko) ====

@@ -13,7 +13,7 @@
  * I have removed all of the ifdef spaghetti which is not relevant to
  * zic from this file.
  *
- * $FreeBSD: src/contrib/tzcode/zic/private.h,v 1.1 2010/02/25 06:53:46 edwin Exp $
+ * $FreeBSD: src/contrib/tzcode/zic/private.h,v 1.2 2010/05/03 22:32:26 emaste Exp $
  */
 
 /*
@@ -34,7 +34,7 @@
 #endif /* !defined NOID */
 #endif /* !defined lint */
 
-#define GRANDPARENTED	"Local time zone must be set--see zic manual page"
+#define GRANDPARENTED	"Local time zone must be set--use tzsetup"
 
 /*
 ** Defaults for preprocessor symbols.

==== //depot/projects/soc2009/pgj_libstat/src/etc/network.subr#4 (text+ko) ====

@@ -22,7 +22,7 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/etc/network.subr,v 1.207 2010/04/09 01:35:09 dougb Exp $
+# $FreeBSD: src/etc/network.subr,v 1.208 2010/05/04 01:46:58 dougb Exp $
 #
 
 #
@@ -399,6 +399,8 @@
 	$_if|"$_if "*|*" $_if"|*" $_if "*|[Aa][Uu][Tt][Oo])
 		# True if $ifconfig_IF_ipv6 is defined.
 		_tmpargs=`_ifconfig_getargs $_if ipv6`
+		# Also true if ipv6_prefix_IF is defined
+		[ -n "$_tmpargs" ] || _tmpargs=`get_if_var $_if ipv6_prefix_IF`
 		;;
 	esac
 

==== //depot/projects/soc2009/pgj_libstat/src/lib/libc/sys/getrusage.2#2 (text+ko) ====

@@ -26,9 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)getrusage.2	8.1 (Berkeley) 6/4/93
-.\" $FreeBSD: src/lib/libc/sys/getrusage.2,v 1.22 2007/01/09 00:28:14 imp Exp $
+.\" $FreeBSD: src/lib/libc/sys/getrusage.2,v 1.23 2010/05/04 06:01:25 kib Exp $
 .\"
-.Dd June 4, 1993
+.Dd May 1, 2010
 .Dt GETRUSAGE 2
 .Os
 .Sh NAME
@@ -42,6 +42,7 @@
 .In sys/resource.h
 .Fd "#define	RUSAGE_SELF	 0"
 .Fd "#define	RUSAGE_CHILDREN	-1"
+.Fd "#define	RUSAGE_THREAD	1"
 .Ft int
 .Fn getrusage "int who" "struct rusage *rusage"
 .Sh DESCRIPTION
@@ -49,11 +50,12 @@
 .Fn getrusage
 system call
 returns information describing the resources utilized by the current
-process, or all its terminated child processes.
+thread, the current process, or all its terminated child processes.
 The
 .Fa who
 argument is either
-.Dv RUSAGE_SELF
+.Dv RUSAGE_THREAD ,
+.Dv RUSAGE_SELF ,
 or
 .Dv RUSAGE_CHILDREN .
 The buffer to which
@@ -175,6 +177,10 @@
 .Fn getrusage
 system call appeared in
 .Bx 4.2 .
+The
+.Dv RUSAGE_THREAD
+facility first appeared in
+.Fx 8.1 .
 .Sh BUGS
 There is no way to obtain information about a child process
 that has not yet terminated.

==== //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/Makefile#3 (text+ko) ====

@@ -1,16 +1,15 @@
 #	@(#)Makefile	8.1 (Berkeley) 6/4/93
-# $FreeBSD: src/libexec/tftpd/Makefile,v 1.11 2010/01/02 09:50:19 ed Exp $
+# $FreeBSD: src/libexec/tftpd/Makefile,v 1.12 2010/05/04 06:19:19 imp Exp $
 
 PROG=	tftpd
-SRCS=	tftpd.c tftpsubs.c
-DPADD=	${LIBUTIL}
-LDADD=	-lutil
-
-WARNS?=	1
+SRCS=	tftpd.c tftp-io.c tftp-utils.c tftp-file.c tftp-transfer.c tftp-options.c
+WARNS=	3
 WFORMAT=0
-
 MAN=	tftpd.8
-CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
+CFLAGS=-g -Wall
+CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp -I${.CURDIR}/../../libexec/tftpd
 .PATH:	${.CURDIR}/../../usr.bin/tftp
+COPTFLAGS = -O
+LDFLAGS= -lwrap
 
 .include <bsd.prog.mk>

==== //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/tftpd.8#3 (text+ko) ====

@@ -30,7 +30,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"	@(#)tftpd.8	8.1 (Berkeley) 6/4/93
-.\" $FreeBSD: src/libexec/tftpd/tftpd.8,v 1.24 2010/03/12 10:01:06 uqs Exp $
+.\" $FreeBSD: src/libexec/tftpd/tftpd.8,v 1.25 2010/05/04 06:19:19 imp Exp $
 .\"
 .Dd September 14, 2000
 .Dt TFTPD 8
@@ -40,7 +40,7 @@
 .Nd Internet Trivial File Transfer Protocol server
 .Sh SYNOPSIS
 .Nm tftpd
-.Op Fl cClnwW
+.Op Fl cdClnow
 .Op Fl F Ar strftime-format
 .Op Fl s Ar directory
 .Op Fl u Ar user
@@ -150,6 +150,9 @@
 .Fl W
 is specified.
 By default the string "%Y%m%d" is used.
+.It Fl d
+Enables debug output.
+If specified twice, it will log DATA and ACK packets too.
 .It Fl l
 Log all requests using
 .Xr syslog 3
@@ -164,6 +167,8 @@
 .It Fl n
 Suppress negative acknowledgement of requests for nonexistent
 relative filenames.
+.It Fl o
+Disable support for RFC2347 style TFTP Options.
 .It Fl s Ar directory
 Cause
 .Nm
@@ -240,10 +245,16 @@
 and
 .Fl W
 options were introduced in
-.Fx 8.0 .
+.Fx 7 .
 .Pp
+Support for Timeout Interval and Transfer Size Options (RFC2349)
+was introduced in
+.Fx 5.0 ,
+support for the TFTP Blocksize Option (RFC2348) and the blksize2 option
+was introduced in
+.Fx 7 .
 .Sh BUGS
 Files larger than 33488896 octets (65535 blocks) cannot be transferred
-without client and server supporting blocksize negotiation (RFC1783).
+without client and server supporting blocksize negotiation (RFC2348).
 .Pp
 Many tftp clients will not transfer files over 16744448 octets (32767 blocks).

==== //depot/projects/soc2009/pgj_libstat/src/libexec/tftpd/tftpd.c#2 (text+ko) ====

@@ -41,9 +41,9 @@
 #if 0
 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
 #endif
-static const char rcsid[] =
-  "$FreeBSD: src/libexec/tftpd/tftpd.c,v 1.38 2007/11/23 00:05:29 edwin Exp $";
 #endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/libexec/tftpd/tftpd.c,v 1.39 2010/05/04 06:19:19 imp Exp $");
 
 /*
  * Trivial file transfer protocol server.
@@ -56,43 +56,30 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/time.h>
 
 #include <netinet/in.h>
 #include <arpa/tftp.h>
-#include <arpa/inet.h>
 
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <libutil.h>
 #include <netdb.h>
 #include <pwd.h>
-#include <setjmp.h>
-#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
+#include <tcpd.h>
 #include <unistd.h>
 
-#include "tftpsubs.h"
+#include "tftp-file.h"
+#include "tftp-io.h"
+#include "tftp-utils.h"
+#include "tftp-transfer.h"
+#include "tftp-options.h"
 
-#define	TIMEOUT		5
-#define	MAX_TIMEOUTS	5
-
-int	peer;
-int	rexmtval = TIMEOUT;
-int	max_rexmtval = 2*TIMEOUT;
-
-#define	PKTSIZE	SEGSIZE+4
-char	buf[PKTSIZE];
-char	ackbuf[PKTSIZE];
-struct	sockaddr_storage from;
-
-void	tftp(struct tftphdr *, int);
-static void unmappedaddr(struct sockaddr_in6 *);
+static void	tftp_wrq(int peer, char *, ssize_t);
+static void	tftp_rrq(int peer, char *, ssize_t);
 
 /*
  * Null-terminated directory prefix list for absolute pathname requests and
@@ -112,31 +99,44 @@
 static int	create_new = 0;
 static char	*newfile_format = "%Y%m%d";
 static int	increase_name = 0;
-static mode_t	mask = S_IWGRP|S_IWOTH;
+static mode_t	mask = S_IWGRP | S_IWOTH;
+
+struct formats;
+static void	tftp_recvfile(int peer, const char *mode);
+static void	tftp_xmitfile(int peer, const char *mode);
+static int	validate_access(int peer, char **, int);
+static char	peername[NI_MAXHOST];
 
-static const char *errtomsg(int);
-static void  nak(int);
-static void  oack(void);
+FILE *file;
 
-static void  timer(int);
-static void  justquit(int);
+struct formats {
+	const char	*f_mode;
+	int	f_convert;
+} formats[] = {
+	{ "netascii",	1 },
+	{ "octet",	0 },
+	{ NULL,		0 }
+};
 
 int
 main(int argc, char *argv[])
 {
 	struct tftphdr *tp;
-	socklen_t fromlen, len;
-	int n;
-	int ch, on;
-	struct sockaddr_storage me;
-	char *chroot_dir = NULL;
-	struct passwd *nobody;
-	const char *chuser = "nobody";
+	int		peer;
+	socklen_t	peerlen, len;
+	ssize_t		n;
+	int		ch;
+	char		*chroot_dir = NULL;
+	struct passwd	*nobody;
+	const char	*chuser = "nobody";
+	char		recvbuffer[MAXPKTSIZE];
+	int		allow_ro = 1, allow_wo = 1;
 
 	tzset();			/* syslog in localtime */
+	acting_as_client = 0;
 
-	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
-	while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
+	tftp_openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+	while ((ch = getopt(argc, argv, "cCd:F:lnoOp:s:u:U:wW")) != -1) {
 		switch (ch) {
 		case 'c':
 			ipchroot = 1;
@@ -144,6 +144,12 @@
 		case 'C':
 			ipchroot = 2;
 			break;
+		case 'd':
+			if (atoi(optarg) != 0)
+				debug += atoi(optarg);
+			else
+				debug |= debug_finds(optarg);
+			break;
 		case 'F':
 			newfile_format = optarg;
 			break;
@@ -153,6 +159,18 @@
 		case 'n':
 			suppress_naks = 1;
 			break;
+		case 'o':
+			options_rfc_enabled = 0;
+			break;
+		case 'O':
+			options_extra_enabled = 0;
+			break;
+		case 'p':
+			packetdroppercentage = atoi(optarg);
+			tftp_log(LOG_INFO,
+			    "Randomly dropping %d out of 100 packets",
+			    packetdroppercentage);
+			break;
 		case 's':
 			chroot_dir = optarg;
 			break;
@@ -170,7 +188,8 @@
 			increase_name = 1;
 			break;
 		default:
-			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
+			tftp_log(LOG_WARNING,
+				"ignoring unknown option -%c", ch);
 		}
 	}
 	if (optind < argc) {
@@ -191,24 +210,31 @@
 		dirs->len = 1;
 	}
 	if (ipchroot > 0 && chroot_dir == NULL) {
-		syslog(LOG_ERR, "-c requires -s");
+		tftp_log(LOG_ERR, "-c requires -s");
 		exit(1);
 	}
 
 	umask(mask);
 
-	on = 1;
-	if (ioctl(0, FIONBIO, &on) < 0) {
-		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
-		exit(1);
+	{
+		int on = 1;
+		if (ioctl(0, FIONBIO, &on) < 0) {
+			tftp_log(LOG_ERR, "ioctl(FIONBIO): %s", strerror(errno));
+			exit(1);
+		}
 	}
-	fromlen = sizeof (from);
-	n = recvfrom(0, buf, sizeof (buf), 0,
-	    (struct sockaddr *)&from, &fromlen);
+
+	/* Find out who we are talking to and what we are going to do */
+	peerlen = sizeof(peer_sock);
+	n = recvfrom(0, recvbuffer, MAXPKTSIZE, 0,
+	    (struct sockaddr *)&peer_sock, &peerlen);
 	if (n < 0) {
-		syslog(LOG_ERR, "recvfrom: %m");
+		tftp_log(LOG_ERR, "recvfrom: %s", strerror(errno));
 		exit(1);
 	}
+	getnameinfo((struct sockaddr *)&peer_sock, peer_sock.ss_len,
+	    peername, sizeof(peername), NULL, 0, NI_NUMERICHOST);
+
 	/*
 	 * Now that we have read the message out of the UDP
 	 * socket, we fork and exit.  Thus, inetd will go back
@@ -240,9 +266,9 @@
 				 * than one tftpd being started up to service
 				 * a single request from a single client.
 				 */
-				fromlen = sizeof from;
-				i = recvfrom(0, buf, sizeof (buf), 0,
-				    (struct sockaddr *)&from, &fromlen);
+				peerlen = sizeof peer_sock;
+				i = recvfrom(0, recvbuffer, MAXPKTSIZE, 0,
+				    (struct sockaddr *)&peer_sock, &peerlen);
 				if (i > 0) {
 					n = i;
 				}
@@ -251,7 +277,7 @@
 		    }
 		}
 		if (pid < 0) {
-			syslog(LOG_ERR, "fork: %m");
+			tftp_log(LOG_ERR, "fork: %s", strerror(errno));
 			exit(1);
 		} else if (pid != 0) {
 			exit(0);
@@ -259,6 +285,55 @@
 	}
 
 	/*
+	 * See if the client is allowed to talk to me.
+	 * (This needs to be done before the chroot())
+	 */
+	{
+		struct request_info req;
+
+		request_init(&req, RQ_CLIENT_ADDR, peername, 0);
+		request_set(&req, RQ_DAEMON, "tftpd", 0);
+
+		if (hosts_access(&req) == 0) {
+			if (debug&DEBUG_ACCESS)
+				tftp_log(LOG_WARNING,
+				    "Access denied by 'tftpd' entry "
+				    "in /etc/hosts.allow");
+
+			/*
+			 * Full access might be disabled, but maybe the
+			 * client is allowed to do read-only access.
+			 */
+			request_set(&req, RQ_DAEMON, "tftpd-ro", 0);
+			allow_ro = hosts_access(&req);
+
+			request_set(&req, RQ_DAEMON, "tftpd-wo", 0);
+			allow_wo = hosts_access(&req);
+
+			if (allow_ro == 0 && allow_wo == 0) {
+				tftp_log(LOG_WARNING,
+				    "Unauthorized access from %s", peername);
+				exit(1);
+			}
+
+			if (debug&DEBUG_ACCESS) {
+				if (allow_ro)
+					tftp_log(LOG_WARNING,
+					    "But allowed readonly access "
+					    "via 'tftpd-ro' entry");
+				if (allow_wo)
+					tftp_log(LOG_WARNING,
+					    "But allowed writeonly access "
+					    "via 'tftpd-wo' entry");
+			}
+		} else
+			if (debug&DEBUG_ACCESS)
+				tftp_log(LOG_WARNING,
+				    "Full access allowed"
+				    "in /etc/hosts.allow");
+	}
+
+	/*
 	 * Since we exit here, we should do that only after the above
 	 * recvfrom to keep inetd from constantly forking should there
 	 * be a problem.  See the above comment about system clogging.
@@ -271,7 +346,8 @@
 			struct sockaddr_storage ss;
 			char hbuf[NI_MAXHOST];
 
-			memcpy(&ss, &from, from.ss_len);
+			statret = -1;
+			memcpy(&ss, &peer_sock, peer_sock.ss_len);
 			unmappedaddr((struct sockaddr_in6 *)&ss);
 			getnameinfo((struct sockaddr *)&ss, ss.ss_len,
 				    hbuf, sizeof(hbuf), NULL, 0,
@@ -285,11 +361,12 @@
 		}
 		/* Must get this before chroot because /etc might go away */
 		if ((nobody = getpwnam(chuser)) == NULL) {
-			syslog(LOG_ERR, "%s: no such user", chuser);
+			tftp_log(LOG_ERR, "%s: no such user", chuser);
 			exit(1);
 		}
 		if (chroot(chroot_dir)) {
-			syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
+			tftp_log(LOG_ERR, "chroot: %s: %s",
+			    chroot_dir, strerror(errno));
 			exit(1);
 		}
 		chdir("/");
@@ -297,44 +374,56 @@
 		setuid(nobody->pw_uid);
 	}
 
-	len = sizeof(me);
-	if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
-		switch (me.ss_family) {
+	len = sizeof(me_sock);
+	if (getsockname(0, (struct sockaddr *)&me_sock, &len) == 0) {
+		switch (me_sock.ss_family) {
 		case AF_INET:
-			((struct sockaddr_in *)&me)->sin_port = 0;
+			((struct sockaddr_in *)&me_sock)->sin_port = 0;
 			break;
 		case AF_INET6:
-			((struct sockaddr_in6 *)&me)->sin6_port = 0;
+			((struct sockaddr_in6 *)&me_sock)->sin6_port = 0;
 			break;
 		default:
 			/* unsupported */
 			break;
 		}
 	} else {
-		memset(&me, 0, sizeof(me));
-		me.ss_family = from.ss_family;
-		me.ss_len = from.ss_len;
+		memset(&me_sock, 0, sizeof(me_sock));
+		me_sock.ss_family = peer_sock.ss_family;
+		me_sock.ss_len = peer_sock.ss_len;
 	}
-	alarm(0);
 	close(0);
 	close(1);
-	peer = socket(from.ss_family, SOCK_DGRAM, 0);
+	peer = socket(peer_sock.ss_family, SOCK_DGRAM, 0);
 	if (peer < 0) {
-		syslog(LOG_ERR, "socket: %m");
+		tftp_log(LOG_ERR, "socket: %s", strerror(errno));
 		exit(1);
 	}
-	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
-		syslog(LOG_ERR, "bind: %m");
+	if (bind(peer, (struct sockaddr *)&me_sock, me_sock.ss_len) < 0) {
+		tftp_log(LOG_ERR, "bind: %s", strerror(errno));
 		exit(1);
 	}
-	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
-		syslog(LOG_ERR, "connect: %m");
-		exit(1);
+
+	tp = (struct tftphdr *)recvbuffer;
+	tp->th_opcode = ntohs(tp->th_opcode);
+	if (tp->th_opcode == RRQ) {
+		if (allow_ro)
+			tftp_rrq(peer, tp->th_stuff, n - 1);
+		else {
+			tftp_log(LOG_WARNING,
+			    "%s read access denied", peername);
+			exit(1);
+		}
+	}
+	if (tp->th_opcode == WRQ) {
+		if (allow_wo)
+			tftp_wrq(peer, tp->th_stuff, n - 1);
+		else {
+			tftp_log(LOG_WARNING,
+			    "%s write access denied", peername);
+			exit(1);
+		}
 	}
-	tp = (struct tftphdr *)buf;
-	tp->th_opcode = ntohs(tp->th_opcode);
-	if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
-		tftp(tp, n);
 	exit(1);
 }
 
@@ -369,138 +458,145 @@
 	}
 }
 
-struct formats;
-int	validate_access(char **, int);
-void	xmitfile(struct formats *);
-void	recvfile(struct formats *);
+static char *
+parse_header(int peer, char *recvbuffer, ssize_t size,
+	char **filename, char **mode)
+{
+	char	*cp;
+	int	i;
+	struct formats *pf;
+
+	*mode = NULL;
+	cp = recvbuffer;
+
+	i = get_field(peer, recvbuffer, size);
+	if (i >= PATH_MAX) {
+		tftp_log(LOG_ERR, "Bad option - filename too long");
+		send_error(peer, EBADOP);
+		exit(1);
+	}
+	*filename = recvbuffer;
+	tftp_log(LOG_INFO, "Filename: '%s'", *filename);
+	cp += i;
 
-struct formats {
-	const char	*f_mode;
-	int	(*f_validate)(char **, int);
-	void	(*f_send)(struct formats *);
-	void	(*f_recv)(struct formats *);
-	int	f_convert;
-} formats[] = {
-	{ "netascii",	validate_access,	xmitfile,	recvfile, 1 },
-	{ "octet",	validate_access,	xmitfile,	recvfile, 0 },
-#ifdef notdef
-	{ "mail",	validate_user,		sendmail,	recvmail, 1 },
-#endif
-	{ 0,		NULL,			NULL,		NULL,	  0 }
-};
+	i = get_field(peer, cp, size);
+	*mode = cp;
+	cp += i;
 
-struct options {
-	const char	*o_type;
-	char	*o_request;
-	int	o_reply;	/* turn into union if need be */
-} options[] = {
-	{ "tsize",	NULL, 0 },		/* OPT_TSIZE */
-	{ "timeout",	NULL, 0 },		/* OPT_TIMEOUT */
-	{ NULL,		NULL, 0 }
-};
+	/* Find the file transfer mode */
+	for (cp = *mode; *cp; cp++)
+		if (isupper(*cp))
+			*cp = tolower(*cp);
+	for (pf = formats; pf->f_mode; pf++)
+		if (strcmp(pf->f_mode, *mode) == 0)
+			break;
+	if (pf->f_mode == NULL) {
+		tftp_log(LOG_ERR,
+		    "Bad option - Unknown transfer mode (%s)", *mode);
+		send_error(peer, EBADOP);
+		exit(1);
+	}
+	tftp_log(LOG_INFO, "Mode: '%s'", *mode);
 
-enum opt_enum {
-	OPT_TSIZE = 0,
-	OPT_TIMEOUT,
-};
+	return (cp + 1);
+}
 
 /*
- * Handle initial connection protocol.
+ * WRQ - receive a file from the client
  */
 void
-tftp(struct tftphdr *tp, int size)
+tftp_wrq(int peer, char *recvbuffer, ssize_t size)
 {
 	char *cp;
-	int i, first = 1, has_options = 0, ecode;
-	struct formats *pf;
-	char *filename, *mode, *option, *ccp;
+	int has_options = 0, ecode;
+	char *filename, *mode;
 	char fnbuf[PATH_MAX];
 
-	cp = tp->th_stuff;
-again:
-	while (cp < buf + size) {
-		if (*cp == '\0')
-			break;
-		cp++;
+	cp = parse_header(peer, recvbuffer, size, &filename, &mode);
+	size -= (cp - recvbuffer) + 1;
+
+	strcpy(fnbuf, filename);
+	reduce_path(fnbuf);
+	filename = fnbuf;
+
+	if (size > 0) {
+		if (options_rfc_enabled)
+			has_options = !parse_options(peer, cp, size);
+		else
+			tftp_log(LOG_INFO, "Options found but not enabled");
 	}
-	if (*cp != '\0') {
-		nak(EBADOP);
-		exit(1);
+
+	ecode = validate_access(peer, &filename, WRQ);
+	if (ecode == 0) {
+		if (has_options)
+			send_oack(peer);
+		else
+			send_ack(peer, 0);
 	}
-	i = cp - tp->th_stuff;
-	if (i >= sizeof(fnbuf)) {
-		nak(EBADOP);
-		exit(1);
+	if (logging) {
+		tftp_log(LOG_INFO, "%s: write request for %s: %s", peername,
+			    filename, errtomsg(ecode));
 	}
-	memcpy(fnbuf, tp->th_stuff, i);
-	fnbuf[i] = '\0';
+
+	tftp_recvfile(peer, mode);
+	exit(0);
+}
+
+/*
+ * RRQ - send a file to the client
+ */
+void
+tftp_rrq(int peer, char *recvbuffer, ssize_t size)
+{
+	char *cp;
+	int has_options = 0, ecode;
+	char *filename, *mode;
+	char	fnbuf[PATH_MAX];
+
+	cp = parse_header(peer, recvbuffer, size, &filename, &mode);
+	size -= (cp - recvbuffer) + 1;
+
+	strcpy(fnbuf, filename);
 	reduce_path(fnbuf);
 	filename = fnbuf;
-	if (first) {
-		mode = ++cp;
-		first = 0;
-		goto again;
+
+	if (size > 0) {
+		if (options_rfc_enabled)
+			has_options = !parse_options(peer, cp, size);
+		else
+			tftp_log(LOG_INFO, "Options found but not enabled");
 	}
-	for (cp = mode; *cp; cp++)
-		if (isupper(*cp))
-			*cp = tolower(*cp);
-	for (pf = formats; pf->f_mode; pf++)
-		if (strcmp(pf->f_mode, mode) == 0)
-			break;
-	if (pf->f_mode == 0) {
-		nak(EBADOP);
-		exit(1);
-	}
-	while (++cp < buf + size) {
-		for (i = 2, ccp = cp; i > 0; ccp++) {
-			if (ccp >= buf + size) {
-				/*
-				 * Don't reject the request, just stop trying
-				 * to parse the option and get on with it.
-				 * Some Apple Open Firmware versions have
-				 * trailing garbage on the end of otherwise
-				 * valid requests.
-				 */
-				goto option_fail;
-			} else if (*ccp == '\0')
-				i--;
-		}
-		for (option = cp; *cp; cp++)
-			if (isupper(*cp))
-				*cp = tolower(*cp);
-		for (i = 0; options[i].o_type != NULL; i++)
-			if (strcmp(option, options[i].o_type) == 0) {
-				options[i].o_request = ++cp;
-				has_options = 1;
+
+	ecode = validate_access(peer, &filename, RRQ);
+	if (ecode == 0) {
+		if (has_options) {
+			int n;
+			char lrecvbuffer[MAXPKTSIZE];
+			struct tftphdr *rp = (struct tftphdr *)lrecvbuffer;
+
+			send_oack(peer);
+			n = receive_packet(peer, lrecvbuffer, MAXPKTSIZE,
+				NULL, timeoutpacket);
+			if (n < 0) {
+				if (debug&DEBUG_SIMPLE)
+					tftp_log(LOG_DEBUG, "Aborting: %s",
+					    rp_strerror(n));
+				return;
+			}
+			if (rp->th_opcode != ACK) {
+				if (debug&DEBUG_SIMPLE)
+					tftp_log(LOG_DEBUG,
+					    "Expected ACK, got %s on OACK",
+					    packettype(rp->th_opcode));
+				return;
 			}
-		cp = ccp-1;
-	}
-
-option_fail:
-	if (options[OPT_TIMEOUT].o_request) {
-		int to = atoi(options[OPT_TIMEOUT].o_request);
-		if (to < 1 || to > 255) {
-			nak(EBADOP);
-			exit(1);
 		}
-		else if (to <= max_rexmtval)
-			options[OPT_TIMEOUT].o_reply = rexmtval = to;
-		else
-			options[OPT_TIMEOUT].o_request = NULL;
 	}
 
-	ecode = (*pf->f_validate)(&filename, tp->th_opcode);
-	if (has_options && ecode == 0)
-		oack();
-	if (logging) {
-		char hbuf[NI_MAXHOST];
+	if (logging)
+		tftp_log(LOG_INFO, "%s: read request for %s: %s", peername,
+			    filename, errtomsg(ecode));
 
-		getnameinfo((struct sockaddr *)&from, from.ss_len,
-			    hbuf, sizeof(hbuf), NULL, 0, 0);
-		syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
-			tp->th_opcode == WRQ ? "write" : "read",
-			filename, errtomsg(ecode));
-	}
 	if (ecode) {
 		/*
 		 * Avoid storms of naks to a RRQ broadcast for a relative
@@ -508,19 +604,13 @@
 		 */
 		if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
 			exit(0);
-		nak(ecode);
+		tftp_log(LOG_ERR, "Prevent NAK storm");
+		send_error(peer, ecode);
 		exit(1);
 	}
-	if (tp->th_opcode == WRQ)
-		(*pf->f_recv)(pf);
-	else
-		(*pf->f_send)(pf);
-	exit(0);
+	tftp_xmitfile(peer, mode);
 }
 
-
-FILE *file;
-
 /*
  * Find the next value for YYYYMMDD.nn when the file to be written should
  * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
@@ -536,8 +626,6 @@
 	struct tm lt;
 	char yyyymmdd[MAXPATHLEN];
 	char newname[MAXPATHLEN];
-	struct stat sb;
-	int ret;
 
 	/* Create the YYYYMMDD part of the filename */
 	time(&tval);
@@ -553,7 +641,7 @@
 	/* Make sure the new filename is not too long */
 	if (strlen(filename) > MAXPATHLEN - len - 5) {
 		syslog(LOG_WARNING,
-			"Filename too long (%d characters, %d maximum)",
+			"Filename too long (%zd characters, %zd maximum)",
 			strlen(filename), MAXPATHLEN - len - 5);
 		return (EACCESS);
 	}
@@ -584,7 +672,7 @@
  * given as we have no login directory.
  */
 int
-validate_access(char **filep, int mode)
+validate_access(int peer, char **filep, int mode)
 {
 	struct stat stbuf;
 	int	fd;
@@ -660,14 +748,13 @@
 		else if (mode == RRQ)
 			return (err);
 	}
-	if (options[OPT_TSIZE].o_request) {
-		if (mode == RRQ) 
-			options[OPT_TSIZE].o_reply = stbuf.st_size;
-		else
-			/* XXX Allows writes of all sizes. */
-			options[OPT_TSIZE].o_reply =
-				atoi(options[OPT_TSIZE].o_request);
-	}
+
+	/*
+	 * This option is handled here because it (might) require(s) the
+	 * size of the file.
+	 */
+	option_tsize(peer, NULL, mode, &stbuf);
+
 	if (mode == RRQ)
 		fd = open(filename, O_RDONLY);
 	else {
@@ -694,305 +781,60 @@
 	return (0);
 }
 
-int	timeouts;
-jmp_buf	timeoutbuf;
-
-void
-timer(int sig __unused)
+static void
+tftp_xmitfile(int peer, const char *mode)
 {
-	if (++timeouts > MAX_TIMEOUTS)
-		exit(1);
-	longjmp(timeoutbuf, 1);
-}
+	uint16_t block;
+	uint32_t amount;
+	time_t now;
+	struct tftp_stats ts;
 
-/*
- * Send the requested file.
- */
-void
-xmitfile(struct formats *pf)
-{
-	struct tftphdr *dp;
-	struct tftphdr *ap;    /* ack packet */
-	int size, n;
-	volatile unsigned short block;
+	now = time(NULL);
+	if (debug&DEBUG_SIMPLE)
+		tftp_log(LOG_DEBUG, "Transmitting file");
 
-	signal(SIGALRM, timer);
-	dp = r_init();
-	ap = (struct tftphdr *)ackbuf;
+	read_init(0, file, mode);
 	block = 1;
-	do {

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201005040808.o4488LZV063120>