summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2011-01-24 12:43:25 +0000
committerColin Watson <cjwatson@debian.org>2011-01-24 12:43:25 +0000
commit626f1d986ff72aa514da63e34744e1de9cf21b9a (patch)
treed215a5280bc2e57251e4a9e08bfd3674ad824a94 /scp.c
parent6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff)
parent0970072c89b079b022538e3c366fbfa2c53fc821 (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.c241
1 files changed, 129 insertions, 112 deletions
diff --git a/scp.c b/scp.c
index b28d75eba..69344b804 100644
--- a/scp.c
+++ b/scp.c
@@ -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
121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
122 122int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
123void bwlimit(int);
124 123
125/* Struct for addargs */ 124/* Struct for addargs */
126arglist args; 125arglist args;
126arglist remote_remote_args;
127 127
128/* Bandwidth limit */ 128/* Bandwidth limit */
129off_t limit_rate = 0; 129long long limit_kbps = 0;
130struct bwlimit bwlimit;
130 131
131/* Name of current file being transferred. */ 132/* Name of current file being transferred. */
132char *curfile; 133char *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. */
138int showprogress = 1; 139int showprogress = 1;
139 140
141/*
142 * This is set to non-zero if remote-remote copy should be piped
143 * through this process.
144 */
145int 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) */
141char *ssh_program = _PATH_SSH_PROGRAM; 148char *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 */
310int
311do_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
298typedef struct { 349typedef struct {
299 size_t cnt; 350 size_t cnt;
300 char *buf; 351 char *buf;
@@ -320,15 +371,14 @@ void sink(int, char *[]);
320void source(int, char *[]); 371void source(int, char *[]);
321void tolocal(int, char *[]); 372void tolocal(int, char *[]);
322void toremote(char *, int, char *[]); 373void toremote(char *, int, char *[]);
323size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *);
324void usage(void); 374void usage(void);
325 375
326int 376int
327main(int argc, char **argv) 377main(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 550static int
487 * the progressmeter counter. 551scpio(void *_cnt, size_t s)
488 */
489size_t
490scpio(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
522void 561void
@@ -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
835void 905void
836bwlimit(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
889void
890sink(int argc, char **argv) 906sink(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
1205usage(void) 1222usage(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);