*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.273 2003/07/16 10:34:53 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.291 2004/05/09 01:19:28 djm Exp $");
#include <openssl/dh.h>
#include <openssl/bn.h>
#include "rsa.h"
#include "sshpty.h"
#include "packet.h"
-#include "mpaux.h"
#include "log.h"
#include "servconf.h"
#include "uidswap.h"
/* variables used for privilege separation */
int use_privsep;
-struct monitor *pmonitor;
+struct monitor *pmonitor = NULL;
/* message to be displayed after login */
Buffer loginmsg;
+/* global authentication context */
+Authctxt *the_authctxt = NULL;
+
/* Prototypes for various functions defined later in this file. */
void destroy_sensitive_data(void);
void demote_sensitive_data(void);
{
/* XXX no idea how fix this signal handler */
+ if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
+ kill(pmonitor->m_pid, SIGALRM);
+
/* Log error and exit. */
fatal("Timeout before authentication for %s", get_remote_ipaddr());
}
strlen(server_version_string))
!= strlen(server_version_string)) {
logit("Could not write ident string to %s", get_remote_ipaddr());
- fatal_cleanup();
+ cleanup_exit(255);
}
/* Read other sides version identification. */
if (atomicio(read, sock_in, &buf[i], 1) != 1) {
logit("Did not receive identification string from %s",
get_remote_ipaddr());
- fatal_cleanup();
+ cleanup_exit(255);
}
if (buf[i] == '\r') {
buf[i] = 0;
close(sock_out);
logit("Bad protocol version identification '%.100s' from %s",
client_version_string, get_remote_ipaddr());
- fatal_cleanup();
+ cleanup_exit(255);
}
debug("Client protocol version %d.%d; client software version %.100s",
remote_major, remote_minor, remote_version);
if (datafellows & SSH_BUG_PROBE) {
logit("probed from %s with %s. Don't panic.",
get_remote_ipaddr(), client_version_string);
- fatal_cleanup();
+ cleanup_exit(255);
}
if (datafellows & SSH_BUG_SCANNER) {
logit("scanned from %s with %s. Don't panic.",
get_remote_ipaddr(), client_version_string);
- fatal_cleanup();
+ cleanup_exit(255);
}
mismatch = 0;
logit("Protocol major versions differ for %s: %.200s vs. %.200s",
get_remote_ipaddr(),
server_version_string, client_version_string);
- fatal_cleanup();
+ cleanup_exit(255);
}
}
debug3("privsep user:group %u:%u", (u_int)pw->pw_uid,
(u_int)pw->pw_gid);
#if 0
- /* XXX not ready, to heavy after chroot */
+ /* XXX not ready, too heavy after chroot */
do_setusercontext(pw);
#else
gidset[0] = pw->pw_gid;
#endif
}
-static Authctxt *
-privsep_preauth(void)
+static int
+privsep_preauth(Authctxt *authctxt)
{
- Authctxt *authctxt = NULL;
int status;
pid_t pid;
if (pid == -1) {
fatal("fork of unprivileged child failed");
} else if (pid != 0) {
- fatal_remove_cleanup((void (*) (void *)) packet_close, NULL);
-
debug2("Network child is on pid %ld", (long)pid);
close(pmonitor->m_recvfd);
- authctxt = monitor_child_preauth(pmonitor);
+ pmonitor->m_pid = pid;
+ monitor_child_preauth(authctxt, pmonitor);
close(pmonitor->m_sendfd);
/* Sync memory */
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
-
- /* Reinstall, since the child has finished */
- fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
-
- return (authctxt);
+ return (1);
} else {
/* child */
privsep_preauth_child();
setproctitle("%s", "[net]");
}
- return (NULL);
+ return (0);
}
static void
privsep_postauth(Authctxt *authctxt)
{
- extern Authctxt *x_authctxt;
-
- /* XXX - Remote port forwarding */
- x_authctxt = authctxt;
-
#ifdef DISABLE_FD_PASSING
if (1) {
#else
if (pmonitor->m_pid == -1)
fatal("fork of unprivileged child failed");
else if (pmonitor->m_pid != 0) {
- fatal_remove_cleanup((void (*) (void *)) packet_close, NULL);
-
debug2("User child is on pid %ld", (long)pmonitor->m_pid);
close(pmonitor->m_recvfd);
monitor_child_postauth(pmonitor);
list_hostkey_types(void)
{
Buffer b;
- char *p;
+ const char *p;
+ char *ret;
int i;
buffer_init(&b);
}
}
buffer_append(&b, "\0", 1);
- p = xstrdup(buffer_ptr(&b));
+ ret = xstrdup(buffer_ptr(&b));
buffer_free(&b);
- debug("list_hostkey_types: %s", p);
- return p;
+ debug("list_hostkey_types: %s", ret);
+ return ret;
}
Key *
static void
usage(void)
{
- 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", _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, " -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");
- 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",
- _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");
- fprintf(stderr, " -o option Process the option as if it was read from a configuration file.\n");
+ fprintf(stderr, "%s, %s\n",
+ SSH_VERSION, 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"
+ );
exit(1);
}
FILE *f;
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+ char *line;
int listen_sock, maxfd;
int startup_p[2];
int startups = 0;
- Authctxt *authctxt;
Key *key;
+ Authctxt *authctxt;
int ret, key_used = 0;
#ifdef HAVE_SECUREWARE
(void)set_auth_parameters(ac, av);
#endif
- __progname = get_progname(av[0]);
+ __progname = ssh_get_progname(av[0]);
init_rng();
/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
av = saved_argv;
#endif
+ if (geteuid() == 0 && setgroups(0, NULL) == -1)
+ debug("setgroups(): %.200s", strerror(errno));
+
/* Initialize configuration options to their default values. */
initialize_server_options(&options);
}
break;
case 'o':
- if (process_server_config_line(&options, optarg,
+ line = xstrdup(optarg);
+ if (process_server_config_line(&options, line,
"command-line", 0) != 0)
exit(1);
+ xfree(line);
break;
case '?':
default:
SYSLOG_FACILITY_AUTH : options.log_facility,
log_stderr || !inetd_flag);
+#ifdef _AIX
+ /*
+ * Unset KRB5CCNAME, otherwise the user's session may inherit it from
+ * root's environment
+ */
+ unsetenv("KRB5CCNAME");
+#endif /* _AIX */
#ifdef _UNICOS
- /* Cray can define user privs drop all prives now!
+ /* Cray can define user privs drop all privs now!
* Not needed on PRIV_SU systems!
*/
drop_cray_privs();
/*
* Clear out any supplemental groups we may have inherited. This
* prevents inadvertent creation of files with bad modes (in the
- * portable version at least, it's certainly possible for PAM
- * to create a file, and we can't control the code in every
+ * portable version at least, it's certainly possible for PAM
+ * to create a file, and we can't control the code in every
* module which might be used).
*/
if (setgroups(0, NULL) < 0)
/* Start listening on the port. */
logit("Server listening on %s port %s.", ntop, strport);
- if (listen(listen_sock, 5) < 0)
+ if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
fatal("listen: %.100s", strerror(errno));
}
if ((options.protocol & SSH_PROTO_1) &&
key_used == 0) {
/* Schedule server key regeneration alarm. */
- mysignal(SIGALRM, key_regeneration_alarm);
+ signal(SIGALRM, key_regeneration_alarm);
alarm(options.key_regeneration_time);
key_used = 1;
}
}
/* This is the child processing a new connection. */
+ setproctitle("%s", "[accepted]");
/*
* Create a new session and process group since the 4.4BSD
signal(SIGCHLD, SIG_DFL);
signal(SIGINT, SIG_DFL);
- /* Set keepalives if requested. */
- if (options.keepalives &&
+ /* Set SO_KEEPALIVE if requested. */
+ if (options.tcp_keep_alive &&
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
* mode; it is just annoying to have the server exit just when you
* are about to discover the bug.
*/
- mysignal(SIGALRM, grace_alarm_handler);
+ signal(SIGALRM, grace_alarm_handler);
if (!debug_flag)
alarm(options.login_grace_time);
sshd_exchange_identification(sock_in, sock_out);
- /*
- * Check that the connection comes from a privileged port.
- * Rhosts-Authentication only makes sense from privileged
- * programs. Of course, if the intruder has root access on his local
- * machine, he can connect from any port. So do not use these
- * authentication methods from machines that you do not trust.
- */
- if (options.rhosts_authentication &&
- (remote_port >= IPPORT_RESERVED ||
- remote_port < IPPORT_RESERVED / 2)) {
- debug("Rhosts Authentication disabled, "
- "originating port %d not trusted.", remote_port);
- options.rhosts_authentication = 0;
- }
-#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 && !KRB5 */
-#ifdef AFS
- /* If machine has AFS, set process authentication group. */
- if (k_hasafs()) {
- k_setpag();
- k_unlog();
- }
-#endif /* AFS */
packet_set_nonblocking();
- /* prepare buffers to collect authentication messages */
+ /* prepare buffers to collect authentication messages */
buffer_init(&loginmsg);
+ /* allocate authentication context */
+ authctxt = xmalloc(sizeof(*authctxt));
+ memset(authctxt, 0, sizeof(*authctxt));
+
+ /* XXX global for cleanup, access from other modules */
+ the_authctxt = authctxt;
+
if (use_privsep)
- if ((authctxt = privsep_preauth()) != NULL)
+ if (privsep_preauth(authctxt) == 1)
goto authenticated;
/* perform the key exchange */
/* authenticate user and start session */
if (compat20) {
do_ssh2_kex();
- authctxt = do_authentication2();
+ do_authentication2(authctxt);
} else {
do_ssh1_kex();
- authctxt = do_authentication();
+ do_authentication(authctxt);
}
/*
* If we use privilege separation, the unprivileged child transfers
destroy_sensitive_data();
}
- /* Perform session preparation. */
+ /* Start session. */
do_authenticated(authctxt);
/* The connection has been terminated. */
/* Declare supported authentication types. */
auth_mask = 0;
- if (options.rhosts_authentication)
- auth_mask |= 1 << SSH_AUTH_RHOSTS;
if (options.rhosts_rsa_authentication)
auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
if (options.rsa_authentication)
auth_mask |= 1 << SSH_AUTH_RSA;
-#if defined(KRB4) || defined(KRB5)
- if (options.kerberos_authentication)
- auth_mask |= 1 << SSH_AUTH_KERBEROS;
-#endif
-#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_response_authentication == 1)
auth_mask |= 1 << SSH_AUTH_TIS;
if (options.password_authentication)
BN_bn2bin(session_key_int,
session_key + sizeof(session_key) - len);
- compute_session_id(session_id, cookie,
- sensitive_data.ssh1_host_key->rsa->n,
- sensitive_data.server_key->rsa->n);
+ derive_ssh1_session_id(
+ sensitive_data.ssh1_host_key->rsa->n,
+ sensitive_data.server_key->rsa->n,
+ cookie, session_id);
/*
* Xor the first 16 bytes of the session key with the
* session id.
#endif
debug("KEX done");
}
+
+/* server specific fatal cleanup */
+void
+cleanup_exit(int i)
+{
+ if (the_authctxt)
+ do_cleanup(the_authctxt);
+ _exit(i);
+}