source: MondoRescue/branches/3.3/mindi-busybox/networking/tftp.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 24.6 KB
RevLine 
[821]1/* vi: set sw=4 ts=4: */
[2725]2/*
3 * A simple tftp client/server for busybox.
[821]4 * Tries to follow RFC1350.
5 * Only "octet" mode supported.
6 * Optional blocksize negotiation (RFC2347 + RFC2348)
7 *
8 * Copyright (C) 2001 Magnus Damm <damm@opensource.se>
9 *
10 * Parts of the code based on:
11 *
12 * atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>
13 * and Remi Lefebvre <remi@debian.org>
14 *
15 * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
16 *
[2725]17 * tftpd added by Denys Vlasenko & Vladimir Dronnikov
18 *
19 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
20 */
[3232]21
22//usage:#define tftp_trivial_usage
23//usage: "[OPTIONS] HOST [PORT]"
24//usage:#define tftp_full_usage "\n\n"
25//usage: "Transfer a file from/to tftp server\n"
26//usage: "\n -l FILE Local FILE"
27//usage: "\n -r FILE Remote FILE"
28//usage: IF_FEATURE_TFTP_GET(
29//usage: "\n -g Get file"
30//usage: )
31//usage: IF_FEATURE_TFTP_PUT(
32//usage: "\n -p Put file"
33//usage: )
34//usage: IF_FEATURE_TFTP_BLOCKSIZE(
35//usage: "\n -b SIZE Transfer blocks of SIZE octets"
36//usage: )
37//usage:
38//usage:#define tftpd_trivial_usage
39//usage: "[-cr] [-u USER] [DIR]"
40//usage:#define tftpd_full_usage "\n\n"
41//usage: "Transfer a file on tftp client's request\n"
42//usage: "\n"
43//usage: "tftpd should be used as an inetd service.\n"
44//usage: "tftpd's line for inetd.conf:\n"
45//usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n"
46//usage: "It also can be ran from udpsvd:\n"
47//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n"
48//usage: "\n -r Prohibit upload"
49//usage: "\n -c Allow file creation via upload"
50//usage: "\n -u Access files as USER"
51//usage: "\n -l Log to syslog (inetd mode requires this)"
52
[1765]53#include "libbb.h"
[3621]54#include "common_bufsiz.h"
[3232]55#include <syslog.h>
[821]56
[1765]57#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
[821]58
[2725]59#define TFTP_BLKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
60#define TFTP_BLKSIZE_DEFAULT_STR "512"
61/* Was 50 ms but users asked to bump it up a bit */
62#define TFTP_TIMEOUT_MS 100
63#define TFTP_MAXTIMEOUT_MS 2000
64#define TFTP_NUM_RETRIES 12 /* number of backed-off retries */
[821]65
66/* opcodes we support */
67#define TFTP_RRQ 1
68#define TFTP_WRQ 2
69#define TFTP_DATA 3
70#define TFTP_ACK 4
71#define TFTP_ERROR 5
72#define TFTP_OACK 6
73
[2725]74/* error codes sent over network (we use only 0, 1, 3 and 8) */
75/* generic (error message is included in the packet) */
76#define ERR_UNSPEC 0
77#define ERR_NOFILE 1
78#define ERR_ACCESS 2
79/* disk full or allocation exceeded */
80#define ERR_WRITE 3
81#define ERR_OP 4
82#define ERR_BAD_ID 5
83#define ERR_EXIST 6
84#define ERR_BAD_USER 7
85#define ERR_BAD_OPT 8
86
87/* masks coming from getopt32 */
88enum {
89 TFTP_OPT_GET = (1 << 0),
90 TFTP_OPT_PUT = (1 << 1),
91 /* pseudo option: if set, it's tftpd */
92 TFTPD_OPT = (1 << 7) * ENABLE_TFTPD,
93 TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD,
94 TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD,
95 TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD,
[3232]96 TFTPD_OPT_l = (1 << 11) * ENABLE_TFTPD,
[2725]97};
98
[1765]99#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
[2725]100#define IF_GETPUT(...)
[1765]101#define CMD_GET(cmd) 1
102#define CMD_PUT(cmd) 0
103#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
[2725]104#define IF_GETPUT(...)
[1765]105#define CMD_GET(cmd) 0
106#define CMD_PUT(cmd) 1
[821]107#else
[2725]108#define IF_GETPUT(...) __VA_ARGS__
109#define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
110#define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
[821]111#endif
[1765]112/* NB: in the code below
113 * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
114 */
[821]115
116
[2725]117struct globals {
118 /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
119 uint8_t error_pkt[4 + 32];
[3232]120 struct passwd *pw;
[3621]121 /* Used in tftpd_main() for initial packet */
122 /* Some HP PA-RISC firmware always sends fixed 516-byte requests */
123 char block_buf[516];
124 char block_buf_tail[1];
[2725]125#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
126 off_t pos;
127 off_t size;
128 const char *file;
129 bb_progress_t pmt;
130#endif
131} FIX_ALIASING;
[3621]132#define G (*(struct globals*)bb_common_bufsiz1)
133#define INIT_G() do { \
134 setup_common_bufsiz(); \
135 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
136} while (0)
[2725]137
[3232]138#define G_error_pkt_reason (G.error_pkt[3])
139#define G_error_pkt_str ((char*)(G.error_pkt + 4))
[2725]140
141#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
142static void tftp_progress_update(void)
143{
[3232]144 bb_progress_update(&G.pmt, 0, G.pos, G.size);
[2725]145}
146static void tftp_progress_init(void)
147{
[3232]148 bb_progress_init(&G.pmt, G.file);
[2725]149 tftp_progress_update();
150}
151static void tftp_progress_done(void)
152{
[3232]153 if (is_bb_progress_inited(&G.pmt)) {
[2725]154 tftp_progress_update();
155 bb_putchar_stderr('\n');
[3232]156 bb_progress_free(&G.pmt);
[2725]157 }
158}
159#else
160# define tftp_progress_init() ((void)0)
161# define tftp_progress_done() ((void)0)
162#endif
163
[1765]164#if ENABLE_FEATURE_TFTP_BLOCKSIZE
[821]165
[2725]166static int tftp_blksize_check(const char *blksize_str, int maxsize)
[821]167{
[2725]168 /* Check if the blksize is valid:
[821]169 * RFC2348 says between 8 and 65464,
170 * but our implementation makes it impossible
[2725]171 * to use blksizes smaller than 22 octets. */
172 unsigned blksize = bb_strtou(blksize_str, NULL, 10);
173 if (errno
174 || (blksize < 24) || (blksize > maxsize)
[1765]175 ) {
[2725]176 bb_error_msg("bad blocksize '%s'", blksize_str);
177 return -1;
[821]178 }
[2725]179# if ENABLE_TFTP_DEBUG
180 bb_error_msg("using blksize %u", blksize);
181# endif
182 return blksize;
[821]183}
184
[2725]185static char *tftp_get_option(const char *option, char *buf, int len)
[821]186{
187 int opt_val = 0;
188 int opt_found = 0;
189 int k;
190
[2725]191 /* buf points to:
192 * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */
193
[821]194 while (len > 0) {
[2725]195 /* Make sure options are terminated correctly */
[821]196 for (k = 0; k < len; k++) {
197 if (buf[k] == '\0') {
[1765]198 goto nul_found;
[821]199 }
200 }
[1765]201 return NULL;
202 nul_found:
[2725]203 if (opt_val == 0) { /* it's "name" part */
[821]204 if (strcasecmp(buf, option) == 0) {
205 opt_found = 1;
206 }
[1765]207 } else if (opt_found) {
208 return buf;
[821]209 }
210
211 k++;
212 buf += k;
213 len -= k;
214 opt_val ^= 1;
215 }
216
217 return NULL;
218}
219
220#endif
221
[2725]222static int tftp_protocol(
223 /* NULL if tftp, !NULL if tftpd: */
224 len_and_sockaddr *our_lsa,
[1765]225 len_and_sockaddr *peer_lsa,
[2725]226 const char *local_file
227 IF_TFTP(, const char *remote_file)
228#if !ENABLE_TFTP
229# define remote_file NULL
230#endif
231 /* 1 for tftp; 1/0 for tftpd depending whether client asked about it: */
232 IF_FEATURE_TFTP_BLOCKSIZE(, int want_transfer_size)
233 IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
[821]234{
[2725]235#if !ENABLE_FEATURE_TFTP_BLOCKSIZE
236 enum { blksize = TFTP_BLKSIZE_DEFAULT };
237#endif
238
239 struct pollfd pfd[1];
240#define socket_fd (pfd[0].fd)
[821]241 int len;
[1765]242 int send_len;
[2725]243 IF_FEATURE_TFTP_BLOCKSIZE(smallint expect_OACK = 0;)
[1765]244 smallint finished = 0;
245 uint16_t opcode;
[2725]246 uint16_t block_nr;
[1765]247 uint16_t recv_blk;
[2725]248 int open_mode, local_fd;
249 int retries, waittime_ms;
250 int io_bufsize = blksize + 4;
[821]251 char *cp;
[2725]252 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
253 * size varies meaning BUFFERS_GO_ON_STACK would fail.
254 *
255 * We must keep the transmit and receive buffers separate
256 * in case we rcv a garbage pkt - we need to rexmit the last pkt.
257 */
258 char *xbuf = xmalloc(io_bufsize);
259 char *rbuf = xmalloc(io_bufsize);
[821]260
[2725]261 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
262 setsockopt_reuseaddr(socket_fd);
[821]263
[2725]264 if (!ENABLE_TFTP || our_lsa) { /* tftpd */
265 /* Create a socket which is:
266 * 1. bound to IP:port peer sent 1st datagram to,
267 * 2. connected to peer's IP:port
268 * This way we will answer from the IP:port peer
269 * expects, will not get any other packets on
270 * the socket, and also plain read/write will work. */
271 xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
272 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
[821]273
[2725]274 /* Is there an error already? Send pkt and bail out */
[3232]275 if (G_error_pkt_reason || G_error_pkt_str[0])
[2725]276 goto send_err_pkt;
[821]277
[3232]278 if (G.pw) {
279 change_identity(G.pw); /* initgroups, setgid, setuid */
[2725]280 }
281 }
[821]282
[2725]283 /* Prepare open mode */
284 if (CMD_PUT(option_mask32)) {
285 open_mode = O_RDONLY;
286 } else {
287 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
288#if ENABLE_TFTPD
289 if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) {
290 /* tftpd without -c */
291 open_mode = O_WRONLY | O_TRUNC;
292 }
293#endif
[821]294 }
[2725]295
296 /* Examples of network traffic.
297 * Note two cases when ACKs with block# of 0 are sent.
298 *
299 * Download without options:
300 * tftp -> "\0\1FILENAME\0octet\0"
301 * "\0\3\0\1FILEDATA..." <- tftpd
302 * tftp -> "\0\4\0\1"
303 * ...
304 * Download with option of blksize 16384:
305 * tftp -> "\0\1FILENAME\0octet\0blksize\00016384\0"
306 * "\0\6blksize\00016384\0" <- tftpd
307 * tftp -> "\0\4\0\0"
308 * "\0\3\0\1FILEDATA..." <- tftpd
309 * tftp -> "\0\4\0\1"
310 * ...
311 * Upload without options:
312 * tftp -> "\0\2FILENAME\0octet\0"
313 * "\0\4\0\0" <- tftpd
314 * tftp -> "\0\3\0\1FILEDATA..."
315 * "\0\4\0\1" <- tftpd
316 * ...
317 * Upload with option of blksize 16384:
318 * tftp -> "\0\2FILENAME\0octet\0blksize\00016384\0"
319 * "\0\6blksize\00016384\0" <- tftpd
320 * tftp -> "\0\3\0\1FILEDATA..."
321 * "\0\4\0\1" <- tftpd
322 * ...
323 */
324 block_nr = 1;
[1765]325 cp = xbuf + 2;
[821]326
[2725]327 if (!ENABLE_TFTP || our_lsa) { /* tftpd */
328 /* Open file (must be after changing user) */
329 local_fd = open(local_file, open_mode, 0666);
330 if (local_fd < 0) {
[3232]331 G_error_pkt_reason = ERR_NOFILE;
332 strcpy(G_error_pkt_str, "can't open file");
[2725]333 goto send_err_pkt;
334 }
335/* gcc 4.3.1 would NOT optimize it out as it should! */
[1765]336#if ENABLE_FEATURE_TFTP_BLOCKSIZE
[2725]337 if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) {
338 /* Create and send OACK packet. */
339 /* For the download case, block_nr is still 1 -
340 * we expect 1st ACK from peer to be for (block_nr-1),
341 * that is, for "block 0" which is our OACK pkt */
342 opcode = TFTP_OACK;
343 goto add_blksize_opt;
344 }
345#endif
346 if (CMD_GET(option_mask32)) {
347 /* It's upload and we don't send OACK.
348 * We must ACK 1st packet (with filename)
349 * as if it is "block 0" */
350 block_nr = 0;
351 }
352 } else { /* tftp */
353 /* Open file (must be after changing user) */
354 local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO;
355 if (NOT_LONE_DASH(local_file))
356 local_fd = xopen(local_file, open_mode);
357/* Removing #if, or using if() statement instead of #if may lead to
358 * "warning: null argument where non-null required": */
359#if ENABLE_TFTP
360 /* tftp */
361
362 /* We can't (and don't really need to) bind the socket:
363 * we don't know from which local IP datagrams will be sent,
364 * but kernel will pick the same IP every time (unless routing
365 * table is changed), thus peer will see dgrams consistently
366 * coming from the same IP.
367 * We would like to connect the socket, but since peer's
368 * UDP code can be less perfect than ours, _peer's_ IP:port
369 * in replies may differ from IP:port we used to send
370 * our first packet. We can connect() only when we get
371 * first reply. */
372
373 /* build opcode */
374 opcode = TFTP_WRQ;
375 if (CMD_GET(option_mask32)) {
376 opcode = TFTP_RRQ;
377 }
378 /* add filename and mode */
379 /* fill in packet if the filename fits into xbuf */
380 len = strlen(remote_file) + 1;
381 if (2 + len + sizeof("octet") >= io_bufsize) {
[1765]382 bb_error_msg("remote filename is too long");
383 goto ret;
384 }
[2725]385 strcpy(cp, remote_file);
386 cp += len;
387 /* add "mode" part of the packet */
388 strcpy(cp, "octet");
389 cp += sizeof("octet");
390
391# if ENABLE_FEATURE_TFTP_BLOCKSIZE
392 if (blksize == TFTP_BLKSIZE_DEFAULT && !want_transfer_size)
393 goto send_pkt;
394
395 /* Need to add option to pkt */
396 if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN tsize ") + sizeof(off_t)*3) {
397 bb_error_msg("remote filename is too long");
398 goto ret;
399 }
400 expect_OACK = 1;
401# endif
402#endif /* ENABLE_TFTP */
403
404#if ENABLE_FEATURE_TFTP_BLOCKSIZE
405 add_blksize_opt:
406 if (blksize != TFTP_BLKSIZE_DEFAULT) {
407 /* add "blksize", <nul>, blksize, <nul> */
408 strcpy(cp, "blksize");
409 cp += sizeof("blksize");
410 cp += snprintf(cp, 6, "%d", blksize) + 1;
411 }
412 if (want_transfer_size) {
413 /* add "tsize", <nul>, size, <nul> (see RFC2349) */
414 /* if tftp and downloading, we send "0" (since we opened local_fd with O_TRUNC)
415 * and this makes server to send "tsize" option with the size */
416 /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */
417 /* if tftpd and downloading, we are answering to client's request */
418 /* if tftpd and uploading: !want_transfer_size, this code is not executed */
419 struct stat st;
420 strcpy(cp, "tsize");
421 cp += sizeof("tsize");
422 st.st_size = 0;
423 fstat(local_fd, &st);
424 cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1;
425# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
426 /* Save for progress bar. If 0 (tftp downloading),
427 * we look at server's reply later */
428 G.size = st.st_size;
429 if (remote_file && st.st_size)
430 tftp_progress_init();
431# endif
432 }
433#endif
434 /* First packet is built, so skip packet generation */
435 goto send_pkt;
[1765]436 }
[821]437
[1765]438 /* Using mostly goto's - continue/break will be less clear
439 * in where we actually jump to */
440 while (1) {
441 /* Build ACK or DATA */
442 cp = xbuf + 2;
443 *((uint16_t*)cp) = htons(block_nr);
[821]444 cp += 2;
[1765]445 block_nr++;
446 opcode = TFTP_ACK;
[2725]447 if (CMD_PUT(option_mask32)) {
[1765]448 opcode = TFTP_DATA;
[2725]449 len = full_read(local_fd, cp, blksize);
[1765]450 if (len < 0) {
[2725]451 goto send_read_err_pkt;
[821]452 }
[2725]453 if (len != blksize) {
[1765]454 finished = 1;
[821]455 }
[1765]456 cp += len;
[3232]457 IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += len;)
[1765]458 }
459 send_pkt:
460 /* Send packet */
461 *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
462 send_len = cp - xbuf;
463 /* NB: send_len value is preserved in code below
464 * for potential resend */
[2725]465
466 retries = TFTP_NUM_RETRIES; /* re-initialize */
467 waittime_ms = TFTP_TIMEOUT_MS;
468
[1765]469 send_again:
[2725]470#if ENABLE_TFTP_DEBUG
[1765]471 fprintf(stderr, "sending %u bytes\n", send_len);
472 for (cp = xbuf; cp < &xbuf[send_len]; cp++)
473 fprintf(stderr, "%02x ", (unsigned char) *cp);
474 fprintf(stderr, "\n");
[821]475#endif
[2725]476 xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
477
478#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
[3232]479 if (is_bb_progress_inited(&G.pmt))
[2725]480 tftp_progress_update();
481#endif
[1765]482 /* Was it final ACK? then exit */
483 if (finished && (opcode == TFTP_ACK))
484 goto ret;
[821]485
[1765]486 recv_again:
487 /* Receive packet */
[2725]488 /*pfd[0].fd = socket_fd;*/
489 pfd[0].events = POLLIN;
490 switch (safe_poll(pfd, 1, waittime_ms)) {
491 default:
492 /*bb_perror_msg("poll"); - done in safe_poll */
493 goto ret;
494 case 0:
495 retries--;
496 if (retries == 0) {
497 tftp_progress_done();
498 bb_error_msg("timeout");
499 goto ret; /* no err packet sent */
500 }
501
502 /* exponential backoff with limit */
503 waittime_ms += waittime_ms/2;
504 if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
505 waittime_ms = TFTP_MAXTIMEOUT_MS;
506 }
507
508 goto send_again; /* resend last sent pkt */
[1765]509 case 1:
[2725]510 if (!our_lsa) {
511 /* tftp (not tftpd!) receiving 1st packet */
512 our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
513 len = recvfrom(socket_fd, rbuf, io_bufsize, 0,
514 &peer_lsa->u.sa, &peer_lsa->len);
515 /* Our first dgram went to port 69
516 * but reply may come from different one.
517 * Remember and use this new port (and IP) */
518 if (len >= 0)
519 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
520 } else {
521 /* tftpd, or not the very first packet:
522 * socket is connect()ed, can just read from it. */
523 /* Don't full_read()!
524 * This is not TCP, one read == one pkt! */
525 len = safe_read(socket_fd, rbuf, io_bufsize);
526 }
[1765]527 if (len < 0) {
[2725]528 goto send_read_err_pkt;
[821]529 }
[2725]530 if (len < 4) { /* too small? */
[1765]531 goto recv_again;
[821]532 }
533 }
[2725]534
[1765]535 /* Process recv'ed packet */
536 opcode = ntohs( ((uint16_t*)rbuf)[0] );
537 recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
[2725]538#if ENABLE_TFTP_DEBUG
[1765]539 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
[821]540#endif
541 if (opcode == TFTP_ERROR) {
[2725]542 static const char errcode_str[] ALIGN1 =
543 "\0"
544 "file not found\0"
545 "access violation\0"
546 "disk full\0"
547 "bad operation\0"
548 "unknown transfer id\0"
549 "file already exists\0"
550 "no such user\0"
551 "bad option";
[821]552
[1765]553 const char *msg = "";
[821]554
[2725]555 if (len > 4 && rbuf[4] != '\0') {
[1765]556 msg = &rbuf[4];
[2725]557 rbuf[io_bufsize - 1] = '\0'; /* paranoia */
558 } else if (recv_blk <= 8) {
559 msg = nth_string(errcode_str, recv_blk);
[821]560 }
[1765]561 bb_error_msg("server error: (%u) %s", recv_blk, msg);
562 goto ret;
563 }
[821]564
[1765]565#if ENABLE_FEATURE_TFTP_BLOCKSIZE
[2725]566 if (expect_OACK) {
567 expect_OACK = 0;
[821]568 if (opcode == TFTP_OACK) {
569 /* server seems to support options */
570 char *res;
571
[2725]572 res = tftp_get_option("blksize", &rbuf[2], len - 2);
[821]573 if (res) {
[2725]574 blksize = tftp_blksize_check(res, blksize);
575 if (blksize < 0) {
[3232]576 G_error_pkt_reason = ERR_BAD_OPT;
[2725]577 goto send_err_pkt;
[1765]578 }
[2725]579 io_bufsize = blksize + 4;
580 }
581# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
582 if (remote_file && G.size == 0) { /* if we don't know it yet */
583 res = tftp_get_option("tsize", &rbuf[2], len - 2);
584 if (res) {
585 G.size = bb_strtoull(res, NULL, 10);
586 if (G.size)
587 tftp_progress_init();
588 }
589 }
590# endif
591 if (CMD_GET(option_mask32)) {
592 /* We'll send ACK for OACK,
593 * such ACK has "block no" of 0 */
[1765]594 block_nr = 0;
[821]595 }
[2725]596 continue;
[821]597 }
[2725]598 /* rfc2347:
599 * "An option not acknowledged by the server
600 * must be ignored by the client and server
601 * as if it were never requested." */
602 if (blksize != TFTP_BLKSIZE_DEFAULT)
603 bb_error_msg("falling back to blocksize "TFTP_BLKSIZE_DEFAULT_STR);
604 blksize = TFTP_BLKSIZE_DEFAULT;
605 io_bufsize = TFTP_BLKSIZE_DEFAULT + 4;
[821]606 }
607#endif
[1765]608 /* block_nr is already advanced to next block# we expect
609 * to get / block# we are about to send next time */
[821]610
[2725]611 if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) {
[1765]612 if (recv_blk == block_nr) {
[2725]613 int sz = full_write(local_fd, &rbuf[4], len - 4);
614 if (sz != len - 4) {
[3232]615 strcpy(G_error_pkt_str, bb_msg_write_error);
616 G_error_pkt_reason = ERR_WRITE;
[2725]617 goto send_err_pkt;
[821]618 }
[2725]619 if (sz != blksize) {
[1765]620 finished = 1;
[821]621 }
[3232]622 IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += sz;)
[1765]623 continue; /* send ACK */
[821]624 }
[2725]625/* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */
626#if 0
[1765]627 if (recv_blk == (block_nr - 1)) {
[821]628 /* Server lost our TFTP_ACK. Resend it */
[1765]629 block_nr = recv_blk;
[821]630 continue;
631 }
[2725]632#endif
[821]633 }
634
[2725]635 if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) {
636 /* did peer ACK our last DATA pkt? */
[1765]637 if (recv_blk == (uint16_t) (block_nr - 1)) {
638 if (finished)
639 goto ret;
640 continue; /* send next block */
[821]641 }
642 }
[1765]643 /* Awww... recv'd packet is not recognized! */
644 goto recv_again;
645 /* why recv_again? - rfc1123 says:
646 * "The sender (i.e., the side originating the DATA packets)
647 * must never resend the current DATA packet on receipt
648 * of a duplicate ACK".
649 * DATA pkts are resent ONLY on timeout.
650 * Thus "goto send_again" will ba a bad mistake above.
651 * See:
652 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
653 */
[2725]654 } /* end of "while (1)" */
[1765]655 ret:
656 if (ENABLE_FEATURE_CLEAN_UP) {
[2725]657 close(local_fd);
658 close(socket_fd);
[1765]659 free(xbuf);
660 free(rbuf);
661 }
662 return finished == 0; /* returns 1 on failure */
[2725]663
664 send_read_err_pkt:
[3232]665 strcpy(G_error_pkt_str, bb_msg_read_error);
[2725]666 send_err_pkt:
[3232]667 if (G_error_pkt_str[0])
668 bb_error_msg("%s", G_error_pkt_str);
669 G.error_pkt[1] = TFTP_ERROR;
670 xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str),
[2725]671 &peer_lsa->u.sa, peer_lsa->len);
672 return EXIT_FAILURE;
673#undef remote_file
[821]674}
675
[2725]676#if ENABLE_TFTP
677
678int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
679int tftp_main(int argc UNUSED_PARAM, char **argv)
[821]680{
[1765]681 len_and_sockaddr *peer_lsa;
[2725]682 const char *local_file = NULL;
683 const char *remote_file = NULL;
684# if ENABLE_FEATURE_TFTP_BLOCKSIZE
685 const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR;
686 int blksize;
687# endif
688 int result;
[821]689 int port;
[2725]690 IF_GETPUT(int opt;)
[821]691
[2725]692 INIT_G();
693
[1765]694 /* -p or -g is mandatory, and they are mutually exclusive */
[2725]695 opt_complementary = "" IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:")
696 IF_GETPUT("g--p:p--g:");
[821]697
[2725]698 IF_GETPUT(opt =) getopt32(argv,
699 IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p")
700 "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:"),
701 &local_file, &remote_file
702 IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
[1765]703 argv += optind;
[821]704
[2725]705# if ENABLE_FEATURE_TFTP_BLOCKSIZE
706 /* Check if the blksize is valid:
707 * RFC2348 says between 8 and 65464 */
708 blksize = tftp_blksize_check(blksize_str, 65564);
709 if (blksize < 0) {
710 //bb_error_msg("bad block size");
711 return EXIT_FAILURE;
712 }
713# endif
[821]714
[2725]715 if (remote_file) {
716 if (!local_file) {
717 const char *slash = strrchr(remote_file, '/');
718 local_file = slash ? slash + 1 : remote_file;
[821]719 }
[2725]720 } else {
721 remote_file = local_file;
[821]722 }
723
[1765]724 /* Error if filename or host is not known */
[2725]725 if (!remote_file || !argv[0])
[821]726 bb_show_usage();
727
[1765]728 port = bb_lookup_port(argv[1], "udp", 69);
729 peer_lsa = xhost2sockaddr(argv[0], port);
[821]730
[2725]731# if ENABLE_TFTP_DEBUG
732 fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
733 xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
734 remote_file, local_file);
735# endif
[821]736
[2725]737# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
738 G.file = remote_file;
739# endif
740 result = tftp_protocol(
741 NULL /*our_lsa*/, peer_lsa,
742 local_file, remote_file
743 IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */)
744 IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
745 );
746 tftp_progress_done();
[821]747
[2725]748 if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
749 unlink(local_file);
[821]750 }
[1765]751 return result;
[821]752}
[1765]753
[2725]754#endif /* ENABLE_TFTP */
755
756#if ENABLE_TFTPD
757int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
758int tftpd_main(int argc UNUSED_PARAM, char **argv)
759{
760 len_and_sockaddr *our_lsa;
761 len_and_sockaddr *peer_lsa;
[3621]762 char *mode, *user_opt;
763 char *local_file = local_file;
[2725]764 const char *error_msg;
765 int opt, result, opcode;
766 IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
767 IF_FEATURE_TFTP_BLOCKSIZE(int want_transfer_size = 0;)
768
769 INIT_G();
770
771 our_lsa = get_sock_lsa(STDIN_FILENO);
772 if (!our_lsa) {
773 /* This is confusing:
774 *bb_error_msg_and_die("stdin is not a socket");
775 * Better: */
776 bb_show_usage();
777 /* Help text says that tftpd must be used as inetd service,
778 * which is by far the most usual cause of get_sock_lsa
779 * failure */
780 }
781 peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
782 peer_lsa->len = our_lsa->len;
783
784 /* Shifting to not collide with TFTP_OPTs */
[3232]785 opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:l", &user_opt) << 8);
[2725]786 argv += optind;
[3232]787 if (opt & TFTPD_OPT_l) {
788 openlog(applet_name, LOG_PID, LOG_DAEMON);
789 logmode = LOGMODE_SYSLOG;
790 }
791 if (opt & TFTPD_OPT_u) {
792 /* Must be before xchroot */
793 G.pw = xgetpwnam(user_opt);
794 }
795 if (argv[0]) {
796 xchroot(argv[0]);
797 }
[2725]798
[3621]799 result = recv_from_to(STDIN_FILENO,
800 G.block_buf, sizeof(G.block_buf) + 1,
801 /* ^^^ sizeof+1 to reliably detect oversized input */
[2725]802 0 /* flags */,
803 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
804
805 error_msg = "malformed packet";
[3232]806 opcode = ntohs(*(uint16_t*)G.block_buf);
[3621]807 if (result < 4 || result > sizeof(G.block_buf)
808 /*|| G.block_buf[result-1] != '\0' - bug compatibility, see below */
[2725]809 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
810 IF_GETPUT(&&)
811 IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
812 )
813 ) {
814 goto err;
815 }
[3621]816 /* Some HP PA-RISC firmware always sends fixed 516-byte requests,
817 * with trailing garbage.
818 * Support that by not requiring NUL to be the last byte (see above).
819 * To make strXYZ() ops safe, force NUL termination:
820 */
821 G.block_buf_tail[0] = '\0';
822
[3232]823 local_file = G.block_buf + 2;
[2725]824 if (local_file[0] == '.' || strstr(local_file, "/.")) {
825 error_msg = "dot in file name";
826 goto err;
827 }
828 mode = local_file + strlen(local_file) + 1;
[3232]829 /* RFC 1350 says mode string is case independent */
830 if (mode >= G.block_buf + result || strcasecmp(mode, "octet") != 0) {
[2725]831 goto err;
832 }
833# if ENABLE_FEATURE_TFTP_BLOCKSIZE
834 {
835 char *res;
836 char *opt_str = mode + sizeof("octet");
[3232]837 int opt_len = G.block_buf + result - opt_str;
[2725]838 if (opt_len > 0) {
839 res = tftp_get_option("blksize", opt_str, opt_len);
840 if (res) {
841 blksize = tftp_blksize_check(res, 65564);
842 if (blksize < 0) {
[3232]843 G_error_pkt_reason = ERR_BAD_OPT;
[2725]844 /* will just send error pkt */
845 goto do_proto;
846 }
847 }
848 if (opcode != TFTP_WRQ /* download? */
849 /* did client ask us about file size? */
850 && tftp_get_option("tsize", opt_str, opt_len)
851 ) {
852 want_transfer_size = 1;
853 }
854 }
855 }
856# endif
857
858 if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
859 if (opt & TFTPD_OPT_r) {
860 /* This would mean "disk full" - not true */
[3232]861 /*G_error_pkt_reason = ERR_WRITE;*/
[2725]862 error_msg = bb_msg_write_error;
863 goto err;
864 }
865 IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
866 } else {
867 IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
868 }
869
[3232]870 /* NB: if G_error_pkt_str or G_error_pkt_reason is set up,
[2725]871 * tftp_protocol() just sends one error pkt and returns */
872
873 do_proto:
874 close(STDIN_FILENO); /* close old, possibly wildcard socket */
875 /* tftp_protocol() will create new one, bound to particular local IP */
876 result = tftp_protocol(
877 our_lsa, peer_lsa,
878 local_file IF_TFTP(, NULL /*remote_file*/)
879 IF_FEATURE_TFTP_BLOCKSIZE(, want_transfer_size)
880 IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
881 );
882
883 return result;
884 err:
[3232]885 strcpy(G_error_pkt_str, error_msg);
[2725]886 goto do_proto;
887}
888
889#endif /* ENABLE_TFTPD */
890
[1765]891#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */
Note: See TracBrowser for help on using the repository browser.