1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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 /* 33 * Trivial file transfer protocol server. 34 * 35 * This version includes many modifications by Jim Guyton 36 * <guyton@rand-unix>. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/ioctl.h> 41 #include <sys/socket.h> 42 #include <sys/stat.h> 43 #include <sys/time.h> 44 45 #include <netinet/in.h> 46 #include <arpa/tftp.h> 47 48 #include <ctype.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <netdb.h> 52 #include <pwd.h> 53 #include <stdint.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <syslog.h> 58 #include <time.h> 59 #include <unistd.h> 60 61 #include "tftp-file.h" 62 #include "tftp-io.h" 63 #include "tftp-utils.h" 64 #include "tftp-transfer.h" 65 #include "tftp-options.h" 66 67 #ifdef LIBWRAP 68 #include <tcpd.h> 69 #endif 70 71 static void tftp_wrq(int peer, char *, ssize_t); 72 static void tftp_rrq(int peer, char *, ssize_t); 73 74 /* 75 * Null-terminated directory prefix list for absolute pathname requests and 76 * search list for relative pathname requests. 77 * 78 * MAXDIRS should be at least as large as the number of arguments that 79 * inetd allows (currently 20). 80 */ 81 #define MAXDIRS 20 82 static struct dirlist { 83 const char *name; 84 int len; 85 } dirs[MAXDIRS+1]; 86 static int suppress_naks; 87 static int logging; 88 static int ipchroot; 89 static int check_woth = 1; 90 static int create_new = 0; 91 static const char *newfile_format = "%Y%m%d"; 92 static int increase_name = 0; 93 static mode_t mask = S_IWGRP | S_IWOTH; 94 95 struct formats; 96 static void tftp_recvfile(int peer, const char *mode); 97 static void tftp_xmitfile(int peer, const char *mode); 98 static int validate_access(int peer, char **, int); 99 static char peername[NI_MAXHOST]; 100 101 static FILE *file; 102 103 static struct formats { 104 const char *f_mode; 105 int f_convert; 106 } formats[] = { 107 { "netascii", 1 }, 108 { "octet", 0 }, 109 { NULL, 0 } 110 }; 111 112 int 113 main(int argc, char *argv[]) 114 { 115 struct tftphdr *tp; 116 int peer; 117 socklen_t peerlen, len; 118 ssize_t n; 119 int ch; 120 char *chroot_dir = NULL; 121 struct passwd *nobody; 122 const char *chuser = "nobody"; 123 char recvbuffer[MAXPKTSIZE]; 124 int allow_ro = 1, allow_wo = 1, on = 1; 125 pid_t pid; 126 127 tzset(); /* syslog in localtime */ 128 acting_as_client = 0; 129 130 tftp_openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP); 131 while ((ch = getopt(argc, argv, "cCd::F:lnoOp:s:Su:U:wW")) != -1) { 132 switch (ch) { 133 case 'c': 134 ipchroot = 1; 135 break; 136 case 'C': 137 ipchroot = 2; 138 break; 139 case 'd': 140 if (optarg == NULL) 141 debug++; 142 else if (atoi(optarg) != 0) 143 debug += atoi(optarg); 144 else 145 debug |= debug_finds(optarg); 146 break; 147 case 'F': 148 newfile_format = optarg; 149 break; 150 case 'l': 151 logging = 1; 152 break; 153 case 'n': 154 suppress_naks = 1; 155 break; 156 case 'o': 157 options_rfc_enabled = 0; 158 break; 159 case 'O': 160 options_extra_enabled = 0; 161 break; 162 case 'p': 163 packetdroppercentage = atoi(optarg); 164 tftp_log(LOG_INFO, 165 "Randomly dropping %d out of 100 packets", 166 packetdroppercentage); 167 break; 168 case 's': 169 chroot_dir = optarg; 170 break; 171 case 'S': 172 check_woth = -1; 173 break; 174 case 'u': 175 chuser = optarg; 176 break; 177 case 'U': 178 mask = strtol(optarg, NULL, 0); 179 break; 180 case 'w': 181 create_new = 1; 182 break; 183 case 'W': 184 create_new = 1; 185 increase_name = 1; 186 break; 187 default: 188 tftp_log(LOG_WARNING, 189 "ignoring unknown option -%c", ch); 190 } 191 } 192 if (optind < argc) { 193 struct dirlist *dirp; 194 195 /* Get list of directory prefixes. Skip relative pathnames. */ 196 for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS]; 197 optind++) { 198 if (argv[optind][0] == '/') { 199 dirp->name = argv[optind]; 200 dirp->len = strlen(dirp->name); 201 dirp++; 202 } 203 } 204 } 205 else if (chroot_dir) { 206 dirs->name = "/"; 207 dirs->len = 1; 208 } 209 if (ipchroot > 0 && chroot_dir == NULL) { 210 tftp_log(LOG_ERR, "-c requires -s"); 211 exit(1); 212 } 213 214 umask(mask); 215 216 if (ioctl(0, FIONBIO, &on) < 0) { 217 tftp_log(LOG_ERR, "ioctl(FIONBIO): %s", strerror(errno)); 218 exit(1); 219 } 220 221 /* Find out who we are talking to and what we are going to do */ 222 peerlen = sizeof(peer_sock); 223 n = recvfrom(0, recvbuffer, MAXPKTSIZE, 0, 224 (struct sockaddr *)&peer_sock, &peerlen); 225 if (n < 0) { 226 tftp_log(LOG_ERR, "recvfrom: %s", strerror(errno)); 227 exit(1); 228 } 229 getnameinfo((struct sockaddr *)&peer_sock, peer_sock.ss_len, 230 peername, sizeof(peername), NULL, 0, NI_NUMERICHOST); 231 232 /* 233 * Now that we have read the message out of the UDP 234 * socket, we fork and exit. Thus, inetd will go back 235 * to listening to the tftp port, and the next request 236 * to come in will start up a new instance of tftpd. 237 * 238 * We do this so that inetd can run tftpd in "wait" mode. 239 * The problem with tftpd running in "nowait" mode is that 240 * inetd may get one or more successful "selects" on the 241 * tftp port before we do our receive, so more than one 242 * instance of tftpd may be started up. Worse, if tftpd 243 * break before doing the above "recvfrom", inetd would 244 * spawn endless instances, clogging the system. 245 */ 246 pid = fork(); 247 if (pid < 0) { 248 tftp_log(LOG_ERR, "fork: %s", strerror(errno)); 249 exit(1); 250 } else if (pid != 0) { 251 exit(0); 252 } 253 /* child */ 254 255 #ifdef LIBWRAP 256 /* 257 * See if the client is allowed to talk to me. 258 * (This needs to be done before the chroot()) 259 */ 260 { 261 struct request_info req; 262 263 request_init(&req, RQ_CLIENT_ADDR, peername, 0); 264 request_set(&req, RQ_DAEMON, "tftpd", 0); 265 266 if (hosts_access(&req) == 0) { 267 if (debug & DEBUG_ACCESS) 268 tftp_log(LOG_WARNING, 269 "Access denied by 'tftpd' entry " 270 "in /etc/hosts.allow"); 271 272 /* 273 * Full access might be disabled, but maybe the 274 * client is allowed to do read-only access. 275 */ 276 request_set(&req, RQ_DAEMON, "tftpd-ro", 0); 277 allow_ro = hosts_access(&req); 278 279 request_set(&req, RQ_DAEMON, "tftpd-wo", 0); 280 allow_wo = hosts_access(&req); 281 282 if (allow_ro == 0 && allow_wo == 0) { 283 tftp_log(LOG_WARNING, 284 "Unauthorized access from %s", peername); 285 exit(1); 286 } 287 288 if (debug & DEBUG_ACCESS) { 289 if (allow_ro) 290 tftp_log(LOG_WARNING, 291 "But allowed readonly access " 292 "via 'tftpd-ro' entry"); 293 if (allow_wo) 294 tftp_log(LOG_WARNING, 295 "But allowed writeonly access " 296 "via 'tftpd-wo' entry"); 297 } 298 } else 299 if (debug & DEBUG_ACCESS) 300 tftp_log(LOG_WARNING, 301 "Full access allowed" 302 "in /etc/hosts.allow"); 303 } 304 #endif 305 306 /* 307 * Since we exit here, we should do that only after the above 308 * recvfrom to keep inetd from constantly forking should there 309 * be a problem. See the above comment about system clogging. 310 */ 311 if (chroot_dir) { 312 if (ipchroot > 0) { 313 char *tempchroot; 314 struct stat sb; 315 int statret; 316 struct sockaddr_storage ss; 317 char hbuf[NI_MAXHOST]; 318 319 statret = -1; 320 memcpy(&ss, &peer_sock, peer_sock.ss_len); 321 unmappedaddr((struct sockaddr_in6 *)&ss); 322 getnameinfo((struct sockaddr *)&ss, ss.ss_len, 323 hbuf, sizeof(hbuf), NULL, 0, 324 NI_NUMERICHOST); 325 asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf); 326 if (ipchroot == 2) 327 statret = stat(tempchroot, &sb); 328 if (ipchroot == 1 || 329 (statret == 0 && (sb.st_mode & S_IFDIR))) 330 chroot_dir = tempchroot; 331 } 332 /* Must get this before chroot because /etc might go away */ 333 if ((nobody = getpwnam(chuser)) == NULL) { 334 tftp_log(LOG_ERR, "%s: no such user", chuser); 335 exit(1); 336 } 337 if (chroot(chroot_dir)) { 338 tftp_log(LOG_ERR, "chroot: %s: %s", 339 chroot_dir, strerror(errno)); 340 exit(1); 341 } 342 if (chdir("/") != 0) { 343 tftp_log(LOG_ERR, "chdir: %s", strerror(errno)); 344 exit(1); 345 } 346 if (setgroups(1, &nobody->pw_gid) != 0) { 347 tftp_log(LOG_ERR, "setgroups failed"); 348 exit(1); 349 } 350 if (setuid(nobody->pw_uid) != 0) { 351 tftp_log(LOG_ERR, "setuid failed"); 352 exit(1); 353 } 354 if (check_woth == -1) 355 check_woth = 0; 356 } 357 if (check_woth == -1) 358 check_woth = 1; 359 360 len = sizeof(me_sock); 361 if (getsockname(0, (struct sockaddr *)&me_sock, &len) == 0) { 362 switch (me_sock.ss_family) { 363 case AF_INET: 364 ((struct sockaddr_in *)&me_sock)->sin_port = 0; 365 break; 366 case AF_INET6: 367 ((struct sockaddr_in6 *)&me_sock)->sin6_port = 0; 368 break; 369 default: 370 /* unsupported */ 371 break; 372 } 373 } else { 374 memset(&me_sock, 0, sizeof(me_sock)); 375 me_sock.ss_family = peer_sock.ss_family; 376 me_sock.ss_len = peer_sock.ss_len; 377 } 378 close(STDIN_FILENO); 379 close(STDOUT_FILENO); 380 close(STDERR_FILENO); 381 peer = socket(peer_sock.ss_family, SOCK_DGRAM, 0); 382 if (peer < 0) { 383 tftp_log(LOG_ERR, "socket: %s", strerror(errno)); 384 exit(1); 385 } 386 if (bind(peer, (struct sockaddr *)&me_sock, me_sock.ss_len) < 0) { 387 tftp_log(LOG_ERR, "bind: %s", strerror(errno)); 388 exit(1); 389 } 390 391 tp = (struct tftphdr *)recvbuffer; 392 tp->th_opcode = ntohs(tp->th_opcode); 393 if (tp->th_opcode == RRQ) { 394 if (allow_ro) 395 tftp_rrq(peer, tp->th_stuff, n - 1); 396 else { 397 tftp_log(LOG_WARNING, 398 "%s read access denied", peername); 399 exit(1); 400 } 401 } else if (tp->th_opcode == WRQ) { 402 if (allow_wo) 403 tftp_wrq(peer, tp->th_stuff, n - 1); 404 else { 405 tftp_log(LOG_WARNING, 406 "%s write access denied", peername); 407 exit(1); 408 } 409 } else 410 send_error(peer, EBADOP); 411 exit(1); 412 } 413 414 static void 415 reduce_path(char *fn) 416 { 417 char *slash, *ptr; 418 419 /* Reduce all "/+./" to "/" (just in case we've got "/./../" later */ 420 while ((slash = strstr(fn, "/./")) != NULL) { 421 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--) 422 ; 423 slash += 2; 424 while (*slash) 425 *++ptr = *++slash; 426 } 427 428 /* Now reduce all "/something/+../" to "/" */ 429 while ((slash = strstr(fn, "/../")) != NULL) { 430 if (slash == fn) 431 break; 432 for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--) 433 ; 434 for (ptr--; ptr >= fn; ptr--) 435 if (*ptr == '/') 436 break; 437 if (ptr < fn) 438 break; 439 slash += 3; 440 while (*slash) 441 *++ptr = *++slash; 442 } 443 } 444 445 static char * 446 parse_header(int peer, char *recvbuffer, ssize_t size, 447 char **filename, char **mode) 448 { 449 char *cp; 450 int i; 451 struct formats *pf; 452 453 *mode = NULL; 454 cp = recvbuffer; 455 456 i = get_field(peer, recvbuffer, size); 457 if (i >= PATH_MAX) { 458 tftp_log(LOG_ERR, "Bad option - filename too long"); 459 send_error(peer, EBADOP); 460 exit(1); 461 } 462 *filename = recvbuffer; 463 tftp_log(LOG_INFO, "Filename: '%s'", *filename); 464 cp += i; 465 466 i = get_field(peer, cp, size); 467 *mode = cp; 468 cp += i; 469 470 /* Find the file transfer mode */ 471 for (cp = *mode; *cp; cp++) 472 if (isupper(*cp)) 473 *cp = tolower(*cp); 474 for (pf = formats; pf->f_mode; pf++) 475 if (strcmp(pf->f_mode, *mode) == 0) 476 break; 477 if (pf->f_mode == NULL) { 478 tftp_log(LOG_ERR, 479 "Bad option - Unknown transfer mode (%s)", *mode); 480 send_error(peer, EBADOP); 481 exit(1); 482 } 483 tftp_log(LOG_INFO, "Mode: '%s'", *mode); 484 485 return (cp + 1); 486 } 487 488 /* 489 * WRQ - receive a file from the client 490 */ 491 void 492 tftp_wrq(int peer, char *recvbuffer, ssize_t size) 493 { 494 char *cp; 495 int has_options = 0, ecode; 496 char *filename, *mode; 497 char fnbuf[PATH_MAX]; 498 499 cp = parse_header(peer, recvbuffer, size, &filename, &mode); 500 size -= (cp - recvbuffer) + 1; 501 502 strlcpy(fnbuf, filename, sizeof(fnbuf)); 503 reduce_path(fnbuf); 504 filename = fnbuf; 505 506 if (size > 0) { 507 if (options_rfc_enabled) 508 has_options = !parse_options(peer, cp, size); 509 else 510 tftp_log(LOG_INFO, "Options found but not enabled"); 511 } 512 513 ecode = validate_access(peer, &filename, WRQ); 514 if (ecode == 0) { 515 if (has_options) 516 send_oack(peer); 517 else 518 send_ack(peer, 0); 519 } 520 if (logging) { 521 tftp_log(LOG_INFO, "%s: write request for %s: %s", peername, 522 filename, errtomsg(ecode)); 523 } 524 525 if (ecode) { 526 send_error(peer, ecode); 527 exit(1); 528 } 529 tftp_recvfile(peer, mode); 530 exit(0); 531 } 532 533 /* 534 * RRQ - send a file to the client 535 */ 536 void 537 tftp_rrq(int peer, char *recvbuffer, ssize_t size) 538 { 539 char *cp; 540 int has_options = 0, ecode; 541 char *filename, *mode; 542 char fnbuf[PATH_MAX]; 543 544 cp = parse_header(peer, recvbuffer, size, &filename, &mode); 545 size -= (cp - recvbuffer) + 1; 546 547 strlcpy(fnbuf, filename, sizeof(fnbuf)); 548 reduce_path(fnbuf); 549 filename = fnbuf; 550 551 if (size > 0) { 552 if (options_rfc_enabled) 553 has_options = !parse_options(peer, cp, size); 554 else 555 tftp_log(LOG_INFO, "Options found but not enabled"); 556 } 557 558 ecode = validate_access(peer, &filename, RRQ); 559 if (ecode == 0) { 560 if (has_options) { 561 int n; 562 char lrecvbuffer[MAXPKTSIZE]; 563 struct tftphdr *rp = (struct tftphdr *)lrecvbuffer; 564 565 send_oack(peer); 566 n = receive_packet(peer, lrecvbuffer, MAXPKTSIZE, 567 NULL, timeoutpacket); 568 if (n < 0) { 569 if (debug & DEBUG_SIMPLE) 570 tftp_log(LOG_DEBUG, "Aborting: %s", 571 rp_strerror(n)); 572 return; 573 } 574 if (rp->th_opcode != ACK) { 575 if (debug & DEBUG_SIMPLE) 576 tftp_log(LOG_DEBUG, 577 "Expected ACK, got %s on OACK", 578 packettype(rp->th_opcode)); 579 return; 580 } 581 } 582 } 583 584 if (logging) 585 tftp_log(LOG_INFO, "%s: read request for %s: %s", peername, 586 filename, errtomsg(ecode)); 587 588 if (ecode) { 589 /* 590 * Avoid storms of naks to a RRQ broadcast for a relative 591 * bootfile pathname from a diskless Sun. 592 */ 593 if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) 594 exit(0); 595 send_error(peer, ecode); 596 exit(1); 597 } 598 tftp_xmitfile(peer, mode); 599 } 600 601 /* 602 * Find the next value for YYYYMMDD.nn when the file to be written should 603 * be unique. Due to the limitations of nn, we will fail if nn reaches 100. 604 * Besides, that is four updates per hour on a file, which is kind of 605 * execessive anyway. 606 */ 607 static int 608 find_next_name(char *filename, int *fd) 609 { 610 int i; 611 time_t tval; 612 size_t len; 613 struct tm lt; 614 char yyyymmdd[MAXPATHLEN]; 615 char newname[MAXPATHLEN]; 616 617 /* Create the YYYYMMDD part of the filename */ 618 time(&tval); 619 lt = *localtime(&tval); 620 len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, <); 621 if (len == 0) { 622 syslog(LOG_WARNING, 623 "Filename suffix too long (%d characters maximum)", 624 MAXPATHLEN); 625 return (EACCESS); 626 } 627 628 /* Make sure the new filename is not too long */ 629 if (strlen(filename) > MAXPATHLEN - len - 5) { 630 syslog(LOG_WARNING, 631 "Filename too long (%zd characters, %zd maximum)", 632 strlen(filename), MAXPATHLEN - len - 5); 633 return (EACCESS); 634 } 635 636 /* Find the first file which doesn't exist */ 637 for (i = 0; i < 100; i++) { 638 sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i); 639 *fd = open(newname, 640 O_WRONLY | O_CREAT | O_EXCL, 641 S_IRUSR | S_IWUSR | S_IRGRP | 642 S_IWGRP | S_IROTH | S_IWOTH); 643 if (*fd > 0) 644 return 0; 645 } 646 647 return (EEXIST); 648 } 649 650 /* 651 * Validate file access. Since we 652 * have no uid or gid, for now require 653 * file to exist and be publicly 654 * readable/writable. 655 * If we were invoked with arguments 656 * from inetd then the file must also be 657 * in one of the given directory prefixes. 658 * Note also, full path name must be 659 * given as we have no login directory. 660 */ 661 int 662 validate_access(int peer, char **filep, int mode) 663 { 664 struct stat stbuf; 665 int fd; 666 int error; 667 struct dirlist *dirp; 668 static char pathname[MAXPATHLEN]; 669 char *filename = *filep; 670 671 /* 672 * Prevent tricksters from getting around the directory restrictions 673 */ 674 if (strstr(filename, "/../")) 675 return (EACCESS); 676 677 if (*filename == '/') { 678 /* 679 * Allow the request if it's in one of the approved locations. 680 * Special case: check the null prefix ("/") by looking 681 * for length = 1 and relying on the arg. processing that 682 * it's a /. 683 */ 684 for (dirp = dirs; dirp->name != NULL; dirp++) { 685 if (dirp->len == 1 || 686 (!strncmp(filename, dirp->name, dirp->len) && 687 filename[dirp->len] == '/')) 688 break; 689 } 690 /* If directory list is empty, allow access to any file */ 691 if (dirp->name == NULL && dirp != dirs) 692 return (EACCESS); 693 if (stat(filename, &stbuf) < 0) 694 return (errno == ENOENT ? ENOTFOUND : EACCESS); 695 if ((stbuf.st_mode & S_IFMT) != S_IFREG) 696 return (ENOTFOUND); 697 if (mode == RRQ) { 698 if ((stbuf.st_mode & S_IROTH) == 0) 699 return (EACCESS); 700 } else { 701 if (check_woth && ((stbuf.st_mode & S_IWOTH) == 0)) 702 return (EACCESS); 703 } 704 } else { 705 int err; 706 707 /* 708 * Relative file name: search the approved locations for it. 709 * Don't allow write requests that avoid directory 710 * restrictions. 711 */ 712 713 if (!strncmp(filename, "../", 3)) 714 return (EACCESS); 715 716 /* 717 * If the file exists in one of the directories and isn't 718 * readable, continue looking. However, change the error code 719 * to give an indication that the file exists. 720 */ 721 err = ENOTFOUND; 722 for (dirp = dirs; dirp->name != NULL; dirp++) { 723 snprintf(pathname, sizeof(pathname), "%s/%s", 724 dirp->name, filename); 725 if (stat(pathname, &stbuf) == 0 && 726 (stbuf.st_mode & S_IFMT) == S_IFREG) { 727 if (mode == RRQ) { 728 if ((stbuf.st_mode & S_IROTH) != 0) 729 break; 730 } else { 731 if (!check_woth || ((stbuf.st_mode & S_IWOTH) != 0)) 732 break; 733 } 734 err = EACCESS; 735 } 736 } 737 if (dirp->name != NULL) 738 *filep = filename = pathname; 739 else if (mode == RRQ) 740 return (err); 741 else if (err != ENOTFOUND || !create_new) 742 return (err); 743 } 744 745 /* 746 * This option is handled here because it (might) require(s) the 747 * size of the file. 748 */ 749 option_tsize(peer, NULL, mode, &stbuf); 750 751 if (mode == RRQ) 752 fd = open(filename, O_RDONLY); 753 else { 754 if (create_new) { 755 if (increase_name) { 756 error = find_next_name(filename, &fd); 757 if (error > 0) 758 return (error + 100); 759 } else 760 fd = open(filename, 761 O_WRONLY | O_TRUNC | O_CREAT, 762 S_IRUSR | S_IWUSR | S_IRGRP | 763 S_IWGRP | S_IROTH | S_IWOTH ); 764 } else 765 fd = open(filename, O_WRONLY | O_TRUNC); 766 } 767 if (fd < 0) 768 return (errno + 100); 769 file = fdopen(fd, (mode == RRQ)? "r":"w"); 770 if (file == NULL) { 771 close(fd); 772 return (errno + 100); 773 } 774 return (0); 775 } 776 777 static void 778 tftp_xmitfile(int peer, const char *mode) 779 { 780 uint16_t block; 781 time_t now; 782 struct tftp_stats ts; 783 784 memset(&ts, 0, sizeof(ts)); 785 now = time(NULL); 786 if (debug & DEBUG_SIMPLE) 787 tftp_log(LOG_DEBUG, "Transmitting file"); 788 789 read_init(0, file, mode); 790 block = 1; 791 tftp_send(peer, &block, &ts); 792 read_close(); 793 if (debug & DEBUG_SIMPLE) 794 tftp_log(LOG_INFO, "Sent %jd bytes in %jd seconds", 795 (intmax_t)ts.amount, (intmax_t)time(NULL) - now); 796 } 797 798 static void 799 tftp_recvfile(int peer, const char *mode) 800 { 801 uint16_t block; 802 struct timeval now1, now2; 803 struct tftp_stats ts; 804 805 gettimeofday(&now1, NULL); 806 if (debug & DEBUG_SIMPLE) 807 tftp_log(LOG_DEBUG, "Receiving file"); 808 809 write_init(0, file, mode); 810 811 block = 0; 812 tftp_receive(peer, &block, &ts, NULL, 0); 813 814 gettimeofday(&now2, NULL); 815 816 if (debug & DEBUG_SIMPLE) { 817 double f; 818 if (now1.tv_usec > now2.tv_usec) { 819 now2.tv_usec += 1000000; 820 now2.tv_sec--; 821 } 822 823 f = now2.tv_sec - now1.tv_sec + 824 (now2.tv_usec - now1.tv_usec) / 100000.0; 825 tftp_log(LOG_INFO, 826 "Download of %jd bytes in %d blocks completed after %0.1f seconds\n", 827 (intmax_t)ts.amount, block, f); 828 } 829 830 return; 831 } 832