1 /* $NetBSD: tftp.c,v 1.18 2003/08/07 11:16:14 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 36 #else 37 __RCSID("$NetBSD: tftp.c,v 1.18 2003/08/07 11:16:14 agc Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 42 43 /* 44 * TFTP User Program -- Protocol Machines 45 */ 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/stat.h> 50 #include <sys/time.h> 51 52 #include <netinet/in.h> 53 54 #include <arpa/tftp.h> 55 56 #include <err.h> 57 #include <errno.h> 58 #include <setjmp.h> 59 #include <signal.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <netdb.h> 65 66 #include "extern.h" 67 #include "tftpsubs.h" 68 69 extern struct sockaddr_storage peeraddr; /* filled in by main */ 70 extern int f; /* the opened socket */ 71 extern int trace; 72 extern int verbose; 73 extern int def_rexmtval; 74 extern int rexmtval; 75 extern int maxtimeout; 76 extern int tsize; 77 extern int tout; 78 extern int def_blksize; 79 extern int blksize; 80 81 char ackbuf[PKTSIZE]; 82 int timeout; 83 jmp_buf toplevel; 84 jmp_buf timeoutbuf; 85 86 static void nak __P((int, struct sockaddr *)); 87 static int makerequest __P((int, const char *, struct tftphdr *, const char *, off_t)); 88 static void printstats __P((const char *, unsigned long)); 89 static void startclock __P((void)); 90 static void stopclock __P((void)); 91 static void timer __P((int)); 92 static void tpacket __P((const char *, struct tftphdr *, int)); 93 static int cmpport __P((struct sockaddr *, struct sockaddr *)); 94 95 static void get_options(struct tftphdr *, int); 96 97 static void 98 get_options(struct tftphdr *ap, int size) 99 { 100 unsigned long val; 101 char *opt, *endp, *nextopt, *valp; 102 int l; 103 104 size -= 2; /* skip over opcode */ 105 opt = ap->th_stuff; 106 endp = opt + size - 1; 107 *endp = '\0'; 108 109 while (opt < endp) { 110 l = strlen(opt) + 1; 111 valp = opt + l; 112 if (valp < endp) { 113 val = strtoul(valp, NULL, 10); 114 l = strlen(valp) + 1; 115 nextopt = valp + l; 116 if (val == ULONG_MAX && errno == ERANGE) { 117 /* Report illegal value */ 118 opt = nextopt; 119 continue; 120 } 121 } else { 122 /* Badly formed OACK */ 123 break; 124 } 125 if (strcmp(opt, "tsize") == 0) { 126 /* cool, but we'll ignore it */ 127 } else if (strcmp(opt, "timeout") == 0) { 128 if (val >= 1 && val <= 255) { 129 rexmtval = val; 130 } else { 131 /* Report error? */ 132 } 133 } else if (strcmp(opt, "blksize") == 0) { 134 if (val >= 8 && val <= MAXSEGSIZE) { 135 blksize = val; 136 } else { 137 /* Report error? */ 138 } 139 } else { 140 /* unknown option */ 141 } 142 opt = nextopt; 143 } 144 } 145 146 /* 147 * Send the requested file. 148 */ 149 void 150 sendfile(fd, name, mode) 151 int fd; 152 char *name; 153 char *mode; 154 { 155 struct tftphdr *ap; /* data and ack packets */ 156 struct tftphdr *dp; 157 int n; 158 volatile unsigned int block; 159 volatile int size, convert; 160 volatile unsigned long amount; 161 struct sockaddr_storage from; 162 struct stat sbuf; 163 off_t filesize=0; 164 int fromlen; 165 FILE *file; 166 struct sockaddr_storage peer; 167 struct sockaddr_storage serv; /* valid server port number */ 168 169 startclock(); /* start stat's clock */ 170 dp = r_init(); /* reset fillbuf/read-ahead code */ 171 ap = (struct tftphdr *)ackbuf; 172 if (tsize) { 173 if (fstat(fd, &sbuf) == 0) { 174 filesize = sbuf.st_size; 175 } else { 176 filesize = -1ULL; 177 } 178 } 179 file = fdopen(fd, "r"); 180 convert = !strcmp(mode, "netascii"); 181 block = 0; 182 amount = 0; 183 memcpy(&peer, &peeraddr, peeraddr.ss_len); 184 memset(&serv, 0, sizeof(serv)); 185 186 signal(SIGALRM, timer); 187 do { 188 if (block == 0) 189 size = makerequest(WRQ, name, dp, mode, filesize) - 4; 190 else { 191 /* size = read(fd, dp->th_data, SEGSIZE); */ 192 size = readit(file, &dp, blksize, convert); 193 if (size < 0) { 194 nak(errno + 100, (struct sockaddr *)&peer); 195 break; 196 } 197 dp->th_opcode = htons((u_short)DATA); 198 dp->th_block = htons((u_short)block); 199 } 200 timeout = 0; 201 (void) setjmp(timeoutbuf); 202 send_data: 203 if (trace) 204 tpacket("sent", dp, size + 4); 205 n = sendto(f, dp, size + 4, 0, 206 (struct sockaddr *)&peer, peer.ss_len); 207 if (n != size + 4) { 208 warn("sendto"); 209 goto abort; 210 } 211 if (block) 212 read_ahead(file, blksize, convert); 213 for ( ; ; ) { 214 alarm(rexmtval); 215 do { 216 fromlen = sizeof(from); 217 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 218 (struct sockaddr *)&from, &fromlen); 219 } while (n <= 0); 220 alarm(0); 221 if (n < 0) { 222 warn("recvfrom"); 223 goto abort; 224 } 225 if (!serv.ss_family) 226 serv = from; 227 else if (!cmpport((struct sockaddr *)&serv, 228 (struct sockaddr *)&from)) { 229 warn("server port mismatch"); 230 goto abort; 231 } 232 peer = from; 233 if (trace) 234 tpacket("received", ap, n); 235 /* should verify packet came from server */ 236 ap->th_opcode = ntohs(ap->th_opcode); 237 ap->th_block = ntohs(ap->th_block); 238 if (ap->th_opcode == ERROR) { 239 printf("Error code %d: %s\n", ap->th_code, 240 ap->th_msg); 241 goto abort; 242 } 243 if (ap->th_opcode == ACK) { 244 int j; 245 246 if (ap->th_block == 0) { 247 /* 248 * If the extended options are enabled, 249 * the server just refused 'em all. 250 * The only one that _really_ 251 * matters is blksize, but we'll 252 * clear timeout, too. 253 */ 254 blksize = def_blksize; 255 rexmtval = def_rexmtval; 256 } 257 if (ap->th_block == block) { 258 break; 259 } 260 /* On an error, try to synchronize 261 * both sides. 262 */ 263 j = synchnet(f, blksize+4); 264 if (j && trace) { 265 printf("discarded %d packets\n", 266 j); 267 } 268 if (ap->th_block == (block-1)) { 269 goto send_data; 270 } 271 } 272 if (ap->th_opcode == OACK) { 273 if (block == 0) { 274 blksize = def_blksize; 275 rexmtval = def_rexmtval; 276 get_options(ap, n); 277 break; 278 } 279 } 280 } 281 if (block > 0) 282 amount += size; 283 block++; 284 } while (size == blksize || block == 1); 285 abort: 286 fclose(file); 287 stopclock(); 288 if (amount > 0) 289 printstats("Sent", amount); 290 } 291 292 /* 293 * Receive a file. 294 */ 295 void 296 recvfile(fd, name, mode) 297 int fd; 298 char *name; 299 char *mode; 300 { 301 struct tftphdr *ap; 302 struct tftphdr *dp; 303 int n, oack=0; 304 volatile unsigned int block; 305 volatile int size, firsttrip; 306 volatile unsigned long amount; 307 struct sockaddr_storage from; 308 int fromlen, readlen; 309 FILE *file; 310 volatile int convert; /* true if converting crlf -> lf */ 311 struct sockaddr_storage peer; 312 struct sockaddr_storage serv; /* valid server port number */ 313 314 startclock(); 315 dp = w_init(); 316 ap = (struct tftphdr *)ackbuf; 317 file = fdopen(fd, "w"); 318 convert = !strcmp(mode, "netascii"); 319 block = 1; 320 firsttrip = 1; 321 amount = 0; 322 memcpy(&peer, &peeraddr, peeraddr.ss_len); 323 memset(&serv, 0, sizeof(serv)); 324 325 signal(SIGALRM, timer); 326 do { 327 if (firsttrip) { 328 size = makerequest(RRQ, name, ap, mode, 0); 329 readlen = PKTSIZE; 330 firsttrip = 0; 331 } else { 332 ap->th_opcode = htons((u_short)ACK); 333 ap->th_block = htons((u_short)(block)); 334 readlen = blksize+4; 335 size = 4; 336 block++; 337 } 338 timeout = 0; 339 (void) setjmp(timeoutbuf); 340 send_ack: 341 if (trace) 342 tpacket("sent", ap, size); 343 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 344 peer.ss_len) != size) { 345 alarm(0); 346 warn("sendto"); 347 goto abort; 348 } 349 write_behind(file, convert); 350 for ( ; ; ) { 351 alarm(rexmtval); 352 do { 353 fromlen = sizeof(from); 354 n = recvfrom(f, dp, readlen, 0, 355 (struct sockaddr *)&from, &fromlen); 356 } while (n <= 0); 357 alarm(0); 358 if (n < 0) { 359 warn("recvfrom"); 360 goto abort; 361 } 362 if (!serv.ss_family) 363 serv = from; 364 else if (!cmpport((struct sockaddr *)&serv, 365 (struct sockaddr *)&from)) { 366 warn("server port mismatch"); 367 goto abort; 368 } 369 peer = from; 370 if (trace) 371 tpacket("received", dp, n); 372 /* should verify client address */ 373 dp->th_opcode = ntohs(dp->th_opcode); 374 dp->th_block = ntohs(dp->th_block); 375 if (dp->th_opcode == ERROR) { 376 printf("Error code %d: %s\n", dp->th_code, 377 dp->th_msg); 378 goto abort; 379 } 380 if (dp->th_opcode == DATA) { 381 int j; 382 383 if (dp->th_block == 1 && !oack) { 384 /* no OACK, revert to defaults */ 385 blksize = def_blksize; 386 rexmtval = def_rexmtval; 387 } 388 if (dp->th_block == block) { 389 break; /* have next packet */ 390 } 391 /* On an error, try to synchronize 392 * both sides. 393 */ 394 j = synchnet(f, blksize); 395 if (j && trace) { 396 printf("discarded %d packets\n", j); 397 } 398 if (dp->th_block == (block-1)) { 399 goto send_ack; /* resend ack */ 400 } 401 } 402 if (dp->th_opcode == OACK) { 403 if (block == 1) { 404 oack = 1; 405 blksize = def_blksize; 406 rexmtval = def_rexmtval; 407 get_options(dp, n); 408 ap->th_opcode = htons(ACK); 409 ap->th_block = 0; 410 readlen = blksize+4; 411 size = 4; 412 goto send_ack; 413 } 414 } 415 } 416 /* size = write(fd, dp->th_data, n - 4); */ 417 size = writeit(file, &dp, n - 4, convert); 418 if (size < 0) { 419 nak(errno + 100, (struct sockaddr *)&peer); 420 break; 421 } 422 amount += size; 423 } while (size == blksize || block == 1); 424 abort: /* ok to ack, since user */ 425 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 426 ap->th_block = htons((u_short)block); 427 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 428 peer.ss_len); 429 write_behind(file, convert); /* flush last buffer */ 430 fclose(file); 431 stopclock(); 432 if (amount > 0) 433 printstats("Received", amount); 434 } 435 436 static int 437 makerequest(request, name, tp, mode, filesize) 438 int request; 439 const char *name; 440 struct tftphdr *tp; 441 const char *mode; 442 off_t filesize; 443 { 444 char *cp; 445 446 tp->th_opcode = htons((u_short)request); 447 #ifndef __SVR4 448 cp = tp->th_stuff; 449 #else 450 cp = (void *)&tp->th_stuff; 451 #endif 452 strcpy(cp, name); 453 cp += strlen(name); 454 *cp++ = '\0'; 455 strcpy(cp, mode); 456 cp += strlen(mode); 457 *cp++ = '\0'; 458 if (tsize) { 459 strcpy(cp, "tsize"); 460 cp += strlen(cp); 461 *cp++ = '\0'; 462 sprintf(cp, "%lu", (unsigned long) filesize); 463 cp += strlen(cp); 464 *cp++ = '\0'; 465 } 466 if (tout) { 467 strcpy(cp, "timeout"); 468 cp += strlen(cp); 469 *cp++ = '\0'; 470 sprintf(cp, "%d", rexmtval); 471 cp += strlen(cp); 472 *cp++ = '\0'; 473 } 474 if (blksize != SEGSIZE) { 475 strcpy(cp, "blksize"); 476 cp += strlen(cp); 477 *cp++ = '\0'; 478 sprintf(cp, "%d", blksize); 479 cp += strlen(cp); 480 *cp++ = '\0'; 481 } 482 return (cp - (char *)tp); 483 } 484 485 const struct errmsg { 486 int e_code; 487 const char *e_msg; 488 } errmsgs[] = { 489 { EUNDEF, "Undefined error code" }, 490 { ENOTFOUND, "File not found" }, 491 { EACCESS, "Access violation" }, 492 { ENOSPACE, "Disk full or allocation exceeded" }, 493 { EBADOP, "Illegal TFTP operation" }, 494 { EBADID, "Unknown transfer ID" }, 495 { EEXISTS, "File already exists" }, 496 { ENOUSER, "No such user" }, 497 { EOPTNEG, "Option negotiation failed" }, 498 { -1, 0 } 499 }; 500 501 /* 502 * Send a nak packet (error message). 503 * Error code passed in is one of the 504 * standard TFTP codes, or a UNIX errno 505 * offset by 100. 506 */ 507 static void 508 nak(error, peer) 509 int error; 510 struct sockaddr *peer; 511 { 512 const struct errmsg *pe; 513 struct tftphdr *tp; 514 int length; 515 size_t msglen; 516 517 tp = (struct tftphdr *)ackbuf; 518 tp->th_opcode = htons((u_short)ERROR); 519 msglen = sizeof(ackbuf) - (&tp->th_msg[0] - ackbuf); 520 for (pe = errmsgs; pe->e_code >= 0; pe++) 521 if (pe->e_code == error) 522 break; 523 if (pe->e_code < 0) { 524 tp->th_code = EUNDEF; 525 strlcpy(tp->th_msg, strerror(error - 100), msglen); 526 } else { 527 tp->th_code = htons((u_short)error); 528 strlcpy(tp->th_msg, pe->e_msg, msglen); 529 } 530 length = strlen(tp->th_msg); 531 msglen = &tp->th_msg[length + 1] - ackbuf; 532 if (trace) 533 tpacket("sent", tp, (int)msglen); 534 if (sendto(f, ackbuf, msglen, 0, peer, peer->sa_len) != msglen) 535 warn("nak"); 536 } 537 538 static void 539 tpacket(s, tp, n) 540 const char *s; 541 struct tftphdr *tp; 542 int n; 543 { 544 static char *opcodes[] = 545 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; 546 char *cp, *file, *endp, *opt, *spc; 547 u_short op = ntohs(tp->th_opcode); 548 int i, o; 549 550 if (op < RRQ || op > OACK) 551 printf("%s opcode=%x ", s, op); 552 else 553 printf("%s %s ", s, opcodes[op]); 554 switch (op) { 555 556 case RRQ: 557 case WRQ: 558 n -= 2; 559 #ifndef __SVR4 560 cp = tp->th_stuff; 561 #else 562 cp = (void *) &tp->th_stuff; 563 #endif 564 endp = cp + n - 1; 565 if (*endp != '\0') { /* Shouldn't happen, but... */ 566 *endp = '\0'; 567 } 568 file = cp; 569 cp = strchr(cp, '\0') + 1; 570 printf("<file=%s, mode=%s", file, cp); 571 cp = strchr(cp, '\0') + 1; 572 o = 0; 573 while (cp < endp) { 574 i = strlen(cp) + 1; 575 if (o) { 576 printf(", %s=%s", opt, cp); 577 } else { 578 opt = cp; 579 } 580 o = (o+1) % 2; 581 cp += i; 582 } 583 printf(">\n"); 584 break; 585 586 case DATA: 587 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 588 break; 589 590 case ACK: 591 printf("<block=%d>\n", ntohs(tp->th_block)); 592 break; 593 594 case ERROR: 595 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 596 break; 597 598 case OACK: 599 o = 0; 600 n -= 2; 601 cp = tp->th_stuff; 602 endp = cp + n - 1; 603 if (*endp != '\0') { /* Shouldn't happen, but... */ 604 *endp = '\0'; 605 } 606 printf("<"); 607 spc = ""; 608 while (cp < endp) { 609 i = strlen(cp) + 1; 610 if (o) { 611 printf("%s%s=%s", spc, opt, cp); 612 spc = ", "; 613 } else { 614 opt = cp; 615 } 616 o = (o+1) % 2; 617 cp += i; 618 } 619 printf(">\n"); 620 break; 621 } 622 } 623 624 struct timeval tstart; 625 struct timeval tstop; 626 627 static void 628 startclock() 629 { 630 631 (void)gettimeofday(&tstart, NULL); 632 } 633 634 static void 635 stopclock() 636 { 637 638 (void)gettimeofday(&tstop, NULL); 639 } 640 641 static void 642 printstats(direction, amount) 643 const char *direction; 644 unsigned long amount; 645 { 646 double delta; 647 648 /* compute delta in 1/10's second units */ 649 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 650 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 651 delta = delta/10.; /* back to seconds */ 652 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 653 if (verbose) 654 printf(" [%.0f bits/sec]", (amount*8.)/delta); 655 putchar('\n'); 656 } 657 658 static void 659 timer(sig) 660 int sig; 661 { 662 663 timeout += rexmtval; 664 if (timeout >= maxtimeout) { 665 printf("Transfer timed out.\n"); 666 longjmp(toplevel, -1); 667 } 668 longjmp(timeoutbuf, 1); 669 } 670 671 static int 672 cmpport(sa, sb) 673 struct sockaddr *sa; 674 struct sockaddr *sb; 675 { 676 char a[NI_MAXSERV], b[NI_MAXSERV]; 677 678 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 679 return 0; 680 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 681 return 0; 682 if (strcmp(a, b) != 0) 683 return 0; 684 685 return 1; 686 } 687