summaryrefslogtreecommitdiffstats
path: root/libexec/tftpd/tftpd.c
diff options
context:
space:
mode:
authoredwin <edwin@FreeBSD.org>2007-11-23 00:05:29 +0000
committeredwin <edwin@FreeBSD.org>2007-11-23 00:05:29 +0000
commit0aec4e0b506e5c497afd67081c3f0e3ab21317c0 (patch)
treea7729c13fe827d1a85808078706aa7d749d98598 /libexec/tftpd/tftpd.c
parentf51346a2b9fb629798aa46867bbde1ace870e7ea (diff)
downloadFreeBSD-src-0aec4e0b506e5c497afd67081c3f0e3ab21317c0.zip
FreeBSD-src-0aec4e0b506e5c497afd67081c3f0e3ab21317c0.tar.gz
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)
Diffstat (limited to 'libexec/tftpd/tftpd.c')
-rw-r--r--libexec/tftpd/tftpd.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index 7958bbb..027e4bc 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -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);
OpenPOWER on IntegriCloud