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