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