diff --git a/libexec/tftpd/tftpd.8 b/libexec/tftpd/tftpd.8 index fb81e4a59f54..36bb6d5a9857 100644 --- a/libexec/tftpd/tftpd.8 +++ b/libexec/tftpd/tftpd.8 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91 -.\" $Id: tftpd.8,v 1.2 1993/08/01 07:39:46 mycroft Exp $ +.\" $Id: tftpd.8,v 1.3 1994/01/10 16:29:46 mycroft Exp $ .\" .Dd May 13, 1991 .Dt TFTPD 8 @@ -43,6 +43,9 @@ Trivial File Transfer Protocol server .Sh SYNOPSIS .Nm tftpd .Op Ar directory ... +.Nm tftpd +.Fl s +.Op Ar directory .Sh DESCRIPTION .Nm Tftpd is a server which supports the @@ -83,6 +86,14 @@ as server program arguments in .Pa /etc/inetd.conf . In this case access is restricted to files whose names are prefixed by the one of the given directories. +.Pp +When using the +.Fl s +flag with a directory name, tftpd will +.Xr chroot 2 +on startup; therefore the remote host is not expected to pass the directory +as part of the file name to transfer. This option is intended primarily for +compatibility with SunOS boot ROMs which do not include a directory name. .Sh SEE ALSO .Xr tftp 1 , .Xr inetd 8 @@ -91,3 +102,7 @@ The .Nm command appeared in .Bx 4.2 . +.Pp +The +.Fl s +flag appeared in NetBSD 0.9a. diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c index 217250d174fa..b4b90316b309 100644 --- a/libexec/tftpd/tftpd.c +++ b/libexec/tftpd/tftpd.c @@ -39,7 +39,7 @@ char copyright[] = #ifndef lint /*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/ -static char rcsid[] = "$Id: tftpd.c,v 1.3 1993/08/01 18:28:53 mycroft Exp $"; +static char rcsid[] = "$Id: tftpd.c,v 1.4 1994/01/10 16:29:48 mycroft Exp $"; #endif /* not lint */ /* @@ -84,6 +84,8 @@ int fromlen; #define MAXARG 4 char *dirs[MAXARG+1]; +int secure = 0; + main(ac, av) char **av; { @@ -92,9 +94,28 @@ main(ac, av) int on = 1; ac--; av++; - while (ac-- > 0 && n < MAXARG) - dirs[n++] = *av++; + if (!strcmp(*av, "-s")) { + ac--; av++; + secure = 1; + } openlog("tftpd", LOG_PID, LOG_DAEMON); + while (ac-- > 0) { + if (!secure) { + if (n >= MAXARG) { + syslog(LOG_ERR, "too many directories\n"); + exit(1); + } else + dirs[n++] = *av; + } + if (chdir(*av++)) { + syslog(LOG_ERR, "%s: %m\n", av[-1]); + exit(1); + } + } + if (secure && chroot(".")) { + syslog(LOG_ERR, "chroot: %m\n"); + exit(1); + } if (ioctl(0, FIONBIO, &on) < 0) { syslog(LOG_ERR, "ioctl(FIONBIO): %m\n"); exit(1); @@ -270,19 +291,22 @@ validate_access(filename, mode) int fd; char *cp, **dirp; - if (*filename != '/') - return (EACCESS); - /* - * prevent tricksters from getting around the directory restrictions - */ - for (cp = filename + 1; *cp; cp++) - if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0) - return(EACCESS); - for (dirp = dirs; *dirp; dirp++) - if (strncmp(filename, *dirp, strlen(*dirp)) == 0) - break; - if (*dirp==0 && dirp!=dirs) - return (EACCESS); + if (!secure) { + if (*filename != '/') + return (EACCESS); + /* + * prevent tricksters from getting around the directory + * restrictions + */ + for (cp = filename + 1; *cp; cp++) + if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0) + return(EACCESS); + for (dirp = dirs; *dirp; dirp++) + if (strncmp(filename, *dirp, strlen(*dirp)) == 0) + break; + if (*dirp==0 && dirp!=dirs) + return (EACCESS); + } if (stat(filename, &stbuf) < 0) return (errno == ENOENT ? ENOTFOUND : EACCESS); if (mode == RRQ) {