1 /* $NetBSD: tftp.c,v 1.20 2004/10/10 22:15:34 he 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.20 2004/10/10 22:15:34 he 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 j, 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 if (ap->th_opcode == ERROR) { 238 printf("Error code %d: %s\n", ap->th_code, 239 ap->th_msg); 240 goto abort; 241 } 242 if (ap->th_opcode == ACK) { 243 ap->th_block = ntohs(ap->th_block); 244 245 if (ap->th_block == 0) { 246 /* 247 * If the extended options are enabled, 248 * the server just refused 'em all. 249 * The only one that _really_ 250 * matters is blksize, but we'll 251 * clear timeout, too. 252 */ 253 blksize = def_blksize; 254 rexmtval = def_rexmtval; 255 } 256 if (ap->th_block == block) { 257 break; 258 } 259 /* On an error, try to synchronize 260 * both sides. 261 */ 262 j = synchnet(f, blksize+4); 263 if (j && trace) { 264 printf("discarded %d packets\n", 265 j); 266 } 267 if (ap->th_block == (block-1)) { 268 goto send_data; 269 } 270 } 271 if (ap->th_opcode == OACK) { 272 if (block == 0) { 273 blksize = def_blksize; 274 rexmtval = def_rexmtval; 275 get_options(ap, n); 276 break; 277 } 278 } 279 } 280 if (block > 0) 281 amount += size; 282 block++; 283 } while (size == blksize || block == 1); 284 abort: 285 fclose(file); 286 stopclock(); 287 if (amount > 0) 288 printstats("Sent", amount); 289 } 290 291 /* 292 * Receive a file. 293 */ 294 void 295 recvfile(fd, name, mode) 296 int fd; 297 char *name; 298 char *mode; 299 { 300 struct tftphdr *ap; 301 struct tftphdr *dp; 302 int j, n, oack=0; 303 volatile unsigned int block; 304 volatile int size, firsttrip; 305 volatile unsigned long amount; 306 struct sockaddr_storage from; 307 int fromlen, readlen; 308 FILE *file; 309 volatile int convert; /* true if converting crlf -> lf */ 310 struct sockaddr_storage peer; 311 struct sockaddr_storage serv; /* valid server port number */ 312 313 startclock(); 314 dp = w_init(); 315 ap = (struct tftphdr *)ackbuf; 316 file = fdopen(fd, "w"); 317 convert = !strcmp(mode, "netascii"); 318 block = 1; 319 firsttrip = 1; 320 amount = 0; 321 memcpy(&peer, &peeraddr, peeraddr.ss_len); 322 memset(&serv, 0, sizeof(serv)); 323 324 signal(SIGALRM, timer); 325 do { 326 if (firsttrip) { 327 size = makerequest(RRQ, name, ap, mode, 0); 328 readlen = PKTSIZE; 329 firsttrip = 0; 330 } else { 331 ap->th_opcode = htons((u_short)ACK); 332 ap->th_block = htons((u_short)(block)); 333 readlen = blksize+4; 334 size = 4; 335 block++; 336 } 337 timeout = 0; 338 (void) setjmp(timeoutbuf); 339 send_ack: 340 if (trace) 341 tpacket("sent", ap, size); 342 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 343 peer.ss_len) != size) { 344 alarm(0); 345 warn("sendto"); 346 goto abort; 347 } 348 write_behind(file, convert); 349 for ( ; ; ) { 350 alarm(rexmtval); 351 do { 352 fromlen = sizeof(from); 353 n = recvfrom(f, dp, readlen, 0, 354 (struct sockaddr *)&from, &fromlen); 355 } while (n <= 0); 356 alarm(0); 357 if (n < 0) { 358 warn("recvfrom"); 359 goto abort; 360 } 361 if (!serv.ss_family) 362 serv = from; 363 else if (!cmpport((struct sockaddr *)&serv, 364 (struct sockaddr *)&from)) { 365 warn("server port mismatch"); 366 goto abort; 367 } 368 peer = from; 369 if (trace) 370 tpacket("received", dp, n); 371 /* should verify client address */ 372 dp->th_opcode = ntohs(dp->th_opcode); 373 if (dp->th_opcode == ERROR) { 374 printf("Error code %d: %s\n", dp->th_code, 375 dp->th_msg); 376 goto abort; 377 } 378 if (dp->th_opcode == DATA) { 379 dp->th_block = ntohs(dp->th_block); 380 381 if (dp->th_block == 1 && !oack) { 382 /* no OACK, revert to defaults */ 383 blksize = def_blksize; 384 rexmtval = def_rexmtval; 385 } 386 if (dp->th_block == block) { 387 break; /* have next packet */ 388 } 389 /* On an error, try to synchronize 390 * both sides. 391 */ 392 j = synchnet(f, blksize); 393 if (j && trace) { 394 printf("discarded %d packets\n", j); 395 } 396 if (dp->th_block == (block-1)) { 397 goto send_ack; /* resend ack */ 398 } 399 } 400 if (dp->th_opcode == OACK) { 401 if (block == 1) { 402 oack = 1; 403 blksize = def_blksize; 404 rexmtval = def_rexmtval; 405 get_options(dp, n); 406 ap->th_opcode = htons(ACK); 407 ap->th_block = 0; 408 readlen = blksize+4; 409 size = 4; 410 goto send_ack; 411 } 412 } 413 } 414 /* size = write(fd, dp->th_data, n - 4); */ 415 size = writeit(file, &dp, n - 4, convert); 416 if (size < 0) { 417 nak(errno + 100, (struct sockaddr *)&peer); 418 break; 419 } 420 amount += size; 421 } while (size == blksize); 422 abort: /* ok to ack, since user */ 423 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 424 ap->th_block = htons((u_short)block); 425 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 426 peer.ss_len); 427 write_behind(file, convert); /* flush last buffer */ 428 fclose(file); 429 stopclock(); 430 if (amount > 0) 431 printstats("Received", amount); 432 } 433 434 static int 435 makerequest(request, name, tp, mode, filesize) 436 int request; 437 const char *name; 438 struct tftphdr *tp; 439 const char *mode; 440 off_t filesize; 441 { 442 char *cp; 443 444 tp->th_opcode = htons((u_short)request); 445 #ifndef __SVR4 446 cp = tp->th_stuff; 447 #else 448 cp = (void *)&tp->th_stuff; 449 #endif 450 strcpy(cp, name); 451 cp += strlen(name); 452 *cp++ = '\0'; 453 strcpy(cp, mode); 454 cp += strlen(mode); 455 *cp++ = '\0'; 456 if (tsize) { 457 strcpy(cp, "tsize"); 458 cp += strlen(cp); 459 *cp++ = '\0'; 460 sprintf(cp, "%lu", (unsigned long) filesize); 461 cp += strlen(cp); 462 *cp++ = '\0'; 463 } 464 if (tout) { 465 strcpy(cp, "timeout"); 466 cp += strlen(cp); 467 *cp++ = '\0'; 468 sprintf(cp, "%d", rexmtval); 469 cp += strlen(cp); 470 *cp++ = '\0'; 471 } 472 if (blksize != SEGSIZE) { 473 strcpy(cp, "blksize"); 474 cp += strlen(cp); 475 *cp++ = '\0'; 476 sprintf(cp, "%d", blksize); 477 cp += strlen(cp); 478 *cp++ = '\0'; 479 } 480 return (cp - (char *)tp); 481 } 482 483 const struct errmsg { 484 int e_code; 485 const char *e_msg; 486 } errmsgs[] = { 487 { EUNDEF, "Undefined error code" }, 488 { ENOTFOUND, "File not found" }, 489 { EACCESS, "Access violation" }, 490 { ENOSPACE, "Disk full or allocation exceeded" }, 491 { EBADOP, "Illegal TFTP operation" }, 492 { EBADID, "Unknown transfer ID" }, 493 { EEXISTS, "File already exists" }, 494 { ENOUSER, "No such user" }, 495 { EOPTNEG, "Option negotiation failed" }, 496 { -1, 0 } 497 }; 498 499 /* 500 * Send a nak packet (error message). 501 * Error code passed in is one of the 502 * standard TFTP codes, or a UNIX errno 503 * offset by 100. 504 */ 505 static void 506 nak(error, peer) 507 int error; 508 struct sockaddr *peer; 509 { 510 const struct errmsg *pe; 511 struct tftphdr *tp; 512 int length; 513 size_t msglen; 514 515 tp = (struct tftphdr *)ackbuf; 516 tp->th_opcode = htons((u_short)ERROR); 517 msglen = sizeof(ackbuf) - (&tp->th_msg[0] - ackbuf); 518 for (pe = errmsgs; pe->e_code >= 0; pe++) 519 if (pe->e_code == error) 520 break; 521 if (pe->e_code < 0) { 522 tp->th_code = EUNDEF; 523 strlcpy(tp->th_msg, strerror(error - 100), msglen); 524 } else { 525 tp->th_code = htons((u_short)error); 526 strlcpy(tp->th_msg, pe->e_msg, msglen); 527 } 528 length = strlen(tp->th_msg); 529 msglen = &tp->th_msg[length + 1] - ackbuf; 530 if (trace) 531 tpacket("sent", tp, (int)msglen); 532 if (sendto(f, ackbuf, msglen, 0, peer, peer->sa_len) != msglen) 533 warn("nak"); 534 } 535 536 static void 537 tpacket(s, tp, n) 538 const char *s; 539 struct tftphdr *tp; 540 int n; 541 { 542 static char *opcodes[] = 543 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; 544 char *cp, *file, *endp, *opt, *spc; 545 u_short op = ntohs(tp->th_opcode); 546 int i, o; 547 548 if (op < RRQ || op > OACK) 549 printf("%s opcode=%x ", s, op); 550 else 551 printf("%s %s ", s, opcodes[op]); 552 switch (op) { 553 554 case RRQ: 555 case WRQ: 556 n -= 2; 557 #ifndef __SVR4 558 cp = tp->th_stuff; 559 #else 560 cp = (void *) &tp->th_stuff; 561 #endif 562 endp = cp + n - 1; 563 if (*endp != '\0') { /* Shouldn't happen, but... */ 564 *endp = '\0'; 565 } 566 file = cp; 567 cp = strchr(cp, '\0') + 1; 568 printf("<file=%s, mode=%s", file, cp); 569 cp = strchr(cp, '\0') + 1; 570 o = 0; 571 while (cp < endp) { 572 i = strlen(cp) + 1; 573 if (o) { 574 printf(", %s=%s", opt, cp); 575 } else { 576 opt = cp; 577 } 578 o = (o+1) % 2; 579 cp += i; 580 } 581 printf(">\n"); 582 break; 583 584 case DATA: 585 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 586 break; 587 588 case ACK: 589 printf("<block=%d>\n", ntohs(tp->th_block)); 590 break; 591 592 case ERROR: 593 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 594 break; 595 596 case OACK: 597 o = 0; 598 n -= 2; 599 cp = tp->th_stuff; 600 endp = cp + n - 1; 601 if (*endp != '\0') { /* Shouldn't happen, but... */ 602 *endp = '\0'; 603 } 604 printf("<"); 605 spc = ""; 606 while (cp < endp) { 607 i = strlen(cp) + 1; 608 if (o) { 609 printf("%s%s=%s", spc, opt, cp); 610 spc = ", "; 611 } else { 612 opt = cp; 613 } 614 o = (o+1) % 2; 615 cp += i; 616 } 617 printf(">\n"); 618 break; 619 } 620 } 621 622 struct timeval tstart; 623 struct timeval tstop; 624 625 static void 626 startclock() 627 { 628 629 (void)gettimeofday(&tstart, NULL); 630 } 631 632 static void 633 stopclock() 634 { 635 636 (void)gettimeofday(&tstop, NULL); 637 } 638 639 static void 640 printstats(direction, amount) 641 const char *direction; 642 unsigned long amount; 643 { 644 double delta; 645 646 /* compute delta in 1/10's second units */ 647 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 648 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 649 delta = delta/10.; /* back to seconds */ 650 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 651 if (verbose) 652 printf(" [%.0f bits/sec]", (amount*8.)/delta); 653 putchar('\n'); 654 } 655 656 static void 657 timer(sig) 658 int sig; 659 { 660 661 timeout += rexmtval; 662 if (timeout >= maxtimeout) { 663 printf("Transfer timed out.\n"); 664 longjmp(toplevel, -1); 665 } 666 longjmp(timeoutbuf, 1); 667 } 668 669 static int 670 cmpport(sa, sb) 671 struct sockaddr *sa; 672 struct sockaddr *sb; 673 { 674 char a[NI_MAXSERV], b[NI_MAXSERV]; 675 676 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 677 return 0; 678 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 679 return 0; 680 if (strcmp(a, b) != 0) 681 return 0; 682 683 return 1; 684 } 685