All pastes #794208 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-11-22 23:47 UTC
rendered paste body
? tftpd
? tftpd.8.gz
Index: Makefile
===================================================================
RCS file: /home/ncvs/src/libexec/tftpd/Makefile,v
retrieving revision 1.9
diff -u -r1.9 Makefile
--- Makefile	26 Mar 2001 14:22:11 -0000	1.9
+++ Makefile	22 Nov 2007 23:46:23 -0000
@@ -8,5 +8,6 @@
 MAN=	tftpd.8
 CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
 .PATH:	${.CURDIR}/../../usr.bin/tftp
+WFORMAT=0
 
 .include <bsd.prog.mk>
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	22 Nov 2007 23:46:23 -0000
@@ -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 @@
 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 @@
 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 @@
 .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).
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	22 Nov 2007 23:46:23 -0000
@@ -110,6 +110,8 @@
 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 @@
 	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 @@
 		case 'C':
 			ipchroot = 2;
 			break;
+		case 'F':
+			newfile_format = optarg;
+			break;
 		case 'l':
 			logging = 1;
 			break;
@@ -160,6 +165,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);
 		}
@@ -513,6 +522,57 @@
 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 @@
 {
 	struct stat stbuf;
 	int	fd;
+	int	error;
 	struct dirlist *dirp;
 	static char pathname[MAXPATHLEN];
 	char *filename = *filep;
@@ -610,10 +671,18 @@
 	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);