summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/ssh.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2014-01-31 13:12:02 +0000
committerdes <des@FreeBSD.org>2014-01-31 13:12:02 +0000
commit7573e91b127f1c198210fd345d3ca198b598cfc6 (patch)
treed32fb61cec38c52314210c3459fd436685dacdba /crypto/openssh/ssh.c
parentc692973c992c321bb10e631f572fab1500ae5b0e (diff)
parent45d0197dd79eceffb5bbc29f75199eb09af5a5f9 (diff)
downloadFreeBSD-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.c318
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;
}
-
OpenPOWER on IntegriCloud