From dbed6c4b46f3c8dc74d50e4cf35b1cb8b8c4ff2d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 18 Jul 2012 17:32:32 +0200 Subject: tftpd: fix -u USER to work with chroot. Closes 5348 function old new delta tftpd_main 546 568 +22 tftp_protocol 1844 1839 -5 Signed-off-by: Denys Vlasenko --- networking/tftp.c | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'networking') diff --git a/networking/tftp.c b/networking/tftp.c index ce48a1edd..630fdaf9a 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -116,7 +116,7 @@ enum { struct globals { /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ uint8_t error_pkt[4 + 32]; - char *user_opt; + struct passwd *pw; /* used in tftpd_main(), a bit big for stack: */ char block_buf[TFTP_BLKSIZE_DEFAULT]; #if ENABLE_FEATURE_TFTP_PROGRESS_BAR @@ -130,13 +130,10 @@ struct globals { struct BUG_G_too_big { char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; -#define block_buf (G.block_buf ) -#define user_opt (G.user_opt ) -#define error_pkt (G.error_pkt ) #define INIT_G() do { } while (0) -#define error_pkt_reason (error_pkt[3]) -#define error_pkt_str (error_pkt + 4) +#define G_error_pkt_reason (G.error_pkt[3]) +#define G_error_pkt_str ((char*)(G.error_pkt + 4)) #if ENABLE_FEATURE_TFTP_PROGRESS_BAR static void tftp_progress_update(void) @@ -272,12 +269,11 @@ static int tftp_protocol( xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); /* Is there an error already? Send pkt and bail out */ - if (error_pkt_reason || error_pkt_str[0]) + if (G_error_pkt_reason || G_error_pkt_str[0]) goto send_err_pkt; - if (user_opt) { - struct passwd *pw = xgetpwnam(user_opt); - change_identity(pw); /* initgroups, setgid, setuid */ + if (G.pw) { + change_identity(G.pw); /* initgroups, setgid, setuid */ } } @@ -329,8 +325,8 @@ static int tftp_protocol( /* Open file (must be after changing user) */ local_fd = open(local_file, open_mode, 0666); if (local_fd < 0) { - error_pkt_reason = ERR_NOFILE; - strcpy((char*)error_pkt_str, "can't open file"); + G_error_pkt_reason = ERR_NOFILE; + strcpy(G_error_pkt_str, "can't open file"); goto send_err_pkt; } /* gcc 4.3.1 would NOT optimize it out as it should! */ @@ -575,7 +571,7 @@ static int tftp_protocol( if (res) { blksize = tftp_blksize_check(res, blksize); if (blksize < 0) { - error_pkt_reason = ERR_BAD_OPT; + G_error_pkt_reason = ERR_BAD_OPT; goto send_err_pkt; } io_bufsize = blksize + 4; @@ -614,8 +610,8 @@ static int tftp_protocol( if (recv_blk == block_nr) { int sz = full_write(local_fd, &rbuf[4], len - 4); if (sz != len - 4) { - strcpy((char*)error_pkt_str, bb_msg_write_error); - error_pkt_reason = ERR_WRITE; + strcpy(G_error_pkt_str, bb_msg_write_error); + G_error_pkt_reason = ERR_WRITE; goto send_err_pkt; } if (sz != blksize) { @@ -664,12 +660,12 @@ static int tftp_protocol( return finished == 0; /* returns 1 on failure */ send_read_err_pkt: - strcpy((char*)error_pkt_str, bb_msg_read_error); + strcpy(G_error_pkt_str, bb_msg_read_error); send_err_pkt: - if (error_pkt_str[0]) - bb_error_msg("%s", (char*)error_pkt_str); - error_pkt[1] = TFTP_ERROR; - xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str), + if (G_error_pkt_str[0]) + bb_error_msg("%s", G_error_pkt_str); + G.error_pkt[1] = TFTP_ERROR; + xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), &peer_lsa->u.sa, peer_lsa->len); return EXIT_FAILURE; #undef remote_file @@ -761,7 +757,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) { len_and_sockaddr *our_lsa; len_and_sockaddr *peer_lsa; - char *local_file, *mode; + char *local_file, *mode, *user_opt; const char *error_msg; int opt, result, opcode; IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;) @@ -789,18 +785,22 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, LOG_PID, LOG_DAEMON); logmode = LOGMODE_SYSLOG; } + if (opt & TFTPD_OPT_u) { + /* Must be before xchroot */ + G.pw = xgetpwnam(user_opt); + } if (argv[0]) { xchroot(argv[0]); } - result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), + result = recv_from_to(STDIN_FILENO, G.block_buf, sizeof(G.block_buf), 0 /* flags */, &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); error_msg = "malformed packet"; - opcode = ntohs(*(uint16_t*)block_buf); - if (result < 4 || result >= sizeof(block_buf) - || block_buf[result-1] != '\0' + opcode = ntohs(*(uint16_t*)G.block_buf); + if (result < 4 || result >= sizeof(G.block_buf) + || G.block_buf[result-1] != '\0' || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */ IF_GETPUT(&&) IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */ @@ -808,27 +808,27 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) ) { goto err; } - local_file = block_buf + 2; + local_file = G.block_buf + 2; if (local_file[0] == '.' || strstr(local_file, "/.")) { error_msg = "dot in file name"; goto err; } mode = local_file + strlen(local_file) + 1; /* RFC 1350 says mode string is case independent */ - if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) { + if (mode >= G.block_buf + result || strcasecmp(mode, "octet") != 0) { goto err; } # if ENABLE_FEATURE_TFTP_BLOCKSIZE { char *res; char *opt_str = mode + sizeof("octet"); - int opt_len = block_buf + result - opt_str; + int opt_len = G.block_buf + result - opt_str; if (opt_len > 0) { res = tftp_get_option("blksize", opt_str, opt_len); if (res) { blksize = tftp_blksize_check(res, 65564); if (blksize < 0) { - error_pkt_reason = ERR_BAD_OPT; + G_error_pkt_reason = ERR_BAD_OPT; /* will just send error pkt */ goto do_proto; } @@ -846,7 +846,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { if (opt & TFTPD_OPT_r) { /* This would mean "disk full" - not true */ - /*error_pkt_reason = ERR_WRITE;*/ + /*G_error_pkt_reason = ERR_WRITE;*/ error_msg = bb_msg_write_error; goto err; } @@ -855,7 +855,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */ } - /* NB: if error_pkt_str or error_pkt_reason is set up, + /* NB: if G_error_pkt_str or G_error_pkt_reason is set up, * tftp_protocol() just sends one error pkt and returns */ do_proto: @@ -870,7 +870,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) return result; err: - strcpy((char*)error_pkt_str, error_msg); + strcpy(G_error_pkt_str, error_msg); goto do_proto; } -- cgit v1.2.3