On Wed, Oct 25, 2017 at 06:54:01PM +0200, Jeremie Courreges-Anglas wrote:
> New diff after feedback from jmc@
OK bluhm@
> Index: tftpd.8
> ===================================================================
> RCS file: /d/cvs/src/usr.sbin/tftpd/tftpd.8,v
> retrieving revision 1.5
> diff -u -p -r1.5 tftpd.8
> --- tftpd.8 18 Jul 2015 05:32:56 -0000 1.5
> +++ tftpd.8 25 Oct 2017 16:48:32 -0000
> @@ -37,16 +37,14 @@
> .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
> .Ar directory
> .Sh DESCRIPTION
> .Nm
> -is a server which implements the
> -.Tn DARPA
> -Trivial File Transfer Protocol.
> +is a server which implements the DARPA Trivial File Transfer Protocol.
> .Pp
> The use of
> .Xr tftp 1
> @@ -100,6 +98,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 +133,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
> @@ -151,6 +160,6 @@ and appeared in
> It was rewritten for
> .Ox 5.2
> as a persistent non-blocking daemon.
> -.Sh BUGS
> +.Sh CAVEATS
> Many TFTP clients will not transfer files over 16744448 octets
> .Pq 32767 blocks .
> Index: tftpd.c
> ===================================================================
> RCS file: /d/cvs/src/usr.sbin/tftpd/tftpd.c,v
> retrieving revision 1.39
> diff -u -p -r1.39 tftpd.c
> --- tftpd.c 26 May 2017 17:38:46 -0000 1.39
> +++ tftpd.c 24 Oct 2017 17:37:46 -0000
> @@ -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 *clie
> 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
>
>
> --
> jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE