*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.188 2001/04/04 09:48:35 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.204 2001/08/23 17:59:31 camield Exp $");
#include <openssl/dh.h>
#include <openssl/bn.h>
*/
int debug_flag = 0;
+/* Flag indicating that the daemon should only test the configuration and keys. */
+int test_flag = 0;
+
/* Flag indicating that the daemon is being started from inetd. */
int inetd_flag = 0;
char *client_version_string = NULL;
char *server_version_string = NULL;
+/* for rekeying XXX fixme */
+Kex *xxx_kex;
+
/*
* Any really sensitive data in the application is contained in this
* structure. The idea is that this structure could be locked into memory so
*/
int key_do_regen = 0;
-/* This is set to true when SIGHUP is received. */
+/* This is set to true when a signal is received. */
int received_sighup = 0;
+int received_sigterm = 0;
/* session identifier, used by RSA-auth */
u_char session_id[16];
u_int utmp_len = MAXHOSTNAMELEN;
/* Prototypes for various functions defined later in this file. */
-void do_ssh1_kex(void);
-void do_ssh2_kex(void);
+void destroy_sensitive_data(void);
-void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *);
-void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *);
+static void do_ssh1_kex(void);
+static void do_ssh2_kex(void);
/*
* Close all listening sockets
*/
-void
+static void
close_listen_socks(void)
{
int i;
* the effect is to reread the configuration file (and to regenerate
* the server key).
*/
-void
+static void
sighup_handler(int sig)
{
received_sighup = 1;
* Called from the main program after receiving SIGHUP.
* Restarts the server.
*/
-void
+static void
sighup_restart(void)
{
log("Received SIGHUP; restarting.");
/*
* Generic signal handler for terminating signals in the master daemon.
- * These close the listen socket; not closing it seems to cause "Address
- * already in use" problems on some machines, which is inconvenient.
*/
-void
+static void
sigterm_handler(int sig)
{
- log("Received signal %d; terminating.", sig);
- close_listen_socks();
- unlink(options.pid_file);
- exit(255);
+ received_sigterm = sig;
}
/*
* SIGCHLD handler. This is called whenever a child dies. This will then
- * reap any zombies left by exited c.
+ * reap any zombies left by exited children.
*/
-void
+static void
main_sigchld_handler(int sig)
{
int save_errno = errno;
/*
* Signal handler for the alarm after the login grace period has expired.
*/
-void
+static void
grace_alarm_handler(int sig)
{
+ /* XXX no idea how fix this signal handler */
+
/* Close the connection. */
packet_close();
* Thus there should be no concurrency control/asynchronous execution
* problems.
*/
-void
+static void
generate_ephemeral_server_key(void)
{
u_int32_t rand = 0;
int i;
- verbose("Generating %s%d bit RSA key.",
+ verbose("Generating %s%d bit RSA key.",
sensitive_data.server_key ? "new " : "", options.server_key_bits);
if (sensitive_data.server_key != NULL)
key_free(sensitive_data.server_key);
- sensitive_data.server_key = key_generate(KEY_RSA1,
+ sensitive_data.server_key = key_generate(KEY_RSA1,
options.server_key_bits);
verbose("RSA key generation complete.");
arc4random_stir();
}
-void
+static void
key_regeneration_alarm(int sig)
{
int save_errno = errno;
key_do_regen = 1;
}
-void
+static void
sshd_exchange_identification(int sock_in, int sock_out)
{
int i, mismatch;
}
/* Read other side's version identification. */
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, sizeof(buf));
for (i = 0; i < sizeof(buf) - 1; i++) {
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
log("Did not receive identification string from %s.",
server_version_string, client_version_string);
fatal_cleanup();
}
- if (compat20)
- packet_set_ssh2_format();
}
memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
}
-char *
+static char *
list_hostkey_types(void)
{
static char buf[1024];
return buf;
}
-Key *
+static Key *
get_hostkey_by_type(int type)
{
int i;
* of (max_startups_rate/100). the probability increases linearly until
* all connections are dropped for startups > max_startups
*/
-int
+static int
drop_connection(int startups)
{
double p, r;
initialize_server_options(&options);
/* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDiqQ46")) != -1) {
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDeiqtQ46")) != -1) {
switch (opt) {
case '4':
IPv4or6 = AF_INET;
case 'D':
no_daemon_flag = 1;
break;
+ case 'e':
+ log_stderr = 1;
+ break;
case 'i':
inetd_flag = 1;
break;
fprintf(stderr, "too many ports.\n");
exit(1);
}
- options.ports[options.num_ports++] = atoi(optarg);
+ options.ports[options.num_ports++] = a2port(optarg);
+ if (options.ports[options.num_ports-1] == 0) {
+ fprintf(stderr, "Bad port number.\n");
+ exit(1);
+ }
break;
case 'g':
- options.login_grace_time = atoi(optarg);
+ if ((options.login_grace_time = convtime(optarg)) == -1) {
+ fprintf(stderr, "Invalid login grace time.\n");
+ exit(1);
+ }
break;
case 'k':
- options.key_regeneration_time = atoi(optarg);
+ if ((options.key_regeneration_time = convtime(optarg)) == -1) {
+ fprintf(stderr, "Invalid key regeneration interval.\n");
+ exit(1);
+ }
break;
case 'h':
if (options.num_host_key_files >= MAX_HOSTKEYS) {
/* only makes sense with inetd_flag, i.e. no listen() */
inetd_flag = 1;
break;
+ case 't':
+ test_flag = 1;
+ break;
case 'u':
utmp_len = atoi(optarg);
break;
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, " -t Only test configuration file and keys\n");
fprintf(stderr, " -q Quiet (no logging)\n");
fprintf(stderr, " -p port Listen on the specified port (default: 22)\n");
fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n");
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
!inetd_flag);
+#ifdef _CRAY
+ /* Cray can define user privs drop all prives now!
+ * Not needed on PRIV_SU systems!
+ */
+ drop_cray_privs();
+#endif
+
seed_rng();
/* Read server configuration options from the configuration file. */
key = key_load_private(options.host_key_files[i], "", NULL);
sensitive_data.host_keys[i] = key;
if (key == NULL) {
- error("Could not load host key: %.200s: %.100s",
- options.host_key_files[i], strerror(errno));
+ error("Could not load host key: %s",
+ options.host_key_files[i]);
sensitive_data.host_keys[i] = NULL;
continue;
}
}
}
+ /* Configuration looks good, so exit if in test mode. */
+ if (test_flag)
+ exit(0);
+
#ifdef HAVE_SCO_PROTECTED_PW
(void) set_auth_parameters(ac, av);
#endif
/* Start listening for a socket, unless started from inetd. */
if (inetd_flag) {
- int s1, s2;
+ int s1;
s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
- s2 = dup(s1);
+ dup(s1);
sock_in = dup(0);
sock_out = dup(1);
startup_pipe = -1;
if (!num_listen_socks)
fatal("Cannot bind any address.");
+ if (options.protocol & SSH_PROTO_1)
+ generate_ephemeral_server_key();
+
+ /*
+ * Arrange to restart on SIGHUP. The handler needs
+ * listen_sock.
+ */
+ signal(SIGHUP, sighup_handler);
+
+ signal(SIGTERM, sigterm_handler);
+ signal(SIGQUIT, sigterm_handler);
+
+ /* Arrange SIGCHLD to be caught. */
+ signal(SIGCHLD, main_sigchld_handler);
+
+ /* Write out the pid file after the sigterm handler is setup */
if (!debug_flag) {
/*
* Record our pid in /var/run/sshd.pid to make it
fclose(f);
}
}
- if (options.protocol & SSH_PROTO_1)
- generate_ephemeral_server_key();
-
- /* Arrange to restart on SIGHUP. The handler needs listen_sock. */
- signal(SIGHUP, sighup_handler);
-
- signal(SIGTERM, sigterm_handler);
- signal(SIGQUIT, sigterm_handler);
-
- /* Arrange SIGCHLD to be caught. */
- signal(SIGCHLD, main_sigchld_handler);
/* setup fd set for listen */
fdset = NULL;
ret = select(maxfd+1, fdset, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR)
error("select: %.100s", strerror(errno));
+ if (received_sigterm) {
+ log("Received signal %d; terminating.",
+ received_sigterm);
+ close_listen_socks();
+ unlink(options.pid_file);
+ exit(255);
+ }
if (key_used && key_do_regen) {
generate_ephemeral_server_key();
key_used = 0;
{
struct request_info req;
- request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, NULL);
+ request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);
fromhost(&req);
if (!hosts_access(&req)) {
"originating port not trusted.");
options.rhosts_authentication = 0;
}
-#ifdef KRB4
+#if defined(KRB4) && !defined(KRB5)
if (!packet_connection_is_ipv4() &&
options.kerberos_authentication) {
debug("Kerberos Authentication disabled, only available for IPv4.");
options.kerberos_authentication = 0;
}
-#endif /* KRB4 */
+#endif /* KRB4 && !KRB5 */
#ifdef AFS
/* If machine has AFS, set process authentication group. */
if (k_hasafs()) {
do_ssh1_kex();
do_authentication();
}
-
-#ifdef KRB4
- /* Cleanup user's ticket cache file. */
- if (options.kerberos_ticket_cleanup)
- (void) dest_tkt();
-#endif /* KRB4 */
-
/* The connection has been terminated. */
verbose("Closing connection to %.100s", remote_ip);
/*
* SSH1 key exchange
*/
-void
+static void
do_ssh1_kex(void)
{
int i, len;
auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
if (options.rsa_authentication)
auth_mask |= 1 << SSH_AUTH_RSA;
-#ifdef KRB4
+#if defined(KRB4) || defined(KRB5)
if (options.kerberos_authentication)
auth_mask |= 1 << SSH_AUTH_KERBEROS;
#endif
-#ifdef AFS
+#if defined(AFS) || defined(KRB5)
if (options.kerberos_tgt_passing)
auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
+#endif
+#ifdef AFS
if (options.afs_token_passing)
auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
#endif
- if (options.challenge_reponse_authentication == 1)
+ if (options.challenge_response_authentication == 1)
auth_mask |= 1 << SSH_AUTH_TIS;
if (options.password_authentication)
auth_mask |= 1 << SSH_AUTH_PASSWORD;
/*
* SSH2 key exchange: diffie-hellman-group1-sha1
*/
-void
+static void
do_ssh2_kex(void)
{
Kex *kex;
}
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
+ /* start key exchange */
kex = kex_setup(myproposal);
kex->server = 1;
kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string;
kex->load_host_key=&get_hostkey_by_type;
- /* start key exchange */
- dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex);
+ xxx_kex = kex;
+
+ dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
session_id2 = kex->session_id;
session_id2_len = kex->session_id_len;