version 1.218, 2021/08/07 00:00:33 |
version 1.219, 2021/08/07 00:06:30 |
|
|
#define COPY_BUFLEN 16384 |
#define COPY_BUFLEN 16384 |
|
|
int do_cmd(char *program, char *host, char *remuser, int port, char *cmd, |
int do_cmd(char *program, char *host, char *remuser, int port, char *cmd, |
int *fdin, int *fdout); |
int *fdin, int *fdout, pid_t *pidp); |
int do_cmd2(char *host, char *remuser, int port, char *cmd, |
int do_cmd2(char *host, char *remuser, int port, char *cmd, |
int fdin, int fdout); |
int fdin, int fdout); |
|
|
|
|
|
|
/* This is used to store the pid of ssh_program */ |
/* This is used to store the pid of ssh_program */ |
pid_t do_cmd_pid = -1; |
pid_t do_cmd_pid = -1; |
|
pid_t do_cmd_pid2 = -1; |
|
|
/* Needed for sftp */ |
/* Needed for sftp */ |
volatile sig_atomic_t interrupted = 0; |
volatile sig_atomic_t interrupted = 0; |
|
|
kill(do_cmd_pid, signo ? signo : SIGTERM); |
kill(do_cmd_pid, signo ? signo : SIGTERM); |
waitpid(do_cmd_pid, NULL, 0); |
waitpid(do_cmd_pid, NULL, 0); |
} |
} |
|
if (do_cmd_pid2 > 1) { |
|
kill(do_cmd_pid2, signo ? signo : SIGTERM); |
|
waitpid(do_cmd_pid2, NULL, 0); |
|
} |
|
|
if (signo) |
if (signo) |
_exit(1); |
_exit(1); |
|
|
} |
} |
|
|
static void |
static void |
suspchild(int signo) |
suspone(int pid, int signo) |
{ |
{ |
int status; |
int status; |
|
|
if (do_cmd_pid > 1) { |
if (pid > 1) { |
kill(do_cmd_pid, signo); |
kill(pid, signo); |
while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 && |
while (waitpid(pid, &status, WUNTRACED) == -1 && |
errno == EINTR) |
errno == EINTR) |
; |
; |
kill(getpid(), SIGSTOP); |
|
} |
} |
} |
} |
|
|
|
static void |
|
suspchild(int signo) |
|
{ |
|
suspone(do_cmd_pid, signo); |
|
suspone(do_cmd_pid2, signo); |
|
kill(getpid(), SIGSTOP); |
|
} |
|
|
static int |
static int |
do_local_cmd(arglist *a) |
do_local_cmd(arglist *a) |
{ |
{ |
|
|
|
|
int |
int |
do_cmd(char *program, char *host, char *remuser, int port, char *cmd, |
do_cmd(char *program, char *host, char *remuser, int port, char *cmd, |
int *fdin, int *fdout) |
int *fdin, int *fdout, int *pid) |
{ |
{ |
int pin[2], pout[2], reserved[2]; |
int pin[2], pout[2], reserved[2]; |
|
|
|
|
ssh_signal(SIGTTOU, suspchild); |
ssh_signal(SIGTTOU, suspchild); |
|
|
/* Fork a child to execute the command on the remote host using ssh. */ |
/* Fork a child to execute the command on the remote host using ssh. */ |
do_cmd_pid = fork(); |
*pid = fork(); |
if (do_cmd_pid == 0) { |
if (*pid == 0) { |
/* Child. */ |
/* Child. */ |
close(pin[1]); |
close(pin[1]); |
close(pout[0]); |
close(pout[0]); |
|
|
execvp(program, args.list); |
execvp(program, args.list); |
perror(program); |
perror(program); |
exit(1); |
exit(1); |
} else if (do_cmd_pid == -1) { |
} else if (*pid == -1) { |
fatal("fork: %s", strerror(errno)); |
fatal("fork: %s", strerror(errno)); |
} |
} |
/* Parent. Close the other side, and return the local side. */ |
/* Parent. Close the other side, and return the local side. */ |
|
|
* This way the input and output of two commands can be connected. |
* This way the input and output of two commands can be connected. |
*/ |
*/ |
int |
int |
do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout) |
do_cmd2(char *host, char *remuser, int port, char *cmd, |
|
int fdin, int fdout) |
{ |
{ |
pid_t pid; |
|
int status; |
int status; |
|
pid_t pid; |
|
|
if (verbose_mode) |
if (verbose_mode) |
fmprintf(stderr, |
fmprintf(stderr, |
|
|
|
|
struct passwd *pwd; |
struct passwd *pwd; |
uid_t userid; |
uid_t userid; |
int errs, remin, remout; |
int errs, remin, remout, remin2, remout2; |
int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; |
int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; |
|
|
#define CMDNEEDS 64 |
#define CMDNEEDS 64 |
|
|
|
|
void source_sftp(int, char *, char *, struct sftp_conn *, char **); |
void source_sftp(int, char *, char *, struct sftp_conn *, char **); |
void sink_sftp(int, char *, const char *, struct sftp_conn *); |
void sink_sftp(int, char *, const char *, struct sftp_conn *); |
|
void throughlocal_sftp(struct sftp_conn *, struct sftp_conn *, |
|
char *, char *, char **); |
|
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
|
|
} |
} |
|
|
static struct sftp_conn * |
static struct sftp_conn * |
do_sftp_connect(char *host, char *user, int port, char *sftp_direct) |
do_sftp_connect(char *host, char *user, int port, char *sftp_direct, |
|
int *reminp, int *remoutp, int *pidp) |
{ |
{ |
if (sftp_direct == NULL) { |
if (sftp_direct == NULL) { |
addargs(&args, "-s"); |
addargs(&args, "-s"); |
if (do_cmd(ssh_program, host, user, port, "sftp", |
if (do_cmd(ssh_program, host, user, port, "sftp", |
&remin, &remout) < 0) |
reminp, remoutp, pidp) < 0) |
return NULL; |
return NULL; |
|
|
} else { |
} else { |
args.list = NULL; |
args.list = NULL; |
addargs(&args, "sftp-server"); |
addargs(&args, "sftp-server"); |
if (do_cmd(sftp_direct, host, NULL, -1, "sftp", |
if (do_cmd(sftp_direct, host, NULL, -1, "sftp", |
&remin, &remout) < 0) |
reminp, remoutp, pidp) < 0) |
return NULL; |
return NULL; |
} |
} |
return do_init(remin, remout, 32768, 64, limit_kbps); |
return do_init(*reminp, *remoutp, 32768, 64, limit_kbps); |
} |
} |
|
|
void |
void |
|
|
char *bp, *tuser, *thost, *targ; |
char *bp, *tuser, *thost, *targ; |
char *remote_path = NULL; |
char *remote_path = NULL; |
int sport = -1, tport = -1; |
int sport = -1, tport = -1; |
struct sftp_conn *conn = NULL; |
struct sftp_conn *conn = NULL, *conn2 = NULL; |
arglist alist; |
arglist alist; |
int i, r; |
int i, r, status; |
u_int j; |
u_int j; |
|
|
memset(&alist, '\0', sizeof(alist)); |
memset(&alist, '\0', sizeof(alist)); |
|
|
continue; |
continue; |
} |
} |
if (host && throughlocal) { /* extended remote to remote */ |
if (host && throughlocal) { /* extended remote to remote */ |
/* XXX uses scp; need to support SFTP remote-remote */ |
if (mode == MODE_SFTP) { |
xasprintf(&bp, "%s -f %s%s", cmd, |
if (remin == -1) { |
*src == '-' ? "-- " : "", src); |
/* Connect to dest now */ |
if (do_cmd(ssh_program, host, suser, sport, bp, |
conn = do_sftp_connect(thost, tuser, |
&remin, &remout) < 0) |
tport, sftp_direct, |
exit(1); |
&remin, &remout, &do_cmd_pid); |
free(bp); |
if (conn == NULL) { |
xasprintf(&bp, "%s -t %s%s", cmd, |
fatal("Unable to open " |
*targ == '-' ? "-- " : "", targ); |
"destination connection"); |
if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0) |
} |
exit(1); |
debug3_f("origin in %d out %d pid %ld", |
free(bp); |
remin, remout, (long)do_cmd_pid); |
(void) close(remin); |
} |
(void) close(remout); |
/* |
remin = remout = -1; |
* XXX remember suser/host/sport and only |
|
* reconnect if they change between arguments. |
|
* would save reconnections for cases like |
|
* scp -3 hosta:/foo hosta:/bar hostb: |
|
*/ |
|
/* Connect to origin now */ |
|
conn2 = do_sftp_connect(host, suser, |
|
sport, sftp_direct, |
|
&remin2, &remout2, &do_cmd_pid2); |
|
if (conn2 == NULL) { |
|
fatal("Unable to open " |
|
"source connection"); |
|
} |
|
debug3_f("destination in %d out %d pid %ld", |
|
remin2, remout2, (long)do_cmd_pid2); |
|
throughlocal_sftp(conn2, conn, src, targ, |
|
&remote_path); |
|
(void) close(remin2); |
|
(void) close(remout2); |
|
remin2 = remout2 = -1; |
|
if (waitpid(do_cmd_pid2, &status, 0) == -1) |
|
++errs; |
|
else if (!WIFEXITED(status) || |
|
WEXITSTATUS(status) != 0) |
|
++errs; |
|
do_cmd_pid2 = -1; |
|
continue; |
|
} else { |
|
xasprintf(&bp, "%s -f %s%s", cmd, |
|
*src == '-' ? "-- " : "", src); |
|
if (do_cmd(ssh_program, host, suser, sport, |
|
bp, &remin, &remout, &do_cmd_pid) < 0) |
|
exit(1); |
|
free(bp); |
|
xasprintf(&bp, "%s -t %s%s", cmd, |
|
*targ == '-' ? "-- " : "", targ); |
|
if (do_cmd2(thost, tuser, tport, bp, |
|
remin, remout) < 0) |
|
exit(1); |
|
free(bp); |
|
(void) close(remin); |
|
(void) close(remout); |
|
remin = remout = -1; |
|
} |
} else if (host) { /* standard remote to remote */ |
} else if (host) { /* standard remote to remote */ |
/* |
/* |
* Second remote user is passed to first remote side |
* Second remote user is passed to first remote side |
|
|
if (remin == -1) { |
if (remin == -1) { |
/* Connect to remote now */ |
/* Connect to remote now */ |
conn = do_sftp_connect(thost, tuser, |
conn = do_sftp_connect(thost, tuser, |
tport, sftp_direct); |
tport, sftp_direct, |
|
&remin, &remout, &do_cmd_pid); |
if (conn == NULL) { |
if (conn == NULL) { |
fatal("Unable to open sftp " |
fatal("Unable to open sftp " |
"connection"); |
"connection"); |
|
|
xasprintf(&bp, "%s -t %s%s", cmd, |
xasprintf(&bp, "%s -t %s%s", cmd, |
*targ == '-' ? "-- " : "", targ); |
*targ == '-' ? "-- " : "", targ); |
if (do_cmd(ssh_program, thost, tuser, tport, bp, |
if (do_cmd(ssh_program, thost, tuser, tport, bp, |
&remin, &remout) < 0) |
&remin, &remout, &do_cmd_pid) < 0) |
exit(1); |
exit(1); |
if (response() < 0) |
if (response() < 0) |
exit(1); |
exit(1); |
|
|
} |
} |
/* Remote to local. */ |
/* Remote to local. */ |
if (mode == MODE_SFTP) { |
if (mode == MODE_SFTP) { |
conn = do_sftp_connect(host, suser, sport, sftp_direct); |
conn = do_sftp_connect(host, suser, sport, |
|
sftp_direct, &remin, &remout, &do_cmd_pid); |
if (conn == NULL) { |
if (conn == NULL) { |
error("Couldn't make sftp connection " |
error("Couldn't make sftp connection " |
"to server"); |
"to server"); |
|
|
/* SCP */ |
/* SCP */ |
xasprintf(&bp, "%s -f %s%s", |
xasprintf(&bp, "%s -f %s%s", |
cmd, *src == '-' ? "-- " : "", src); |
cmd, *src == '-' ? "-- " : "", src); |
if (do_cmd(ssh_program, host, suser, sport, bp, &remin, |
if (do_cmd(ssh_program, host, suser, sport, bp, |
&remout) < 0) { |
&remin, &remout, &do_cmd_pid) < 0) { |
free(bp); |
free(bp); |
++errs; |
++errs; |
continue; |
continue; |
|
|
free(patterns); |
free(patterns); |
run_err("protocol error: %s", why); |
run_err("protocol error: %s", why); |
exit(1); |
exit(1); |
|
} |
|
|
|
void |
|
throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to, |
|
char *src, char *targ, char **to_remote_path) |
|
{ |
|
char *target = NULL, *filename = NULL, *abs_dst = NULL; |
|
char *abs_src = NULL, *tmp = NULL, *from_remote_path; |
|
glob_t g; |
|
int i, r, targetisdir, err = 0; |
|
|
|
if (*to_remote_path == NULL) { |
|
*to_remote_path = do_realpath(to, "."); |
|
if (*to_remote_path == NULL) { |
|
fatal("Unable to determine destination remote " |
|
"working directory"); |
|
} |
|
} |
|
|
|
if ((from_remote_path = do_realpath(from, ".")) == NULL) { |
|
fatal("Unable to determine source remote " |
|
"working directory"); |
|
} |
|
|
|
if ((filename = basename(src)) == NULL) |
|
fatal("basename %s: %s", src, strerror(errno)); |
|
|
|
abs_src = xstrdup(src); |
|
abs_src = make_absolute(abs_src, from_remote_path); |
|
free(from_remote_path); |
|
target = xstrdup(targ); |
|
target = make_absolute(target, *to_remote_path); |
|
memset(&g, 0, sizeof(g)); |
|
|
|
targetisdir = remote_is_dir(to, target); |
|
if (!targetisdir && targetshouldbedirectory) { |
|
error("Destination path \"%s\" is not a directory", target); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
debug3_f("copying remote %s to remote %s", abs_src, target); |
|
if ((r = remote_glob(from, abs_src, GLOB_MARK, NULL, &g)) != 0) { |
|
if (r == GLOB_NOSPACE) |
|
error("Too many glob matches for \"%s\".", abs_src); |
|
else |
|
error("File \"%s\" not found.", abs_src); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
|
tmp = xstrdup(g.gl_pathv[i]); |
|
if ((filename = basename(tmp)) == NULL) { |
|
error("basename %s: %s", tmp, strerror(errno)); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
if (targetisdir) |
|
abs_dst = path_append(target, filename); |
|
else |
|
abs_dst = xstrdup(target); |
|
|
|
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
|
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { |
|
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst, |
|
NULL, pflag, 1) == -1) |
|
err = -1; |
|
} else { |
|
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL, |
|
pflag) == -1) |
|
err = -1; |
|
} |
|
free(abs_dst); |
|
abs_dst = NULL; |
|
free(tmp); |
|
tmp = NULL; |
|
} |
|
|
|
out: |
|
free(abs_src); |
|
free(abs_dst); |
|
free(target); |
|
free(tmp); |
|
globfree(&g); |
|
if (err == -1) |
|
fatal("Failed to download file '%s'", src); |
} |
} |
|
|
int |
int |