X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/f546c7809836bd6d7fce818781a88166fe50cded..6a416424046d6c8f6acd13d2bc5dd3553178b3ac:/sshd.c diff --git a/sshd.c b/sshd.c index 298a1b6b..e3291129 100644 --- a/sshd.c +++ b/sshd.c @@ -40,32 +40,36 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.147 2001/01/10 19:43:20 deraadt Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.163 2001/02/04 23:56:23 deraadt Exp $"); +#include +#include +#include + +#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 -#include -#include +#include "cipher.h" #include "kex.h" -#include -#include #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 @@ -88,7 +92,7 @@ char *__progname; 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. @@ -153,10 +157,10 @@ struct { } 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; @@ -266,7 +270,6 @@ grace_alarm_handler(int sig) * 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) @@ -284,17 +287,9 @@ 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 @@ -434,7 +429,7 @@ destroy_sensitive_data(void) key_free(sensitive_data.server_key); sensitive_data.server_key = NULL; } - for(i = 0; i < options.num_host_key_files; i++) { + for(i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; @@ -556,7 +551,6 @@ main(int ac, char **av) 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; @@ -568,6 +562,7 @@ main(int ac, char **av) int listen_sock, maxfd; int startup_p[2]; int startups = 0; + int ret, key_used = 0; __progname = get_progname(av[0]); init_rng(); @@ -580,7 +575,7 @@ main(int ac, char **av) 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; @@ -609,7 +604,7 @@ main(int ac, char **av) inetd_flag = 1; break; case 'Q': - silent = 1; + /* ignored */ break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; @@ -651,7 +646,7 @@ main(int ac, char **av) 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"); @@ -661,7 +656,7 @@ main(int ac, char **av) 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"); @@ -674,9 +669,9 @@ main(int ac, char **av) * 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); @@ -728,9 +723,7 @@ main(int ac, char **av) log("Disabling protocol version 2. Could not load host key"); 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"); + if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { log("sshd: no hostkeys available -- exiting.\n"); exit(1); } @@ -890,14 +883,9 @@ main(int ac, char **av) 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); @@ -927,7 +915,7 @@ main(int ac, char **av) 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); @@ -938,11 +926,17 @@ main(int ac, char **av) 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)) { @@ -989,7 +983,7 @@ main(int ac, char **av) startups++; break; } - + /* * Got connection. Fork a child to handle it, unless * we are in debugging mode. @@ -1042,7 +1036,13 @@ main(int ac, char **av) 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(); @@ -1080,6 +1080,12 @@ main(int ac, char **av) 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. @@ -1180,6 +1186,7 @@ do_ssh1_kex(void) { 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]; @@ -1245,10 +1252,8 @@ do_ssh1_kex(void) 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); @@ -1292,7 +1297,7 @@ do_ssh1_kex(void) * 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", @@ -1301,10 +1306,12 @@ do_ssh1_kex(void) 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) < @@ -1315,10 +1322,12 @@ do_ssh1_kex(void) 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, @@ -1333,15 +1342,29 @@ do_ssh1_kex(void) * 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, (int)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); @@ -1484,7 +1507,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) fprintf(stderr, "\npub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); + DHparams_print_fp(stderr, dh); #endif if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); @@ -1524,6 +1547,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) 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++) @@ -1553,6 +1577,7 @@ ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) packet_write_wait(); kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); packet_set_kex(kex); /* have keys, free DH */ @@ -1625,7 +1650,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) fprintf(stderr, "\npub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); + DHparams_print_fp(stderr, dh); #endif if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); @@ -1666,6 +1691,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) 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++) @@ -1695,6 +1721,7 @@ ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) packet_write_wait(); kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); packet_set_kex(kex); /* have keys, free DH */