mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-12-24 02:42:25 +00:00
upstream: support for using the SFTP protocol for file transfers in
scp, via a new "-M sftp" option. Marked as experimental for now. Some corner-cases exist, in particular there is no attempt to provide bug-compatibility with scp's weird "double shell" quoting rules. Mostly by Jakub Jelen in GHPR#194 with some tweaks by me. ok markus@ Thanks jmc@ for improving the scp.1 bits. OpenBSD-Commit-ID: 6ce4c9157ff17b650ace571c9f7793d92874051c
This commit is contained in:
parent
dd533c7ab7
commit
197e29f1cc
2
.depend
2
.depend
@ -110,7 +110,7 @@ sandbox-seccomp-filter.o: includes.h config.h defines.h platform.h openbsd-compa
|
||||
sandbox-solaris.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
|
||||
sandbox-systrace.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
|
||||
sc25519.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sc25519.h crypto_api.h
|
||||
scp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h atomicio.h pathnames.h log.h ssherr.h misc.h progressmeter.h utf8.h
|
||||
scp.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h atomicio.h pathnames.h log.h ssherr.h misc.h progressmeter.h utf8.h sftp-common.h sftp-client.h openbsd-compat/glob.h
|
||||
servconf.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h openbsd-compat/sys-queue.h xmalloc.h ssh.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h pathnames.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h sshkey.h
|
||||
servconf.o: kex.h mac.h crypto_api.h match.h channels.h groupaccess.h canohost.h packet.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h myproposal.h digest.h
|
||||
serverloop.o: cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h hostfile.h auth.h auth-pam.h audit.h loginrec.h session.h auth-options.h serverloop.h
|
||||
|
@ -131,7 +131,9 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
|
||||
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
|
||||
sandbox-solaris.o uidswap.o $(SKOBJS)
|
||||
|
||||
SCP_OBJS= scp.o progressmeter.o
|
||||
SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
|
||||
|
||||
SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS)
|
||||
|
||||
SSHADD_OBJS= ssh-add.o $(SKOBJS)
|
||||
|
||||
@ -149,7 +151,7 @@ SSHKEYSCAN_OBJS=ssh-keyscan.o $(SKOBJS)
|
||||
|
||||
SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o
|
||||
|
||||
SFTP_OBJS= sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
|
||||
SFTP_OBJS= sftp.o progressmeter.o $(SFTP_CLIENT_OBJS)
|
||||
|
||||
MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-sk-helper.8.out sshd_config.5.out ssh_config.5.out
|
||||
MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-sk-helper.8 sshd_config.5 ssh_config.5
|
||||
|
21
scp.1
21
scp.1
@ -8,9 +8,9 @@
|
||||
.\"
|
||||
.\" Created: Sun May 7 00:14:37 1995 ylo
|
||||
.\"
|
||||
.\" $OpenBSD: scp.1,v 1.96 2021/07/02 05:11:21 dtucker Exp $
|
||||
.\" $OpenBSD: scp.1,v 1.97 2021/08/02 23:38:27 djm Exp $
|
||||
.\"
|
||||
.Dd $Mdocdate: July 2 2021 $
|
||||
.Dd $Mdocdate: August 2 2021 $
|
||||
.Dt SCP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -20,10 +20,12 @@
|
||||
.Nm scp
|
||||
.Op Fl 346ABCpqrTv
|
||||
.Op Fl c Ar cipher
|
||||
.Op Fl D Ar sftp_server_path
|
||||
.Op Fl F Ar ssh_config
|
||||
.Op Fl i Ar identity_file
|
||||
.Op Fl J Ar destination
|
||||
.Op Fl l Ar limit
|
||||
.Op Fl M Ar scp | sftp
|
||||
.Op Fl o Ar ssh_option
|
||||
.Op Fl P Ar port
|
||||
.Op Fl S Ar program
|
||||
@ -108,6 +110,13 @@ to enable compression.
|
||||
Selects the cipher to use for encrypting the data transfer.
|
||||
This option is directly passed to
|
||||
.Xr ssh 1 .
|
||||
.It Fl D Ar sftp_server_path
|
||||
When using the experimental SFTP protocol support via
|
||||
.Fl M ,
|
||||
connect directly to a local SFTP server program rather than a
|
||||
remote one via
|
||||
.Xr ssh 1 .
|
||||
This option may be useful in debugging the client and server.
|
||||
.It Fl F Ar ssh_config
|
||||
Specifies an alternative
|
||||
per-user configuration file for
|
||||
@ -134,6 +143,14 @@ This option is directly passed to
|
||||
.Xr ssh 1 .
|
||||
.It Fl l Ar limit
|
||||
Limits the used bandwidth, specified in Kbit/s.
|
||||
.It Fl M Ar scp | sftp
|
||||
Specifies a mode which will be used to transfer files.
|
||||
The default is to use the original
|
||||
.Cm scp
|
||||
protocol.
|
||||
Alternately, experimental support for using the
|
||||
.Cm sftp
|
||||
protocol is available.
|
||||
.It Fl o Ar ssh_option
|
||||
Can be used to pass options to
|
||||
.Nm ssh
|
||||
|
304
scp.c
304
scp.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: scp.c,v 1.215 2021/07/05 00:25:42 djm Exp $ */
|
||||
/* $OpenBSD: scp.c,v 1.216 2021/08/02 23:38:27 djm Exp $ */
|
||||
/*
|
||||
* scp - secure remote copy. This is basically patched BSD rcp which
|
||||
* uses ssh to do the data transfer (instead of using rcmd).
|
||||
@ -97,6 +97,10 @@
|
||||
#ifdef HAVE_FNMATCH_H
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
#include <glob.h>
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <pwd.h>
|
||||
@ -123,12 +127,17 @@
|
||||
#include "progressmeter.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#include "sftp-common.h"
|
||||
#include "sftp-client.h"
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
#define COPY_BUFLEN 16384
|
||||
|
||||
int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);
|
||||
int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);
|
||||
int do_cmd(char *program, char *host, char *remuser, int port, char *cmd,
|
||||
int *fdin, int *fdout);
|
||||
int do_cmd2(char *host, char *remuser, int port, char *cmd,
|
||||
int fdin, int fdout);
|
||||
|
||||
/* Struct for addargs */
|
||||
arglist args;
|
||||
@ -143,6 +152,7 @@ char *curfile;
|
||||
|
||||
/* This is set to non-zero to enable verbose mode. */
|
||||
int verbose_mode = 0;
|
||||
LogLevel log_level = SYSLOG_LEVEL_INFO;
|
||||
|
||||
/* This is set to zero if the progressmeter is not desired. */
|
||||
int showprogress = 1;
|
||||
@ -162,6 +172,12 @@ char *ssh_program = _PATH_SSH_PROGRAM;
|
||||
/* This is used to store the pid of ssh_program */
|
||||
pid_t do_cmd_pid = -1;
|
||||
|
||||
/* Needed for sftp */
|
||||
volatile sig_atomic_t interrupted = 0;
|
||||
|
||||
int remote_glob(struct sftp_conn *, const char *, int,
|
||||
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
|
||||
|
||||
static void
|
||||
killchild(int signo)
|
||||
{
|
||||
@ -238,14 +254,15 @@ do_local_cmd(arglist *a)
|
||||
*/
|
||||
|
||||
int
|
||||
do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
do_cmd(char *program, char *host, char *remuser, int port, char *cmd,
|
||||
int *fdin, int *fdout)
|
||||
{
|
||||
int pin[2], pout[2], reserved[2];
|
||||
|
||||
if (verbose_mode)
|
||||
fmprintf(stderr,
|
||||
"Executing: program %s host %s, user %s, command %s\n",
|
||||
ssh_program, host,
|
||||
program, host,
|
||||
remuser ? remuser : "(unspecified)", cmd);
|
||||
|
||||
if (port == -1)
|
||||
@ -283,7 +300,7 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
close(pin[0]);
|
||||
close(pout[1]);
|
||||
|
||||
replacearg(&args, 0, "%s", ssh_program);
|
||||
replacearg(&args, 0, "%s", program);
|
||||
if (port != -1) {
|
||||
addargs(&args, "-p");
|
||||
addargs(&args, "%d", port);
|
||||
@ -296,8 +313,8 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
|
||||
addargs(&args, "%s", host);
|
||||
addargs(&args, "%s", cmd);
|
||||
|
||||
execvp(ssh_program, args.list);
|
||||
perror(ssh_program);
|
||||
execvp(program, args.list);
|
||||
perror(program);
|
||||
exit(1);
|
||||
} else if (do_cmd_pid == -1) {
|
||||
fatal("fork: %s", strerror(errno));
|
||||
@ -388,22 +405,33 @@ int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
|
||||
#define CMDNEEDS 64
|
||||
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
|
||||
|
||||
enum scp_mode_e {
|
||||
MODE_SCP,
|
||||
MODE_SFTP
|
||||
};
|
||||
|
||||
int response(void);
|
||||
void rsource(char *, struct stat *);
|
||||
void sink(int, char *[], const char *);
|
||||
void source(int, char *[]);
|
||||
void tolocal(int, char *[]);
|
||||
void toremote(int, char *[]);
|
||||
void tolocal(int, char *[], enum scp_mode_e, char *sftp_direct);
|
||||
void toremote(int, char *[], enum scp_mode_e, char *sftp_direct);
|
||||
void usage(void);
|
||||
|
||||
void source_sftp(int, char *, char *, struct sftp_conn *, char **);
|
||||
void sink_sftp(int, char *, const char *, struct sftp_conn *);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ch, fflag, tflag, status, n;
|
||||
char **newargv;
|
||||
char **newargv, *argv0;
|
||||
const char *errstr;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
/* For now, keep SCP as default */
|
||||
enum scp_mode_e mode = MODE_SCP;
|
||||
char *sftp_direct = NULL;
|
||||
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||
sanitise_stdfd();
|
||||
@ -413,6 +441,7 @@ main(int argc, char **argv)
|
||||
msetlocale();
|
||||
|
||||
/* Copy argv, because we modify it */
|
||||
argv0 = argv[0];
|
||||
newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
|
||||
for (n = 0; n < argc; n++)
|
||||
newargv[n] = xstrdup(argv[n]);
|
||||
@ -432,7 +461,7 @@ main(int argc, char **argv)
|
||||
|
||||
fflag = Tflag = tflag = 0;
|
||||
while ((ch = getopt(argc, argv,
|
||||
"12346ABCTdfpqrtvF:J:P:S:c:i:l:o:")) != -1) {
|
||||
"12346ABCTdfpqrtvD:F:J:M:P:S:c:i:l:o:")) != -1) {
|
||||
switch (ch) {
|
||||
/* User-visible flags. */
|
||||
case '1':
|
||||
@ -448,6 +477,9 @@ main(int argc, char **argv)
|
||||
addargs(&args, "-%c", ch);
|
||||
addargs(&remote_remote_args, "-%c", ch);
|
||||
break;
|
||||
case 'D':
|
||||
sftp_direct = optarg;
|
||||
break;
|
||||
case '3':
|
||||
throughlocal = 1;
|
||||
break;
|
||||
@ -470,6 +502,14 @@ main(int argc, char **argv)
|
||||
addargs(&remote_remote_args, "-oBatchmode=yes");
|
||||
addargs(&args, "-oBatchmode=yes");
|
||||
break;
|
||||
case 'M':
|
||||
if (strcmp(optarg, "sftp") == 0)
|
||||
mode = MODE_SFTP;
|
||||
else if (strcmp(optarg, "scp") == 0)
|
||||
mode = MODE_SCP;
|
||||
else
|
||||
usage();
|
||||
break;
|
||||
case 'l':
|
||||
limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
|
||||
&errstr);
|
||||
@ -490,6 +530,10 @@ main(int argc, char **argv)
|
||||
case 'v':
|
||||
addargs(&args, "-v");
|
||||
addargs(&remote_remote_args, "-v");
|
||||
if (verbose_mode == 0)
|
||||
log_level = SYSLOG_LEVEL_DEBUG1;
|
||||
else if (log_level < SYSLOG_LEVEL_DEBUG3)
|
||||
log_level++;
|
||||
verbose_mode = 1;
|
||||
break;
|
||||
case 'q':
|
||||
@ -523,9 +567,17 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
log_init(argv0, log_level, SYSLOG_FACILITY_USER, 1);
|
||||
|
||||
/* Do this last because we want the user to be able to override it */
|
||||
addargs(&args, "-oForwardAgent=no");
|
||||
|
||||
if (mode != MODE_SFTP && sftp_direct != NULL)
|
||||
fatal("SFTP direct can be used only in SFTP mode");
|
||||
|
||||
if (mode == MODE_SFTP && iamremote)
|
||||
fatal("The server can not be ran in SFTP mode");
|
||||
|
||||
if ((pwd = getpwuid(userid = getuid())) == NULL)
|
||||
fatal("unknown user %u", (u_int) userid);
|
||||
|
||||
@ -572,11 +624,11 @@ main(int argc, char **argv)
|
||||
(void) ssh_signal(SIGPIPE, lostconn);
|
||||
|
||||
if (colon(argv[argc - 1])) /* Dest is remote host. */
|
||||
toremote(argc, argv);
|
||||
toremote(argc, argv, mode, sftp_direct);
|
||||
else {
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(argv[argc - 1]);
|
||||
tolocal(argc, argv); /* Dest is local host. */
|
||||
tolocal(argc, argv, mode, sftp_direct); /* Dest is local host. */
|
||||
}
|
||||
/*
|
||||
* Finally check the exit status of the ssh process, if one was forked
|
||||
@ -887,12 +939,33 @@ brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sftp_conn *
|
||||
do_sftp_connect(char *host, char *user, int port, char *sftp_direct)
|
||||
{
|
||||
if (sftp_direct == NULL) {
|
||||
addargs(&args, "-s");
|
||||
if (do_cmd(ssh_program, host, user, port, "sftp",
|
||||
&remin, &remout) < 0)
|
||||
return NULL;
|
||||
|
||||
} else {
|
||||
args.list = NULL;
|
||||
addargs(&args, "sftp-server");
|
||||
if (do_cmd(sftp_direct, host, NULL, -1, "sftp",
|
||||
&remin, &remout) < 0)
|
||||
return NULL;
|
||||
}
|
||||
return do_init(remin, remout, 32768, 64, limit_kbps);
|
||||
}
|
||||
|
||||
void
|
||||
toremote(int argc, char **argv)
|
||||
toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
|
||||
{
|
||||
char *suser = NULL, *host = NULL, *src = NULL;
|
||||
char *bp, *tuser, *thost, *targ;
|
||||
char *remote_path = NULL;
|
||||
int sport = -1, tport = -1;
|
||||
struct sftp_conn *conn = NULL;
|
||||
arglist alist;
|
||||
int i, r;
|
||||
u_int j;
|
||||
@ -935,9 +1008,15 @@ toremote(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
if (host && throughlocal) { /* extended remote to remote */
|
||||
if (mode == MODE_SFTP) {
|
||||
/* TODO */
|
||||
fatal("Extended remote to remote through local "
|
||||
"is not yet supported with SFTP");
|
||||
}
|
||||
xasprintf(&bp, "%s -f %s%s", cmd,
|
||||
*src == '-' ? "-- " : "", src);
|
||||
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
|
||||
if (do_cmd(ssh_program, host, suser, sport, bp,
|
||||
&remin, &remout) < 0)
|
||||
exit(1);
|
||||
free(bp);
|
||||
xasprintf(&bp, "%s -t %s%s", cmd,
|
||||
@ -985,6 +1064,14 @@ toremote(int argc, char **argv)
|
||||
addargs(&alist, "--");
|
||||
addargs(&alist, "%s", host);
|
||||
addargs(&alist, "%s", cmd);
|
||||
/*
|
||||
* This will work only if the first remote scp
|
||||
* supports sftp mode
|
||||
*/
|
||||
if (mode == MODE_SFTP) {
|
||||
addargs(&alist, "-M");
|
||||
addargs(&alist, "sftp");
|
||||
}
|
||||
addargs(&alist, "%s", src);
|
||||
addargs(&alist, "%s%s%s:%s",
|
||||
tuser ? tuser : "", tuser ? "@" : "",
|
||||
@ -992,11 +1079,28 @@ toremote(int argc, char **argv)
|
||||
if (do_local_cmd(&alist) != 0)
|
||||
errs = 1;
|
||||
} else { /* local to remote */
|
||||
if (mode == MODE_SFTP) {
|
||||
if (remin == -1) {
|
||||
/* Connect to remote now */
|
||||
conn = do_sftp_connect(thost, tuser,
|
||||
tport, sftp_direct);
|
||||
if (conn == NULL) {
|
||||
fatal("Unable to open sftp "
|
||||
"connection");
|
||||
}
|
||||
}
|
||||
|
||||
/* The protocol */
|
||||
source_sftp(1, argv[i], targ, conn,
|
||||
&remote_path);
|
||||
continue;
|
||||
}
|
||||
/* SCP */
|
||||
if (remin == -1) {
|
||||
xasprintf(&bp, "%s -t %s%s", cmd,
|
||||
*targ == '-' ? "-- " : "", targ);
|
||||
if (do_cmd(thost, tuser, tport, bp, &remin,
|
||||
&remout) < 0)
|
||||
if (do_cmd(ssh_program, thost, tuser, tport, bp,
|
||||
&remin, &remout) < 0)
|
||||
exit(1);
|
||||
if (response() < 0)
|
||||
exit(1);
|
||||
@ -1006,6 +1110,10 @@ toremote(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (mode == MODE_SFTP) {
|
||||
free(remote_path);
|
||||
free(conn);
|
||||
}
|
||||
free(tuser);
|
||||
free(thost);
|
||||
free(targ);
|
||||
@ -1015,10 +1123,11 @@ out:
|
||||
}
|
||||
|
||||
void
|
||||
tolocal(int argc, char **argv)
|
||||
tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
|
||||
{
|
||||
char *bp, *host = NULL, *src = NULL, *suser = NULL;
|
||||
arglist alist;
|
||||
struct sftp_conn *conn = NULL;
|
||||
int i, r, sport = -1;
|
||||
|
||||
memset(&alist, '\0', sizeof(alist));
|
||||
@ -1055,9 +1164,29 @@ tolocal(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
/* Remote to local. */
|
||||
if (mode == MODE_SFTP) {
|
||||
conn = do_sftp_connect(host, suser, sport, sftp_direct);
|
||||
if (conn == NULL) {
|
||||
error("Couldn't make sftp connection "
|
||||
"to server");
|
||||
++errs;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The protocol */
|
||||
sink_sftp(1, argv[argc - 1], src, conn);
|
||||
|
||||
free(conn);
|
||||
(void) close(remin);
|
||||
(void) close(remout);
|
||||
remin = remout = -1;
|
||||
continue;
|
||||
}
|
||||
/* SCP */
|
||||
xasprintf(&bp, "%s -f %s%s",
|
||||
cmd, *src == '-' ? "-- " : "", src);
|
||||
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
|
||||
if (do_cmd(ssh_program, host, suser, sport, bp, &remin,
|
||||
&remout) < 0) {
|
||||
free(bp);
|
||||
++errs;
|
||||
continue;
|
||||
@ -1072,6 +1201,53 @@ tolocal(int argc, char **argv)
|
||||
free(src);
|
||||
}
|
||||
|
||||
void
|
||||
source_sftp(int argc, char *src, char *targ,
|
||||
struct sftp_conn *conn, char **remote_path)
|
||||
{
|
||||
char *target = NULL, *filename = NULL, *abs_dst = NULL;
|
||||
int target_is_dir;
|
||||
|
||||
if (*remote_path == NULL) {
|
||||
*remote_path = do_realpath(conn, ".");
|
||||
if (*remote_path == NULL)
|
||||
fatal("Unable to determine remote working directory");
|
||||
}
|
||||
|
||||
if ((filename = basename(src)) == NULL)
|
||||
fatal("basename %s: %s", src, strerror(errno));
|
||||
|
||||
/*
|
||||
* No need to glob here - the local shell already took care of
|
||||
* the expansions
|
||||
*/
|
||||
target = xstrdup(targ);
|
||||
target = make_absolute(target, *remote_path);
|
||||
target_is_dir = remote_is_dir(conn, target);
|
||||
if (targetshouldbedirectory && !target_is_dir) {
|
||||
fatal("Target is not a directory, but more files selected "
|
||||
"for upload");
|
||||
}
|
||||
if (target_is_dir)
|
||||
abs_dst = path_append(target, filename);
|
||||
else {
|
||||
abs_dst = target;
|
||||
target = NULL;
|
||||
}
|
||||
debug3_f("copying local %s to remote %s", src, abs_dst);
|
||||
|
||||
if (local_is_dir(src) && iamrecursive) {
|
||||
if (upload_dir(conn, src, abs_dst, pflag, 1, 0, 0) != 0) {
|
||||
fatal("failed to upload directory %s to %s",
|
||||
src, abs_dst);
|
||||
}
|
||||
} else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0)
|
||||
fatal("failed to upload file %s to %s", src, abs_dst);
|
||||
|
||||
free(abs_dst);
|
||||
free(target);
|
||||
}
|
||||
|
||||
void
|
||||
source(int argc, char **argv)
|
||||
{
|
||||
@ -1233,6 +1409,88 @@ rsource(char *name, struct stat *statp)
|
||||
(void) response();
|
||||
}
|
||||
|
||||
void
|
||||
sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
|
||||
{
|
||||
char *abs_src = NULL;
|
||||
char *abs_dst = NULL;
|
||||
glob_t g;
|
||||
char *filename, *tmp = NULL, *remote_path = NULL;
|
||||
int i, r, err = 0;
|
||||
|
||||
/*
|
||||
* Here, we need remote glob as SFTP can not depend on remote shell
|
||||
* expansions
|
||||
*/
|
||||
|
||||
remote_path = do_realpath(conn, ".");
|
||||
if (remote_path == NULL) {
|
||||
error("Could not obtain remote working directory");
|
||||
/* TODO - gracefully degrade by using relative paths ? */
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
abs_src = xstrdup(src);
|
||||
abs_src = make_absolute(abs_src, remote_path);
|
||||
free(remote_path);
|
||||
memset(&g, 0, sizeof(g));
|
||||
|
||||
debug3_f("copying remote %s to local %s", abs_src, dst);
|
||||
if ((r = remote_glob(conn, 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;
|
||||
}
|
||||
|
||||
if (g.gl_matchc > 1 && !local_is_dir(dst)) {
|
||||
error("Multiple files match pattern, but destination "
|
||||
"\"%s\" is not a directory", dst);
|
||||
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));
|
||||
free(tmp);
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
if (local_is_dir(dst))
|
||||
abs_dst = path_append(dst, filename);
|
||||
else
|
||||
abs_dst = xstrdup(dst);
|
||||
|
||||
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
|
||||
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
|
||||
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
|
||||
pflag, 1, 0, 0) == -1)
|
||||
err = -1;
|
||||
} else {
|
||||
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
|
||||
pflag, 0, 0) == -1)
|
||||
err = -1;
|
||||
}
|
||||
free(abs_dst);
|
||||
abs_dst = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
free(abs_src);
|
||||
globfree(&g);
|
||||
if (err == -1) {
|
||||
fatal("Failed to download file '%s'", src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TYPE_OVERFLOW(type, val) \
|
||||
((sizeof(type) == 4 && (val) > INT32_MAX) || \
|
||||
(sizeof(type) == 8 && (val) > INT64_MAX) || \
|
||||
@ -1600,9 +1858,9 @@ void
|
||||
usage(void)
|
||||
{
|
||||
(void) fprintf(stderr,
|
||||
"usage: scp [-346ABCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
|
||||
" [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
|
||||
" [-S program] source ... target\n");
|
||||
"usage: scp [-346ABCpqrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
|
||||
" [-i identity_file] [-J destination] [-l limit] [-M scp|sftp]\n"
|
||||
" [-o ssh_option] [-P port] [-S program] source ... target\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user