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