Date: Thu, 27 Jul 2006 17:58:57 +0200 (CEST) From: Auster <lrou@presto.telepluscom.net> To: FreeBSD-gnats-submit@FreeBSD.org Cc: lrou@x.ua Subject: bin/100921: libexec/tftpd: `-w' non-traditional access control Message-ID: <200607271558.k6RFwvGn062227@presto.telepluscom.net> Resent-Message-ID: <200607271600.k6RG0abf050604@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 100921 >Category: bin >Synopsis: libexec/tftpd: `-w' non-traditional access control >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Jul 27 16:00:36 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Auster >Release: FreeBSD 6.1-RELEASE-p2 i386 >Organization: >Environment: System: FreeBSD presto.telepluscom.net 6.1-RELEASE-p2 FreeBSD 6.1-RELEASE-p2 #0: Thu Jun 15 20:30:57 CEST 2006 yx@presto.telepluscom.net:/usr/obj/usr/src/sys/presto i386 >Description: Partially non-traditional(2) tftp write access control: tftpd(8): (1) files may be written only if they already exist and are publicly writable. (2) -w Allow writes requests to create new files. By default tftpd requires that the file specified in a write request exist. Condition: `-w' allow writes requests to create new files. Summary, creation new files: absolute filenames - incorrect relative filenames - correct >How-To-Repeat: ~# grep '^tftp' /etc/inetd.conf tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -w -s /spool/tftp ~# touch a ~# mkdir /spool/tftp/1 ~# chown nobody:nogroup /spool/tftp/1 ~# chmod 755 /spool/tftp/1 ~# rm -f /spool/tftp/1/a ~# tftp localhost tftp| put a /1/a Error code 1: File not found ! error - incorrect (for `tftpd -w') tftp| put a 1/a ! no error - correct (for `tftpd -w') >Fix: for example: variants (1), (2), and (3). variant (1): tftpd(8) manual correction only: -w Allow writes requests to create new files. By default tftpd requires that the file specified in a write request exist. + File creation are allowed for relative file names only. variant (2): small code correction (create request w/ absolute file names): diff -up libexec/tftpd/tftpd.c.orig libexec/tftpd/tftpd.c --- libexec/tftpd/tftpd.c.orig Thu Jul 27 12:02:59 2006 +++ libexec/tftpd/tftpd.c Thu Jul 27 16:08:33 2006 @@ -527,7 +527,7 @@ int validate_access(char **filep, int mode) { struct stat stbuf; - int fd; + int fd, crq; struct dirlist *dirp; static char pathname[MAXPATHLEN]; char *filename = *filep; @@ -554,16 +554,26 @@ validate_access(char **filep, int mode) /* If directory list is empty, allow access to any file */ if (dirp->name == NULL && dirp != dirs) return (EACCESS); - if (stat(filename, &stbuf) < 0) - return (errno == ENOENT ? ENOTFOUND : EACCESS); - if ((stbuf.st_mode & S_IFMT) != S_IFREG) - return (ENOTFOUND); + + crq = 0; + if (stat(filename, &stbuf) < 0) { + if (create_new && (mode == WRQ) && (errno == ENOENT)) + crq = 1; + if (!crq) + return (errno == ENOENT ? ENOTFOUND : EACCESS); + } + if (!crq) { + if ((stbuf.st_mode & S_IFMT) != S_IFREG) + return (ENOTFOUND); + } if (mode == RRQ) { if ((stbuf.st_mode & S_IROTH) == 0) return (EACCESS); } else { - if ((stbuf.st_mode & S_IWOTH) == 0) - return (EACCESS); + if (!crq) { + if ((stbuf.st_mode & S_IWOTH) == 0) + return (EACCESS); + } } } else { int err; variant (3): non-traditional read/write access control: tftpd(8): - -w Allow writes requests to create new files. By default tftpd - requires that the file specified in a write request exist. + -w Offers a non-traditional (for tftp) access control, which + will allows to read, write, and create files, with credentials + to tftpd ``user'' (default ``nobody'') only. diff -up libexec/tftpd/tftpd.c.orig libexec/tftpd/tftpd.c --- libexec/tftpd/tftpd.c.orig Thu Jul 27 12:02:59 2006 +++ libexec/tftpd/tftpd.c Thu Jul 27 16:53:54 2006 @@ -109,7 +109,7 @@ static struct dirlist { static int suppress_naks; static int logging; static int ipchroot; -static int create_new = 0; +static int traditional_mode = 1; static mode_t mask = S_IWGRP|S_IWOTH; static const char *errtomsg(int); @@ -158,7 +158,7 @@ main(int argc, char *argv[]) mask = strtol(optarg, NULL, 0); break; case 'w': - create_new = 1; + traditional_mode = 0; break; default: syslog(LOG_WARNING, "ignoring unknown option -%c", ch); @@ -527,7 +527,7 @@ int validate_access(char **filep, int mode) { struct stat stbuf; - int fd; + int fd, crq; struct dirlist *dirp; static char pathname[MAXPATHLEN]; char *filename = *filep; @@ -554,16 +554,26 @@ validate_access(char **filep, int mode) /* If directory list is empty, allow access to any file */ if (dirp->name == NULL && dirp != dirs) return (EACCESS); - if (stat(filename, &stbuf) < 0) - return (errno == ENOENT ? ENOTFOUND : EACCESS); - if ((stbuf.st_mode & S_IFMT) != S_IFREG) - return (ENOTFOUND); - if (mode == RRQ) { - if ((stbuf.st_mode & S_IROTH) == 0) - return (EACCESS); - } else { - if ((stbuf.st_mode & S_IWOTH) == 0) - return (EACCESS); + + crq = 0; + if (stat(filename, &stbuf) < 0) { + if (!traditional_mode && (mode == WRQ) && (errno == ENOENT)) + crq = 1; + if (!crq) + return (errno == ENOENT ? ENOTFOUND : EACCESS); + } + if (!crq) { + if ((stbuf.st_mode & S_IFMT) != S_IFREG) + return (ENOTFOUND); + } + if (traditional_mode) { + if (mode == RRQ) { + if ((stbuf.st_mode & S_IROTH) == 0) + return (EACCESS); + } else { + if ((stbuf.st_mode & S_IWOTH) == 0) + return (EACCESS); + } } } else { int err; @@ -588,16 +598,30 @@ validate_access(char **filep, int mode) dirp->name, filename); if (stat(pathname, &stbuf) == 0 && (stbuf.st_mode & S_IFMT) == S_IFREG) { - if ((stbuf.st_mode & S_IROTH) != 0) { + if (!traditional_mode) break; + if (mode == RRQ) { + if ((stbuf.st_mode & S_IROTH) != 0) { + break; + } + } else { + if ((stbuf.st_mode & S_IWOTH) != 0) { + break; + } } err = EACCESS; } } if (dirp->name != NULL) *filep = filename = pathname; - else if (mode == RRQ) - return (err); + else { + if (mode == RRQ) { + return (err); + } else { + if (traditional_mode) + return (err); + } + } } if (options[OPT_TSIZE].o_request) { if (mode == RRQ) @@ -610,10 +634,10 @@ 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 + if (traditional_mode) fd = open(filename, O_WRONLY|O_TRUNC); + else + fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666); } if (fd < 0) return (errno + 100); >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607271558.k6RFwvGn062227>