summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
authormillert@openbsd.org <millert@openbsd.org>2017-10-21 23:06:24 +0000
committerDamien Miller <djm@mindrot.org>2017-10-23 16:10:08 +1100
commit887669ef032d63cf07f53cada216fa8a0c9a7d72 (patch)
tree089b20255da21a489d7bc796a8ee86bd0b8f028f /scp.c
parentd27bff293cfeb2252f4c7a58babe5ad3262c6c98 (diff)
upstream commit
Add URI support to ssh, sftp and scp. For example ssh://user@host or sftp://user@host/path. The connection parameters described in draft-ietf-secsh-scp-sftp-ssh-uri-04 are not implemented since the ssh fingerprint format in the draft uses md5 with no way to specify the hash function type. OK djm@ Upstream-ID: 4ba3768b662d6722de59e6ecb00abf2d4bf9cacc
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c199
1 files changed, 105 insertions, 94 deletions
diff --git a/scp.c b/scp.c
index a533eb09..2103a54e 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.192 2017/05/31 09:15:42 deraadt Exp $ */
+/* $OpenBSD: scp.c,v 1.193 2017/10/21 23:06:24 millert Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@@ -112,6 +112,7 @@
#endif
#include "xmalloc.h"
+#include "ssh.h"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
@@ -123,8 +124,8 @@ 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);
+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);
/* Struct for addargs */
arglist args;
@@ -149,6 +150,9 @@ int showprogress = 1;
*/
int throughlocal = 0;
+/* Non-standard port to use for the ssh connection or -1. */
+int sshport = -1;
+
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM;
@@ -231,7 +235,7 @@ do_local_cmd(arglist *a)
*/
int
-do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
+do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
{
int pin[2], pout[2], reserved[2];
@@ -241,6 +245,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
+ if (port == -1)
+ port = sshport;
+
/*
* Reserve two descriptors so that the real pipes won't get
* descriptors 0 and 1 because that will screw up dup2 below.
@@ -274,6 +281,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
close(pout[1]);
replacearg(&args, 0, "%s", ssh_program);
+ if (port != -1) {
+ addargs(&args, "-p");
+ addargs(&args, "%d", port);
+ }
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
@@ -305,7 +316,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
* 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)
+do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
{
pid_t pid;
int status;
@@ -316,6 +327,9 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
+ if (port == -1)
+ port = sshport;
+
/* Fork a child to execute the command on the remote host using ssh. */
pid = fork();
if (pid == 0) {
@@ -323,6 +337,10 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
dup2(fdout, 1);
replacearg(&args, 0, "%s", ssh_program);
+ if (port != -1) {
+ addargs(&args, "-p");
+ addargs(&args, "%d", port);
+ }
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
@@ -367,14 +385,14 @@ void rsource(char *, struct stat *);
void sink(int, char *[]);
void source(int, char *[]);
void tolocal(int, char *[]);
-void toremote(char *, int, char *[]);
+void toremote(int, char *[]);
void usage(void);
int
main(int argc, char **argv)
{
int ch, fflag, tflag, status, n;
- char *targ, **newargv;
+ char **newargv;
const char *errstr;
extern char *optarg;
extern int optind;
@@ -430,10 +448,9 @@ main(int argc, char **argv)
addargs(&args, "%s", optarg);
break;
case 'P':
- addargs(&remote_remote_args, "-p");
- addargs(&remote_remote_args, "%s", optarg);
- addargs(&args, "-p");
- addargs(&args, "%s", optarg);
+ sshport = a2port(optarg);
+ if (sshport <= 0)
+ fatal("bad port \"%s\"\n", optarg);
break;
case 'B':
addargs(&remote_remote_args, "-oBatchmode=yes");
@@ -533,8 +550,8 @@ main(int argc, char **argv)
(void) signal(SIGPIPE, lostconn);
- if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
- toremote(targ, argc, argv);
+ if (colon(argv[argc - 1])) /* Dest is remote host. */
+ toremote(argc, argv);
else {
if (targetshouldbedirectory)
verifydir(argv[argc - 1]);
@@ -590,71 +607,65 @@ do_times(int fd, int verb, const struct stat *sb)
}
void
-toremote(char *targ, int argc, char **argv)
+toremote(int argc, char **argv)
{
- char *bp, *host, *src, *suser, *thost, *tuser, *arg;
+ char *suser = NULL, *host = NULL, *src = NULL;
+ char *bp, *tuser, *thost, *targ;
+ int sport = -1, tport = -1;
arglist alist;
- int i;
+ int i, r;
u_int j;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
- *targ++ = 0;
- if (*targ == 0)
- targ = ".";
-
- arg = xstrdup(argv[argc - 1]);
- if ((thost = strrchr(arg, '@'))) {
- /* user@host */
- *thost++ = 0;
- tuser = arg;
- if (*tuser == '\0')
- tuser = NULL;
- } else {
- thost = arg;
- tuser = NULL;
- }
-
- if (tuser != NULL && !okname(tuser)) {
- free(arg);
- return;
+ /* Parse target */
+ r = parse_uri("scp", argv[argc - 1], &tuser, &thost, &tport, &targ);
+ if (r == -1)
+ goto out; /* invalid URI */
+ if (r != 0) {
+ if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
+ &targ) == -1)
+ goto out;
}
+ if (tuser != NULL && !okname(tuser))
+ goto out;
+ /* Parse source files */
for (i = 0; i < argc - 1; i++) {
- src = colon(argv[i]);
- 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;
- }
+ free(suser);
+ free(host);
+ free(src);
+ r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
+ if (r == -1)
+ continue; /* invalid URI */
+ if (r != 0)
+ parse_user_host_path(argv[i], &suser, &host, &src);
+ if (suser != NULL && !okname(suser)) {
+ ++errs;
+ continue;
+ }
+ if (host && throughlocal) { /* extended remote to remote */
xasprintf(&bp, "%s -f %s%s", cmd,
*src == '-' ? "-- " : "", src);
- if (do_cmd(host, suser, bp, &remin, &remout) < 0)
+ if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
exit(1);
free(bp);
- host = cleanhostname(thost);
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
- if (do_cmd2(host, tuser, bp, remin, remout) < 0)
+ 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 (src) { /* standard remote to remote */
+ } else if (host) { /* standard remote to remote */
+ if (tport != -1 && tport != SSH_DEFAULT_PORT) {
+ /* This would require the remote support URIs */
+ fatal("target port not supported with two "
+ "remote hosts without the -3 option");
+ }
+
freeargs(&alist);
addargs(&alist, "%s", ssh_program);
addargs(&alist, "-x");
@@ -664,23 +675,14 @@ toremote(char *targ, int argc, char **argv)
addargs(&alist, "%s",
remote_remote_args.list[j]);
}
- *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;
+
+ if (sport != -1) {
+ addargs(&alist, "-p");
+ addargs(&alist, "%d", sport);
+ }
+ if (suser) {
addargs(&alist, "-l");
addargs(&alist, "%s", suser);
- } else {
- host = cleanhostname(argv[i]);
}
addargs(&alist, "--");
addargs(&alist, "%s", host);
@@ -695,8 +697,7 @@ toremote(char *targ, int argc, char **argv)
if (remin == -1) {
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
- host = cleanhostname(thost);
- if (do_cmd(host, tuser, bp, &remin,
+ if (do_cmd(thost, tuser, tport, bp, &remin,
&remout) < 0)
exit(1);
if (response() < 0)
@@ -706,21 +707,41 @@ toremote(char *targ, int argc, char **argv)
source(1, argv + i);
}
}
- free(arg);
+out:
+ free(tuser);
+ free(thost);
+ free(targ);
+ free(suser);
+ free(host);
+ free(src);
}
void
tolocal(int argc, char **argv)
{
- char *bp, *host, *src, *suser;
+ char *bp, *host = NULL, *src = NULL, *suser = NULL;
arglist alist;
- int i;
+ int i, r, sport = -1;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
for (i = 0; i < argc - 1; i++) {
- if (!(src = colon(argv[i]))) { /* Local to local. */
+ free(suser);
+ free(host);
+ free(src);
+ r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
+ if (r == -1) {
+ ++errs;
+ continue;
+ }
+ if (r != 0)
+ parse_user_host_path(argv[i], &suser, &host, &src);
+ if (suser != NULL && !okname(suser)) {
+ ++errs;
+ continue;
+ }
+ if (!host) { /* Local to local. */
freeargs(&alist);
addargs(&alist, "%s", _PATH_CP);
if (iamrecursive)
@@ -734,22 +755,10 @@ tolocal(int argc, char **argv)
++errs;
continue;
}
- *src++ = 0;
- if (*src == 0)
- src = ".";
- if ((host = strrchr(argv[i], '@')) == NULL) {
- host = argv[i];
- suser = NULL;
- } else {
- *host++ = 0;
- suser = argv[i];
- if (*suser == '\0')
- suser = pwd->pw_name;
- }
- host = cleanhostname(host);
+ /* Remote to local. */
xasprintf(&bp, "%s -f %s%s",
cmd, *src == '-' ? "-- " : "", src);
- if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
+ if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
free(bp);
++errs;
continue;
@@ -759,6 +768,9 @@ tolocal(int argc, char **argv)
(void) close(remin);
remin = remout = -1;
}
+ free(suser);
+ free(host);
+ free(src);
}
void
@@ -1275,8 +1287,7 @@ usage(void)
{
(void) fprintf(stderr,
"usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
- " [-l limit] [-o ssh_option] [-P port] [-S program]\n"
- " [[user@]host1:]file1 ... [[user@]host2:]file2\n");
+ " [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
exit(1);
}