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