-/* $OpenBSD: sshd.c,v 1.353 2007/12/31 15:27:04 dtucker Exp $ */
+/* $OpenBSD: sshd.c,v 1.368 2009/10/28 16:38:18 reyk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
# include <sys/time.h>
#endif
#include "openbsd-compat/sys-tree.h"
+#include "openbsd-compat/sys-queue.h"
#include <sys/wait.h>
#include <errno.h>
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
-#include "monitor_fdpass.h"
+#include "roaming.h"
#include "version.h"
#ifdef LIBWRAP
#include <tcpd.h>
#include <syslog.h>
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;
+int allow_severity;
+int deny_severity;
#endif /* LIBWRAP */
#ifndef O_NOCTTY
static void
generate_ephemeral_server_key(void)
{
- u_int32_t rnd = 0;
- int i;
-
verbose("Generating %s%d bit RSA key.",
sensitive_data.server_key ? "new " : "", options.server_key_bits);
if (sensitive_data.server_key != NULL)
options.server_key_bits);
verbose("RSA key generation complete.");
- for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- sensitive_data.ssh1_cookie[i] = rnd & 0xff;
- rnd >>= 8;
- }
+ arc4random_buf(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
arc4random_stir();
}
int mismatch;
int remote_major, remote_minor;
int major, minor;
- char *s;
+ char *s, *newline = "\n";
char buf[256]; /* Must not be larger than remote_version. */
char remote_version[256]; /* Must be at least as big as buf. */
} else if (options.protocol & SSH_PROTO_2) {
major = PROTOCOL_MAJOR_2;
minor = PROTOCOL_MINOR_2;
+ newline = "\r\n";
} else {
major = PROTOCOL_MAJOR_1;
minor = PROTOCOL_MINOR_1;
}
- snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
+ SSH_VERSION, newline);
server_version_string = xstrdup(buf);
/* Send our protocol version identification. */
- if (atomicio(vwrite, sock_out, server_version_string,
+ if (roaming_atomicio(vwrite, sock_out, server_version_string,
strlen(server_version_string))
!= strlen(server_version_string)) {
logit("Could not write ident string to %s", get_remote_ipaddr());
/* Read other sides version identification. */
memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
- if (atomicio(read, sock_in, &buf[i], 1) != 1) {
+ if (roaming_atomicio(read, sock_in, &buf[i], 1) != 1) {
logit("Did not receive identification string from %s",
get_remote_ipaddr());
cleanup_exit(255);
{
u_int32_t rnd[256];
gid_t gidset[1];
- int i;
/* Enable challenge-response authentication for privilege separation */
privsep_challenge_enable();
- for (i = 0; i < 256; i++)
- rnd[i] = arc4random();
+ arc4random_stir();
+ arc4random_buf(rnd, sizeof(rnd));
RAND_seed(rnd, sizeof(rnd));
/* Demote the private keys to public keys. */
static void
privsep_postauth(Authctxt *authctxt)
{
+ u_int32_t rnd[256];
+
#ifdef DISABLE_FD_PASSING
if (1) {
#else
if (pmonitor->m_pid == -1)
fatal("fork of unprivileged child failed");
else if (pmonitor->m_pid != 0) {
- debug2("User child is on pid %ld", (long)pmonitor->m_pid);
+ verbose("User child is on pid %ld", (long)pmonitor->m_pid);
close(pmonitor->m_recvfd);
buffer_clear(&loginmsg);
monitor_child_postauth(pmonitor);
/* Demote the private keys to public keys. */
demote_sensitive_data();
+ arc4random_stir();
+ arc4random_buf(rnd, sizeof(rnd));
+ RAND_seed(rnd, sizeof(rnd));
+
/* Drop privileges */
do_setusercontext(authctxt->pw);
p *= startups - options.max_startups_begin;
p /= options.max_startups - options.max_startups_begin;
p += options.max_startups_rate;
- r = arc4random() % 100;
+ r = arc4random_uniform(100);
debug("drop_connection: p %d, r %d", p, r);
return (r < p) ? 1 : 0;
fprintf(stderr, "%s, %s\n",
SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
fprintf(stderr,
-"usage: sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time]\n"
-" [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]\n"
+"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n"
+" [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n"
+" [-o option] [-p port] [-u len]\n"
);
exit(1);
}
continue;
}
/* Create socket for listening. */
- listen_sock = socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol);
+ listen_sock = socket_rdomain(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol, options.rdomain);
if (listen_sock < 0) {
/* kernel may not support ipv6 */
verbose("socket: %.100s", strerror(errno));
&on, sizeof(on)) == -1)
error("setsockopt SO_REUSEADDR: %s", strerror(errno));
-#ifdef IPV6_V6ONLY
/* Only communicate in IPv6 over AF_INET6 sockets. */
- if (ai->ai_family == AF_INET6) {
- if (setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY,
- &on, sizeof(on)) == -1)
- error("setsockopt IPV6_V6ONLY: %s",
- strerror(errno));
- }
-#endif
+ if (ai->ai_family == AF_INET6)
+ sock_set_v6only(listen_sock);
debug("Bind to port %s on %s.", strport, ntop);
*newsock = accept(listen_socks[i],
(struct sockaddr *)&from, &fromlen);
if (*newsock < 0) {
- if (errno != EINTR && errno != EWOULDBLOCK)
+ if (errno != EINTR && errno != EAGAIN &&
+ errno != EWOULDBLOCK)
error("accept: %.100s", strerror(errno));
continue;
}
int opt, i, on = 1;
int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip;
+ char *test_user = NULL, *test_host = NULL, *test_addr = NULL;
int remote_port;
- char *line;
+ char *line, *p, *cp;
int config_s[2] = { -1 , -1 };
+ u_int64_t ibytes, obytes;
+ mode_t new_umask;
Key *key;
Authctxt *authctxt;
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) {
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeiqrtQRT46")) != -1) {
switch (opt) {
case '4':
options.address_family = AF_INET;
exit(1);
}
options.ports[options.num_ports++] = a2port(optarg);
- if (options.ports[options.num_ports-1] == 0) {
+ if (options.ports[options.num_ports-1] <= 0) {
fprintf(stderr, "Bad port number.\n");
exit(1);
}
case 't':
test_flag = 1;
break;
+ case 'T':
+ test_flag = 2;
+ break;
+ case 'C':
+ cp = optarg;
+ while ((p = strsep(&cp, ",")) && *p != '\0') {
+ if (strncmp(p, "addr=", 5) == 0)
+ test_addr = xstrdup(p + 5);
+ else if (strncmp(p, "host=", 5) == 0)
+ test_host = xstrdup(p + 5);
+ else if (strncmp(p, "user=", 5) == 0)
+ test_user = xstrdup(p + 5);
+ else {
+ fprintf(stderr, "Invalid test "
+ "mode specification %s\n", p);
+ exit(1);
+ }
+ }
+ break;
case 'u':
utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
if (utmp_len > MAXHOSTNAMELEN) {
}
if (rexeced_flag || inetd_flag)
rexec_flag = 0;
- if (rexec_flag && (av[0] == NULL || *av[0] != '/'))
+ if (!test_flag && (rexec_flag && (av[0] == NULL || *av[0] != '/')))
fatal("sshd re-exec requires execution with an absolute path");
if (rexeced_flag)
closefrom(REEXEC_MIN_FREE_FD);
sensitive_data.have_ssh1_key = 0;
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 (test_flag >= 2 &&
+ (test_user != NULL || test_host != NULL || test_addr != NULL)
+ && (test_user == NULL || test_host == NULL || test_addr == NULL))
+ fatal("user, host and addr are all required when testing "
+ "Match configs");
+ if (test_flag < 2 && (test_user != NULL || test_host != NULL ||
+ test_addr != NULL))
+ fatal("Config test connection parameter (-C) provided without "
+ "test mode (-T)");
+
/* Fetch our configuration */
buffer_init(&cfg);
if (rexeced_flag)
if (options.challenge_response_authentication)
options.kbd_interactive_authentication = 1;
- /* set default channel AF */
+ /* set default channel AF and routing domain */
channel_set_af(options.address_family);
+ channel_set_rdomain(options.rdomain);
/* Check that there are no remaining arguments. */
if (optind < ac) {
"world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
}
+ if (test_flag > 1) {
+ if (test_user != NULL && test_addr != NULL && test_host != NULL)
+ parse_server_match_config(&options, test_user,
+ test_host, test_addr);
+ dump_config(&options);
+ }
+
/* Configuration looks good, so exit if in test mode. */
if (test_flag)
exit(0);
rexec_argv[rexec_argc + 1] = NULL;
}
+ /* Ensure that umask disallows at least group and world write */
+ new_umask = umask(0077) | 0022;
+ (void) umask(new_umask);
+
/* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && (!inetd_flag || rexeced_flag))
log_stderr = 1;
if (inetd_flag) {
server_accept_inetd(&sock_in, &sock_out);
} else {
+ platform_pre_listen();
server_listen();
if (options.protocol & SSH_PROTO_1)
audit_connection_from(remote_ip, remote_port);
#endif
#ifdef LIBWRAP
+ allow_severity = options.log_facility|LOG_INFO;
+ deny_severity = options.log_facility|LOG_WARNING;
/* Check whether logins are denied from this host. */
if (packet_connection_is_on_socket()) {
struct request_info req;
audit_event(SSH_AUTH_SUCCESS);
#endif
+#ifdef GSSAPI
+ if (options.gss_authentication) {
+ temporarily_use_uid(authctxt->pw);
+ ssh_gssapi_storecreds();
+ restore_uid();
+ }
+#endif
+#ifdef USE_PAM
+ if (options.use_pam) {
+ do_pam_setcred(1);
+ do_pam_session();
+ }
+#endif
+
/*
* In privilege separation, we fork another child and prepare
* file descriptor passing.
destroy_sensitive_data();
}
+ packet_set_timeout(options.client_alive_interval,
+ options.client_alive_count_max);
+
/* Start session. */
do_authenticated(authctxt);
/* The connection has been terminated. */
- verbose("Closing connection to %.100s", remote_ip);
+ packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+ packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+ verbose("Transferred: sent %llu, received %llu bytes", obytes, ibytes);
+
+ verbose("Closing connection to %.500s port %d", remote_ip, remote_port);
#ifdef USE_PAM
if (options.use_pam)
u_char session_key[SSH_SESSION_KEY_LENGTH];
u_char cookie[8];
u_int cipher_type, auth_mask, protocol_flags;
- u_int32_t rnd = 0;
/*
* Generate check bytes that the client must send back in the user
* cookie. This only affects rhosts authentication, and this is one
* of the reasons why it is inherently insecure.
*/
- for (i = 0; i < 8; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- cookie[i] = rnd & 0xff;
- rnd >>= 8;
- }
+ arc4random_buf(cookie, sizeof(cookie));
/*
* Send our public key. We include in the packet 64 bits of random