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");