diff options
author | des <des@FreeBSD.org> | 2014-01-31 13:12:02 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2014-01-31 13:12:02 +0000 |
commit | 7573e91b127f1c198210fd345d3ca198b598cfc6 (patch) | |
tree | d32fb61cec38c52314210c3459fd436685dacdba /crypto/openssh/ssh.c | |
parent | c692973c992c321bb10e631f572fab1500ae5b0e (diff) | |
parent | 45d0197dd79eceffb5bbc29f75199eb09af5a5f9 (diff) | |
download | FreeBSD-src-7573e91b127f1c198210fd345d3ca198b598cfc6.zip FreeBSD-src-7573e91b127f1c198210fd345d3ca198b598cfc6.tar.gz |
Upgrade to OpenSSH 6.5p1.
Diffstat (limited to 'crypto/openssh/ssh.c')
-rw-r--r-- | crypto/openssh/ssh.c | 318 |
1 files changed, 229 insertions, 89 deletions
diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index e2deee8..a286823 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.381 2013/07/25 00:29:10 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.397 2013/12/29 05:42:16 djm Exp $ */ /* $FreeBSD$ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -201,11 +201,11 @@ usage(void) "usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-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] [-Q protocol_feature]\n" -" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" -" [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" -" [-W host:port] [-w local_tun[:remote_tun]]\n" -" [user@]hostname [command]\n" +" [-L [bind_address:]port:host:hostport] [-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" +" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" ); exit(255); } @@ -233,6 +233,134 @@ tilde_expand_paths(char **paths, u_int num_paths) } } +static struct addrinfo * +resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen) +{ + char strport[NI_MAXSERV]; + struct addrinfo hints, *res; + int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; + + snprintf(strport, sizeof strport, "%u", port); + bzero(&hints, sizeof(hints)); + hints.ai_family = options.address_family; + hints.ai_socktype = SOCK_STREAM; + if (cname != NULL) + hints.ai_flags = AI_CANONNAME; + if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { + if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA)) + loglevel = SYSLOG_LEVEL_ERROR; + do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s", + __progname, name, ssh_gai_strerror(gaierr)); + return NULL; + } + if (cname != NULL && res->ai_canonname != NULL) { + if (strlcpy(cname, res->ai_canonname, clen) >= clen) { + error("%s: host \"%s\" cname \"%s\" too long (max %lu)", + __func__, name, res->ai_canonname, (u_long)clen); + if (clen > 0) + *cname = '\0'; + } + } + return res; +} + +/* + * Check whether the cname is a permitted replacement for the hostname + * and perform the replacement if it is. + */ +static int +check_follow_cname(char **namep, const char *cname) +{ + int i; + struct allowed_cname *rule; + + if (*cname == '\0' || options.num_permitted_cnames == 0 || + strcmp(*namep, cname) == 0) + return 0; + if (options.canonicalize_hostname == SSH_CANONICALISE_NO) + return 0; + /* + * Don't attempt to canonicalize names that will be interpreted by + * a proxy unless the user specifically requests so. + */ + if (options.proxy_command != NULL && + options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) + return 0; + 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) + continue; + verbose("Canonicalized DNS aliased hostname " + "\"%s\" => \"%s\"", *namep, cname); + free(*namep); + *namep = xstrdup(cname); + return 1; + } + return 0; +} + +/* + * Attempt to resolve the supplied hostname after applying the user's + * canonicalization rules. Returns the address list for the host or NULL + * if no name was found after canonicalization. + */ +static struct addrinfo * +resolve_canonicalize(char **hostp, u_int port) +{ + int i, ndots; + char *cp, *fullhost, cname_target[NI_MAXHOST]; + struct addrinfo *addrs; + + if (options.canonicalize_hostname == SSH_CANONICALISE_NO) + return NULL; + /* + * Don't attempt to canonicalize names that will be interpreted by + * a proxy unless the user specifically requests so. + */ + if (options.proxy_command != NULL && + options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) + return NULL; + /* Don't apply canonicalization to sufficiently-qualified hostnames */ + ndots = 0; + for (cp = *hostp; *cp != '\0'; cp++) { + if (*cp == '.') + ndots++; + } + if (ndots > options.canonicalize_max_dots) { + debug3("%s: not canonicalizing hostname \"%s\" (max dots %d)", + __func__, *hostp, options.canonicalize_max_dots); + return NULL; + } + /* Attempt each supplied suffix */ + for (i = 0; i < options.num_canonical_domains; i++) { + *cname_target = '\0'; + xasprintf(&fullhost, "%s.%s.", *hostp, + options.canonical_domains[i]); + if ((addrs = resolve_host(fullhost, options.port, 0, + cname_target, sizeof(cname_target))) == NULL) { + free(fullhost); + continue; + } + /* Remove trailing '.' */ + fullhost[strlen(fullhost) - 1] = '\0'; + /* Follow CNAME if requested */ + if (!check_follow_cname(&fullhost, cname_target)) { + debug("Canonicalized hostname \"%s\" => \"%s\"", + *hostp, fullhost); + } + free(*hostp); + *hostp = fullhost; + return addrs; + } + if (!options.canonicalize_fallback_local) + fatal("%s: Could not resolve host \"%s\"", __progname, host); + return NULL; +} + /* * Main program for the ssh client. */ @@ -242,14 +370,14 @@ main(int ac, char **av) int i, r, opt, exit_status, use_syslog; char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; + char cname[NI_MAXHOST]; struct stat st; struct passwd *pw; - int dummy, timeout_ms; + int timeout_ms; extern int optind, optreset; extern char *optarg; - - struct servent *sp; Forward fwd; + struct addrinfo *addrs = NULL; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -391,16 +519,22 @@ main(int ac, char **av) case 'P': /* deprecated */ options.use_privileged_port = 0; break; - case 'Q': /* deprecated */ + case 'Q': cp = NULL; - if (strcasecmp(optarg, "cipher") == 0) - cp = cipher_alg_list(); - else if (strcasecmp(optarg, "mac") == 0) - cp = mac_alg_list(); - else if (strcasecmp(optarg, "kex") == 0) - cp = kex_alg_list(); - else if (strcasecmp(optarg, "key") == 0) - cp = key_alg_list(); + if (strcmp(optarg, "cipher") == 0) + cp = cipher_alg_list('\n', 0); + else if (strcmp(optarg, "cipher-auth") == 0) + cp = cipher_alg_list('\n', 1); + else if (strcmp(optarg, "mac") == 0) + cp = mac_alg_list('\n'); + else if (strcmp(optarg, "kex") == 0) + cp = kex_alg_list('\n'); + else if (strcmp(optarg, "key") == 0) + cp = key_alg_list(0, 0); + else if (strcmp(optarg, "key-cert") == 0) + cp = key_alg_list(1, 0); + else if (strcmp(optarg, "key-plain") == 0) + cp = key_alg_list(0, 1); if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); printf("%s\n", cp); @@ -614,10 +748,9 @@ main(int ac, char **av) #endif break; case 'o': - dummy = 1; line = xstrdup(optarg); - if (process_config_line(&options, host ? host : "", - line, "command-line", 0, &dummy, SSHCONF_USERCONF) + if (process_config_line(&options, pw, host ? host : "", + line, "command-line", 0, NULL, SSHCONF_USERCONF) != 0) exit(255); free(line); @@ -652,9 +785,9 @@ main(int ac, char **av) usage(); options.user = p; *cp = '\0'; - host = ++cp; + host = xstrdup(++cp); } else - host = *av; + host = xstrdup(*av); if (ac > 1) { optind = optreset = 1; goto again; @@ -666,6 +799,9 @@ main(int ac, char **av) if (!host) usage(); + lowercase(host); + host_arg = xstrdup(host); + OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); @@ -722,18 +858,19 @@ main(int ac, char **av) */ if (config != NULL) { if (strcasecmp(config, "none") != 0 && - !read_config_file(config, host, &options, SSHCONF_USERCONF)) + !read_config_file(config, pw, host, &options, + SSHCONF_USERCONF)) 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, host, &options, + (void)read_config_file(buf, pw, host, &options, SSHCONF_CHECKPERM|SSHCONF_USERCONF); /* Read systemwide configuration file after user config. */ - (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, + (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, &options, 0); } @@ -742,6 +879,18 @@ main(int ac, char **av) channel_set_af(options.address_family); + /* Tidy and check options */ + if (options.host_key_alias != NULL) + lowercase(options.host_key_alias); + if (options.proxy_command != NULL && + strcmp(options.proxy_command, "-") == 0 && + options.proxy_use_fdpass) + fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); +#ifndef HAVE_CYGWIN + if (original_effective_uid != 0) + options.use_privileged_port = 0; +#endif + /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); @@ -771,16 +920,33 @@ main(int ac, char **av) options.user = xstrdup(pw->pw_name); /* Get default port if port has not been set. */ - if (options.port == 0) { - sp = getservbyname(SSH_SERVICE_NAME, "tcp"); - options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT; - } + if (options.port == 0) + options.port = default_ssh_port(); /* preserve host name given on command line for %n expansion */ - host_arg = host; if (options.hostname != NULL) { - host = percent_expand(options.hostname, + /* NB. Please keep in sync with readconf.c:match_cfg_line() */ + cp = percent_expand(options.hostname, "h", host, (char *)NULL); + free(host); + host = cp; + } + + /* If canonicalization requested then try to apply it */ + if (options.canonicalize_hostname != SSH_CANONICALISE_NO) + addrs = resolve_canonicalize(&host, options.port); + /* + * If canonicalization not requested, or if it failed then try to + * resolve the bare hostname name using the system resolver's usual + * search rules. Skip the lookup if a ProxyCommand is being used + * unless the user has specifically requested canonicalisation. + */ + if (addrs == NULL && (options.proxy_command == NULL || + 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 (gethostname(thishost, sizeof(thishost)) == -1) @@ -800,41 +966,6 @@ main(int ac, char **av) free(cp); } - /* Find canonic host name. */ - if (strchr(host, '.') == 0) { - struct addrinfo hints; - struct addrinfo *ai = NULL; - int errgai; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = options.address_family; - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - errgai = getaddrinfo(host, NULL, &hints, &ai); - if (errgai == 0) { - if (ai->ai_canonname != NULL) - host = xstrdup(ai->ai_canonname); - freeaddrinfo(ai); - } - } - - /* force lowercase for hostkey matching */ - if (options.host_key_alias != NULL) { - for (p = options.host_key_alias; *p; p++) - if (isupper(*p)) - *p = (char)tolower(*p); - } - - if (options.proxy_command != NULL && - strcmp(options.proxy_command, "none") == 0) { - free(options.proxy_command); - options.proxy_command = NULL; - } - if (options.control_path != NULL && - strcmp(options.control_path, "none") == 0) { - free(options.control_path); - options.control_path = NULL; - } - if (options.control_path != NULL) { cp = tilde_expand_filename(options.control_path, original_real_uid); @@ -853,16 +984,17 @@ main(int ac, char **av) timeout_ms = options.connection_timeout * 1000; /* Open a connection to the remote host. */ - if (ssh_connect(host, &hostaddr, options.port, - options.address_family, options.connection_attempts, &timeout_ms, - options.tcp_keep_alive, -#ifdef HAVE_CYGWIN - options.use_privileged_port, -#else - original_effective_uid == 0 && options.use_privileged_port, -#endif - options.proxy_command) != 0) - exit(255); + if (ssh_connect(host, addrs, &hostaddr, options.port, + options.address_family, options.connection_attempts, + &timeout_ms, options.tcp_keep_alive, + options.use_privileged_port) != 0) + exit(255); + + if (addrs != NULL) + freeaddrinfo(addrs); + + packet_set_timeout(options.server_alive_interval, + options.server_alive_count_max); if (timeout_ms > 0) debug3("timeout: %d ms remain after connect", timeout_ms); @@ -880,7 +1012,7 @@ main(int ac, char **av) sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { - sensitive_data.nkeys = 7; + sensitive_data.nkeys = 9; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); for (i = 0; i < sensitive_data.nkeys; i++) @@ -897,21 +1029,26 @@ main(int ac, char **av) #endif sensitive_data.keys[3] = key_load_private_cert(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL); - sensitive_data.keys[4] = key_load_private_type(KEY_DSA, + 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); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA, + sensitive_data.keys[6] = key_load_private_type(KEY_ECDSA, _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL); #endif - sensitive_data.keys[6] = key_load_private_type(KEY_RSA, + 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); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && - sensitive_data.keys[4] == NULL && sensitive_data.keys[5] == NULL && - sensitive_data.keys[6] == NULL) { + 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 @@ -920,14 +1057,18 @@ main(int ac, char **av) #endif sensitive_data.keys[3] = key_load_cert( _PATH_HOST_RSA_KEY_FILE); - sensitive_data.keys[4] = key_load_public( + 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); #ifdef OPENSSL_HAS_ECC - sensitive_data.keys[5] = key_load_public( + sensitive_data.keys[6] = key_load_public( _PATH_HOST_ECDSA_KEY_FILE, NULL); #endif - sensitive_data.keys[6] = key_load_public( + 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); sensitive_data.external_keysign = 1; } } @@ -1127,7 +1268,7 @@ ssh_init_stdio_forwarding(void) if (stdio_forward_host == NULL) return; - if (!compat20) + if (!compat20) fatal("stdio forwarding require Protocol 2"); debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port); @@ -1299,7 +1440,7 @@ ssh_session(void) char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, + options.forward_x11_trusted, options.forward_x11_timeout, &proto, &data); /* Request forwarding with authentication spoofing. */ @@ -1712,4 +1853,3 @@ main_sigchld_handler(int sig) signal(sig, main_sigchld_handler); errno = save_errno; } - |