1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* 40 * TFTP User Program -- Protocol Machines 41 */ 42 #include <sys/types.h> 43 #include <sys/socket.h> 44 #include <sys/time.h> 45 #include <sys/stat.h> 46 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <stdbool.h> 51 #include <unistd.h> 52 #include <errno.h> 53 #include <string.h> 54 #include <stddef.h> 55 #include <inttypes.h> 56 57 #include "tftpcommon.h" 58 #include "tftpprivate.h" 59 60 static char *blksize_str(void); 61 static char *timeout_str(void); 62 static char *tsize_str(void); 63 static int blksize_handler(char *); 64 static int timeout_handler(char *); 65 static int tsize_handler(char *); 66 static int add_options(char *, char *); 67 static int process_oack(tftpbuf *, int); 68 static void nak(int); 69 static void startclock(void); 70 static void stopclock(void); 71 static void printstats(char *, off_t); 72 static int makerequest(int, char *, struct tftphdr *, char *); 73 static void tpacket(char *, struct tftphdr *, int); 74 75 static struct options { 76 char *opt_name; 77 char *(*opt_str)(void); 78 int (*opt_handler)(char *); 79 } options[] = { 80 { "blksize", blksize_str, blksize_handler }, 81 { "timeout", timeout_str, timeout_handler }, 82 { "tsize", tsize_str, tsize_handler }, 83 { NULL } 84 }; 85 86 static char optbuf[MAX_OPTVAL_LEN]; 87 static bool tsize_set; 88 89 static tftpbuf ackbuf; 90 static int timeout; 91 static off_t tsize; 92 static jmp_buf timeoutbuf; 93 94 int blocksize = SEGSIZE; /* Number of data bytes in a DATA packet */ 95 96 /*ARGSUSED*/ 97 static void 98 timer(int signum) 99 { 100 timeout += rexmtval; 101 if (timeout >= maxtimeout) { 102 (void) fputs("Transfer timed out.\n", stderr); 103 longjmp(toplevel, -1); 104 } 105 (void) signal(SIGALRM, timer); 106 longjmp(timeoutbuf, 1); 107 } 108 109 /* 110 * Send the requested file. 111 */ 112 void 113 tftp_sendfile(int fd, char *name, char *mode) 114 { 115 struct tftphdr *ap; /* data and ack packets */ 116 struct tftphdr *dp; 117 int n; 118 volatile int count = 0, size; 119 volatile ushort_t block = 0; 120 volatile off_t amount = 0; 121 struct sockaddr_in6 from; 122 socklen_t fromlen; 123 int convert; /* true if doing nl->crlf conversion */ 124 FILE *file; 125 struct stat statb; 126 int errcode; 127 128 startclock(); /* start stat's clock */ 129 dp = r_init(); /* reset fillbuf/read-ahead code */ 130 ap = &ackbuf.tb_hdr; 131 file = fdopen(fd, "r"); 132 convert = (strcmp(mode, "netascii") == 0); 133 134 tsize_set = ((tsize_opt != 0) && !convert && (fstat(fd, &statb) == 0)); 135 if (tsize_set) 136 tsize = statb.st_size; 137 138 do { 139 (void) signal(SIGALRM, timer); 140 if (count == 0) { 141 if ((size = makerequest(WRQ, name, dp, mode)) == -1) { 142 (void) fprintf(stderr, 143 "tftp: Error: Write request packet too " 144 "big\n"); 145 (void) fclose(file); 146 return; 147 } 148 size -= 4; 149 } else { 150 size = readit(file, &dp, convert); 151 if (size < 0) { 152 nak(errno + 100); 153 break; 154 } 155 dp->th_opcode = htons((ushort_t)DATA); 156 dp->th_block = htons((ushort_t)block); 157 } 158 timeout = 0; 159 (void) setjmp(timeoutbuf); 160 if (trace) 161 tpacket("sent", dp, size + 4); 162 n = sendto(f, dp, size + 4, 0, 163 (struct sockaddr *)&sin6, sizeof (sin6)); 164 if (n != size + 4) { 165 perror("tftp: sendto"); 166 goto abort; 167 } 168 /* Can't read-ahead first block as OACK may change blocksize */ 169 if (count != 0) 170 read_ahead(file, convert); 171 (void) alarm(rexmtval); 172 for (; ; ) { 173 (void) sigrelse(SIGALRM); 174 do { 175 fromlen = (socklen_t)sizeof (from); 176 n = recvfrom(f, ackbuf.tb_data, 177 sizeof (ackbuf.tb_data), 0, 178 (struct sockaddr *)&from, &fromlen); 179 if (n < 0) { 180 perror("tftp: recvfrom"); 181 goto abort; 182 } 183 } while (n < offsetof(struct tftphdr, th_data)); 184 (void) sighold(SIGALRM); 185 sin6.sin6_port = from.sin6_port; /* added */ 186 if (trace) 187 tpacket("received", ap, n); 188 /* should verify packet came from server */ 189 ap->th_opcode = ntohs(ap->th_opcode); 190 if (ap->th_opcode == ERROR) { 191 ap->th_code = ntohs(ap->th_code); 192 (void) fprintf(stderr, 193 "Error code %d", ap->th_code); 194 if (n > offsetof(struct tftphdr, th_data)) 195 (void) fprintf(stderr, ": %.*s", n - 196 offsetof(struct tftphdr, th_data), 197 ap->th_msg); 198 (void) fputc('\n', stderr); 199 goto abort; 200 } 201 if ((count == 0) && (ap->th_opcode == OACK)) { 202 errcode = process_oack(&ackbuf, n); 203 if (errcode >= 0) { 204 nak(errcode); 205 (void) fputs("Rejected OACK\n", 206 stderr); 207 goto abort; 208 } 209 break; 210 } 211 if (ap->th_opcode == ACK) { 212 ap->th_block = ntohs(ap->th_block); 213 if (ap->th_block == block) { 214 break; 215 } 216 /* 217 * Never resend the current DATA packet on 218 * receipt of a duplicate ACK, doing so would 219 * cause the "Sorcerer's Apprentice Syndrome". 220 */ 221 } 222 } 223 cancel_alarm(); 224 if (count > 0) 225 amount += size; 226 block++; 227 count++; 228 } while (size == blocksize || count == 1); 229 abort: 230 cancel_alarm(); 231 (void) fclose(file); 232 stopclock(); 233 if (amount > 0) 234 printstats("Sent", amount); 235 } 236 237 /* 238 * Receive a file. 239 */ 240 void 241 tftp_recvfile(int fd, char *name, char *mode) 242 { 243 struct tftphdr *ap; 244 struct tftphdr *dp; 245 volatile ushort_t block = 1; 246 int n; 247 volatile int size; 248 volatile unsigned long amount = 0; 249 struct sockaddr_in6 from; 250 socklen_t fromlen; 251 volatile bool firsttrip = true; 252 FILE *file; 253 int convert; /* true if converting crlf -> lf */ 254 int errcode; 255 256 startclock(); 257 dp = w_init(); 258 ap = &ackbuf.tb_hdr; 259 file = fdopen(fd, "w"); 260 convert = (strcmp(mode, "netascii") == 0); 261 262 tsize_set = (tsize_opt != 0); 263 if (tsize_set) 264 tsize = 0; 265 266 if ((size = makerequest(RRQ, name, ap, mode)) == -1) { 267 (void) fprintf(stderr, 268 "tftp: Error: Read request packet too big\n"); 269 (void) fclose(file); 270 return; 271 } 272 273 do { 274 (void) signal(SIGALRM, timer); 275 if (firsttrip) { 276 firsttrip = false; 277 } else { 278 ap->th_opcode = htons((ushort_t)ACK); 279 ap->th_block = htons((ushort_t)(block)); 280 size = 4; 281 block++; 282 } 283 284 send_oack_ack: 285 timeout = 0; 286 (void) setjmp(timeoutbuf); 287 send_ack: 288 if (trace) 289 tpacket("sent", ap, size); 290 if (sendto(f, ackbuf.tb_data, size, 0, (struct sockaddr *)&sin6, 291 sizeof (sin6)) != size) { 292 (void) alarm(0); 293 perror("tftp: sendto"); 294 goto abort; 295 } 296 if (write_behind(file, convert) < 0) { 297 nak(errno + 100); 298 goto abort; 299 } 300 (void) alarm(rexmtval); 301 for (; ; ) { 302 (void) sigrelse(SIGALRM); 303 do { 304 fromlen = (socklen_t)sizeof (from); 305 n = recvfrom(f, dp, blocksize + 4, 0, 306 (struct sockaddr *)&from, &fromlen); 307 if (n < 0) { 308 perror("tftp: recvfrom"); 309 goto abort; 310 } 311 } while (n < offsetof(struct tftphdr, th_data)); 312 (void) sighold(SIGALRM); 313 sin6.sin6_port = from.sin6_port; /* added */ 314 if (trace) 315 tpacket("received", dp, n); 316 /* should verify client address */ 317 dp->th_opcode = ntohs(dp->th_opcode); 318 if (dp->th_opcode == ERROR) { 319 dp->th_code = ntohs(dp->th_code); 320 (void) fprintf(stderr, "Error code %d", 321 dp->th_code); 322 if (n > offsetof(struct tftphdr, th_data)) 323 (void) fprintf(stderr, ": %.*s", n - 324 offsetof(struct tftphdr, th_data), 325 dp->th_msg); 326 (void) fputc('\n', stderr); 327 goto abort; 328 } 329 if ((block == 1) && (dp->th_opcode == OACK)) { 330 errcode = process_oack((tftpbuf *)dp, n); 331 if (errcode >= 0) { 332 cancel_alarm(); 333 nak(errcode); 334 (void) fputs("Rejected OACK\n", 335 stderr); 336 (void) fclose(file); 337 return; 338 } 339 ap->th_opcode = htons((ushort_t)ACK); 340 ap->th_block = htons(0); 341 size = 4; 342 goto send_oack_ack; 343 } 344 if (dp->th_opcode == DATA) { 345 int j; 346 347 dp->th_block = ntohs(dp->th_block); 348 if (dp->th_block == block) { 349 break; /* have next packet */ 350 } 351 /* 352 * On an error, try to synchronize 353 * both sides. 354 */ 355 j = synchnet(f); 356 if (j < 0) { 357 perror("tftp: recvfrom"); 358 goto abort; 359 } 360 if ((j > 0) && trace) { 361 (void) printf("discarded %d packets\n", 362 j); 363 } 364 if (dp->th_block == (block-1)) { 365 goto send_ack; /* resend ack */ 366 } 367 } 368 } 369 cancel_alarm(); 370 size = writeit(file, &dp, n - 4, convert); 371 if (size < 0) { 372 nak(errno + 100); 373 goto abort; 374 } 375 amount += size; 376 } while (size == blocksize); 377 378 cancel_alarm(); 379 if (write_behind(file, convert) < 0) { /* flush last buffer */ 380 nak(errno + 100); 381 goto abort; 382 } 383 n = fclose(file); 384 file = NULL; 385 if (n == EOF) { 386 nak(errno + 100); 387 goto abort; 388 } 389 390 /* ok to ack, since user has seen err msg */ 391 ap->th_opcode = htons((ushort_t)ACK); 392 ap->th_block = htons((ushort_t)block); 393 if (trace) 394 tpacket("sent", ap, 4); 395 if (sendto(f, ackbuf.tb_data, 4, 0, 396 (struct sockaddr *)&sin6, sizeof (sin6)) != 4) 397 perror("tftp: sendto"); 398 399 abort: 400 cancel_alarm(); 401 if (file != NULL) 402 (void) fclose(file); 403 stopclock(); 404 if (amount > 0) 405 printstats("Received", amount); 406 } 407 408 static int 409 makerequest(int request, char *name, struct tftphdr *tp, char *mode) 410 { 411 char *cp, *cpend; 412 int len; 413 414 tp->th_opcode = htons((ushort_t)request); 415 cp = (char *)&tp->th_stuff; 416 417 /* Maximum size of a request packet is 512 bytes (RFC 2347) */ 418 cpend = (char *)tp + SEGSIZE; 419 420 len = strlcpy(cp, name, cpend - cp) + 1; 421 cp += len; 422 if (cp > cpend) 423 return (-1); 424 425 len = strlcpy(cp, mode, cpend - cp) + 1; 426 cp += len; 427 if (cp > cpend) 428 return (-1); 429 430 len = add_options(cp, cpend); 431 if (len == -1) 432 return (-1); 433 cp += len; 434 435 return (cp - (char *)tp); 436 } 437 438 /* 439 * Return the blksize option value string to include in the request packet. 440 */ 441 static char * 442 blksize_str(void) 443 { 444 blocksize = SEGSIZE; 445 if (blksize == 0) 446 return (NULL); 447 448 (void) snprintf(optbuf, sizeof (optbuf), "%d", blksize); 449 return (optbuf); 450 } 451 452 /* 453 * Return the timeout option value string to include in the request packet. 454 */ 455 static char * 456 timeout_str(void) 457 { 458 if (srexmtval == 0) 459 return (NULL); 460 461 (void) snprintf(optbuf, sizeof (optbuf), "%d", srexmtval); 462 return (optbuf); 463 } 464 465 /* 466 * Return the tsize option value string to include in the request packet. 467 */ 468 static char * 469 tsize_str(void) 470 { 471 if (tsize_set == false) 472 return (NULL); 473 474 (void) snprintf(optbuf, sizeof (optbuf), OFF_T_FMT, tsize); 475 return (optbuf); 476 } 477 478 /* 479 * Validate and action the blksize option value string from the OACK packet. 480 * Returns -1 on success or an error code on failure. 481 */ 482 static int 483 blksize_handler(char *optstr) 484 { 485 char *endp; 486 int value; 487 488 /* Make sure the option was requested */ 489 if (blksize == 0) 490 return (EOPTNEG); 491 errno = 0; 492 value = (int)strtol(optstr, &endp, 10); 493 if (errno != 0 || value < MIN_BLKSIZE || value > blksize || 494 *endp != '\0') 495 return (EOPTNEG); 496 blocksize = value; 497 return (-1); 498 } 499 500 /* 501 * Validate and action the timeout option value string from the OACK packet. 502 * Returns -1 on success or an error code on failure. 503 */ 504 static int 505 timeout_handler(char *optstr) 506 { 507 char *endp; 508 int value; 509 510 /* Make sure the option was requested */ 511 if (srexmtval == 0) 512 return (EOPTNEG); 513 errno = 0; 514 value = (int)strtol(optstr, &endp, 10); 515 if (errno != 0 || value != srexmtval || *endp != '\0') 516 return (EOPTNEG); 517 /* 518 * Nothing to set, client and server retransmission intervals are 519 * set separately in the client. 520 */ 521 return (-1); 522 } 523 524 /* 525 * Validate and action the tsize option value string from the OACK packet. 526 * Returns -1 on success or an error code on failure. 527 */ 528 static int 529 tsize_handler(char *optstr) 530 { 531 char *endp; 532 longlong_t value; 533 534 /* Make sure the option was requested */ 535 if (tsize_set == false) 536 return (EOPTNEG); 537 errno = 0; 538 value = strtoll(optstr, &endp, 10); 539 if (errno != 0 || value < 0 || *endp != '\0') 540 return (EOPTNEG); 541 #if _FILE_OFFSET_BITS == 32 542 if (value > MAXOFF_T) 543 return (ENOSPACE); 544 #endif 545 /* 546 * Don't bother checking the tsize value we specified in a write 547 * request is echoed back in the OACK. 548 */ 549 if (tsize == 0) 550 tsize = value; 551 return (-1); 552 } 553 554 /* 555 * Add TFTP options to a request packet. 556 */ 557 static int 558 add_options(char *obuf, char *obufend) 559 { 560 int i; 561 char *cp, *ostr; 562 563 cp = obuf; 564 for (i = 0; options[i].opt_name != NULL; i++) { 565 ostr = options[i].opt_str(); 566 if (ostr != NULL) { 567 cp += strlcpy(cp, options[i].opt_name, obufend - cp) 568 + 1; 569 if (cp > obufend) 570 return (-1); 571 572 cp += strlcpy(cp, ostr, obufend - cp) + 1; 573 if (cp > obufend) 574 return (-1); 575 } 576 } 577 return (cp - obuf); 578 } 579 580 /* 581 * Process OACK packet sent by server in response to options in the request 582 * packet. Returns -1 on success or an error code on failure. 583 */ 584 static int 585 process_oack(tftpbuf *oackbuf, int n) 586 { 587 char *cp, *oackend, *optname, *optval; 588 struct tftphdr *oackp; 589 int i, errcode; 590 591 oackp = &oackbuf->tb_hdr; 592 cp = (char *)&oackp->th_stuff; 593 oackend = (char *)oackbuf + n; 594 595 while (cp < oackend) { 596 optname = cp; 597 if ((optval = next_field(optname, oackend)) == NULL) 598 return (EOPTNEG); 599 if ((cp = next_field(optval, oackend)) == NULL) 600 return (EOPTNEG); 601 for (i = 0; options[i].opt_name != NULL; i++) { 602 if (strcasecmp(optname, options[i].opt_name) == 0) 603 break; 604 } 605 if (options[i].opt_name == NULL) 606 return (EOPTNEG); 607 errcode = options[i].opt_handler(optval); 608 if (errcode >= 0) 609 return (errcode); 610 } 611 return (-1); 612 } 613 614 /* 615 * Send a nak packet (error message). 616 * Error code passed in is one of the 617 * standard TFTP codes, or a UNIX errno 618 * offset by 100. 619 */ 620 static void 621 nak(int error) 622 { 623 struct tftphdr *tp; 624 int length; 625 struct errmsg *pe; 626 627 tp = &ackbuf.tb_hdr; 628 tp->th_opcode = htons((ushort_t)ERROR); 629 tp->th_code = htons((ushort_t)error); 630 for (pe = errmsgs; pe->e_code >= 0; pe++) 631 if (pe->e_code == error) 632 break; 633 if (pe->e_code < 0) { 634 pe->e_msg = strerror(error - 100); 635 tp->th_code = EUNDEF; 636 } 637 (void) strlcpy(tp->th_msg, pe->e_msg, 638 sizeof (ackbuf) - sizeof (struct tftphdr)); 639 length = strlen(pe->e_msg) + 4; 640 if (trace) 641 tpacket("sent", tp, length); 642 if (sendto(f, ackbuf.tb_data, length, 0, 643 (struct sockaddr *)&sin6, sizeof (sin6)) != length) 644 perror("nak"); 645 } 646 647 static void 648 tpacket(char *s, struct tftphdr *tp, int n) 649 { 650 static char *opcodes[] = { 651 "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" 652 }; 653 char *cp, *file, *mode; 654 ushort_t op = ntohs(tp->th_opcode); 655 char *tpend; 656 657 if (op < RRQ || op > OACK) 658 (void) printf("%s opcode=%x ", s, op); 659 else 660 (void) printf("%s %s ", s, opcodes[op]); 661 662 switch (op) { 663 case RRQ: 664 case WRQ: 665 tpend = (char *)tp + n; 666 n -= sizeof (tp->th_opcode); 667 file = (char *)&tp->th_stuff; 668 if ((mode = next_field(file, tpend)) == NULL) { 669 (void) printf("<file=%.*s>\n", n, file); 670 break; 671 } 672 n -= mode - file; 673 if ((cp = next_field(mode, tpend)) == NULL) { 674 (void) printf("<file=%s, mode=%.*s>\n", file, n, mode); 675 break; 676 } 677 (void) printf("<file=%s, mode=%s", file, mode); 678 n -= cp - mode; 679 if (n > 0) { 680 (void) printf(", options: "); 681 print_options(stdout, cp, n); 682 } 683 (void) puts(">"); 684 break; 685 686 case DATA: 687 (void) printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), 688 n - sizeof (tp->th_opcode) - sizeof (tp->th_block)); 689 break; 690 691 case ACK: 692 (void) printf("<block=%d>\n", ntohs(tp->th_block)); 693 break; 694 695 case OACK: 696 (void) printf("<options: "); 697 print_options(stdout, (char *)&tp->th_stuff, 698 n - sizeof (tp->th_opcode)); 699 (void) puts(">"); 700 break; 701 702 case ERROR: 703 (void) printf("<code=%d", ntohs(tp->th_code)); 704 n = n - sizeof (tp->th_opcode) - sizeof (tp->th_code); 705 if (n > 0) 706 (void) printf(", msg=%.*s", n, tp->th_msg); 707 (void) puts(">"); 708 break; 709 } 710 } 711 712 static hrtime_t tstart, tstop; 713 714 static void 715 startclock(void) 716 { 717 tstart = gethrtime(); 718 } 719 720 static void 721 stopclock(void) 722 { 723 tstop = gethrtime(); 724 } 725 726 static void 727 printstats(char *direction, off_t amount) 728 { 729 hrtime_t delta, tenths; 730 731 delta = tstop - tstart; 732 tenths = delta / (NANOSEC / 10); 733 (void) printf("%s " OFF_T_FMT " bytes in %" PRId64 ".%" PRId64 734 " seconds", direction, amount, tenths / 10, tenths % 10); 735 if (verbose) 736 (void) printf(" [%" PRId64 " bits/sec]\n", 737 ((hrtime_t)amount * 8 * NANOSEC) / delta); 738 else 739 (void) putchar('\n'); 740 } 741