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