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 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 /* 42 * TFTP User Program -- Protocol Machines 43 */ 44 #include <sys/types.h> 45 #include <sys/socket.h> 46 #include <sys/time.h> 47 #include <sys/stat.h> 48 49 #include <signal.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <errno.h> 54 #include <string.h> 55 #include <stddef.h> 56 #include <inttypes.h> 57 58 #include "tftpcommon.h" 59 #include "tftpprivate.h" 60 61 static char *blksize_str(void); 62 static char *timeout_str(void); 63 static char *tsize_str(void); 64 static int blksize_handler(char *); 65 static int timeout_handler(char *); 66 static int tsize_handler(char *); 67 static int add_options(char *, char *); 68 static int process_oack(tftpbuf *, int); 69 static void nak(int); 70 static void startclock(void); 71 static void stopclock(void); 72 static void printstats(char *, off_t); 73 static int makerequest(int, char *, struct tftphdr *, char *); 74 static void tpacket(char *, struct tftphdr *, int); 75 76 static struct options { 77 char *opt_name; 78 char *(*opt_str)(void); 79 int (*opt_handler)(char *); 80 } options[] = { 81 { "blksize", blksize_str, blksize_handler }, 82 { "timeout", timeout_str, timeout_handler }, 83 { "tsize", tsize_str, tsize_handler }, 84 { NULL } 85 }; 86 87 static char optbuf[MAX_OPTVAL_LEN]; 88 static boolean_t tsize_set; 89 90 static tftpbuf ackbuf; 91 static int timeout; 92 static off_t tsize; 93 static jmp_buf timeoutbuf; 94 95 int blocksize = SEGSIZE; /* Number of data bytes in a DATA packet */ 96 97 /*ARGSUSED*/ 98 static void 99 timer(int signum) 100 { 101 timeout += rexmtval; 102 if (timeout >= maxtimeout) { 103 (void) fputs("Transfer timed out.\n", stderr); 104 longjmp(toplevel, -1); 105 } 106 (void) signal(SIGALRM, timer); 107 longjmp(timeoutbuf, 1); 108 } 109 110 /* 111 * Send the requested file. 112 */ 113 void 114 tftp_sendfile(int fd, char *name, char *mode) 115 { 116 struct tftphdr *ap; /* data and ack packets */ 117 struct tftphdr *dp; 118 int count = 0, size, n; 119 ushort_t block = 0; 120 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 ushort_t block = 1; 246 int n, size; 247 unsigned long amount = 0; 248 struct sockaddr_in6 from; 249 socklen_t fromlen; 250 boolean_t firsttrip = B_TRUE; 251 FILE *file; 252 int convert; /* true if converting crlf -> lf */ 253 int errcode; 254 255 startclock(); 256 dp = w_init(); 257 ap = &ackbuf.tb_hdr; 258 file = fdopen(fd, "w"); 259 convert = (strcmp(mode, "netascii") == 0); 260 261 tsize_set = (tsize_opt != 0); 262 if (tsize_set) 263 tsize = 0; 264 265 if ((size = makerequest(RRQ, name, ap, mode)) == -1) { 266 (void) fprintf(stderr, 267 "tftp: Error: Read request packet too big\n"); 268 (void) fclose(file); 269 return; 270 } 271 272 do { 273 (void) signal(SIGALRM, timer); 274 if (firsttrip) { 275 firsttrip = B_FALSE; 276 } else { 277 ap->th_opcode = htons((ushort_t)ACK); 278 ap->th_block = htons((ushort_t)(block)); 279 size = 4; 280 block++; 281 } 282 283 send_oack_ack: 284 timeout = 0; 285 (void) setjmp(timeoutbuf); 286 send_ack: 287 if (trace) 288 tpacket("sent", ap, size); 289 if (sendto(f, ackbuf.tb_data, size, 0, (struct sockaddr *)&sin6, 290 sizeof (sin6)) != size) { 291 (void) alarm(0); 292 perror("tftp: sendto"); 293 goto abort; 294 } 295 if (write_behind(file, convert) < 0) { 296 nak(errno + 100); 297 goto abort; 298 } 299 (void) alarm(rexmtval); 300 for (; ; ) { 301 (void) sigrelse(SIGALRM); 302 do { 303 fromlen = (socklen_t)sizeof (from); 304 n = recvfrom(f, dp, blocksize + 4, 0, 305 (struct sockaddr *)&from, &fromlen); 306 if (n < 0) { 307 perror("tftp: recvfrom"); 308 goto abort; 309 } 310 } while (n < offsetof(struct tftphdr, th_data)); 311 (void) sighold(SIGALRM); 312 sin6.sin6_port = from.sin6_port; /* added */ 313 if (trace) 314 tpacket("received", dp, n); 315 /* should verify client address */ 316 dp->th_opcode = ntohs(dp->th_opcode); 317 if (dp->th_opcode == ERROR) { 318 dp->th_code = ntohs(dp->th_code); 319 (void) fprintf(stderr, "Error code %d", 320 dp->th_code); 321 if (n > offsetof(struct tftphdr, th_data)) 322 (void) fprintf(stderr, ": %.*s", n - 323 offsetof(struct tftphdr, th_data), 324 dp->th_msg); 325 (void) fputc('\n', stderr); 326 goto abort; 327 } 328 if ((block == 1) && (dp->th_opcode == OACK)) { 329 errcode = process_oack((tftpbuf *)dp, n); 330 if (errcode >= 0) { 331 cancel_alarm(); 332 nak(errcode); 333 (void) fputs("Rejected OACK\n", 334 stderr); 335 (void) fclose(file); 336 return; 337 } 338 ap->th_opcode = htons((ushort_t)ACK); 339 ap->th_block = htons(0); 340 size = 4; 341 goto send_oack_ack; 342 } 343 if (dp->th_opcode == DATA) { 344 int j; 345 346 dp->th_block = ntohs(dp->th_block); 347 if (dp->th_block == block) { 348 break; /* have next packet */ 349 } 350 /* 351 * On an error, try to synchronize 352 * both sides. 353 */ 354 j = synchnet(f); 355 if (j < 0) { 356 perror("tftp: recvfrom"); 357 goto abort; 358 } 359 if ((j > 0) && trace) { 360 (void) printf("discarded %d packets\n", 361 j); 362 } 363 if (dp->th_block == (block-1)) { 364 goto send_ack; /* resend ack */ 365 } 366 } 367 } 368 cancel_alarm(); 369 size = writeit(file, &dp, n - 4, convert); 370 if (size < 0) { 371 nak(errno + 100); 372 goto abort; 373 } 374 amount += size; 375 } while (size == blocksize); 376 377 cancel_alarm(); 378 if (write_behind(file, convert) < 0) { /* flush last buffer */ 379 nak(errno + 100); 380 goto abort; 381 } 382 n = fclose(file); 383 file = NULL; 384 if (n == EOF) { 385 nak(errno + 100); 386 goto abort; 387 } 388 389 /* ok to ack, since user has seen err msg */ 390 ap->th_opcode = htons((ushort_t)ACK); 391 ap->th_block = htons((ushort_t)block); 392 if (trace) 393 tpacket("sent", ap, 4); 394 if (sendto(f, ackbuf.tb_data, 4, 0, 395 (struct sockaddr *)&sin6, sizeof (sin6)) != 4) 396 perror("tftp: sendto"); 397 398 abort: 399 cancel_alarm(); 400 if (file != NULL) 401 (void) fclose(file); 402 stopclock(); 403 if (amount > 0) 404 printstats("Received", amount); 405 } 406 407 static int 408 makerequest(int request, char *name, struct tftphdr *tp, char *mode) 409 { 410 char *cp, *cpend; 411 int len; 412 413 tp->th_opcode = htons((ushort_t)request); 414 cp = (char *)&tp->th_stuff; 415 416 /* Maximum size of a request packet is 512 bytes (RFC 2347) */ 417 cpend = (char *)tp + SEGSIZE; 418 419 len = strlcpy(cp, name, cpend - cp) + 1; 420 cp += len; 421 if (cp > cpend) 422 return (-1); 423 424 len = strlcpy(cp, mode, cpend - cp) + 1; 425 cp += len; 426 if (cp > cpend) 427 return (-1); 428 429 len = add_options(cp, cpend); 430 if (len == -1) 431 return (-1); 432 cp += len; 433 434 return (cp - (char *)tp); 435 } 436 437 /* 438 * Return the blksize option value string to include in the request packet. 439 */ 440 static char * 441 blksize_str(void) 442 { 443 blocksize = SEGSIZE; 444 if (blksize == 0) 445 return (NULL); 446 447 (void) snprintf(optbuf, sizeof (optbuf), "%d", blksize); 448 return (optbuf); 449 } 450 451 /* 452 * Return the timeout option value string to include in the request packet. 453 */ 454 static char * 455 timeout_str(void) 456 { 457 if (srexmtval == 0) 458 return (NULL); 459 460 (void) snprintf(optbuf, sizeof (optbuf), "%d", srexmtval); 461 return (optbuf); 462 } 463 464 /* 465 * Return the tsize option value string to include in the request packet. 466 */ 467 static char * 468 tsize_str(void) 469 { 470 if (tsize_set == B_FALSE) 471 return (NULL); 472 473 (void) snprintf(optbuf, sizeof (optbuf), OFF_T_FMT, tsize); 474 return (optbuf); 475 } 476 477 /* 478 * Validate and action the blksize option value string from the OACK packet. 479 * Returns -1 on success or an error code on failure. 480 */ 481 static int 482 blksize_handler(char *optstr) 483 { 484 char *endp; 485 int value; 486 487 /* Make sure the option was requested */ 488 if (blksize == 0) 489 return (EOPTNEG); 490 errno = 0; 491 value = (int)strtol(optstr, &endp, 10); 492 if (errno != 0 || value < MIN_BLKSIZE || value > blksize || 493 *endp != '\0') 494 return (EOPTNEG); 495 blocksize = value; 496 return (-1); 497 } 498 499 /* 500 * Validate and action the timeout option value string from the OACK packet. 501 * Returns -1 on success or an error code on failure. 502 */ 503 static int 504 timeout_handler(char *optstr) 505 { 506 char *endp; 507 int value; 508 509 /* Make sure the option was requested */ 510 if (srexmtval == 0) 511 return (EOPTNEG); 512 errno = 0; 513 value = (int)strtol(optstr, &endp, 10); 514 if (errno != 0 || value != srexmtval || *endp != '\0') 515 return (EOPTNEG); 516 /* 517 * Nothing to set, client and server retransmission intervals are 518 * set separately in the client. 519 */ 520 return (-1); 521 } 522 523 /* 524 * Validate and action the tsize option value string from the OACK packet. 525 * Returns -1 on success or an error code on failure. 526 */ 527 static int 528 tsize_handler(char *optstr) 529 { 530 char *endp; 531 longlong_t value; 532 533 /* Make sure the option was requested */ 534 if (tsize_set == B_FALSE) 535 return (EOPTNEG); 536 errno = 0; 537 value = strtoll(optstr, &endp, 10); 538 if (errno != 0 || value < 0 || *endp != '\0') 539 return (EOPTNEG); 540 #if _FILE_OFFSET_BITS == 32 541 if (value > MAXOFF_T) 542 return (ENOSPACE); 543 #endif 544 /* 545 * Don't bother checking the tsize value we specified in a write 546 * request is echoed back in the OACK. 547 */ 548 if (tsize == 0) 549 tsize = value; 550 return (-1); 551 } 552 553 /* 554 * Add TFTP options to a request packet. 555 */ 556 static int 557 add_options(char *obuf, char *obufend) 558 { 559 int i; 560 char *cp, *ostr; 561 562 cp = obuf; 563 for (i = 0; options[i].opt_name != NULL; i++) { 564 ostr = options[i].opt_str(); 565 if (ostr != NULL) { 566 cp += strlcpy(cp, options[i].opt_name, obufend - cp) 567 + 1; 568 if (cp > obufend) 569 return (-1); 570 571 cp += strlcpy(cp, ostr, obufend - cp) + 1; 572 if (cp > obufend) 573 return (-1); 574 } 575 } 576 return (cp - obuf); 577 } 578 579 /* 580 * Process OACK packet sent by server in response to options in the request 581 * packet. Returns -1 on success or an error code on failure. 582 */ 583 static int 584 process_oack(tftpbuf *oackbuf, int n) 585 { 586 char *cp, *oackend, *optname, *optval; 587 struct tftphdr *oackp; 588 int i, errcode; 589 590 oackp = &oackbuf->tb_hdr; 591 cp = (char *)&oackp->th_stuff; 592 oackend = (char *)oackbuf + n; 593 594 while (cp < oackend) { 595 optname = cp; 596 if ((optval = next_field(optname, oackend)) == NULL) 597 return (EOPTNEG); 598 if ((cp = next_field(optval, oackend)) == NULL) 599 return (EOPTNEG); 600 for (i = 0; options[i].opt_name != NULL; i++) { 601 if (strcasecmp(optname, options[i].opt_name) == 0) 602 break; 603 } 604 if (options[i].opt_name == NULL) 605 return (EOPTNEG); 606 errcode = options[i].opt_handler(optval); 607 if (errcode >= 0) 608 return (errcode); 609 } 610 return (-1); 611 } 612 613 /* 614 * Send a nak packet (error message). 615 * Error code passed in is one of the 616 * standard TFTP codes, or a UNIX errno 617 * offset by 100. 618 */ 619 static void 620 nak(int error) 621 { 622 struct tftphdr *tp; 623 int length; 624 struct errmsg *pe; 625 626 tp = &ackbuf.tb_hdr; 627 tp->th_opcode = htons((ushort_t)ERROR); 628 tp->th_code = htons((ushort_t)error); 629 for (pe = errmsgs; pe->e_code >= 0; pe++) 630 if (pe->e_code == error) 631 break; 632 if (pe->e_code < 0) { 633 pe->e_msg = strerror(error - 100); 634 tp->th_code = EUNDEF; 635 } 636 (void) strlcpy(tp->th_msg, pe->e_msg, 637 sizeof (ackbuf) - sizeof (struct tftphdr)); 638 length = strlen(pe->e_msg) + 4; 639 if (trace) 640 tpacket("sent", tp, length); 641 if (sendto(f, ackbuf.tb_data, length, 0, 642 (struct sockaddr *)&sin6, sizeof (sin6)) != length) 643 perror("nak"); 644 } 645 646 static void 647 tpacket(char *s, struct tftphdr *tp, int n) 648 { 649 static char *opcodes[] = \ 650 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; 651 char *cp, *file, *mode; 652 ushort_t op = ntohs(tp->th_opcode); 653 char *tpend; 654 655 if (op < RRQ || op > OACK) 656 (void) printf("%s opcode=%x ", s, op); 657 else 658 (void) printf("%s %s ", s, opcodes[op]); 659 660 switch (op) { 661 case RRQ: 662 case WRQ: 663 tpend = (char *)tp + n; 664 n -= sizeof (tp->th_opcode); 665 file = (char *)&tp->th_stuff; 666 if ((mode = next_field(file, tpend)) == NULL) { 667 (void) printf("<file=%.*s>\n", n, file); 668 break; 669 } 670 n -= mode - file; 671 if ((cp = next_field(mode, tpend)) == NULL) { 672 (void) printf("<file=%s, mode=%.*s>\n", file, n, mode); 673 break; 674 } 675 (void) printf("<file=%s, mode=%s", file, mode); 676 n -= cp - mode; 677 if (n > 0) { 678 (void) printf(", options: "); 679 print_options(stdout, cp, n); 680 } 681 (void) puts(">"); 682 break; 683 684 case DATA: 685 (void) printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), 686 n - sizeof (tp->th_opcode) - sizeof (tp->th_block)); 687 break; 688 689 case ACK: 690 (void) printf("<block=%d>\n", ntohs(tp->th_block)); 691 break; 692 693 case OACK: 694 (void) printf("<options: "); 695 print_options(stdout, (char *)&tp->th_stuff, 696 n - sizeof (tp->th_opcode)); 697 (void) puts(">"); 698 break; 699 700 case ERROR: 701 (void) printf("<code=%d", ntohs(tp->th_code)); 702 n = n - sizeof (tp->th_opcode) - sizeof (tp->th_code); 703 if (n > 0) 704 (void) printf(", msg=%.*s", n, tp->th_msg); 705 (void) puts(">"); 706 break; 707 } 708 } 709 710 static hrtime_t tstart, tstop; 711 712 static void 713 startclock(void) 714 { 715 tstart = gethrtime(); 716 } 717 718 static void 719 stopclock(void) 720 { 721 tstop = gethrtime(); 722 } 723 724 static void 725 printstats(char *direction, off_t amount) 726 { 727 hrtime_t delta, tenths; 728 729 delta = tstop - tstart; 730 tenths = delta / (NANOSEC / 10); 731 (void) printf("%s " OFF_T_FMT " bytes in %" PRId64 ".%" PRId64 732 " seconds", direction, amount, tenths / 10, tenths % 10); 733 if (verbose) 734 (void) printf(" [%" PRId64 " bits/sec]\n", 735 ((hrtime_t)amount * 8 * NANOSEC) / delta); 736 else 737 (void) putchar('\n'); 738 } 739