diff options
Diffstat (limited to 'crypto/openssh/ssh.c')
-rw-r--r-- | crypto/openssh/ssh.c | 403 |
1 files changed, 296 insertions, 107 deletions
diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index eaeb5c7..046dc9d 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.401 2014/02/26 20:18:37 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.420 2015/07/30 00:01:34 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -49,7 +49,6 @@ __RCSID("$FreeBSD$"); #endif #include <sys/resource.h> #include <sys/ioctl.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/wait.h> @@ -68,12 +67,15 @@ __RCSID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <limits.h> #include <netinet/in.h> #include <arpa/inet.h> +#ifdef WITH_OPENSSL #include <openssl/evp.h> #include <openssl/err.h> +#endif #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" @@ -84,6 +86,7 @@ __RCSID("$FreeBSD$"); #include "canohost.h" #include "compat.h" #include "cipher.h" +#include "digest.h" #include "packet.h" #include "buffer.h" #include "channels.h" @@ -94,9 +97,9 @@ __RCSID("$FreeBSD$"); #include "dispatch.h" #include "clientloop.h" #include "log.h" +#include "misc.h" #include "readconf.h" #include "sshconnect.h" -#include "misc.h" #include "kex.h" #include "mac.h" #include "sshpty.h" @@ -105,6 +108,8 @@ __RCSID("$FreeBSD$"); #include "uidswap.h" #include "roaming.h" #include "version.h" +#include "ssherr.h" +#include "myproposal.h" #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -197,13 +202,13 @@ static void usage(void) { fprintf(stderr, -"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" +"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]\n" -" [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]\n" +" [-L address] [-l login_name] [-m mac_spec]\n" " [-O ctl_cmd] [-o option] [-p port]\n" " [-Q cipher | cipher-auth | mac | kex | key]\n" -" [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]\n" +" [-R address] [-S ctl_path] [-W host:port]\n" " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" ); exit(255); @@ -274,6 +279,60 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen) } /* + * Attempt to resolve a numeric host address / port to a single address. + * Returns a canonical address string. + * Returns NULL on failure. + * NB. this function must operate with a options having undefined members. + */ +static struct addrinfo * +resolve_addr(const char *name, int port, char *caddr, size_t clen) +{ + char addr[NI_MAXHOST], strport[NI_MAXSERV]; + struct addrinfo hints, *res; + int gaierr; + + if (port <= 0) + port = default_ssh_port(); + snprintf(strport, sizeof strport, "%u", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = options.address_family == -1 ? + AF_UNSPEC : options.address_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; + if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { + debug2("%s: could not resolve name %.100s as address: %s", + __func__, name, ssh_gai_strerror(gaierr)); + return NULL; + } + if (res == NULL) { + debug("%s: getaddrinfo %.100s returned no addresses", + __func__, name); + return NULL; + } + if (res->ai_next != NULL) { + debug("%s: getaddrinfo %.100s returned multiple addresses", + __func__, name); + goto fail; + } + if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen, + addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) { + debug("%s: Could not format address for name %.100s: %s", + __func__, name, ssh_gai_strerror(gaierr)); + goto fail; + } + if (strlcpy(caddr, addr, clen) >= clen) { + error("%s: host \"%s\" addr \"%s\" too long (max %lu)", + __func__, name, addr, (u_long)clen); + if (clen > 0) + *caddr = '\0'; + fail: + freeaddrinfo(res); + return NULL; + } + return res; +} + +/* * Check whether the cname is a permitted replacement for the hostname * and perform the replacement if it is. * NB. this function must operate with a options having undefined members. @@ -299,10 +358,8 @@ check_follow_cname(char **namep, const char *cname) debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); for (i = 0; i < options.num_permitted_cnames; i++) { rule = options.permitted_cnames + i; - if (match_pattern_list(*namep, rule->source_list, - strlen(rule->source_list), 1) != 1 || - match_pattern_list(cname, rule->target_list, - strlen(rule->target_list), 1) != 1) + if (match_pattern_list(*namep, rule->source_list, 1) != 1 || + match_pattern_list(cname, rule->target_list, 1) != 1) continue; verbose("Canonicalized DNS aliased hostname " "\"%s\" => \"%s\"", *namep, cname); @@ -323,7 +380,7 @@ static struct addrinfo * resolve_canonicalize(char **hostp, int port) { int i, ndots; - char *cp, *fullhost, cname_target[NI_MAXHOST]; + char *cp, *fullhost, newname[NI_MAXHOST]; struct addrinfo *addrs; if (options.canonicalize_hostname == SSH_CANONICALISE_NO) @@ -337,6 +394,19 @@ resolve_canonicalize(char **hostp, int port) options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) return NULL; + /* Try numeric hostnames first */ + if ((addrs = resolve_addr(*hostp, port, + newname, sizeof(newname))) != NULL) { + debug2("%s: hostname %.100s is address", __func__, *hostp); + if (strcasecmp(*hostp, newname) != 0) { + debug2("%s: canonicalised address \"%s\" => \"%s\"", + __func__, *hostp, newname); + free(*hostp); + *hostp = xstrdup(newname); + } + return addrs; + } + /* Don't apply canonicalization to sufficiently-qualified hostnames */ ndots = 0; for (cp = *hostp; *cp != '\0'; cp++) { @@ -350,20 +420,20 @@ resolve_canonicalize(char **hostp, int port) } /* Attempt each supplied suffix */ for (i = 0; i < options.num_canonical_domains; i++) { - *cname_target = '\0'; + *newname = '\0'; xasprintf(&fullhost, "%s.%s.", *hostp, options.canonical_domains[i]); debug3("%s: attempting \"%s\" => \"%s\"", __func__, *hostp, fullhost); if ((addrs = resolve_host(fullhost, port, 0, - cname_target, sizeof(cname_target))) == NULL) { + newname, sizeof(newname))) == NULL) { free(fullhost); continue; } /* Remove trailing '.' */ fullhost[strlen(fullhost) - 1] = '\0'; /* Follow CNAME if requested */ - if (!check_follow_cname(&fullhost, cname_target)) { + if (!check_follow_cname(&fullhost, newname)) { debug("Canonicalized hostname \"%s\" => \"%s\"", *hostp, fullhost); } @@ -382,27 +452,49 @@ resolve_canonicalize(char **hostp, int port) * file if the user specifies a config file on the command line. */ static void -process_config_files(struct passwd *pw) +process_config_files(const char *host_arg, struct passwd *pw, int post_canon) { - char buf[MAXPATHLEN]; + char buf[PATH_MAX]; int r; if (config != NULL) { if (strcasecmp(config, "none") != 0 && - !read_config_file(config, pw, host, &options, - SSHCONF_USERCONF)) + !read_config_file(config, pw, host, host_arg, &options, + SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) - (void)read_config_file(buf, pw, host, &options, - SSHCONF_CHECKPERM|SSHCONF_USERCONF); + (void)read_config_file(buf, pw, host, host_arg, + &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | + (post_canon ? SSHCONF_POSTCANON : 0)); /* Read systemwide configuration file after user config. */ - (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, - &options, 0); + (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, + host, host_arg, &options, + post_canon ? SSHCONF_POSTCANON : 0); + } +} + +/* Rewrite the port number in an addrinfo list of addresses */ +static void +set_addrinfo_port(struct addrinfo *addrs, int port) +{ + struct addrinfo *addr; + + for (addr = addrs; addr != NULL; addr = addr->ai_next) { + switch (addr->ai_family) { + case AF_INET: + ((struct sockaddr_in *)addr->ai_addr)-> + sin_port = htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *)addr->ai_addr)-> + sin6_port = htons(port); + break; + } } } @@ -412,8 +504,8 @@ process_config_files(struct passwd *pw) int main(int ac, char **av) { - int i, r, opt, exit_status, use_syslog; - char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; + int i, r, opt, exit_status, use_syslog, 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]; struct stat st; @@ -421,8 +513,11 @@ main(int ac, char **av) int timeout_ms; extern int optind, optreset; extern char *optarg; - Forward fwd; + struct Forward fwd; struct addrinfo *addrs = NULL; + struct ssh_digest_ctx *md; + u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; + char *conn_hash_hex; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -502,7 +597,7 @@ main(int ac, char **av) again: while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" - "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { + "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -535,12 +630,15 @@ main(int ac, char **av) case 'E': logfile = xstrdup(optarg); break; + case 'G': + config_test = 1; + break; case 'Y': options.forward_x11 = 1; options.forward_x11_trusted = 1; break; case 'g': - options.gateway_ports = 1; + options.fwd_opts.gateway_ports = 1; break; case 'O': if (stdio_forward_host != NULL) @@ -580,6 +678,13 @@ main(int ac, char **av) cp = key_alg_list(1, 0); else if (strcmp(optarg, "key-plain") == 0) cp = key_alg_list(0, 1); + else if (strcmp(optarg, "protocol-version") == 0) { +#ifdef WITH_SSH1 + cp = xstrdup("1\n2"); +#else + cp = xstrdup("2"); +#endif + } if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); printf("%s\n", cp); @@ -635,10 +740,10 @@ main(int ac, char **av) *options.version_addendum != '\0') fprintf(stderr, "%s %s, %s\n", SSH_RELEASE, options.version_addendum, - SSLeay_version(SSLEAY_VERSION)); + OPENSSL_VERSION); else fprintf(stderr, "%s, %s\n", SSH_RELEASE, - SSLeay_version(SSLEAY_VERSION)); + OPENSSL_VERSION); if (opt == 'V') exit(0); break; @@ -691,26 +796,26 @@ main(int ac, char **av) } break; case 'c': - if (ciphers_valid(optarg)) { + if (ciphers_valid(*optarg == '+' ? + optarg + 1 : optarg)) { /* SSH2 only */ options.ciphers = xstrdup(optarg); options.cipher = SSH_CIPHER_INVALID; - } else { - /* SSH1 only */ - options.cipher = cipher_number(optarg); - if (options.cipher == -1) { - fprintf(stderr, - "Unknown cipher type '%s'\n", - optarg); - exit(255); - } - if (options.cipher == SSH_CIPHER_3DES) - options.ciphers = "3des-cbc"; - else if (options.cipher == SSH_CIPHER_BLOWFISH) - options.ciphers = "blowfish-cbc"; - else - options.ciphers = (char *)-1; + break; + } + /* SSH1 only */ + options.cipher = cipher_number(optarg); + if (options.cipher == -1) { + fprintf(stderr, "Unknown cipher type '%s'\n", + optarg); + exit(255); } + if (options.cipher == SSH_CIPHER_3DES) + options.ciphers = xstrdup("3des-cbc"); + else if (options.cipher == SSH_CIPHER_BLOWFISH) + options.ciphers = xstrdup("blowfish-cbc"); + else + options.ciphers = xstrdup(KEX_CLIENT_ENCRYPT); break; case 'm': if (mac_valid(optarg)) @@ -783,9 +888,9 @@ main(int ac, char **av) break; case 'o': line = xstrdup(optarg); - if (process_config_line(&options, pw, host ? host : "", - line, "command-line", 0, NULL, SSHCONF_USERCONF) - != 0) + if (process_config_line(&options, pw, + host ? host : "", host ? host : "", line, + "command-line", 0, NULL, SSHCONF_USERCONF) != 0) exit(255); free(line); break; @@ -835,8 +940,10 @@ main(int ac, char **av) host_arg = xstrdup(host); +#ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); +#endif /* Initialize the command to execute on remote host. */ buffer_init(&command); @@ -883,10 +990,11 @@ main(int ac, char **av) SYSLOG_FACILITY_USER, !use_syslog); if (debug_flag) - logit("%s, %s", SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); + /* version_addendum is always NULL at this point */ + logit("%s, %s", SSH_RELEASE, OPENSSL_VERSION); /* Parse the configuration files */ - process_config_files(pw); + process_config_files(host_arg, pw, 0); /* Hostname canonicalisation needs a few options filled. */ fill_default_options_for_canonicalization(&options); @@ -898,6 +1006,8 @@ main(int ac, char **av) "h", host, (char *)NULL); free(host); host = cp; + free(options.hostname); + options.hostname = xstrdup(host); } /* If canonicalization requested then try to apply it */ @@ -921,19 +1031,33 @@ main(int ac, char **av) if (addrs == NULL && options.num_permitted_cnames != 0 && (option_clear_or_none(options.proxy_command) || options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) { - if ((addrs = resolve_host(host, options.port, 1, - cname, sizeof(cname))) == NULL) - cleanup_exit(255); /* resolve_host logs the error */ - check_follow_cname(&host, cname); + if ((addrs = resolve_host(host, options.port, + option_clear_or_none(options.proxy_command), + cname, sizeof(cname))) == NULL) { + /* Don't fatal proxied host names not in the DNS */ + if (option_clear_or_none(options.proxy_command)) + cleanup_exit(255); /* logged in resolve_host */ + } else + check_follow_cname(&host, cname); } /* - * If the target hostname has changed as a result of canonicalisation - * then re-parse the configuration files as new stanzas may match. + * If canonicalisation is enabled then re-parse the configuration + * files as new stanzas may match. */ - if (strcasecmp(host_arg, host) != 0) { - debug("Hostname has changed; re-reading configuration"); - process_config_files(pw); + if (options.canonicalize_hostname != 0) { + debug("Re-reading configuration after hostname " + "canonicalisation"); + free(options.hostname); + options.hostname = xstrdup(host); + process_config_files(host_arg, pw, 1); + /* + * Address resolution happens early with canonicalisation + * enabled and the port number may have changed since, so + * reset it in address list + */ + if (addrs != NULL && options.port > 0) + set_addrinfo_port(addrs, options.port); } /* Fill configuration defaults. */ @@ -950,6 +1074,12 @@ main(int ac, char **av) strcmp(options.proxy_command, "-") == 0 && options.proxy_use_fdpass) fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); + if (options.control_persist && + options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { + debug("UpdateHostKeys=ask is incompatible with ControlPersist; " + "disabling"); + options.update_hostkeys = 0; + } #ifndef HAVE_CYGWIN if (original_effective_uid != 0) options.use_privileged_port = 0; @@ -1006,12 +1136,29 @@ main(int ac, char **av) } } + if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || + ssh_digest_update(md, thishost, strlen(thishost)) < 0 || + ssh_digest_update(md, host, strlen(host)) < 0 || + ssh_digest_update(md, portstr, strlen(portstr)) < 0 || + ssh_digest_update(md, options.user, strlen(options.user)) < 0 || + ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) + fatal("%s: mux digest failed", __func__); + ssh_digest_free(md); + conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); + if (options.local_command != NULL) { debug3("expanding LocalCommand: %s", options.local_command); cp = options.local_command; - options.local_command = percent_expand(cp, "d", pw->pw_dir, - "h", host, "l", thishost, "n", host_arg, "r", options.user, - "p", portstr, "u", pw->pw_name, "L", shorthost, + options.local_command = percent_expand(cp, + "C", conn_hash_hex, + "L", shorthost, + "d", pw->pw_dir, + "h", host, + "l", thishost, + "n", host_arg, + "p", portstr, + "r", options.user, + "u", pw->pw_name, (char *)NULL); debug3("expanded LocalCommand: %s", options.local_command); free(cp); @@ -1021,12 +1168,25 @@ main(int ac, char **av) cp = tilde_expand_filename(options.control_path, original_real_uid); free(options.control_path); - options.control_path = percent_expand(cp, "h", host, - "l", thishost, "n", host_arg, "r", options.user, - "p", portstr, "u", pw->pw_name, "L", shorthost, + options.control_path = percent_expand(cp, + "C", conn_hash_hex, + "L", shorthost, + "h", host, + "l", thishost, + "n", host_arg, + "p", portstr, + "r", options.user, + "u", pw->pw_name, (char *)NULL); free(cp); } + free(conn_hash_hex); + + if (config_test) { + dump_client_config(&options, host); + exit(0); + } + if (muxclient_command != 0 && options.control_path == NULL) fatal("No ControlPath specified for \"-O\" command"); if (options.control_path != NULL) @@ -1082,26 +1242,26 @@ main(int ac, char **av) PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, - _PATH_HOST_DSA_KEY_FILE, "", NULL); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA, + sensitive_data.keys[1] = key_load_private_cert(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL); #endif + sensitive_data.keys[2] = key_load_private_cert(KEY_ED25519, + _PATH_HOST_ED25519_KEY_FILE, "", NULL); sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); - sensitive_data.keys[4] = key_load_private_cert(KEY_ED25519, - _PATH_HOST_ED25519_KEY_FILE, "", NULL); - sensitive_data.keys[5] = key_load_private_type(KEY_DSA, - _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); + sensitive_data.keys[4] = key_load_private_cert(KEY_DSA, + _PATH_HOST_DSA_KEY_FILE, "", NULL); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[6] = key_load_private_type(KEY_ECDSA, + sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); #endif + sensitive_data.keys[6] = key_load_private_type(KEY_ED25519, + _PATH_HOST_ED25519_KEY_FILE, "", NULL, NULL); sensitive_data.keys[7] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[8] = key_load_private_type(KEY_ED25519, - _PATH_HOST_ED25519_KEY_FILE, "", NULL, NULL); + sensitive_data.keys[8] = key_load_private_type(KEY_DSA, + _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); PRIV_END; if (options.hostbased_authentication == 1 && @@ -1110,26 +1270,26 @@ main(int ac, char **av) sensitive_data.keys[6] == NULL && sensitive_data.keys[7] == NULL && sensitive_data.keys[8] == NULL) { - sensitive_data.keys[1] = key_load_cert( - _PATH_HOST_DSA_KEY_FILE); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[2] = key_load_cert( + sensitive_data.keys[1] = key_load_cert( _PATH_HOST_ECDSA_KEY_FILE); #endif + sensitive_data.keys[2] = key_load_cert( + _PATH_HOST_ED25519_KEY_FILE); sensitive_data.keys[3] = key_load_cert( _PATH_HOST_RSA_KEY_FILE); sensitive_data.keys[4] = key_load_cert( - _PATH_HOST_ED25519_KEY_FILE); - sensitive_data.keys[5] = key_load_public( - _PATH_HOST_DSA_KEY_FILE, NULL); + _PATH_HOST_DSA_KEY_FILE); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[6] = key_load_public( + sensitive_data.keys[5] = key_load_public( _PATH_HOST_ECDSA_KEY_FILE, NULL); #endif + sensitive_data.keys[6] = key_load_public( + _PATH_HOST_ED25519_KEY_FILE, NULL); sensitive_data.keys[7] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.keys[8] = key_load_public( - _PATH_HOST_ED25519_KEY_FILE, NULL); + _PATH_HOST_DSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } } @@ -1280,13 +1440,17 @@ fork_postauth(void) static void ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) { - Forward *rfwd = (Forward *)ctxt; + struct Forward *rfwd = (struct Forward *)ctxt; /* XXX verbose() on failure? */ - debug("remote forward %s for: listen %d, connect %s:%d", + debug("remote forward %s for: listen %s%s%d, connect %s:%d", type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", - rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); - if (rfwd->listen_port == 0) { + rfwd->listen_path ? rfwd->listen_path : + rfwd->listen_host ? rfwd->listen_host : "", + (rfwd->listen_path || rfwd->listen_host) ? ":" : "", + rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : + rfwd->connect_host, rfwd->connect_port); + if (rfwd->listen_path == NULL && rfwd->listen_port == 0) { if (type == SSH2_MSG_REQUEST_SUCCESS) { rfwd->allocated_port = packet_get_int(); logit("Allocated port %u for remote forward to %s:%d", @@ -1300,12 +1464,21 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) } if (type == SSH2_MSG_REQUEST_FAILURE) { - if (options.exit_on_forward_failure) - fatal("Error: remote port forwarding failed for " - "listen port %d", rfwd->listen_port); - else - logit("Warning: remote port forwarding failed for " - "listen port %d", rfwd->listen_port); + if (options.exit_on_forward_failure) { + if (rfwd->listen_path != NULL) + fatal("Error: remote port forwarding failed " + "for listen path %s", rfwd->listen_path); + else + fatal("Error: remote port forwarding failed " + "for listen port %d", rfwd->listen_port); + } else { + if (rfwd->listen_path != NULL) + logit("Warning: remote port forwarding failed " + "for listen path %s", rfwd->listen_path); + else + logit("Warning: remote port forwarding failed " + "for listen port %d", rfwd->listen_port); + } } if (++remote_forward_confirms_received == options.num_remote_forwards) { debug("All remote forwarding requests processed"); @@ -1322,6 +1495,13 @@ client_cleanup_stdio_fwd(int id, void *arg) } static void +ssh_stdio_confirm(int id, int success, void *arg) +{ + if (!success) + fatal("stdio forwarding failed"); +} + +static void ssh_init_stdio_forwarding(void) { Channel *c; @@ -1341,6 +1521,7 @@ ssh_init_stdio_forwarding(void) 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); } static void @@ -1353,18 +1534,18 @@ ssh_init_forwarding(void) for (i = 0; i < options.num_local_forwards; i++) { debug("Local connections to %.200s:%d forwarded to remote " "address %.200s:%d", + (options.local_forwards[i].listen_path != NULL) ? + options.local_forwards[i].listen_path : (options.local_forwards[i].listen_host == NULL) ? - (options.gateway_ports ? "*" : "LOCALHOST") : + (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : options.local_forwards[i].listen_host, options.local_forwards[i].listen_port, + (options.local_forwards[i].connect_path != NULL) ? + options.local_forwards[i].connect_path : options.local_forwards[i].connect_host, options.local_forwards[i].connect_port); success += channel_setup_local_fwd_listener( - options.local_forwards[i].listen_host, - options.local_forwards[i].listen_port, - options.local_forwards[i].connect_host, - options.local_forwards[i].connect_port, - options.gateway_ports); + &options.local_forwards[i], &options.fwd_opts); } if (i > 0 && success != i && options.exit_on_forward_failure) fatal("Could not request local forwarding."); @@ -1375,17 +1556,18 @@ ssh_init_forwarding(void) for (i = 0; i < options.num_remote_forwards; i++) { debug("Remote connections from %.200s:%d forwarded to " "local address %.200s:%d", + (options.remote_forwards[i].listen_path != NULL) ? + options.remote_forwards[i].listen_path : (options.remote_forwards[i].listen_host == NULL) ? "LOCALHOST" : options.remote_forwards[i].listen_host, options.remote_forwards[i].listen_port, + (options.remote_forwards[i].connect_path != NULL) ? + options.remote_forwards[i].connect_path : options.remote_forwards[i].connect_host, options.remote_forwards[i].connect_port); options.remote_forwards[i].handle = channel_request_remote_forwarding( - options.remote_forwards[i].listen_host, - options.remote_forwards[i].listen_port, - options.remote_forwards[i].connect_host, - options.remote_forwards[i].connect_port); + &options.remote_forwards[i]); if (options.remote_forwards[i].handle < 0) { if (options.exit_on_forward_failure) fatal("Could not request remote forwarding."); @@ -1413,10 +1595,16 @@ ssh_init_forwarding(void) static void check_agent_present(void) { + int r; + if (options.forward_agent) { /* Clear agent forwarding if we don't have an agent. */ - if (!ssh_agent_present()) + if ((r = ssh_get_authentication_socket(NULL)) != 0) { options.forward_agent = 0; + if (r != SSH_ERR_AGENT_NOT_PRESENT) + debug("ssh_get_authentication_socket: %s", + ssh_err(r)); + } } } @@ -1497,6 +1685,8 @@ ssh_session(void) } /* Request X11 forwarding if enabled and DISPLAY is set. */ display = getenv("DISPLAY"); + if (display == NULL && options.forward_x11) + debug("X11 forwarding requested but DISPLAY not set"); if (options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ @@ -1598,6 +1788,8 @@ ssh_session2_setup(int id, int success, void *arg) return; /* No need for error message, channels code sens one */ display = getenv("DISPLAY"); + if (display == NULL && options.forward_x11) + debug("X11 forwarding requested but DISPLAY not set"); if (options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ @@ -1753,9 +1945,6 @@ ssh_session2(void) fork_postauth(); } - if (options.use_roaming) - request_roaming(); - return client_loop(tty_flag, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, id); } |