Deleted Added
sdiff udiff text old ( 107857 ) new ( 113911 )
full compact
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>

--- 61 unchanged lines hidden (view full) ---

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"
78RCSID("$OpenBSD: scp.c,v 1.102 2003/03/05 22:33:43 markus Exp $");
79RCSID("$FreeBSD: head/crypto/openssh/scp.c 113911 2003-04-23 17:13:13Z des $");
80
81#include "xmalloc.h"
82#include "atomicio.h"
83#include "pathnames.h"
84#include "log.h"
85#include "misc.h"
86#include "progressmeter.h"
87
88#ifdef HAVE___PROGNAME
89extern char *__progname;
90#else
91char *__progname;
92#endif
93
94void bwlimit(int);
95
96/* Struct for addargs */
97arglist args;
98
99/* Bandwidth limit */
100off_t limitbw = 0;
101
102/* Name of current file being transferred. */
103char *curfile;
104
105/* This is set to non-zero to enable verbose mode. */
106int verbose_mode = 0;
107
108/* This is set to zero if the progressmeter is not desired. */
109int showprogress = 1;
110
111/* This is the program to execute for the secured connection. ("ssh" or -S) */
112char *ssh_program = _PATH_SSH_PROGRAM;
113
114/* This is used to store the pid of ssh_program */
115pid_t do_cmd_pid;
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
123int
124do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)

--- 18 unchanged lines hidden (view full) ---

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 /* For 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 return 0;
179}

--- 26 unchanged lines hidden (view full) ---

206void toremote(char *, int, char *[]);
207void usage(void);
208
209int
210main(argc, argv)
211 int argc;
212 char *argv[];
213{
214 int ch, fflag, tflag, status;
215 double speed;
216 char *targ, *endp;
217 extern char *optarg;
218 extern int optind;
219
220 __progname = get_progname(argv[0]);
221
222 args.list = NULL;
223 addargs(&args, "ssh"); /* overwritten with ssh_program */
224 addargs(&args, "-x");
225 addargs(&args, "-oForwardAgent no");
226 addargs(&args, "-oClearAllForwardings yes");
227
228 fflag = tflag = 0;
229 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
230 switch (ch) {
231 /* User-visible flags. */
232 case '1':
233 case '2':
234 case '4':
235 case '6':
236 case 'C':
237 addargs(&args, "-%c", ch);
238 break;
239 case 'o':
240 case 'c':
241 case 'i':
242 case 'F':
243 addargs(&args, "-%c%s", ch, optarg);
244 break;
245 case 'P':
246 addargs(&args, "-p%s", optarg);
247 break;
248 case 'B':
249 addargs(&args, "-oBatchmode yes");
250 break;
251 case 'l':
252 speed = strtod(optarg, &endp);
253 if (speed <= 0 || *endp != '\0')
254 usage();
255 limitbw = speed * 1024;
256 break;
257 case 'p':
258 pflag = 1;
259 break;
260 case 'r':
261 iamrecursive = 1;
262 break;
263 case 'S':
264 ssh_program = xstrdup(optarg);

--- 48 unchanged lines hidden (view full) ---

313 exit(errs != 0);
314 }
315 if (argc < 2)
316 usage();
317 if (argc > 2)
318 targetshouldbedirectory = 1;
319
320 remin = remout = -1;
321 do_cmd_pid = -1;
322 /* Command to be executed on remote system using "ssh". */
323 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
324 verbose_mode ? " -v" : "",
325 iamrecursive ? " -r" : "", pflag ? " -p" : "",
326 targetshouldbedirectory ? " -d" : "");
327
328 (void) signal(SIGPIPE, lostconn);
329
330 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
331 toremote(targ, argc, argv);
332 else {
333 tolocal(argc, argv); /* Dest is local host. */
334 if (targetshouldbedirectory)
335 verifydir(argv[argc - 1]);
336 }
337 /*
338 * Finally check the exit status of the ssh process, if one was forked
339 * and no error has occured yet
340 */
341 if (do_cmd_pid != -1 && errs == 0) {
342 if (remin != -1)
343 (void) close(remin);
344 if (remout != -1)
345 (void) close(remout);
346 if (waitpid(do_cmd_pid, &status, 0) == -1)
347 errs = 1;
348 else {
349 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
350 errs = 1;
351 }
352 }
353 exit(errs != 0);
354}
355
356void
357toremote(targ, argc, argv)
358 char *targ, *argv[];
359 int argc;
360{
361 int i, len;
362 char *bp, *host, *src, *suser, *thost, *tuser;
363
364 *targ++ = 0;
365 if (*targ == 0)
366 targ = ".";
367
368 if ((thost = strrchr(argv[argc - 1], '@'))) {
369 /* user@host */
370 *thost++ = 0;
371 tuser = argv[argc - 1];
372 if (*tuser == '\0')
373 tuser = NULL;
374 } else {
375 thost = argv[argc - 1];
376 tuser = NULL;
377 }
378
379 for (i = 0; i < argc - 1; i++) {
380 src = colon(argv[i]);
381 if (src) { /* remote to remote */
382 static char *ssh_options =
383 "-x -o'ClearAllForwardings yes'";
384 *src++ = 0;
385 if (*src == 0)
386 src = ".";
387 host = strrchr(argv[i], '@');
388 len = strlen(ssh_program) + strlen(argv[i]) +
389 strlen(src) + (tuser ? strlen(tuser) : 0) +
390 strlen(thost) + strlen(targ) +
391 strlen(ssh_options) + CMDNEEDS + 20;
392 bp = xmalloc(len);
393 if (host) {
394 *host++ = 0;
395 host = cleanhostname(host);
396 suser = argv[i];
397 if (*suser == '\0')
398 suser = pwd->pw_name;
399 else if (!okname(suser)) {
400 xfree(bp);
401 continue;
402 }
403 if (tuser && !okname(tuser)) {
404 xfree(bp);
405 continue;
406 }
407 snprintf(bp, len,
408 "%s%s %s -n "
409 "-l %s %s %s %s '%s%s%s:%s'",
410 ssh_program, verbose_mode ? " -v" : "",
411 ssh_options, suser, host, cmd, src,
412 tuser ? tuser : "", tuser ? "@" : "",
413 thost, targ);
414 } else {

--- 49 unchanged lines hidden (view full) ---

464 if (system(bp))
465 ++errs;
466 (void) xfree(bp);
467 continue;
468 }
469 *src++ = 0;
470 if (*src == 0)
471 src = ".";
472 if ((host = strrchr(argv[i], '@')) == NULL) {
473 host = argv[i];
474 suser = NULL;
475 } else {
476 *host++ = 0;
477 suser = argv[i];
478 if (*suser == '\0')
479 suser = pwd->pw_name;
480 }
481 host = cleanhostname(host);
482 len = strlen(src) + CMDNEEDS + 20;
483 bp = xmalloc(len);
484 (void) snprintf(bp, len, "%s -f %s", cmd, src);
485 if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {
486 (void) xfree(bp);
487 ++errs;

--- 9 unchanged lines hidden (view full) ---

497void
498source(argc, argv)
499 int argc;
500 char *argv[];
501{
502 struct stat stb;
503 static BUF buffer;
504 BUF *bp;
505 off_t i, amt, result, statbytes;
506 int fd, haderr, indx;
507 char *last, *name, buf[2048];
508 int len;
509
510 for (indx = 0; indx < argc; ++indx) {
511 name = argv[indx];
512 statbytes = 0;
513 len = strlen(name);

--- 48 unchanged lines hidden (view full) ---

562#else
563 /* XXX: Handle integer overflow? */
564 snprintf(buf, sizeof buf, "C%04o %lu %s\n",
565 (u_int) (stb.st_mode & FILEMODEMASK),
566 (u_long) stb.st_size, last);
567#endif
568 if (verbose_mode) {
569 fprintf(stderr, "Sending file modes: %s", buf);
570 }
571 (void) atomicio(write, remout, buf, strlen(buf));
572 if (response() < 0)
573 goto next;
574 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
575next: (void) close(fd);
576 continue;
577 }
578 if (showprogress)
579 start_progress_meter(curfile, stb.st_size, &statbytes);
580 /* Keep writing after an error so that we stay sync'd up. */
581 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
582 amt = bp->cnt;
583 if (i + amt > stb.st_size)
584 amt = stb.st_size - i;
585 if (!haderr) {
586 result = atomicio(read, fd, bp->buf, amt);
587 if (result != amt)
588 haderr = result >= 0 ? EIO : errno;
589 }
590 if (haderr)
591 (void) atomicio(write, remout, bp->buf, amt);
592 else {
593 result = atomicio(write, remout, bp->buf, amt);
594 if (result != amt)
595 haderr = result >= 0 ? EIO : errno;
596 statbytes += result;
597 }
598 if (limitbw)
599 bwlimit(amt);
600 }
601 if (showprogress)
602 stop_progress_meter();
603
604 if (close(fd) < 0 && !haderr)
605 haderr = errno;
606 if (!haderr)
607 (void) atomicio(write, remout, "", 1);
608 else
609 run_err("%s: %s", name, strerror(haderr));
610 (void) response();

--- 51 unchanged lines hidden (view full) ---

662 source(1, vect);
663 }
664 (void) closedir(dirp);
665 (void) atomicio(write, remout, "E\n", 2);
666 (void) response();
667}
668
669void
670bwlimit(int amount)
671{
672 static struct timeval bwstart, bwend;
673 static int lamt, thresh = 16384;
674 u_int64_t wait;
675 struct timespec ts, rm;
676
677 if (!timerisset(&bwstart)) {
678 gettimeofday(&bwstart, NULL);
679 return;
680 }
681
682 lamt += amount;
683 if (lamt < thresh)
684 return;
685
686 gettimeofday(&bwend, NULL);
687 timersub(&bwend, &bwstart, &bwend);
688 if (!timerisset(&bwend))
689 return;
690
691 lamt *= 8;
692 wait = (double)1000000L * lamt / limitbw;
693
694 bwstart.tv_sec = wait / 1000000L;
695 bwstart.tv_usec = wait % 1000000L;
696
697 if (timercmp(&bwstart, &bwend, >)) {
698 timersub(&bwstart, &bwend, &bwend);
699
700 /* Adjust the wait time */
701 if (bwend.tv_sec) {
702 thresh /= 2;
703 if (thresh < 2048)
704 thresh = 2048;
705 } else if (bwend.tv_usec < 100) {
706 thresh *= 2;
707 if (thresh > 32768)
708 thresh = 32768;
709 }
710
711 TIMEVAL_TO_TIMESPEC(&bwend, &ts);
712 while (nanosleep(&ts, &rm) == -1) {
713 if (errno != EINTR)
714 break;
715 ts = rm;
716 }
717 }
718
719 lamt = 0;
720 gettimeofday(&bwstart, NULL);
721}
722
723void
724sink(argc, argv)
725 int argc;
726 char *argv[];
727{
728 static BUF buffer;
729 struct stat stb;
730 enum {
731 YES, NO, DISPLAYED
732 } wrerr;
733 BUF *bp;
734 off_t i, j;
735 int amt, count, exists, first, mask, mode, ofd, omode;
736 off_t size, statbytes;
737 int setimes, targisdir, wrerrno = 0;
738 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
739 struct timeval tv[2];
740
741#define atime tv[0]
742#define mtime tv[1]
743#define SCREWUP(str) do { why = str; goto screwup; } while (0)
744

--- 145 unchanged lines hidden (view full) ---

890 (void) atomicio(write, remout, "", 1);
891 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
892 (void) close(ofd);
893 continue;
894 }
895 cp = bp->buf;
896 wrerr = NO;
897
898 statbytes = 0;
899 if (showprogress)
900 start_progress_meter(curfile, size, &statbytes);
901 for (count = i = 0; i < size; i += 4096) {
902 amt = 4096;
903 if (i + amt > size)
904 amt = size - i;
905 count += amt;
906 do {
907 j = read(remin, cp, amt);
908 if (j == -1 && (errno == EINTR ||
909 errno == EAGAIN)) {
910 continue;
911 } else if (j <= 0) {
912 run_err("%s", j ? strerror(errno) :
913 "dropped connection");
914 exit(1);
915 }
916 amt -= j;
917 cp += j;
918 statbytes += j;
919 } while (amt > 0);
920
921 if (limitbw)
922 bwlimit(4096);
923
924 if (count == bp->cnt) {
925 /* Keep reading so we stay sync'd up. */
926 if (wrerr == NO) {
927 j = atomicio(write, ofd, bp->buf, count);
928 if (j != count) {
929 wrerr = YES;
930 wrerrno = j >= 0 ? EIO : errno;
931 }
932 }
933 count = 0;
934 cp = bp->buf;
935 }
936 }
937 if (showprogress)
938 stop_progress_meter();
939 if (count != 0 && wrerr == NO &&
940 (j = atomicio(write, ofd, bp->buf, count)) != count) {
941 wrerr = YES;
942 wrerrno = j >= 0 ? EIO : errno;
943 }
944 if (wrerr == NO && ftruncate(ofd, size) != 0) {
945 run_err("%s: truncate: %s", np, strerror(errno));
946 wrerr = DISPLAYED;
947 }
948 if (pflag) {
949 if (exists || omode != mode)
950#ifdef HAVE_FCHMOD
951 if (fchmod(ofd, omode))
952#else /* HAVE_FCHMOD */

--- 72 unchanged lines hidden (view full) ---

1025 }
1026 /* NOTREACHED */
1027}
1028
1029void
1030usage(void)
1031{
1032 (void) fprintf(stderr,
1033 "usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n"
1034 " [-c cipher] [-i identity] [-l limit] [-o option]\n"
1035 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
1036 exit(1);
1037}
1038
1039void
1040run_err(const char *fmt,...)
1041{
1042 static FILE *fp;

--- 40 unchanged lines hidden (view full) ---

1083 int c;
1084 char *cp;
1085
1086 cp = cp0;
1087 do {
1088 c = (int)*cp;
1089 if (c & 0200)
1090 goto bad;
1091 if (!isalpha(c) && !isdigit(c)) {
1092 switch (c) {
1093 case '\'':
1094 case '"':
1095 case '`':
1096 case ' ':
1097 case '#':
1098 goto bad;
1099 default:
1100 break;
1101 }
1102 }
1103 } while (*++cp);
1104 return (1);
1105
1106bad: fprintf(stderr, "%s: invalid user name\n", cp0);
1107 return (0);
1108}
1109
1110BUF *

--- 4 unchanged lines hidden (view full) ---

1115 size_t size;
1116#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1117 struct stat stb;
1118
1119 if (fstat(fd, &stb) < 0) {
1120 run_err("fstat: %s", strerror(errno));
1121 return (0);
1122 }
1123 size = roundup(stb.st_blksize, blksize);
1124 if (size == 0)
1125 size = blksize;
1126#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1127 size = blksize;
1128#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1129 if (bp->cnt >= size)
1130 return (bp);
1131 if (bp->buf == NULL)
1132 bp->buf = xmalloc(size);
1133 else

--- 9 unchanged lines hidden (view full) ---

1143{
1144 if (!iamremote)
1145 write(STDERR_FILENO, "lost connection\n", 16);
1146 if (signo)
1147 _exit(1);
1148 else
1149 exit(1);
1150}