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