diff options
author | millert@openbsd.org <millert@openbsd.org> | 2017-10-21 23:06:24 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2017-10-23 16:10:08 +1100 |
commit | 887669ef032d63cf07f53cada216fa8a0c9a7d72 (patch) | |
tree | 089b20255da21a489d7bc796a8ee86bd0b8f028f /scp.c | |
parent | d27bff293cfeb2252f4c7a58babe5ad3262c6c98 (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.c | 199 |
1 files changed, 105 insertions, 94 deletions
@@ -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); } |