From owner-freebsd-bugs@FreeBSD.ORG Thu Jul 27 16:01:21 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8F8D316A4DD for ; Thu, 27 Jul 2006 16:01:21 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 49AE943D64 for ; Thu, 27 Jul 2006 16:00:40 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k6RG0bfx050605 for ; Thu, 27 Jul 2006 16:00:37 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k6RG0abf050604; Thu, 27 Jul 2006 16:00:36 GMT (envelope-from gnats) Resent-Date: Thu, 27 Jul 2006 16:00:36 GMT Resent-Message-Id: <200607271600.k6RG0abf050604@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Auster Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 493B816A4DA for ; Thu, 27 Jul 2006 15:59:03 +0000 (UTC) (envelope-from lrou@presto.telepluscom.net) Received: from presto.telepluscom.net (presto.telepluscom.net [217.73.83.2]) by mx1.FreeBSD.org (Postfix) with ESMTP id 79ECF43D6E for ; Thu, 27 Jul 2006 15:58:59 +0000 (GMT) (envelope-from lrou@presto.telepluscom.net) Received: from presto.telepluscom.net (localhost [127.0.0.1]) by presto.telepluscom.net (8.13.6/8.13.6) with ESMTP id k6RFwwsl062228 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 27 Jul 2006 17:58:58 +0200 (CEST) (envelope-from lrou@presto.telepluscom.net) Received: (from lrou@localhost) by presto.telepluscom.net (8.13.6/8.13.6/Submit) id k6RFwvGn062227; Thu, 27 Jul 2006 17:58:57 +0200 (CEST) (envelope-from lrou) Message-Id: <200607271558.k6RFwvGn062227@presto.telepluscom.net> Date: Thu, 27 Jul 2006 17:58:57 +0200 (CEST) From: Auster To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: lrou@x.ua Subject: bin/100921: libexec/tftpd: `-w' non-traditional access control X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Auster List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Jul 2006 16:01:21 -0000 >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: