@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.279 2017/09/21 19:16:53 markus Exp $ */
/* $OpenBSD: readconf.c,v 1.280 2017/10/21 23:06:24 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -683,34 +683,6 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
return result;
}

/* Check and prepare a domain name: removes trailing '.' and lowercases */
static void
valid_domain(char *name, const char *filename, int linenum)
{
size_t i, l = strlen(name);
u_char c, last = '\0';

if (l == 0)
fatal("%s line %d: empty hostname suffix", filename, linenum);
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
fatal("%s line %d: hostname suffix \"%.100s\" "
"starts with invalid character", filename, linenum, name);
for (i = 0; i < l; i++) {
c = tolower((u_char)name[i]);
name[i] = (char)c;
if (last == '.' && c == '.')
fatal("%s line %d: hostname suffix \"%.100s\" contains "
"consecutive separators", filename, linenum, name);
if (c != '.' && c != '-' && !isalnum(c) &&
c != '_') /* technically invalid, but common */
fatal("%s line %d: hostname suffix \"%.100s\" contains "
"invalid characters", filename, linenum, name);
last = c;
}
if (name[l - 1] == '.')
name[l - 1] = '\0';
}

/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@@ -1562,7 +1534,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
case oCanonicalDomains:
value = options->num_canonical_domains != 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
valid_domain(arg, filename, linenum);
const char *errstr;
if (!valid_domain(arg, 1, &errstr)) {
fatal("%s line %d: %s", filename, linenum,
errstr);
}
if (!*activep || value)
continue;
if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
@@ -2294,11 +2270,13 @@ parse_jump(const char *s, Options *o, int active)

if (first) {
/* First argument and configuration is active */
if (parse_user_host_port(cp, &user, &host, &port) != 0)
if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
parse_user_host_port(cp, &user, &host, &port) != 0)
goto out;
} else {
/* Subsequent argument or inactive configuration */
if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
parse_user_host_port(cp, NULL, NULL, NULL) != 0)
goto out;
}
first = 0; /* only check syntax for subsequent hosts */
@@ -2323,6 +2301,18 @@ parse_jump(const char *s, Options *o, int active)
return ret;
}

int
parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
{
char *path;
int r;

r = parse_uri("ssh", uri, userp, hostp, portp, &path);
if (r == 0 && path != NULL)
r = -1; /* path not allowed */
return r;
}

/* XXX the following is a near-vebatim copy from servconf.c; refactor */
static const char *
fmt_multistate_int(int val, const struct multistate *m)
@@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.123 2017/09/03 23:33:13 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.124 2017/10/21 23:06:24 millert Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -204,6 +204,7 @@ int read_config_file(const char *, struct passwd *, const char *,
const char *, Options *, int);
int parse_forward(struct Forward *, const char *, int, int);
int parse_jump(const char *, Options *, int);
int parse_ssh_uri(const char *, char **, char **, int *);
int default_ssh_port(void);
int option_clear_or_none(const char *);
void dump_client_config(Options *o, const char *host);
41 scp.1
@@ -8,9 +8,9 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.74 2017/05/03 21:49:18 naddy Exp $
.\" $OpenBSD: scp.1,v 1.75 2017/10/21 23:06:24 millert Exp $
.\"
.Dd $Mdocdate: May 3 2017 $
.Dd $Mdocdate: October 21 2017 $
.Dt SCP 1
.Os
.Sh NAME
@@ -27,20 +27,8 @@
.Op Fl o Ar ssh_option
.Op Fl P Ar port
.Op Fl S Ar program
.Sm off
.Oo
.Op Ar user No @
.Ar host1 :
.Oc Ar file1
.Sm on
.Ar ...
.Sm off
.Oo
.Op Ar user No @
.Ar host2 :
.Oc Ar file2
.Sm on
.Ek
.Ar source ...
.Ar target
.Sh DESCRIPTION
.Nm
copies files between hosts on a network.
@@ -53,15 +41,30 @@ same security as
will ask for passwords or passphrases if they are needed for
authentication.
.Pp
File names may contain a user and host specification to indicate
that the file is to be copied to/from that host.
The
.Ar target
and
.Ar destination
may be specified as a local pathname, a remote host with optional path
in the form
.Oo Ar user Ns @ Oc Ns Ar host Ns : Ns Oo Ar path Oc ,
or an scp URI in the form
.No scp:// Ns Oo Ar user Ns @ Oc Ns Ar host Ns
.Oo : Ns Ar port Oc Ns Oo / Ns Ar path Oc .
Local file names can be made explicit using absolute or relative pathnames
to avoid
.Nm
treating file names containing
.Sq :\&
as host specifiers.
Copies between two remote hosts are also permitted.
.Pp
When copying between two remote hosts, if the URI format is used, a
.Ar port
may only be specified on the
.Ar target
if the
.Fl 3
option is used.
.Pp
The options are as follows:
.Bl -tag -width Ds
199 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,13 +327,20 @@ 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) {
dup2(fdin, 0);
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);
}

77 sftp.1
@@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.110 2017/05/03 21:49:18 naddy Exp $
.\" $OpenBSD: sftp.1,v 1.111 2017/10/21 23:06:24 millert Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: May 3 2017 $
.Dd $Mdocdate: October 21 2017 $
.Dt SFTP 1
.Os
.Sh NAME
@@ -44,54 +44,52 @@
.Op Fl R Ar num_requests
.Op Fl S Ar program
.Op Fl s Ar subsystem | sftp_server
.Ar host
.Ek
.Nm sftp
.Oo Ar user Ns @ Oc Ns
.Ar host Ns Op : Ns Ar
.Nm sftp
.Oo
.Ar user Ns @ Oc Ns
.Ar host Ns Oo : Ns Ar dir Ns
.Op Ar /
.Oc
.Nm sftp
.Fl b Ar batchfile
.Oo Ar user Ns @ Oc Ns Ar host
.Ar destination
.Sh DESCRIPTION
.Nm
is an interactive file transfer program, similar to
is a file transfer program, similar to
.Xr ftp 1 ,
which performs all operations over an encrypted
.Xr ssh 1
transport.
It may also use many features of ssh, such as public key authentication and
compression.
.Nm
connects and logs into the specified
.Ar host ,
then enters an interactive command mode.
.Pp
The second usage format will retrieve files automatically if a non-interactive
The
.Ar destination
may be specified either as
.Oo Ar user Ns @ Oc Ns Ar host Ns Oo : Ns Ar path Oc
or as an sftp URI in the form
.No sftp:// Ns Oo Ar user Ns @ Oc Ns Ar host Ns
.Oo : Ns Ar port Oc Ns Oo / Ns Ar path Oc .
.Pp
If the
.Ar destination
includes a
.Ar path
and it is not a directory,
.Nm
will retrieve files automatically if a non-interactive
authentication method is used; otherwise it will do so after
successful interactive authentication.
.Pp
The third usage format allows
If no
.Ar path
is specified, or if the
.Ar path
is a directory,
.Nm
to start in a remote directory.
.Pp
The final usage format allows for automated sessions using the
.Fl b
option.
In such cases, it is necessary to configure non-interactive authentication
to obviate the need to enter a password at connection time (see
.Xr sshd 8
and
.Xr ssh-keygen 1
for details).
will log in to the specified
.Ar host
and enter interactive command mode, changing to the remote directory
if one was specified.
An optional trailing slash can be used to force the
.Ar path
to be interpreted as a directory.
.Pp
Since some usage formats use colon characters to delimit host names from path
names, IPv6 addresses must be enclosed in square brackets to avoid ambiguity.
Since the destination formats use colon characters to delimit host
names from path names or port numbers, IPv6 addresses must be
enclosed in square brackets to avoid ambiguity.
.Pp
The options are as follows:
.Bl -tag -width Ds
@@ -121,7 +119,12 @@ Batch mode reads a series of commands from an input
instead of
.Em stdin .
Since it lacks user interaction it should be used in conjunction with
non-interactive authentication.
non-interactive authentication to obviate the need to enter a password
at connection time (see
.Xr sshd 8
and
.Xr ssh-keygen 1
for details).
A
.Ar batchfile
of
58 sftp.c
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */
/* $OpenBSD: sftp.c,v 1.181 2017/10/21 23:06:24 millert Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -2301,19 +2301,16 @@ usage(void)
"[-i identity_file] [-l limit]\n"
" [-o ssh_option] [-P port] [-R num_requests] "
"[-S program]\n"
" [-s subsystem | sftp_server] host\n"
" %s [user@]host[:file ...]\n"
" %s [user@]host[:dir[/]]\n"
" %s -b batchfile [user@]host\n",
__progname, __progname, __progname, __progname);
" [-s subsystem | sftp_server] destination\n",
__progname);
exit(1);
}

int
main(int argc, char **argv)
{
int in, out, ch, err;
char *host = NULL, *userhost, *cp, *file2 = NULL;
int in, out, ch, err, tmp, port = -1;
char *host = NULL, *user, *cp, *file2 = NULL;
int debug_level = 0, sshver = 2;
char *file1 = NULL, *sftp_server = NULL;
char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
@@ -2368,7 +2365,9 @@ main(int argc, char **argv)
addargs(&args, "-%c", ch);
break;
case 'P':
addargs(&args, "-oPort %s", optarg);
port = a2port(optarg);
if (port <= 0)
fatal("Bad port \"%s\"\n", optarg);
break;
case 'v':
if (debug_level < 3) {
@@ -2451,33 +2450,38 @@ main(int argc, char **argv)
if (sftp_direct == NULL) {
if (optind == argc || argc > (optind + 2))
usage();
argv += optind;

userhost = xstrdup(argv[optind]);
file2 = argv[optind+1];

if ((host = strrchr(userhost, '@')) == NULL)
host = userhost;
else {
*host++ = '\0';
if (!userhost[0]) {
fprintf(stderr, "Missing username\n");
usage();
switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) {
case -1:
usage();
break;
case 0:
if (tmp != -1)
port = tmp;
break;
default:
if (parse_user_host_path(*argv, &user, &host,
&file1) == -1) {
/* Treat as a plain hostname. */
host = xstrdup(*argv);
host = cleanhostname(host);
}
addargs(&args, "-l");
addargs(&args, "%s", userhost);
}

if ((cp = colon(host)) != NULL) {
*cp++ = '\0';
file1 = cp;
break;
}
file2 = *(argv + 1);

host = cleanhostname(host);
if (!*host) {
fprintf(stderr, "Missing hostname\n");
usage();
}

if (port != -1)
addargs(&args, "-oPort %d", port);
if (user != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", user);
}
addargs(&args, "-oProtocol %d", sshver);

/* no subsystem if the server-spec contains a '/' */
36 ssh.1
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.385 2017/10/13 06:45:18 djm Exp $
.Dd $Mdocdate: October 13 2017 $
.\" $OpenBSD: ssh.1,v 1.386 2017/10/21 23:06:24 millert Exp $
.Dd $Mdocdate: October 21 2017 $
.Dt SSH 1
.Os
.Sh NAME
@@ -52,7 +52,7 @@
.Op Fl F Ar configfile
.Op Fl I Ar pkcs11
.Op Fl i Ar identity_file
.Op Fl J Oo Ar user Ns @ Oc Ns Ar host Ns Op : Ns Ar port
.Op Fl J Ar destination
.Op Fl L Ar address
.Op Fl l Ar login_name
.Op Fl m Ar mac_spec
@@ -64,7 +64,7 @@
.Op Fl S Ar ctl_path
.Op Fl W Ar host : Ns Ar port
.Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun
.Oo Ar user Ns @ Oc Ns Ar hostname
.Ar destination
.Op Ar command
.Ek
.Sh DESCRIPTION
@@ -79,15 +79,23 @@ sockets can also be forwarded over the secure channel.
.Pp
.Nm
connects and logs into the specified
.Ar hostname
(with optional
.Ar destination
which may be specified as either
.Oo Ar user Ns @ Oc Ns Ar hostname
where the
.Ar user
is optional, or an ssh URI of the form
.No ssh:// Ns Oo Ar user Ns @ Oc Ns Ar hostname Ns Oo : Ns Ar port Oc
where the
.Ar user
name).
and
.Ar port
are optional.
The user must prove
his/her identity to the remote machine using one of several methods
(see below).
.Pp
If
If a
.Ar command
is specified,
it is executed on the remote host instead of a login shell.
@@ -287,17 +295,11 @@ by appending
.Pa -cert.pub
to identity filenames.
.Pp
.It Fl J Xo
.Sm off
.Op Ar user No @
.Ar host
.Op : Ar port
.Sm on
.Xc
.It Fl J Ar destination
Connect to the target host by first making a
.Nm
connection to the jump
.Ar host
connection to the jump host described by
.Ar destination
and then establishing a TCP forwarding to the ultimate destination from
there.
Multiple jump hops may be specified separated by comma characters.
56 ssh.c
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.464 2017/09/21 19:16:53 markus Exp $ */
/* $OpenBSD: ssh.c,v 1.465 2017/10/21 23:06:24 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -203,7 +203,7 @@ usage(void)
" [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n"
" [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n"
" [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n"
" [user@]hostname [command]\n"
" destination [command]\n"
);
exit(255);
}
@@ -846,14 +846,18 @@ main(int ac, char **av)
options.control_master = SSHCTL_MASTER_YES;
break;
case 'p':
options.port = a2port(optarg);
if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
exit(255);
if (options.port == -1) {
options.port = a2port(optarg);
if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n",
optarg);
exit(255);
}
}
break;
case 'l':
options.user = optarg;
if (options.user == NULL)
options.user = optarg;
break;

case 'L':
@@ -933,16 +937,38 @@ main(int ac, char **av)
av += optind;

if (ac > 0 && !host) {
if (strrchr(*av, '@')) {
int tport;
char *tuser;
switch (parse_ssh_uri(*av, &tuser, &host, &tport)) {
case -1:
usage();
break;
case 0:
if (options.user == NULL) {
options.user = tuser;
tuser = NULL;
}
free(tuser);
if (options.port == -1 && tport != -1)
options.port = tport;
break;
default:
p = xstrdup(*av);
cp = strrchr(p, '@');
if (cp == NULL || cp == p)
usage();
options.user = p;
*cp = '\0';
host = xstrdup(++cp);
} else
host = xstrdup(*av);
if (cp != NULL) {
if (cp == p)
usage();
if (options.user == NULL) {
options.user = p;
p = NULL;
}
*cp++ = '\0';
host = xstrdup(cp);
free(p);
} else
host = p;
break;
}
if (ac > 1 && !opt_terminated) {
optind = optreset = 1;
goto again;
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.259 2017/10/18 05:36:59 jmc Exp $
.Dd $Mdocdate: October 18 2017 $
.\" $OpenBSD: ssh_config.5,v 1.260 2017/10/21 23:06:24 millert Exp $
.Dd $Mdocdate: October 21 2017 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@@ -1198,13 +1198,14 @@ For example, the following directive would connect via an HTTP proxy at
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
.Ed
.It Cm ProxyJump
Specifies one or more jump proxies as
Specifies one or more jump proxies as either
.Xo
.Sm off
.Op Ar user No @
.Ar host
.Op : Ns Ar port
.Sm on
or an ssh URI
.Xc .
Multiple proxies may be separated by comma characters and will be visited
sequentially.