summaryrefslogtreecommitdiffstats
path: root/sshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c4503
1 files changed, 2252 insertions, 2251 deletions
diff --git a/sshd.c b/sshd.c
index 5718eae9..dba2d474 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,24 +1,17 @@
/*
-
-sshd.c
-
-Author: Tatu Ylonen <ylo@cs.hut.fi>
-
-Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- All rights reserved
-
-Created: Fri Mar 17 17:09:28 1995 ylo
-
-This program is the ssh daemon. It listens for connections from clients, and
-performs authentication, executes use commands or shell, and forwards
-information to/from the application to the user client over an encrypted
-connection. This can also handle forwarding of X11, TCP/IP, and authentication
-agent connections.
-
-*/
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * Created: Fri Mar 17 17:09:28 1995 ylo
+ * This program is the ssh daemon. It listens for connections from clients, and
+ * performs authentication, executes use commands or shell, and forwards
+ * information to/from the application to the user client over an encrypted
+ * connection. This can also handle forwarding of X11, TCP/IP, and authentication
+ * agent connections.
+ */
#include "includes.h"
-RCSID("$Id: sshd.c,v 1.29 1999/11/23 00:24:32 damien Exp $");
+RCSID("$Id: sshd.c,v 1.30 1999/11/24 13:26:23 damien Exp $");
#include "xmalloc.h"
#include "rsa.h"
@@ -52,10 +45,12 @@ ServerOptions options;
/* Name of the server configuration file. */
char *config_file_name = SERVER_CONFIG_FILE;
-/* Debug mode flag. This can be set on the command line. If debug
- mode is enabled, extra debugging output will be sent to the system
- log, the daemon will not go to background, and will exit after processing
- the first connection. */
+/*
+ * Debug mode flag. This can be set on the command line. If debug
+ * mode is enabled, extra debugging output will be sent to the system
+ * log, the daemon will not go to background, and will exit after processing
+ * the first connection.
+ */
int debug_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
@@ -74,15 +69,21 @@ char **saved_argv;
the SIGHUP signal handler. */
int listen_sock;
-/* Flags set in auth-rsa from authorized_keys flags. These are set in
- auth-rsa.c. */
+/* the client's version string, passed by sshd2 in compat mode.
+ if != NULL, sshd will skip the version-number exchange */
+char *client_version_string = NULL;
+
+/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
int no_port_forwarding_flag = 0;
int no_agent_forwarding_flag = 0;
int no_x11_forwarding_flag = 0;
int no_pty_flag = 0;
-char *forced_command = NULL; /* RSA authentication "command=" option. */
-struct envstring *custom_environment = NULL;
- /* RSA authentication "environment=" options. */
+
+/* RSA authentication "command=" option. */
+char *forced_command = NULL;
+
+/* RSA authentication "environment=" options. */
+struct envstring *custom_environment = NULL;
/* Session id for the current session. */
unsigned char session_id[16];
@@ -93,13 +94,9 @@ unsigned char session_id[16];
The private key contains BIGNUMs, and we do not (in principle) have
access to the internals of them, and locking just the structure is not
very useful. Currently, memory locking is not implemented. */
-struct
-{
- /* Private part of server key. */
- RSA *private_key;
-
- /* Private part of host key. */
- RSA *host_key;
+struct {
+ RSA *private_key; /* Private part of server key. */
+ RSA *host_key; /* Private part of host key. */
} sensitive_data;
/* Flag indicating whether the current session key has been used. This flag
@@ -116,2454 +113,2458 @@ RSA *public_key;
/* Prototypes for various functions defined later in this file. */
void do_connection();
void do_authentication(char *user);
-void do_authloop(struct passwd *pw);
+void do_authloop(struct passwd * pw);
void do_fake_authloop(char *user);
-void do_authenticated(struct passwd *pw);
-void do_exec_pty(const char *command, int ptyfd, int ttyfd,
- const char *ttyname, struct passwd *pw, const char *term,
- const char *display, const char *auth_proto,
- const char *auth_data);
-void do_exec_no_pty(const char *command, struct passwd *pw,
- const char *display, const char *auth_proto,
- const char *auth_data);
-void do_child(const char *command, struct passwd *pw, const char *term,
+void do_authenticated(struct passwd * pw);
+void do_exec_pty(const char *command, int ptyfd, int ttyfd,
+ const char *ttyname, struct passwd * pw, const char *term,
+ const char *display, const char *auth_proto,
+ const char *auth_data);
+void do_exec_no_pty(const char *command, struct passwd * pw,
+ const char *display, const char *auth_proto,
+ const char *auth_data);
+void do_child(const char *command, struct passwd * pw, const char *term,
const char *display, const char *auth_proto,
const char *auth_data, const char *ttyname);
#ifdef HAVE_LIBPAM
static int pamconv(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr);
+ struct pam_response **resp, void *appdata_ptr);
void do_pam_account_and_session(char *username, char *remote_user,
- const char *remote_host);
+ const char *remote_host);
void pam_cleanup_proc(void *context);
static struct pam_conv conv = {
- pamconv,
- NULL
+ pamconv,
+ NULL
};
struct pam_handle_t *pamh = NULL;
const char *pampasswd = NULL;
char *pamconv_msg = NULL;
static int pamconv(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata_ptr)
+ struct pam_response **resp, void *appdata_ptr)
{
- struct pam_response *reply;
- int count;
- size_t msg_len;
- char *p;
-
- /* PAM will free this later */
- reply = malloc(num_msg * sizeof(*reply));
- if (reply == NULL)
- return PAM_CONV_ERR;
-
- for(count = 0; count < num_msg; count++)
- {
- switch (msg[count]->msg_style)
- {
- case PAM_PROMPT_ECHO_OFF:
- if (pampasswd == NULL)
- {
- free(reply);
- return PAM_CONV_ERR;
- }
- reply[count].resp_retcode = PAM_SUCCESS;
- reply[count].resp = xstrdup(pampasswd);
- break;
-
- case PAM_TEXT_INFO:
- reply[count].resp_retcode = PAM_SUCCESS;
- reply[count].resp = xstrdup("");
-
- if (msg[count]->msg == NULL)
- break;
- debug("Adding PAM message: %s", msg[count]->msg);
-
- msg_len = strlen(msg[count]->msg);
- if (pamconv_msg)
- {
- size_t n = strlen(pamconv_msg);
- pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
- p = pamconv_msg + n;
+ struct pam_response *reply;
+ int count;
+ size_t msg_len;
+ char *p;
+
+ /* PAM will free this later */
+ reply = malloc(num_msg * sizeof(*reply));
+ if (reply == NULL)
+ return PAM_CONV_ERR;
+
+ for(count = 0; count < num_msg; count++) {
+ switch (msg[count]->msg_style) {
+ case PAM_PROMPT_ECHO_OFF:
+ if (pampasswd == NULL) {
+ free(reply);
+ return PAM_CONV_ERR;
+ }
+ reply[count].resp_retcode = PAM_SUCCESS;
+ reply[count].resp = xstrdup(pampasswd);
+ break;
+
+ case PAM_TEXT_INFO:
+ reply[count].resp_retcode = PAM_SUCCESS;
+ reply[count].resp = xstrdup("");
+
+ if (msg[count]->msg == NULL)
+ break;
+
+ debug("Adding PAM message: %s", msg[count]->msg);
+
+ msg_len = strlen(msg[count]->msg);
+ if (pamconv_msg) {
+ size_t n = strlen(pamconv_msg);
+ pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
+ p = pamconv_msg + n;
+ } else {
+ pamconv_msg = p = xmalloc(msg_len + 2);
+ }
+ memcpy(p, msg[count]->msg, msg_len);
+ p[msg_len] = '\n';
+ p[msg_len + 1] = '\0';
+ break;
+
+ case PAM_PROMPT_ECHO_ON:
+ case PAM_ERROR_MSG:
+ default:
+ free(reply);
+ return PAM_CONV_ERR;
+ }
}
- else
- pamconv_msg = p = xmalloc(msg_len + 2);
- memcpy(p, msg[count]->msg, msg_len);
- p[msg_len] = '\n';
- p[msg_len + 1] = '\0';
- break;
-
- case PAM_PROMPT_ECHO_ON:
- case PAM_ERROR_MSG:
- default:
- free(reply);
- return PAM_CONV_ERR;
- }
- }
-
- *resp = reply;
-
- return PAM_SUCCESS;
+
+ *resp = reply;
+
+ return PAM_SUCCESS;
}
void pam_cleanup_proc(void *context)
{
- int pam_retval;
-
- if (pamh != NULL)
- {
- pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
- if (pam_retval != PAM_SUCCESS)
- {
- log("Cannot close PAM session: %.200s",
- PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- }
-
- pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
- if (pam_retval != PAM_SUCCESS)
- {
- log("Cannot release PAM authentication: %.200s",
- PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- }
- }
+ int pam_retval;
+
+ if (pamh != NULL)
+ {
+ pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
+ if (pam_retval != PAM_SUCCESS) {
+ log("Cannot close PAM session: %.200s",
+ PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ }
+
+ pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
+ if (pam_retval != PAM_SUCCESS) {
+ log("Cannot release PAM authentication: %.200s",
+ PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ }
+ }
}
void do_pam_account_and_session(char *username, char *remote_user,
- const char *remote_host)
+ const char *remote_host)
{
- int pam_retval;
-
- if (remote_host != NULL)
- {
- debug("PAM setting rhost to \"%.200s\"", remote_host);
- pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host);
- if (pam_retval != PAM_SUCCESS)
- {
- log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- do_fake_authloop(username);
- }
- }
-
- if (remote_user != NULL)
- {
- debug("PAM setting ruser to \"%.200s\"", remote_user);
- pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
- if (pam_retval != PAM_SUCCESS)
- {
- log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- do_fake_authloop(username);
- }
- }
-
- pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
- if (pam_retval != PAM_SUCCESS)
- {
- log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- do_fake_authloop(username);
- }
-
- pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
- if (pam_retval != PAM_SUCCESS)
- {
- log("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
- do_fake_authloop(username);
- }
+ int pam_retval;
+
+ if (remote_host != NULL) {
+ debug("PAM setting rhost to \"%.200s\"", remote_host);
+ pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host);
+ if (pam_retval != PAM_SUCCESS) {
+ log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ do_fake_authloop(username);
+ }
+ }
+
+ if (remote_user != NULL) {
+ debug("PAM setting ruser to \"%.200s\"", remote_user);
+ pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
+ if (pam_retval != PAM_SUCCESS) {
+ log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ do_fake_authloop(username);
+ }
+ }
+
+ pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
+ if (pam_retval != PAM_SUCCESS) {
+ log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ do_fake_authloop(username);
+ }
+
+ pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
+ if (pam_retval != PAM_SUCCESS) {
+ log("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
+ do_fake_authloop(username);
+ }
}
#endif /* HAVE_LIBPAM */
-/* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
- the effect is to reread the configuration file (and to regenerate
- the server key). */
-
-void sighup_handler(int sig)
+/*
+ * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
+ * the effect is to reread the configuration file (and to regenerate
+ * the server key).
+ */
+void
+sighup_handler(int sig)
{
- received_sighup = 1;
- signal(SIGHUP, sighup_handler);
+ received_sighup = 1;
+ signal(SIGHUP, sighup_handler);
}
-/* Called from the main program after receiving SIGHUP. Restarts the
- server. */
-
-void sighup_restart()
+/*
+ * Called from the main program after receiving SIGHUP.
+ * Restarts the server.
+ */
+void
+sighup_restart()
{
- log("Received SIGHUP; restarting.");
- close(listen_sock);
- execv(saved_argv[0], saved_argv);
- log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
- exit(1);
+ log("Received SIGHUP; restarting.");
+ close(listen_sock);
+ execv(saved_argv[0], saved_argv);
+ log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
+ exit(1);
}
-/* 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 sigterm_handler(int sig)
+/*
+ * 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
+sigterm_handler(int sig)
{
- log("Received signal %d; terminating.", sig);
- close(listen_sock);
- exit(255);
+ log("Received signal %d; terminating.", sig);
+ close(listen_sock);
+ exit(255);
}
-/* SIGCHLD handler. This is called whenever a child dies. This will then
- reap any zombies left by exited c. */
-
-void main_sigchld_handler(int sig)
+/*
+ * SIGCHLD handler. This is called whenever a child dies. This will then
+ * reap any zombies left by exited c.
+ */
+void
+main_sigchld_handler(int sig)
{
- int save_errno = errno;
- int status;
+ int save_errno = errno;
+ int status;
- while (waitpid(-1, &status, WNOHANG) > 0)
- ;
+ while (waitpid(-1, &status, WNOHANG) > 0)
+ ;
- signal(SIGCHLD, main_sigchld_handler);
- errno = save_errno;
+ signal(SIGCHLD, main_sigchld_handler);
+ errno = save_errno;
}
-/* Signal handler for the alarm after the login grace period has expired. */
-
-void grace_alarm_handler(int sig)
+/*
+ * Signal handler for the alarm after the login grace period has expired.
+ */
+void
+grace_alarm_handler(int sig)
{
- /* Close the connection. */
- packet_close();
-
- /* Log error and exit. */
- fatal("Timeout before authentication.");
-}
+ /* Close the connection. */
+ packet_close();
-/* Signal handler for the key regeneration alarm. Note that this
- alarm only occurs in the daemon waiting for connections, and it does not
- do anything with the private key or random state before forking. Thus there
- should be no concurrency control/asynchronous execution problems. */
+ /* Log error and exit. */
+ fatal("Timeout before authentication for %s.", get_remote_ipaddr());
+}
-void key_regeneration_alarm(int sig)
+/*
+ * convert ssh auth msg type into description
+ */
+char *
+get_authname(int type)
{
- int save_errno = errno;
-
- /* Check if we should generate a new key. */
- if (key_used)
- {
- /* This should really be done in the background. */
- log("Generating new %d bit RSA key.", options.server_key_bits);
-
- if (sensitive_data.private_key != NULL)
- RSA_free(sensitive_data.private_key);
- sensitive_data.private_key = RSA_new();
-
- if (public_key != NULL)
- RSA_free(public_key);
- public_key = RSA_new();
-
- rsa_generate_key(sensitive_data.private_key, public_key,
- options.server_key_bits);
- arc4random_stir();
- key_used = 0;
- log("RSA key generation complete.");
- }
-
- /* Reschedule the alarm. */
- signal(SIGALRM, key_regeneration_alarm);
- alarm(options.key_regeneration_time);
- errno = save_errno;
+ switch (type) {
+ case SSH_CMSG_AUTH_PASSWORD:
+ return "password";
+ case SSH_CMSG_AUTH_RSA:
+ return "rsa";
+ case SSH_CMSG_AUTH_RHOSTS_RSA:
+ return "rhosts-rsa";
+ case SSH_CMSG_AUTH_RHOSTS:
+ return "rhosts";
+#ifdef KRB4
+ case SSH_CMSG_AUTH_KERBEROS:
+ return "kerberos";
+#endif
+#ifdef SKEY
+ case SSH_CMSG_AUTH_TIS_RESPONSE:
+ return "s/key";
+#endif
+ }
+ fatal("get_authname: unknown auth %d: internal error", type);
+ return NULL;
}
-/* Main program for the daemon. */
+/*
+ * Signal handler for the key regeneration alarm. Note that this
+ * alarm only occurs in the daemon waiting for connections, and it does not
+ * do anything with the private key or random state before forking.
+ * Thus there should be no concurrency control/asynchronous execution
+ * problems.
+ */
+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. */
+ log("Generating new %d bit RSA key.", options.server_key_bits);
+
+ if (sensitive_data.private_key != NULL)
+ RSA_free(sensitive_data.private_key);
+ sensitive_data.private_key = RSA_new();
+
+ if (public_key != NULL)
+ RSA_free(public_key);
+ public_key = RSA_new();
+
+ rsa_generate_key(sensitive_data.private_key, public_key,
+ options.server_key_bits);
+ arc4random_stir();
+ key_used = 0;
+ log("RSA key generation complete.");
+ }
+ /* Reschedule the alarm. */
+ signal(SIGALRM, key_regeneration_alarm);
+ alarm(options.key_regeneration_time);
+ errno = save_errno;
+}
+/*
+ * Main program for the daemon.
+ */
int
main(int ac, char **av)
{
- extern char *optarg;
- extern int optind;
- int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1;
- int remote_major, remote_minor;
- int silentrsa = 0;
- struct sockaddr_in sin;
- char buf[100]; /* Must not be larger than remote_version. */
- char remote_version[100]; /* Must be at least as big as buf. */
- int remote_port;
- char *comment;
- FILE *f;
- struct linger linger;
-
- /* Save argv[0]. */
- saved_argv = av;
- if (strchr(av[0], '/'))
- av0 = strrchr(av[0], '/') + 1;
- else
- av0 = av[0];
-
- /* Initialize configuration options to their default values. */
- initialize_server_options(&options);
-
- /* Parse command-line arguments. */
- while ((opt = getopt(ac, av, "f:p:b:k:h:g:diqQ")) != EOF)
- {
- switch (opt)
- {
- case 'f':
- config_file_name = optarg;
- break;
- case 'd':
- debug_flag = 1;
- options.log_level = SYSLOG_LEVEL_DEBUG;
- break;
- case 'i':
- inetd_flag = 1;
- break;
- case 'Q':
- silentrsa = 1;
- break;
- case 'q':
- options.log_level = SYSLOG_LEVEL_QUIET;
- break;
- case 'b':
- options.server_key_bits = atoi(optarg);
- break;
- case 'p':
- options.port = atoi(optarg);
- break;
- case 'g':
- options.login_grace_time = atoi(optarg);
- break;
- case 'k':
- options.key_regeneration_time = atoi(optarg);
- break;
- case 'h':
- options.host_key_file = optarg;
- break;
- case '?':
- default:
- fprintf(stderr, "sshd version %s\n", SSH_VERSION);
- fprintf(stderr, "Usage: %s [options]\n", av0);
- fprintf(stderr, "Options:\n");
- fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR);
- fprintf(stderr, " -d Debugging mode\n");
- fprintf(stderr, " -i Started from inetd\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");
- fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\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);
- exit(1);
+ extern char *optarg;
+ extern int optind;
+ int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1;
+ int remote_major, remote_minor;
+ int silentrsa = 0;
+ struct sockaddr_in sin;
+ char buf[100]; /* Must not be larger than remote_version. */
+ char remote_version[100]; /* Must be at least as big as buf. */
+ const char *remote_ip;
+ int remote_port;
+ char *comment;
+ FILE *f;
+ struct linger linger;
+
+ /* Save argv[0]. */
+ saved_argv = av;
+ if (strchr(av[0], '/'))
+ av0 = strrchr(av[0], '/') + 1;
+ else
+ av0 = av[0];
+
+ /* Initialize configuration options to their default values. */
+ initialize_server_options(&options);
+
+ /* Parse command-line arguments. */
+ while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ")) != EOF) {
+ switch (opt) {
+ case 'f':
+ config_file_name = optarg;
+ break;
+ case 'd':
+ debug_flag = 1;
+ options.log_level = SYSLOG_LEVEL_DEBUG;
+ break;
+ case 'i':
+ inetd_flag = 1;
+ break;
+ case 'Q':
+ silentrsa = 1;
+ break;
+ case 'q':
+ options.log_level = SYSLOG_LEVEL_QUIET;
+ break;
+ case 'b':
+ options.server_key_bits = atoi(optarg);
+ break;
+ case 'p':
+ options.port = atoi(optarg);
+ break;
+ case 'g':
+ options.login_grace_time = atoi(optarg);
+ break;
+ case 'k':
+ options.key_regeneration_time = atoi(optarg);
+ break;
+ case 'h':
+ options.host_key_file = optarg;
+ break;
+ case 'V':
+ client_version_string = optarg;
+ /* only makes sense with inetd_flag, i.e. no listen() */
+ inetd_flag = 1;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "sshd version %s\n", SSH_VERSION);
+ fprintf(stderr, "Usage: %s [options]\n", av0);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR);
+ fprintf(stderr, " -d Debugging mode\n");
+ fprintf(stderr, " -i Started from inetd\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");
+ fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\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);
+ exit(1);
+ }
+ }
+
+ /* check if RSA support exists */
+ if (rsa_alive() == 0) {
+ if (silentrsa == 0)
+ printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
+ log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
+ exit(1);
+ }
+ /* Read server configuration options from the configuration file. */
+ read_server_config(&options, config_file_name);
+
+ /* Fill in default values for those options not explicitly set. */
+ fill_default_server_options(&options);
+
+ /* Check certain values for sanity. */
+ if (options.server_key_bits < 512 ||
+ options.server_key_bits > 32768) {
+ fprintf(stderr, "Bad server key size.\n");
+ exit(1);
+ }
+ if (options.port < 1 || options.port > 65535) {
+ fprintf(stderr, "Bad port number.\n");
+ exit(1);
+ }
+ /* Check that there are no remaining arguments. */
+ if (optind < ac) {
+ fprintf(stderr, "Extra argument %s.\n", av[optind]);
+ exit(1);
}
- }
-
- /* check if RSA support exists */
- if (rsa_alive() == 0) {
- if (silentrsa == 0)
- printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
- log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
- exit(1);
- }
-
- /* Read server configuration options from the configuration file. */
- read_server_config(&options, config_file_name);
-
- /* Fill in default values for those options not explicitly set. */
- fill_default_server_options(&options);
-
- /* Check certain values for sanity. */
- if (options.server_key_bits < 512 ||
- options.server_key_bits > 32768)
- {
- fprintf(stderr, "Bad server key size.\n");
- exit(1);
- }
- if (options.port < 1 || options.port > 65535)
- {
- fprintf(stderr, "Bad port number.\n");
- exit(1);
- }
-
- /* Check that there are no remaining arguments. */
- if (optind < ac)
- {
- fprintf(stderr, "Extra argument %s.\n", av[optind]);
- exit(1);
- }
-
- /* Force logging to stderr while loading the private host key
- unless started from inetd */
- log_init(av0, options.log_level, options.log_facility, !inetd_flag);
-
- debug("sshd version %.100s", SSH_VERSION);
-
- sensitive_data.host_key = RSA_new();
- errno = 0;
- /* Load the host key. It must have empty passphrase. */
- if (!load_private_key(options.host_key_file, "",
- sensitive_data.host_key, &comment))
- {
- error("Could not load host key: %.200s: %.100s",
- options.host_key_file, strerror(errno));
- exit(1);
- }
- xfree(comment);
-
- /* Initialize the log (it is reinitialized below in case we forked). */
- if (debug_flag && !inetd_flag)
- log_stderr = 1;
- log_init(av0, options.log_level, options.log_facility, log_stderr);
-
- /* If not in debugging mode, and not started from inetd, disconnect from
- the controlling terminal, and fork. The original process exits. */
- if (!debug_flag && !inetd_flag)
- {
+ /* Force logging to stderr while loading the private host key
+ unless started from inetd */
+ log_init(av0, options.log_level, options.log_facility, !inetd_flag);
+
+ debug("sshd version %.100s", SSH_VERSION);
+
+ sensitive_data.host_key = RSA_new();
+ errno = 0;
+ /* Load the host key. It must have empty passphrase. */
+ if (!load_private_key(options.host_key_file, "",
+ sensitive_data.host_key, &comment)) {
+ error("Could not load host key: %.200s: %.100s",
+ options.host_key_file, strerror(errno));
+ exit(1);
+ }
+ xfree(comment);
+
+ /* Initialize the log (it is reinitialized below in case we
+ forked). */
+ if (debug_flag && !inetd_flag)
+ log_stderr = 1;
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
+
+ /* If not in debugging mode, and not started from inetd,
+ disconnect from the controlling terminal, and fork. The
+ original process exits. */
+ if (!debug_flag && !inetd_flag) {
#ifdef TIOCNOTTY
- int fd;
+ int fd;
#endif /* TIOCNOTTY */
- if (daemon(0, 0) < 0)
- fatal("daemon() failed: %.200s", strerror(errno));
-
- /* Disconnect from the controlling tty. */
+ if (daemon(0, 0) < 0)
+ fatal("daemon() failed: %.200s", strerror(errno));
+
+ /* Disconnect from the controlling tty. */
#ifdef TIOCNOTTY
- fd = open("/dev/tty", O_RDWR|O_NOCTTY);
- if (fd >= 0)
- {
- (void)ioctl(fd, TIOCNOTTY, NULL);
- close(fd);
- }
+ fd = open("/dev/tty", O_RDWR | O_NOCTTY);
+ if (fd >= 0) {
+ (void) ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
#endif /* TIOCNOTTY */
- }
-
- /* Reinitialize the log (because of the fork above). */
- log_init(av0, options.log_level, options.log_facility, log_stderr);
-
- /* Check that server and host key lengths differ sufficiently. This is
- necessary to make double encryption work with rsaref. Oh, I hate
- software patents. I dont know if this can go? Niels */
- if (options.server_key_bits >
- BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
- options.server_key_bits <
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED)
- {
- options.server_key_bits =
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
- debug("Forcing server key to %d bits to make it differ from host key.",
- options.server_key_bits);
- }
-
- /* Do not display messages to stdout in RSA code. */
- rsa_set_verbose(0);
-
- /* Initialize the random number generator. */
- arc4random_stir();
-
- /* Chdir to the root directory so that the current disk can be unmounted
- if desired. */
- chdir("/");
-
- /* Close connection cleanly after attack. */
- cipher_attack_detected = packet_disconnect;
-
- /* Start listening for a socket, unless started from inetd. */
- if (inetd_flag)
- {
- int s1, s2;
- s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */
- s2 = dup(s1);
- sock_in = dup(0);
- sock_out = dup(1);
- /* We intentionally do not close the descriptors 0, 1, and 2 as our
- code for setting the descriptors won\'t work if ttyfd happens to
- be one of those. */
- debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
-
- public_key = RSA_new();
- sensitive_data.private_key = RSA_new();
- /* Generate an rsa key. */
- log("Generating %d bit RSA key.", options.server_key_bits);
- rsa_generate_key(sensitive_data.private_key, public_key,
- options.server_key_bits);
- arc4random_stir();
- log("RSA key generation complete.");
- }
- else
- {
- /* Create socket for listening. */
- listen_sock = socket(AF_INET, SOCK_STREAM, 0);
- if (listen_sock < 0)
- fatal("socket: %.100s", strerror(errno));
-
- /* Set socket options. We try to make the port reusable and have it
- close as fast as possible without waiting in unnecessary wait states
- on close. */
- setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
- sizeof(on));
- linger.l_onoff = 1;
- linger.l_linger = 5;
- setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *)&linger,
- sizeof(linger));
-
- /* Initialize the socket address. */
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr = options.listen_addr;
- sin.sin_port = htons(options.port);
-
- /* Bind the socket to the desired port. */
- if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
- {
- error("bind: %.100s", strerror(errno));
- shutdown(listen_sock, SHUT_RDWR);
- close(listen_sock);
- fatal("Bind to port %d failed.", options.port);
}
-
- if (!debug_flag)
- {
- /* Record our pid in /etc/sshd_pid to make it easier to kill the
- correct sshd. We don\'t want to do this before the bind above
- because the bind will fail if there already is a daemon, and this
- will overwrite any old pid in the file. */
- f = fopen(SSH_DAEMON_PID_FILE, "w");
- if (f)
- {
- fprintf(f, "%u\n", (unsigned int)getpid());
- fclose(f);
- }
+ /* Reinitialize the log (because of the fork above). */
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
+
+ /* Check that server and host key lengths differ sufficiently.
+ This is necessary to make double encryption work with rsaref.
+ Oh, I hate software patents. I dont know if this can go? Niels */
+ if (options.server_key_bits >
+ BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
+ options.server_key_bits <
+ BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+ options.server_key_bits =
+ BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
+ debug("Forcing server key to %d bits to make it differ from host key.",
+ options.server_key_bits);
}
-
- /* Start listening on the port. */
- log("Server listening on port %d.", options.port);
- if (listen(listen_sock, 5) < 0)
- fatal("listen: %.100s", strerror(errno));
-
- public_key = RSA_new();
- sensitive_data.private_key = RSA_new();
- /* Generate an rsa key. */
- log("Generating %d bit RSA key.", options.server_key_bits);
- rsa_generate_key(sensitive_data.private_key, public_key,
- options.server_key_bits);
- arc4random_stir();
- log("RSA key generation complete.");
-
- /* 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);
- signal(SIGTERM, sigterm_handler);
- signal(SIGQUIT, sigterm_handler);
-
- /* Arrange SIGCHLD to be caught. */
- signal(SIGCHLD, main_sigchld_handler);
-
- /* Stay listening for connections until the system crashes or the
- daemon is killed with a signal. */
- for (;;)
- {
- if (received_sighup)
- sighup_restart();
- /* Wait in accept until there is a connection. */
- aux = sizeof(sin);
- newsock = accept(listen_sock, (struct sockaddr *)&sin, &aux);
- if (received_sighup)
- sighup_restart();
- if (newsock < 0)
- {
- if (errno == EINTR)
- continue;
- error("accept: %.100s", strerror(errno));
- continue;
- }
-
- /* Got connection. Fork a child to handle it, unless we are in
- debugging mode. */
- if (debug_flag)
- {
- /* In debugging mode. Close the listening socket, and start
- processing the connection without forking. */
- debug("Server will not fork when running in debugging mode.");
- close(listen_sock);
- sock_in = newsock;
- sock_out = newsock;
- pid = getpid();
- break;
- }
- else
- {
- /* Normal production daemon. Fork, and have the child process
- the connection. The parent continues listening. */
- if ((pid = fork()) == 0)
- {
- /* Child. Close the listening socket, and start using
- the accepted socket. Reinitialize logging (since our
- pid has changed). We break out of the loop to handle
- the connection. */
- close(listen_sock);
- sock_in = newsock;
- sock_out = newsock;
- log_init(av0, options.log_level, options.log_facility, log_stderr);
- break;
+ /* Do not displa