Page MenuHomeFreeBSD

D46281.diff
No OneTemporary

D46281.diff

diff --git a/libexec/tftpd/Makefile b/libexec/tftpd/Makefile
--- a/libexec/tftpd/Makefile
+++ b/libexec/tftpd/Makefile
@@ -10,9 +10,17 @@
LIBADD= wrap
.endif
+.if ${MK_CASPER} != "no"
+LIBADD+= casper
+LIBADD+= cap_dns
+LIBADD+= cap_net
+LIBADD+= cap_fileargs
+CFLAGS+=-DWITH_CASPER
+.endif
+
CWARNFLAGS.gcc+= -Wno-format-nonliteral
HAS_TESTS=
SUBDIR.${MK_TESTS}+= tests
-
+LIBADD+= ipsec
.include <bsd.prog.mk>
diff --git a/libexec/tftpd/tftp-io.c b/libexec/tftpd/tftp-io.c
--- a/libexec/tftpd/tftp-io.c
+++ b/libexec/tftpd/tftp-io.c
@@ -106,8 +106,7 @@
for (i = 0; i < 12 ; i++) {
DROPPACKETn("send_packet", 0);
- if (sendto(peer, pkt, size, 0, (struct sockaddr *)&peer_sock,
- peer_sock.ss_len) == size) {
+ if (send(peer, pkt, size, 0) == size) {
if (i)
tftp_log(LOG_ERR,
"%s block %d, attempt %d successful",
@@ -162,8 +161,7 @@
if (debug & DEBUG_PACKETS)
tftp_log(LOG_DEBUG, "Sending ERROR %d: %s", error, tp->th_msg);
- if (sendto(peer, buf, length, 0,
- (struct sockaddr *)&peer_sock, peer_sock.ss_len) != length)
+ if (send(peer, buf, length, 0) != length)
tftp_log(LOG_ERR, "send_error: %s", strerror(errno));
}
@@ -206,8 +204,7 @@
if (options_rfc_enabled)
size += make_options(peer, bp, sizeof(buf) - size);
- n = sendto(peer, buf, size, 0,
- (struct sockaddr *)&peer_sock, peer_sock.ss_len);
+ n = send(peer, buf, size, 0);
if (n != size) {
tftp_log(LOG_ERR, "send_wrq: %s", strerror(errno));
return (1);
@@ -256,8 +253,7 @@
size += make_options(peer, bp, sizeof(buf) - size);
}
- n = sendto(peer, buf, size, 0,
- (struct sockaddr *)&peer_sock, peer_sock.ss_len);
+ n = send(peer, buf, size, 0);
if (n != size) {
tftp_log(LOG_ERR, "send_rrq: %d %s", n, strerror(errno));
return (1);
@@ -303,8 +299,7 @@
}
size = bp - buf;
- if (sendto(peer, buf, size, 0,
- (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
+ if (send(peer, buf, size, 0) != size) {
tftp_log(LOG_INFO, "send_oack: %s", strerror(errno));
return (1);
}
@@ -332,8 +327,7 @@
tp->th_block = htons((u_short)block);
size = 4;
- if (sendto(fp, buf, size, 0,
- (struct sockaddr *)&peer_sock, peer_sock.ss_len) != size) {
+ if (send(fp, buf, size, 0) != size) {
tftp_log(LOG_INFO, "send_ack: %s", strerror(errno));
return (1);
}
@@ -381,7 +375,6 @@
struct tftphdr *pkt;
struct sockaddr_storage from_local;
struct sockaddr_storage *pfrom;
- socklen_t fromlen;
int n;
if (debug & DEBUG_PACKETS)
@@ -399,8 +392,7 @@
}
pfrom = (from == NULL) ? &from_local : from;
- fromlen = sizeof(*pfrom);
- n = recvfrom(peer, data, size, 0, (struct sockaddr *)pfrom, &fromlen);
+ n = recv(peer, data, size, 0);
DROPPACKETn("receive_packet", RP_TIMEOUT);
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -36,8 +36,10 @@
* <guyton@rand-unix>.
*/
+#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/ioctl.h>
+#include <sys/nv.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -45,8 +47,15 @@
#include <netinet/in.h>
#include <arpa/tftp.h>
+#include <libcasper.h>
+#include <casper/cap_dns.h>
+#include <casper/cap_fileargs.h>
+#include <casper/cap_net.h>
+#include <capsicum_helpers.h>
+
#include <ctype.h>
#include <errno.h>
+#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
@@ -64,10 +73,9 @@
#include "tftp-transfer.h"
#include "tftp-options.h"
-#ifdef LIBWRAP
+#ifdef LIBWRAP
#include <tcpd.h>
#endif
-
static void tftp_wrq(int peer, char *, size_t);
static void tftp_rrq(int peer, char *, size_t);
@@ -123,11 +131,20 @@
char recvbuffer[MAXPKTSIZE];
int allow_ro = 1, allow_wo = 1, on = 1;
pid_t pid;
-
+ cap_channel_t *casper;
+ cap_channel_t *casnet;
+
+ tftp_openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
tzset(); /* syslog in localtime */
acting_as_client = 0;
+ casper = cap_init();
+ casnet = cap_service_open(casper, "system.net");
+ if (casper == NULL)
+ tftp_log(LOG_ERR, "Unable to contact Casper");
+ cap_close(casper);
+ caph_cache_catpages();
+ caph_cache_tzdata();
- tftp_openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
while ((ch = getopt(argc, argv, "cCd::F:lnoOp:s:Su:U:wW")) != -1) {
switch (ch) {
case 'c':
@@ -196,6 +213,7 @@
for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
optind++) {
if (argv[optind][0] == '/') {
+ tftp_log(LOG_ERR,"%s",argv[optind]);
dirp->name = argv[optind];
dirp->len = strlen(dirp->name);
dirp++;
@@ -221,19 +239,18 @@
/* Find out who we are talking to and what we are going to do */
peerlen = sizeof(peer_sock);
n = recvfrom(0, recvbuffer, MAXPKTSIZE, 0,
- (struct sockaddr *)&peer_sock, &peerlen);
+ (struct sockaddr *)&peer_sock, &peerlen);
if (n < 0) {
tftp_log(LOG_ERR, "recvfrom: %s", strerror(errno));
exit(1);
}
- getnameinfo((struct sockaddr *)&peer_sock, peer_sock.ss_len,
+ cap_getnameinfo(casnet, (struct sockaddr *)&peer_sock, peer_sock.ss_len,
peername, sizeof(peername), NULL, 0, NI_NUMERICHOST);
if ((size_t)n < 4 /* tftphdr */) {
tftp_log(LOG_ERR, "Rejecting %zd-byte request from %s",
n, peername);
exit(1);
}
-
/*
* Now that we have read the message out of the UDP
* socket, we fork and exit. Thus, inetd will go back
@@ -313,6 +330,7 @@
* recvfrom to keep inetd from constantly forking should there
* be a problem. See the above comment about system clogging.
*/
+
if (chroot_dir) {
if (ipchroot > 0) {
char *tempchroot;
@@ -324,7 +342,7 @@
statret = -1;
memcpy(&ss, &peer_sock, peer_sock.ss_len);
unmappedaddr((struct sockaddr_in6 *)&ss);
- getnameinfo((struct sockaddr *)&ss, ss.ss_len,
+ cap_getnameinfo(casnet, (struct sockaddr *)&ss, ss.ss_len,
hbuf, sizeof(hbuf), NULL, 0,
NI_NUMERICHOST);
asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
@@ -361,7 +379,6 @@
}
if (check_woth == -1)
check_woth = 1;
-
len = sizeof(me_sock);
if (getsockname(0, (struct sockaddr *)&me_sock, &len) == 0) {
switch (me_sock.ss_family) {
@@ -388,10 +405,15 @@
tftp_log(LOG_ERR, "socket: %s", strerror(errno));
exit(1);
}
- if (bind(peer, (struct sockaddr *)&me_sock, me_sock.ss_len) < 0) {
+
+ if (cap_bind(casnet, peer, (struct sockaddr *)&me_sock, me_sock.ss_len) < 0) {
tftp_log(LOG_ERR, "bind: %s", strerror(errno));
exit(1);
}
+ if (cap_connect(casnet, peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) {
+ tftp_log(LOG_ERR, "connect:%s",strerror(errno));
+ exit(1);
+ }
tp = (struct tftphdr *)recvbuffer;
tp->th_opcode = ntohs(tp->th_opcode);
@@ -403,6 +425,7 @@
"%s read access denied", peername);
exit(1);
}
+ tftp_log(LOG_ERR,"out");
} else if (tp->th_opcode == WRQ) {
if (allow_wo)
tftp_wrq(peer, tp->th_stuff, (size_t)n - 1);
@@ -521,6 +544,7 @@
else
send_ack(peer, 0);
}
+
if (logging) {
tftp_log(LOG_INFO, "%s: write request for %s: %s", peername,
filename, errtomsg(ecode));
@@ -551,8 +575,8 @@
strlcpy(fnbuf, filename, sizeof(fnbuf));
reduce_path(fnbuf);
filename = fnbuf;
-
- if (size > 0) {
+
+ if(size > 0) {
if (options_rfc_enabled)
has_options = !parse_options(peer, cp, size);
else
@@ -609,7 +633,7 @@
* execessive anyway.
*/
static int
-find_next_name(char *filename, int *fd)
+find_next_name(char *filename, int *fd, fileargs_t *fa)
{
/*
* GCC "knows" that we might write all of yyyymmdd plus the static
@@ -658,7 +682,7 @@
*/
if (ret < 0 || (size_t)ret >= sizeof(newname))
__unreachable();
- *fd = open(newname, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ *fd = fileargs_open(fa, newname);
if (*fd > 0)
return 0;
}
@@ -680,27 +704,58 @@
int
validate_access(int peer, char **filep, int mode)
{
- static char pathname[MAXPATHLEN];
- struct stat sb;
+ struct stat stbuf;
+ int fd;
+ int error;
struct dirlist *dirp;
+ static char pathname[MAXPATHLEN];
char *filename = *filep;
- int err, fd;
+ char *fnlist[1];
+ fileargs_t *fa;
+ cap_rights_t rights;
/*
* Prevent tricksters from getting around the directory restrictions
*/
- if (strncmp(filename, "../", 3) == 0 ||
- strstr(filename, "/../") != NULL)
- return (EACCESS);
+ if(strncmp(filename,"../",3) == 0 ||
+ strstr(filename,"/../") != NULL)
+ return (EACCESS);
+
+ if(*filename != '/') {
+ for (dirp = dirs; dirp->name != NULL; dirp++) {
+ snprintf(pathname, sizeof(pathname), "%s/%s",
+ dirp->name, filename);
+ }
+ fnlist[0] = pathname;
+ } else
+ fnlist[0] = filename;
+ if (mode == RRQ) {
+ fa = fileargs_init(1, fnlist, O_RDWR, 0,
+ cap_rights_init(&rights, CAP_FCNTL, CAP_READ
+ , CAP_SEEK, CAP_FSTAT, CAP_CONNECT, CAP_WRITE), FA_OPEN | FA_LSTAT);
+ if (fa == NULL)
+ tftp_log(LOG_DEBUG, "unable to open rrq system.fileargs service");
+ } else {
+ fa = fileargs_init(1, fnlist, O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP |
+ S_IWGRP | S_IROTH | S_IWOTH,
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_CREATE,
+ CAP_FCNTL ,CAP_SEEK, CAP_FTRUNCATE, CAP_FSTAT, CAP_CONNECT), FA_OPEN);
+ if (fa == NULL)
+ tftp_log(LOG_DEBUG, "unable to open wrq system.fileargs service");
+ }
+
+ if (caph_enter_casper() < 0)
+ tftp_log(LOG_ERR, "Unable to enter capability mode");
if (*filename == '/') {
/*
- * Absolute file name: allow the request if it's in one of the
- * approved locations.
+ * Allow the request if it's in one of the approved locations.
+ * Special case: check the null prefix ("/") by looking
+ * for length = 1 and relying on the arg. processing that
+ * it's a /.
*/
for (dirp = dirs; dirp->name != NULL; dirp++) {
if (dirp->len == 1)
- /* Only "/" can have len 1 */
break;
if (strncmp(filename, dirp->name, dirp->len) == 0 &&
filename[dirp->len] == '/')
@@ -709,42 +764,78 @@
/* If directory list is empty, allow access to any file */
if (dirp->name == NULL && dirp != dirs)
return (EACCESS);
- if (stat(filename, &sb) != 0)
+
+ if (mode == RRQ) {
+ fd = fileargs_open(fa, filename);
+ } else if (create_new) {
+ if (increase_name) {
+ error = find_next_name(pathname, &fd, fa);
+ if (error > 0)
+ return (error + 100);
+ } else {
+ fd = fileargs_open(fa, filename);
+ }
+ } else {
+ fd = fileargs_open(fa, filename);
+ }
+
+ if(dirp->name == NULL && dirp != dirs)
+ return (EACCESS);
+ if (fstat(fd, &stbuf) < 0)
return (errno == ENOENT ? ENOTFOUND : EACCESS);
- if (!S_ISREG(sb.st_mode))
+ if ((stbuf.st_mode & S_IFMT) != S_IFREG)
return (ENOTFOUND);
if (mode == RRQ) {
- if ((sb.st_mode & S_IROTH) == 0)
+ if ((stbuf.st_mode & S_IROTH) == 0)
return (EACCESS);
} else {
- if (check_woth && (sb.st_mode & S_IWOTH) == 0)
+ if (check_woth && ((stbuf.st_mode & S_IWOTH) == 0))
return (EACCESS);
}
} else {
+ int err;
+
/*
* Relative file name: search the approved locations for it.
* If the file exists in one of the directories and isn't
* readable, continue looking. However, change the error code
* to give an indication that the file exists.
*/
+
err = ENOTFOUND;
for (dirp = dirs; dirp->name != NULL; dirp++) {
snprintf(pathname, sizeof(pathname), "%s/%s",
- dirp->name, filename);
- if (stat(pathname, &sb) != 0)
+ dirp->name, filename);
+ if (mode == RRQ) {
+ fd = fileargs_open(fa, pathname);
+ } else if (create_new) {
+ if (increase_name) {
+ err = find_next_name(pathname, &fd, fa);
+ if (err > 0)
+ return (err + 100);
+ } else {
+ fd = fileargs_open(fa, pathname);
+ }
+ } else {
+ fd = fileargs_open(fa, pathname);
+ }
+ if (fstat(fd, &stbuf) != 0) {
+ tftp_log(LOG_ERR, "fstat failed:%d",errno);
continue;
- if (!S_ISREG(sb.st_mode))
+ }
+ if (!S_ISREG(stbuf.st_mode))
continue;
err = EACCESS;
if (mode == RRQ) {
- if ((sb.st_mode & S_IROTH) == 0)
+ if ((stbuf.st_mode & S_IROTH) == 0)
continue;
} else {
- if (check_woth && (sb.st_mode & S_IWOTH) == 0)
+ if (check_woth && (stbuf.st_mode & S_IWOTH) == 0)
continue;
}
break;
}
+
if (dirp->name != NULL)
*filep = filename = pathname;
else if (mode == RRQ)
@@ -757,31 +848,18 @@
* This option is handled here because it (might) require(s) the
* size of the file.
*/
- option_tsize(peer, NULL, mode, &sb);
-
- if (mode == RRQ) {
- fd = open(filename, O_RDONLY);
- } else if (create_new) {
- if (increase_name) {
- err = find_next_name(filename, &fd);
- if (err > 0)
- return (err + 100);
- } else {
- fd = open(filename,
- O_WRONLY | O_TRUNC | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP |
- S_IWGRP | S_IROTH | S_IWOTH );
- }
- } else {
- fd = open(filename, O_WRONLY | O_TRUNC);
- }
- if (fd < 0)
+ option_tsize(peer, NULL, mode, &stbuf);
+ if (fd < 0){
+ tftp_log(LOG_ERR,"fd");
return (errno + 100);
- file = fdopen(fd, mode == RRQ ? "r" : "w");
+ }
+ file = fdopen(fd, (mode == RRQ)? "r":"w");
if (file == NULL) {
+ tftp_log(LOG_ERR,"null file");
close(fd);
return (errno + 100);
}
+ fileargs_free(fa);
return (0);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Dec 18, 10:59 AM (18 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15485416
Default Alt Text
D46281.diff (13 KB)

Event Timeline