PERFORCE change 177699 for review
Gabor Pali
pgj at FreeBSD.org
Tue May 4 08:08:22 UTC 2010
http://p4web.freebsd.org/@@177699?ac=10
Change 177699 by pgj at 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) <<<
More information about the p4-projects
mailing list