diff options
author | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2017-11-07 14:15:39 +0000 |
---|---|---|
committer | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2017-11-07 14:15:39 +0000 |
commit | 41650afcf69a59f547cbedc53fc02a84ae5ef1ee (patch) | |
tree | 10374f9490ec9518fdc0603e02eacc2a6937e419 /usr.sbin/tftpd | |
parent | 511399762efb24545117d332c506fa55cc60269a (diff) |
Add support for client-specific directories (named after the client address)
tftpd -i will look up the requested path the directory named after the
client's IP address. For read requests, if the file is not found, there's
a fall back to its root directory.
From Jan Klemkow with input and tweaks from at least jmc@, bluhm@,
deraadt@, sthen@, semarie@ and myself. ok bluhm@
Diffstat (limited to 'usr.sbin/tftpd')
-rw-r--r-- | usr.sbin/tftpd/tftpd.8 | 17 | ||||
-rw-r--r-- | usr.sbin/tftpd/tftpd.c | 49 |
2 files changed, 55 insertions, 11 deletions
diff --git a/usr.sbin/tftpd/tftpd.8 b/usr.sbin/tftpd/tftpd.8 index 2e8f89cb5cf..561d112ee94 100644 --- a/usr.sbin/tftpd/tftpd.8 +++ b/usr.sbin/tftpd/tftpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tftpd.8,v 1.5 2015/07/18 05:32:56 mcbride Exp $ +.\" $OpenBSD: tftpd.8,v 1.6 2017/11/07 14:15:38 jca Exp $ .\" .\" Copyright (c) 1983, 1991 The Regents of the University of California. .\" All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91 .\" -.Dd $Mdocdate: July 18 2015 $ +.Dd $Mdocdate: November 7 2017 $ .Dt TFTPD 8 .Os .Sh NAME @@ -37,7 +37,7 @@ .Nd DARPA Trivial File Transfer Protocol daemon .Sh SYNOPSIS .Nm tftpd -.Op Fl 46cdv +.Op Fl 46cdiv .Op Fl l Ar address .Op Fl p Ar port .Op Fl r Ar socket @@ -100,6 +100,15 @@ If this option is specified, .Nm will run in the foreground and log the client IP, type of request, and filename to stderr. +.It Fl i +Look up the requested path in the subdirectory named after the +client's IP address. +For read requests, if the file is not found, +.Nm +falls back on the requested path. +Note that no attempt is made to limit the client to its subdirectory. +This option cannot be combined with +.Fl r . .It Fl l Ar address Listen on the specified address. By default @@ -126,6 +135,8 @@ before the TFTP request will continue. By default .Nm does not use filename rewriting. +This option cannot be combined with +.Fl i . .It Fl v Log the client IP, type of request, and filename. .It Ar directory diff --git a/usr.sbin/tftpd/tftpd.c b/usr.sbin/tftpd/tftpd.c index de12d2ac3b1..8536cf59048 100644 --- a/usr.sbin/tftpd/tftpd.c +++ b/usr.sbin/tftpd/tftpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftpd.c,v 1.39 2017/05/26 17:38:46 florian Exp $ */ +/* $OpenBSD: tftpd.c,v 1.40 2017/11/07 14:15:38 jca Exp $ */ /* * Copyright (c) 2012 David Gwynne <dlg@uq.edu.au> @@ -282,7 +282,7 @@ __dead void usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-46cdv] [-l address] [-p port] [-r socket]" + fprintf(stderr, "usage: %s [-46cdiv] [-l address] [-p port] [-r socket]" " directory\n", __progname); exit(1); } @@ -290,6 +290,7 @@ usage(void) int cancreate = 0; int verbose = 0; int debug = 0; +int iflag = 0; int main(int argc, char *argv[]) @@ -307,7 +308,7 @@ main(int argc, char *argv[]) int family = AF_UNSPEC; int devnull = -1; - while ((c = getopt(argc, argv, "46cdl:p:r:v")) != -1) { + while ((c = getopt(argc, argv, "46cdil:p:r:v")) != -1) { switch (c) { case '4': family = AF_INET; @@ -321,6 +322,11 @@ main(int argc, char *argv[]) case 'd': verbose = debug = 1; break; + case 'i': + if (rewrite != NULL) + errx(1, "options -i and -r are incompatible"); + iflag = 1; + break; case 'l': addr = optarg; break; @@ -328,6 +334,8 @@ main(int argc, char *argv[]) port = optarg; break; case 'r': + if (iflag == 1) + errx(1, "options -i and -r are incompatible"); rewrite = optarg; break; case 'v': @@ -949,15 +957,16 @@ error: * given as we have no login directory. */ int -validate_access(struct tftp_client *client, const char *filename) +validate_access(struct tftp_client *client, const char *requested) { int mode = client->opcode; struct opt_client *options = client->options; struct stat stbuf; int fd, wmode; - const char *errstr; + const char *errstr, *filename; + char rewritten[PATH_MAX]; - if (strcmp(filename, SEEDPATH) == 0) { + if (strcmp(requested, SEEDPATH) == 0) { char *buf; if (mode != RRQ) return (EACCESS); @@ -971,15 +980,39 @@ validate_access(struct tftp_client *client, const char *filename) return (0); } + if (iflag) { + int ret; + + /* + * In -i mode, look in the directory named after the + * client address. + */ + ret = snprintf(rewritten, sizeof(rewritten), "%s/%s", + getip(&client->ss), requested); + if (ret == -1 || ret >= sizeof(rewritten)) + return (ENAMETOOLONG + 100); + filename = rewritten; + } else { +retryread: + filename = requested; + } + /* * We use a different permissions scheme if `cancreate' is * set. */ wmode = O_TRUNC; if (stat(filename, &stbuf) < 0) { - if (!cancreate) + if (!cancreate) { + /* + * In -i mode, retry failed read requests from + * the root directory. + */ + if (mode == RRQ && errno == ENOENT && + filename == rewritten) + goto retryread; return (errno == ENOENT ? ENOTFOUND : EACCESS); - else { + } else { if ((errno == ENOENT) && (mode != RRQ)) wmode |= O_CREAT; else |