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