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