From edwin@mavetju.org  Thu Nov 30 05:31:45 2006
Return-Path: <edwin@mavetju.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 0D82C16A415
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 30 Nov 2006 05:31:45 +0000 (UTC)
	(envelope-from edwin@mavetju.org)
Received: from mail4out.barnet.com.au (mail4.barnet.com.au [202.83.178.125])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 9786143CAA
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 30 Nov 2006 05:31:37 +0000 (GMT)
	(envelope-from edwin@mavetju.org)
Received: by mail4out.barnet.com.au (Postfix, from userid 1001)
	id 709EA37BB3E; Thu, 30 Nov 2006 16:31:42 +1100 (EST)
Received: from mail4auth.barnet.com.au (mail4.barnet.com.au [202.83.178.125])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client did not present a certificate)
	by mail4.barnet.com.au (Postfix) with ESMTP id 1E4394224CB
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 30 Nov 2006 16:31:42 +1100 (EST)
Received: from k7.mavetju (k7.mavetju.org [10.251.1.18])
	by mail4auth.barnet.com.au (Postfix) with ESMTP id 80A4137BAEE
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 30 Nov 2006 16:31:41 +1100 (EST)
Received: by k7.mavetju (Postfix, from userid 1001)
	id 8BD5CFB; Thu, 30 Nov 2006 16:31:40 +1100 (EST)
Message-Id: <20061130053140.8BD5CFB@k7.mavetju>
Date: Thu, 30 Nov 2006 16:31:40 +1100 (EST)
From: Edwin Groothuis <edwin@mavetju.org>
Reply-To: Edwin Groothuis <edwin@mavetju.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] tftpd - improve -w option to support unique filenames
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         106049
>Category:       bin
>Synopsis:       [patch] tftpd(8) - improve -w option to support unique filenames
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 30 05:40:12 GMT 2006
>Closed-Date:    Sun Oct 03 04:51:00 UTC 2010
>Last-Modified:  Sun Oct 03 04:51:00 UTC 2010
>Originator:     Edwin Groothuis
>Release:        FreeBSD 6.1-RELEASE i386
>Organization:
-
>Environment:
System: FreeBSD k7.mavetju 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Sun May 7 04:42:56 UTC 2006 root@opus.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP i386


>Description:

I'm managing a large collection of network devices which, once per
month, I want to download the configuration from for safekeeping
and historical reasons.

Up to now it always was a fight with keeping track of the names of
new devices to make sure their filenames were touched in /tftpboot
and set with the proper permissions. The -w option resolved this a
little bit, but it still caused the configurations to be overwritten
without my knowledge.

So I added the -W option, which behaves the same as -w, but adds a
three digit postfix to the file to be created so it will never
overwrite old ones.

>How-To-Repeat:
>Fix:


--- tftpd.c.orig	Tue Nov 28 22:54:43 2006
+++ tftpd.c	Thu Nov 30 16:17:32 2006
@@ -110,6 +110,7 @@
 static int	logging;
 static int	ipchroot;
 static int	create_new = 0;
+static int	increase_name = 0;
 static mode_t	mask = S_IWGRP|S_IWOTH;
 
 static const char *errtomsg(int);
@@ -134,7 +135,7 @@
 	tzset();			/* syslog in localtime */
 
 	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
-	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
+	while ((ch = getopt(argc, argv, "cClns:u:U:wW")) != -1) {
 		switch (ch) {
 		case 'c':
 			ipchroot = 1;
@@ -160,6 +161,10 @@
 		case 'w':
 			create_new = 1;
 			break;
+		case 'W':
+			create_new = 1;
+			increase_name = 1;
+			break;
 		default:
 			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
 		}
@@ -610,9 +615,41 @@
 	if (mode == RRQ)
 		fd = open(filename, O_RDONLY);
 	else {
-		if (create_new)
-			fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
-		else
+		if (create_new) {
+			if (increase_name) {
+				int i;
+
+				/* Make sure the new filename is not too long */
+				if (strlen(filename) > MAXPATHLEN-4) {
+					syslog(LOG_WARNING,
+						"Filename too long (%ld characters, %d maximum)",
+						strlen(filename), MAXPATHLEN);
+					return (EACCESS);
+				}
+
+				/* If we can't find anything, fail */
+				fd = -1;
+
+				/* Find the first file which doesn't exist */
+				for (i = 0; i < 1000; i++) {
+					char newname[MAXPATHLEN];
+					struct stat sb;
+					int ret;
+
+					sprintf(newname, "%s.%d", filename, i);
+					ret = stat(newname, &sb);
+					if (ret == -1 && errno == ENOENT) {
+						fd = open(newname,
+							O_WRONLY|O_TRUNC|
+							O_CREAT, 0666);
+						break;
+					}
+				}
+			} else {
+				fd = open(filename,
+					O_WRONLY|O_TRUNC|O_CREAT, 0666);
+			}
+		} else
 			fd = open(filename, O_WRONLY|O_TRUNC);
 	}
 	if (fd < 0)

--- tftpd.8.orig	Tue Nov 28 22:54:51 2006
+++ tftpd.8	Thu Nov 30 16:23:34 2006
@@ -40,7 +40,7 @@
 .Nd Internet Trivial File Transfer Protocol server
 .Sh SYNOPSIS
 .Nm /usr/libexec/tftpd
-.Op Fl cClnw
+.Op Fl cClnwW
 .Op Fl s Ar directory
 .Op Fl u Ar user
 .Op Fl U Ar umask
@@ -171,10 +171,17 @@
 The default is 022
 .Pq Dv S_IWGRP | S_IWOTH .
 .It Fl w
-Allow writes requests to create new files.
+Allow write requests to create new files.
 By default
 .Nm
-requires that the file specified in a write request exist.
+requires that the file specified in a write request exist. Note that this
+only works in directories writable by the user specified with
+.Fl u
+option.
+.It Fl W
+As
+.Fl w
+but append a three digit sequence number to the end of the filename.
 .El
 .Sh SEE ALSO
 .Xr tftp 1 ,
@@ -200,10 +207,14 @@
 .Fl u
 option was introduced in
 .Fx 4.2 ,
-and the
+the
 .Fl c
 option was introduced in
-.Fx 4.3 .
+.Fx 4.3 ,
+and the
+.Fl W
+option was introduced in
+.Fx 6.3 .
 .Sh BUGS
 Files larger than 33488896 octets (65535 blocks) cannot be transferred
 without client and server supporting blocksize negotiation (RFC1783).
>Release-Note:
>Audit-Trail:

From: "Bjoern A. Zeeb" <bzeeb-lists@lists.zabbadoz.net>
To: bug-followup@FreeBSD.org, edwin@mavetju.org
Cc:  
Subject: Re: bin/106049: [patch] tftpd - improve -w option to support unique
 filenames
Date: Thu, 30 Nov 2006 06:21:57 +0000 (UTC)

 On Thu, 30 Nov 2006, Edwin Groothuis wrote:
 
 > So I added the -W option, which behaves the same as -w, but adds a
 > three digit postfix to the file to be created so it will never
 > overwrite old ones.
 
 could you make it a timestamp like ..?
  	YYYYMMDD-hhmm[ss]
 or	YYYYMMDD-hhmm[ss][-nn]
 or	YYYYMMDD-[nn]
 
 With optional [ss] seconds and optional [nn] serial (with "optional"
 as in you decide which one makes most sense; I'd prefer the former).
 
 -- 
 Bjoern A. Zeeb				bzeeb at Zabbadoz dot NeT
Responsible-Changed-From-To: freebsd-bugs->bz 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Thu May 24 12:42:15 UTC 2007 
Responsible-Changed-Why:  
If I make it the YYYYMMDD-nn one, will you commit it? 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 

From: Edwin Groothuis <edwin@mavetju.org>
To: FreeBSD Gnats Submit <freebsd-gnats-submit@freebsd.org>
Cc:  
Subject: Re: bin/106049: [patch] tftpd(8) - improve -w option to support unique filenames
Date: Sun, 27 May 2007 10:07:10 +1000

 On Thu, May 24, 2007 at 01:00:22PM +0000, Bjoern A. Zeeb wrote:
 > On Thu, 24 May 2007, Edwin Groothuis wrote:
 > 
 > >Synopsis: [patch] tftpd(8) - improve -w option to support unique filenames
 > >
 > >Responsible-Changed-From-To: freebsd-bugs->bz
 > >Responsible-Changed-By: edwin
 > >Responsible-Changed-When: Thu May 24 12:42:15 UTC 2007
 > >Responsible-Changed-Why:
 > >If I make it the YYYYMMDD-nn one, will you commit it?
 > 
 > I'll review it and if it's ok will commit it.
 > At least if it's, like I remember, fine otherwise;-)
 > 
 > Yes, definitively would be a great feature to have, so we should work
 > this out.
 
 New ones attached:
 
 --- tftpd.c.orig	Tue Nov 28 22:54:43 2006
 +++ tftpd.c	Sun May 27 10:01:38 2007
 @@ -110,6 +110,7 @@
  static int	logging;
  static int	ipchroot;
  static int	create_new = 0;
 +static int	increase_name = 0;
  static mode_t	mask = S_IWGRP|S_IWOTH;
  
  static const char *errtomsg(int);
 @@ -134,7 +135,7 @@
  	tzset();			/* syslog in localtime */
  
  	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
 -	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
 +	while ((ch = getopt(argc, argv, "cClns:u:U:wW")) != -1) {
  		switch (ch) {
  		case 'c':
  			ipchroot = 1;
 @@ -160,6 +161,10 @@
  		case 'w':
  			create_new = 1;
  			break;
 +		case 'W':
 +			create_new = 1;
 +			increase_name = 1;
 +			break;
  		default:
  			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
  		}
 @@ -610,9 +615,51 @@
  	if (mode == RRQ)
  		fd = open(filename, O_RDONLY);
  	else {
 -		if (create_new)
 -			fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
 -		else
 +		if (create_new) {
 +			if (increase_name) {
 +				int i;
 +				time_t tval;
 +				struct tm lt;
 +				char yyyymmdd[10];
 +
 +				/* Make sure the new filename is not too long */
 +				if (strlen(filename) > MAXPATHLEN-12) {
 +					syslog(LOG_WARNING,
 +						"Filename too long (%ld characters, %d maximum)",
 +						strlen(filename), MAXPATHLEN-12);
 +					return (EACCESS);
 +				}
 +
 +				/* If we can't find anything, fail */
 +				fd = -1;
 +
 +				/* Append the YYYYMMDD string to the filename */
 +				time(&tval);
 +				lt = *localtime(&tval);
 +				strftime(yyyymmdd, sizeof(yyyymmdd),
 +					"%Y%m%d", &lt);
 +
 +				/* Find the first file which doesn't exist */
 +				for (i = 0; i < 100; i++) {
 +					char newname[MAXPATHLEN];
 +					struct stat sb;
 +					int ret;
 +
 +					sprintf(newname, "%s.%s.%02d",
 +						filename, yyyymmdd, i);
 +					ret = stat(newname, &sb);
 +					if (ret == -1 && errno == ENOENT) {
 +						fd = open(newname,
 +							O_WRONLY|O_TRUNC|
 +							O_CREAT, 0666);
 +						break;
 +					}
 +				}
 +			} else {
 +				fd = open(filename,
 +					O_WRONLY|O_TRUNC|O_CREAT, 0666);
 +			}
 +		} else
  			fd = open(filename, O_WRONLY|O_TRUNC);
  	}
  	if (fd < 0)
 
 
 
 
 --- tftpd.8.orig	Tue Nov 28 22:54:51 2006
 +++ tftpd.8	Sun May 27 10:04:20 2007
 @@ -40,7 +40,7 @@
  .Nd Internet Trivial File Transfer Protocol server
  .Sh SYNOPSIS
  .Nm /usr/libexec/tftpd
 -.Op Fl cClnw
 +.Op Fl cClnwW
  .Op Fl s Ar directory
  .Op Fl u Ar user
  .Op Fl U Ar umask
 @@ -171,10 +171,17 @@
  The default is 022
  .Pq Dv S_IWGRP | S_IWOTH .
  .It Fl w
 -Allow writes requests to create new files.
 +Allow write requests to create new files.
  By default
  .Nm
 -requires that the file specified in a write request exist.
 +requires that the file specified in a write request exist. Note that this
 +only works in directories writable by the user specified with
 +.Fl u
 +option.
 +.It Fl W
 +As
 +.Fl w
 +but append a YYYYMMDD.nn sequence number to the end of the filename.
  .El
  .Sh SEE ALSO
  .Xr tftp 1 ,
 @@ -200,10 +207,14 @@
  .Fl u
  option was introduced in
  .Fx 4.2 ,
 -and the
 +the
  .Fl c
  option was introduced in
 -.Fx 4.3 .
 +.Fx 4.3 ,
 +and the
 +.Fl W
 +option was introduced in
 +.Fx 6.3 .
  .Sh BUGS
  Files larger than 33488896 octets (65535 blocks) cannot be transferred
  without client and server supporting blocksize negotiation (RFC1783).
 
 -- 
 Edwin Groothuis      |            Personal website: http://www.mavetju.org
 edwin@mavetju.org    |              Weblog: http://www.mavetju.org/weblog/

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/106049: commit references a PR
Date: Sun,  3 Jun 2007 15:32:13 +0000 (UTC)

 bz          2007-06-03 15:32:06 UTC
 
   FreeBSD src repository
 
   Modified files:
     libexec/tftpd        tftpd.8 
   Log:
   Correct a typo.
   
   PR:             106049
   Submitted by:   edwin (as part of a larger patch)
   
   Revision  Changes    Path
   1.21      +1 -1      src/libexec/tftpd/tftpd.8
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
Responsible-Changed-From-To: bz->edwin 
Responsible-Changed-By: bz 
Responsible-Changed-When: Mon Aug 20 20:57:17 UTC 2007 
Responsible-Changed-Why:  
You are source committer yourself these days, so feel 
free to handle your PR yourself. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 

From: "Bjoern A. Zeeb" <bz@FreeBSD.org>
To: bug-followup@FreeBSD.org, edwin@mavetju.org
Cc:  
Subject: Re: bin/106049: [patch] tftpd(8) - improve -w option to support
 unique filenames
Date: Mon, 20 Aug 2007 20:56:51 +0000 (UTC)

 Hi,
 
 [resend with Cc: bug-followup]
 
 I thought a bit more about the patch while I was just about to
 commit it.
 
 There were three things that came to my mind:
 
 a) reduced the char yyyymmdd[10] to [9] which should be enough - am I
      missing something?
 
 b) make it possible to (locally) adopt the maximum for .nn . While I
      still didn't want ot make it -W nn, I went for an overwritable #define .
      But if nn could be > 99, the initial length check would be wrong so I
      collapsed it into the sprintf and made it an snprintf checking the
      result.
 
 c) if I am not mistaken, if -W is turned on, no matter what the user
      will do, all files from write requests will have the serial suffix.
      But sometimes you do not want that. So I thought I'd do it the good
      old way: if the file without the serial already exists, then
      overwrite it. If the file does not exists, then append the serial
      and try to find the first unused serial.
      This allows one to touch img.gz && chmod 666 img.gz -> put img.gz ,
      but also to just 'put config' and get config.YYYYMMDD.nn if there
      is no file named 'config' before.
 
 I have put up an untested, updated patch at (also attached below):
 http://sources.zabbadoz.net/freebsd/patchset/EXPERIMENTAL/tftp-pr106049-p5.diff
 
 I'd only like to put this up for discussion. If you do not like it
 just go ahead and commit your version;)
 
 
 Index: tftpd.8
 ===================================================================
 RCS file: /shared/mirror/FreeBSD/r/ncvs/src/libexec/tftpd/tftpd.8,v
 retrieving revision 1.21
 diff -u -p -r1.21 tftpd.8
 --- tftpd.8	3 Jun 2007 15:32:06 -0000	1.21
 +++ tftpd.8	4 Jun 2007 21:30:26 -0000
 @@ -40,7 +40,7 @@
   .Nd Internet Trivial File Transfer Protocol server
   .Sh SYNOPSIS
   .Nm tftpd
 -.Op Fl cClnw
 +.Op Fl cClnwW
   .Op Fl s Ar directory
   .Op Fl u Ar user
   .Op Fl U Ar umask
 @@ -184,6 +184,19 @@ Allow write requests to create new files
   By default
   .Nm
   requires that the file specified in a write request exist.
 +Note that this only works in directories writable by the user specified
 +with
 +.Fl u
 +option.
 +.It Fl W
 +Like
 +.Fl w
 +if the file already exists.
 +If the file does not exist, additionally append a YYYYMMDD.nn serial to the
 +end of the filename. Increment nn until we find the first filename with a
 +serial that does not exist.
 +In case nn exceeds the compiled in maximum, which defaults to 99, deny
 +the write request.
   .El
   .Sh SEE ALSO
   .Xr tftp 1 ,
 @@ -212,10 +225,14 @@ the
   .Fl u
   option was introduced in
   .Fx 4.2 ,
 -and the
 +the
   .Fl c
   option was introduced in
 -.Fx 4.3 .
 +.Fx 4.3 ,
 +and the
 +.Fl W
 +option was introduced in
 +.Fx 6.3 .
   .Sh BUGS
   Files larger than 33488896 octets (65535 blocks) cannot be transferred
   without client and server supporting blocksize negotiation (RFC1783).
 Index: tftpd.c
 ===================================================================
 RCS file: /shared/mirror/FreeBSD/r/ncvs/src/libexec/tftpd/tftpd.c,v
 retrieving revision 1.37
 diff -u -p -r1.37 tftpd.c
 --- tftpd.c	31 May 2005 17:22:53 -0000	1.37
 +++ tftpd.c	4 Jun 2007 21:30:26 -0000
 @@ -91,6 +91,10 @@ char	buf[PKTSIZE];
   char	ackbuf[PKTSIZE];
   struct	sockaddr_storage from;
 
 +#ifndef INCREASE_NAME_MAX_SEQ
 +#define	INCREASE_NAME_MAX_SEQ	100
 +#endif
 +
   void	tftp(struct tftphdr *, int);
   static void unmappedaddr(struct sockaddr_in6 *);
 
 @@ -110,6 +114,7 @@ static int	suppress_naks;
   static int	logging;
   static int	ipchroot;
   static int	create_new = 0;
 +static int	increase_name = 0;
   static mode_t	mask = S_IWGRP|S_IWOTH;
 
   static const char *errtomsg(int);
 @@ -134,7 +139,7 @@ main(int argc, char *argv[])
   	tzset();			/* syslog in localtime */
 
   	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
 -	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
 +	while ((ch = getopt(argc, argv, "cClns:u:U:wW")) != -1) {
   		switch (ch) {
   		case 'c':
   			ipchroot = 1;
 @@ -160,6 +165,10 @@ main(int argc, char *argv[])
   		case 'w':
   			create_new = 1;
   			break;
 +		case 'W':
 +			create_new = 1;
 +			increase_name = 1;
 +			break;
   		default:
   			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
   		}
 @@ -610,9 +619,66 @@ validate_access(char **filep, int mode)
   	if (mode == RRQ)
   		fd = open(filename, O_RDONLY);
   	else {
 -		if (create_new)
 -			fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
 -		else
 +		if (create_new) {
 +			int fexists = 0;
 +			struct stat sb;
 +
 +			/*
 +			 * Only create a file with a serial suffix if the file
 +			 *  without one does not yet exist.
 +			 */
 +			fexists = stat(filename, &sb);
 +			if (fexists == -1 && errno == ENOENT && increase_name) {
 +				int i;
 +				time_t tval;
 +				struct tm *lt;
 +				char yyyymmdd[9];
 +
 +				/* Fail if we cannot find anything */
 +				fd = -1;
 +
 +				/* Append the YYYYMMDD string to the filename */
 +				time(&tval);
 +				lt = localtime(&tval);
 +				if (strftime(yyyymmdd, sizeof(yyyymmdd),
 +				    "%Y%m%d", lt) != 8) {
 +					syslog(LOG_WARNING, "Cannot format "
 +					    "date for filename.");
 +					return (EACCESS);
 +				}
 +
 +				/* Find the first file which doesn't exist */
 +				for (i = 0; i < INCREASE_NAME_MAX_SEQ; i++) {
 +					char newname[MAXPATHLEN];
 +					int len;
 +
 +					/*
 +					 * Make sure the new filename is
 +					 * not too long.
 +					 */
 +					if ((len = snprintf(newname, MAXPATHLEN,
 +					    "%s.%s.%02d", filename, yyyymmdd,
 +					    i)) >= MAXPATHLEN) {
 +						syslog(LOG_WARNING,
 +						    "Filename with serial too "
 +						    "long (%d characters, "
 +						    "%d maximum)",
 +						    len, MAXPATHLEN-1);
 +						return (ENAMETOOLONG);
 +					}
 +					fexists = stat(newname, &sb);
 +					if (fexists == -1 && errno == ENOENT) {
 +						fd = open(newname,
 +						    O_WRONLY|O_TRUNC|O_CREAT,
 +						    0666);
 +						break;
 +					}
 +				}
 +			} else {
 +				fd = open(filename,
 +					O_WRONLY|O_TRUNC|O_CREAT, 0666);
 +			}
 +		} else
   			fd = open(filename, O_WRONLY|O_TRUNC);
   	}
   	if (fd < 0)
 
 -- 
 Bjoern A. Zeeb                                 bzeeb at Zabbadoz dot NeT
 Software is harder than hardware  so better get it right the first time.

From: Edwin Groothuis <edwin@mavetju.org>
To: FreeBSD Gnats Submit <freebsd-gnats-submit@freebsd.org>
Cc:  
Subject: Re: bin/106049: [patch] tftpd(8) - improve -w option to support unique filenames
Date: Fri, 5 Oct 2007 16:40:36 +1000

 --vtzGhvizbBRQ85DL
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 update for mentor
 
 -- 
 Edwin Groothuis      |            Personal website: http://www.mavetju.org
 edwin@mavetju.org    |              Weblog: http://www.mavetju.org/weblog/
 
 --vtzGhvizbBRQ85DL
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename=a
 
 ? tftpd
 ? tftpd.8.gz
 Index: tftpd.8
 ===================================================================
 RCS file: /home/ncvs/src/libexec/tftpd/tftpd.8,v
 retrieving revision 1.21
 diff -u -r1.21 tftpd.8
 --- tftpd.8	3 Jun 2007 15:32:06 -0000	1.21
 +++ tftpd.8	5 Oct 2007 06:37:50 -0000
 @@ -40,7 +40,7 @@
  .Nd Internet Trivial File Transfer Protocol server
  .Sh SYNOPSIS
  .Nm tftpd
 -.Op Fl cClnw
 +.Op Fl cClnwW
  .Op Fl s Ar directory
  .Op Fl u Ar user
  .Op Fl U Ar umask
 @@ -184,6 +184,14 @@
  By default
  .Nm
  requires that the file specified in a write request exist.
 +Note that this only works in directories writable by the user
 +specified with
 +.Fl u
 +option
 +.It Fl W
 +As
 +.Fl w
 +but append a YYYYMMDD.nn sequence number to the end of the filename.
  .El
  .Sh SEE ALSO
  .Xr tftp 1 ,
 @@ -212,10 +220,14 @@
  .Fl u
  option was introduced in
  .Fx 4.2 ,
 -and the
 +the
  .Fl c
  option was introduced in
 -.Fx 4.3 .
 +.Fx 4.3 ,
 +and the
 +.Fl W
 +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).
 Index: tftpd.c
 ===================================================================
 RCS file: /home/ncvs/src/libexec/tftpd/tftpd.c,v
 retrieving revision 1.37
 diff -u -r1.37 tftpd.c
 --- tftpd.c	31 May 2005 17:22:53 -0000	1.37
 +++ tftpd.c	5 Oct 2007 06:37:51 -0000
 @@ -110,6 +110,7 @@
  static int	logging;
  static int	ipchroot;
  static int	create_new = 0;
 +static int	increase_name = 0;
  static mode_t	mask = S_IWGRP|S_IWOTH;
  
  static const char *errtomsg(int);
 @@ -134,7 +135,7 @@
  	tzset();			/* syslog in localtime */
  
  	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
 -	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
 +	while ((ch = getopt(argc, argv, "cClns:u:U:wW")) != -1) {
  		switch (ch) {
  		case 'c':
  			ipchroot = 1;
 @@ -160,6 +161,10 @@
  		case 'w':
  			create_new = 1;
  			break;
 +		case 'W':
 +			create_new = 1;
 +			increase_name = 1;
 +			break;
  		default:
  			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
  		}
 @@ -262,6 +267,7 @@
  			struct sockaddr_storage ss;
  			char hbuf[NI_MAXHOST];
  
 +			statret = -1;
  			memcpy(&ss, &from, from.ss_len);
  			unmappedaddr((struct sockaddr_in6 *)&ss);
  			getnameinfo((struct sockaddr *)&ss, ss.ss_len,
 @@ -408,6 +414,7 @@
  	char fnbuf[PATH_MAX];
  
  	cp = tp->th_stuff;
 +	mode = NULL;
  again:
  	while (cp < buf + size) {
  		if (*cp == '\0')
 @@ -513,6 +520,55 @@
  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.
 + * Besides, that is four updates per hour on a file, which is kind of
 + * execessive anyway.
 + */
 +static int
 +find_next_name(char *filename)
 +{
 +	int i;
 +	int fd;
 +	time_t tval;
 +	struct tm lt;
 +	char yyyymmdd[10];
 +	char newname[MAXPATHLEN];
 +	struct stat sb;
 +	int ret;
 +
 +	/* Make sure the new filename is not too long */
 +	if (strlen(filename) > MAXPATHLEN - 12) {
 +		syslog(LOG_WARNING,
 +			"Filename too long (%d characters, %d maximum)",
 +			strlen(filename), MAXPATHLEN - 12);
 +		return (-EACCESS);
 +	}
 +
 +	/* If we can't find anything, fail */
 +	fd = -1;
 +
 +	/* Append the YYYYMMDD string to the filename */
 +	time(&tval);
 +	lt = *localtime(&tval);
 +	strftime(yyyymmdd, sizeof(yyyymmdd), "%Y%m%d", &lt);
 +
 +	/* Find the first file which doesn't exist */
 +	for (i = 0; i < 100; i++) {
 +		sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
 +		ret = stat(newname, &sb);
 +		if (ret == -1 && errno == ENOENT) {
 +			fd = open(newname, O_WRONLY | O_TRUNC | O_CREAT, 0666);
 +			if (fd < 0)
 +				return -errno;
 +			return fd;
 +		}
 +	}
 +
 +	return (-ENOSPC);
 +}
 +
 +/*
   * Validate file access.  Since we
   * have no uid or gid, for now require
   * file to exist and be publicly
 @@ -610,10 +666,17 @@
  	if (mode == RRQ)
  		fd = open(filename, O_RDONLY);
  	else {
 -		if (create_new)
 -			fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
 -		else
 -			fd = open(filename, O_WRONLY|O_TRUNC);
 +		if (create_new) {
 +			if (increase_name) {
 +				fd = find_next_name(filename);
 +				if (fd < 0)
 +					return -fd;
 +			} else {
 +				fd = open(filename,
 +					O_WRONLY | O_TRUNC | O_CREAT, 0666);
 +			}
 +		} else
 +			fd = open(filename, O_WRONLY | O_TRUNC);
  	}
  	if (fd < 0)
  		return (errno + 100);
 
 --vtzGhvizbBRQ85DL--
State-Changed-From-To: open->patched 
State-Changed-By: edwin 
State-Changed-When: Fri Nov 23 00:14:20 UTC 2007 
State-Changed-Why:  
Commited to HEAD 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/106049: commit references a PR
Date: Fri, 23 Nov 2007 04:24:30 +0000 (UTC)

 edwin       2007-11-23 00:05:29 UTC
 
   FreeBSD src repository
 
   Modified files:
     libexec/tftpd        Makefile tftpd.8 tftpd.c 
   Log:
   Add the -W options, which acts the same as -w but will generate
   unique names based on the submitted filename, a strftime(3) format
   string and a two digit sequence number.
   
   By default the strftime(3) format string is %Y%m%d (YYYYMMDD), but
   this can be changed by the -F option.
   
   PR:             bin/106049 (based on patch in that PR)
   Approved by:    grog@ (mentor)
   
   Revision  Changes    Path
   1.10      +2 -1      src/libexec/tftpd/Makefile
   1.22      +29 -3     src/libexec/tftpd/tftpd.8
   1.38      +74 -5     src/libexec/tftpd/tftpd.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
Responsible-Changed-From-To: edwin->freebsd-bgus 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Thu Feb 14 10:34:20 UTC 2008 
Responsible-Changed-Why:  

Give back into the pool until later. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 
Responsible-Changed-From-To: freebsd-bgus->freebsd-bugs 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Thu Feb 14 10:38:46 UTC 2008 
Responsible-Changed-Why:  
Fix name 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/106049: commit references a PR
Date: Wed, 22 Sep 2010 20:28:06 +0000 (UTC)

 Author: marius
 Date: Wed Sep 22 20:27:59 2010
 New Revision: 213027
 URL: http://svn.freebsd.org/changeset/base/213027
 
 Log:
   MFC: r173852
   
   Add the -W options, which acts the same as -w but will generate
   unique names based on the submitted filename, a strftime(3) format
   string and a two digit sequence number.
   
   By default the strftime(3) format string is %Y%m%d (YYYYMMDD), but
   this can be changed by the -F option.
   
   PR:		bin/106049 (based on patch in that PR)
   Approved by:	grog@ (mentor)
 
 Modified:
   stable/7/libexec/tftpd/Makefile
   stable/7/libexec/tftpd/tftpd.8
   stable/7/libexec/tftpd/tftpd.c
 Directory Properties:
   stable/7/libexec/tftpd/   (props changed)
 
 Modified: stable/7/libexec/tftpd/Makefile
 ==============================================================================
 --- stable/7/libexec/tftpd/Makefile	Wed Sep 22 20:17:34 2010	(r213026)
 +++ stable/7/libexec/tftpd/Makefile	Wed Sep 22 20:27:59 2010	(r213027)
 @@ -5,6 +5,7 @@ PROG=	tftpd
  SRCS=	tftpd.c tftpsubs.c
  DPADD=	${LIBUTIL}
  LDADD=	-lutil
 +WFORMAT=0
  MAN=	tftpd.8
  CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
  .PATH:	${.CURDIR}/../../usr.bin/tftp
 
 Modified: stable/7/libexec/tftpd/tftpd.8
 ==============================================================================
 --- stable/7/libexec/tftpd/tftpd.8	Wed Sep 22 20:17:34 2010	(r213026)
 +++ stable/7/libexec/tftpd/tftpd.8	Wed Sep 22 20:27:59 2010	(r213027)
 @@ -40,7 +40,8 @@
  .Nd Internet Trivial File Transfer Protocol server
  .Sh SYNOPSIS
  .Nm tftpd
 -.Op Fl cClnw
 +.Op Fl cClnwW
 +.Op Fl F Ar strftime-format
  .Op Fl s Ar directory
  .Op Fl u Ar user
  .Op Fl U Ar umask
 @@ -142,6 +143,13 @@ except it falls back to
  specified via
  .Fl s
  if a directory does not exist for the client's IP.
 +.It Fl F
 +Use this
 +.Xr strftime 3
 +compatible format string for the creation of the suffix if
 +.Fl W
 +is specified.
 +By default the string "%Y%m%d" is used.
  .It Fl l
  Log all requests using
  .Xr syslog 3
 @@ -184,6 +192,17 @@ Allow write requests to create new files
  By default
  .Nm
  requires that the file specified in a write request exist.
 +Note that this only works in directories writable by the user
 +specified with
 +.Fl u
 +option
 +.It Fl W
 +As
 +.Fl w
 +but append a YYYYMMDD.nn sequence number to the end of the filename.
 +Note that the string YYYYMMDD can be changed the
 +.Fl F
 +option.
  .El
  .Sh SEE ALSO
  .Xr tftp 1 ,
 @@ -212,10 +231,17 @@ the
  .Fl u
  option was introduced in
  .Fx 4.2 ,
 -and the
 +the
  .Fl c
  option was introduced in
 -.Fx 4.3 .
 +.Fx 4.3 ,
 +and the
 +.Fl F
 +and
 +.Fl W
 +options were introduced in
 +.Fx 7 .
 +.Pp
  .Sh BUGS
  Files larger than 33488896 octets (65535 blocks) cannot be transferred
  without client and server supporting blocksize negotiation (RFC1783).
 
 Modified: stable/7/libexec/tftpd/tftpd.c
 ==============================================================================
 --- stable/7/libexec/tftpd/tftpd.c	Wed Sep 22 20:17:34 2010	(r213026)
 +++ stable/7/libexec/tftpd/tftpd.c	Wed Sep 22 20:27:59 2010	(r213027)
 @@ -110,6 +110,8 @@ static int	suppress_naks;
  static int	logging;
  static int	ipchroot;
  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 const char *errtomsg(int);
 @@ -134,7 +136,7 @@ main(int argc, char *argv[])
  	tzset();			/* syslog in localtime */
  
  	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
 -	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
 +	while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
  		switch (ch) {
  		case 'c':
  			ipchroot = 1;
 @@ -142,6 +144,9 @@ main(int argc, char *argv[])
  		case 'C':
  			ipchroot = 2;
  			break;
 +		case 'F':
 +			newfile_format = optarg;
 +			break;
  		case 'l':
  			logging = 1;
  			break;
 @@ -160,6 +165,10 @@ main(int argc, char *argv[])
  		case 'w':
  			create_new = 1;
  			break;
 +		case 'W':
 +			create_new = 1;
 +			increase_name = 1;
 +			break;
  		default:
  			syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
  		}
 @@ -513,6 +522,57 @@ option_fail:
  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.
 + * Besides, that is four updates per hour on a file, which is kind of
 + * execessive anyway.
 + */
 +static int
 +find_next_name(char *filename, int *fd)
 +{
 +	int i;
 +	time_t tval;
 +	size_t len;
 +	struct tm lt;
 +	char yyyymmdd[MAXPATHLEN];
 +	char newname[MAXPATHLEN];
 +	struct stat sb;
 +	int ret;
 +
 +	/* Create the YYYYMMDD part of the filename */
 +	time(&tval);
 +	lt = *localtime(&tval);
 +	len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
 +	if (len == 0) {
 +		syslog(LOG_WARNING,
 +			"Filename suffix too long (%d characters maximum)",
 +			MAXPATHLEN);
 +		return (EACCESS);
 +	}
 +
 +	/* 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)",
 +			strlen(filename), MAXPATHLEN - len - 5);
 +		return (EACCESS);
 +	}
 +
 +	/* Find the first file which doesn't exist */
 +	for (i = 0; i < 100; i++) {
 +		sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
 +		*fd = open(newname,
 +		    O_WRONLY | O_CREAT | O_EXCL, 
 +		    S_IRUSR | S_IWUSR | S_IRGRP |
 +		    S_IWGRP | S_IROTH | S_IWOTH);
 +		if (*fd > 0)
 +			return 0;
 +	}
 +
 +	return (EEXIST);
 +}
 +
 +/*
   * Validate file access.  Since we
   * have no uid or gid, for now require
   * file to exist and be publicly
 @@ -528,6 +588,7 @@ validate_access(char **filep, int mode)
  {
  	struct stat stbuf;
  	int	fd;
 +	int	error;
  	struct dirlist *dirp;
  	static char pathname[MAXPATHLEN];
  	char *filename = *filep;
 @@ -610,10 +671,18 @@ validate_access(char **filep, int mode)
  	if (mode == RRQ)
  		fd = open(filename, O_RDONLY);
  	else {
 -		if (create_new)
 -			fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
 -		else
 -			fd = open(filename, O_WRONLY|O_TRUNC);
 +		if (create_new) {
 +			if (increase_name) {
 +				error = find_next_name(filename, &fd);
 +				if (error > 0)
 +					return (error + 100);
 +			} else
 +				fd = open(filename,
 +				    O_WRONLY | O_TRUNC | O_CREAT, 
 +				    S_IRUSR | S_IWUSR | S_IRGRP | 
 +				    S_IWGRP | S_IROTH | S_IWOTH );
 +		} else
 +			fd = open(filename, O_WRONLY | O_TRUNC);
  	}
  	if (fd < 0)
  		return (errno + 100);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: arundel 
State-Changed-When: Sun Oct 3 04:50:10 UTC 2010 
State-Changed-Why:  
Looks like this PR can be closed, since all changes have been MFC'ed to 
stable/7. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=106049 
>Unformatted:
