1 /* $OpenBSD: scp.c,v 1.203 2019/01/27 07:14:11 jmc 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/types.h> 75 #include <sys/poll.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 <fnmatch.h> 86 #include <locale.h> 87 #include <pwd.h> 88 #include <signal.h> 89 #include <stdarg.h> 90 #include <stdint.h> 91 #include <stdio.h> 92 #include <stdlib.h> 93 #include <string.h> 94 #include <time.h> 95 #include <unistd.h> 96 #include <limits.h> 97 #include <vis.h> 98 99 #include "xmalloc.h" 100 #include "ssh.h" 101 #include "atomicio.h" 102 #include "pathnames.h" 103 #include "log.h" 104 #include "misc.h" 105 #include "progressmeter.h" 106 #include "utf8.h" 107 108 #define COPY_BUFLEN 16384 109 110 int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout); 111 int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout); 112 113 /* Struct for addargs */ 114 arglist args; 115 arglist remote_remote_args; 116 117 /* Bandwidth limit */ 118 long long limit_kbps = 0; 119 struct bwlimit bwlimit; 120 121 /* Name of current file being transferred. */ 122 char *curfile; 123 124 /* This is set to non-zero to enable verbose mode. */ 125 int verbose_mode = 0; 126 127 /* This is set to zero if the progressmeter is not desired. */ 128 int showprogress = 1; 129 130 /* 131 * This is set to non-zero if remote-remote copy should be piped 132 * through this process. 133 */ 134 int throughlocal = 0; 135 136 /* Non-standard port to use for the ssh connection or -1. */ 137 int sshport = -1; 138 139 /* This is the program to execute for the secured connection. ("ssh" or -S) */ 140 char *ssh_program = _PATH_SSH_PROGRAM; 141 142 /* This is used to store the pid of ssh_program */ 143 pid_t do_cmd_pid = -1; 144 145 static void 146 killchild(int signo) 147 { 148 if (do_cmd_pid > 1) { 149 kill(do_cmd_pid, signo ? signo : SIGTERM); 150 waitpid(do_cmd_pid, NULL, 0); 151 } 152 153 if (signo) 154 _exit(1); 155 exit(1); 156 } 157 158 static void 159 suspchild(int signo) 160 { 161 int status; 162 163 if (do_cmd_pid > 1) { 164 kill(do_cmd_pid, signo); 165 while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 && 166 errno == EINTR) 167 ; 168 kill(getpid(), SIGSTOP); 169 } 170 } 171 172 static int 173 do_local_cmd(arglist *a) 174 { 175 u_int i; 176 int status; 177 pid_t pid; 178 179 if (a->num == 0) 180 fatal("do_local_cmd: no arguments"); 181 182 if (verbose_mode) { 183 fprintf(stderr, "Executing:"); 184 for (i = 0; i < a->num; i++) 185 fmprintf(stderr, " %s", a->list[i]); 186 fprintf(stderr, "\n"); 187 } 188 if ((pid = fork()) == -1) 189 fatal("do_local_cmd: fork: %s", strerror(errno)); 190 191 if (pid == 0) { 192 execvp(a->list[0], a->list); 193 perror(a->list[0]); 194 exit(1); 195 } 196 197 do_cmd_pid = pid; 198 signal(SIGTERM, killchild); 199 signal(SIGINT, killchild); 200 signal(SIGHUP, killchild); 201 202 while (waitpid(pid, &status, 0) == -1) 203 if (errno != EINTR) 204 fatal("do_local_cmd: waitpid: %s", strerror(errno)); 205 206 do_cmd_pid = -1; 207 208 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 209 return (-1); 210 211 return (0); 212 } 213 214 /* 215 * This function executes the given command as the specified user on the 216 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 217 * assigns the input and output file descriptors on success. 218 */ 219 220 int 221 do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout) 222 { 223 int pin[2], pout[2], reserved[2]; 224 225 if (verbose_mode) 226 fmprintf(stderr, 227 "Executing: program %s host %s, user %s, command %s\n", 228 ssh_program, host, 229 remuser ? remuser : "(unspecified)", cmd); 230 231 if (port == -1) 232 port = sshport; 233 234 /* 235 * Reserve two descriptors so that the real pipes won't get 236 * descriptors 0 and 1 because that will screw up dup2 below. 237 */ 238 if (pipe(reserved) < 0) 239 fatal("pipe: %s", strerror(errno)); 240 241 /* Create a socket pair for communicating with ssh. */ 242 if (pipe(pin) < 0) 243 fatal("pipe: %s", strerror(errno)); 244 if (pipe(pout) < 0) 245 fatal("pipe: %s", strerror(errno)); 246 247 /* Free the reserved descriptors. */ 248 close(reserved[0]); 249 close(reserved[1]); 250 251 signal(SIGTSTP, suspchild); 252 signal(SIGTTIN, suspchild); 253 signal(SIGTTOU, suspchild); 254 255 /* Fork a child to execute the command on the remote host using ssh. */ 256 do_cmd_pid = fork(); 257 if (do_cmd_pid == 0) { 258 /* Child. */ 259 close(pin[1]); 260 close(pout[0]); 261 dup2(pin[0], 0); 262 dup2(pout[1], 1); 263 close(pin[0]); 264 close(pout[1]); 265 266 replacearg(&args, 0, "%s", ssh_program); 267 if (port != -1) { 268 addargs(&args, "-p"); 269 addargs(&args, "%d", port); 270 } 271 if (remuser != NULL) { 272 addargs(&args, "-l"); 273 addargs(&args, "%s", remuser); 274 } 275 addargs(&args, "--"); 276 addargs(&args, "%s", host); 277 addargs(&args, "%s", cmd); 278 279 execvp(ssh_program, args.list); 280 perror(ssh_program); 281 exit(1); 282 } else if (do_cmd_pid == -1) { 283 fatal("fork: %s", strerror(errno)); 284 } 285 /* Parent. Close the other side, and return the local side. */ 286 close(pin[0]); 287 *fdout = pin[1]; 288 close(pout[1]); 289 *fdin = pout[0]; 290 signal(SIGTERM, killchild); 291 signal(SIGINT, killchild); 292 signal(SIGHUP, killchild); 293 return 0; 294 } 295 296 /* 297 * This function executes a command similar to do_cmd(), but expects the 298 * input and output descriptors to be setup by a previous call to do_cmd(). 299 * This way the input and output of two commands can be connected. 300 */ 301 int 302 do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout) 303 { 304 pid_t pid; 305 int status; 306 307 if (verbose_mode) 308 fmprintf(stderr, 309 "Executing: 2nd program %s host %s, user %s, command %s\n", 310 ssh_program, host, 311 remuser ? remuser : "(unspecified)", cmd); 312 313 if (port == -1) 314 port = sshport; 315 316 /* Fork a child to execute the command on the remote host using ssh. */ 317 pid = fork(); 318 if (pid == 0) { 319 dup2(fdin, 0); 320 dup2(fdout, 1); 321 322 replacearg(&args, 0, "%s", ssh_program); 323 if (port != -1) { 324 addargs(&args, "-p"); 325 addargs(&args, "%d", port); 326 } 327 if (remuser != NULL) { 328 addargs(&args, "-l"); 329 addargs(&args, "%s", remuser); 330 } 331 addargs(&args, "--"); 332 addargs(&args, "%s", host); 333 addargs(&args, "%s", cmd); 334 335 execvp(ssh_program, args.list); 336 perror(ssh_program); 337 exit(1); 338 } else if (pid == -1) { 339 fatal("fork: %s", strerror(errno)); 340 } 341 while (waitpid(pid, &status, 0) == -1) 342 if (errno != EINTR) 343 fatal("do_cmd2: waitpid: %s", strerror(errno)); 344 return 0; 345 } 346 347 typedef struct { 348 size_t cnt; 349 char *buf; 350 } BUF; 351 352 BUF *allocbuf(BUF *, int, int); 353 void lostconn(int); 354 int okname(char *); 355 void run_err(const char *,...); 356 void verifydir(char *); 357 358 struct passwd *pwd; 359 uid_t userid; 360 int errs, remin, remout; 361 int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; 362 363 #define CMDNEEDS 64 364 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 365 366 int response(void); 367 void rsource(char *, struct stat *); 368 void sink(int, char *[], const char *); 369 void source(int, char *[]); 370 void tolocal(int, char *[]); 371 void toremote(int, char *[]); 372 void usage(void); 373 374 int 375 main(int argc, char **argv) 376 { 377 int ch, fflag, tflag, status, n; 378 char **newargv; 379 const char *errstr; 380 extern char *optarg; 381 extern int optind; 382 383 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 384 sanitise_stdfd(); 385 386 setlocale(LC_CTYPE, ""); 387 388 /* Copy argv, because we modify it */ 389 newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv)); 390 for (n = 0; n < argc; n++) 391 newargv[n] = xstrdup(argv[n]); 392 argv = newargv; 393 394 memset(&args, '\0', sizeof(args)); 395 memset(&remote_remote_args, '\0', sizeof(remote_remote_args)); 396 args.list = remote_remote_args.list = NULL; 397 addargs(&args, "%s", ssh_program); 398 addargs(&args, "-x"); 399 addargs(&args, "-oForwardAgent=no"); 400 addargs(&args, "-oPermitLocalCommand=no"); 401 addargs(&args, "-oClearAllForwardings=yes"); 402 addargs(&args, "-oRemoteCommand=none"); 403 addargs(&args, "-oRequestTTY=no"); 404 405 fflag = Tflag = tflag = 0; 406 while ((ch = getopt(argc, argv, 407 "dfl:prtTvBCc:i:P:q12346S:o:F:J:")) != -1) { 408 switch (ch) { 409 /* User-visible flags. */ 410 case '1': 411 fatal("SSH protocol v.1 is no longer supported"); 412 break; 413 case '2': 414 /* Ignored */ 415 break; 416 case '4': 417 case '6': 418 case 'C': 419 addargs(&args, "-%c", ch); 420 addargs(&remote_remote_args, "-%c", ch); 421 break; 422 case '3': 423 throughlocal = 1; 424 break; 425 case 'o': 426 case 'c': 427 case 'i': 428 case 'F': 429 case 'J': 430 addargs(&remote_remote_args, "-%c", ch); 431 addargs(&remote_remote_args, "%s", optarg); 432 addargs(&args, "-%c", ch); 433 addargs(&args, "%s", optarg); 434 break; 435 case 'P': 436 sshport = a2port(optarg); 437 if (sshport <= 0) 438 fatal("bad port \"%s\"\n", optarg); 439 break; 440 case 'B': 441 addargs(&remote_remote_args, "-oBatchmode=yes"); 442 addargs(&args, "-oBatchmode=yes"); 443 break; 444 case 'l': 445 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 446 &errstr); 447 if (errstr != NULL) 448 usage(); 449 limit_kbps *= 1024; /* kbps */ 450 bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN); 451 break; 452 case 'p': 453 pflag = 1; 454 break; 455 case 'r': 456 iamrecursive = 1; 457 break; 458 case 'S': 459 ssh_program = xstrdup(optarg); 460 break; 461 case 'v': 462 addargs(&args, "-v"); 463 addargs(&remote_remote_args, "-v"); 464 verbose_mode = 1; 465 break; 466 case 'q': 467 addargs(&args, "-q"); 468 addargs(&remote_remote_args, "-q"); 469 showprogress = 0; 470 break; 471 472 /* Server options. */ 473 case 'd': 474 targetshouldbedirectory = 1; 475 break; 476 case 'f': /* "from" */ 477 iamremote = 1; 478 fflag = 1; 479 break; 480 case 't': /* "to" */ 481 iamremote = 1; 482 tflag = 1; 483 break; 484 case 'T': 485 Tflag = 1; 486 break; 487 default: 488 usage(); 489 } 490 } 491 argc -= optind; 492 argv += optind; 493 494 if ((pwd = getpwuid(userid = getuid())) == NULL) 495 fatal("unknown user %u", (u_int) userid); 496 497 if (!isatty(STDOUT_FILENO)) 498 showprogress = 0; 499 500 if (pflag) { 501 /* Cannot pledge: -p allows setuid/setgid files... */ 502 } else { 503 if (pledge("stdio rpath wpath cpath fattr tty proc exec", 504 NULL) == -1) { 505 perror("pledge"); 506 exit(1); 507 } 508 } 509 510 remin = STDIN_FILENO; 511 remout = STDOUT_FILENO; 512 513 if (fflag) { 514 /* Follow "protocol", send data. */ 515 (void) response(); 516 source(argc, argv); 517 exit(errs != 0); 518 } 519 if (tflag) { 520 /* Receive data. */ 521 sink(argc, argv, NULL); 522 exit(errs != 0); 523 } 524 if (argc < 2) 525 usage(); 526 if (argc > 2) 527 targetshouldbedirectory = 1; 528 529 remin = remout = -1; 530 do_cmd_pid = -1; 531 /* Command to be executed on remote system using "ssh". */ 532 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", 533 verbose_mode ? " -v" : "", 534 iamrecursive ? " -r" : "", pflag ? " -p" : "", 535 targetshouldbedirectory ? " -d" : ""); 536 537 (void) signal(SIGPIPE, lostconn); 538 539 if (colon(argv[argc - 1])) /* Dest is remote host. */ 540 toremote(argc, argv); 541 else { 542 if (targetshouldbedirectory) 543 verifydir(argv[argc - 1]); 544 tolocal(argc, argv); /* Dest is local host. */ 545 } 546 /* 547 * Finally check the exit status of the ssh process, if one was forked 548 * and no error has occurred yet 549 */ 550 if (do_cmd_pid != -1 && errs == 0) { 551 if (remin != -1) 552 (void) close(remin); 553 if (remout != -1) 554 (void) close(remout); 555 if (waitpid(do_cmd_pid, &status, 0) == -1) 556 errs = 1; 557 else { 558 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 559 errs = 1; 560 } 561 } 562 exit(errs != 0); 563 } 564 565 /* Callback from atomicio6 to update progress meter and limit bandwidth */ 566 static int 567 scpio(void *_cnt, size_t s) 568 { 569 off_t *cnt = (off_t *)_cnt; 570 571 *cnt += s; 572 refresh_progress_meter(0); 573 if (limit_kbps > 0) 574 bandwidth_limit(&bwlimit, s); 575 return 0; 576 } 577 578 static int 579 do_times(int fd, int verb, const struct stat *sb) 580 { 581 /* strlen(2^64) == 20; strlen(10^6) == 7 */ 582 char buf[(20 + 7 + 2) * 2 + 2]; 583 584 (void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n", 585 (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime), 586 (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime)); 587 if (verb) { 588 fprintf(stderr, "File mtime %lld atime %lld\n", 589 (long long)sb->st_mtime, (long long)sb->st_atime); 590 fprintf(stderr, "Sending file timestamps: %s", buf); 591 } 592 (void) atomicio(vwrite, fd, buf, strlen(buf)); 593 return (response()); 594 } 595 596 static int 597 parse_scp_uri(const char *uri, char **userp, char **hostp, int *portp, 598 char **pathp) 599 { 600 int r; 601 602 r = parse_uri("scp", uri, userp, hostp, portp, pathp); 603 if (r == 0 && *pathp == NULL) 604 *pathp = xstrdup("."); 605 return r; 606 } 607 608 void 609 toremote(int argc, char **argv) 610 { 611 char *suser = NULL, *host = NULL, *src = NULL; 612 char *bp, *tuser, *thost, *targ; 613 int sport = -1, tport = -1; 614 arglist alist; 615 int i, r; 616 u_int j; 617 618 memset(&alist, '\0', sizeof(alist)); 619 alist.list = NULL; 620 621 /* Parse target */ 622 r = parse_scp_uri(argv[argc - 1], &tuser, &thost, &tport, &targ); 623 if (r == -1) { 624 fmprintf(stderr, "%s: invalid uri\n", argv[argc - 1]); 625 ++errs; 626 goto out; 627 } 628 if (r != 0) { 629 if (parse_user_host_path(argv[argc - 1], &tuser, &thost, 630 &targ) == -1) { 631 fmprintf(stderr, "%s: invalid target\n", argv[argc - 1]); 632 ++errs; 633 goto out; 634 } 635 } 636 if (tuser != NULL && !okname(tuser)) { 637 ++errs; 638 goto out; 639 } 640 641 /* Parse source files */ 642 for (i = 0; i < argc - 1; i++) { 643 free(suser); 644 free(host); 645 free(src); 646 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src); 647 if (r == -1) { 648 fmprintf(stderr, "%s: invalid uri\n", argv[i]); 649 ++errs; 650 continue; 651 } 652 if (r != 0) { 653 parse_user_host_path(argv[i], &suser, &host, &src); 654 } 655 if (suser != NULL && !okname(suser)) { 656 ++errs; 657 continue; 658 } 659 if (host && throughlocal) { /* extended remote to remote */ 660 xasprintf(&bp, "%s -f %s%s", cmd, 661 *src == '-' ? "-- " : "", src); 662 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) 663 exit(1); 664 free(bp); 665 xasprintf(&bp, "%s -t %s%s", cmd, 666 *targ == '-' ? "-- " : "", targ); 667 if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0) 668 exit(1); 669 free(bp); 670 (void) close(remin); 671 (void) close(remout); 672 remin = remout = -1; 673 } else if (host) { /* standard remote to remote */ 674 if (tport != -1 && tport != SSH_DEFAULT_PORT) { 675 /* This would require the remote support URIs */ 676 fatal("target port not supported with two " 677 "remote hosts without the -3 option"); 678 } 679 680 freeargs(&alist); 681 addargs(&alist, "%s", ssh_program); 682 addargs(&alist, "-x"); 683 addargs(&alist, "-oClearAllForwardings=yes"); 684 addargs(&alist, "-n"); 685 for (j = 0; j < remote_remote_args.num; j++) { 686 addargs(&alist, "%s", 687 remote_remote_args.list[j]); 688 } 689 690 if (sport != -1) { 691 addargs(&alist, "-p"); 692 addargs(&alist, "%d", sport); 693 } 694 if (suser) { 695 addargs(&alist, "-l"); 696 addargs(&alist, "%s", suser); 697 } 698 addargs(&alist, "--"); 699 addargs(&alist, "%s", host); 700 addargs(&alist, "%s", cmd); 701 addargs(&alist, "%s", src); 702 addargs(&alist, "%s%s%s:%s", 703 tuser ? tuser : "", tuser ? "@" : "", 704 thost, targ); 705 if (do_local_cmd(&alist) != 0) 706 errs = 1; 707 } else { /* local to remote */ 708 if (remin == -1) { 709 xasprintf(&bp, "%s -t %s%s", cmd, 710 *targ == '-' ? "-- " : "", targ); 711 if (do_cmd(thost, tuser, tport, bp, &remin, 712 &remout) < 0) 713 exit(1); 714 if (response() < 0) 715 exit(1); 716 free(bp); 717 } 718 source(1, argv + i); 719 } 720 } 721 out: 722 free(tuser); 723 free(thost); 724 free(targ); 725 free(suser); 726 free(host); 727 free(src); 728 } 729 730 void 731 tolocal(int argc, char **argv) 732 { 733 char *bp, *host = NULL, *src = NULL, *suser = NULL; 734 arglist alist; 735 int i, r, sport = -1; 736 737 memset(&alist, '\0', sizeof(alist)); 738 alist.list = NULL; 739 740 for (i = 0; i < argc - 1; i++) { 741 free(suser); 742 free(host); 743 free(src); 744 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src); 745 if (r == -1) { 746 fmprintf(stderr, "%s: invalid uri\n", argv[i]); 747 ++errs; 748 continue; 749 } 750 if (r != 0) 751 parse_user_host_path(argv[i], &suser, &host, &src); 752 if (suser != NULL && !okname(suser)) { 753 ++errs; 754 continue; 755 } 756 if (!host) { /* Local to local. */ 757 freeargs(&alist); 758 addargs(&alist, "%s", _PATH_CP); 759 if (iamrecursive) 760 addargs(&alist, "-r"); 761 if (pflag) 762 addargs(&alist, "-p"); 763 addargs(&alist, "--"); 764 addargs(&alist, "%s", argv[i]); 765 addargs(&alist, "%s", argv[argc-1]); 766 if (do_local_cmd(&alist)) 767 ++errs; 768 continue; 769 } 770 /* Remote to local. */ 771 xasprintf(&bp, "%s -f %s%s", 772 cmd, *src == '-' ? "-- " : "", src); 773 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) { 774 free(bp); 775 ++errs; 776 continue; 777 } 778 free(bp); 779 sink(1, argv + argc - 1, src); 780 (void) close(remin); 781 remin = remout = -1; 782 } 783 free(suser); 784 free(host); 785 free(src); 786 } 787 788 void 789 source(int argc, char **argv) 790 { 791 struct stat stb; 792 static BUF buffer; 793 BUF *bp; 794 off_t i, statbytes; 795 size_t amt, nr; 796 int fd = -1, haderr, indx; 797 char *last, *name, buf[2048], encname[PATH_MAX]; 798 int len; 799 800 for (indx = 0; indx < argc; ++indx) { 801 name = argv[indx]; 802 statbytes = 0; 803 len = strlen(name); 804 while (len > 1 && name[len-1] == '/') 805 name[--len] = '\0'; 806 if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0) 807 goto syserr; 808 if (strchr(name, '\n') != NULL) { 809 strnvis(encname, name, sizeof(encname), VIS_NL); 810 name = encname; 811 } 812 if (fstat(fd, &stb) < 0) { 813 syserr: run_err("%s: %s", name, strerror(errno)); 814 goto next; 815 } 816 if (stb.st_size < 0) { 817 run_err("%s: %s", name, "Negative file size"); 818 goto next; 819 } 820 unset_nonblock(fd); 821 switch (stb.st_mode & S_IFMT) { 822 case S_IFREG: 823 break; 824 case S_IFDIR: 825 if (iamrecursive) { 826 rsource(name, &stb); 827 goto next; 828 } 829 /* FALLTHROUGH */ 830 default: 831 run_err("%s: not a regular file", name); 832 goto next; 833 } 834 if ((last = strrchr(name, '/')) == NULL) 835 last = name; 836 else 837 ++last; 838 curfile = last; 839 if (pflag) { 840 if (do_times(remout, verbose_mode, &stb) < 0) 841 goto next; 842 } 843 #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 844 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 845 (u_int) (stb.st_mode & FILEMODEMASK), 846 (long long)stb.st_size, last); 847 if (verbose_mode) 848 fmprintf(stderr, "Sending file modes: %s", buf); 849 (void) atomicio(vwrite, remout, buf, strlen(buf)); 850 if (response() < 0) 851 goto next; 852 if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) { 853 next: if (fd != -1) { 854 (void) close(fd); 855 fd = -1; 856 } 857 continue; 858 } 859 if (showprogress) 860 start_progress_meter(curfile, stb.st_size, &statbytes); 861 set_nonblock(remout); 862 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 863 amt = bp->cnt; 864 if (i + (off_t)amt > stb.st_size) 865 amt = stb.st_size - i; 866 if (!haderr) { 867 if ((nr = atomicio(read, fd, 868 bp->buf, amt)) != amt) { 869 haderr = errno; 870 memset(bp->buf + nr, 0, amt - nr); 871 } 872 } 873 /* Keep writing after error to retain sync */ 874 if (haderr) { 875 (void)atomicio(vwrite, remout, bp->buf, amt); 876 memset(bp->buf, 0, amt); 877 continue; 878 } 879 if (atomicio6(vwrite, remout, bp->buf, amt, scpio, 880 &statbytes) != amt) 881 haderr = errno; 882 } 883 unset_nonblock(remout); 884 885 if (fd != -1) { 886 if (close(fd) < 0 && !haderr) 887 haderr = errno; 888 fd = -1; 889 } 890 if (!haderr) 891 (void) atomicio(vwrite, remout, "", 1); 892 else 893 run_err("%s: %s", name, strerror(haderr)); 894 (void) response(); 895 if (showprogress) 896 stop_progress_meter(); 897 } 898 } 899 900 void 901 rsource(char *name, struct stat *statp) 902 { 903 DIR *dirp; 904 struct dirent *dp; 905 char *last, *vect[1], path[PATH_MAX]; 906 907 if (!(dirp = opendir(name))) { 908 run_err("%s: %s", name, strerror(errno)); 909 return; 910 } 911 last = strrchr(name, '/'); 912 if (last == NULL) 913 last = name; 914 else 915 last++; 916 if (pflag) { 917 if (do_times(remout, verbose_mode, statp) < 0) { 918 closedir(dirp); 919 return; 920 } 921 } 922 (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", 923 (u_int) (statp->st_mode & FILEMODEMASK), 0, last); 924 if (verbose_mode) 925 fmprintf(stderr, "Entering directory: %s", path); 926 (void) atomicio(vwrite, remout, path, strlen(path)); 927 if (response() < 0) { 928 closedir(dirp); 929 return; 930 } 931 while ((dp = readdir(dirp)) != NULL) { 932 if (dp->d_ino == 0) 933 continue; 934 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 935 continue; 936 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { 937 run_err("%s/%s: name too long", name, dp->d_name); 938 continue; 939 } 940 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); 941 vect[0] = path; 942 source(1, vect); 943 } 944 (void) closedir(dirp); 945 (void) atomicio(vwrite, remout, "E\n", 2); 946 (void) response(); 947 } 948 949 #define TYPE_OVERFLOW(type, val) \ 950 ((sizeof(type) == 4 && (val) > INT32_MAX) || \ 951 (sizeof(type) == 8 && (val) > INT64_MAX) || \ 952 (sizeof(type) != 4 && sizeof(type) != 8)) 953 954 void 955 sink(int argc, char **argv, const char *src) 956 { 957 static BUF buffer; 958 struct stat stb; 959 enum { 960 YES, NO, DISPLAYED 961 } wrerr; 962 BUF *bp; 963 off_t i; 964 size_t j, count; 965 int amt, exists, first, ofd; 966 mode_t mode, omode, mask; 967 off_t size, statbytes; 968 unsigned long long ull; 969 int setimes, targisdir, wrerrno = 0; 970 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; 971 char *src_copy = NULL, *restrict_pattern = NULL; 972 struct timeval tv[2]; 973 974 #define atime tv[0] 975 #define mtime tv[1] 976 #define SCREWUP(str) { why = str; goto screwup; } 977 978 if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0)) 979 SCREWUP("Unexpected off_t/time_t size"); 980 981 setimes = targisdir = 0; 982 mask = umask(0); 983 if (!pflag) 984 (void) umask(mask); 985 if (argc != 1) { 986 run_err("ambiguous target"); 987 exit(1); 988 } 989 targ = *argv; 990 if (targetshouldbedirectory) 991 verifydir(targ); 992 993 (void) atomicio(vwrite, remout, "", 1); 994 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 995 targisdir = 1; 996 if (src != NULL && !iamrecursive && !Tflag) { 997 /* 998 * Prepare to try to restrict incoming filenames to match 999 * the requested destination file glob. 1000 */ 1001 if ((src_copy = strdup(src)) == NULL) 1002 fatal("strdup failed"); 1003 if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) { 1004 *restrict_pattern++ = '\0'; 1005 } 1006 } 1007 for (first = 1;; first = 0) { 1008 cp = buf; 1009 if (atomicio(read, remin, cp, 1) != 1) 1010 return; 1011 if (*cp++ == '\n') 1012 SCREWUP("unexpected <newline>"); 1013 do { 1014 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 1015 SCREWUP("lost connection"); 1016 *cp++ = ch; 1017 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 1018 *cp = 0; 1019 if (verbose_mode) 1020 fmprintf(stderr, "Sink: %s", buf); 1021 1022 if (buf[0] == '\01' || buf[0] == '\02') { 1023 if (iamremote == 0) { 1024 (void) snmprintf(visbuf, sizeof(visbuf), 1025 NULL, "%s", buf + 1); 1026 (void) atomicio(vwrite, STDERR_FILENO, 1027 visbuf, strlen(visbuf)); 1028 } 1029 if (buf[0] == '\02') 1030 exit(1); 1031 ++errs; 1032 continue; 1033 } 1034 if (buf[0] == 'E') { 1035 (void) atomicio(vwrite, remout, "", 1); 1036 return; 1037 } 1038 if (ch == '\n') 1039 *--cp = 0; 1040 1041 cp = buf; 1042 if (*cp == 'T') { 1043 setimes++; 1044 cp++; 1045 if (!isdigit((unsigned char)*cp)) 1046 SCREWUP("mtime.sec not present"); 1047 ull = strtoull(cp, &cp, 10); 1048 if (!cp || *cp++ != ' ') 1049 SCREWUP("mtime.sec not delimited"); 1050 if (TYPE_OVERFLOW(time_t, ull)) 1051 setimes = 0; /* out of range */ 1052 mtime.tv_sec = ull; 1053 mtime.tv_usec = strtol(cp, &cp, 10); 1054 if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 || 1055 mtime.tv_usec > 999999) 1056 SCREWUP("mtime.usec not delimited"); 1057 if (!isdigit((unsigned char)*cp)) 1058 SCREWUP("atime.sec not present"); 1059 ull = strtoull(cp, &cp, 10); 1060 if (!cp || *cp++ != ' ') 1061 SCREWUP("atime.sec not delimited"); 1062 if (TYPE_OVERFLOW(time_t, ull)) 1063 setimes = 0; /* out of range */ 1064 atime.tv_sec = ull; 1065 atime.tv_usec = strtol(cp, &cp, 10); 1066 if (!cp || *cp++ != '\0' || atime.tv_usec < 0 || 1067 atime.tv_usec > 999999) 1068 SCREWUP("atime.usec not delimited"); 1069 (void) atomicio(vwrite, remout, "", 1); 1070 continue; 1071 } 1072 if (*cp != 'C' && *cp != 'D') { 1073 /* 1074 * Check for the case "rcp remote:foo\* local:bar". 1075 * In this case, the line "No match." can be returned 1076 * by the shell before the rcp command on the remote is 1077 * executed so the ^Aerror_message convention isn't 1078 * followed. 1079 */ 1080 if (first) { 1081 run_err("%s", cp); 1082 exit(1); 1083 } 1084 SCREWUP("expected control record"); 1085 } 1086 mode = 0; 1087 for (++cp; cp < buf + 5; cp++) { 1088 if (*cp < '0' || *cp > '7') 1089 SCREWUP("bad mode"); 1090 mode = (mode << 3) | (*cp - '0'); 1091 } 1092 if (!pflag) 1093 mode &= ~mask; 1094 if (*cp++ != ' ') 1095 SCREWUP("mode not delimited"); 1096 1097 if (!isdigit((unsigned char)*cp)) 1098 SCREWUP("size not present"); 1099 ull = strtoull(cp, &cp, 10); 1100 if (!cp || *cp++ != ' ') 1101 SCREWUP("size not delimited"); 1102 if (TYPE_OVERFLOW(off_t, ull)) 1103 SCREWUP("size out of range"); 1104 size = (off_t)ull; 1105 1106 if (*cp == '\0' || strchr(cp, '/') != NULL || 1107 strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) { 1108 run_err("error: unexpected filename: %s", cp); 1109 exit(1); 1110 } 1111 if (restrict_pattern != NULL && 1112 fnmatch(restrict_pattern, cp, 0) != 0) 1113 SCREWUP("filename does not match request"); 1114 if (targisdir) { 1115 static char *namebuf; 1116 static size_t cursize; 1117 size_t need; 1118 1119 need = strlen(targ) + strlen(cp) + 250; 1120 if (need > cursize) { 1121 free(namebuf); 1122 namebuf = xmalloc(need); 1123 cursize = need; 1124 } 1125 (void) snprintf(namebuf, need, "%s%s%s", targ, 1126 strcmp(targ, "/") ? "/" : "", cp); 1127 np = namebuf; 1128 } else 1129 np = targ; 1130 curfile = cp; 1131 exists = stat(np, &stb) == 0; 1132 if (buf[0] == 'D') { 1133 int mod_flag = pflag; 1134 if (!iamrecursive) 1135 SCREWUP("received directory without -r"); 1136 if (exists) { 1137 if (!S_ISDIR(stb.st_mode)) { 1138 errno = ENOTDIR; 1139 goto bad; 1140 } 1141 if (pflag) 1142 (void) chmod(np, mode); 1143 } else { 1144 /* Handle copying from a read-only 1145 directory */ 1146 mod_flag = 1; 1147 if (mkdir(np, mode | S_IRWXU) < 0) 1148 goto bad; 1149 } 1150 vect[0] = xstrdup(np); 1151 sink(1, vect, src); 1152 if (setimes) { 1153 setimes = 0; 1154 if (utimes(vect[0], tv) < 0) 1155 run_err("%s: set times: %s", 1156 vect[0], strerror(errno)); 1157 } 1158 if (mod_flag) 1159 (void) chmod(vect[0], mode); 1160 free(vect[0]); 1161 continue; 1162 } 1163 omode = mode; 1164 mode |= S_IWUSR; 1165 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 1166 bad: run_err("%s: %s", np, strerror(errno)); 1167 continue; 1168 } 1169 (void) atomicio(vwrite, remout, "", 1); 1170 if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { 1171 (void) close(ofd); 1172 continue; 1173 } 1174 cp = bp->buf; 1175 wrerr = NO; 1176 1177 statbytes = 0; 1178 if (showprogress) 1179 start_progress_meter(curfile, size, &statbytes); 1180 set_nonblock(remin); 1181 for (count = i = 0; i < size; i += bp->cnt) { 1182 amt = bp->cnt; 1183 if (i + amt > size) 1184 amt = size - i; 1185 count += amt; 1186 do { 1187 j = atomicio6(read, remin, cp, amt, 1188 scpio, &statbytes); 1189 if (j == 0) { 1190 run_err("%s", j != EPIPE ? 1191 strerror(errno) : 1192 "dropped connection"); 1193 exit(1); 1194 } 1195 amt -= j; 1196 cp += j; 1197 } while (amt > 0); 1198 1199 if (count == bp->cnt) { 1200 /* Keep reading so we stay sync'd up. */ 1201 if (wrerr == NO) { 1202 if (atomicio(vwrite, ofd, bp->buf, 1203 count) != count) { 1204 wrerr = YES; 1205 wrerrno = errno; 1206 } 1207 } 1208 count = 0; 1209 cp = bp->buf; 1210 } 1211 } 1212 unset_nonblock(remin); 1213 if (count != 0 && wrerr == NO && 1214 atomicio(vwrite, ofd, bp->buf, count) != count) { 1215 wrerr = YES; 1216 wrerrno = errno; 1217 } 1218 if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) && 1219 ftruncate(ofd, size) != 0) { 1220 run_err("%s: truncate: %s", np, strerror(errno)); 1221 wrerr = DISPLAYED; 1222 } 1223 if (pflag) { 1224 if (exists || omode != mode) 1225 if (fchmod(ofd, omode)) { 1226 run_err("%s: set mode: %s", 1227 np, strerror(errno)); 1228 wrerr = DISPLAYED; 1229 } 1230 } else { 1231 if (!exists && omode != mode) 1232 if (fchmod(ofd, omode & ~mask)) { 1233 run_err("%s: set mode: %s", 1234 np, strerror(errno)); 1235 wrerr = DISPLAYED; 1236 } 1237 } 1238 if (close(ofd) == -1) { 1239 wrerr = YES; 1240 wrerrno = errno; 1241 } 1242 (void) response(); 1243 if (showprogress) 1244 stop_progress_meter(); 1245 if (setimes && wrerr == NO) { 1246 setimes = 0; 1247 if (utimes(np, tv) < 0) { 1248 run_err("%s: set times: %s", 1249 np, strerror(errno)); 1250 wrerr = DISPLAYED; 1251 } 1252 } 1253 switch (wrerr) { 1254 case YES: 1255 run_err("%s: %s", np, strerror(wrerrno)); 1256 break; 1257 case NO: 1258 (void) atomicio(vwrite, remout, "", 1); 1259 break; 1260 case DISPLAYED: 1261 break; 1262 } 1263 } 1264 screwup: 1265 run_err("protocol error: %s", why); 1266 exit(1); 1267 } 1268 1269 int 1270 response(void) 1271 { 1272 char ch, *cp, resp, rbuf[2048], visbuf[2048]; 1273 1274 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp)) 1275 lostconn(0); 1276 1277 cp = rbuf; 1278 switch (resp) { 1279 case 0: /* ok */ 1280 return (0); 1281 default: 1282 *cp++ = resp; 1283 /* FALLTHROUGH */ 1284 case 1: /* error, followed by error msg */ 1285 case 2: /* fatal error, "" */ 1286 do { 1287 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 1288 lostconn(0); 1289 *cp++ = ch; 1290 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); 1291 1292 if (!iamremote) { 1293 cp[-1] = '\0'; 1294 (void) snmprintf(visbuf, sizeof(visbuf), 1295 NULL, "%s\n", rbuf); 1296 (void) atomicio(vwrite, STDERR_FILENO, 1297 visbuf, strlen(visbuf)); 1298 } 1299 ++errs; 1300 if (resp == 1) 1301 return (-1); 1302 exit(1); 1303 } 1304 /* NOTREACHED */ 1305 } 1306 1307 void 1308 usage(void) 1309 { 1310 (void) fprintf(stderr, 1311 "usage: scp [-346BCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1312 " [-J destination] [-l limit] [-o ssh_option] [-P port]\n" 1313 " [-S program] source ... target\n"); 1314 exit(1); 1315 } 1316 1317 void 1318 run_err(const char *fmt,...) 1319 { 1320 static FILE *fp; 1321 va_list ap; 1322 1323 ++errs; 1324 if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) { 1325 (void) fprintf(fp, "%c", 0x01); 1326 (void) fprintf(fp, "scp: "); 1327 va_start(ap, fmt); 1328 (void) vfprintf(fp, fmt, ap); 1329 va_end(ap); 1330 (void) fprintf(fp, "\n"); 1331 (void) fflush(fp); 1332 } 1333 1334 if (!iamremote) { 1335 va_start(ap, fmt); 1336 vfmprintf(stderr, fmt, ap); 1337 va_end(ap); 1338 fprintf(stderr, "\n"); 1339 } 1340 } 1341 1342 void 1343 verifydir(char *cp) 1344 { 1345 struct stat stb; 1346 1347 if (!stat(cp, &stb)) { 1348 if (S_ISDIR(stb.st_mode)) 1349 return; 1350 errno = ENOTDIR; 1351 } 1352 run_err("%s: %s", cp, strerror(errno)); 1353 killchild(0); 1354 } 1355 1356 int 1357 okname(char *cp0) 1358 { 1359 int c; 1360 char *cp; 1361 1362 cp = cp0; 1363 do { 1364 c = (int)*cp; 1365 if (c & 0200) 1366 goto bad; 1367 if (!isalpha(c) && !isdigit((unsigned char)c)) { 1368 switch (c) { 1369 case '\'': 1370 case '"': 1371 case '`': 1372 case ' ': 1373 case '#': 1374 goto bad; 1375 default: 1376 break; 1377 } 1378 } 1379 } while (*++cp); 1380 return (1); 1381 1382 bad: fmprintf(stderr, "%s: invalid user name\n", cp0); 1383 return (0); 1384 } 1385 1386 BUF * 1387 allocbuf(BUF *bp, int fd, int blksize) 1388 { 1389 size_t size; 1390 struct stat stb; 1391 1392 if (fstat(fd, &stb) < 0) { 1393 run_err("fstat: %s", strerror(errno)); 1394 return (0); 1395 } 1396 size = ROUNDUP(stb.st_blksize, blksize); 1397 if (size == 0) 1398 size = blksize; 1399 if (bp->cnt >= size) 1400 return (bp); 1401 bp->buf = xrecallocarray(bp->buf, bp->cnt, size, 1); 1402 bp->cnt = size; 1403 return (bp); 1404 } 1405 1406 void 1407 lostconn(int signo) 1408 { 1409 if (!iamremote) 1410 (void)write(STDERR_FILENO, "lost connection\n", 16); 1411 if (signo) 1412 _exit(1); 1413 else 1414 exit(1); 1415 } 1416