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