1 /* $OpenBSD: scp.c,v 1.156 2007/01/22 13:06:21 djm Exp $ */ 2 /* 3 * scp - secure remote copy. This is basically patched BSD rcp which 4 * uses ssh to do the data transfer (instead of using rcmd). 5 * 6 * NOTE: This version should NOT be suid root. (This uses ssh to 7 * do the transfer and ssh has the necessary privileges.) 8 * 9 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> 10 * 11 * As far as I am concerned, the code I have written for this software 12 * can be used freely for any purpose. Any derived versions of this 13 * software must be clearly marked as such, and if the derived work is 14 * incompatible with the protocol description in the RFC file, it must be 15 * called by a name other than "ssh" or "Secure Shell". 16 */ 17 /* 18 * Copyright (c) 1999 Theo de Raadt. All rights reserved. 19 * Copyright (c) 1999 Aaron Campbell. All rights reserved. 20 * 21 * Redistribution and use in source and binary forms, with or without 22 * modification, are permitted provided that the following conditions 23 * are met: 24 * 1. Redistributions of source code must retain the above copyright 25 * notice, this list of conditions and the following disclaimer. 26 * 2. Redistributions in binary form must reproduce the above copyright 27 * notice, this list of conditions and the following disclaimer in the 28 * documentation and/or other materials provided with the distribution. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 33 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 39 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42 /* 43 * Parts from: 44 * 45 * Copyright (c) 1983, 1990, 1992, 1993, 1995 46 * The Regents of the University of California. All rights reserved. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 */ 73 74 #include <sys/param.h> 75 #include <sys/types.h> 76 #include <sys/wait.h> 77 #include <sys/stat.h> 78 #include <sys/time.h> 79 #include <sys/uio.h> 80 81 #include <ctype.h> 82 #include <dirent.h> 83 #include <errno.h> 84 #include <fcntl.h> 85 #include <pwd.h> 86 #include <signal.h> 87 #include <stdarg.h> 88 #include <stdio.h> 89 #include <stdlib.h> 90 #include <string.h> 91 #include <time.h> 92 #include <unistd.h> 93 94 #include "xmalloc.h" 95 #include "atomicio.h" 96 #include "pathnames.h" 97 #include "log.h" 98 #include "misc.h" 99 #include "progressmeter.h" 100 101 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 102 103 void bwlimit(int); 104 105 /* Struct for addargs */ 106 arglist args; 107 108 /* Bandwidth limit */ 109 off_t limit_rate = 0; 110 111 /* Name of current file being transferred. */ 112 char *curfile; 113 114 /* This is set to non-zero to enable verbose mode. */ 115 int verbose_mode = 0; 116 117 /* This is set to zero if the progressmeter is not desired. */ 118 int showprogress = 1; 119 120 /* This is the program to execute for the secured connection. ("ssh" or -S) */ 121 char *ssh_program = _PATH_SSH_PROGRAM; 122 123 /* This is used to store the pid of ssh_program */ 124 pid_t do_cmd_pid = -1; 125 126 static void 127 killchild(int signo) 128 { 129 if (do_cmd_pid > 1) { 130 kill(do_cmd_pid, signo ? signo : SIGTERM); 131 waitpid(do_cmd_pid, NULL, 0); 132 } 133 134 if (signo) 135 _exit(1); 136 exit(1); 137 } 138 139 static int 140 do_local_cmd(arglist *a) 141 { 142 u_int i; 143 int status; 144 pid_t pid; 145 146 if (a->num == 0) 147 fatal("do_local_cmd: no arguments"); 148 149 if (verbose_mode) { 150 fprintf(stderr, "Executing:"); 151 for (i = 0; i < a->num; i++) 152 fprintf(stderr, " %s", a->list[i]); 153 fprintf(stderr, "\n"); 154 } 155 if ((pid = fork()) == -1) 156 fatal("do_local_cmd: fork: %s", strerror(errno)); 157 158 if (pid == 0) { 159 execvp(a->list[0], a->list); 160 perror(a->list[0]); 161 exit(1); 162 } 163 164 do_cmd_pid = pid; 165 signal(SIGTERM, killchild); 166 signal(SIGINT, killchild); 167 signal(SIGHUP, killchild); 168 169 while (waitpid(pid, &status, 0) == -1) 170 if (errno != EINTR) 171 fatal("do_local_cmd: waitpid: %s", strerror(errno)); 172 173 do_cmd_pid = -1; 174 175 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 176 return (-1); 177 178 return (0); 179 } 180 181 /* 182 * This function executes the given command as the specified user on the 183 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 184 * assigns the input and output file descriptors on success. 185 */ 186 187 int 188 do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 189 { 190 int pin[2], pout[2], reserved[2]; 191 192 if (verbose_mode) 193 fprintf(stderr, 194 "Executing: program %s host %s, user %s, command %s\n", 195 ssh_program, host, 196 remuser ? remuser : "(unspecified)", cmd); 197 198 /* 199 * Reserve two descriptors so that the real pipes won't get 200 * descriptors 0 and 1 because that will screw up dup2 below. 201 */ 202 if (pipe(reserved) < 0) 203 fatal("pipe: %s", strerror(errno)); 204 205 /* Create a socket pair for communicating with ssh. */ 206 if (pipe(pin) < 0) 207 fatal("pipe: %s", strerror(errno)); 208 if (pipe(pout) < 0) 209 fatal("pipe: %s", strerror(errno)); 210 211 /* Free the reserved descriptors. */ 212 close(reserved[0]); 213 close(reserved[1]); 214 215 /* Fork a child to execute the command on the remote host using ssh. */ 216 do_cmd_pid = fork(); 217 if (do_cmd_pid == 0) { 218 /* Child. */ 219 close(pin[1]); 220 close(pout[0]); 221 dup2(pin[0], 0); 222 dup2(pout[1], 1); 223 close(pin[0]); 224 close(pout[1]); 225 226 replacearg(&args, 0, "%s", ssh_program); 227 if (remuser != NULL) 228 addargs(&args, "-l%s", remuser); 229 addargs(&args, "%s", host); 230 addargs(&args, "%s", cmd); 231 232 execvp(ssh_program, args.list); 233 perror(ssh_program); 234 exit(1); 235 } else if (do_cmd_pid == -1) { 236 fatal("fork: %s", strerror(errno)); 237 } 238 /* Parent. Close the other side, and return the local side. */ 239 close(pin[0]); 240 *fdout = pin[1]; 241 close(pout[1]); 242 *fdin = pout[0]; 243 signal(SIGTERM, killchild); 244 signal(SIGINT, killchild); 245 signal(SIGHUP, killchild); 246 return 0; 247 } 248 249 typedef struct { 250 size_t cnt; 251 char *buf; 252 } BUF; 253 254 BUF *allocbuf(BUF *, int, int); 255 void lostconn(int); 256 int okname(char *); 257 void run_err(const char *,...); 258 void verifydir(char *); 259 260 struct passwd *pwd; 261 uid_t userid; 262 int errs, remin, remout; 263 int pflag, iamremote, iamrecursive, targetshouldbedirectory; 264 265 #define CMDNEEDS 64 266 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 267 268 int response(void); 269 void rsource(char *, struct stat *); 270 void sink(int, char *[]); 271 void source(int, char *[]); 272 void tolocal(int, char *[]); 273 void toremote(char *, int, char *[]); 274 void usage(void); 275 276 int 277 main(int argc, char **argv) 278 { 279 int ch, fflag, tflag, status, n; 280 double speed; 281 char *targ, *endp, **newargv; 282 extern char *optarg; 283 extern int optind; 284 285 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 286 sanitise_stdfd(); 287 288 /* Copy argv, because we modify it */ 289 newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv)); 290 for (n = 0; n < argc; n++) 291 newargv[n] = xstrdup(argv[n]); 292 argv = newargv; 293 294 memset(&args, '\0', sizeof(args)); 295 args.list = NULL; 296 addargs(&args, "%s", ssh_program); 297 addargs(&args, "-x"); 298 addargs(&args, "-oForwardAgent no"); 299 addargs(&args, "-oPermitLocalCommand no"); 300 addargs(&args, "-oClearAllForwardings yes"); 301 302 fflag = tflag = 0; 303 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) 304 switch (ch) { 305 /* User-visible flags. */ 306 case '1': 307 case '2': 308 case '4': 309 case '6': 310 case 'C': 311 addargs(&args, "-%c", ch); 312 break; 313 case 'o': 314 case 'c': 315 case 'i': 316 case 'F': 317 addargs(&args, "-%c%s", ch, optarg); 318 break; 319 case 'P': 320 addargs(&args, "-p%s", optarg); 321 break; 322 case 'B': 323 addargs(&args, "-oBatchmode yes"); 324 break; 325 case 'l': 326 speed = strtod(optarg, &endp); 327 if (speed <= 0 || *endp != '\0') 328 usage(); 329 limit_rate = speed * 1024; 330 break; 331 case 'p': 332 pflag = 1; 333 break; 334 case 'r': 335 iamrecursive = 1; 336 break; 337 case 'S': 338 ssh_program = xstrdup(optarg); 339 break; 340 case 'v': 341 addargs(&args, "-v"); 342 verbose_mode = 1; 343 break; 344 case 'q': 345 addargs(&args, "-q"); 346 showprogress = 0; 347 break; 348 349 /* Server options. */ 350 case 'd': 351 targetshouldbedirectory = 1; 352 break; 353 case 'f': /* "from" */ 354 iamremote = 1; 355 fflag = 1; 356 break; 357 case 't': /* "to" */ 358 iamremote = 1; 359 tflag = 1; 360 break; 361 default: 362 usage(); 363 } 364 argc -= optind; 365 argv += optind; 366 367 if ((pwd = getpwuid(userid = getuid())) == NULL) 368 fatal("unknown user %u", (u_int) userid); 369 370 if (!isatty(STDOUT_FILENO)) 371 showprogress = 0; 372 373 remin = STDIN_FILENO; 374 remout = STDOUT_FILENO; 375 376 if (fflag) { 377 /* Follow "protocol", send data. */ 378 (void) response(); 379 source(argc, argv); 380 exit(errs != 0); 381 } 382 if (tflag) { 383 /* Receive data. */ 384 sink(argc, argv); 385 exit(errs != 0); 386 } 387 if (argc < 2) 388 usage(); 389 if (argc > 2) 390 targetshouldbedirectory = 1; 391 392 remin = remout = -1; 393 do_cmd_pid = -1; 394 /* Command to be executed on remote system using "ssh". */ 395 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", 396 verbose_mode ? " -v" : "", 397 iamrecursive ? " -r" : "", pflag ? " -p" : "", 398 targetshouldbedirectory ? " -d" : ""); 399 400 (void) signal(SIGPIPE, lostconn); 401 402 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 403 toremote(targ, argc, argv); 404 else { 405 if (targetshouldbedirectory) 406 verifydir(argv[argc - 1]); 407 tolocal(argc, argv); /* Dest is local host. */ 408 } 409 /* 410 * Finally check the exit status of the ssh process, if one was forked 411 * and no error has occured yet 412 */ 413 if (do_cmd_pid != -1 && errs == 0) { 414 if (remin != -1) 415 (void) close(remin); 416 if (remout != -1) 417 (void) close(remout); 418 if (waitpid(do_cmd_pid, &status, 0) == -1) 419 errs = 1; 420 else { 421 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 422 errs = 1; 423 } 424 } 425 exit(errs != 0); 426 } 427 428 void 429 toremote(char *targ, int argc, char **argv) 430 { 431 char *bp, *host, *src, *suser, *thost, *tuser, *arg; 432 arglist alist; 433 int i; 434 435 memset(&alist, '\0', sizeof(alist)); 436 alist.list = NULL; 437 438 *targ++ = 0; 439 if (*targ == 0) 440 targ = "."; 441 442 arg = xstrdup(argv[argc - 1]); 443 if ((thost = strrchr(arg, '@'))) { 444 /* user@host */ 445 *thost++ = 0; 446 tuser = arg; 447 if (*tuser == '\0') 448 tuser = NULL; 449 } else { 450 thost = arg; 451 tuser = NULL; 452 } 453 454 if (tuser != NULL && !okname(tuser)) { 455 xfree(arg); 456 return; 457 } 458 459 for (i = 0; i < argc - 1; i++) { 460 src = colon(argv[i]); 461 if (src) { /* remote to remote */ 462 freeargs(&alist); 463 addargs(&alist, "%s", ssh_program); 464 if (verbose_mode) 465 addargs(&alist, "-v"); 466 addargs(&alist, "-x"); 467 addargs(&alist, "-oClearAllForwardings yes"); 468 addargs(&alist, "-n"); 469 470 *src++ = 0; 471 if (*src == 0) 472 src = "."; 473 host = strrchr(argv[i], '@'); 474 475 if (host) { 476 *host++ = 0; 477 host = cleanhostname(host); 478 suser = argv[i]; 479 if (*suser == '\0') 480 suser = pwd->pw_name; 481 else if (!okname(suser)) 482 continue; 483 addargs(&alist, "-l"); 484 addargs(&alist, "%s", suser); 485 } else { 486 host = cleanhostname(argv[i]); 487 } 488 addargs(&alist, "%s", host); 489 addargs(&alist, "%s", cmd); 490 addargs(&alist, "%s", src); 491 addargs(&alist, "%s%s%s:%s", 492 tuser ? tuser : "", tuser ? "@" : "", 493 thost, targ); 494 if (do_local_cmd(&alist) != 0) 495 errs = 1; 496 } else { /* local to remote */ 497 if (remin == -1) { 498 xasprintf(&bp, "%s -t %s", cmd, targ); 499 host = cleanhostname(thost); 500 if (do_cmd(host, tuser, bp, &remin, 501 &remout) < 0) 502 exit(1); 503 if (response() < 0) 504 exit(1); 505 (void) xfree(bp); 506 } 507 source(1, argv + i); 508 } 509 } 510 xfree(arg); 511 } 512 513 void 514 tolocal(int argc, char **argv) 515 { 516 char *bp, *host, *src, *suser; 517 arglist alist; 518 int i; 519 520 memset(&alist, '\0', sizeof(alist)); 521 alist.list = NULL; 522 523 for (i = 0; i < argc - 1; i++) { 524 if (!(src = colon(argv[i]))) { /* Local to local. */ 525 freeargs(&alist); 526 addargs(&alist, "%s", _PATH_CP); 527 if (iamrecursive) 528 addargs(&alist, "-r"); 529 if (pflag) 530 addargs(&alist, "-p"); 531 addargs(&alist, "%s", argv[i]); 532 addargs(&alist, "%s", argv[argc-1]); 533 if (do_local_cmd(&alist)) 534 ++errs; 535 continue; 536 } 537 *src++ = 0; 538 if (*src == 0) 539 src = "."; 540 if ((host = strrchr(argv[i], '@')) == NULL) { 541 host = argv[i]; 542 suser = NULL; 543 } else { 544 *host++ = 0; 545 suser = argv[i]; 546 if (*suser == '\0') 547 suser = pwd->pw_name; 548 } 549 host = cleanhostname(host); 550 xasprintf(&bp, "%s -f %s", cmd, src); 551 if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 552 (void) xfree(bp); 553 ++errs; 554 continue; 555 } 556 xfree(bp); 557 sink(1, argv + argc - 1); 558 (void) close(remin); 559 remin = remout = -1; 560 } 561 } 562 563 void 564 source(int argc, char **argv) 565 { 566 struct stat stb; 567 static BUF buffer; 568 BUF *bp; 569 off_t i, amt, statbytes; 570 size_t result; 571 int fd = -1, haderr, indx; 572 char *last, *name, buf[2048]; 573 int len; 574 575 for (indx = 0; indx < argc; ++indx) { 576 name = argv[indx]; 577 statbytes = 0; 578 len = strlen(name); 579 while (len > 1 && name[len-1] == '/') 580 name[--len] = '\0'; 581 if (strchr(name, '\n') != NULL) { 582 run_err("%s: skipping, filename contains a newline", 583 name); 584 goto next; 585 } 586 if ((fd = open(name, O_RDONLY, 0)) < 0) 587 goto syserr; 588 if (fstat(fd, &stb) < 0) { 589 syserr: run_err("%s: %s", name, strerror(errno)); 590 goto next; 591 } 592 switch (stb.st_mode & S_IFMT) { 593 case S_IFREG: 594 break; 595 case S_IFDIR: 596 if (iamrecursive) { 597 rsource(name, &stb); 598 goto next; 599 } 600 /* FALLTHROUGH */ 601 default: 602 run_err("%s: not a regular file", name); 603 goto next; 604 } 605 if ((last = strrchr(name, '/')) == NULL) 606 last = name; 607 else 608 ++last; 609 curfile = last; 610 if (pflag) { 611 /* 612 * Make it compatible with possible future 613 * versions expecting microseconds. 614 */ 615 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", 616 (u_long) stb.st_mtime, 617 (u_long) stb.st_atime); 618 (void) atomicio(vwrite, remout, buf, strlen(buf)); 619 if (response() < 0) 620 goto next; 621 } 622 #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 623 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 624 (u_int) (stb.st_mode & FILEMODEMASK), 625 (long long)stb.st_size, last); 626 if (verbose_mode) { 627 fprintf(stderr, "Sending file modes: %s", buf); 628 } 629 (void) atomicio(vwrite, remout, buf, strlen(buf)); 630 if (response() < 0) 631 goto next; 632 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 633 next: if (fd != -1) { 634 (void) close(fd); 635 fd = -1; 636 } 637 continue; 638 } 639 if (showprogress) 640 start_progress_meter(curfile, stb.st_size, &statbytes); 641 /* Keep writing after an error so that we stay sync'd up. */ 642 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 643 amt = bp->cnt; 644 if (i + amt > stb.st_size) 645 amt = stb.st_size - i; 646 if (!haderr) { 647 result = atomicio(read, fd, bp->buf, amt); 648 if (result != amt) 649 haderr = errno; 650 } 651 if (haderr) 652 (void) atomicio(vwrite, remout, bp->buf, amt); 653 else { 654 result = atomicio(vwrite, remout, bp->buf, amt); 655 if (result != amt) 656 haderr = errno; 657 statbytes += result; 658 } 659 if (limit_rate) 660 bwlimit(amt); 661 } 662 if (showprogress) 663 stop_progress_meter(); 664 665 if (fd != -1) { 666 if (close(fd) < 0 && !haderr) 667 haderr = errno; 668 fd = -1; 669 } 670 if (!haderr) 671 (void) atomicio(vwrite, remout, "", 1); 672 else 673 run_err("%s: %s", name, strerror(haderr)); 674 (void) response(); 675 } 676 } 677 678 void 679 rsource(char *name, struct stat *statp) 680 { 681 DIR *dirp; 682 struct dirent *dp; 683 char *last, *vect[1], path[1100]; 684 685 if (!(dirp = opendir(name))) { 686 run_err("%s: %s", name, strerror(errno)); 687 return; 688 } 689 last = strrchr(name, '/'); 690 if (last == 0) 691 last = name; 692 else 693 last++; 694 if (pflag) { 695 (void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n", 696 (u_long) statp->st_mtime, 697 (u_long) statp->st_atime); 698 (void) atomicio(vwrite, remout, path, strlen(path)); 699 if (response() < 0) { 700 closedir(dirp); 701 return; 702 } 703 } 704 (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", 705 (u_int) (statp->st_mode & FILEMODEMASK), 0, last); 706 if (verbose_mode) 707 fprintf(stderr, "Entering directory: %s", path); 708 (void) atomicio(vwrite, remout, path, strlen(path)); 709 if (response() < 0) { 710 closedir(dirp); 711 return; 712 } 713 while ((dp = readdir(dirp)) != NULL) { 714 if (dp->d_ino == 0) 715 continue; 716 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 717 continue; 718 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { 719 run_err("%s/%s: name too long", name, dp->d_name); 720 continue; 721 } 722 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); 723 vect[0] = path; 724 source(1, vect); 725 } 726 (void) closedir(dirp); 727 (void) atomicio(vwrite, remout, "E\n", 2); 728 (void) response(); 729 } 730 731 void 732 bwlimit(int amount) 733 { 734 static struct timeval bwstart, bwend; 735 static int lamt, thresh = 16384; 736 u_int64_t waitlen; 737 struct timespec ts, rm; 738 739 if (!timerisset(&bwstart)) { 740 gettimeofday(&bwstart, NULL); 741 return; 742 } 743 744 lamt += amount; 745 if (lamt < thresh) 746 return; 747 748 gettimeofday(&bwend, NULL); 749 timersub(&bwend, &bwstart, &bwend); 750 if (!timerisset(&bwend)) 751 return; 752 753 lamt *= 8; 754 waitlen = (double)1000000L * lamt / limit_rate; 755 756 bwstart.tv_sec = waitlen / 1000000L; 757 bwstart.tv_usec = waitlen % 1000000L; 758 759 if (timercmp(&bwstart, &bwend, >)) { 760 timersub(&bwstart, &bwend, &bwend); 761 762 /* Adjust the wait time */ 763 if (bwend.tv_sec) { 764 thresh /= 2; 765 if (thresh < 2048) 766 thresh = 2048; 767 } else if (bwend.tv_usec < 100) { 768 thresh *= 2; 769 if (thresh > 32768) 770 thresh = 32768; 771 } 772 773 TIMEVAL_TO_TIMESPEC(&bwend, &ts); 774 while (nanosleep(&ts, &rm) == -1) { 775 if (errno != EINTR) 776 break; 777 ts = rm; 778 } 779 } 780 781 lamt = 0; 782 gettimeofday(&bwstart, NULL); 783 } 784 785 void 786 sink(int argc, char **argv) 787 { 788 static BUF buffer; 789 struct stat stb; 790 enum { 791 YES, NO, DISPLAYED 792 } wrerr; 793 BUF *bp; 794 off_t i; 795 size_t j, count; 796 int amt, exists, first, ofd; 797 mode_t mode, omode, mask; 798 off_t size, statbytes; 799 int setimes, targisdir, wrerrno = 0; 800 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 801 struct timeval tv[2]; 802 803 #define atime tv[0] 804 #define mtime tv[1] 805 #define SCREWUP(str) { why = str; goto screwup; } 806 807 setimes = targisdir = 0; 808 mask = umask(0); 809 if (!pflag) 810 (void) umask(mask); 811 if (argc != 1) { 812 run_err("ambiguous target"); 813 exit(1); 814 } 815 targ = *argv; 816 if (targetshouldbedirectory) 817 verifydir(targ); 818 819 (void) atomicio(vwrite, remout, "", 1); 820 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 821 targisdir = 1; 822 for (first = 1;; first = 0) { 823 cp = buf; 824 if (atomicio(read, remin, cp, 1) != 1) 825 return; 826 if (*cp++ == '\n') 827 SCREWUP("unexpected <newline>"); 828 do { 829 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 830 SCREWUP("lost connection"); 831 *cp++ = ch; 832 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 833 *cp = 0; 834 if (verbose_mode) 835 fprintf(stderr, "Sink: %s", buf); 836 837 if (buf[0] == '\01' || buf[0] == '\02') { 838 if (iamremote == 0) 839 (void) atomicio(vwrite, STDERR_FILENO, 840 buf + 1, strlen(buf + 1)); 841 if (buf[0] == '\02') 842 exit(1); 843 ++errs; 844 continue; 845 } 846 if (buf[0] == 'E') { 847 (void) atomicio(vwrite, remout, "", 1); 848 return; 849 } 850 if (ch == '\n') 851 *--cp = 0; 852 853 cp = buf; 854 if (*cp == 'T') { 855 setimes++; 856 cp++; 857 mtime.tv_sec = strtol(cp, &cp, 10); 858 if (!cp || *cp++ != ' ') 859 SCREWUP("mtime.sec not delimited"); 860 mtime.tv_usec = strtol(cp, &cp, 10); 861 if (!cp || *cp++ != ' ') 862 SCREWUP("mtime.usec not delimited"); 863 atime.tv_sec = strtol(cp, &cp, 10); 864 if (!cp || *cp++ != ' ') 865 SCREWUP("atime.sec not delimited"); 866 atime.tv_usec = strtol(cp, &cp, 10); 867 if (!cp || *cp++ != '\0') 868 SCREWUP("atime.usec not delimited"); 869 (void) atomicio(vwrite, remout, "", 1); 870 continue; 871 } 872 if (*cp != 'C' && *cp != 'D') { 873 /* 874 * Check for the case "rcp remote:foo\* local:bar". 875 * In this case, the line "No match." can be returned 876 * by the shell before the rcp command on the remote is 877 * executed so the ^Aerror_message convention isn't 878 * followed. 879 */ 880 if (first) { 881 run_err("%s", cp); 882 exit(1); 883 } 884 SCREWUP("expected control record"); 885 } 886 mode = 0; 887 for (++cp; cp < buf + 5; cp++) { 888 if (*cp < '0' || *cp > '7') 889 SCREWUP("bad mode"); 890 mode = (mode << 3) | (*cp - '0'); 891 } 892 if (*cp++ != ' ') 893 SCREWUP("mode not delimited"); 894 895 for (size = 0; isdigit(*cp);) 896 size = size * 10 + (*cp++ - '0'); 897 if (*cp++ != ' ') 898 SCREWUP("size not delimited"); 899 if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) { 900 run_err("error: unexpected filename: %s", cp); 901 exit(1); 902 } 903 if (targisdir) { 904 static char *namebuf; 905 static size_t cursize; 906 size_t need; 907 908 need = strlen(targ) + strlen(cp) + 250; 909 if (need > cursize) { 910 if (namebuf) 911 xfree(namebuf); 912 namebuf = xmalloc(need); 913 cursize = need; 914 } 915 (void) snprintf(namebuf, need, "%s%s%s", targ, 916 strcmp(targ, "/") ? "/" : "", cp); 917 np = namebuf; 918 } else 919 np = targ; 920 curfile = cp; 921 exists = stat(np, &stb) == 0; 922 if (buf[0] == 'D') { 923 int mod_flag = pflag; 924 if (!iamrecursive) 925 SCREWUP("received directory without -r"); 926 if (exists) { 927 if (!S_ISDIR(stb.st_mode)) { 928 errno = ENOTDIR; 929 goto bad; 930 } 931 if (pflag) 932 (void) chmod(np, mode); 933 } else { 934 /* Handle copying from a read-only 935 directory */ 936 mod_flag = 1; 937 if (mkdir(np, mode | S_IRWXU) < 0) 938 goto bad; 939 } 940 vect[0] = xstrdup(np); 941 sink(1, vect); 942 if (setimes) { 943 setimes = 0; 944 if (utimes(vect[0], tv) < 0) 945 run_err("%s: set times: %s", 946 vect[0], strerror(errno)); 947 } 948 if (mod_flag) 949 (void) chmod(vect[0], mode); 950 if (vect[0]) 951 xfree(vect[0]); 952 continue; 953 } 954 omode = mode; 955 mode |= S_IWRITE; 956 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 957 bad: run_err("%s: %s", np, strerror(errno)); 958 continue; 959 } 960 (void) atomicio(vwrite, remout, "", 1); 961 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 962 (void) close(ofd); 963 continue; 964 } 965 cp = bp->buf; 966 wrerr = NO; 967 968 statbytes = 0; 969 if (showprogress) 970 start_progress_meter(curfile, size, &statbytes); 971 for (count = i = 0; i < size; i += 4096) { 972 amt = 4096; 973 if (i + amt > size) 974 amt = size - i; 975 count += amt; 976 do { 977 j = atomicio(read, remin, cp, amt); 978 if (j == 0) { 979 run_err("%s", j ? strerror(errno) : 980 "dropped connection"); 981 exit(1); 982 } 983 amt -= j; 984 cp += j; 985 statbytes += j; 986 } while (amt > 0); 987 988 if (limit_rate) 989 bwlimit(4096); 990 991 if (count == bp->cnt) { 992 /* Keep reading so we stay sync'd up. */ 993 if (wrerr == NO) { 994 if (atomicio(vwrite, ofd, bp->buf, 995 count) != count) { 996 wrerr = YES; 997 wrerrno = errno; 998 } 999 } 1000 count = 0; 1001 cp = bp->buf; 1002 } 1003 } 1004 if (showprogress) 1005 stop_progress_meter(); 1006 if (count != 0 && wrerr == NO && 1007 atomicio(vwrite, ofd, bp->buf, count) != count) { 1008 wrerr = YES; 1009 wrerrno = errno; 1010 } 1011 if (wrerr == NO && ftruncate(ofd, size) != 0) { 1012 run_err("%s: truncate: %s", np, strerror(errno)); 1013 wrerr = DISPLAYED; 1014 } 1015 if (pflag) { 1016 if (exists || omode != mode) 1017 if (fchmod(ofd, omode)) { 1018 run_err("%s: set mode: %s", 1019 np, strerror(errno)); 1020 wrerr = DISPLAYED; 1021 } 1022 } else { 1023 if (!exists && omode != mode) 1024 if (fchmod(ofd, omode & ~mask)) { 1025 run_err("%s: set mode: %s", 1026 np, strerror(errno)); 1027 wrerr = DISPLAYED; 1028 } 1029 } 1030 if (close(ofd) == -1) { 1031 wrerr = YES; 1032 wrerrno = errno; 1033 } 1034 (void) response(); 1035 if (setimes && wrerr == NO) { 1036 setimes = 0; 1037 if (utimes(np, tv) < 0) { 1038 run_err("%s: set times: %s", 1039 np, strerror(errno)); 1040 wrerr = DISPLAYED; 1041 } 1042 } 1043 switch (wrerr) { 1044 case YES: 1045 run_err("%s: %s", np, strerror(wrerrno)); 1046 break; 1047 case NO: 1048 (void) atomicio(vwrite, remout, "", 1); 1049 break; 1050 case DISPLAYED: 1051 break; 1052 } 1053 } 1054 screwup: 1055 run_err("protocol error: %s", why); 1056 exit(1); 1057 } 1058 1059 int 1060 response(void) 1061 { 1062 char ch, *cp, resp, rbuf[2048]; 1063 1064 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) 1065 lostconn(0); 1066 1067 cp = rbuf; 1068 switch (resp) { 1069 case 0: /* ok */ 1070 return (0); 1071 default: 1072 *cp++ = resp; 1073 /* FALLTHROUGH */ 1074 case 1: /* error, followed by error msg */ 1075 case 2: /* fatal error, "" */ 1076 do { 1077 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 1078 lostconn(0); 1079 *cp++ = ch; 1080 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 1081 1082 if (!iamremote) 1083 (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf); 1084 ++errs; 1085 if (resp == 1) 1086 return (-1); 1087 exit(1); 1088 } 1089 /* NOTREACHED */ 1090 } 1091 1092 void 1093 usage(void) 1094 { 1095 (void) fprintf(stderr, 1096 "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1097 " [-l limit] [-o ssh_option] [-P port] [-S program]\n" 1098 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); 1099 exit(1); 1100 } 1101 1102 void 1103 run_err(const char *fmt,...) 1104 { 1105 static FILE *fp; 1106 va_list ap; 1107 1108 ++errs; 1109 if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) { 1110 (void) fprintf(fp, "%c", 0x01); 1111 (void) fprintf(fp, "scp: "); 1112 va_start(ap, fmt); 1113 (void) vfprintf(fp, fmt, ap); 1114 va_end(ap); 1115 (void) fprintf(fp, "\n"); 1116 (void) fflush(fp); 1117 } 1118 1119 if (!iamremote) { 1120 va_start(ap, fmt); 1121 vfprintf(stderr, fmt, ap); 1122 va_end(ap); 1123 fprintf(stderr, "\n"); 1124 } 1125 } 1126 1127 void 1128 verifydir(char *cp) 1129 { 1130 struct stat stb; 1131 1132 if (!stat(cp, &stb)) { 1133 if (S_ISDIR(stb.st_mode)) 1134 return; 1135 errno = ENOTDIR; 1136 } 1137 run_err("%s: %s", cp, strerror(errno)); 1138 killchild(0); 1139 } 1140 1141 int 1142 okname(char *cp0) 1143 { 1144 int c; 1145 char *cp; 1146 1147 cp = cp0; 1148 do { 1149 c = (int)*cp; 1150 if (c & 0200) 1151 goto bad; 1152 if (!isalpha(c) && !isdigit(c)) { 1153 switch (c) { 1154 case '\'': 1155 case '"': 1156 case '`': 1157 case ' ': 1158 case '#': 1159 goto bad; 1160 default: 1161 break; 1162 } 1163 } 1164 } while (*++cp); 1165 return (1); 1166 1167 bad: fprintf(stderr, "%s: invalid user name\n", cp0); 1168 return (0); 1169 } 1170 1171 BUF * 1172 allocbuf(BUF *bp, int fd, int blksize) 1173 { 1174 size_t size; 1175 struct stat stb; 1176 1177 if (fstat(fd, &stb) < 0) { 1178 run_err("fstat: %s", strerror(errno)); 1179 return (0); 1180 } 1181 size = roundup(stb.st_blksize, blksize); 1182 if (size == 0) 1183 size = blksize; 1184 if (bp->cnt >= size) 1185 return (bp); 1186 if (bp->buf == NULL) 1187 bp->buf = xmalloc(size); 1188 else 1189 bp->buf = xrealloc(bp->buf, 1, size); 1190 memset(bp->buf, 0, size); 1191 bp->cnt = size; 1192 return (bp); 1193 } 1194 1195 void 1196 lostconn(int signo) 1197 { 1198 if (!iamremote) 1199 write(STDERR_FILENO, "lost connection\n", 16); 1200 if (signo) 1201 _exit(1); 1202 else 1203 exit(1); 1204 } 1205