tftpd.c (36085B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * 9 * Trivial file transfer protocol server. 10 * 11 * This code includes many modifications by Jim Guyton <guyton@rand-unix> 12 * 13 * This source file was started based on netkit-tftpd 0.17 14 * Heavily modified for curl's test suite 15 */ 16 17 /* 18 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 19 * Copyright (c) 1983, Regents of the University of California. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * This product includes software developed by the University of 33 * California, Berkeley and its contributors. 34 * 4. Neither the name of the University nor the names of its contributors 35 * may be used to endorse or promote products derived from this software 36 * without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * 50 * SPDX-License-Identifier: BSD-4-Clause-UC 51 */ 52 #include "first.h" 53 54 #ifdef HAVE_SYS_IOCTL_H 55 #include <sys/ioctl.h> /* for ioctl() */ 56 #endif 57 #ifdef HAVE_FCNTL_H 58 #include <fcntl.h> 59 #endif 60 #ifdef HAVE_SYS_FILIO_H 61 #include <sys/filio.h> /* FIONREAD on Solaris 7 */ 62 #endif 63 64 #include <setjmp.h> 65 66 #ifdef HAVE_PWD_H 67 #include <pwd.h> 68 #endif 69 70 #include <ctype.h> 71 72 /***************************************************************************** 73 * This is a rewrite/clone of the arpa/tftp.h file for systems without it. * 74 *****************************************************************************/ 75 #define SEGSIZE 512 /* data segment size */ 76 77 #if defined(__GNUC__) && ((__GNUC__ >= 3) || \ 78 ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) 79 # define PACKED_STRUCT __attribute__((__packed__)) 80 #else 81 # define PACKED_STRUCT /* NOTHING */ 82 #endif 83 84 /* Using a packed struct as binary in a program is begging for problems, but 85 the tftpd server was written like this so we have this struct here to make 86 things build. */ 87 88 struct tftphdr { 89 unsigned short th_opcode; /* packet type */ 90 unsigned short th_block; /* all sorts of things */ 91 char th_data[1]; /* data or error string */ 92 } PACKED_STRUCT; 93 94 #define th_stuff th_block 95 #define th_code th_block 96 #define th_msg th_data 97 98 #define TFTP_EUNDEF 0 99 #define TFTP_ENOTFOUND 1 100 #define TFTP_EACCESS 2 101 #define TFTP_ENOSPACE 3 102 #define TFTP_EBADOP 4 103 #define TFTP_EBADID 5 104 #define TFTP_EEXISTS 6 105 #define TFTP_ENOUSER 7 106 107 /***************************************************************************** 108 * STRUCT DECLARATIONS AND DEFINES * 109 *****************************************************************************/ 110 111 #ifndef PKTSIZE 112 #define PKTSIZE (SEGSIZE + 4) /* SEGSIZE defined in arpa/tftp.h */ 113 #endif 114 115 struct testcase { 116 char *buffer; /* holds the file data to send to the client */ 117 size_t bufsize; /* size of the data in buffer */ 118 char *rptr; /* read pointer into the buffer */ 119 size_t rcount; /* amount of data left to read of the file */ 120 long testno; /* test case number */ 121 int ofile; /* file descriptor for output file when uploading to us */ 122 123 int writedelay; /* number of seconds between each packet */ 124 }; 125 126 struct formats { 127 const char *f_mode; 128 int f_convert; 129 }; 130 131 struct errmsg { 132 int e_code; 133 const char *e_msg; 134 }; 135 136 typedef union { 137 struct tftphdr hdr; 138 char storage[PKTSIZE]; 139 } tftphdr_storage_t; 140 141 /* 142 * bf.counter values in range [-1 .. SEGSIZE] represents size of data in the 143 * bf.buf buffer. Additionally it can also hold flags BF_ALLOC or BF_FREE. 144 */ 145 146 struct bf { 147 int counter; /* size of data in buffer, or flag */ 148 tftphdr_storage_t buf; /* room for data packet */ 149 }; 150 151 #define BF_ALLOC -3 /* alloc'd but not yet filled */ 152 #define BF_FREE -2 /* free */ 153 154 #define opcode_RRQ 1 155 #define opcode_WRQ 2 156 #define opcode_DATA 3 157 #define opcode_ACK 4 158 #define opcode_ERROR 5 159 160 #define TIMEOUT 5 161 162 #define REQUEST_DUMP "server.input" 163 164 /***************************************************************************** 165 * GLOBAL VARIABLES * 166 *****************************************************************************/ 167 168 static struct errmsg errmsgs[] = { 169 { TFTP_EUNDEF, "Undefined error code" }, 170 { TFTP_ENOTFOUND, "File not found" }, 171 { TFTP_EACCESS, "Access violation" }, 172 { TFTP_ENOSPACE, "Disk full or allocation exceeded" }, 173 { TFTP_EBADOP, "Illegal TFTP operation" }, 174 { TFTP_EBADID, "Unknown transfer ID" }, 175 { TFTP_EEXISTS, "File already exists" }, 176 { TFTP_ENOUSER, "No such user" }, 177 { -1, 0 } 178 }; 179 180 static const struct formats formata[] = { 181 { "netascii", 1 }, 182 { "octet", 0 }, 183 { NULL, 0 } 184 }; 185 186 static struct bf bfs[2]; 187 188 static int nextone; /* index of next buffer to use */ 189 static int current; /* index of buffer in use */ 190 191 /* control flags for crlf conversions */ 192 static int newline = 0; /* fillbuf: in middle of newline expansion */ 193 static int prevchar = -1; /* putbuf: previous char (cr check) */ 194 195 static tftphdr_storage_t trsbuf; 196 static tftphdr_storage_t ackbuf; 197 198 static curl_socket_t peer = CURL_SOCKET_BAD; 199 200 static unsigned int timeout; 201 static unsigned int maxtimeout = 5 * TIMEOUT; 202 203 static int tftpd_wrotepidfile = 0; 204 static int tftpd_wroteportfile = 0; 205 206 #ifdef HAVE_SIGSETJMP 207 static sigjmp_buf timeoutbuf; 208 #endif 209 210 #if defined(HAVE_ALARM) && defined(SIGALRM) 211 static const unsigned int rexmtval = TIMEOUT; 212 #endif 213 214 /***************************************************************************** 215 * FUNCTION PROTOTYPES * 216 *****************************************************************************/ 217 218 static struct tftphdr *rw_init(int); 219 220 static struct tftphdr *w_init(void); 221 222 static struct tftphdr *r_init(void); 223 224 static void read_ahead(struct testcase *test, int convert); 225 226 static ssize_t write_behind(struct testcase *test, int convert); 227 228 static int synchnet(curl_socket_t); 229 230 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size); 231 232 static int validate_access(struct testcase *test, 233 const char *filename, unsigned short mode); 234 235 static void sendtftp(struct testcase *test, const struct formats *pf); 236 237 static void recvtftp(struct testcase *test, const struct formats *pf); 238 239 static void nak(int error); 240 241 #if defined(HAVE_ALARM) && defined(SIGALRM) 242 243 static void mysignal(int sig, void (*handler)(int)); 244 245 static void timer(int signum); 246 247 static void justtimeout(int signum); 248 249 #endif /* HAVE_ALARM && SIGALRM */ 250 251 /***************************************************************************** 252 * FUNCTION IMPLEMENTATIONS * 253 *****************************************************************************/ 254 255 #if defined(HAVE_ALARM) && defined(SIGALRM) 256 257 /* 258 * Like signal(), but with well-defined semantics. 259 */ 260 static void mysignal(int sig, void (*handler)(int)) 261 { 262 struct sigaction sa; 263 memset(&sa, 0, sizeof(sa)); 264 sa.sa_handler = handler; 265 sigaction(sig, &sa, NULL); 266 } 267 268 #ifdef HAVE_SIGSETJMP 269 CURL_NORETURN 270 #endif 271 static void timer(int signum) 272 { 273 (void)signum; 274 275 logmsg("alarm!"); 276 277 timeout += rexmtval; 278 if(timeout >= maxtimeout) { 279 if(tftpd_wrotepidfile) { 280 tftpd_wrotepidfile = 0; 281 unlink(pidname); 282 } 283 if(tftpd_wroteportfile) { 284 tftpd_wroteportfile = 0; 285 unlink(portname); 286 } 287 if(serverlogslocked) { 288 serverlogslocked = 0; 289 clear_advisor_read_lock(loglockfile); 290 } 291 exit(1); 292 } 293 #ifdef HAVE_SIGSETJMP 294 siglongjmp(timeoutbuf, 1); 295 #endif 296 } 297 298 static void justtimeout(int signum) 299 { 300 (void)signum; 301 } 302 303 #endif /* HAVE_ALARM && SIGALRM */ 304 305 /* 306 * init for either read-ahead or write-behind. 307 * zero for write-behind, one for read-head. 308 */ 309 static struct tftphdr *rw_init(int x) 310 { 311 newline = 0; /* init crlf flag */ 312 prevchar = -1; 313 bfs[0].counter = BF_ALLOC; /* pass out the first buffer */ 314 current = 0; 315 bfs[1].counter = BF_FREE; 316 nextone = x; /* ahead or behind? */ 317 return &bfs[0].buf.hdr; 318 } 319 320 static struct tftphdr *w_init(void) 321 { 322 return rw_init(0); /* write-behind */ 323 } 324 325 static struct tftphdr *r_init(void) 326 { 327 return rw_init(1); /* read-ahead */ 328 } 329 330 /* Have emptied current buffer by sending to net and getting ack. 331 Free it and return next buffer filled with data. 332 */ 333 static int readit(struct testcase *test, struct tftphdr * volatile *dpp, 334 int convert /* if true, convert to ASCII */) 335 { 336 struct bf *b; 337 338 bfs[current].counter = BF_FREE; /* free old one */ 339 current = !current; /* "incr" current */ 340 341 b = &bfs[current]; /* look at new buffer */ 342 if(b->counter == BF_FREE) /* if it's empty */ 343 read_ahead(test, convert); /* fill it */ 344 345 *dpp = &b->buf.hdr; /* set caller's ptr */ 346 return b->counter; 347 } 348 349 /* 350 * fill the input buffer, doing ASCII conversions if requested 351 * conversions are lf -> cr, lf and cr -> cr, nul 352 */ 353 static void read_ahead(struct testcase *test, 354 int convert /* if true, convert to ASCII */) 355 { 356 int i; 357 char *p; 358 int c; 359 struct bf *b; 360 struct tftphdr *dp; 361 362 b = &bfs[nextone]; /* look at "next" buffer */ 363 if(b->counter != BF_FREE) /* nop if not free */ 364 return; 365 nextone = !nextone; /* "incr" next buffer ptr */ 366 367 dp = &b->buf.hdr; 368 369 if(convert == 0) { 370 /* The former file reading code did this: 371 b->counter = read(fileno(file), dp->th_data, SEGSIZE); */ 372 size_t copy_n = CURLMIN(SEGSIZE, test->rcount); 373 memcpy(dp->th_data, test->rptr, copy_n); 374 375 /* decrease amount, advance pointer */ 376 test->rcount -= copy_n; 377 test->rptr += copy_n; 378 b->counter = (int)copy_n; 379 return; 380 } 381 382 p = dp->th_data; 383 for(i = 0 ; i < SEGSIZE; i++) { 384 if(newline) { 385 if(prevchar == '\n') 386 c = '\n'; /* lf to cr,lf */ 387 else 388 c = '\0'; /* cr to cr,nul */ 389 newline = 0; 390 } 391 else { 392 if(test->rcount) { 393 c = test->rptr[0]; 394 test->rptr++; 395 test->rcount--; 396 } 397 else 398 break; 399 if(c == '\n' || c == '\r') { 400 prevchar = c; 401 c = '\r'; 402 newline = 1; 403 } 404 } 405 *p++ = (char)c; 406 } 407 b->counter = (int)(p - dp->th_data); 408 } 409 410 /* Update count associated with the buffer, get new buffer from the queue. 411 Calls write_behind only if next buffer not available. 412 */ 413 static int writeit(struct testcase *test, struct tftphdr * volatile *dpp, 414 int ct, int convert) 415 { 416 bfs[current].counter = ct; /* set size of data to write */ 417 current = !current; /* switch to other buffer */ 418 if(bfs[current].counter != BF_FREE) /* if not free */ 419 write_behind(test, convert); /* flush it */ 420 bfs[current].counter = BF_ALLOC; /* mark as alloc'd */ 421 *dpp = &bfs[current].buf.hdr; 422 return ct; /* this is a lie of course */ 423 } 424 425 /* 426 * Output a buffer to a file, converting from netascii if requested. 427 * CR, NUL -> CR and CR, LF => LF. 428 * Note spec is undefined if we get CR as last byte of file or a 429 * CR followed by anything else. In this case we leave it alone. 430 */ 431 static ssize_t write_behind(struct testcase *test, int convert) 432 { 433 char *writebuf; 434 int count; 435 int ct; 436 char *p; 437 int c; /* current character */ 438 struct bf *b; 439 struct tftphdr *dp; 440 441 b = &bfs[nextone]; 442 if(b->counter < -1) /* anything to flush? */ 443 return 0; /* just nop if nothing to do */ 444 445 if(!test->ofile) { 446 char outfile[256]; 447 snprintf(outfile, sizeof(outfile), "%s/upload.%ld", logdir, test->testno); 448 test->ofile = open(outfile, O_CREAT|O_RDWR|CURL_O_BINARY, 0777); 449 if(test->ofile == -1) { 450 logmsg("Couldn't create and/or open file %s for upload!", outfile); 451 return -1; /* failure! */ 452 } 453 } 454 else if(test->ofile <= 0) { 455 return -1; /* failure! */ 456 } 457 458 count = b->counter; /* remember byte count */ 459 b->counter = BF_FREE; /* reset flag */ 460 dp = &b->buf.hdr; 461 nextone = !nextone; /* incr for next time */ 462 writebuf = dp->th_data; 463 464 if(count <= 0) 465 return -1; /* nak logic? */ 466 467 if(convert == 0) 468 return write(test->ofile, writebuf, count); 469 470 p = writebuf; 471 ct = count; 472 while(ct--) { /* loop over the buffer */ 473 c = *p++; /* pick up a character */ 474 if(prevchar == '\r') { /* if prev char was cr */ 475 if(c == '\n') /* if have cr,lf then just */ 476 lseek(test->ofile, -1, SEEK_CUR); /* smash lf on top of the cr */ 477 else 478 if(c == '\0') /* if have cr,nul then */ 479 goto skipit; /* just skip over the putc */ 480 /* else just fall through and allow it */ 481 } 482 /* formerly 483 putc(c, file); */ 484 if(1 != write(test->ofile, &c, 1)) 485 break; 486 skipit: 487 prevchar = c; 488 } 489 return count; 490 } 491 492 /* When an error has occurred, it is possible that the two sides are out of 493 * synch. Ie: that what I think is the other side's response to packet N is 494 * really their response to packet N-1. 495 * 496 * So, to try to prevent that, we flush all the input queued up for us on the 497 * network connection on our host. 498 * 499 * We return the number of packets we flushed (mostly for reporting when trace 500 * is active). 501 */ 502 503 static int synchnet(curl_socket_t f /* socket to flush */) 504 { 505 int j = 0; 506 char rbuf[PKTSIZE]; 507 srvr_sockaddr_union_t fromaddr; 508 curl_socklen_t fromaddrlen; 509 510 for(;;) { 511 #if defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) 512 long i; 513 (void) IoctlSocket(f, FIONBIO, &i); 514 #elif defined(HAVE_IOCTLSOCKET) 515 unsigned long i; 516 (void) ioctlsocket(f, FIONREAD, &i); 517 #else 518 int i; 519 (void) ioctl(f, FIONREAD, &i); 520 #endif 521 if(i) { 522 j++; 523 #ifdef USE_IPV6 524 if(!use_ipv6) 525 #endif 526 fromaddrlen = sizeof(fromaddr.sa4); 527 #ifdef USE_IPV6 528 else 529 fromaddrlen = sizeof(fromaddr.sa6); 530 #endif 531 (void) recvfrom(f, rbuf, sizeof(rbuf), 0, 532 &fromaddr.sa, &fromaddrlen); 533 } 534 else 535 break; 536 } 537 return j; 538 } 539 540 static int test_tftpd(int argc, char **argv) 541 { 542 srvr_sockaddr_union_t me; 543 struct tftphdr *tp; 544 ssize_t n = 0; 545 int arg = 1; 546 unsigned short port = 8999; /* UDP */ 547 curl_socket_t sock = CURL_SOCKET_BAD; 548 int flag; 549 int rc; 550 int error; 551 struct testcase test; 552 int result = 0; 553 srvr_sockaddr_union_t from; 554 curl_socklen_t fromlen; 555 556 memset(&test, 0, sizeof(test)); 557 558 pidname = ".tftpd.pid"; 559 serverlogfile = "log/tftpd.log"; 560 serverlogslocked = 0; 561 562 while(argc > arg) { 563 if(!strcmp("--version", argv[arg])) { 564 printf("tftpd IPv4%s\n", 565 #ifdef USE_IPV6 566 "/IPv6" 567 #else 568 "" 569 #endif 570 ); 571 return 0; 572 } 573 else if(!strcmp("--pidfile", argv[arg])) { 574 arg++; 575 if(argc > arg) 576 pidname = argv[arg++]; 577 } 578 else if(!strcmp("--portfile", argv[arg])) { 579 arg++; 580 if(argc > arg) 581 portname = argv[arg++]; 582 } 583 else if(!strcmp("--logfile", argv[arg])) { 584 arg++; 585 if(argc > arg) 586 serverlogfile = argv[arg++]; 587 } 588 else if(!strcmp("--logdir", argv[arg])) { 589 arg++; 590 if(argc > arg) 591 logdir = argv[arg++]; 592 } 593 else if(!strcmp("--ipv4", argv[arg])) { 594 #ifdef USE_IPV6 595 ipv_inuse = "IPv4"; 596 use_ipv6 = FALSE; 597 #endif 598 arg++; 599 } 600 else if(!strcmp("--ipv6", argv[arg])) { 601 #ifdef USE_IPV6 602 ipv_inuse = "IPv6"; 603 use_ipv6 = TRUE; 604 #endif 605 arg++; 606 } 607 else if(!strcmp("--port", argv[arg])) { 608 arg++; 609 if(argc > arg) { 610 char *endptr; 611 unsigned long ulnum = strtoul(argv[arg], &endptr, 10); 612 port = util_ultous(ulnum); 613 arg++; 614 } 615 } 616 else if(!strcmp("--srcdir", argv[arg])) { 617 arg++; 618 if(argc > arg) { 619 srcpath = argv[arg]; 620 arg++; 621 } 622 } 623 else { 624 puts("Usage: tftpd [option]\n" 625 " --version\n" 626 " --logfile [file]\n" 627 " --logdir [directory]\n" 628 " --pidfile [file]\n" 629 " --portfile [file]\n" 630 " --ipv4\n" 631 " --ipv6\n" 632 " --port [port]\n" 633 " --srcdir [path]"); 634 return 0; 635 } 636 } 637 638 snprintf(loglockfile, sizeof(loglockfile), "%s/%s/tftp-%s.lock", 639 logdir, SERVERLOGS_LOCKDIR, ipv_inuse); 640 641 #ifdef _WIN32 642 if(win32_init()) 643 return 2; 644 #endif 645 646 install_signal_handlers(true); 647 648 #ifdef USE_IPV6 649 if(!use_ipv6) 650 #endif 651 sock = socket(AF_INET, SOCK_DGRAM, 0); 652 #ifdef USE_IPV6 653 else 654 sock = socket(AF_INET6, SOCK_DGRAM, 0); 655 #endif 656 657 if(CURL_SOCKET_BAD == sock) { 658 error = SOCKERRNO; 659 logmsg("Error creating socket (%d) %s", error, sstrerror(error)); 660 result = 1; 661 goto tftpd_cleanup; 662 } 663 664 flag = 1; 665 if(0 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 666 (void *)&flag, sizeof(flag))) { 667 error = SOCKERRNO; 668 logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", 669 error, sstrerror(error)); 670 result = 1; 671 goto tftpd_cleanup; 672 } 673 674 #ifdef USE_IPV6 675 if(!use_ipv6) { 676 #endif 677 memset(&me.sa4, 0, sizeof(me.sa4)); 678 me.sa4.sin_family = AF_INET; 679 me.sa4.sin_addr.s_addr = INADDR_ANY; 680 me.sa4.sin_port = htons(port); 681 rc = bind(sock, &me.sa, sizeof(me.sa4)); 682 #ifdef USE_IPV6 683 } 684 else { 685 memset(&me.sa6, 0, sizeof(me.sa6)); 686 me.sa6.sin6_family = AF_INET6; 687 me.sa6.sin6_addr = in6addr_any; 688 me.sa6.sin6_port = htons(port); 689 rc = bind(sock, &me.sa, sizeof(me.sa6)); 690 } 691 #endif /* USE_IPV6 */ 692 if(rc) { 693 error = SOCKERRNO; 694 logmsg("Error binding socket on port %hu (%d) %s", port, error, 695 sstrerror(error)); 696 result = 1; 697 goto tftpd_cleanup; 698 } 699 700 if(!port) { 701 /* The system was supposed to choose a port number, figure out which 702 port we actually got and update the listener port value with it. */ 703 curl_socklen_t la_size; 704 srvr_sockaddr_union_t localaddr; 705 #ifdef USE_IPV6 706 if(!use_ipv6) 707 #endif 708 la_size = sizeof(localaddr.sa4); 709 #ifdef USE_IPV6 710 else 711 la_size = sizeof(localaddr.sa6); 712 #endif 713 memset(&localaddr.sa, 0, (size_t)la_size); 714 if(getsockname(sock, &localaddr.sa, &la_size) < 0) { 715 error = SOCKERRNO; 716 logmsg("getsockname() failed with error (%d) %s", 717 error, sstrerror(error)); 718 sclose(sock); 719 goto tftpd_cleanup; 720 } 721 switch(localaddr.sa.sa_family) { 722 case AF_INET: 723 port = ntohs(localaddr.sa4.sin_port); 724 break; 725 #ifdef USE_IPV6 726 case AF_INET6: 727 port = ntohs(localaddr.sa6.sin6_port); 728 break; 729 #endif 730 default: 731 break; 732 } 733 if(!port) { 734 /* Real failure, listener port shall not be zero beyond this point. */ 735 logmsg("Apparently getsockname() succeeded, with listener port zero."); 736 logmsg("A valid reason for this failure is a binary built without"); 737 logmsg("proper network library linkage. This might not be the only"); 738 logmsg("reason, but double check it before anything else."); 739 result = 2; 740 goto tftpd_cleanup; 741 } 742 } 743 744 tftpd_wrotepidfile = write_pidfile(pidname); 745 if(!tftpd_wrotepidfile) { 746 result = 1; 747 goto tftpd_cleanup; 748 } 749 750 if(portname) { 751 tftpd_wroteportfile = write_portfile(portname, port); 752 if(!tftpd_wroteportfile) { 753 result = 1; 754 goto tftpd_cleanup; 755 } 756 } 757 758 logmsg("Running %s version on port UDP/%d", ipv_inuse, (int)port); 759 760 for(;;) { 761 fromlen = sizeof(from); 762 #ifdef USE_IPV6 763 if(!use_ipv6) 764 #endif 765 fromlen = sizeof(from.sa4); 766 #ifdef USE_IPV6 767 else 768 fromlen = sizeof(from.sa6); 769 #endif 770 n = (ssize_t)recvfrom(sock, &trsbuf.storage[0], sizeof(trsbuf.storage), 0, 771 &from.sa, &fromlen); 772 if(got_exit_signal) 773 break; 774 if(n < 0) { 775 logmsg("recvfrom"); 776 result = 3; 777 break; 778 } 779 780 set_advisor_read_lock(loglockfile); 781 serverlogslocked = 1; 782 783 #ifdef USE_IPV6 784 if(!use_ipv6) { 785 #endif 786 from.sa4.sin_family = AF_INET; 787 peer = socket(AF_INET, SOCK_DGRAM, 0); 788 if(CURL_SOCKET_BAD == peer) { 789 logmsg("socket"); 790 result = 2; 791 break; 792 } 793 if(connect(peer, &from.sa, sizeof(from.sa4)) < 0) { 794 logmsg("connect: fail"); 795 result = 1; 796 break; 797 } 798 #ifdef USE_IPV6 799 } 800 else { 801 from.sa6.sin6_family = AF_INET6; 802 peer = socket(AF_INET6, SOCK_DGRAM, 0); 803 if(CURL_SOCKET_BAD == peer) { 804 logmsg("socket"); 805 result = 2; 806 break; 807 } 808 if(connect(peer, &from.sa, sizeof(from.sa6)) < 0) { 809 logmsg("connect: fail"); 810 result = 1; 811 break; 812 } 813 } 814 #endif 815 816 maxtimeout = 5*TIMEOUT; 817 818 tp = &trsbuf.hdr; 819 tp->th_opcode = ntohs(tp->th_opcode); 820 if(tp->th_opcode == opcode_RRQ || tp->th_opcode == opcode_WRQ) { 821 memset(&test, 0, sizeof(test)); 822 if(do_tftp(&test, tp, n) < 0) 823 break; 824 free(test.buffer); 825 } 826 sclose(peer); 827 peer = CURL_SOCKET_BAD; 828 829 if(got_exit_signal) 830 break; 831 832 if(serverlogslocked) { 833 serverlogslocked = 0; 834 clear_advisor_read_lock(loglockfile); 835 } 836 837 logmsg("end of one transfer"); 838 } 839 840 tftpd_cleanup: 841 842 if(test.ofile > 0) 843 close(test.ofile); 844 845 if((peer != sock) && (peer != CURL_SOCKET_BAD)) 846 sclose(peer); 847 848 if(sock != CURL_SOCKET_BAD) 849 sclose(sock); 850 851 if(got_exit_signal) 852 logmsg("signalled to die"); 853 854 if(tftpd_wrotepidfile) 855 unlink(pidname); 856 if(tftpd_wroteportfile) 857 unlink(portname); 858 859 if(serverlogslocked) { 860 serverlogslocked = 0; 861 clear_advisor_read_lock(loglockfile); 862 } 863 864 restore_signal_handlers(true); 865 866 if(got_exit_signal) { 867 logmsg("========> %s tftpd (port: %d pid: %ld) exits with signal (%d)", 868 ipv_inuse, (int)port, (long)our_getpid(), exit_signal); 869 /* 870 * To properly set the return status of the process we 871 * must raise the same signal SIGINT or SIGTERM that we 872 * caught and let the old handler take care of it. 873 */ 874 raise(exit_signal); 875 } 876 877 logmsg("========> tftpd quits"); 878 return result; 879 } 880 881 /* 882 * Handle initial connection protocol. 883 */ 884 static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) 885 { 886 char *cp; 887 int first = 1, ecode; 888 const struct formats *pf; 889 char *filename, *mode = NULL; 890 #ifdef USE_WINSOCK 891 DWORD recvtimeout, recvtimeoutbak; 892 #endif 893 const char *option = "mode"; /* mode is implicit */ 894 int toggle = 1; 895 FILE *server; 896 char dumpfile[256]; 897 898 snprintf(dumpfile, sizeof(dumpfile), "%s/%s", logdir, REQUEST_DUMP); 899 900 /* Open request dump file. */ 901 server = fopen(dumpfile, "ab"); 902 if(!server) { 903 int error = errno; 904 logmsg("fopen() failed with error (%d) %s", error, strerror(error)); 905 logmsg("Error opening file '%s'", dumpfile); 906 return -1; 907 } 908 909 /* store input protocol */ 910 fprintf(server, "opcode = %x\n", tp->th_opcode); 911 912 cp = (char *)&tp->th_stuff; 913 filename = cp; 914 do { 915 bool endofit = true; 916 while(cp < &trsbuf.storage[size]) { 917 if(*cp == '\0') { 918 endofit = false; 919 break; 920 } 921 cp++; 922 } 923 if(endofit) 924 /* no more options */ 925 break; 926 927 /* before increasing pointer, make sure it is still within the legal 928 space */ 929 if((cp + 1) < &trsbuf.storage[size]) { 930 ++cp; 931 if(first) { 932 /* store the mode since we need it later */ 933 mode = cp; 934 first = 0; 935 } 936 if(toggle) 937 /* name/value pair: */ 938 fprintf(server, "%s = %s\n", option, cp); 939 else { 940 /* store the name pointer */ 941 option = cp; 942 } 943 toggle ^= 1; 944 } 945 else 946 /* No more options */ 947 break; 948 } while(1); 949 950 if(*cp || !mode) { 951 nak(TFTP_EBADOP); 952 fclose(server); 953 return 3; 954 } 955 956 /* store input protocol */ 957 fprintf(server, "filename = %s\n", filename); 958 959 for(cp = mode; cp && *cp; cp++) 960 if(ISUPPER(*cp)) 961 *cp = (char)tolower((int)*cp); 962 963 /* store input protocol */ 964 fclose(server); 965 966 for(pf = formata; pf->f_mode; pf++) 967 if(strcmp(pf->f_mode, mode) == 0) 968 break; 969 if(!pf->f_mode) { 970 nak(TFTP_EBADOP); 971 return 2; 972 } 973 ecode = validate_access(test, filename, tp->th_opcode); 974 if(ecode) { 975 nak(ecode); 976 return 1; 977 } 978 979 #ifdef USE_WINSOCK 980 recvtimeout = sizeof(recvtimeoutbak); 981 getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 982 (char *)&recvtimeoutbak, (int *)&recvtimeout); 983 recvtimeout = TIMEOUT*1000; 984 setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 985 (const char *)&recvtimeout, sizeof(recvtimeout)); 986 #endif 987 988 if(tp->th_opcode == opcode_WRQ) 989 recvtftp(test, pf); 990 else 991 sendtftp(test, pf); 992 993 #ifdef USE_WINSOCK 994 recvtimeout = recvtimeoutbak; 995 setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, 996 (const char *)&recvtimeout, sizeof(recvtimeout)); 997 #endif 998 999 return 0; 1000 } 1001 1002 /* Based on the testno, parse the correct server commands. */ 1003 static int tftpd_parse_servercmd(struct testcase *req) 1004 { 1005 FILE *stream; 1006 int error; 1007 1008 stream = test2fopen(req->testno, logdir); 1009 if(!stream) { 1010 error = errno; 1011 logmsg("fopen() failed with error (%d) %s", error, strerror(error)); 1012 logmsg(" Couldn't open test file %ld", req->testno); 1013 return 1; /* done */ 1014 } 1015 else { 1016 char *orgcmd = NULL; 1017 char *cmd = NULL; 1018 size_t cmdsize = 0; 1019 int num = 0; 1020 1021 /* get the custom server control "commands" */ 1022 error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream); 1023 fclose(stream); 1024 if(error) { 1025 logmsg("getpart() failed with error (%d)", error); 1026 return 1; /* done */ 1027 } 1028 1029 cmd = orgcmd; 1030 while(cmd && cmdsize) { 1031 char *check; 1032 if(1 == sscanf(cmd, "writedelay: %d", &num)) { 1033 logmsg("instructed to delay %d secs between packets", num); 1034 req->writedelay = num; 1035 } 1036 else { 1037 logmsg("Unknown <servercmd> instruction found: %s", cmd); 1038 } 1039 /* try to deal with CRLF or just LF */ 1040 check = strchr(cmd, '\r'); 1041 if(!check) 1042 check = strchr(cmd, '\n'); 1043 1044 if(check) { 1045 /* get to the letter following the newline */ 1046 while((*check == '\r') || (*check == '\n')) 1047 check++; 1048 1049 if(!*check) 1050 /* if we reached a zero, get out */ 1051 break; 1052 cmd = check; 1053 } 1054 else 1055 break; 1056 } 1057 free(orgcmd); 1058 } 1059 1060 return 0; /* OK! */ 1061 } 1062 1063 1064 /* 1065 * Validate file access. 1066 */ 1067 static int validate_access(struct testcase *test, 1068 const char *filename, unsigned short mode) 1069 { 1070 char *ptr; 1071 1072 logmsg("trying to get file: %s mode %x", filename, mode); 1073 1074 if(!strncmp("verifiedserver", filename, 14)) { 1075 char weare[128]; 1076 size_t count = snprintf(weare, sizeof(weare), "WE ROOLZ: %ld\r\n", 1077 (long)our_getpid()); 1078 1079 logmsg("Are-we-friendly question received"); 1080 test->buffer = strdup(weare); 1081 test->rptr = test->buffer; /* set read pointer */ 1082 test->bufsize = count; /* set total count */ 1083 test->rcount = count; /* set data left to read */ 1084 return 0; /* fine */ 1085 } 1086 1087 /* find the last slash */ 1088 ptr = strrchr(filename, '/'); 1089 1090 if(ptr) { 1091 char partbuf[80]="data"; 1092 long partno; 1093 long testno; 1094 FILE *stream; 1095 1096 ptr++; /* skip the slash */ 1097 1098 /* skip all non-numericals following the slash */ 1099 while(*ptr && !ISDIGIT(*ptr)) 1100 ptr++; 1101 1102 /* get the number */ 1103 testno = strtol(ptr, &ptr, 10); 1104 1105 if(testno > 10000) { 1106 partno = testno % 10000; 1107 testno /= 10000; 1108 } 1109 else 1110 partno = 0; 1111 1112 1113 logmsg("requested test number %ld part %ld", testno, partno); 1114 1115 test->testno = testno; 1116 1117 (void)tftpd_parse_servercmd(test); 1118 1119 stream = test2fopen(testno, logdir); 1120 1121 if(0 != partno) 1122 snprintf(partbuf, sizeof(partbuf), "data%ld", partno); 1123 1124 if(!stream) { 1125 int error = errno; 1126 logmsg("fopen() failed with error (%d) %s", error, strerror(error)); 1127 logmsg("Couldn't open test file for test: %ld", testno); 1128 return TFTP_EACCESS; 1129 } 1130 else { 1131 size_t count; 1132 int error = getpart(&test->buffer, &count, "reply", partbuf, stream); 1133 fclose(stream); 1134 if(error) { 1135 logmsg("getpart() failed with error (%d)", error); 1136 return TFTP_EACCESS; 1137 } 1138 if(test->buffer) { 1139 test->rptr = test->buffer; /* set read pointer */ 1140 test->bufsize = count; /* set total count */ 1141 test->rcount = count; /* set data left to read */ 1142 } 1143 else 1144 return TFTP_EACCESS; 1145 } 1146 } 1147 else { 1148 logmsg("no slash found in path"); 1149 return TFTP_EACCESS; /* failure */ 1150 } 1151 1152 logmsg("file opened and all is good"); 1153 return 0; 1154 } 1155 1156 /* 1157 * Send the requested file. 1158 */ 1159 static void sendtftp(struct testcase *test, const struct formats *pf) 1160 { 1161 int size; 1162 ssize_t n; 1163 /* These are volatile to live through a siglongjmp */ 1164 volatile unsigned short sendblock; /* block count */ 1165 struct tftphdr * volatile sdp = r_init(); /* data buffer */ 1166 struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */ 1167 1168 sendblock = 1; 1169 #if defined(HAVE_ALARM) && defined(SIGALRM) 1170 mysignal(SIGALRM, timer); 1171 #endif 1172 do { 1173 size = readit(test, (struct tftphdr * volatile *)&sdp, pf->f_convert); 1174 if(size < 0) { 1175 nak(errno + 100); 1176 return; 1177 } 1178 sdp->th_opcode = htons(opcode_DATA); 1179 sdp->th_block = htons(sendblock); 1180 timeout = 0; 1181 #ifdef HAVE_SIGSETJMP 1182 (void) sigsetjmp(timeoutbuf, 1); 1183 #endif 1184 if(test->writedelay) { 1185 logmsg("Pausing %d seconds before %d bytes", test->writedelay, 1186 size); 1187 curlx_wait_ms(1000*test->writedelay); 1188 } 1189 1190 send_data: 1191 logmsg("write"); 1192 if(swrite(peer, sdp, size + 4) != size + 4) { 1193 logmsg("write: fail"); 1194 return; 1195 } 1196 read_ahead(test, pf->f_convert); 1197 for(;;) { 1198 #ifdef HAVE_ALARM 1199 alarm(rexmtval); /* read the ack */ 1200 #endif 1201 logmsg("read"); 1202 n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage)); 1203 logmsg("read: %zd", n); 1204 #ifdef HAVE_ALARM 1205 alarm(0); 1206 #endif 1207 if(got_exit_signal) 1208 return; 1209 if(n < 0) { 1210 logmsg("read: fail"); 1211 return; 1212 } 1213 sap->th_opcode = ntohs(sap->th_opcode); 1214 sap->th_block = ntohs(sap->th_block); 1215 1216 if(sap->th_opcode == opcode_ERROR) { 1217 logmsg("got ERROR"); 1218 return; 1219 } 1220 1221 if(sap->th_opcode == opcode_ACK) { 1222 if(sap->th_block == sendblock) { 1223 break; 1224 } 1225 /* Re-synchronize with the other side */ 1226 (void) synchnet(peer); 1227 if(sap->th_block == (sendblock-1)) { 1228 goto send_data; 1229 } 1230 } 1231 1232 } 1233 sendblock++; 1234 } while(size == SEGSIZE); 1235 } 1236 1237 /* 1238 * Receive a file. 1239 */ 1240 static void recvtftp(struct testcase *test, const struct formats *pf) 1241 { 1242 ssize_t n, size; 1243 /* These are volatile to live through a siglongjmp */ 1244 volatile unsigned short recvblock; /* block count */ 1245 struct tftphdr * volatile rdp; /* data buffer */ 1246 struct tftphdr *rap; /* ack buffer */ 1247 1248 recvblock = 0; 1249 rdp = w_init(); 1250 #if defined(HAVE_ALARM) && defined(SIGALRM) 1251 mysignal(SIGALRM, timer); 1252 #endif 1253 rap = &ackbuf.hdr; 1254 do { 1255 timeout = 0; 1256 rap->th_opcode = htons(opcode_ACK); 1257 rap->th_block = htons(recvblock); 1258 recvblock++; 1259 #ifdef HAVE_SIGSETJMP 1260 (void) sigsetjmp(timeoutbuf, 1); 1261 #endif 1262 send_ack: 1263 logmsg("write"); 1264 if(swrite(peer, &ackbuf.storage[0], 4) != 4) { 1265 logmsg("write: fail"); 1266 goto abort; 1267 } 1268 write_behind(test, pf->f_convert); 1269 for(;;) { 1270 #ifdef HAVE_ALARM 1271 alarm(rexmtval); 1272 #endif 1273 logmsg("read"); 1274 n = sread(peer, rdp, PKTSIZE); 1275 logmsg("read: %zd", n); 1276 #ifdef HAVE_ALARM 1277 alarm(0); 1278 #endif 1279 if(got_exit_signal) 1280 goto abort; 1281 if(n < 0) { /* really? */ 1282 logmsg("read: fail"); 1283 goto abort; 1284 } 1285 rdp->th_opcode = ntohs(rdp->th_opcode); 1286 rdp->th_block = ntohs(rdp->th_block); 1287 if(rdp->th_opcode == opcode_ERROR) 1288 goto abort; 1289 if(rdp->th_opcode == opcode_DATA) { 1290 if(rdp->th_block == recvblock) { 1291 break; /* normal */ 1292 } 1293 /* Re-synchronize with the other side */ 1294 (void) synchnet(peer); 1295 if(rdp->th_block == (recvblock-1)) 1296 goto send_ack; /* rexmit */ 1297 } 1298 } 1299 1300 size = writeit(test, &rdp, (int)(n - 4), pf->f_convert); 1301 if(size != (n-4)) { /* ahem */ 1302 if(size < 0) 1303 nak(errno + 100); 1304 else 1305 nak(TFTP_ENOSPACE); 1306 goto abort; 1307 } 1308 } while(size == SEGSIZE); 1309 write_behind(test, pf->f_convert); 1310 /* close the output file as early as possible after upload completion */ 1311 if(test->ofile > 0) { 1312 close(test->ofile); 1313 test->ofile = 0; 1314 } 1315 1316 rap->th_opcode = htons(opcode_ACK); /* send the "final" ack */ 1317 rap->th_block = htons(recvblock); 1318 (void) swrite(peer, &ackbuf.storage[0], 4); 1319 #if defined(HAVE_ALARM) && defined(SIGALRM) 1320 mysignal(SIGALRM, justtimeout); /* just abort read on timeout */ 1321 alarm(rexmtval); 1322 #endif 1323 /* normally times out and quits */ 1324 n = sread(peer, &trsbuf.storage[0], sizeof(trsbuf.storage)); 1325 #ifdef HAVE_ALARM 1326 alarm(0); 1327 #endif 1328 if(got_exit_signal) 1329 goto abort; 1330 if(n >= 4 && /* if read some data */ 1331 rdp->th_opcode == opcode_DATA && /* and got a data block */ 1332 recvblock == rdp->th_block) { /* then my last ack was lost */ 1333 (void) swrite(peer, &ackbuf.storage[0], 4); /* resend final ack */ 1334 } 1335 abort: 1336 /* make sure the output file is closed in case of abort */ 1337 if(test->ofile > 0) { 1338 close(test->ofile); 1339 test->ofile = 0; 1340 } 1341 return; 1342 } 1343 1344 /* 1345 * Send a nak packet (error message). Error code passed in is one of the 1346 * standard TFTP codes, or a Unix errno offset by 100. 1347 */ 1348 static void nak(int error) 1349 { 1350 struct tftphdr *tp; 1351 int length; 1352 struct errmsg *pe; 1353 1354 tp = &trsbuf.hdr; 1355 tp->th_opcode = htons(opcode_ERROR); 1356 tp->th_code = htons((unsigned short)error); 1357 for(pe = errmsgs; pe->e_code >= 0; pe++) 1358 if(pe->e_code == error) 1359 break; 1360 if(pe->e_code < 0) { 1361 pe->e_msg = strerror(error - 100); 1362 tp->th_code = TFTP_EUNDEF; /* set 'undef' errorcode */ 1363 } 1364 length = (int)strlen(pe->e_msg); 1365 1366 /* we use memcpy() instead of strcpy() in order to avoid buffer overflow 1367 * report from glibc with FORTIFY_SOURCE */ 1368 memcpy(tp->th_msg, pe->e_msg, length + 1); 1369 length += 5; 1370 if(swrite(peer, &trsbuf.storage[0], length) != length) 1371 logmsg("nak: fail\n"); 1372 }