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