tftpd: fix download: we must change user AFTER bind
[oweals/busybox.git] / networking / tftp.c
1 /* vi: set sw=4 ts=4: */
2 /* -------------------------------------------------------------------------
3  * tftp.c
4  *
5  * A simple tftp client/server for busybox.
6  * Tries to follow RFC1350.
7  * Only "octet" mode supported.
8  * Optional blocksize negotiation (RFC2347 + RFC2348)
9  *
10  * Copyright (C) 2001 Magnus Damm <damm@opensource.se>
11  *
12  * Parts of the code based on:
13  *
14  * atftp:  Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>
15  *                        and Remi Lefebvre <remi@debian.org>
16  *
17  * utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
18  *
19  * tftpd added by Denys Vlasenko & Vladimir Dronnikov
20  *
21  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
22  * ------------------------------------------------------------------------- */
23
24 #include "libbb.h"
25
26 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
27
28 #define TFTP_BLKSIZE_DEFAULT   512      /* according to RFC 1350, don't change */
29 #define TFTP_TIMEOUT_MS         50
30 #define TFTP_MAXTIMEOUT_MS    2000
31 #define TFTP_NUM_RETRIES        12      /* number of backed-off retries */
32
33 /* opcodes we support */
34 #define TFTP_RRQ   1
35 #define TFTP_WRQ   2
36 #define TFTP_DATA  3
37 #define TFTP_ACK   4
38 #define TFTP_ERROR 5
39 #define TFTP_OACK  6
40
41 /* error codes sent over network (we use only 0, 3 and 8) */
42 /* generic (error message is included in the packet) */
43 #define ERR_UNSPEC   0
44 #define ERR_NOFILE   1
45 #define ERR_ACCESS   2
46 /* disk full or allocation exceeded */
47 #define ERR_WRITE    3
48 #define ERR_OP       4
49 #define ERR_BAD_ID   5
50 #define ERR_EXIST    6
51 #define ERR_BAD_USER 7
52 #define ERR_BAD_OPT  8
53
54 /* masks coming from getopt32 */
55 enum {
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
65 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
66 #define USE_GETPUT(...)
67 #define CMD_GET(cmd) 1
68 #define CMD_PUT(cmd) 0
69 #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
70 #define USE_GETPUT(...)
71 #define CMD_GET(cmd) 0
72 #define CMD_PUT(cmd) 1
73 #else
74 #define USE_GETPUT(...) __VA_ARGS__
75 #define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
76 #define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
77 #endif
78 /* NB: in the code below
79  * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
80  */
81
82
83 struct globals {
84         /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
85         uint8_t error_pkt[4 + 32];
86         char *user_opt;
87         /* used in tftpd_main(), a bit big for stack: */
88         char block_buf[TFTP_BLKSIZE_DEFAULT];
89 };
90 #define G (*(struct globals*)&bb_common_bufsiz1)
91 #define block_buf        (G.block_buf   )
92 #define user_opt         (G.user_opt    )
93 #define error_pkt        (G.error_pkt   )
94 #define INIT_G() \
95         do { \
96         } while (0)
97
98 #define error_pkt_reason (error_pkt[3])
99 #define error_pkt_str    (error_pkt + 4)
100
101
102 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
103
104 static int tftp_blksize_check(const char *blksize_str, int maxsize)
105 {
106         /* Check if the blksize is valid:
107          * RFC2348 says between 8 and 65464,
108          * but our implementation makes it impossible
109          * to use blksizes smaller than 22 octets. */
110         unsigned blksize = bb_strtou(blksize_str, NULL, 10);
111         if (errno
112          || (blksize < 24) || (blksize > maxsize)
113         ) {
114                 bb_error_msg("bad blocksize '%s'", blksize_str);
115                 return -1;
116         }
117 #if ENABLE_DEBUG_TFTP
118         bb_error_msg("using blksize %u", blksize);
119 #endif
120         return blksize;
121 }
122
123 static char *tftp_get_blksize(char *buf, int len)
124 {
125 #define option "blksize"
126         int opt_val = 0;
127         int opt_found = 0;
128         int k;
129
130         /* buf points to:
131          * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */
132
133         while (len > 0) {
134                 /* Make sure options are terminated correctly */
135                 for (k = 0; k < len; k++) {
136                         if (buf[k] == '\0') {
137                                 goto nul_found;
138                         }
139                 }
140                 return NULL;
141  nul_found:
142                 if (opt_val == 0) { /* it's "name" part */
143                         if (strcasecmp(buf, option) == 0) {
144                                 opt_found = 1;
145                         }
146                 } else if (opt_found) {
147                         return buf;
148                 }
149
150                 k++;
151                 buf += k;
152                 len -= k;
153                 opt_val ^= 1;
154         }
155
156         return NULL;
157 #undef option
158 }
159
160 #endif
161
162 static int tftp_protocol(
163                 len_and_sockaddr *our_lsa,
164                 len_and_sockaddr *peer_lsa,
165                 const char *local_file,
166                 USE_TFTP(const char *remote_file,)
167                 int blksize)
168 {
169 #if !ENABLE_TFTP
170 #define remote_file NULL
171 #endif
172         struct pollfd pfd[1];
173 #define socket_fd (pfd[0].fd)
174         int len;
175         int send_len;
176         USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
177         smallint finished = 0;
178         uint16_t opcode;
179         uint16_t block_nr;
180         uint16_t recv_blk;
181         int open_mode, local_fd;
182         int retries, waittime_ms;
183         int io_bufsize = blksize + 4;
184         char *cp = cp; /* for compiler */
185         /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
186          * size varies meaning BUFFERS_GO_ON_STACK would fail */
187         /* We must keep the transmit and receive buffers seperate */
188         /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
189         char *xbuf = xmalloc(io_bufsize);
190         char *rbuf = xmalloc(io_bufsize);
191
192         socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
193         setsockopt_reuseaddr(socket_fd);
194
195         block_nr = 1;
196
197         if (!ENABLE_TFTP || our_lsa) {
198                 /* tftpd */
199
200                 /* Create a socket which is:
201                  * 1. bound to IP:port peer sent 1st datagram to,
202                  * 2. connected to peer's IP:port
203                  * This way we will answer from the IP:port peer
204                  * expects, will not get any other packets on
205                  * the socket, and also plain read/write will work. */
206                 xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
207                 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
208
209                 /* Is there an error already? Send pkt and bail out */
210                 if (error_pkt_reason || error_pkt_str[0])
211                         goto send_err_pkt;
212
213                 if (CMD_GET(option_mask32)) {
214                         /* it's upload - we must ACK 1st packet (with filename)
215                          * as if it's "block 0" */
216                         block_nr = 0;
217                 }
218
219 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
220                 if (blksize != TFTP_BLKSIZE_DEFAULT) {
221                         /* Create and send OACK packet */
222                         /* For the download case, block_nr is still 1 -
223                          * we expect 1st ACK from peer to be for (block_nr-1),
224                          * that is, for "block 0" which is our OACK pkt */
225                         opcode = TFTP_OACK;
226                         cp = xbuf + 2;
227                         /* to be continued, see below */
228                 }
229 #endif
230                 if (user_opt) {
231                         struct passwd *pw = getpwnam(user_opt);
232                         if (!pw)
233                                 bb_error_msg_and_die("unknown user '%s'", user_opt);
234                         change_identity(pw); /* initgroups, setgid, setuid */
235                 }
236         }
237
238         /* Open local file (must be after changing user) */
239         if (CMD_PUT(option_mask32)) {
240                 open_mode = O_RDONLY;
241         } else {
242                 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
243 #if ENABLE_TFTPD
244                 if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) {
245                         /* tftpd without -c */
246                         open_mode = O_WRONLY | O_TRUNC;
247                 }
248 #endif
249         }
250         if (!(option_mask32 & TFTPD_OPT)) {
251                 local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO;
252                 if (NOT_LONE_DASH(local_file))
253                         local_fd = xopen(local_file, open_mode);
254         } else {
255                 local_fd = open_or_warn(local_file, open_mode);
256                 if (local_fd < 0) {
257                         /*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/
258                         strcpy(error_pkt_str, "can't open file");
259                         goto send_err_pkt;
260                 }
261         }
262
263         if (!ENABLE_TFTP || our_lsa) {
264 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
265                 if (blksize != TFTP_BLKSIZE_DEFAULT) {
266                         /* Create and send OACK packet. continued */
267                         goto add_blksize_opt;
268                 }
269 #endif
270         } else {
271                 /* tftp */
272
273                 /* We can't (and don't really need to) bind the socket:
274                  * we don't know from which local IP datagrams will be sent,
275                  * but kernel will pick the same IP every time (unless routing
276                  * table is changed), thus peer will see dgrams consistently
277                  * coming from the same IP.
278                  * We would like to connect the socket, but since peer's
279                  * UDP code can be less perfect than ours, _peer's_ IP:port
280                  * in replies may differ from IP:port we used to send
281                  * our first packet. We can connect() only when we get
282                  * first reply. */
283
284                 /* build opcode */
285                 opcode = TFTP_WRQ;
286                 if (CMD_GET(option_mask32)) {
287                         opcode = TFTP_RRQ;
288                 }
289                 cp = xbuf + 2;
290                 /* add filename and mode */
291                 /* fill in packet if the filename fits into xbuf */
292                 len = strlen(remote_file) + 1;
293                 if (2 + len + sizeof("octet") >= io_bufsize) {
294                         bb_error_msg("remote filename is too long");
295                         goto ret;
296                 }
297                 strcpy(cp, remote_file);
298                 cp += len;
299                 /* add "mode" part of the package */
300                 strcpy(cp, "octet");
301                 cp += sizeof("octet");
302
303 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
304                 if (blksize != TFTP_BLKSIZE_DEFAULT) {
305                         /* rfc2348 says that 65464 is a max allowed value */
306                         if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
307                                 bb_error_msg("remote filename is too long");
308                                 goto ret;
309                         }
310                         want_option_ack = 1;
311  add_blksize_opt:
312                         /* add "blksize", <nul>, blksize, <nul> */
313                         strcpy(cp, "blksize");
314                         cp += sizeof("blksize");
315                         cp += snprintf(cp, 6, "%d", blksize) + 1;
316                 }
317 #endif
318                 /* First packet is built, so skip packet generation */
319                 goto send_pkt;
320         }
321
322         /* Using mostly goto's - continue/break will be less clear
323          * in where we actually jump to */
324         while (1) {
325                 /* Build ACK or DATA */
326                 cp = xbuf + 2;
327                 *((uint16_t*)cp) = htons(block_nr);
328                 cp += 2;
329                 block_nr++;
330                 opcode = TFTP_ACK;
331                 if (CMD_PUT(option_mask32)) {
332                         opcode = TFTP_DATA;
333                         len = full_read(local_fd, cp, blksize);
334                         if (len < 0) {
335                                 goto send_read_err_pkt;
336                         }
337                         if (len != blksize) {
338                                 finished = 1;
339                         }
340                         cp += len;
341                 }
342  send_pkt:
343                 /* Send packet */
344                 *((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
345                 send_len = cp - xbuf;
346                 /* NB: send_len value is preserved in code below
347                  * for potential resend */
348
349                 retries = TFTP_NUM_RETRIES;     /* re-initialize */
350                 waittime_ms = TFTP_TIMEOUT_MS;
351
352  send_again:
353 #if ENABLE_DEBUG_TFTP
354                 fprintf(stderr, "sending %u bytes\n", send_len);
355                 for (cp = xbuf; cp < &xbuf[send_len]; cp++)
356                         fprintf(stderr, "%02x ", (unsigned char) *cp);
357                 fprintf(stderr, "\n");
358 #endif
359                 xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
360                 /* Was it final ACK? then exit */
361                 if (finished && (opcode == TFTP_ACK))
362                         goto ret;
363
364  recv_again:
365                 /* Receive packet */
366                 /*pfd[0].fd = socket_fd;*/
367                 pfd[0].events = POLLIN;
368                 switch (safe_poll(pfd, 1, waittime_ms)) {
369                 default:
370                         /*bb_perror_msg("poll"); - done in safe_poll */
371                         goto ret;
372                 case 0:
373                         retries--;
374                         if (retries == 0) {
375                                 bb_error_msg("timeout");
376                                 goto ret; /* no err packet sent */
377                         }
378
379                         /* exponential backoff with limit */
380                         waittime_ms += waittime_ms/2;
381                         if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
382                                 waittime_ms = TFTP_MAXTIMEOUT_MS;
383                         }
384
385                         goto send_again; /* resend last sent pkt */
386                 case 1:
387                         if (!our_lsa) {
388                                 /* tftp (not tftpd!) receiving 1st packet */
389                                 our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
390                                 len = recvfrom(socket_fd, rbuf, io_bufsize, 0,
391                                                 &peer_lsa->u.sa, &peer_lsa->len);
392                                 /* Our first dgram went to port 69
393                                  * but reply may come from different one.
394                                  * Remember and use this new port (and IP) */
395                                 if (len >= 0)
396                                         xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
397                         } else {
398                                 /* tftpd, or not the very first packet:
399                                  * socket is connect()ed, can just read from it. */
400                                 /* Don't full_read()!
401                                  * This is not TCP, one read == one pkt! */
402                                 len = safe_read(socket_fd, rbuf, io_bufsize);
403                         }
404                         if (len < 0) {
405                                 goto send_read_err_pkt;
406                         }
407                         if (len < 4) { /* too small? */
408                                 goto recv_again;
409                         }
410                 }
411
412                 /* Process recv'ed packet */
413                 opcode = ntohs( ((uint16_t*)rbuf)[0] );
414                 recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
415 #if ENABLE_DEBUG_TFTP
416                 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
417 #endif
418
419                 if (opcode == TFTP_ERROR) {
420                         static const char errcode_str[] =
421                                 "\0"
422                                 "file not found\0"
423                                 "access violation\0"
424                                 "disk full\0"
425                                 "bad operation\0"
426                                 "unknown transfer id\0"
427                                 "file already exists\0"
428                                 "no such user\0"
429                                 "bad option";
430
431                         const char *msg = "";
432
433                         if (len > 4 && rbuf[4] != '\0') {
434                                 msg = &rbuf[4];
435                                 rbuf[io_bufsize - 1] = '\0'; /* paranoia */
436                         } else if (recv_blk <= 8) {
437                                 msg = nth_string(errcode_str, recv_blk);
438                         }
439                         bb_error_msg("server error: (%u) %s", recv_blk, msg);
440                         goto ret;
441                 }
442
443 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
444                 if (want_option_ack) {
445                         want_option_ack = 0;
446                         if (opcode == TFTP_OACK) {
447                                 /* server seems to support options */
448                                 char *res;
449
450                                 res = tftp_get_blksize(&rbuf[2], len - 2);
451                                 if (res) {
452                                         blksize = tftp_blksize_check(res, blksize);
453                                         if (blksize < 0) {
454                                                 error_pkt_reason = ERR_BAD_OPT;
455                                                 goto send_err_pkt;
456                                         }
457                                         io_bufsize = blksize + 4;
458                                         /* Send ACK for OACK ("block" no: 0) */
459                                         block_nr = 0;
460                                         continue;
461                                 }
462                                 /* rfc2347:
463                                  * "An option not acknowledged by the server
464                                  *  must be ignored by the client and server
465                                  *  as if it were never requested." */
466                         }
467                         bb_error_msg("server only supports blocksize of 512");
468                         blksize = TFTP_BLKSIZE_DEFAULT;
469                         io_bufsize = TFTP_BLKSIZE_DEFAULT + 4;
470                 }
471 #endif
472                 /* block_nr is already advanced to next block# we expect
473                  * to get / block# we are about to send next time */
474
475                 if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) {
476                         if (recv_blk == block_nr) {
477                                 int sz = full_write(local_fd, &rbuf[4], len - 4);
478                                 if (sz != len - 4) {
479                                         strcpy(error_pkt_str, bb_msg_write_error);
480                                         error_pkt_reason = ERR_WRITE;
481                                         goto send_err_pkt;
482                                 }
483                                 if (sz != blksize) {
484                                         finished = 1;
485                                 }
486                                 continue; /* send ACK */
487                         }
488                         if (recv_blk == (block_nr - 1)) {
489                                 /* Server lost our TFTP_ACK.  Resend it */
490                                 block_nr = recv_blk;
491                                 continue;
492                         }
493                 }
494
495                 if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) {
496                         /* did peer ACK our last DATA pkt? */
497                         if (recv_blk == (uint16_t) (block_nr - 1)) {
498                                 if (finished)
499                                         goto ret;
500                                 continue; /* send next block */
501                         }
502                 }
503                 /* Awww... recv'd packet is not recognized! */
504                 goto recv_again;
505                 /* why recv_again? - rfc1123 says:
506                  * "The sender (i.e., the side originating the DATA packets)
507                  *  must never resend the current DATA packet on receipt
508                  *  of a duplicate ACK".
509                  * DATA pkts are resent ONLY on timeout.
510                  * Thus "goto send_again" will ba a bad mistake above.
511                  * See:
512                  * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
513                  */
514         } /* end of "while (1)" */
515  ret:
516         if (ENABLE_FEATURE_CLEAN_UP) {
517                 close(local_fd);
518                 close(socket_fd);
519                 free(xbuf);
520                 free(rbuf);
521         }
522         return finished == 0; /* returns 1 on failure */
523
524  send_read_err_pkt:
525         strcpy(error_pkt_str, bb_msg_read_error);
526  send_err_pkt:
527         if (error_pkt_str[0])
528                 bb_error_msg(error_pkt_str);
529         error_pkt[1] = TFTP_ERROR;
530         xsendto(socket_fd, error_pkt, 4 + 1 + strlen(error_pkt_str),
531                         &peer_lsa->u.sa, peer_lsa->len);
532         return EXIT_FAILURE;
533 }
534
535 #if ENABLE_TFTP
536
537 int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
538 int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
539 {
540         len_and_sockaddr *peer_lsa;
541         const char *local_file = NULL;
542         const char *remote_file = NULL;
543         const char *blksize_str = "512";
544         int blksize;
545         int result;
546         int port;
547         USE_GETPUT(int opt;)
548
549         INIT_G();
550
551         /* -p or -g is mandatory, and they are mutually exclusive */
552         opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
553                         USE_GETPUT("g--p:p--g:");
554
555         USE_GETPUT(opt =) getopt32(argv,
556                         USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
557                                 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
558                         &local_file, &remote_file
559                         USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
560         argv += optind;
561
562 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
563         /* Check if the blksize is valid:
564          * RFC2348 says between 8 and 65464 */
565         blksize = tftp_blksize_check(blksize_str, 65564);
566         if (blksize < 0) {
567                 //bb_error_msg("bad block size");
568                 return EXIT_FAILURE;
569         }
570 #endif
571
572         if (!local_file)
573                 local_file = remote_file;
574         if (!remote_file)
575                 remote_file = local_file;
576         /* Error if filename or host is not known */
577         if (!remote_file || !argv[0])
578                 bb_show_usage();
579
580         port = bb_lookup_port(argv[1], "udp", 69);
581         peer_lsa = xhost2sockaddr(argv[0], port);
582
583 #if ENABLE_DEBUG_TFTP
584         fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
585                         xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
586                         remote_file, local_file);
587 #endif
588
589         result = tftp_protocol(
590                         NULL /* our_lsa*/, peer_lsa,
591                         local_file, remote_file,
592                         blksize);
593
594         if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
595                 unlink(local_file);
596         }
597         return result;
598 }
599
600 #endif /* ENABLE_TFTP */
601
602 #if ENABLE_TFTPD
603
604 /* TODO: libbb candidate? */
605 static len_and_sockaddr *get_sock_lsa(int s)
606 {
607         len_and_sockaddr *lsa;
608         socklen_t len = 0;
609
610         if (getsockname(s, NULL, &len) != 0)
611                 return NULL;
612         lsa = xzalloc(LSA_LEN_SIZE + len);
613         lsa->len = len;
614         getsockname(s, &lsa->u.sa, &lsa->len);
615         return lsa;
616 }
617
618 int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
619 int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
620 {
621         len_and_sockaddr *our_lsa;
622         len_and_sockaddr *peer_lsa;
623         char *local_file, *mode;
624         const char *error_msg;
625         int opt, result, opcode;
626         int local_fd = local_fd; /* for compiler */
627         int blksize = blksize;
628         USE_GETPUT(int cmd = cmd;)
629
630         INIT_G();
631
632         our_lsa = get_sock_lsa(STDIN_FILENO);
633         if (!our_lsa)
634                 bb_perror_msg_and_die("stdin is not a socket");
635         peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
636         peer_lsa->len = our_lsa->len;
637
638         /* Shifting to not collide with TFTP_OPTs */
639         opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8);
640         argv += optind;
641         if (argv[0])
642                 xchdir(argv[0]);
643
644         result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
645                         0 /* flags */,
646                         &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
647
648         error_msg = "malformed packet";
649         opcode = ntohs(*(uint16_t*)block_buf);
650         if (result < 4 || result >= sizeof(block_buf)
651          || block_buf[result-1] != '\0'
652          || (USE_FEATURE_TFTP_GET(opcode != TFTP_RRQ) /* not download */
653              USE_GETPUT(&&)
654              USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
655             )
656         ) {
657                 goto err;
658         }
659         local_file = block_buf + 2;
660         if (local_file[0] == '.' || strstr(local_file, "/.")) {
661                 error_msg = "dot in local_file";
662                 goto err;
663         }
664         mode = local_file + strlen(local_file) + 1;
665         if (mode >= block_buf + result || strcmp(mode, "octet") != 0) {
666                 goto err;
667         }
668         blksize = TFTP_BLKSIZE_DEFAULT;
669 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
670         {
671                 char *res;
672                 char *opt_str = mode + sizeof("octet");
673                 int opt_len = block_buf + result - opt_str;
674                 if (opt_len > 0) {
675                         res = tftp_get_blksize(opt_str, opt_len);
676                         if (res) {
677                                 blksize = tftp_blksize_check(res, 65564);
678                                 if (blksize < 0) {
679                                         error_pkt_reason = ERR_BAD_OPT;
680                                         /* will just send error pkt */
681                                         goto do_proto;
682                                 }
683                         }
684                 }
685         }
686 #endif
687
688         if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
689                 if (opt & TFTPD_OPT_r) {
690                         /* This would mean "disk full" - not true */
691                         /*error_pkt_reason = ERR_WRITE;*/
692                         error_msg = bb_msg_write_error;
693                         goto err;
694                 }
695                 USE_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
696         } else {
697                 USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
698         }
699
700         close(STDIN_FILENO); /* close old, possibly wildcard socket */
701         /* tftp_protocol() will create new one, bound to particular local IP */
702
703         /* NB: if error_pkt_str or error_pkt_reason is set up,
704          * tftp_protocol() just sends one error pkt and returns */
705  do_proto:
706         result = tftp_protocol(
707                 our_lsa, peer_lsa,
708                 local_file, USE_TFTP(NULL /*remote_file*/,)
709                 blksize
710         );
711
712         return result;
713  err:
714         strcpy(error_pkt_str, error_msg);
715         goto do_proto;
716 }
717
718 #endif /* ENABLE_TFTPD */
719
720 #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */