Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F105542076
D46281.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D46281.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D46281: tftpd:capsicumize tftpd
Attached
Detach File
Event Timeline
Log In to Comment