bin/100921: libexec/tftpd: `-w' non-traditional access control
Auster
lrou at presto.telepluscom.net
Thu Jul 27 16:01:21 UTC 2006
>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 at 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:
More information about the freebsd-bugs
mailing list