*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.147 2001/01/10 19:43:20 deraadt Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.159 2001/01/29 19:47:31 markus Exp $");
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/hmac.h>
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
#include "xmalloc.h"
#include "rsa.h"
-#include "ssh.h"
#include "pty.h"
#include "packet.h"
#include "mpaux.h"
+#include "log.h"
#include "servconf.h"
#include "uidswap.h"
#include "compat.h"
#include "buffer.h"
-
-#include "ssh2.h"
-#include <openssl/dh.h>
-#include <openssl/bn.h>
-#include <openssl/hmac.h>
+#include "cipher.h"
#include "kex.h"
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
#include "key.h"
#include "dh.h"
-
-#include "auth.h"
#include "myproposal.h"
#include "authfile.h"
+#include "pathnames.h"
+#include "atomicio.h"
+#include "canohost.h"
+#include "auth.h"
+#include "misc.h"
#ifdef LIBWRAP
#include <tcpd.h>
ServerOptions options;
/* Name of the server configuration file. */
-char *config_file_name = SERVER_CONFIG_FILE;
+char *config_file_name = _PATH_SERVER_CONFIG_FILE;
/*
* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
} sensitive_data;
/*
- * Flag indicating whether the current session key has been used. This flag
- * is set whenever the key is used, and cleared when the key is regenerated.
+ * Flag indicating whether the RSA server key needs to be regenerated.
+ * Is set in the SIGALRM handler and cleared when the key is regenerated.
*/
-int key_used = 0;
+int key_do_regen = 0;
/* This is set to true when SIGHUP is received. */
int received_sighup = 0;
* do anything with the private key or random state before forking.
* Thus there should be no concurrency control/asynchronous execution
* problems.
- * XXX calling log() is not safe from races.
*/
void
generate_empheral_server_key(void)
key_regeneration_alarm(int sig)
{
int save_errno = errno;
-
- /* Check if we should generate a new key. */
- if (key_used) {
- /* This should really be done in the background. */
- generate_empheral_server_key();
- key_used = 0;
- }
- /* Reschedule the alarm. */
- signal(SIGALRM, key_regeneration_alarm);
- alarm(options.key_regeneration_time);
+ signal(SIGALRM, SIG_DFL);
errno = save_errno;
+ key_do_regen = 1;
}
void
int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
pid_t pid;
socklen_t fromlen;
- int silent = 0;
fd_set *fdset;
struct sockaddr_storage from;
const char *remote_ip;
int listen_sock, maxfd;
int startup_p[2];
int startups = 0;
+ int ret, key_used = 0;
__progname = get_progname(av[0]);
init_rng();
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDiqQ46")) != EOF) {
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDiqQ46")) != -1) {
switch (opt) {
case '4':
IPv4or6 = AF_INET;
inetd_flag = 1;
break;
case 'Q':
- silent = 1;
+ /* ignored */
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
fprintf(stderr, "sshd version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [options]\n", __progname);
fprintf(stderr, "Options:\n");
- fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE);
+ fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE);
fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n");
fprintf(stderr, " -i Started from inetd\n");
fprintf(stderr, " -D Do not fork into daemon mode\n");
fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n");
fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
- HOST_KEY_FILE);
+ _PATH_HOST_KEY_FILE);
fprintf(stderr, " -u len Maximum hostname length for utmp recording\n");
fprintf(stderr, " -4 Use IPv4 only\n");
fprintf(stderr, " -6 Use IPv6 only\n");
* key (unless started from inetd)
*/
log_init(__progname,
- options.log_level == -1 ? SYSLOG_LEVEL_NOTICE : options.log_level,
+ options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
- !silent && !inetd_flag);
+ !inetd_flag);
/* Read server configuration options from the configuration file. */
read_server_config(&options, config_file_name);
options.protocol &= ~SSH_PROTO_2;
}
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
- if (silent == 0)
- fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
log("sshd: no hostkeys available -- exiting.\n");
exit(1);
}
fclose(f);
}
}
- if (options.protocol & SSH_PROTO_1) {
+ if (options.protocol & SSH_PROTO_1)
generate_empheral_server_key();
- /* Schedule server key regeneration alarm. */
- signal(SIGALRM, key_regeneration_alarm);
- alarm(options.key_regeneration_time);
- }
-
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler);
sighup_restart();
if (fdset != NULL)
xfree(fdset);
- fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
fdset = (fd_set *)xmalloc(fdsetsz);
memset(fdset, 0, fdsetsz);
FD_SET(startup_pipes[i], fdset);
/* Wait in select until there is a connection. */
- if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
- if (errno != EINTR)
- error("select: %.100s", strerror(errno));
- continue;
+ ret = select(maxfd+1, fdset, NULL, NULL, NULL);
+ if (ret < 0 && errno != EINTR)
+ error("select: %.100s", strerror(errno));
+ if (key_used && key_do_regen) {
+ generate_empheral_server_key();
+ key_used = 0;
+ key_do_regen = 0;
}
+ if (ret < 0)
+ continue;
+
for (i = 0; i < options.max_startups; i++)
if (startup_pipes[i] != -1 &&
FD_ISSET(startup_pipes[i], fdset)) {
close(startup_p[1]);
/* Mark that the key has been used (it was "given" to the child). */
- key_used = 1;
+ if ((options.protocol & SSH_PROTO_1) &&
+ key_used == 0) {
+ /* Schedule server key regeneration alarm. */
+ signal(SIGALRM, key_regeneration_alarm);
+ alarm(options.key_regeneration_time);
+ key_used = 1;
+ }
arc4random_stir();
linger.l_linger = 5;
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
+ /* Set keepalives if requested. */
+ if (options.keepalives &&
+ setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
+ sizeof(on)) < 0)
+ error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
+
/*
* Register our connection. This turns encryption off because we do
* not have a key.
{
int i, len;
int plen, slen;
+ int rsafail = 0;
BIGNUM *session_key_int;
u_char session_key[SSH_SESSION_KEY_LENGTH];
u_char cookie[8];
if (options.afs_token_passing)
auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
#endif
-#ifdef SKEY
- if (options.skey_authentication == 1)
+ if (options.challenge_reponse_authentication == 1)
auth_mask |= 1 << SSH_AUTH_TIS;
-#endif
if (options.password_authentication)
auth_mask |= 1 << SSH_AUTH_PASSWORD;
packet_put_int(auth_mask);
* with larger modulus first).
*/
if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) {
- /* Private key has bigger modulus. */
+ /* Server key has bigger modulus. */
if (BN_num_bits(sensitive_data.server_key->rsa->n) <
BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d",
BN_num_bits(sensitive_data.ssh1_host_key->rsa->n),
SSH_KEY_BITS_RESERVED);
}
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.server_key->rsa);
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.ssh1_host_key->rsa);
+ if (rsa_private_decrypt(session_key_int, session_key_int,
+ sensitive_data.server_key->rsa) <= 0)
+ rsafail++;
+ if (rsa_private_decrypt(session_key_int, session_key_int,
+ sensitive_data.ssh1_host_key->rsa) <= 0)
+ rsafail++;
} else {
/* Host key has bigger modulus (or they are equal). */
if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) <
BN_num_bits(sensitive_data.server_key->rsa->n),
SSH_KEY_BITS_RESERVED);
}
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.ssh1_host_key->rsa);
- rsa_private_decrypt(session_key_int, session_key_int,
- sensitive_data.server_key->rsa);
+ if (rsa_private_decrypt(session_key_int, session_key_int,
+ sensitive_data.ssh1_host_key->rsa) < 0)
+ rsafail++;
+ if (rsa_private_decrypt(session_key_int, session_key_int,
+ sensitive_data.server_key->rsa) < 0)
+ rsafail++;
}
compute_session_id(session_id, cookie,
* least significant 256 bits of the integer; the first byte of the
* key is in the highest bits.
*/
- BN_mask_bits(session_key_int, sizeof(session_key) * 8);
- len = BN_num_bytes(session_key_int);
- if (len < 0 || len > sizeof(session_key))
- fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d",
- get_remote_ipaddr(),
- len, sizeof(session_key));
- memset(session_key, 0, sizeof(session_key));
- BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
-
+ if (!rsafail) {
+ BN_mask_bits(session_key_int, sizeof(session_key) * 8);
+ len = BN_num_bytes(session_key_int);
+ if (len < 0 || len > sizeof(session_key)) {
+ error("do_connection: bad session key len from %s: "
+ "session_key_int %d > sizeof(session_key) %d",
+ get_remote_ipaddr(), len, sizeof(session_key));
+ rsafail++;
+ } else {
+ memset(session_key, 0, sizeof(session_key));
+ BN_bn2bin(session_key_int,
+ session_key + sizeof(session_key) - len);
+ }
+ }
+ if (rsafail) {
+ log("do_connection: generating a fake encryption key");
+ for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+ if (i % 4 == 0)
+ rand = arc4random();
+ session_key[i] = rand & 0xff;
+ rand >>= 8;
+ }
+ }
/* Destroy the decrypted integer. It is no longer needed. */
BN_clear_free(session_key_int);
buffer_free(server_kexinit);
xfree(client_kexinit);
xfree(server_kexinit);
+ BN_free(dh_client_pub);
#ifdef DEBUG_KEXDH
fprintf(stderr, "hash == ");
for (i = 0; i< 20; i++)
packet_write_wait();
kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
packet_set_kex(kex);
/* have keys, free DH */
buffer_free(server_kexinit);
xfree(client_kexinit);
xfree(server_kexinit);
+ BN_free(dh_client_pub);
#ifdef DEBUG_KEXDH
fprintf(stderr, "hash == ");
for (i = 0; i< 20; i++)
packet_write_wait();
kex_derive_keys(kex, hash, shared_secret);
+ BN_clear_free(shared_secret);
packet_set_kex(kex);
/* have keys, free DH */