From owner-p4-projects@FreeBSD.ORG Tue May 4 08:08:22 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 5D3EC1065674; Tue, 4 May 2010 08:08:22 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 209B4106566B for ; Tue, 4 May 2010 08:08:22 +0000 (UTC) (envelope-from pgj@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 0E2748FC0C for ; Tue, 4 May 2010 08:08:22 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o4488MhY063122 for ; Tue, 4 May 2010 08:08:22 GMT (envelope-from pgj@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o4488LZV063120 for perforce@freebsd.org; Tue, 4 May 2010 08:08:21 GMT (envelope-from pgj@FreeBSD.org) Date: Tue, 4 May 2010 08:08:21 GMT Message-Id: <201005040808.o4488LZV063120@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to pgj@FreeBSD.org using -f From: Gabor Pali To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 177699 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 May 2010 08:08:22 -0000 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 ==== //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 +__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 #include #include -#include -#include #include #include -#include #include #include #include -#include #include #include -#include -#include #include #include #include #include +#include #include -#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) <<<