tftpd: make open() check r/w permissions instead of doing it ourself.

Add -r "prohibit upload" opt for those lazy people who run tftpd as root.
-40 bytes.
This commit is contained in:
Denis Vlasenko 2008-03-18 01:13:11 +00:00
parent 78c5656530
commit d7e6af2dda
2 changed files with 31 additions and 23 deletions

View File

@ -3977,9 +3977,11 @@
)
#define tftpd_trivial_usage \
"[DIR]"
"[-r] [DIR]"
#define tftpd_full_usage \
"Transfer a file on request from a tftp client" \
"Transfer a file on request from a tftp client.\n" \
"\nOptions:" \
"\n -r Prohibit upload" \
#define time_trivial_usage \
"[OPTION]... COMMAND [ARGS...]"

View File

@ -56,6 +56,8 @@
* CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
*/
// TODO: emit error packets before dying
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
@ -340,7 +342,7 @@ static int tftp_protocol(
const char *msg = "";
if (rbuf[4] != '\0') {
if (len > 4 && rbuf[4] != '\0') {
msg = &rbuf[4];
rbuf[tftp_bufsize - 1] = '\0';
} else if (recv_blk < ARRAY_SIZE(errcode_str)) {
@ -533,14 +535,14 @@ static len_and_sockaddr *get_sock_lsa(int s)
}
int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
struct stat statbuf;
char block_buf[TFTP_BLOCKSIZE_DEFAULT];
len_and_sockaddr *our_lsa;
len_and_sockaddr *peer_lsa;
char *filename, *mode, *opt_str;
int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize;
int opt_r, result, opcode, open_mode, local_fd, blksize;
USE_GETPUT(int cmd;)
our_lsa = get_sock_lsa(STDIN_FILENO);
if (!our_lsa)
@ -548,8 +550,10 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
peer_lsa->len = our_lsa->len;
if (argv[1])
xchdir(argv[1]);
opt_r = getopt32(argv, "r");
argv += optind;
if (argv[0])
xchdir(argv[0]);
result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
0 /* flags */,
@ -558,7 +562,10 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
opcode = ntohs(*(uint16_t*)block_buf);
if (result < 4 || result >= sizeof(block_buf)
|| block_buf[result-1] != '\0'
|| (opcode != TFTP_RRQ && opcode != TFTP_WRQ)
|| (USE_FEATURE_TFTP_GET(opcode != TFTP_RRQ) /* not download */
USE_GETPUT(&&)
USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
)
) {
bb_error_msg_and_die("malformed packet");
}
@ -584,21 +591,20 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
}
}
#endif
xstat(filename, &statbuf);
/* if opcode == TFTP_WRQ: */
cmd = 1; /* CMD_GET: we will receive file's data */
req_modebits = 0222; /* writable by anyone */
open_mode = O_WRONLY | O_TRUNC;
if (opcode == TFTP_RRQ) {
cmd = 2; /* CMD_PUT */
req_modebits = 0444; /* readable by anyone */
open_mode = O_RDONLY;
}
if (!S_ISREG(statbuf.st_mode)
|| (statbuf.st_mode & req_modebits) != req_modebits
) {
bb_error_msg_and_die("access to '%s' is denied", filename);
#if ENABLE_FEATURE_TFTP_PUT
/* in case opcode is TFTP_RRQ: */
USE_GETPUT(cmd = 2;) /* CMD_PUT: we will send file's data */
open_mode = O_RDONLY;
#endif
#if ENABLE_FEATURE_TFTP_GET
if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
if (opt_r)
bb_error_msg_and_die("upload is prohibited");
USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */
open_mode = O_WRONLY | O_TRUNC;
}
#endif
local_fd = xopen(filename, open_mode);
close(STDIN_FILENO); /* close old, possibly wildcard socket */