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