diff options
author | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
commit | 626f1d986ff72aa514da63e34744e1de9cf21b9a (patch) | |
tree | d215a5280bc2e57251e4a9e08bfd3674ad824a94 /scp.c | |
parent | 6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff) | |
parent | 0970072c89b079b022538e3c366fbfa2c53fc821 (diff) |
* New upstream release (http://www.openssh.org/txt/release-5.7):
- Implement Elliptic Curve Cryptography modes for key exchange (ECDH)
and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA
offer better performance than plain DH and DSA at the same equivalent
symmetric key length, as well as much shorter keys.
- sftp(1)/sftp-server(8): add a protocol extension to support a hard
link operation. It is available through the "ln" command in the
client. The old "ln" behaviour of creating a symlink is available
using its "-s" option or through the preexisting "symlink" command.
- scp(1): Add a new -3 option to scp: Copies between two remote hosts
are transferred through the local host (closes: #508613).
- ssh(1): "atomically" create the listening mux socket by binding it on
a temporary name and then linking it into position after listen() has
succeeded. This allows the mux clients to determine that the server
socket is either ready or stale without races (closes: #454784).
Stale server sockets are now automatically removed (closes: #523250).
- ssh(1): install a SIGCHLD handler to reap expired child process
(closes: #594687).
- ssh(1)/ssh-agent(1): honour $TMPDIR for client xauth and ssh-agent
temporary directories (closes: #357469, although only if you arrange
for ssh-agent to actually see $TMPDIR since the setgid bit will cause
it to be stripped off).
Diffstat (limited to 'scp.c')
-rw-r--r-- | scp.c | 241 |
1 files changed, 129 insertions, 112 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: scp.c,v 1.166 2010/07/01 13:06:59 millert Exp $ */ | 1 | /* $OpenBSD: scp.c,v 1.170 2010/12/09 14:13:33 jmc Exp $ */ |
2 | /* | 2 | /* |
3 | * scp - secure remote copy. This is basically patched BSD rcp which | 3 | * scp - secure remote copy. This is basically patched BSD rcp which |
4 | * uses ssh to do the data transfer (instead of using rcmd). | 4 | * uses ssh to do the data transfer (instead of using rcmd). |
@@ -119,14 +119,15 @@ extern char *__progname; | |||
119 | #define COPY_BUFLEN 16384 | 119 | #define COPY_BUFLEN 16384 |
120 | 120 | ||
121 | int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); | 121 | int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); |
122 | 122 | int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout); | |
123 | void bwlimit(int); | ||
124 | 123 | ||
125 | /* Struct for addargs */ | 124 | /* Struct for addargs */ |
126 | arglist args; | 125 | arglist args; |
126 | arglist remote_remote_args; | ||
127 | 127 | ||
128 | /* Bandwidth limit */ | 128 | /* Bandwidth limit */ |
129 | off_t limit_rate = 0; | 129 | long long limit_kbps = 0; |
130 | struct bwlimit bwlimit; | ||
130 | 131 | ||
131 | /* Name of current file being transferred. */ | 132 | /* Name of current file being transferred. */ |
132 | char *curfile; | 133 | char *curfile; |
@@ -137,6 +138,12 @@ int verbose_mode = 0; | |||
137 | /* This is set to zero if the progressmeter is not desired. */ | 138 | /* This is set to zero if the progressmeter is not desired. */ |
138 | int showprogress = 1; | 139 | int showprogress = 1; |
139 | 140 | ||
141 | /* | ||
142 | * This is set to non-zero if remote-remote copy should be piped | ||
143 | * through this process. | ||
144 | */ | ||
145 | int throughlocal = 0; | ||
146 | |||
140 | /* This is the program to execute for the secured connection. ("ssh" or -S) */ | 147 | /* This is the program to execute for the secured connection. ("ssh" or -S) */ |
141 | char *ssh_program = _PATH_SSH_PROGRAM; | 148 | char *ssh_program = _PATH_SSH_PROGRAM; |
142 | 149 | ||
@@ -295,6 +302,50 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) | |||
295 | return 0; | 302 | return 0; |
296 | } | 303 | } |
297 | 304 | ||
305 | /* | ||
306 | * This functions executes a command simlar to do_cmd(), but expects the | ||
307 | * input and output descriptors to be setup by a previous call to do_cmd(). | ||
308 | * This way the input and output of two commands can be connected. | ||
309 | */ | ||
310 | int | ||
311 | do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) | ||
312 | { | ||
313 | pid_t pid; | ||
314 | int status; | ||
315 | |||
316 | if (verbose_mode) | ||
317 | fprintf(stderr, | ||
318 | "Executing: 2nd program %s host %s, user %s, command %s\n", | ||
319 | ssh_program, host, | ||
320 | remuser ? remuser : "(unspecified)", cmd); | ||
321 | |||
322 | /* Fork a child to execute the command on the remote host using ssh. */ | ||
323 | pid = fork(); | ||
324 | if (pid == 0) { | ||
325 | dup2(fdin, 0); | ||
326 | dup2(fdout, 1); | ||
327 | |||
328 | replacearg(&args, 0, "%s", ssh_program); | ||
329 | if (remuser != NULL) { | ||
330 | addargs(&args, "-l"); | ||
331 | addargs(&args, "%s", remuser); | ||
332 | } | ||
333 | addargs(&args, "--"); | ||
334 | addargs(&args, "%s", host); | ||
335 | addargs(&args, "%s", cmd); | ||
336 | |||
337 | execvp(ssh_program, args.list); | ||
338 | perror(ssh_program); | ||
339 | exit(1); | ||
340 | } else if (pid == -1) { | ||
341 | fatal("fork: %s", strerror(errno)); | ||
342 | } | ||
343 | while (waitpid(pid, &status, 0) == -1) | ||
344 | if (errno != EINTR) | ||
345 | fatal("do_cmd2: waitpid: %s", strerror(errno)); | ||
346 | return 0; | ||
347 | } | ||
348 | |||
298 | typedef struct { | 349 | typedef struct { |
299 | size_t cnt; | 350 | size_t cnt; |
300 | char *buf; | 351 | char *buf; |
@@ -320,15 +371,14 @@ void sink(int, char *[]); | |||
320 | void source(int, char *[]); | 371 | void source(int, char *[]); |
321 | void tolocal(int, char *[]); | 372 | void tolocal(int, char *[]); |
322 | void toremote(char *, int, char *[]); | 373 | void toremote(char *, int, char *[]); |
323 | size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *); | ||
324 | void usage(void); | 374 | void usage(void); |
325 | 375 | ||
326 | int | 376 | int |
327 | main(int argc, char **argv) | 377 | main(int argc, char **argv) |
328 | { | 378 | { |
329 | int ch, fflag, tflag, status, n; | 379 | int ch, fflag, tflag, status, n; |
330 | double speed; | 380 | char *targ, **newargv; |
331 | char *targ, *endp, **newargv; | 381 | const char *errstr; |
332 | extern char *optarg; | 382 | extern char *optarg; |
333 | extern int optind; | 383 | extern int optind; |
334 | 384 | ||
@@ -344,15 +394,16 @@ main(int argc, char **argv) | |||
344 | __progname = ssh_get_progname(argv[0]); | 394 | __progname = ssh_get_progname(argv[0]); |
345 | 395 | ||
346 | memset(&args, '\0', sizeof(args)); | 396 | memset(&args, '\0', sizeof(args)); |
347 | args.list = NULL; | 397 | memset(&remote_remote_args, '\0', sizeof(remote_remote_args)); |
398 | args.list = remote_remote_args.list = NULL; | ||
348 | addargs(&args, "%s", ssh_program); | 399 | addargs(&args, "%s", ssh_program); |
349 | addargs(&args, "-x"); | 400 | addargs(&args, "-x"); |
350 | addargs(&args, "-oForwardAgent no"); | 401 | addargs(&args, "-oForwardAgent=no"); |
351 | addargs(&args, "-oPermitLocalCommand no"); | 402 | addargs(&args, "-oPermitLocalCommand=no"); |
352 | addargs(&args, "-oClearAllForwardings yes"); | 403 | addargs(&args, "-oClearAllForwardings=yes"); |
353 | 404 | ||
354 | fflag = tflag = 0; | 405 | fflag = tflag = 0; |
355 | while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) | 406 | while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) |
356 | switch (ch) { | 407 | switch (ch) { |
357 | /* User-visible flags. */ | 408 | /* User-visible flags. */ |
358 | case '1': | 409 | case '1': |
@@ -361,26 +412,37 @@ main(int argc, char **argv) | |||
361 | case '6': | 412 | case '6': |
362 | case 'C': | 413 | case 'C': |
363 | addargs(&args, "-%c", ch); | 414 | addargs(&args, "-%c", ch); |
415 | addargs(&remote_remote_args, "-%c", ch); | ||
416 | break; | ||
417 | case '3': | ||
418 | throughlocal = 1; | ||
364 | break; | 419 | break; |
365 | case 'o': | 420 | case 'o': |
366 | case 'c': | 421 | case 'c': |
367 | case 'i': | 422 | case 'i': |
368 | case 'F': | 423 | case 'F': |
424 | addargs(&remote_remote_args, "-%c", ch); | ||
425 | addargs(&remote_remote_args, "%s", optarg); | ||
369 | addargs(&args, "-%c", ch); | 426 | addargs(&args, "-%c", ch); |
370 | addargs(&args, "%s", optarg); | 427 | addargs(&args, "%s", optarg); |
371 | break; | 428 | break; |
372 | case 'P': | 429 | case 'P': |
430 | addargs(&remote_remote_args, "-p"); | ||
431 | addargs(&remote_remote_args, "%s", optarg); | ||
373 | addargs(&args, "-p"); | 432 | addargs(&args, "-p"); |
374 | addargs(&args, "%s", optarg); | 433 | addargs(&args, "%s", optarg); |
375 | break; | 434 | break; |
376 | case 'B': | 435 | case 'B': |
377 | addargs(&args, "-oBatchmode yes"); | 436 | addargs(&remote_remote_args, "-oBatchmode=yes"); |
437 | addargs(&args, "-oBatchmode=yes"); | ||
378 | break; | 438 | break; |
379 | case 'l': | 439 | case 'l': |
380 | speed = strtod(optarg, &endp); | 440 | limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, |
381 | if (speed <= 0 || *endp != '\0') | 441 | &errstr); |
442 | if (errstr != NULL) | ||
382 | usage(); | 443 | usage(); |
383 | limit_rate = speed * 1024; | 444 | limit_kbps *= 1024; /* kbps */ |
445 | bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN); | ||
384 | break; | 446 | break; |
385 | case 'p': | 447 | case 'p': |
386 | pflag = 1; | 448 | pflag = 1; |
@@ -393,10 +455,12 @@ main(int argc, char **argv) | |||
393 | break; | 455 | break; |
394 | case 'v': | 456 | case 'v': |
395 | addargs(&args, "-v"); | 457 | addargs(&args, "-v"); |
458 | addargs(&remote_remote_args, "-v"); | ||
396 | verbose_mode = 1; | 459 | verbose_mode = 1; |
397 | break; | 460 | break; |
398 | case 'q': | 461 | case 'q': |
399 | addargs(&args, "-q"); | 462 | addargs(&args, "-q"); |
463 | addargs(&remote_remote_args, "-q"); | ||
400 | showprogress = 0; | 464 | showprogress = 0; |
401 | break; | 465 | break; |
402 | 466 | ||
@@ -482,41 +546,16 @@ main(int argc, char **argv) | |||
482 | exit(errs != 0); | 546 | exit(errs != 0); |
483 | } | 547 | } |
484 | 548 | ||
485 | /* | 549 | /* Callback from atomicio6 to update progress meter and limit bandwidth */ |
486 | * atomicio-like wrapper that also applies bandwidth limits and updates | 550 | static int |
487 | * the progressmeter counter. | 551 | scpio(void *_cnt, size_t s) |
488 | */ | ||
489 | size_t | ||
490 | scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c) | ||
491 | { | 552 | { |
492 | u_char *p = (u_char *)_p; | 553 | off_t *cnt = (off_t *)_cnt; |
493 | size_t offset; | 554 | |
494 | ssize_t r; | 555 | *cnt += s; |
495 | struct pollfd pfd; | 556 | if (limit_kbps > 0) |
496 | 557 | bandwidth_limit(&bwlimit, s); | |
497 | pfd.fd = fd; | 558 | return 0; |
498 | pfd.events = f == read ? POLLIN : POLLOUT; | ||
499 | for (offset = 0; offset < l;) { | ||
500 | r = f(fd, p + offset, l - offset); | ||
501 | if (r == 0) { | ||
502 | errno = EPIPE; | ||
503 | return offset; | ||
504 | } | ||
505 | if (r < 0) { | ||
506 | if (errno == EINTR) | ||
507 | continue; | ||
508 | if (errno == EAGAIN || errno == EWOULDBLOCK) { | ||
509 | (void)poll(&pfd, 1, -1); /* Ignore errors */ | ||
510 | continue; | ||
511 | } | ||
512 | return offset; | ||
513 | } | ||
514 | offset += (size_t)r; | ||
515 | *c += (off_t)r; | ||
516 | if (limit_rate) | ||
517 | bwlimit(r); | ||
518 | } | ||
519 | return offset; | ||
520 | } | 559 | } |
521 | 560 | ||
522 | void | 561 | void |
@@ -525,6 +564,7 @@ toremote(char *targ, int argc, char **argv) | |||
525 | char *bp, *host, *src, *suser, *thost, *tuser, *arg; | 564 | char *bp, *host, *src, *suser, *thost, *tuser, *arg; |
526 | arglist alist; | 565 | arglist alist; |
527 | int i; | 566 | int i; |
567 | u_int j; | ||
528 | 568 | ||
529 | memset(&alist, '\0', sizeof(alist)); | 569 | memset(&alist, '\0', sizeof(alist)); |
530 | alist.list = NULL; | 570 | alist.list = NULL; |
@@ -552,15 +592,45 @@ toremote(char *targ, int argc, char **argv) | |||
552 | 592 | ||
553 | for (i = 0; i < argc - 1; i++) { | 593 | for (i = 0; i < argc - 1; i++) { |
554 | src = colon(argv[i]); | 594 | src = colon(argv[i]); |
555 | if (src) { /* remote to remote */ | 595 | if (src && throughlocal) { /* extended remote to remote */ |
596 | *src++ = 0; | ||
597 | if (*src == 0) | ||
598 | src = "."; | ||
599 | host = strrchr(argv[i], '@'); | ||
600 | if (host) { | ||
601 | *host++ = 0; | ||
602 | host = cleanhostname(host); | ||
603 | suser = argv[i]; | ||
604 | if (*suser == '\0') | ||
605 | suser = pwd->pw_name; | ||
606 | else if (!okname(suser)) | ||
607 | continue; | ||
608 | } else { | ||
609 | host = cleanhostname(argv[i]); | ||
610 | suser = NULL; | ||
611 | } | ||
612 | xasprintf(&bp, "%s -f -- %s", cmd, src); | ||
613 | if (do_cmd(host, suser, bp, &remin, &remout) < 0) | ||
614 | exit(1); | ||
615 | (void) xfree(bp); | ||
616 | host = cleanhostname(thost); | ||
617 | xasprintf(&bp, "%s -t -- %s", cmd, targ); | ||
618 | if (do_cmd2(host, tuser, bp, remin, remout) < 0) | ||
619 | exit(1); | ||
620 | (void) xfree(bp); | ||
621 | (void) close(remin); | ||
622 | (void) close(remout); | ||
623 | remin = remout = -1; | ||
624 | } else if (src) { /* standard remote to remote */ | ||
556 | freeargs(&alist); | 625 | freeargs(&alist); |
557 | addargs(&alist, "%s", ssh_program); | 626 | addargs(&alist, "%s", ssh_program); |
558 | if (verbose_mode) | ||
559 | addargs(&alist, "-v"); | ||
560 | addargs(&alist, "-x"); | 627 | addargs(&alist, "-x"); |
561 | addargs(&alist, "-oClearAllForwardings yes"); | 628 | addargs(&alist, "-oClearAllForwardings=yes"); |
562 | addargs(&alist, "-n"); | 629 | addargs(&alist, "-n"); |
563 | 630 | for (j = 0; j < remote_remote_args.num; j++) { | |
631 | addargs(&alist, "%s", | ||
632 | remote_remote_args.list[j]); | ||
633 | } | ||
564 | *src++ = 0; | 634 | *src++ = 0; |
565 | if (*src == 0) | 635 | if (*src == 0) |
566 | src = "."; | 636 | src = "."; |
@@ -758,7 +828,7 @@ next: if (fd != -1) { | |||
758 | (void)atomicio(vwrite, remout, bp->buf, amt); | 828 | (void)atomicio(vwrite, remout, bp->buf, amt); |
759 | continue; | 829 | continue; |
760 | } | 830 | } |
761 | if (scpio(vwrite, remout, bp->buf, amt, | 831 | if (atomicio6(vwrite, remout, bp->buf, amt, scpio, |
762 | &statbytes) != amt) | 832 | &statbytes) != amt) |
763 | haderr = errno; | 833 | haderr = errno; |
764 | } | 834 | } |
@@ -833,60 +903,6 @@ rsource(char *name, struct stat *statp) | |||
833 | } | 903 | } |
834 | 904 | ||
835 | void | 905 | void |
836 | bwlimit(int amount) | ||
837 | { | ||
838 | static struct timeval bwstart, bwend; | ||
839 | static int lamt, thresh = 16384; | ||
840 | u_int64_t waitlen; | ||
841 | struct timespec ts, rm; | ||
842 | |||
843 | if (!timerisset(&bwstart)) { | ||
844 | gettimeofday(&bwstart, NULL); | ||
845 | return; | ||
846 | } | ||
847 | |||
848 | lamt += amount; | ||
849 | if (lamt < thresh) | ||
850 | return; | ||
851 | |||
852 | gettimeofday(&bwend, NULL); | ||
853 | timersub(&bwend, &bwstart, &bwend); | ||
854 | if (!timerisset(&bwend)) | ||
855 | return; | ||
856 | |||
857 | lamt *= 8; | ||
858 | waitlen = (double)1000000L * lamt / limit_rate; | ||
859 | |||
860 | bwstart.tv_sec = waitlen / 1000000L; | ||
861 | bwstart.tv_usec = waitlen % 1000000L; | ||
862 | |||
863 | if (timercmp(&bwstart, &bwend, >)) { | ||
864 | timersub(&bwstart, &bwend, &bwend); | ||
865 | |||
866 | /* Adjust the wait time */ | ||
867 | if (bwend.tv_sec) { | ||
868 | thresh /= 2; | ||
869 | if (thresh < 2048) | ||
870 | thresh = 2048; | ||
871 | } else if (bwend.tv_usec < 10000) { | ||
872 | thresh *= 2; | ||
873 | if (thresh > COPY_BUFLEN * 4) | ||
874 | thresh = COPY_BUFLEN * 4; | ||
875 | } | ||
876 | |||
877 | TIMEVAL_TO_TIMESPEC(&bwend, &ts); | ||
878 | while (nanosleep(&ts, &rm) == -1) { | ||
879 | if (errno != EINTR) | ||
880 | break; | ||
881 | ts = rm; | ||
882 | } | ||
883 | } | ||
884 | |||
885 | lamt = 0; | ||
886 | gettimeofday(&bwstart, NULL); | ||
887 | } | ||
888 | |||
889 | void | ||
890 | sink(int argc, char **argv) | 906 | sink(int argc, char **argv) |
891 | { | 907 | { |
892 | static BUF buffer; | 908 | static BUF buffer; |
@@ -1079,7 +1095,8 @@ bad: run_err("%s: %s", np, strerror(errno)); | |||
1079 | amt = size - i; | 1095 | amt = size - i; |
1080 | count += amt; | 1096 | count += amt; |
1081 | do { | 1097 | do { |
1082 | j = scpio(read, remin, cp, amt, &statbytes); | 1098 | j = atomicio6(read, remin, cp, amt, |
1099 | scpio, &statbytes); | ||
1083 | if (j == 0) { | 1100 | if (j == 0) { |
1084 | run_err("%s", j != EPIPE ? | 1101 | run_err("%s", j != EPIPE ? |
1085 | strerror(errno) : | 1102 | strerror(errno) : |
@@ -1205,7 +1222,7 @@ void | |||
1205 | usage(void) | 1222 | usage(void) |
1206 | { | 1223 | { |
1207 | (void) fprintf(stderr, | 1224 | (void) fprintf(stderr, |
1208 | "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" | 1225 | "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" |
1209 | " [-l limit] [-o ssh_option] [-P port] [-S program]\n" | 1226 | " [-l limit] [-o ssh_option] [-P port] [-S program]\n" |
1210 | " [[user@]host1:]file1 ... [[user@]host2:]file2\n"); | 1227 | " [[user@]host1:]file1 ... [[user@]host2:]file2\n"); |
1211 | exit(1); | 1228 | exit(1); |