aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-19 13:07:00 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-19 13:07:00 +0000
commit403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44 (patch)
tree6a31deaf0444b2e375a03db0a66c0d14d61e97c9
parent71c9f015e9d83910ea3ae127944ef5d900c5a582 (diff)
downloadbusybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.tar.gz
busybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.tar.bz2
busybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.zip
tftpd: options -c (allow _new_ files to be uploaded) and -u USER
function old new delta tftp_protocol 1316 1466 +150 packed_usage 23774 23798 +24 tftpd_main 509 502 -7 tftp_main 311 252 -59 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/2 up/down: 174/-66) Total: 108 bytes text data bss dec hex filename 797700 641 7380 805721 c4b59 busybox_old 797833 641 7380 805854 c4bde busybox_unstripped
-rw-r--r--include/usage.h6
-rw-r--r--networking/tftp.c147
2 files changed, 88 insertions, 65 deletions
diff --git a/include/usage.h b/include/usage.h
index 7fe9ad063..ad9009763 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3977,11 +3977,13 @@
3977 ) 3977 )
3978 3978
3979#define tftpd_trivial_usage \ 3979#define tftpd_trivial_usage \
3980 "[-r] [DIR]" 3980 "[-cr] [-u USER] [DIR]"
3981#define tftpd_full_usage \ 3981#define tftpd_full_usage \
3982 "Transfer a file on request from a tftp client.\n" \ 3982 "Transfer a file on tftp client's request.\n" \
3983 "\nOptions:" \ 3983 "\nOptions:" \
3984 "\n -r Prohibit upload" \ 3984 "\n -r Prohibit upload" \
3985 "\n -c Allow file creation via upload" \
3986 "\n -u Access files as USER" \
3985 3987
3986#define time_trivial_usage \ 3988#define time_trivial_usage \
3987 "[OPTION]... COMMAND [ARGS...]" 3989 "[OPTION]... COMMAND [ARGS...]"
diff --git a/networking/tftp.c b/networking/tftp.c
index e0f2b91cf..5fac48769 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -51,6 +51,17 @@
51#define ERR_BAD_USER 7 51#define ERR_BAD_USER 7
52#define ERR_BAD_OPT 8 52#define ERR_BAD_OPT 8
53 53
54/* masks coming from getopt32 */
55enum {
56 TFTP_OPT_GET = (1 << 0),
57 TFTP_OPT_PUT = (1 << 1),
58 /* pseudo option: if set, it's tftpd */
59 TFTPD_OPT = (1 << 7) * ENABLE_TFTPD,
60 TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD,
61 TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD,
62 TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD,
63};
64
54#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT 65#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
55#define USE_GETPUT(...) 66#define USE_GETPUT(...)
56#define CMD_GET(cmd) 1 67#define CMD_GET(cmd) 1
@@ -61,9 +72,8 @@
61#define CMD_PUT(cmd) 1 72#define CMD_PUT(cmd) 1
62#else 73#else
63#define USE_GETPUT(...) __VA_ARGS__ 74#define USE_GETPUT(...) __VA_ARGS__
64/* masks coming from getopt32 */ 75#define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
65#define CMD_GET(cmd) ((cmd) & 1) 76#define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
66#define CMD_PUT(cmd) ((cmd) & 2)
67#endif 77#endif
68/* NB: in the code below 78/* NB: in the code below
69 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive 79 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
@@ -73,11 +83,15 @@
73struct globals { 83struct globals {
74 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ 84 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
75 uint8_t error_pkt[4 + 32]; 85 uint8_t error_pkt[4 + 32];
86#if ENABLE_TFTPD
87 char *user_opt;
88#endif
76 /* used in tftpd_main(), a bit big for stack: */ 89 /* used in tftpd_main(), a bit big for stack: */
77 char block_buf[TFTP_BLKSIZE_DEFAULT]; 90 char block_buf[TFTP_BLKSIZE_DEFAULT];
78}; 91};
79#define G (*(struct globals*)&bb_common_bufsiz1) 92#define G (*(struct globals*)&bb_common_bufsiz1)
80#define block_buf (G.block_buf ) 93#define block_buf (G.block_buf )
94#define user_opt (G.user_opt )
81#define error_pkt (G.error_pkt ) 95#define error_pkt (G.error_pkt )
82#define INIT_G() \ 96#define INIT_G() \
83 do { \ 97 do { \
@@ -148,11 +162,10 @@ static char *tftp_get_blksize(char *buf, int len)
148#endif 162#endif
149 163
150static int tftp_protocol( 164static int tftp_protocol(
151 USE_GETPUT(int cmd,)
152 len_and_sockaddr *our_lsa, 165 len_and_sockaddr *our_lsa,
153 len_and_sockaddr *peer_lsa, 166 len_and_sockaddr *peer_lsa,
167 const char *local_file,
154 USE_TFTP(const char *remote_file,) 168 USE_TFTP(const char *remote_file,)
155 int local_fd,
156 int blksize) 169 int blksize)
157{ 170{
158#if !ENABLE_TFTP 171#if !ENABLE_TFTP
@@ -167,6 +180,7 @@ static int tftp_protocol(
167 uint16_t opcode; 180 uint16_t opcode;
168 uint16_t block_nr; 181 uint16_t block_nr;
169 uint16_t recv_blk; 182 uint16_t recv_blk;
183 int open_mode, local_fd;
170 int retries, waittime_ms; 184 int retries, waittime_ms;
171 int io_bufsize = blksize + 4; 185 int io_bufsize = blksize + 4;
172 char *cp; 186 char *cp;
@@ -180,6 +194,39 @@ static int tftp_protocol(
180 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); 194 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
181 setsockopt_reuseaddr(socket_fd); 195 setsockopt_reuseaddr(socket_fd);
182 196
197#if ENABLE_TFTPD
198 if (user_opt) {
199 struct passwd *pw = getpwnam(user_opt); /* initgroups, setgid, setuid */
200 if (!pw)
201 bb_error_msg_and_die("unknown user '%s'", user_opt);
202 change_identity(pw);
203 }
204#endif
205
206 if (CMD_PUT(option_mask32)) {
207 open_mode = O_RDONLY;
208 } else {
209 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
210#if ENABLE_TFTPD
211 if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) {
212 /* tftpd without -c */
213 open_mode = O_WRONLY | O_TRUNC;
214 }
215#endif
216 }
217 if (!(option_mask32 & TFTPD_OPT)) {
218 local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO;
219 if (NOT_LONE_DASH(local_file))
220 local_fd = xopen(local_file, open_mode);
221 } else {
222 local_fd = open_or_warn(local_file, open_mode);
223 if (local_fd < 0) {
224 /*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/
225 strcpy(error_pkt_str, "can't open file");
226 goto send_err_pkt;
227 }
228 }
229
183 block_nr = 1; 230 block_nr = 1;
184 if (!ENABLE_TFTP || our_lsa) { 231 if (!ENABLE_TFTP || our_lsa) {
185 /* tftpd */ 232 /* tftpd */
@@ -197,7 +244,7 @@ static int tftp_protocol(
197 if (error_pkt_reason || error_pkt_str[0]) 244 if (error_pkt_reason || error_pkt_str[0])
198 goto send_err_pkt; 245 goto send_err_pkt;
199 246
200 if (CMD_GET(cmd)) { 247 if (CMD_GET(option_mask32)) {
201 /* it's upload - we must ACK 1st packet (with filename) 248 /* it's upload - we must ACK 1st packet (with filename)
202 * as if it's "block 0" */ 249 * as if it's "block 0" */
203 block_nr = 0; 250 block_nr = 0;
@@ -231,7 +278,7 @@ static int tftp_protocol(
231 278
232 /* build opcode */ 279 /* build opcode */
233 opcode = TFTP_WRQ; 280 opcode = TFTP_WRQ;
234 if (CMD_GET(cmd)) { 281 if (CMD_GET(option_mask32)) {
235 opcode = TFTP_RRQ; 282 opcode = TFTP_RRQ;
236 } 283 }
237 cp = xbuf + 2; 284 cp = xbuf + 2;
@@ -276,7 +323,7 @@ static int tftp_protocol(
276 cp += 2; 323 cp += 2;
277 block_nr++; 324 block_nr++;
278 opcode = TFTP_ACK; 325 opcode = TFTP_ACK;
279 if (CMD_PUT(cmd)) { 326 if (CMD_PUT(option_mask32)) {
280 opcode = TFTP_DATA; 327 opcode = TFTP_DATA;
281 len = full_read(local_fd, cp, blksize); 328 len = full_read(local_fd, cp, blksize);
282 if (len < 0) { 329 if (len < 0) {
@@ -420,7 +467,7 @@ static int tftp_protocol(
420 /* block_nr is already advanced to next block# we expect 467 /* block_nr is already advanced to next block# we expect
421 * to get / block# we are about to send next time */ 468 * to get / block# we are about to send next time */
422 469
423 if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { 470 if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) {
424 if (recv_blk == block_nr) { 471 if (recv_blk == block_nr) {
425 int sz = full_write(local_fd, &rbuf[4], len - 4); 472 int sz = full_write(local_fd, &rbuf[4], len - 4);
426 if (sz != len - 4) { 473 if (sz != len - 4) {
@@ -440,7 +487,7 @@ static int tftp_protocol(
440 } 487 }
441 } 488 }
442 489
443 if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { 490 if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) {
444 /* did peer ACK our last DATA pkt? */ 491 /* did peer ACK our last DATA pkt? */
445 if (recv_blk == (uint16_t) (block_nr - 1)) { 492 if (recv_blk == (uint16_t) (block_nr - 1)) {
446 if (finished) 493 if (finished)
@@ -462,6 +509,7 @@ static int tftp_protocol(
462 } /* end of "while (1)" */ 509 } /* end of "while (1)" */
463 ret: 510 ret:
464 if (ENABLE_FEATURE_CLEAN_UP) { 511 if (ENABLE_FEATURE_CLEAN_UP) {
512 close(local_fd);
465 close(socket_fd); 513 close(socket_fd);
466 free(xbuf); 514 free(xbuf);
467 free(rbuf); 515 free(rbuf);
@@ -487,13 +535,11 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
487 len_and_sockaddr *peer_lsa; 535 len_and_sockaddr *peer_lsa;
488 const char *local_file = NULL; 536 const char *local_file = NULL;
489 const char *remote_file = NULL; 537 const char *remote_file = NULL;
490 int port;
491 USE_GETPUT(int cmd;)
492 int local_fd;
493 int flags = 0;
494 int result;
495 int blksize;
496 const char *blksize_str = "512"; 538 const char *blksize_str = "512";
539 int blksize;
540 int result;
541 int port;
542 USE_GETPUT(int opt;)
497 543
498 INIT_G(); 544 INIT_G();
499 545
@@ -501,17 +547,13 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
501 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") 547 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
502 USE_GETPUT("g--p:p--g:"); 548 USE_GETPUT("g--p:p--g:");
503 549
504 USE_GETPUT(cmd =) getopt32(argv, 550 USE_GETPUT(opt =) getopt32(argv,
505 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") 551 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
506 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), 552 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
507 &local_file, &remote_file 553 &local_file, &remote_file
508 USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str)); 554 USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
509 argv += optind; 555 argv += optind;
510 556
511 flags = O_RDONLY;
512 if (CMD_GET(cmd))
513 flags = O_WRONLY | O_CREAT | O_TRUNC;
514
515#if ENABLE_FEATURE_TFTP_BLOCKSIZE 557#if ENABLE_FEATURE_TFTP_BLOCKSIZE
516 /* Check if the blksize is valid: 558 /* Check if the blksize is valid:
517 * RFC2348 says between 8 and 65464 */ 559 * RFC2348 says between 8 and 65464 */
@@ -530,11 +572,6 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
530 if (!remote_file || !argv[0]) 572 if (!remote_file || !argv[0])
531 bb_show_usage(); 573 bb_show_usage();
532 574
533 local_fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
534 if (!LONE_DASH(local_file)) {
535 local_fd = xopen(local_file, flags);
536 }
537
538 port = bb_lookup_port(argv[1], "udp", 69); 575 port = bb_lookup_port(argv[1], "udp", 69);
539 peer_lsa = xhost2sockaddr(argv[0], port); 576 peer_lsa = xhost2sockaddr(argv[0], port);
540 577
@@ -545,14 +582,11 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
545#endif 582#endif
546 583
547 result = tftp_protocol( 584 result = tftp_protocol(
548 USE_GETPUT(cmd,) 585 NULL /* our_lsa*/, peer_lsa,
549 NULL /* our_lsa*/, 586 local_file, remote_file,
550 peer_lsa, 587 blksize);
551 remote_file, local_fd, blksize);
552 588
553 if (ENABLE_FEATURE_CLEAN_UP) 589 if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
554 close(local_fd);
555 if (result != EXIT_SUCCESS && !LONE_DASH(local_file) && CMD_GET(cmd)) {
556 unlink(local_file); 590 unlink(local_file);
557 } 591 }
558 return result; 592 return result;
@@ -581,9 +615,9 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
581{ 615{
582 len_and_sockaddr *our_lsa; 616 len_and_sockaddr *our_lsa;
583 len_and_sockaddr *peer_lsa; 617 len_and_sockaddr *peer_lsa;
584 char *filename, *mode; 618 char *local_file, *mode;
585 const char *error_msg; 619 const char *error_msg;
586 int opt_r, result, opcode, open_mode; 620 int opt, result, opcode;
587 int local_fd = local_fd; /* for compiler */ 621 int local_fd = local_fd; /* for compiler */
588 int blksize = blksize; 622 int blksize = blksize;
589 USE_GETPUT(int cmd = cmd;) 623 USE_GETPUT(int cmd = cmd;)
@@ -596,7 +630,8 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
596 peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len); 630 peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
597 peer_lsa->len = our_lsa->len; 631 peer_lsa->len = our_lsa->len;
598 632
599 opt_r = getopt32(argv, "r"); 633 /* Shifting to not collide with TFTP_OPTs */
634 opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8);
600 argv += optind; 635 argv += optind;
601 if (argv[0]) 636 if (argv[0])
602 xchdir(argv[0]); 637 xchdir(argv[0]);
@@ -616,15 +651,13 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
616 ) { 651 ) {
617 goto err; 652 goto err;
618 } 653 }
619 filename = block_buf + 2; 654 local_file = block_buf + 2;
620 if (filename[0] == '.' || strstr(filename, "/.")) { 655 if (local_file[0] == '.' || strstr(local_file, "/.")) {
621 error_msg = "dot in filename"; 656 error_msg = "dot in local_file";
622 goto err; 657 goto err;
623 } 658 }
624 mode = filename + strlen(filename) + 1; 659 mode = local_file + strlen(local_file) + 1;
625 if (mode >= block_buf + result 660 if (mode >= block_buf + result || strcmp(mode, "octet") != 0) {
626 || strcmp(mode, "octet") != 0
627 ) {
628 goto err; 661 goto err;
629 } 662 }
630 blksize = TFTP_BLKSIZE_DEFAULT; 663 blksize = TFTP_BLKSIZE_DEFAULT;
@@ -647,29 +680,16 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
647 } 680 }
648#endif 681#endif
649 682
650#if ENABLE_FEATURE_TFTP_PUT
651 /* in case opcode is TFTP_RRQ: */
652 USE_GETPUT(cmd = 2;) /* CMD_PUT: we will send file's data */
653 open_mode = O_RDONLY;
654#endif
655#if ENABLE_FEATURE_TFTP_GET
656 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { 683 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
657 if (opt_r) { 684 if (opt & TFTPD_OPT_r) {
658 /* This would mean "disk full" - not true */ 685 /* This would mean "disk full" - not true */
659 /*error_pkt_reason = ERR_WRITE;*/ 686 /*error_pkt_reason = ERR_WRITE;*/
660 error_msg = bb_msg_write_error; 687 error_msg = bb_msg_write_error;
661 goto err; 688 goto err;
662 } 689 }
663 USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */ 690 USE_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
664 open_mode = O_WRONLY | O_TRUNC; 691 } else {
665 } 692 USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
666#endif
667 local_fd = open(filename, open_mode);
668 if (local_fd < 0) {
669 /*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/
670 error_msg = "can't open file";
671 err:
672 strcpy(error_pkt_str, error_msg);
673 } 693 }
674 694
675 close(STDIN_FILENO); /* close old, possibly wildcard socket */ 695 close(STDIN_FILENO); /* close old, possibly wildcard socket */
@@ -679,14 +699,15 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
679 * tftp_protocol() just sends one error pkt and returns */ 699 * tftp_protocol() just sends one error pkt and returns */
680 do_proto: 700 do_proto:
681 result = tftp_protocol( 701 result = tftp_protocol(
682 USE_GETPUT(cmd,)
683 our_lsa, peer_lsa, 702 our_lsa, peer_lsa,
684 USE_TFTP(NULL /*remote_file*/,) 703 local_file, USE_TFTP(NULL /*remote_file*/,)
685 local_fd,
686 blksize 704 blksize
687 ); 705 );
688 706
689 return result; 707 return result;
708 err:
709 strcpy(error_pkt_str, error_msg);
710 goto do_proto;
690} 711}
691 712
692#endif /* ENABLE_TFTPD */ 713#endif /* ENABLE_TFTPD */