summaryrefslogtreecommitdiff
path: root/sshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c218
1 files changed, 141 insertions, 77 deletions
diff --git a/sshd.c b/sshd.c
index 51a1aaf6ec86..fd95b681b7c5 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.492 2017/09/12 06:32:07 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.506 2018/03/03 03:15:51 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -119,6 +119,7 @@
#endif
#include "monitor_wrap.h"
#include "ssh-sandbox.h"
+#include "auth-options.h"
#include "version.h"
#include "ssherr.h"
@@ -144,7 +145,12 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE;
*/
int debug_flag = 0;
-/* Flag indicating that the daemon should only test the configuration and keys. */
+/*
+ * Indicating that the daemon should only test the configuration and keys.
+ * If test_flag > 1 ("-T" flag), then sshd will also dump the effective
+ * configuration, optionally using connection information provided by the
+ * "-C" flag.
+ */
int test_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
@@ -227,6 +233,9 @@ static int privsep_chroot = 1;
/* global authentication context */
Authctxt *the_authctxt = NULL;
+/* global key/cert auth options. XXX move to permanent ssh->authctxt? */
+struct sshauthopt *auth_opts = NULL;
+
/* sshd_config buffer */
Buffer cfg;
@@ -278,7 +287,6 @@ sighup_handler(int sig)
int save_errno = errno;
received_sighup = 1;
- signal(SIGHUP, sighup_handler);
errno = save_errno;
}
@@ -328,8 +336,6 @@ main_sigchld_handler(int sig)
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
-
- signal(SIGCHLD, main_sigchld_handler);
errno = save_errno;
}
@@ -441,16 +447,12 @@ sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out)
logit("Client version \"%.100s\" uses unsafe RSA signature "
"scheme; disabling use of RSA keys", remote_version);
}
- if ((ssh->compat & SSH_BUG_DERIVEKEY) != 0) {
- fatal("Client version \"%.100s\" uses unsafe key agreement; "
- "refusing connection", remote_version);
- }
chop(server_version_string);
debug("Local version string %.200s", server_version_string);
- if (remote_major != 2 ||
- (remote_major == 1 && remote_minor != 99)) {
+ if (remote_major != 2 &&
+ !(remote_major == 1 && remote_minor == 99)) {
s = "Protocol major versions differ.\n";
(void) atomicio(vwrite, sock_out, s, strlen(s));
close(sock_in);
@@ -467,7 +469,7 @@ sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out)
void
destroy_sensitive_data(void)
{
- int i;
+ u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
@@ -486,7 +488,7 @@ void
demote_sensitive_data(void)
{
struct sshkey *tmp;
- int i;
+ u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
@@ -685,7 +687,7 @@ list_hostkey_types(void)
Buffer b;
const char *p;
char *ret;
- int i;
+ u_int i;
struct sshkey *key;
buffer_init(&b);
@@ -707,6 +709,7 @@ list_hostkey_types(void)
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
+ case KEY_XMSS:
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
p = key_ssh_name(key);
@@ -728,6 +731,7 @@ list_hostkey_types(void)
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ED25519_CERT:
+ case KEY_XMSS_CERT:
if (buffer_len(&b) > 0)
buffer_append(&b, ",", 1);
p = key_ssh_name(key);
@@ -745,7 +749,7 @@ list_hostkey_types(void)
static struct sshkey *
get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
{
- int i;
+ u_int i;
struct sshkey *key;
for (i = 0; i < options.num_host_key_files; i++) {
@@ -754,6 +758,7 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
case KEY_DSA_CERT:
case KEY_ECDSA_CERT:
case KEY_ED25519_CERT:
+ case KEY_XMSS_CERT:
key = sensitive_data.host_certificates[i];
break;
default:
@@ -785,7 +790,7 @@ get_hostkey_private_by_type(int type, int nid, struct ssh *ssh)
struct sshkey *
get_hostkey_by_index(int ind)
{
- if (ind < 0 || ind >= options.num_host_key_files)
+ if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_keys[ind]);
}
@@ -793,7 +798,7 @@ get_hostkey_by_index(int ind)
struct sshkey *
get_hostkey_public_by_index(int ind, struct ssh *ssh)
{
- if (ind < 0 || ind >= options.num_host_key_files)
+ if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_pubkeys[ind]);
}
@@ -801,7 +806,7 @@ get_hostkey_public_by_index(int ind, struct ssh *ssh)
int
get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh)
{
- int i;
+ u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (key_is_cert(key)) {
@@ -830,7 +835,8 @@ notify_hostkeys(struct ssh *ssh)
{
struct sshbuf *buf;
struct sshkey *key;
- int i, nkeys, r;
+ u_int i, nkeys;
+ int r;
char *fp;
/* Some clients cannot cope with the hostkeys message, skip those. */
@@ -861,7 +867,7 @@ notify_hostkeys(struct ssh *ssh)
packet_put_string(sshbuf_ptr(buf), sshbuf_len(buf));
nkeys++;
}
- debug3("%s: sent %d hostkeys", __func__, nkeys);
+ debug3("%s: sent %u hostkeys", __func__, nkeys);
if (nkeys == 0)
fatal("%s: no hostkeys", __func__);
packet_send();
@@ -1014,13 +1020,13 @@ server_accept_inetd(int *sock_in, int *sock_out)
* Listen for TCP connections
*/
static void
-server_listen(void)
+listen_on_addrs(struct listenaddr *la)
{
- int ret, listen_sock, on = 1;
+ int ret, listen_sock;
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
- for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
+ for (ai = la->addrs; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
if (num_listen_socks >= MAX_LISTEN_SOCKS)
@@ -1050,13 +1056,13 @@ server_listen(void)
close(listen_sock);
continue;
}
- /*
- * Set socket options.
- * Allow local port reuse in TIME_WAIT.
- */
- if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
- &on, sizeof(on)) == -1)
- error("setsockopt SO_REUSEADDR: %s", strerror(errno));
+ /* Socket options */
+ set_reuseaddr(listen_sock);
+ if (la->rdomain != NULL &&
+ set_rdomain(listen_sock, la->rdomain) == -1) {
+ close(listen_sock);
+ continue;
+ }
/* Only communicate in IPv6 over AF_INET6 sockets. */
if (ai->ai_family == AF_INET6)
@@ -1078,9 +1084,28 @@ server_listen(void)
if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
fatal("listen on [%s]:%s: %.100s",
ntop, strport, strerror(errno));
- logit("Server listening on %s port %s.", ntop, strport);
+ logit("Server listening on %s port %s%s%s.",
+ ntop, strport,
+ la->rdomain == NULL ? "" : " rdomain ",
+ la->rdomain == NULL ? "" : la->rdomain);
}
- freeaddrinfo(options.listen_addrs);
+}
+
+static void
+server_listen(void)
+{
+ u_int i;
+
+ for (i = 0; i < options.num_listen_addrs; i++) {
+ listen_on_addrs(&options.listen_addrs[i]);
+ freeaddrinfo(options.listen_addrs[i].addrs);
+ free(options.listen_addrs[i].rdomain);
+ memset(&options.listen_addrs[i], 0,
+ sizeof(options.listen_addrs[i]));
+ }
+ free(options.listen_addrs);
+ options.listen_addrs = NULL;
+ options.num_listen_addrs = 0;
if (!num_listen_socks)
fatal("Cannot bind any address.");
@@ -1348,6 +1373,46 @@ check_ip_options(struct ssh *ssh)
#endif /* IP_OPTIONS */
}
+/* Set the routing domain for this process */
+static void
+set_process_rdomain(struct ssh *ssh, const char *name)
+{
+#if defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
+ if (name == NULL)
+ return; /* default */
+
+ if (strcmp(name, "%D") == 0) {
+ /* "expands" to routing domain of connection */
+ if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
+ return;
+ }
+ /* NB. We don't pass 'ssh' to sys_set_process_rdomain() */
+ return sys_set_process_rdomain(name);
+#elif defined(__OpenBSD__)
+ int rtable, ortable = getrtable();
+ const char *errstr;
+
+ if (name == NULL)
+ return; /* default */
+
+ if (strcmp(name, "%D") == 0) {
+ /* "expands" to routing domain of connection */
+ if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
+ return;
+ }
+
+ rtable = (int)strtonum(name, 0, 255, &errstr);
+ if (errstr != NULL) /* Shouldn't happen */
+ fatal("Invalid routing domain \"%s\": %s", name, errstr);
+ if (rtable != ortable && setrtable(rtable) != 0)
+ fatal("Unable to set routing domain %d: %s",
+ rtable, strerror(errno));
+ debug("%s: set routing domain %d (was %d)", __func__, rtable, ortable);
+#else /* defined(__OpenBSD__) */
+ fatal("Unable to set routing domain: not supported in this platform");
+#endif
+}
+
/*
* Main program for the daemon.
*/
@@ -1357,20 +1422,19 @@ main(int ac, char **av)
struct ssh *ssh = NULL;
extern char *optarg;
extern int optind;
- int r, opt, i, j, on = 1, already_daemon;
+ int r, opt, on = 1, already_daemon, remote_port;
int sock_in = -1, sock_out = -1, newsock = -1;
- const char *remote_ip;
- int remote_port;
+ const char *remote_ip, *rdomain;
char *fp, *line, *laddr, *logfile = NULL;
int config_s[2] = { -1 , -1 };
- u_int n;
+ u_int i, j;
u_int64_t ibytes, obytes;
mode_t new_umask;
struct sshkey *key;
struct sshkey *pubkey;
int keytype;
Authctxt *authctxt;
- struct connection_info *connection_info = get_connection_info(0, 0);
+ struct connection_info *connection_info = NULL;
ssh_malloc_init(); /* must be called before any mallocs */
@@ -1383,7 +1447,7 @@ main(int ac, char **av)
saved_argc = ac;
rexec_argc = ac;
saved_argv = xcalloc(ac + 1, sizeof(*saved_argv));
- for (i = 0; i < ac; i++)
+ for (i = 0; (int)i < ac; i++)
saved_argv[i] = xstrdup(av[i]);
saved_argv[i] = NULL;
@@ -1416,12 +1480,8 @@ main(int ac, char **av)
config_file_name = optarg;
break;
case 'c':
- if (options.num_host_cert_files >= MAX_HOSTCERTS) {
- fprintf(stderr, "too many host certificates.\n");
- exit(1);
- }
- options.host_cert_files[options.num_host_cert_files++] =
- derelativise_path(optarg);
+ servconf_add_hostcert("[command-line]", 0,
+ &options, optarg);
break;
case 'd':
if (debug_flag == 0) {
@@ -1480,12 +1540,8 @@ main(int ac, char **av)
/* protocol 1, ignored */
break;
case 'h':
- if (options.num_host_key_files >= MAX_HOSTKEYS) {
- fprintf(stderr, "too many host keys.\n");
- exit(1);
- }
- options.host_key_files[options.num_host_key_files++] =
- derelativise_path(optarg);
+ servconf_add_hostkey("[command-line]", 0,
+ &options, optarg);
break;
case 't':
test_flag = 1;
@@ -1494,6 +1550,7 @@ main(int ac, char **av)
test_flag = 2;
break;
case 'C':
+ connection_info = get_connection_info(0, 0);
if (parse_server_match_testspec(connection_info,
optarg) == -1)
exit(1);
@@ -1552,24 +1609,13 @@ main(int ac, char **av)
if (getenv("KRB5CCNAME") != NULL)
(void) unsetenv("KRB5CCNAME");
-#ifdef _UNICOS
- /* Cray can define user privs drop all privs now!
- * Not needed on PRIV_SU systems!
- */
- drop_cray_privs();
-#endif
-
sensitive_data.have_ssh2_key = 0;
/*
- * If we're doing an extended config test, make sure we have all of
- * the parameters we need. If we're not doing an extended test,
- * do not silently ignore connection test params.
+ * If we're not doing an extended test do not silently ignore connection
+ * test params.
*/
- if (test_flag >= 2 && server_match_spec_complete(connection_info) == 0)
- fatal("user, host and addr are all required when testing "
- "Match configs");
- if (test_flag < 2 && server_match_spec_complete(connection_info) >= 0)
+ if (test_flag < 2 && connection_info != NULL)
fatal("Config test connection parameter (-C) provided without "
"test mode (-T)");
@@ -1611,12 +1657,12 @@ main(int ac, char **av)
* and warns for trivial misconfigurations that could break login.
*/
if (options.num_auth_methods != 0) {
- for (n = 0; n < options.num_auth_methods; n++) {
- if (auth2_methods_valid(options.auth_methods[n],
+ for (i = 0; i < options.num_auth_methods; i++) {
+ if (auth2_methods_valid(options.auth_methods[i],
1) == 0)
break;
}
- if (n >= options.num_auth_methods)
+ if (i >= options.num_auth_methods)
fatal("AuthenticationMethods cannot be satisfied by "
"enabled authentication methods");
}
@@ -1642,10 +1688,8 @@ main(int ac, char **av)
fatal("Privilege separation user %s does not exist",
SSH_PRIVSEP_USER);
} else {
- explicit_bzero(privsep_pw->pw_passwd,
- strlen(privsep_pw->pw_passwd));
privsep_pw = pwcopy(privsep_pw);
- free(privsep_pw->pw_passwd);
+ freezero(privsep_pw->pw_passwd, strlen(privsep_pw->pw_passwd));
privsep_pw->pw_passwd = xstrdup("*");
}
endpwent();
@@ -1697,6 +1741,7 @@ main(int ac, char **av)
case KEY_DSA:
case KEY_ECDSA:
case KEY_ED25519:
+ case KEY_XMSS:
if (have_agent || key != NULL)
sensitive_data.have_ssh2_key = 1;
break;
@@ -1752,7 +1797,7 @@ main(int ac, char **av)
continue;
}
sensitive_data.host_certificates[j] = key;
- debug("host certificate: #%d type %d %s", j, key->type,
+ debug("host certificate: #%u type %d %s", j, key->type,
key_type(key));
}
@@ -1776,8 +1821,13 @@ main(int ac, char **av)
}
if (test_flag > 1) {
- if (server_match_spec_complete(connection_info) == 1)
- parse_server_match_config(&options, connection_info);
+ /*
+ * If no connection info was provided by -C then use
+ * use a blank one that will cause no predicate to match.
+ */
+ if (connection_info == NULL)
+ connection_info = get_connection_info(0, 0);
+ parse_server_match_config(&options, connection_info);
dump_config(&options);
}
@@ -1796,8 +1846,10 @@ main(int ac, char **av)
debug("setgroups() failed: %.200s", strerror(errno));
if (rexec_flag) {
+ if (rexec_argc < 0)
+ fatal("rexec_argc %d < 0", rexec_argc);
rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *));
- for (i = 0; i < rexec_argc; i++) {
+ for (i = 0; i < (u_int)rexec_argc; i++) {
debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
rexec_argv[i] = saved_argv[i];
}
@@ -1970,6 +2022,9 @@ main(int ac, char **av)
cleanup_exit(255);
}
+ if (options.routing_domain != NULL)
+ set_process_rdomain(ssh, options.routing_domain);
+
/*
* The rest of the code depends on the fact that
* ssh_remote_ipaddr() caches the remote ip, even if
@@ -1981,10 +2036,15 @@ main(int ac, char **av)
audit_connection_from(remote_ip, remote_port);
#endif
+ rdomain = ssh_packet_rdomain_in(ssh);
+
/* Log the connection. */
laddr = get_local_ipaddr(sock_in);
- verbose("Connection from %s port %d on %s port %d",
- remote_ip, remote_port, laddr, ssh_local_port(ssh));
+ verbose("Connection from %s port %d on %s port %d%s%s%s",
+ remote_ip, remote_port, laddr, ssh_local_port(ssh),
+ rdomain == NULL ? "" : " rdomain \"",
+ rdomain == NULL ? "" : rdomain,
+ rdomain == NULL ? "" : "\"");
free(laddr);
/*
@@ -2010,6 +2070,10 @@ main(int ac, char **av)
/* XXX global for cleanup, access from other modules */
the_authctxt = authctxt;
+ /* Set default key authentication options */
+ if ((auth_opts = sshauthopt_new_with_keys_defaults()) == NULL)
+ fatal("allocation failed");
+
/* prepare buffer to collect messages to display to user after login */
buffer_init(&loginmsg);
auth_debug_reset();
@@ -2066,7 +2130,7 @@ main(int ac, char **av)
#ifdef USE_PAM
if (options.use_pam) {
do_pam_setcred(1);
- do_pam_session();
+ do_pam_session(ssh);
}
#endif