From 1ed0e5d2e1a094027c254234e6f8008cb95b8a1b Mon Sep 17 00:00:00 2001 From: Bill Fumerola Date: Thu, 25 Jan 2001 04:20:25 +0000 Subject: Add -c/C which chroots by IP of tftp client, (i.e. /tftproot/127.0.0.1/). --- libexec/tftpd/tftpd.8 | 29 ++++++++++++++++++++++++++--- libexec/tftpd/tftpd.c | 25 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'libexec') diff --git a/libexec/tftpd/tftpd.8 b/libexec/tftpd/tftpd.8 index f53229ddd3ef..41e0a92a37f0 100644 --- a/libexec/tftpd/tftpd.8 +++ b/libexec/tftpd/tftpd.8 @@ -41,7 +41,7 @@ Internet Trivial File Transfer Protocol server .Sh SYNOPSIS .Nm /usr/libexec/tftpd -.Op Fl ln +.Op Fl cCln .Op Fl s Ar directory .Op Fl u Ar user .Op Ar directory ... @@ -114,6 +114,25 @@ option is specified. .Pp The options are: .Bl -tag -width Ds +.It Fl c +Changes the default root directory of a connecting host via chroot based on the +connecting IP address. +This prevents multiple clients from writing to the same file at the same time. +If the directory does not exist, the client connection is refused. +The +.Fl s +option is required for +.Fl c +and the specified +.Ar directory +is used as a base. +.It Fl C +Operates the same as +.Fl c +except it falls back to +.Fl s Ns No 's +.Ar directory +if a directory does not exist for the client's IP. .It Fl l Log all requests using .Xr syslog 3 @@ -165,7 +184,11 @@ the .Fl s option was introduced in .Fx 2.2 , -and the +the .Fl u option was introduced in -.Fx 4.2 . +.Fx 4.2 , +and the +.Fl c +option was introduced in +.Fx 5.0 . diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c index 56c6c028b19c..f0f0ca43ddb1 100644 --- a/libexec/tftpd/tftpd.c +++ b/libexec/tftpd/tftpd.c @@ -106,6 +106,7 @@ static struct dirlist { } dirs[MAXDIRS+1]; static int suppress_naks; static int logging; +static int ipchroot; static char *errtomsg __P((int)); static void nak __P((int)); @@ -124,8 +125,14 @@ main(argc, argv) char *chuser = "nobody"; openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - while ((ch = getopt(argc, argv, "lns:u:")) != -1) { + while ((ch = getopt(argc, argv, "cClns:u:")) != -1) { switch (ch) { + case 'c': + ipchroot = 1; + break; + case 'C': + ipchroot = 2; + break; case 'l': logging = 1; break; @@ -159,6 +166,10 @@ main(argc, argv) dirs->name = "/"; dirs->len = 1; } + if (ipchroot && chroot_dir == NULL) { + syslog(LOG_ERR, "-c requires -s"); + exit(1); + } on = 1; if (ioctl(0, FIONBIO, &on) < 0) { @@ -229,6 +240,18 @@ main(argc, argv) * be a problem. See the above comment about system clogging. */ if (chroot_dir) { + if (ipchroot) { + char *tempchroot; + struct stat sb; + int statret; + + tempchroot = inet_ntoa(from.sin_addr); + asprintf(&tempchroot, "%s/%s", chroot_dir, tempchroot); + statret = stat(tempchroot, &sb); + if ((sb.st_mode & S_IFDIR) && + (statret == 0 || (statret == -1 && ipchroot == 1))) + chroot_dir = tempchroot; + } /* Must get this before chroot because /etc might go away */ if ((nobody = getpwnam(chuser)) == NULL) { syslog(LOG_ERR, "%s: no such user", chuser); -- cgit v1.2.3