Module Name:    src
Committed By:   hubertf
Date:           Wed Apr 28 22:21:51 UTC 2010

Modified Files:
        src/doc: CHANGES
        src/libexec/tftpd: tftpd.8 tftpd.c

Log Message:
tftpd(8): Add -w so files can be uploaded without requiring them
        to be created before the upload. See the section on security
        considerations before enabling. [hubertf 20100429]

Addresses PR bin/43164.


To generate a diff of this commit:
cvs rdiff -u -r1.1383 -r1.1384 src/doc/CHANGES
cvs rdiff -u -r1.24 -r1.25 src/libexec/tftpd/tftpd.8
cvs rdiff -u -r1.36 -r1.37 src/libexec/tftpd/tftpd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/doc/CHANGES
diff -u src/doc/CHANGES:1.1383 src/doc/CHANGES:1.1384
--- src/doc/CHANGES:1.1383	Sun Apr 25 00:57:12 2010
+++ src/doc/CHANGES	Wed Apr 28 22:21:51 2010
@@ -1,4 +1,4 @@
-# LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.1383 $>
+# LIST OF CHANGES FROM LAST RELEASE:			<$Revision: 1.1384 $>
 #
 #
 # [Note: This file does not mention every change made to the NetBSD source tree.
@@ -599,3 +599,6 @@
 		The database cache for services(5) has been updated to use
 		this. services_mkdb(8) can still be used to create the old
 		format. [joerg 20100425]
+	tftpd(8): Add -w so files can be uploaded without requiring them
+		to be created before the upload. See the section on security 
+		considerations before enabling. [hubertf 20100429]

Index: src/libexec/tftpd/tftpd.8
diff -u src/libexec/tftpd/tftpd.8:1.24 src/libexec/tftpd/tftpd.8:1.25
--- src/libexec/tftpd/tftpd.8:1.24	Fri Jan  8 23:27:08 2010
+++ src/libexec/tftpd/tftpd.8	Wed Apr 28 22:21:51 2010
@@ -1,4 +1,4 @@
-.\"	$NetBSD: tftpd.8,v 1.24 2010/01/08 23:27:08 wiz Exp $
+.\"	$NetBSD: tftpd.8,v 1.25 2010/04/28 22:21:51 hubertf Exp $
 .\"
 .\" Copyright (c) 1983, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"	from: @(#)tftpd.8	8.1 (Berkeley) 6/4/93
 .\"
-.Dd January 8, 2010
+.Dd April 22, 2010
 .Dt TFTPD 8
 .Os
 .Sh NAME
@@ -44,6 +44,7 @@
 .Op Fl p Ar pathsep
 .Op Fl s Ar directory
 .Op Fl u Ar user
+.Op Fl w
 .Op Ar directory ...
 .Sh DESCRIPTION
 .Nm
@@ -70,7 +71,10 @@
 or containing
 .Dq Pa /../
 are not allowed.
-Files may be written to only if they already exist and are publicly writable.
+Unless option
+.Fl w
+is used,
+files may be written to only if they already exist and are publicly writable.
 .Pp
 Note that this extends the concept of
 .Qq public
@@ -148,6 +152,9 @@
 isn't also given, change the gid to that of
 .Ar user
 as well.
+.It Fl w
+Allow unrestricted writing of new files, with no need for
+a prior existance.
 .El
 .Sh SEE ALSO
 .Xr tftp 1 ,
@@ -232,3 +239,9 @@
 sort of file-access restrictions in place.
 The exact methods are specific to each site and therefore
 difficult to document here.
+.Pp
+If unrestricted file upload is enabled via the
+.Fl w
+option, care should be taken that this can be used
+to fill up disk space in an uncontrolled manner
+if this is used in an insecure environment.

Index: src/libexec/tftpd/tftpd.c
diff -u src/libexec/tftpd/tftpd.c:1.36 src/libexec/tftpd/tftpd.c:1.37
--- src/libexec/tftpd/tftpd.c:1.36	Sat Jan  9 10:46:31 2010
+++ src/libexec/tftpd/tftpd.c	Wed Apr 28 22:21:51 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: tftpd.c,v 1.36 2010/01/09 10:46:31 mbalmer Exp $	*/
+/*	$NetBSD: tftpd.c,v 1.37 2010/04/28 22:21:51 hubertf Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -36,7 +36,7 @@
 #if 0
 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: tftpd.c,v 1.36 2010/01/09 10:46:31 mbalmer Exp $");
+__RCSID("$NetBSD: tftpd.c,v 1.37 2010/04/28 22:21:51 hubertf Exp $");
 #endif
 #endif /* not lint */
 
@@ -109,6 +109,7 @@
 static int	secure;
 static char	pathsep = '\0';
 static char	*securedir;
+static int	unrestricted_writes;    /* uploaded files don't have to exist */
 
 struct formats;
 
@@ -171,7 +172,7 @@
 	curuid = getuid();
 	curgid = getgid();
 
-	while ((ch = getopt(argc, argv, "dg:lnp:s:u:w:")) != -1)
+	while ((ch = getopt(argc, argv, "dg:lnp:s:u:w")) != -1)
 		switch (ch) {
 		case 'd':
 			debug++;
@@ -204,6 +205,10 @@
 			tgtuser = optarg;
 			break;
 
+		case 'w':
+			unrestricted_writes = 1;
+			break;
+
 		default:
 			usage();
 			break;
@@ -739,6 +744,8 @@
 	static char	 pathname[MAXPATHLEN];
 	char		*filename;
 	int		 fd;
+	int		 create = 0;
+	int		 trunc = 0;
 
 	filename = *filep;
 
@@ -804,21 +811,45 @@
 				return (EACCESS);
 			*filep = filename = pathname;
 		} else {
+			int stat_rc;
+
 			/*
 			 * If there's no directory list, take our cue from the
 			 * absolute file request check above (*filename == '/'),
 			 * and allow access to anything.
 			 */
-			if (stat(filename, &stbuf) < 0)
-				return (errno == ENOENT ? ENOTFOUND : EACCESS);
-			if (!S_ISREG(stbuf.st_mode))
-				return (ENOTFOUND);
+			stat_rc = stat(filename, &stbuf);
 			if (mode == RRQ) {
+				/* Read request */
+				if (stat_rc < 0)
+				       return (errno == ENOENT ? ENOTFOUND : EACCESS);
+				if (!S_ISREG(stbuf.st_mode))
+				       return (ENOTFOUND);
 				if ((stbuf.st_mode & S_IROTH) == 0)
 					return (EACCESS);
 			} else {
-				if ((stbuf.st_mode & S_IWOTH) == 0)
-					return (EACCESS);
+				if (stat_rc < 0) {
+				       /* Can't stat */
+				       if (errno == EACCES) {
+					       /* Permission denied */
+					       return EACCESS;
+				       } else {
+					       /* Not there */
+					       if (unrestricted_writes) {
+						       /* need to creat new file! */
+						       create = O_CREAT;
+					       } else {
+						       /* Permission denied */
+						       return EACCESS;
+					       }
+				       }
+				} else {
+				       /* Can stat */
+				       if ((stbuf.st_mode & S_IWOTH) == 0) {
+					       return (EACCESS);
+				       }
+				       trunc = O_TRUNC;
+				}
 			}
 			*filep = filename;
 		}
@@ -827,7 +858,8 @@
 	if (tftp_opt_tsize && mode == RRQ)
 		tftp_tsize = (unsigned long) stbuf.st_size;
 
-	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC);
+	fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | trunc | create,
+			0644); /* debatable */
 	if (fd < 0)
 		return (errno + 100);
 	file = fdopen(fd, (mode == RRQ)? "r":"w");

Reply via email to