summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c140
1 files changed, 105 insertions, 35 deletions
diff --git a/ssh.c b/ssh.c
index f9ff91f049d59..03a23fb6a3064 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.436 2016/02/15 09:47:49 dtucker Exp $ */
+/* $OpenBSD: ssh.c,v 1.445 2016/07/17 04:20:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -67,6 +67,7 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#include <locale.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -151,10 +152,6 @@ int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
*/
int fork_after_authentication_flag = 0;
-/* forward stdio to remote host and port */
-char *stdio_forward_host = NULL;
-int stdio_forward_port = 0;
-
/*
* General data structure for command line options and options configurable
* in configuration files. See readconf.h.
@@ -202,10 +199,11 @@ usage(void)
fprintf(stderr,
"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
" [-D [bind_address:]port] [-E log_file] [-e escape_char]\n"
-" [-F configfile] [-I pkcs11] [-i identity_file] [-L address]\n"
-" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
-" [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n"
-" [-w local_tun[:remote_tun]] [user@]hostname [command]\n"
+" [-F configfile] [-I pkcs11] [-i identity_file]\n"
+" [-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"
);
exit(255);
}
@@ -334,7 +332,7 @@ resolve_addr(const char *name, int port, char *caddr, size_t clen)
* NB. this function must operate with a options having undefined members.
*/
static int
-check_follow_cname(char **namep, const char *cname)
+check_follow_cname(int direct, char **namep, const char *cname)
{
int i;
struct allowed_cname *rule;
@@ -346,9 +344,9 @@ check_follow_cname(char **namep, const char *cname)
return 0;
/*
* Don't attempt to canonicalize names that will be interpreted by
- * a proxy unless the user specifically requests so.
+ * a proxy or jump host unless the user specifically requests so.
*/
- if (!option_clear_or_none(options.proxy_command) &&
+ if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return 0;
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
@@ -375,7 +373,7 @@ check_follow_cname(char **namep, const char *cname)
static struct addrinfo *
resolve_canonicalize(char **hostp, int port)
{
- int i, ndots;
+ int i, direct, ndots;
char *cp, *fullhost, newname[NI_MAXHOST];
struct addrinfo *addrs;
@@ -386,7 +384,9 @@ resolve_canonicalize(char **hostp, int port)
* Don't attempt to canonicalize names that will be interpreted by
* a proxy unless the user specifically requests so.
*/
- if (!option_clear_or_none(options.proxy_command) &&
+ direct = option_clear_or_none(options.proxy_command) &&
+ options.jump_host == NULL;
+ if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return NULL;
@@ -441,7 +441,7 @@ resolve_canonicalize(char **hostp, int port)
/* Remove trailing '.' */
fullhost[strlen(fullhost) - 1] = '\0';
/* Follow CNAME if requested */
- if (!check_follow_cname(&fullhost, newname)) {
+ if (!check_follow_cname(direct, &fullhost, newname)) {
debug("Canonicalized hostname \"%s\" => \"%s\"",
*hostp, fullhost);
}
@@ -513,7 +513,8 @@ set_addrinfo_port(struct addrinfo *addrs, int port)
int
main(int ac, char **av)
{
- int i, r, opt, exit_status, use_syslog, config_test = 0;
+ struct ssh *ssh = NULL;
+ int i, r, opt, exit_status, use_syslog, direct, config_test = 0;
char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
@@ -592,6 +593,8 @@ main(int ac, char **av)
*/
umask(022);
+ setlocale(LC_CTYPE, "");
+
/*
* Initialize option structure to indicate that no values have been
* set.
@@ -606,7 +609,7 @@ main(int ac, char **av)
again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
- "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
+ "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
@@ -650,7 +653,7 @@ main(int ac, char **av)
options.fwd_opts.gateway_ports = 1;
break;
case 'O':
- if (stdio_forward_host != NULL)
+ if (options.stdio_forward_host != NULL)
fatal("Cannot specify multiplexing "
"command with -W");
else if (muxclient_command != 0)
@@ -731,6 +734,15 @@ main(int ac, char **av)
fprintf(stderr, "no support for PKCS#11.\n");
#endif
break;
+ case 'J':
+ if (options.jump_host != NULL)
+ fatal("Only a single -J option permitted");
+ if (options.proxy_command != NULL)
+ fatal("Cannot specify -J with ProxyCommand");
+ if (parse_jump(optarg, &options, 1) == -1)
+ fatal("Invalid -J argument");
+ options.proxy_command = xstrdup("none");
+ break;
case 't':
if (options.request_tty == REQUEST_TTY_YES)
options.request_tty = REQUEST_TTY_FORCE;
@@ -742,8 +754,10 @@ main(int ac, char **av)
debug_flag = 1;
options.log_level = SYSLOG_LEVEL_DEBUG1;
} else {
- if (options.log_level < SYSLOG_LEVEL_DEBUG3)
+ if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
+ debug_flag++;
options.log_level++;
+ }
}
break;
case 'V':
@@ -769,13 +783,13 @@ main(int ac, char **av)
}
break;
case 'W':
- if (stdio_forward_host != NULL)
+ if (options.stdio_forward_host != NULL)
fatal("stdio forward already specified");
if (muxclient_command != 0)
fatal("Cannot specify stdio forward with -O");
if (parse_forward(&fwd, optarg, 1, 0)) {
- stdio_forward_host = fwd.listen_host;
- stdio_forward_port = fwd.listen_port;
+ options.stdio_forward_host = fwd.listen_host;
+ options.stdio_forward_port = fwd.listen_port;
free(fwd.connect_host);
} else {
fprintf(stderr,
@@ -785,8 +799,6 @@ main(int ac, char **av)
}
options.request_tty = REQUEST_TTY_NO;
no_shell_flag = 1;
- options.clear_forwardings = 1;
- options.exit_on_forward_failure = 1;
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
@@ -1043,9 +1055,10 @@ main(int ac, char **av)
* has specifically requested canonicalisation for this case via
* CanonicalizeHostname=always
*/
- if (addrs == NULL && options.num_permitted_cnames != 0 &&
- (option_clear_or_none(options.proxy_command) ||
- options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
+ direct = option_clear_or_none(options.proxy_command) &&
+ options.jump_host == NULL;
+ if (addrs == NULL && options.num_permitted_cnames != 0 && (direct ||
+ options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
if ((addrs = resolve_host(host, options.port,
option_clear_or_none(options.proxy_command),
cname, sizeof(cname))) == NULL) {
@@ -1053,7 +1066,7 @@ main(int ac, char **av)
if (option_clear_or_none(options.proxy_command))
cleanup_exit(255); /* logged in resolve_host */
} else
- check_follow_cname(&host, cname);
+ check_follow_cname(direct, &host, cname);
}
/*
@@ -1078,6 +1091,41 @@ main(int ac, char **av)
/* Fill configuration defaults. */
fill_default_options(&options);
+ /*
+ * If ProxyJump option specified, then construct a ProxyCommand now.
+ */
+ if (options.jump_host != NULL) {
+ char port_s[8];
+
+ /* Consistency check */
+ if (options.proxy_command != NULL)
+ fatal("inconsistent options: ProxyCommand+ProxyJump");
+ /* Never use FD passing for ProxyJump */
+ options.proxy_use_fdpass = 0;
+ snprintf(port_s, sizeof(port_s), "%d", options.jump_port);
+ xasprintf(&options.proxy_command,
+ "ssh%s%s%s%s%s%s%s%s%s%.*s -W %%h:%%p %s",
+ /* Optional "-l user" argument if jump_user set */
+ options.jump_user == NULL ? "" : " -l ",
+ options.jump_user == NULL ? "" : options.jump_user,
+ /* Optional "-p port" argument if jump_port set */
+ options.jump_port <= 0 ? "" : " -p ",
+ options.jump_port <= 0 ? "" : port_s,
+ /* Optional additional jump hosts ",..." */
+ options.jump_extra == NULL ? "" : " -J ",
+ options.jump_extra == NULL ? "" : options.jump_extra,
+ /* Optional "-F" argumment if -F specified */
+ config == NULL ? "" : " -F ",
+ config == NULL ? "" : config,
+ /* Optional "-v" arguments if -v set */
+ debug_flag ? " -" : "",
+ debug_flag, "vvv",
+ /* Mandatory hostname */
+ options.jump_host);
+ debug("Setting implicit ProxyCommand from ProxyJump: %s",
+ options.proxy_command);
+ }
+
if (options.port == 0)
options.port = default_ssh_port();
channel_set_af(options.address_family);
@@ -1220,6 +1268,8 @@ main(int ac, char **av)
packet_set_timeout(options.server_alive_interval,
options.server_alive_count_max);
+ ssh = active_state; /* XXX */
+
if (timeout_ms > 0)
debug3("timeout: %d ms remain after connect", timeout_ms);
@@ -1332,6 +1382,23 @@ main(int ac, char **av)
/* load options.identity_files */
load_public_identity_files();
+ /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */
+ if (options.identity_agent &&
+ strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
+ if (strcmp(options.identity_agent, "none") == 0) {
+ unsetenv(SSH_AUTHSOCKET_ENV_NAME);
+ } else {
+ p = tilde_expand_filename(options.identity_agent,
+ original_real_uid);
+ cp = percent_expand(p, "d", pw->pw_dir,
+ "u", pw->pw_name, "l", thishost, "h", host,
+ "r", options.user, (char *)NULL);
+ setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
+ free(cp);
+ free(p);
+ }
+ }
+
/* Expand ~ in known host file names. */
tilde_expand_paths(options.system_hostfiles,
options.num_system_hostfiles);
@@ -1346,7 +1413,7 @@ main(int ac, char **av)
if (packet_connection_is_on_socket()) {
verbose("Authenticated to %s ([%s]:%d).", host,
- get_remote_ipaddr(), get_remote_port());
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
} else {
verbose("Authenticated to %s (via proxy).", host);
}
@@ -1392,7 +1459,7 @@ static void
control_persist_detach(void)
{
pid_t pid;
- int devnull;
+ int devnull, keep_stderr;
debug("%s: backgrounding master process", __func__);
@@ -1423,8 +1490,10 @@ control_persist_detach(void)
error("%s: open(\"/dev/null\"): %s", __func__,
strerror(errno));
} else {
+ keep_stderr = log_is_on_stderr() && debug_flag;
if (dup2(devnull, STDIN_FILENO) == -1 ||
- dup2(devnull, STDOUT_FILENO) == -1)
+ dup2(devnull, STDOUT_FILENO) == -1 ||
+ (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1))
error("%s: dup2: %s", __func__, strerror(errno));
if (devnull > STDERR_FILENO)
close(devnull);
@@ -1516,18 +1585,19 @@ ssh_init_stdio_forwarding(void)
Channel *c;
int in, out;
- if (stdio_forward_host == NULL)
+ if (options.stdio_forward_host == NULL)
return;
if (!compat20)
fatal("stdio forwarding require Protocol 2");
- debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port);
+ debug3("%s: %s:%d", __func__, options.stdio_forward_host,
+ options.stdio_forward_port);
if ((in = dup(STDIN_FILENO)) < 0 ||
(out = dup(STDOUT_FILENO)) < 0)
fatal("channel_connect_stdio_fwd: dup() in/out failed");
- if ((c = channel_connect_stdio_fwd(stdio_forward_host,
- stdio_forward_port, in, out)) == NULL)
+ if ((c = channel_connect_stdio_fwd(options.stdio_forward_host,
+ options.stdio_forward_port, in, out)) == NULL)
fatal("%s: channel_connect_stdio_fwd failed", __func__);
channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL);