1 /* 2 * Copyright 2006 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 } else { 992 if (!exists && omode != mode) 993 #ifdef HAVE_FCHMOD 994 if (fchmod(ofd, omode & ~mask)) 995 #else /* HAVE_FCHMOD */ 996 if (chmod(np, omode & ~mask)) 997 #endif /* HAVE_FCHMOD */ 998 run_err("%s: set mode: %s", 999 np, strerror(errno)); 1000 } 1001 if (close(ofd) == -1) { 1002 wrerr = YES; 1003 wrerrno = errno; 1004 } 1005 (void) response(); 1006 if (setimes && wrerr == NO) { 1007 setimes = 0; 1008 if (utimes(np, tv) < 0) { 1009 run_err("%s: set times: %s", 1010 np, strerror(errno)); 1011 wrerr = DISPLAYED; 1012 } 1013 } 1014 switch (wrerr) { 1015 case YES: 1016 run_err("%s: %s", np, strerror(wrerrno)); 1017 break; 1018 case NO: 1019 (void) atomicio(write, remout, "", 1); 1020 break; 1021 case DISPLAYED: 1022 break; 1023 } 1024 } 1025 screwup: 1026 run_err("protocol error: %s", why); 1027 exit(1); 1028 } 1029 1030 int 1031 response(void) 1032 { 1033 char ch, *cp, resp, rbuf[2048]; 1034 1035 if (atomicio(read, remin, &resp, sizeof (resp)) != sizeof (resp)) 1036 lostconn(0); 1037 1038 cp = rbuf; 1039 switch (resp) { 1040 case 0: /* ok */ 1041 return (0); 1042 default: 1043 *cp++ = resp; 1044 /* FALLTHROUGH */ 1045 case 1: /* error, followed by error msg */ 1046 case 2: /* fatal error, "" */ 1047 do { 1048 if (atomicio(read, remin, &ch, sizeof (ch)) != 1049 sizeof (ch)) 1050 lostconn(0); 1051 *cp++ = ch; 1052 } while (cp < &rbuf[sizeof (rbuf) - 1] && ch != '\n'); 1053 1054 if (!iamremote) 1055 (void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf); 1056 ++errs; 1057 if (resp == 1) 1058 return (-1); 1059 exit(1); 1060 } 1061 /* NOTREACHED */ 1062 } 1063 1064 void 1065 usage(void) 1066 { 1067 (void) fprintf(stderr, 1068 gettext( 1069 "Usage: scp [-pqrvBC46] [-F config] [-S program] [-P port]\n" 1070 " [-c cipher] [-i identity] [-o option]\n" 1071 " [[user@]host1:]file1 [...] " 1072 "[[user@]host2:]file2\n")); 1073 exit(1); 1074 } 1075 1076 /* PRINTFLIKE1 */ 1077 void 1078 run_err(const char *fmt, ...) 1079 { 1080 static FILE *fp; 1081 va_list ap; 1082 1083 ++errs; 1084 1085 if (!iamremote) { 1086 va_start(ap, fmt); 1087 vfprintf(stderr, fmt, ap); 1088 va_end(ap); 1089 fprintf(stderr, "\n"); 1090 } 1091 1092 if (fp == NULL && !(fp = fdopen(remout, "w"))) 1093 return; 1094 1095 (void) fprintf(fp, "%c", 0x01); 1096 (void) fprintf(fp, "scp: "); 1097 va_start(ap, fmt); 1098 (void) vfprintf(fp, fmt, ap); 1099 va_end(ap); 1100 (void) fprintf(fp, "\n"); 1101 (void) fflush(fp); 1102 1103 } 1104 1105 void 1106 verifydir(cp) 1107 char *cp; 1108 { 1109 struct stat stb; 1110 1111 if (!stat(cp, &stb)) { 1112 if (S_ISDIR(stb.st_mode)) 1113 return; 1114 errno = ENOTDIR; 1115 } 1116 run_err("%s: %s", cp, strerror(errno)); 1117 exit(1); 1118 } 1119 1120 int 1121 okname(cp0) 1122 char *cp0; 1123 { 1124 int c; 1125 char *cp; 1126 1127 cp = cp0; 1128 do { 1129 c = (int)*cp; 1130 if (c & 0200) 1131 goto bad; 1132 if (!isalpha(c) && !isdigit(c) && 1133 c != '_' && c != '-' && c != '.' && c != '+') 1134 goto bad; 1135 } while (*++cp); 1136 return (1); 1137 1138 bad: fprintf(stderr, gettext("%s: invalid user name\n"), cp0); 1139 return (0); 1140 } 1141 1142 BUF * 1143 allocbuf(bp, fd, blksize) 1144 BUF *bp; 1145 int fd, blksize; 1146 { 1147 size_t size; 1148 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE 1149 struct stat stb; 1150 1151 if (fstat(fd, &stb) < 0) { 1152 run_err("fstat: %s", strerror(errno)); 1153 return (0); 1154 } 1155 if (stb.st_blksize == 0) 1156 size = blksize; 1157 else 1158 size = blksize + (stb.st_blksize - blksize % stb.st_blksize) % 1159 stb.st_blksize; 1160 #else /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1161 size = blksize; 1162 #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ 1163 if (bp->cnt >= size) 1164 return (bp); 1165 if (bp->buf == NULL) 1166 bp->buf = xmalloc(size); 1167 else 1168 bp->buf = xrealloc(bp->buf, size); 1169 memset(bp->buf, 0, size); 1170 bp->cnt = size; 1171 return (bp); 1172 } 1173 1174 void 1175 lostconn(signo) 1176 int signo; 1177 { 1178 if (!iamremote) 1179 write(STDERR_FILENO, "lost connection\n", 16); 1180 if (signo) 1181 _exit(1); 1182 else 1183 exit(1); 1184 } 1185 1186 static void 1187 updateprogressmeter(int ignore) 1188 { 1189 int save_errno = errno; 1190 1191 progressmeter(0); 1192 signal(SIGALRM, updateprogressmeter); 1193 alarm(PROGRESSTIME); 1194 errno = save_errno; 1195 } 1196 1197 static int 1198 foregroundproc(void) 1199 { 1200 static pid_t pgrp = -1; 1201 int ctty_pgrp; 1202 1203 if (pgrp == -1) 1204 pgrp = getpgrp(); 1205 1206 #ifdef HAVE_TCGETPGRP 1207 return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 && 1208 ctty_pgrp == pgrp); 1209 #else 1210 return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && 1211 ctty_pgrp == pgrp)); 1212 #endif 1213 } 1214 1215 void 1216 progressmeter(int flag) 1217 { 1218 static const char prefixes[] = " KMGTP"; 1219 static struct timeval lastupdate; 1220 static off_t lastsize; 1221 struct timeval now, td, wait; 1222 off_t cursize, abbrevsize; 1223 double elapsed; 1224 int ratio, barlength, i, remaining; 1225 char buf[512]; 1226 1227 if (flag == -1) { 1228 (void) gettimeofday(&start, (struct timezone *)0); 1229 lastupdate = start; 1230 lastsize = 0; 1231 } 1232 if (foregroundproc() == 0) 1233 return; 1234 1235 (void) gettimeofday(&now, (struct timezone *)0); 1236 cursize = statbytes; 1237 if (totalbytes != 0) { 1238 ratio = (int)(100.0 * cursize / totalbytes); 1239 ratio = MAX(ratio, 0); 1240 ratio = MIN(ratio, 100); 1241 } else 1242 ratio = 100; 1243 1244 snprintf(buf, sizeof (buf), "\r%-20.20s %3d%% ", curfile, ratio); 1245 1246 barlength = getttywidth() - 51; 1247 if (barlength > 0) { 1248 i = barlength * ratio / 100; 1249 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1250 "|%.*s%*s|", i, 1251 "*******************************************************" 1252 "*******************************************************" 1253 "*******************************************************" 1254 "*******************************************************" 1255 "*******************************************************" 1256 "*******************************************************" 1257 "*******************************************************", 1258 barlength - i, ""); 1259 } 1260 i = 0; 1261 abbrevsize = cursize; 1262 while (abbrevsize >= 100000 && i < sizeof (prefixes)) { 1263 i++; 1264 abbrevsize >>= 10; 1265 } 1266 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), " %5lu %c%c ", 1267 (unsigned long) abbrevsize, prefixes[i], 1268 prefixes[i] == ' ' ? ' ' : 'B'); 1269 1270 timersub(&now, &lastupdate, &wait); 1271 if (cursize > lastsize) { 1272 lastupdate = now; 1273 lastsize = cursize; 1274 if (wait.tv_sec >= STALLTIME) { 1275 start.tv_sec += wait.tv_sec; 1276 start.tv_usec += wait.tv_usec; 1277 } 1278 wait.tv_sec = 0; 1279 } 1280 timersub(&now, &start, &td); 1281 elapsed = td.tv_sec + (td.tv_usec / 1000000.0); 1282 1283 if (flag != 1 && 1284 (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) { 1285 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1286 " --:-- ETA"); 1287 } else if (wait.tv_sec >= STALLTIME) { 1288 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1289 " - stalled -"); 1290 } else { 1291 if (flag != 1) 1292 remaining = (int)(totalbytes / (statbytes / elapsed) - 1293 elapsed); 1294 else 1295 remaining = (int)elapsed; 1296 1297 i = remaining / 3600; 1298 if (i) 1299 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1300 "%2d:", i); 1301 else 1302 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1303 " "); 1304 i = remaining % 3600; 1305 snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), 1306 "%02d:%02d%s", i / 60, i % 60, 1307 (flag != 1) ? " ETA" : " "); 1308 } 1309 atomicio(write, fileno(stdout), buf, strlen(buf)); 1310 1311 if (flag == -1) { 1312 mysignal(SIGALRM, updateprogressmeter); 1313 alarm(PROGRESSTIME); 1314 } else if (flag == 1) { 1315 alarm(0); 1316 atomicio(write, fileno(stdout), "\n", 1); 1317 statbytes = 0; 1318 } 1319 } 1320 1321 int 1322 getttywidth(void) 1323 { 1324 struct winsize winsize; 1325 1326 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) 1327 return (winsize.ws_col ? winsize.ws_col : 80); 1328 else 1329 return (80); 1330 } 1331