diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 140 |
1 files changed, 105 insertions, 35 deletions
@@ -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); |