aboutsummaryrefslogtreecommitdiff
path: root/networking/tftp.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-19 05:00:05 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-19 05:00:05 +0000
commitdd9228b861e41c816b31035ce9c2dfa3e5b5dc97 (patch)
treec98c709ef20814eff1ab22d25095dbd13667d0d0 /networking/tftp.c
parentc0183e6e0d0ad0b60b8891cd0a1eeabf3406805c (diff)
downloadbusybox-w32-dd9228b861e41c816b31035ce9c2dfa3e5b5dc97.tar.gz
busybox-w32-dd9228b861e41c816b31035ce9c2dfa3e5b5dc97.tar.bz2
busybox-w32-dd9228b861e41c816b31035ce9c2dfa3e5b5dc97.zip
tftpd: make it emit error packets
telnetd: use login always, not "sometimes login, sometimes shell" text data bss dec hex filename 797612 641 7380 805633 c4b01 busybox_old 797695 641 7380 805716 c4b54 busybox_unstripped
Diffstat (limited to 'networking/tftp.c')
-rw-r--r--networking/tftp.c292
1 files changed, 178 insertions, 114 deletions
diff --git a/networking/tftp.c b/networking/tftp.c
index 3075ab04b..83b0ef36f 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -25,7 +25,7 @@
25 25
26#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 26#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
27 27
28#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ 28#define TFTP_BLKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
29#define TFTP_TIMEOUT_MS 50 29#define TFTP_TIMEOUT_MS 50
30#define TFTP_MAXTIMEOUT_MS 2000 30#define TFTP_MAXTIMEOUT_MS 2000
31#define TFTP_NUM_RETRIES 12 /* number of backed-off retries */ 31#define TFTP_NUM_RETRIES 12 /* number of backed-off retries */
@@ -38,6 +38,17 @@
38#define TFTP_ERROR 5 38#define TFTP_ERROR 5
39#define TFTP_OACK 6 39#define TFTP_OACK 6
40 40
41/* error codes sent over network */
42#define ERR_UNSPEC 0
43#define ERR_NOFILE 1
44#define ERR_ACCESS 2
45#define ERR_WRITE 3
46#define ERR_OP 4
47#define ERR_BAD_ID 5
48#define ERR_EXIST 6
49#define ERR_BAD_USER 7
50#define ERR_BAD_OPT 8
51
41#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT 52#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
42#define USE_GETPUT(...) 53#define USE_GETPUT(...)
43#define CMD_GET(cmd) 1 54#define CMD_GET(cmd) 1
@@ -56,29 +67,48 @@
56 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive 67 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
57 */ 68 */
58 69
59// TODO: emit error packets before dying 70
71struct globals {
72 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
73 uint8_t error_pkt[4 + 32];
74 /* used in tftpd_main(), a bit big fro stack: */
75 char block_buf[TFTP_BLKSIZE_DEFAULT];
76};
77#define G (*(struct globals*)&bb_common_bufsiz1)
78#define block_buf (G.block_buf )
79#define error_pkt (G.error_pkt )
80#define INIT_G() \
81 do { \
82 } while (0)
83
84#define error_pkt_reason (error_pkt[3])
85#define error_pkt_str (error_pkt + 4)
60 86
61 87
62#if ENABLE_FEATURE_TFTP_BLOCKSIZE 88#if ENABLE_FEATURE_TFTP_BLOCKSIZE
63 89
64static int tftp_blocksize_check(int blocksize, int bufsize) 90static int tftp_blksize_check(const char *blksize_str, int maxsize)
65{ 91{
66 /* Check if the blocksize is valid: 92 /* Check if the blksize is valid:
67 * RFC2348 says between 8 and 65464, 93 * RFC2348 says between 8 and 65464,
68 * but our implementation makes it impossible 94 * but our implementation makes it impossible
69 * to use blocksizes smaller than 22 octets. 95 * to use blksizes smaller than 22 octets. */
70 */ 96 unsigned blksize = bb_strtou(blksize_str, NULL, 10);
71 if ((bufsize && (blocksize > bufsize)) 97 if (errno
72 || (blocksize < 24) || (blocksize > 65564) 98 || (blksize < 24) || (blksize > maxsize)
73 ) { 99 ) {
74 bb_error_msg("bad blocksize"); 100 bb_error_msg("bad blocksize '%s'", blksize_str);
75 return 0; 101 return -1;
76 } 102 }
77 return blocksize; 103#if ENABLE_DEBUG_TFTP
104 bb_error_msg("using blksize %u", blksize);
105#endif
106 return blksize;
78} 107}
79 108
80static char *tftp_option_get(char *buf, int len, const char *option) 109static char *tftp_get_blksize(char *buf, int len)
81{ 110{
111#define option "blksize"
82 int opt_val = 0; 112 int opt_val = 0;
83 int opt_found = 0; 113 int opt_found = 0;
84 int k; 114 int k;
@@ -110,6 +140,7 @@ static char *tftp_option_get(char *buf, int len, const char *option)
110 } 140 }
111 141
112 return NULL; 142 return NULL;
143#undef option
113} 144}
114 145
115#endif 146#endif
@@ -120,7 +151,7 @@ static int tftp_protocol(
120 len_and_sockaddr *peer_lsa, 151 len_and_sockaddr *peer_lsa,
121 USE_TFTP(const char *remote_file,) 152 USE_TFTP(const char *remote_file,)
122 int local_fd, 153 int local_fd,
123 int blocksize) 154 int blksize)
124{ 155{
125#if !ENABLE_TFTP 156#if !ENABLE_TFTP
126#define remote_file NULL 157#define remote_file NULL
@@ -135,14 +166,14 @@ static int tftp_protocol(
135 uint16_t block_nr; 166 uint16_t block_nr;
136 uint16_t recv_blk; 167 uint16_t recv_blk;
137 int retries, waittime_ms; 168 int retries, waittime_ms;
138 int tftp_bufsize = blocksize + 4; 169 int io_bufsize = blksize + 4;
139 char *cp; 170 char *cp;
140 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 171 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
141 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 172 * size varies meaning BUFFERS_GO_ON_STACK would fail */
142 /* We must keep the transmit and receive buffers seperate */ 173 /* We must keep the transmit and receive buffers seperate */
143 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ 174 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
144 char *xbuf = xmalloc(tftp_bufsize); 175 char *xbuf = xmalloc(io_bufsize);
145 char *rbuf = xmalloc(tftp_bufsize); 176 char *rbuf = xmalloc(io_bufsize);
146 177
147 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); 178 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
148 setsockopt_reuseaddr(socket_fd); 179 setsockopt_reuseaddr(socket_fd);
@@ -160,6 +191,10 @@ static int tftp_protocol(
160 xbind(socket_fd, &our_lsa->u.sa, our_lsa->len); 191 xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
161 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); 192 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
162 193
194 /* Is there an error already? Send pkt and bail out */
195 if (error_pkt_reason || error_pkt_str[0])
196 goto send_err_pkt;
197
163 if (CMD_GET(cmd)) { 198 if (CMD_GET(cmd)) {
164 /* it's upload - we must ACK 1st packet (with filename) 199 /* it's upload - we must ACK 1st packet (with filename)
165 * as if it's "block 0" */ 200 * as if it's "block 0" */
@@ -167,10 +202,11 @@ static int tftp_protocol(
167 } 202 }
168 203
169#if ENABLE_FEATURE_TFTP_BLOCKSIZE 204#if ENABLE_FEATURE_TFTP_BLOCKSIZE
170 if (blocksize != TFTP_BLOCKSIZE_DEFAULT) { 205 if (blksize != TFTP_BLKSIZE_DEFAULT) {
171 /* Create and send OACK packet */ 206 /* Create and send OACK packet */
172 /* block_nr is still 1, we expect ACK to (block_nr-1), 207 /* For the download case, block_nr is still 1 -
173 * that is, to "block 0" */ 208 * we expect 1st ACK from peer to be for (block_nr-1),
209 * that is, for "block 0" which is our OACK pkt */
174 opcode = TFTP_OACK; 210 opcode = TFTP_OACK;
175 cp = xbuf + 2; 211 cp = xbuf + 2;
176 goto add_blksize_opt; 212 goto add_blksize_opt;
@@ -200,7 +236,7 @@ static int tftp_protocol(
200 /* add filename and mode */ 236 /* add filename and mode */
201 /* fill in packet if the filename fits into xbuf */ 237 /* fill in packet if the filename fits into xbuf */
202 len = strlen(remote_file) + 1; 238 len = strlen(remote_file) + 1;
203 if (2 + len + sizeof("octet") >= tftp_bufsize) { 239 if (2 + len + sizeof("octet") >= io_bufsize) {
204 bb_error_msg("remote filename is too long"); 240 bb_error_msg("remote filename is too long");
205 goto ret; 241 goto ret;
206 } 242 }
@@ -211,18 +247,18 @@ static int tftp_protocol(
211 cp += sizeof("octet"); 247 cp += sizeof("octet");
212 248
213#if ENABLE_FEATURE_TFTP_BLOCKSIZE 249#if ENABLE_FEATURE_TFTP_BLOCKSIZE
214 if (blocksize != TFTP_BLOCKSIZE_DEFAULT) { 250 if (blksize != TFTP_BLKSIZE_DEFAULT) {
215 /* rfc2348 says that 65464 is a max allowed value */ 251 /* rfc2348 says that 65464 is a max allowed value */
216 if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { 252 if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
217 bb_error_msg("remote filename is too long"); 253 bb_error_msg("remote filename is too long");
218 goto ret; 254 goto ret;
219 } 255 }
220 want_option_ack = 1; 256 want_option_ack = 1;
221 add_blksize_opt: 257 add_blksize_opt:
222 /* add "blksize", <nul>, blocksize, <nul> */ 258 /* add "blksize", <nul>, blksize, <nul> */
223 strcpy(cp, "blksize"); 259 strcpy(cp, "blksize");
224 cp += sizeof("blksize"); 260 cp += sizeof("blksize");
225 cp += snprintf(cp, 6, "%d", blocksize) + 1; 261 cp += snprintf(cp, 6, "%d", blksize) + 1;
226 } 262 }
227#endif 263#endif
228 /* First packet is built, so skip packet generation */ 264 /* First packet is built, so skip packet generation */
@@ -240,12 +276,11 @@ static int tftp_protocol(
240 opcode = TFTP_ACK; 276 opcode = TFTP_ACK;
241 if (CMD_PUT(cmd)) { 277 if (CMD_PUT(cmd)) {
242 opcode = TFTP_DATA; 278 opcode = TFTP_DATA;
243 len = full_read(local_fd, cp, tftp_bufsize - 4); 279 len = full_read(local_fd, cp, blksize);
244 if (len < 0) { 280 if (len < 0) {
245 bb_perror_msg(bb_msg_read_error); 281 goto send_read_err_pkt;
246 goto ret;
247 } 282 }
248 if (len != (tftp_bufsize - 4)) { 283 if (len != blksize) {
249 finished = 1; 284 finished = 1;
250 } 285 }
251 cp += len; 286 cp += len;
@@ -277,11 +312,28 @@ static int tftp_protocol(
277 /*pfd[0].fd = socket_fd;*/ 312 /*pfd[0].fd = socket_fd;*/
278 pfd[0].events = POLLIN; 313 pfd[0].events = POLLIN;
279 switch (safe_poll(pfd, 1, waittime_ms)) { 314 switch (safe_poll(pfd, 1, waittime_ms)) {
315 default:
316 /*bb_perror_msg("poll"); - done in safe_poll */
317 goto ret;
318 case 0:
319 retries--;
320 if (retries == 0) {
321 bb_error_msg("timeout");
322 goto ret; /* no err packet sent */
323 }
324
325 /* exponential backoff with limit */
326 waittime_ms += waittime_ms/2;
327 if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
328 waittime_ms = TFTP_MAXTIMEOUT_MS;
329 }
330
331 goto send_again; /* resend last sent pkt */
280 case 1: 332 case 1:
281 if (!our_lsa) { 333 if (!our_lsa) {
282 /* tftp (not tftpd!) receiving 1st packet */ 334 /* tftp (not tftpd!) receiving 1st packet */
283 our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */ 335 our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
284 len = recvfrom(socket_fd, rbuf, tftp_bufsize, 0, 336 len = recvfrom(socket_fd, rbuf, io_bufsize, 0,
285 &peer_lsa->u.sa, &peer_lsa->len); 337 &peer_lsa->u.sa, &peer_lsa->len);
286 /* Our first dgram went to port 69 338 /* Our first dgram went to port 69
287 * but reply may come from different one. 339 * but reply may come from different one.
@@ -291,62 +343,44 @@ static int tftp_protocol(
291 } else { 343 } else {
292 /* tftpd, or not the very first packet: 344 /* tftpd, or not the very first packet:
293 * socket is connect()ed, can just read from it. */ 345 * socket is connect()ed, can just read from it. */
294 len = safe_read(socket_fd, rbuf, tftp_bufsize); 346 /* Don't full_read()!
347 * This is not TCP, one read == one pkt! */
348 len = safe_read(socket_fd, rbuf, io_bufsize);
295 } 349 }
296 if (len < 0) { 350 if (len < 0) {
297 bb_perror_msg("read"); 351 goto send_read_err_pkt;
298 goto ret;
299 } 352 }
300 if (len < 4) /* too small? */ 353 if (len < 4) { /* too small? */
301 goto recv_again; 354 goto recv_again;
302 goto process_pkt;
303 case 0:
304 retries--;
305 if (retries == 0) {
306 bb_error_msg("timeout");
307 goto ret;
308 } 355 }
309
310 /* exponential backoff with limit */
311 waittime_ms += waittime_ms/2;
312 if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
313 waittime_ms = TFTP_MAXTIMEOUT_MS;
314 }
315
316 goto send_again; /* resend last sent pkt */
317 default:
318 /*bb_perror_msg("poll"); - done in safe_poll */
319 goto ret;
320 } 356 }
321 process_pkt: 357
322 /* Process recv'ed packet */ 358 /* Process recv'ed packet */
323 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 359 opcode = ntohs( ((uint16_t*)rbuf)[0] );
324 recv_blk = ntohs( ((uint16_t*)rbuf)[1] ); 360 recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
325
326#if ENABLE_DEBUG_TFTP 361#if ENABLE_DEBUG_TFTP
327 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); 362 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
328#endif 363#endif
329 364
330 if (opcode == TFTP_ERROR) { 365 if (opcode == TFTP_ERROR) {
331 static const char *const errcode_str[] = { 366 static const char errcode_str[] =
332 "", 367 "\0"
333 "file not found", 368 "file not found\0"
334 "access violation", 369 "access violation\0"
335 "disk full", 370 "disk full\0"
336 "illegal TFTP operation", 371 "bad operation\0"
337 "unknown transfer id", 372 "unknown transfer id\0"
338 "file already exists", 373 "file already exists\0"
339 "no such user", 374 "no such user\0"
340 "bad option" 375 "bad option";
341 };
342 376
343 const char *msg = ""; 377 const char *msg = "";
344 378
345 if (len > 4 && rbuf[4] != '\0') { 379 if (len > 4 && rbuf[4] != '\0') {
346 msg = &rbuf[4]; 380 msg = &rbuf[4];
347 rbuf[tftp_bufsize - 1] = '\0'; 381 rbuf[io_bufsize - 1] = '\0'; /* paranoia */
348 } else if (recv_blk < ARRAY_SIZE(errcode_str)) { 382 } else if (recv_blk <= 8) {
349 msg = errcode_str[recv_blk]; 383 msg = nth_string(errcode_str, recv_blk);
350 } 384 }
351 bb_error_msg("server error: (%u) %s", recv_blk, msg); 385 bb_error_msg("server error: (%u) %s", recv_blk, msg);
352 goto ret; 386 goto ret;
@@ -355,29 +389,18 @@ static int tftp_protocol(
355#if ENABLE_FEATURE_TFTP_BLOCKSIZE 389#if ENABLE_FEATURE_TFTP_BLOCKSIZE
356 if (want_option_ack) { 390 if (want_option_ack) {
357 want_option_ack = 0; 391 want_option_ack = 0;
358
359 if (opcode == TFTP_OACK) { 392 if (opcode == TFTP_OACK) {
360 /* server seems to support options */ 393 /* server seems to support options */
361 char *res; 394 char *res;
362 395
363 res = tftp_option_get(&rbuf[2], len - 2, "blksize"); 396 res = tftp_get_blksize(&rbuf[2], len - 2);
364 if (res) { 397 if (res) {
365 int blksize = xatoi_u(res); 398 blksize = tftp_blksize_check(res, blksize);
366 if (!tftp_blocksize_check(blksize, tftp_bufsize - 4)) { 399 if (blksize < 0) {
367 /* send ERROR 8 to server... */ 400 error_pkt_reason = ERR_BAD_OPT;
368 /* htons can be impossible to use in const initializer: */ 401 goto send_err_pkt;
369 /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/
370 /* thus we open-code big-endian layout */
371 static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 };
372 xsendto(socket_fd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len);
373 bb_error_msg("server proposes bad blksize %d, exiting", blksize);
374 goto ret;
375 } 402 }
376#if ENABLE_DEBUG_TFTP 403 io_bufsize = blksize + 4;
377 fprintf(stderr, "using blksize %u\n",
378 blksize);
379#endif
380 tftp_bufsize = blksize + 4;
381 /* Send ACK for OACK ("block" no: 0) */ 404 /* Send ACK for OACK ("block" no: 0) */
382 block_nr = 0; 405 block_nr = 0;
383 continue; 406 continue;
@@ -387,10 +410,9 @@ static int tftp_protocol(
387 * must be ignored by the client and server 410 * must be ignored by the client and server
388 * as if it were never requested." */ 411 * as if it were never requested." */
389 } 412 }
390 413 bb_error_msg("server only supports blocksize of 512");
391 bb_error_msg("blksize is not supported by server" 414 blksize = TFTP_BLKSIZE_DEFAULT;
392 " - reverting to 512"); 415 io_bufsize = TFTP_BLKSIZE_DEFAULT + 4;
393 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
394 } 416 }
395#endif 417#endif
396 /* block_nr is already advanced to next block# we expect 418 /* block_nr is already advanced to next block# we expect
@@ -401,9 +423,10 @@ static int tftp_protocol(
401 len = full_write(local_fd, &rbuf[4], len - 4); 423 len = full_write(local_fd, &rbuf[4], len - 4);
402 if (len < 0) { 424 if (len < 0) {
403 bb_perror_msg(bb_msg_write_error); 425 bb_perror_msg(bb_msg_write_error);
404 goto ret; 426 error_pkt_reason = ERR_WRITE;
427 goto send_err_pkt;
405 } 428 }
406 if (len != (tftp_bufsize - 4)) { 429 if (len != blksize) {
407 finished = 1; 430 finished = 1;
408 } 431 }
409 continue; /* send ACK */ 432 continue; /* send ACK */
@@ -442,6 +465,15 @@ static int tftp_protocol(
442 free(rbuf); 465 free(rbuf);
443 } 466 }
444 return finished == 0; /* returns 1 on failure */ 467 return finished == 0; /* returns 1 on failure */
468
469 send_read_err_pkt:
470 bb_perror_msg(bb_msg_read_error);
471 strcpy(error_pkt_str, bb_msg_read_error);
472 send_err_pkt:
473 error_pkt[1] = TFTP_ERROR;
474 xsendto(socket_fd, error_pkt, 4 + 1 + strlen(error_pkt_str),
475 &peer_lsa->u.sa, peer_lsa->len);
476 return EXIT_FAILURE;
445} 477}
446 478
447#if ENABLE_TFTP 479#if ENABLE_TFTP
@@ -457,18 +489,20 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
457 int local_fd; 489 int local_fd;
458 int flags = 0; 490 int flags = 0;
459 int result; 491 int result;
460 int blocksize = TFTP_BLOCKSIZE_DEFAULT; 492 int blksize;
493 const char *blksize_str = "512";
494
495 INIT_G();
461 496
462 /* -p or -g is mandatory, and they are mutually exclusive */ 497 /* -p or -g is mandatory, and they are mutually exclusive */
463 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") 498 opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
464 USE_GETPUT("g--p:p--g:") 499 USE_GETPUT("g--p:p--g:");
465 USE_FEATURE_TFTP_BLOCKSIZE("b+");
466 500
467 USE_GETPUT(cmd =) getopt32(argv, 501 USE_GETPUT(cmd =) getopt32(argv,
468 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") 502 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
469 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), 503 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
470 &local_file, &remote_file 504 &local_file, &remote_file
471 USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize)); 505 USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
472 argv += optind; 506 argv += optind;
473 507
474 flags = O_RDONLY; 508 flags = O_RDONLY;
@@ -476,8 +510,13 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
476 flags = O_WRONLY | O_CREAT | O_TRUNC; 510 flags = O_WRONLY | O_CREAT | O_TRUNC;
477 511
478#if ENABLE_FEATURE_TFTP_BLOCKSIZE 512#if ENABLE_FEATURE_TFTP_BLOCKSIZE
479 if (!tftp_blocksize_check(blocksize, 0)) 513 /* Check if the blksize is valid:
514 * RFC2348 says between 8 and 65464 */
515 blksize = tftp_blksize_check(blksize_str, 65564);
516 if (blksize < 0) {
517 //bb_error_msg("bad block size");
480 return EXIT_FAILURE; 518 return EXIT_FAILURE;
519 }
481#endif 520#endif
482 521
483 if (!local_file) 522 if (!local_file)
@@ -506,7 +545,7 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
506 USE_GETPUT(cmd,) 545 USE_GETPUT(cmd,)
507 NULL /* our_lsa*/, 546 NULL /* our_lsa*/,
508 peer_lsa, 547 peer_lsa,
509 remote_file, local_fd, blocksize); 548 remote_file, local_fd, blksize);
510 549
511 if (ENABLE_FEATURE_CLEAN_UP) 550 if (ENABLE_FEATURE_CLEAN_UP)
512 close(local_fd); 551 close(local_fd);
@@ -537,12 +576,16 @@ static len_and_sockaddr *get_sock_lsa(int s)
537int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 576int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
538int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) 577int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
539{ 578{
540 char block_buf[TFTP_BLOCKSIZE_DEFAULT];
541 len_and_sockaddr *our_lsa; 579 len_and_sockaddr *our_lsa;
542 len_and_sockaddr *peer_lsa; 580 len_and_sockaddr *peer_lsa;
543 char *filename, *mode, *opt_str; 581 char *filename, *mode;
544 int opt_r, result, opcode, open_mode, local_fd, blksize; 582 const char *error_msg;
545 USE_GETPUT(int cmd;) 583 int opt_r, result, opcode, open_mode;
584 int local_fd = local_fd; /* for compiler */
585 int blksize = blksize;
586 USE_GETPUT(int cmd = cmd;)
587
588 INIT_G();
546 589
547 our_lsa = get_sock_lsa(STDIN_FILENO); 590 our_lsa = get_sock_lsa(STDIN_FILENO);
548 if (!our_lsa) 591 if (!our_lsa)
@@ -559,6 +602,7 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
559 0 /* flags */, 602 0 /* flags */,
560 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); 603 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
561 604
605 error_msg = "malformed packet";
562 opcode = ntohs(*(uint16_t*)block_buf); 606 opcode = ntohs(*(uint16_t*)block_buf);
563 if (result < 4 || result >= sizeof(block_buf) 607 if (result < 4 || result >= sizeof(block_buf)
564 || block_buf[result-1] != '\0' 608 || block_buf[result-1] != '\0'
@@ -567,27 +611,35 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
567 USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */ 611 USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
568 ) 612 )
569 ) { 613 ) {
570 bb_error_msg_and_die("malformed packet"); 614 goto err;
571 } 615 }
572 filename = block_buf + 2; 616 filename = block_buf + 2;
573 if (filename[0] == '.' || strstr(filename, "/.")) { 617 if (filename[0] == '.' || strstr(filename, "/.")) {
574 bb_error_msg_and_die("dot in filename"); 618 error_msg = "dot in filename";
619 goto err;
575 } 620 }
576 mode = filename + strlen(filename) + 1; 621 mode = filename + strlen(filename) + 1;
577 if (mode >= block_buf + sizeof(block_buf) 622 if (mode >= block_buf + result
578 || strcmp(mode, "octet") != 0 623 || strcmp(mode, "octet") != 0
579 ) { 624 ) {
580 bb_error_msg_and_die("malformed packet"); 625 goto err;
581 } 626 }
582 blksize = TFTP_BLOCKSIZE_DEFAULT; 627 blksize = TFTP_BLKSIZE_DEFAULT;
583#if ENABLE_FEATURE_TFTP_BLOCKSIZE 628#if ENABLE_FEATURE_TFTP_BLOCKSIZE
584 opt_str = mode + 6; 629 {
585 if (opt_str < block_buf + sizeof(block_buf)) { 630 char *res;
586 char *res = tftp_option_get(opt_str, block_buf + sizeof(block_buf) - opt_str, "blksize"); 631 char *opt_str = mode + sizeof("octet");
587 if (res) { 632 int opt_len = block_buf + result - opt_str;
588 int sz = xatoi_u(res); 633 if (opt_len > 0) {
589 if (tftp_blocksize_check(sz, 0)) 634 res = tftp_get_blksize(opt_str, opt_len);
590 blksize = sz; 635 if (res) {
636 blksize = tftp_blksize_check(res, 65564);
637 if (blksize < 0) {
638 error_pkt_reason = ERR_BAD_OPT;
639 /* will just send error pkt */
640 goto do_proto;
641 }
642 }
591 } 643 }
592 } 644 }
593#endif 645#endif
@@ -599,16 +651,28 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
599#endif 651#endif
600#if ENABLE_FEATURE_TFTP_GET 652#if ENABLE_FEATURE_TFTP_GET
601 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { 653 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
602 if (opt_r) 654 if (opt_r) {
603 bb_error_msg_and_die("upload is prohibited"); 655 error_pkt_reason = ERR_WRITE;
656 /* will just send error pkt */
657 goto do_proto;
658 }
604 USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */ 659 USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */
605 open_mode = O_WRONLY | O_TRUNC; 660 open_mode = O_WRONLY | O_TRUNC;
606 } 661 }
607#endif 662#endif
608 local_fd = xopen(filename, open_mode); 663 local_fd = open(filename, open_mode);
664 if (local_fd < 0) {
665 error_msg = "can't open file";
666 err:
667 strcpy(error_pkt_str, error_msg);
668 }
609 669
610 close(STDIN_FILENO); /* close old, possibly wildcard socket */ 670 close(STDIN_FILENO); /* close old, possibly wildcard socket */
611 /* tftp_protocol() will create new one, bound to particular local IP */ 671 /* tftp_protocol() will create new one, bound to particular local IP */
672
673 /* NB: if error_pkt_str or error_pkt_reason is set up,
674 * tftp_protocol() just sends one error pkt and returns */
675 do_proto:
612 result = tftp_protocol( 676 result = tftp_protocol(
613 USE_GETPUT(cmd,) 677 USE_GETPUT(cmd,)
614 our_lsa, peer_lsa, 678 our_lsa, peer_lsa,