diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | scp.1 | 11 | ||||
-rw-r--r-- | scp.c | 89 |
3 files changed, 102 insertions, 6 deletions
@@ -1,3 +1,11 @@ +20110106 + - (djm) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2010/12/08 22:46:03 + [scp.1 scp.c] + add a new -3 option to scp: Copies between two remote hosts are + transferred through the local host. Without this option the data + is copied directly between the two remote hosts. ok djm@ (bugzilla #1837) + 20110104 - (djm) [configure.ac Makefile.in] Use mandoc as preferred manpage formatter if it is present, followed by nroff and groff respectively. @@ -8,9 +8,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.54 2010/11/18 15:01:00 jmc Exp $ +.\" $OpenBSD: scp.1,v 1.55 2010/12/08 22:46:03 markus Exp $ .\" -.Dd $Mdocdate: November 18 2010 $ +.Dd $Mdocdate: December 8 2010 $ .Dt SCP 1 .Os .Sh NAME @@ -19,7 +19,7 @@ .Sh SYNOPSIS .Nm scp .Bk -words -.Op Fl 1246BCpqrv +.Op Fl 12346BCpqrv .Op Fl c Ar cipher .Op Fl F Ar ssh_config .Op Fl i Ar identity_file @@ -75,6 +75,11 @@ to use protocol 1. Forces .Nm to use protocol 2. +.It Fl 3 +Copies between two remote hosts are transferred through the local host. +Without this option the data is copied directly between the two remote +hosts. +Note that this options disables the progress meter. .It Fl 4 Forces .Nm @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.168 2010/11/26 05:52:49 djm Exp $ */ +/* $OpenBSD: scp.c,v 1.169 2010/12/08 22:46:03 markus Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -119,6 +119,7 @@ extern char *__progname; #define COPY_BUFLEN 16384 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); +int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout); /* Struct for addargs */ arglist args; @@ -137,6 +138,12 @@ int verbose_mode = 0; /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; +/* + * This is set to non-zero if remote-remote copy should be piped + * through this process. + */ +int throughlocal = 0; + /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = _PATH_SSH_PROGRAM; @@ -287,6 +294,50 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) return 0; } +/* + * This functions executes a command simlar to do_cmd(), but expects the + * input and output descriptors to be setup by a previous call to do_cmd(). + * This way the input and output of two commands can be connected. + */ +int +do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) +{ + pid_t pid; + int status; + + if (verbose_mode) + fprintf(stderr, + "Executing: 2nd program %s host %s, user %s, command %s\n", + ssh_program, host, + remuser ? remuser : "(unspecified)", cmd); + + /* Fork a child to execute the command on the remote host using ssh. */ + pid = fork(); + if (pid == 0) { + dup2(fdin, 0); + dup2(fdout, 1); + + replacearg(&args, 0, "%s", ssh_program); + if (remuser != NULL) { + addargs(&args, "-l"); + addargs(&args, "%s", remuser); + } + addargs(&args, "--"); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); + + execvp(ssh_program, args.list); + perror(ssh_program); + exit(1); + } else if (pid == -1) { + fatal("fork: %s", strerror(errno)); + } + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) + fatal("do_cmd2: waitpid: %s", strerror(errno)); + return 0; +} + typedef struct { size_t cnt; char *buf; @@ -344,7 +395,7 @@ main(int argc, char **argv) addargs(&args, "-oClearAllForwardings=yes"); fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) + while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) switch (ch) { /* User-visible flags. */ case '1': @@ -355,6 +406,9 @@ main(int argc, char **argv) addargs(&args, "-%c", ch); addargs(&remote_remote_args, "-%c", ch); break; + case '3': + throughlocal = 1; + break; case 'o': case 'c': case 'i': @@ -530,7 +584,36 @@ toremote(char *targ, int argc, char **argv) for (i = 0; i < argc - 1; i++) { src = colon(argv[i]); - if (src) { /* remote to remote */ + if (src && throughlocal) { /* extended remote to remote */ + *src++ = 0; + if (*src == 0) + src = "."; + host = strrchr(argv[i], '@'); + if (host) { + *host++ = 0; + host = cleanhostname(host); + suser = argv[i]; + if (*suser == '\0') + suser = pwd->pw_name; + else if (!okname(suser)) + continue; + } else { + host = cleanhostname(argv[i]); + suser = NULL; + } + xasprintf(&bp, "%s -f -- %s", cmd, src); + if (do_cmd(host, suser, bp, &remin, &remout) < 0) + exit(1); + (void) xfree(bp); + host = cleanhostname(thost); + xasprintf(&bp, "%s -t -- %s", cmd, targ); + if (do_cmd2(host, tuser, bp, remin, remout) < 0) + exit(1); + (void) xfree(bp); + (void) close(remin); + (void) close(remout); + remin = remout = -1; + } else if (src) { /* standard remote to remote */ freeargs(&alist); addargs(&alist, "%s", ssh_program); addargs(&alist, "-x"); |