scp.c (181110) | scp.c (181111) |
---|---|
1/* $OpenBSD: scp.c,v 1.155 2006/08/03 03:34:42 deraadt Exp $ */ | 1/* $OpenBSD: scp.c,v 1.163 2008/06/13 18:55:22 dtucker Exp $ */ |
2/* 3 * scp - secure remote copy. This is basically patched BSD rcp which 4 * uses ssh to do the data transfer (instead of using rcmd). 5 * 6 * NOTE: This version should NOT be suid root. (This uses ssh to 7 * do the transfer and ssh has the necessary privileges.) 8 * 9 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> --- 63 unchanged lines hidden (view full) --- 73 74#include "includes.h" 75 76#include <sys/types.h> 77#include <sys/param.h> 78#ifdef HAVE_SYS_STAT_H 79# include <sys/stat.h> 80#endif | 2/* 3 * scp - secure remote copy. This is basically patched BSD rcp which 4 * uses ssh to do the data transfer (instead of using rcmd). 5 * 6 * NOTE: This version should NOT be suid root. (This uses ssh to 7 * do the transfer and ssh has the necessary privileges.) 8 * 9 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> --- 63 unchanged lines hidden (view full) --- 73 74#include "includes.h" 75 76#include <sys/types.h> 77#include <sys/param.h> 78#ifdef HAVE_SYS_STAT_H 79# include <sys/stat.h> 80#endif |
81#ifdef HAVE_POLL_H 82#include <poll.h> 83#else 84# ifdef HAVE_SYS_POLL_H 85# include <sys/poll.h> 86# endif 87#endif |
|
81#ifdef HAVE_SYS_TIME_H 82# include <sys/time.h> 83#endif 84#include <sys/wait.h> 85#include <sys/uio.h> 86 87#include <ctype.h> 88#include <dirent.h> 89#include <errno.h> 90#include <fcntl.h> 91#include <pwd.h> 92#include <signal.h> 93#include <stdarg.h> 94#include <stdio.h> 95#include <stdlib.h> 96#include <string.h> 97#include <time.h> 98#include <unistd.h> | 88#ifdef HAVE_SYS_TIME_H 89# include <sys/time.h> 90#endif 91#include <sys/wait.h> 92#include <sys/uio.h> 93 94#include <ctype.h> 95#include <dirent.h> 96#include <errno.h> 97#include <fcntl.h> 98#include <pwd.h> 99#include <signal.h> 100#include <stdarg.h> 101#include <stdio.h> 102#include <stdlib.h> 103#include <string.h> 104#include <time.h> 105#include <unistd.h> |
106#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) 107#include <vis.h> 108#endif |
|
99 100#include "xmalloc.h" 101#include "atomicio.h" 102#include "pathnames.h" 103#include "log.h" 104#include "misc.h" 105#include "progressmeter.h" 106 107extern char *__progname; 108 | 109 110#include "xmalloc.h" 111#include "atomicio.h" 112#include "pathnames.h" 113#include "log.h" 114#include "misc.h" 115#include "progressmeter.h" 116 117extern char *__progname; 118 |
119#define COPY_BUFLEN 16384 120 |
|
109int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 110 111void bwlimit(int); 112 113/* Struct for addargs */ 114arglist args; 115 116/* Bandwidth limit */ --- 157 unchanged lines hidden (view full) --- 274char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 275 276int response(void); 277void rsource(char *, struct stat *); 278void sink(int, char *[]); 279void source(int, char *[]); 280void tolocal(int, char *[]); 281void toremote(char *, int, char *[]); | 121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 122 123void bwlimit(int); 124 125/* Struct for addargs */ 126arglist args; 127 128/* Bandwidth limit */ --- 157 unchanged lines hidden (view full) --- 286char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 287 288int response(void); 289void rsource(char *, struct stat *); 290void sink(int, char *[]); 291void source(int, char *[]); 292void tolocal(int, char *[]); 293void toremote(char *, int, char *[]); |
294size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *); |
|
282void usage(void); 283 284int 285main(int argc, char **argv) 286{ 287 int ch, fflag, tflag, status, n; 288 double speed; 289 char *targ, *endp, **newargv; --- 85 unchanged lines hidden (view full) --- 375 usage(); 376 } 377 argc -= optind; 378 argv += optind; 379 380 if ((pwd = getpwuid(userid = getuid())) == NULL) 381 fatal("unknown user %u", (u_int) userid); 382 | 295void usage(void); 296 297int 298main(int argc, char **argv) 299{ 300 int ch, fflag, tflag, status, n; 301 double speed; 302 char *targ, *endp, **newargv; --- 85 unchanged lines hidden (view full) --- 388 usage(); 389 } 390 argc -= optind; 391 argv += optind; 392 393 if ((pwd = getpwuid(userid = getuid())) == NULL) 394 fatal("unknown user %u", (u_int) userid); 395 |
383 if (!isatty(STDERR_FILENO)) | 396 if (!isatty(STDOUT_FILENO)) |
384 showprogress = 0; 385 386 remin = STDIN_FILENO; 387 remout = STDOUT_FILENO; 388 389 if (fflag) { 390 /* Follow "protocol", send data. */ 391 (void) response(); --- 41 unchanged lines hidden (view full) --- 433 else { 434 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 435 errs = 1; 436 } 437 } 438 exit(errs != 0); 439} 440 | 397 showprogress = 0; 398 399 remin = STDIN_FILENO; 400 remout = STDOUT_FILENO; 401 402 if (fflag) { 403 /* Follow "protocol", send data. */ 404 (void) response(); --- 41 unchanged lines hidden (view full) --- 446 else { 447 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 448 errs = 1; 449 } 450 } 451 exit(errs != 0); 452} 453 |
454/* 455 * atomicio-like wrapper that also applies bandwidth limits and updates 456 * the progressmeter counter. 457 */ 458size_t 459scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c) 460{ 461 u_char *p = (u_char *)_p; 462 size_t offset; 463 ssize_t r; 464 struct pollfd pfd; 465 466 pfd.fd = fd; 467 pfd.events = f == read ? POLLIN : POLLOUT; 468 for (offset = 0; offset < l;) { 469 r = f(fd, p + offset, l - offset); 470 if (r == 0) { 471 errno = EPIPE; 472 return offset; 473 } 474 if (r < 0) { 475 if (errno == EINTR) 476 continue; 477 if (errno == EAGAIN || errno == EWOULDBLOCK) { 478 (void)poll(&pfd, 1, -1); /* Ignore errors */ 479 continue; 480 } 481 return offset; 482 } 483 offset += (size_t)r; 484 *c += (off_t)r; 485 if (limit_rate) 486 bwlimit(r); 487 } 488 return offset; 489} 490 |
|
441void 442toremote(char *targ, int argc, char **argv) 443{ 444 char *bp, *host, *src, *suser, *thost, *tuser, *arg; 445 arglist alist; 446 int i; 447 448 memset(&alist, '\0', sizeof(alist)); --- 125 unchanged lines hidden (view full) --- 574} 575 576void 577source(int argc, char **argv) 578{ 579 struct stat stb; 580 static BUF buffer; 581 BUF *bp; | 491void 492toremote(char *targ, int argc, char **argv) 493{ 494 char *bp, *host, *src, *suser, *thost, *tuser, *arg; 495 arglist alist; 496 int i; 497 498 memset(&alist, '\0', sizeof(alist)); --- 125 unchanged lines hidden (view full) --- 624} 625 626void 627source(int argc, char **argv) 628{ 629 struct stat stb; 630 static BUF buffer; 631 BUF *bp; |
582 off_t i, amt, statbytes; 583 size_t result; | 632 off_t i, statbytes; 633 size_t amt; |
584 int fd = -1, haderr, indx; | 634 int fd = -1, haderr, indx; |
585 char *last, *name, buf[2048]; | 635 char *last, *name, buf[2048], encname[MAXPATHLEN]; |
586 int len; 587 588 for (indx = 0; indx < argc; ++indx) { 589 name = argv[indx]; 590 statbytes = 0; 591 len = strlen(name); 592 while (len > 1 && name[len-1] == '/') 593 name[--len] = '\0'; | 636 int len; 637 638 for (indx = 0; indx < argc; ++indx) { 639 name = argv[indx]; 640 statbytes = 0; 641 len = strlen(name); 642 while (len > 1 && name[len-1] == '/') 643 name[--len] = '\0'; |
644 if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0) 645 goto syserr; |
|
594 if (strchr(name, '\n') != NULL) { | 646 if (strchr(name, '\n') != NULL) { |
595 run_err("%s: skipping, filename contains a newline", 596 name); 597 goto next; | 647 strnvis(encname, name, sizeof(encname), VIS_NL); 648 name = encname; |
598 } | 649 } |
599 if ((fd = open(name, O_RDONLY, 0)) < 0) 600 goto syserr; | |
601 if (fstat(fd, &stb) < 0) { 602syserr: run_err("%s: %s", name, strerror(errno)); 603 goto next; 604 } | 650 if (fstat(fd, &stb) < 0) { 651syserr: run_err("%s: %s", name, strerror(errno)); 652 goto next; 653 } |
654 if (stb.st_size < 0) { 655 run_err("%s: %s", name, "Negative file size"); 656 goto next; 657 } 658 unset_nonblock(fd); |
|
605 switch (stb.st_mode & S_IFMT) { 606 case S_IFREG: 607 break; 608 case S_IFDIR: 609 if (iamrecursive) { 610 rsource(name, &stb); 611 goto next; 612 } --- 8 unchanged lines hidden (view full) --- 621 ++last; 622 curfile = last; 623 if (pflag) { 624 /* 625 * Make it compatible with possible future 626 * versions expecting microseconds. 627 */ 628 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", | 659 switch (stb.st_mode & S_IFMT) { 660 case S_IFREG: 661 break; 662 case S_IFDIR: 663 if (iamrecursive) { 664 rsource(name, &stb); 665 goto next; 666 } --- 8 unchanged lines hidden (view full) --- 675 ++last; 676 curfile = last; 677 if (pflag) { 678 /* 679 * Make it compatible with possible future 680 * versions expecting microseconds. 681 */ 682 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", |
629 (u_long) stb.st_mtime, 630 (u_long) stb.st_atime); | 683 (u_long) (stb.st_mtime < 0 ? 0 : stb.st_mtime), 684 (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime)); 685 if (verbose_mode) { 686 fprintf(stderr, "File mtime %ld atime %ld\n", 687 (long)stb.st_mtime, (long)stb.st_atime); 688 fprintf(stderr, "Sending file timestamps: %s", 689 buf); 690 } |
631 (void) atomicio(vwrite, remout, buf, strlen(buf)); 632 if (response() < 0) 633 goto next; 634 } 635#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 636 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 637 (u_int) (stb.st_mode & FILEMODEMASK), 638 (long long)stb.st_size, last); 639 if (verbose_mode) { 640 fprintf(stderr, "Sending file modes: %s", buf); 641 } 642 (void) atomicio(vwrite, remout, buf, strlen(buf)); 643 if (response() < 0) 644 goto next; | 691 (void) atomicio(vwrite, remout, buf, strlen(buf)); 692 if (response() < 0) 693 goto next; 694 } 695#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 696 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 697 (u_int) (stb.st_mode & FILEMODEMASK), 698 (long long)stb.st_size, last); 699 if (verbose_mode) { 700 fprintf(stderr, "Sending file modes: %s", buf); 701 } 702 (void) atomicio(vwrite, remout, buf, strlen(buf)); 703 if (response() < 0) 704 goto next; |
645 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { | 705 if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) { |
646next: if (fd != -1) { 647 (void) close(fd); 648 fd = -1; 649 } 650 continue; 651 } 652 if (showprogress) 653 start_progress_meter(curfile, stb.st_size, &statbytes); | 706next: if (fd != -1) { 707 (void) close(fd); 708 fd = -1; 709 } 710 continue; 711 } 712 if (showprogress) 713 start_progress_meter(curfile, stb.st_size, &statbytes); |
654 /* Keep writing after an error so that we stay sync'd up. */ | 714 set_nonblock(remout); |
655 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 656 amt = bp->cnt; | 715 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 716 amt = bp->cnt; |
657 if (i + amt > stb.st_size) | 717 if (i + (off_t)amt > stb.st_size) |
658 amt = stb.st_size - i; 659 if (!haderr) { | 718 amt = stb.st_size - i; 719 if (!haderr) { |
660 result = atomicio(read, fd, bp->buf, amt); 661 if (result != amt) | 720 if (atomicio(read, fd, bp->buf, amt) != amt) |
662 haderr = errno; 663 } | 721 haderr = errno; 722 } |
664 if (haderr) 665 (void) atomicio(vwrite, remout, bp->buf, amt); 666 else { 667 result = atomicio(vwrite, remout, bp->buf, amt); 668 if (result != amt) 669 haderr = errno; 670 statbytes += result; | 723 /* Keep writing after error to retain sync */ 724 if (haderr) { 725 (void)atomicio(vwrite, remout, bp->buf, amt); 726 continue; |
671 } | 727 } |
672 if (limit_rate) 673 bwlimit(amt); | 728 if (scpio(vwrite, remout, bp->buf, amt, 729 &statbytes) != amt) 730 haderr = errno; |
674 } | 731 } |
732 unset_nonblock(remout); |
|
675 if (showprogress) 676 stop_progress_meter(); 677 678 if (fd != -1) { 679 if (close(fd) < 0 && !haderr) 680 haderr = errno; 681 fd = -1; 682 } --- 89 unchanged lines hidden (view full) --- 772 if (timercmp(&bwstart, &bwend, >)) { 773 timersub(&bwstart, &bwend, &bwend); 774 775 /* Adjust the wait time */ 776 if (bwend.tv_sec) { 777 thresh /= 2; 778 if (thresh < 2048) 779 thresh = 2048; | 733 if (showprogress) 734 stop_progress_meter(); 735 736 if (fd != -1) { 737 if (close(fd) < 0 && !haderr) 738 haderr = errno; 739 fd = -1; 740 } --- 89 unchanged lines hidden (view full) --- 830 if (timercmp(&bwstart, &bwend, >)) { 831 timersub(&bwstart, &bwend, &bwend); 832 833 /* Adjust the wait time */ 834 if (bwend.tv_sec) { 835 thresh /= 2; 836 if (thresh < 2048) 837 thresh = 2048; |
780 } else if (bwend.tv_usec < 100) { | 838 } else if (bwend.tv_usec < 10000) { |
781 thresh *= 2; | 839 thresh *= 2; |
782 if (thresh > 32768) 783 thresh = 32768; | 840 if (thresh > COPY_BUFLEN * 4) 841 thresh = COPY_BUFLEN * 4; |
784 } 785 786 TIMEVAL_TO_TIMESPEC(&bwend, &ts); 787 while (nanosleep(&ts, &rm) == -1) { 788 if (errno != EINTR) 789 break; 790 ts = rm; 791 } --- 174 unchanged lines hidden (view full) --- 966 } 967 omode = mode; 968 mode |= S_IWRITE; 969 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 970bad: run_err("%s: %s", np, strerror(errno)); 971 continue; 972 } 973 (void) atomicio(vwrite, remout, "", 1); | 842 } 843 844 TIMEVAL_TO_TIMESPEC(&bwend, &ts); 845 while (nanosleep(&ts, &rm) == -1) { 846 if (errno != EINTR) 847 break; 848 ts = rm; 849 } --- 174 unchanged lines hidden (view full) --- 1024 } 1025 omode = mode; 1026 mode |= S_IWRITE; 1027 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 1028bad: run_err("%s: %s", np, strerror(errno)); 1029 continue; 1030 } 1031 (void) atomicio(vwrite, remout, "", 1); |
974 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { | 1032 if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { |
975 (void) close(ofd); 976 continue; 977 } 978 cp = bp->buf; 979 wrerr = NO; 980 981 statbytes = 0; 982 if (showprogress) 983 start_progress_meter(curfile, size, &statbytes); | 1033 (void) close(ofd); 1034 continue; 1035 } 1036 cp = bp->buf; 1037 wrerr = NO; 1038 1039 statbytes = 0; 1040 if (showprogress) 1041 start_progress_meter(curfile, size, &statbytes); |
984 for (count = i = 0; i < size; i += 4096) { 985 amt = 4096; | 1042 set_nonblock(remin); 1043 for (count = i = 0; i < size; i += bp->cnt) { 1044 amt = bp->cnt; |
986 if (i + amt > size) 987 amt = size - i; 988 count += amt; 989 do { | 1045 if (i + amt > size) 1046 amt = size - i; 1047 count += amt; 1048 do { |
990 j = atomicio(read, remin, cp, amt); | 1049 j = scpio(read, remin, cp, amt, &statbytes); |
991 if (j == 0) { | 1050 if (j == 0) { |
992 run_err("%s", j ? strerror(errno) : | 1051 run_err("%s", j != EPIPE ? 1052 strerror(errno) : |
993 "dropped connection"); 994 exit(1); 995 } 996 amt -= j; 997 cp += j; | 1053 "dropped connection"); 1054 exit(1); 1055 } 1056 amt -= j; 1057 cp += j; |
998 statbytes += j; | |
999 } while (amt > 0); 1000 | 1058 } while (amt > 0); 1059 |
1001 if (limit_rate) 1002 bwlimit(4096); 1003 | |
1004 if (count == bp->cnt) { 1005 /* Keep reading so we stay sync'd up. */ 1006 if (wrerr == NO) { 1007 if (atomicio(vwrite, ofd, bp->buf, 1008 count) != count) { 1009 wrerr = YES; 1010 wrerrno = errno; 1011 } 1012 } 1013 count = 0; 1014 cp = bp->buf; 1015 } 1016 } | 1060 if (count == bp->cnt) { 1061 /* Keep reading so we stay sync'd up. */ 1062 if (wrerr == NO) { 1063 if (atomicio(vwrite, ofd, bp->buf, 1064 count) != count) { 1065 wrerr = YES; 1066 wrerrno = errno; 1067 } 1068 } 1069 count = 0; 1070 cp = bp->buf; 1071 } 1072 } |
1073 unset_nonblock(remin); |
|
1017 if (showprogress) 1018 stop_progress_meter(); 1019 if (count != 0 && wrerr == NO && 1020 atomicio(vwrite, ofd, bp->buf, count) != count) { 1021 wrerr = YES; 1022 wrerrno = errno; 1023 } | 1074 if (showprogress) 1075 stop_progress_meter(); 1076 if (count != 0 && wrerr == NO && 1077 atomicio(vwrite, ofd, bp->buf, count) != count) { 1078 wrerr = YES; 1079 wrerrno = errno; 1080 } |
1024 if (wrerr == NO && ftruncate(ofd, size) != 0) { | 1081 if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) && 1082 ftruncate(ofd, size) != 0) { |
1025 run_err("%s: truncate: %s", np, strerror(errno)); 1026 wrerr = DISPLAYED; 1027 } 1028 if (pflag) { 1029 if (exists || omode != mode) 1030#ifdef HAVE_FCHMOD 1031 if (fchmod(ofd, omode)) { 1032#else /* HAVE_FCHMOD */ --- 78 unchanged lines hidden (view full) --- 1111} 1112 1113void 1114usage(void) 1115{ 1116 (void) fprintf(stderr, 1117 "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1118 " [-l limit] [-o ssh_option] [-P port] [-S program]\n" | 1083 run_err("%s: truncate: %s", np, strerror(errno)); 1084 wrerr = DISPLAYED; 1085 } 1086 if (pflag) { 1087 if (exists || omode != mode) 1088#ifdef HAVE_FCHMOD 1089 if (fchmod(ofd, omode)) { 1090#else /* HAVE_FCHMOD */ --- 78 unchanged lines hidden (view full) --- 1169} 1170 1171void 1172usage(void) 1173{ 1174 (void) fprintf(stderr, 1175 "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1176 " [-l limit] [-o ssh_option] [-P port] [-S program]\n" |
1119 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); | 1177 " [[user@]host1:]file1 ... [[user@]host2:]file2\n"); |
1120 exit(1); 1121} 1122 1123void 1124run_err(const char *fmt,...) 1125{ 1126 static FILE *fp; 1127 va_list ap; --- 102 unchanged lines hidden --- | 1178 exit(1); 1179} 1180 1181void 1182run_err(const char *fmt,...) 1183{ 1184 static FILE *fp; 1185 va_list ap; --- 102 unchanged lines hidden --- |