xref: /openbsd-src/usr.bin/ssh/sshd-session.c (revision 874e263e8b77a176b69f45173418ce3fe8b8015f)
1*874e263eSdtucker /* $OpenBSD: sshd-session.c,v 1.11 2025/01/16 06:37:10 dtucker Exp $ */
271f11376Sdjm /*
371f11376Sdjm  * SSH2 implementation:
471f11376Sdjm  * Privilege Separation:
571f11376Sdjm  *
671f11376Sdjm  * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.
771f11376Sdjm  * Copyright (c) 2002 Niels Provos.  All rights reserved.
871f11376Sdjm  *
971f11376Sdjm  * Redistribution and use in source and binary forms, with or without
1071f11376Sdjm  * modification, are permitted provided that the following conditions
1171f11376Sdjm  * are met:
1271f11376Sdjm  * 1. Redistributions of source code must retain the above copyright
1371f11376Sdjm  *    notice, this list of conditions and the following disclaimer.
1471f11376Sdjm  * 2. Redistributions in binary form must reproduce the above copyright
1571f11376Sdjm  *    notice, this list of conditions and the following disclaimer in the
1671f11376Sdjm  *    documentation and/or other materials provided with the distribution.
1771f11376Sdjm  *
1871f11376Sdjm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1971f11376Sdjm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2071f11376Sdjm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2171f11376Sdjm  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2271f11376Sdjm  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2371f11376Sdjm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2471f11376Sdjm  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2571f11376Sdjm  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2671f11376Sdjm  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2771f11376Sdjm  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2871f11376Sdjm  */
2971f11376Sdjm 
3071f11376Sdjm #include <sys/types.h>
3171f11376Sdjm #include <sys/ioctl.h>
3271f11376Sdjm #include <sys/wait.h>
3371f11376Sdjm #include <sys/tree.h>
3471f11376Sdjm #include <sys/stat.h>
3571f11376Sdjm #include <sys/socket.h>
3671f11376Sdjm #include <sys/time.h>
3771f11376Sdjm #include <sys/queue.h>
3871f11376Sdjm 
3971f11376Sdjm #include <errno.h>
4071f11376Sdjm #include <fcntl.h>
4171f11376Sdjm #include <netdb.h>
4271f11376Sdjm #include <paths.h>
4371f11376Sdjm #include <pwd.h>
4471f11376Sdjm #include <signal.h>
4571f11376Sdjm #include <stdio.h>
4671f11376Sdjm #include <stdlib.h>
4771f11376Sdjm #include <string.h>
4871f11376Sdjm #include <stdarg.h>
4971f11376Sdjm #include <unistd.h>
5071f11376Sdjm #include <limits.h>
5171f11376Sdjm 
5271f11376Sdjm #ifdef WITH_OPENSSL
5371f11376Sdjm #include <openssl/bn.h>
5471f11376Sdjm #include <openssl/evp.h>
5571f11376Sdjm #endif
5671f11376Sdjm 
5771f11376Sdjm #include "xmalloc.h"
5871f11376Sdjm #include "ssh.h"
5971f11376Sdjm #include "ssh2.h"
6071f11376Sdjm #include "sshpty.h"
6171f11376Sdjm #include "packet.h"
6271f11376Sdjm #include "log.h"
6371f11376Sdjm #include "sshbuf.h"
6471f11376Sdjm #include "misc.h"
6571f11376Sdjm #include "match.h"
6671f11376Sdjm #include "servconf.h"
6771f11376Sdjm #include "uidswap.h"
6871f11376Sdjm #include "compat.h"
6971f11376Sdjm #include "cipher.h"
7071f11376Sdjm #include "digest.h"
7171f11376Sdjm #include "sshkey.h"
7271f11376Sdjm #include "kex.h"
7371f11376Sdjm #include "authfile.h"
7471f11376Sdjm #include "pathnames.h"
7571f11376Sdjm #include "atomicio.h"
7671f11376Sdjm #include "canohost.h"
7771f11376Sdjm #include "hostfile.h"
7871f11376Sdjm #include "auth.h"
7971f11376Sdjm #include "authfd.h"
8071f11376Sdjm #include "msg.h"
8171f11376Sdjm #include "dispatch.h"
8271f11376Sdjm #include "channels.h"
8371f11376Sdjm #include "session.h"
8471f11376Sdjm #include "monitor.h"
8571f11376Sdjm #ifdef GSSAPI
8671f11376Sdjm #include "ssh-gss.h"
8771f11376Sdjm #endif
8871f11376Sdjm #include "monitor_wrap.h"
8971f11376Sdjm #include "auth-options.h"
9071f11376Sdjm #include "version.h"
9171f11376Sdjm #include "ssherr.h"
9271f11376Sdjm #include "sk-api.h"
9371f11376Sdjm #include "srclimit.h"
9471f11376Sdjm #include "dh.h"
9571f11376Sdjm 
9671f11376Sdjm /* Re-exec fds */
9771f11376Sdjm #define REEXEC_DEVCRYPTO_RESERVED_FD	(STDERR_FILENO + 1)
9871f11376Sdjm #define REEXEC_STARTUP_PIPE_FD		(STDERR_FILENO + 2)
9971f11376Sdjm #define REEXEC_CONFIG_PASS_FD		(STDERR_FILENO + 3)
10071f11376Sdjm #define REEXEC_MIN_FREE_FD		(STDERR_FILENO + 4)
10171f11376Sdjm 
102856b6ee8Sdjm /* Privsep fds */
103856b6ee8Sdjm #define PRIVSEP_MONITOR_FD		(STDERR_FILENO + 1)
104856b6ee8Sdjm #define PRIVSEP_LOG_FD			(STDERR_FILENO + 2)
105856b6ee8Sdjm #define PRIVSEP_MIN_FREE_FD		(STDERR_FILENO + 3)
106856b6ee8Sdjm 
10771f11376Sdjm extern char *__progname;
10871f11376Sdjm 
10971f11376Sdjm /* Server configuration options. */
11071f11376Sdjm ServerOptions options;
11171f11376Sdjm 
11271f11376Sdjm /* Name of the server configuration file. */
11371f11376Sdjm char *config_file_name = _PATH_SERVER_CONFIG_FILE;
11471f11376Sdjm 
11571f11376Sdjm /*
11671f11376Sdjm  * Debug mode flag.  This can be set on the command line.  If debug
11771f11376Sdjm  * mode is enabled, extra debugging output will be sent to the system
11871f11376Sdjm  * log, the daemon will not go to background, and will exit after processing
11971f11376Sdjm  * the first connection.
12071f11376Sdjm  */
12171f11376Sdjm int debug_flag = 0;
12271f11376Sdjm 
12371f11376Sdjm /* Flag indicating that the daemon is being started from inetd. */
12471f11376Sdjm static int inetd_flag = 0;
12571f11376Sdjm 
12671f11376Sdjm /* debug goes to stderr unless inetd_flag is set */
12771f11376Sdjm static int log_stderr = 0;
12871f11376Sdjm 
12971f11376Sdjm /* Saved arguments to main(). */
13071f11376Sdjm static char **saved_argv;
13171f11376Sdjm 
13271f11376Sdjm /* Daemon's agent connection */
13371f11376Sdjm int auth_sock = -1;
13471f11376Sdjm static int have_agent = 0;
13571f11376Sdjm 
13671f11376Sdjm /*
13771f11376Sdjm  * Any really sensitive data in the application is contained in this
13871f11376Sdjm  * structure. The idea is that this structure could be locked into memory so
13971f11376Sdjm  * that the pages do not get written into swap.  However, there are some
14071f11376Sdjm  * problems. The private key contains BIGNUMs, and we do not (in principle)
14171f11376Sdjm  * have access to the internals of them, and locking just the structure is
14271f11376Sdjm  * not very useful.  Currently, memory locking is not implemented.
14371f11376Sdjm  */
14471f11376Sdjm struct {
14571f11376Sdjm 	u_int		num_hostkeys;
14671f11376Sdjm 	struct sshkey	**host_keys;		/* all private host keys */
14771f11376Sdjm 	struct sshkey	**host_pubkeys;		/* all public host keys */
14871f11376Sdjm 	struct sshkey	**host_certificates;	/* all public host certificates */
14971f11376Sdjm } sensitive_data;
15071f11376Sdjm 
15171f11376Sdjm /* record remote hostname or ip */
15271f11376Sdjm u_int utmp_len = HOST_NAME_MAX+1;
15371f11376Sdjm 
15471f11376Sdjm static int startup_pipe = -1;		/* in child */
15571f11376Sdjm 
15671f11376Sdjm /* variables used for privilege separation */
15771f11376Sdjm struct monitor *pmonitor = NULL;
15871f11376Sdjm int privsep_is_preauth = 1;
15971f11376Sdjm 
16071f11376Sdjm /* global connection state and authentication contexts */
16171f11376Sdjm Authctxt *the_authctxt = NULL;
16271f11376Sdjm struct ssh *the_active_state;
16371f11376Sdjm 
16471f11376Sdjm /* global key/cert auth options. XXX move to permanent ssh->authctxt? */
16571f11376Sdjm struct sshauthopt *auth_opts = NULL;
16671f11376Sdjm 
16771f11376Sdjm /* sshd_config buffer */
16871f11376Sdjm struct sshbuf *cfg;
16971f11376Sdjm 
17071f11376Sdjm /* Included files from the configuration file */
17171f11376Sdjm struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
17271f11376Sdjm 
17371f11376Sdjm /* message to be displayed after login */
17471f11376Sdjm struct sshbuf *loginmsg;
17571f11376Sdjm 
17671f11376Sdjm /* Prototypes for various functions defined later in this file. */
17771f11376Sdjm void destroy_sensitive_data(void);
17871f11376Sdjm void demote_sensitive_data(void);
179856b6ee8Sdjm 
180856b6ee8Sdjm /* XXX reduce to stub once postauth split */
181856b6ee8Sdjm int
182856b6ee8Sdjm mm_is_monitor(void)
183856b6ee8Sdjm {
184856b6ee8Sdjm 	/*
185856b6ee8Sdjm 	 * m_pid is only set in the privileged part, and
186856b6ee8Sdjm 	 * points to the unprivileged child.
187856b6ee8Sdjm 	 */
188856b6ee8Sdjm 	return (pmonitor && pmonitor->m_pid > 0);
189856b6ee8Sdjm }
19071f11376Sdjm 
19171f11376Sdjm /*
19271f11376Sdjm  * Signal handler for the alarm after the login grace period has expired.
193bdb58b7fSderaadt  * As usual, this may only take signal-safe actions, even though it is
194bdb58b7fSderaadt  * terminal.
19571f11376Sdjm  */
19671f11376Sdjm static void
19771f11376Sdjm grace_alarm_handler(int sig)
19871f11376Sdjm {
19971f11376Sdjm 	/*
20071f11376Sdjm 	 * Try to kill any processes that we have spawned, E.g. authorized
20171f11376Sdjm 	 * keys command helpers or privsep children.
20271f11376Sdjm 	 */
20371f11376Sdjm 	if (getpgid(0) == getpid()) {
204bdb58b7fSderaadt 		struct sigaction sa;
205bdb58b7fSderaadt 
206bdb58b7fSderaadt 		/* mask all other signals while in handler */
207bdb58b7fSderaadt 		memset(&sa, 0, sizeof(sa));
208bdb58b7fSderaadt 		sa.sa_handler = SIG_IGN;
209bdb58b7fSderaadt 		sigfillset(&sa.sa_mask);
210bdb58b7fSderaadt 		sa.sa_flags = SA_RESTART;
211bdb58b7fSderaadt 		(void)sigaction(SIGTERM, &sa, NULL);
21271f11376Sdjm 		kill(0, SIGTERM);
21371f11376Sdjm 	}
2147965d983Sdjm 	_exit(EXIT_LOGIN_GRACE);
21571f11376Sdjm }
21671f11376Sdjm 
21771f11376Sdjm /* Destroy the host and server keys.  They will no longer be needed. */
21871f11376Sdjm void
21971f11376Sdjm destroy_sensitive_data(void)
22071f11376Sdjm {
22171f11376Sdjm 	u_int i;
22271f11376Sdjm 
22371f11376Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
22471f11376Sdjm 		if (sensitive_data.host_keys[i]) {
22571f11376Sdjm 			sshkey_free(sensitive_data.host_keys[i]);
22671f11376Sdjm 			sensitive_data.host_keys[i] = NULL;
22771f11376Sdjm 		}
22871f11376Sdjm 		if (sensitive_data.host_certificates[i]) {
22971f11376Sdjm 			sshkey_free(sensitive_data.host_certificates[i]);
23071f11376Sdjm 			sensitive_data.host_certificates[i] = NULL;
23171f11376Sdjm 		}
23271f11376Sdjm 	}
23371f11376Sdjm }
23471f11376Sdjm 
23571f11376Sdjm /* Demote private to public keys for network child */
23671f11376Sdjm void
23771f11376Sdjm demote_sensitive_data(void)
23871f11376Sdjm {
23971f11376Sdjm 	struct sshkey *tmp;
24071f11376Sdjm 	u_int i;
24171f11376Sdjm 	int r;
24271f11376Sdjm 
24371f11376Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
24471f11376Sdjm 		if (sensitive_data.host_keys[i]) {
24571f11376Sdjm 			if ((r = sshkey_from_private(
24671f11376Sdjm 			    sensitive_data.host_keys[i], &tmp)) != 0)
24771f11376Sdjm 				fatal_r(r, "could not demote host %s key",
24871f11376Sdjm 				    sshkey_type(sensitive_data.host_keys[i]));
24971f11376Sdjm 			sshkey_free(sensitive_data.host_keys[i]);
25071f11376Sdjm 			sensitive_data.host_keys[i] = tmp;
25171f11376Sdjm 		}
25271f11376Sdjm 		/* Certs do not need demotion */
25371f11376Sdjm 	}
25471f11376Sdjm }
25571f11376Sdjm 
256856b6ee8Sdjm struct sshbuf *
257856b6ee8Sdjm pack_hostkeys(void)
25871f11376Sdjm {
259856b6ee8Sdjm 	struct sshbuf *keybuf = NULL, *hostkeys = NULL;
260856b6ee8Sdjm 	int r;
261856b6ee8Sdjm 	u_int i;
26271f11376Sdjm 
263856b6ee8Sdjm 	if ((hostkeys = sshbuf_new()) == NULL)
264856b6ee8Sdjm 		fatal_f("sshbuf_new failed");
26571f11376Sdjm 
266856b6ee8Sdjm 	/* pack hostkeys into a string. Empty key slots get empty strings */
267856b6ee8Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
268856b6ee8Sdjm 		/* public key */
269856b6ee8Sdjm 		if (sensitive_data.host_pubkeys[i] != NULL) {
270856b6ee8Sdjm 			if ((r = sshkey_puts(sensitive_data.host_pubkeys[i],
271856b6ee8Sdjm 			    hostkeys)) != 0)
272856b6ee8Sdjm 				fatal_fr(r, "compose hostkey public");
273856b6ee8Sdjm 		} else {
274856b6ee8Sdjm 			if ((r = sshbuf_put_string(hostkeys, NULL, 0)) != 0)
275856b6ee8Sdjm 				fatal_fr(r, "compose hostkey empty public");
27671f11376Sdjm 		}
277856b6ee8Sdjm 		/* cert */
278856b6ee8Sdjm 		if (sensitive_data.host_certificates[i] != NULL) {
279856b6ee8Sdjm 			if ((r = sshkey_puts(
280856b6ee8Sdjm 			    sensitive_data.host_certificates[i],
281856b6ee8Sdjm 			    hostkeys)) != 0)
282856b6ee8Sdjm 				fatal_fr(r, "compose host cert");
283856b6ee8Sdjm 		} else {
284856b6ee8Sdjm 			if ((r = sshbuf_put_string(hostkeys, NULL, 0)) != 0)
285856b6ee8Sdjm 				fatal_fr(r, "compose host cert empty");
286856b6ee8Sdjm 		}
287856b6ee8Sdjm 	}
288856b6ee8Sdjm 
289856b6ee8Sdjm 	sshbuf_free(keybuf);
290856b6ee8Sdjm 	return hostkeys;
29171f11376Sdjm }
29271f11376Sdjm 
29371f11376Sdjm static int
29471f11376Sdjm privsep_preauth(struct ssh *ssh)
29571f11376Sdjm {
29671f11376Sdjm 	int status, r;
29771f11376Sdjm 	pid_t pid;
29871f11376Sdjm 
29971f11376Sdjm 	/* Set up unprivileged child process to deal with network data */
30071f11376Sdjm 	pmonitor = monitor_init();
30171f11376Sdjm 	/* Store a pointer to the kex for later rekeying */
30271f11376Sdjm 	pmonitor->m_pkex = &ssh->kex;
30371f11376Sdjm 
304856b6ee8Sdjm 	if ((pid = fork()) == -1)
30571f11376Sdjm 		fatal("fork of unprivileged child failed");
306856b6ee8Sdjm 	else if (pid != 0) {
30771f11376Sdjm 		debug2("Network child is on pid %ld", (long)pid);
30871f11376Sdjm 		pmonitor->m_pid = pid;
30971f11376Sdjm 		if (have_agent) {
31071f11376Sdjm 			r = ssh_get_authentication_socket(&auth_sock);
31171f11376Sdjm 			if (r != 0) {
31271f11376Sdjm 				error_r(r, "Could not get agent socket");
31371f11376Sdjm 				have_agent = 0;
31471f11376Sdjm 			}
31571f11376Sdjm 		}
31671f11376Sdjm 		monitor_child_preauth(ssh, pmonitor);
31771f11376Sdjm 
31871f11376Sdjm 		/* Wait for the child's exit status */
31971f11376Sdjm 		while (waitpid(pid, &status, 0) == -1) {
32071f11376Sdjm 			if (errno == EINTR)
32171f11376Sdjm 				continue;
32271f11376Sdjm 			pmonitor->m_pid = -1;
32371f11376Sdjm 			fatal_f("waitpid: %s", strerror(errno));
32471f11376Sdjm 		}
32571f11376Sdjm 		privsep_is_preauth = 0;
32671f11376Sdjm 		pmonitor->m_pid = -1;
32771f11376Sdjm 		if (WIFEXITED(status)) {
32871f11376Sdjm 			if (WEXITSTATUS(status) != 0)
32971f11376Sdjm 				fatal_f("preauth child exited with status %d",
33071f11376Sdjm 				    WEXITSTATUS(status));
33171f11376Sdjm 		} else if (WIFSIGNALED(status))
33271f11376Sdjm 			fatal_f("preauth child terminated by signal %d",
33371f11376Sdjm 			    WTERMSIG(status));
33471f11376Sdjm 		return 1;
33571f11376Sdjm 	} else {
33671f11376Sdjm 		/* child */
33771f11376Sdjm 		close(pmonitor->m_sendfd);
33871f11376Sdjm 		close(pmonitor->m_log_recvfd);
33971f11376Sdjm 
340856b6ee8Sdjm 		/*
341856b6ee8Sdjm 		 * Arrange unpriv-preauth child process fds:
342856b6ee8Sdjm 		 * 0, 1 network socket
343856b6ee8Sdjm 		 * 2 optional stderr
344856b6ee8Sdjm 		 * 3 reserved
345856b6ee8Sdjm 		 * 4 monitor message socket
346856b6ee8Sdjm 		 * 5 monitor logging socket
347856b6ee8Sdjm 		 *
348856b6ee8Sdjm 		 * We know that the monitor sockets will have fds > 4 because
349856b6ee8Sdjm 		 * of the reserved fds in main()
350856b6ee8Sdjm 		 */
35171f11376Sdjm 
352856b6ee8Sdjm 		if (ssh_packet_get_connection_in(ssh) != STDIN_FILENO &&
353856b6ee8Sdjm 		    dup2(ssh_packet_get_connection_in(ssh), STDIN_FILENO) == -1)
354856b6ee8Sdjm 			fatal("dup2 stdin failed: %s", strerror(errno));
355856b6ee8Sdjm 		if (ssh_packet_get_connection_out(ssh) != STDOUT_FILENO &&
356856b6ee8Sdjm 		    dup2(ssh_packet_get_connection_out(ssh),
357856b6ee8Sdjm 		    STDOUT_FILENO) == -1)
358856b6ee8Sdjm 			fatal("dup2 stdout failed: %s", strerror(errno));
359856b6ee8Sdjm 		/* leave stderr as-is */
360856b6ee8Sdjm 		log_redirect_stderr_to(NULL); /* dup can clobber log fd */
361856b6ee8Sdjm 		if (pmonitor->m_recvfd != PRIVSEP_MONITOR_FD &&
362856b6ee8Sdjm 		    dup2(pmonitor->m_recvfd, PRIVSEP_MONITOR_FD) == -1)
363856b6ee8Sdjm 			fatal("dup2 monitor fd: %s", strerror(errno));
364856b6ee8Sdjm 		if (pmonitor->m_log_sendfd != PRIVSEP_LOG_FD &&
365856b6ee8Sdjm 		    dup2(pmonitor->m_log_sendfd, PRIVSEP_LOG_FD) == -1)
366856b6ee8Sdjm 			fatal("dup2 log fd: %s", strerror(errno));
367856b6ee8Sdjm 		closefrom(PRIVSEP_MIN_FREE_FD);
36871f11376Sdjm 
369856b6ee8Sdjm 		saved_argv[0] = options.sshd_auth_path;
370856b6ee8Sdjm 		execv(options.sshd_auth_path, saved_argv);
371856b6ee8Sdjm 
372856b6ee8Sdjm 		fatal_f("exec of %s failed: %s",
373856b6ee8Sdjm 		    options.sshd_auth_path, strerror(errno));
37471f11376Sdjm 	}
37571f11376Sdjm }
37671f11376Sdjm 
37771f11376Sdjm static void
37871f11376Sdjm privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
37971f11376Sdjm {
38071f11376Sdjm 	/* New socket pair */
38171f11376Sdjm 	monitor_reinit(pmonitor);
38271f11376Sdjm 
38371f11376Sdjm 	pmonitor->m_pid = fork();
38471f11376Sdjm 	if (pmonitor->m_pid == -1)
38571f11376Sdjm 		fatal("fork of unprivileged child failed");
38671f11376Sdjm 	else if (pmonitor->m_pid != 0) {
38771f11376Sdjm 		verbose("User child is on pid %ld", (long)pmonitor->m_pid);
38871f11376Sdjm 		sshbuf_reset(loginmsg);
38971f11376Sdjm 		monitor_clear_keystate(ssh, pmonitor);
39071f11376Sdjm 		monitor_child_postauth(ssh, pmonitor);
39171f11376Sdjm 
39271f11376Sdjm 		/* NEVERREACHED */
39371f11376Sdjm 		exit(0);
39471f11376Sdjm 	}
39571f11376Sdjm 
39671f11376Sdjm 	/* child */
39771f11376Sdjm 
39871f11376Sdjm 	close(pmonitor->m_sendfd);
39971f11376Sdjm 	pmonitor->m_sendfd = -1;
40071f11376Sdjm 
40171f11376Sdjm 	/* Demote the private keys to public keys. */
40271f11376Sdjm 	demote_sensitive_data();
40371f11376Sdjm 
40471f11376Sdjm 	/* Drop privileges */
40571f11376Sdjm 	do_setusercontext(authctxt->pw);
40671f11376Sdjm 
40771f11376Sdjm 	/* It is safe now to apply the key state */
40871f11376Sdjm 	monitor_apply_keystate(ssh, pmonitor);
40971f11376Sdjm 
41071f11376Sdjm 	/*
41171f11376Sdjm 	 * Tell the packet layer that authentication was successful, since
41271f11376Sdjm 	 * this information is not part of the key state.
41371f11376Sdjm 	 */
41471f11376Sdjm 	ssh_packet_set_authenticated(ssh);
41571f11376Sdjm }
41671f11376Sdjm 
41771f11376Sdjm static struct sshkey *
41871f11376Sdjm get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
41971f11376Sdjm {
42071f11376Sdjm 	u_int i;
42171f11376Sdjm 	struct sshkey *key;
42271f11376Sdjm 
42371f11376Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
42471f11376Sdjm 		switch (type) {
42571f11376Sdjm 		case KEY_RSA_CERT:
42671f11376Sdjm 		case KEY_DSA_CERT:
42771f11376Sdjm 		case KEY_ECDSA_CERT:
42871f11376Sdjm 		case KEY_ED25519_CERT:
42971f11376Sdjm 		case KEY_ECDSA_SK_CERT:
43071f11376Sdjm 		case KEY_ED25519_SK_CERT:
43171f11376Sdjm 		case KEY_XMSS_CERT:
43271f11376Sdjm 			key = sensitive_data.host_certificates[i];
43371f11376Sdjm 			break;
43471f11376Sdjm 		default:
43571f11376Sdjm 			key = sensitive_data.host_keys[i];
43671f11376Sdjm 			if (key == NULL && !need_private)
43771f11376Sdjm 				key = sensitive_data.host_pubkeys[i];
43871f11376Sdjm 			break;
43971f11376Sdjm 		}
44071f11376Sdjm 		if (key == NULL || key->type != type)
44171f11376Sdjm 			continue;
44271f11376Sdjm 		switch (type) {
44371f11376Sdjm 		case KEY_ECDSA:
44471f11376Sdjm 		case KEY_ECDSA_SK:
44571f11376Sdjm 		case KEY_ECDSA_CERT:
44671f11376Sdjm 		case KEY_ECDSA_SK_CERT:
44771f11376Sdjm 			if (key->ecdsa_nid != nid)
44871f11376Sdjm 				continue;
44971f11376Sdjm 			/* FALLTHROUGH */
45071f11376Sdjm 		default:
45171f11376Sdjm 			return need_private ?
45271f11376Sdjm 			    sensitive_data.host_keys[i] : key;
45371f11376Sdjm 		}
45471f11376Sdjm 	}
45571f11376Sdjm 	return NULL;
45671f11376Sdjm }
45771f11376Sdjm 
45871f11376Sdjm struct sshkey *
45971f11376Sdjm get_hostkey_public_by_type(int type, int nid, struct ssh *ssh)
46071f11376Sdjm {
46171f11376Sdjm 	return get_hostkey_by_type(type, nid, 0, ssh);
46271f11376Sdjm }
46371f11376Sdjm 
46471f11376Sdjm struct sshkey *
46571f11376Sdjm get_hostkey_private_by_type(int type, int nid, struct ssh *ssh)
46671f11376Sdjm {
46771f11376Sdjm 	return get_hostkey_by_type(type, nid, 1, ssh);
46871f11376Sdjm }
46971f11376Sdjm 
47071f11376Sdjm struct sshkey *
47171f11376Sdjm get_hostkey_by_index(int ind)
47271f11376Sdjm {
47371f11376Sdjm 	if (ind < 0 || (u_int)ind >= options.num_host_key_files)
47471f11376Sdjm 		return (NULL);
47571f11376Sdjm 	return (sensitive_data.host_keys[ind]);
47671f11376Sdjm }
47771f11376Sdjm 
47871f11376Sdjm struct sshkey *
47971f11376Sdjm get_hostkey_public_by_index(int ind, struct ssh *ssh)
48071f11376Sdjm {
48171f11376Sdjm 	if (ind < 0 || (u_int)ind >= options.num_host_key_files)
48271f11376Sdjm 		return (NULL);
48371f11376Sdjm 	return (sensitive_data.host_pubkeys[ind]);
48471f11376Sdjm }
48571f11376Sdjm 
48671f11376Sdjm int
48771f11376Sdjm get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh)
48871f11376Sdjm {
48971f11376Sdjm 	u_int i;
49071f11376Sdjm 
49171f11376Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
49271f11376Sdjm 		if (sshkey_is_cert(key)) {
49371f11376Sdjm 			if (key == sensitive_data.host_certificates[i] ||
49471f11376Sdjm 			    (compare && sensitive_data.host_certificates[i] &&
49571f11376Sdjm 			    sshkey_equal(key,
49671f11376Sdjm 			    sensitive_data.host_certificates[i])))
49771f11376Sdjm 				return (i);
49871f11376Sdjm 		} else {
49971f11376Sdjm 			if (key == sensitive_data.host_keys[i] ||
50071f11376Sdjm 			    (compare && sensitive_data.host_keys[i] &&
50171f11376Sdjm 			    sshkey_equal(key, sensitive_data.host_keys[i])))
50271f11376Sdjm 				return (i);
50371f11376Sdjm 			if (key == sensitive_data.host_pubkeys[i] ||
50471f11376Sdjm 			    (compare && sensitive_data.host_pubkeys[i] &&
50571f11376Sdjm 			    sshkey_equal(key, sensitive_data.host_pubkeys[i])))
50671f11376Sdjm 				return (i);
50771f11376Sdjm 		}
50871f11376Sdjm 	}
50971f11376Sdjm 	return (-1);
51071f11376Sdjm }
51171f11376Sdjm 
51271f11376Sdjm /* Inform the client of all hostkeys */
51371f11376Sdjm static void
51471f11376Sdjm notify_hostkeys(struct ssh *ssh)
51571f11376Sdjm {
51671f11376Sdjm 	struct sshbuf *buf;
51771f11376Sdjm 	struct sshkey *key;
51871f11376Sdjm 	u_int i, nkeys;
51971f11376Sdjm 	int r;
52071f11376Sdjm 	char *fp;
52171f11376Sdjm 
52271f11376Sdjm 	/* Some clients cannot cope with the hostkeys message, skip those. */
52371f11376Sdjm 	if (ssh->compat & SSH_BUG_HOSTKEYS)
52471f11376Sdjm 		return;
52571f11376Sdjm 
52671f11376Sdjm 	if ((buf = sshbuf_new()) == NULL)
52771f11376Sdjm 		fatal_f("sshbuf_new");
52871f11376Sdjm 	for (i = nkeys = 0; i < options.num_host_key_files; i++) {
52971f11376Sdjm 		key = get_hostkey_public_by_index(i, ssh);
53071f11376Sdjm 		if (key == NULL || key->type == KEY_UNSPEC ||
53171f11376Sdjm 		    sshkey_is_cert(key))
53271f11376Sdjm 			continue;
53371f11376Sdjm 		fp = sshkey_fingerprint(key, options.fingerprint_hash,
53471f11376Sdjm 		    SSH_FP_DEFAULT);
53571f11376Sdjm 		debug3_f("key %d: %s %s", i, sshkey_ssh_name(key), fp);
53671f11376Sdjm 		free(fp);
53771f11376Sdjm 		if (nkeys == 0) {
53871f11376Sdjm 			/*
53971f11376Sdjm 			 * Start building the request when we find the
54071f11376Sdjm 			 * first usable key.
54171f11376Sdjm 			 */
54271f11376Sdjm 			if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
54371f11376Sdjm 			    (r = sshpkt_put_cstring(ssh, "hostkeys-00@openssh.com")) != 0 ||
54471f11376Sdjm 			    (r = sshpkt_put_u8(ssh, 0)) != 0) /* want reply */
54571f11376Sdjm 				sshpkt_fatal(ssh, r, "%s: start request", __func__);
54671f11376Sdjm 		}
54771f11376Sdjm 		/* Append the key to the request */
54871f11376Sdjm 		sshbuf_reset(buf);
54971f11376Sdjm 		if ((r = sshkey_putb(key, buf)) != 0)
55071f11376Sdjm 			fatal_fr(r, "couldn't put hostkey %d", i);
55171f11376Sdjm 		if ((r = sshpkt_put_stringb(ssh, buf)) != 0)
55271f11376Sdjm 			sshpkt_fatal(ssh, r, "%s: append key", __func__);
55371f11376Sdjm 		nkeys++;
55471f11376Sdjm 	}
55571f11376Sdjm 	debug3_f("sent %u hostkeys", nkeys);
55671f11376Sdjm 	if (nkeys == 0)
55771f11376Sdjm 		fatal_f("no hostkeys");
55871f11376Sdjm 	if ((r = sshpkt_send(ssh)) != 0)
55971f11376Sdjm 		sshpkt_fatal(ssh, r, "%s: send", __func__);
56071f11376Sdjm 	sshbuf_free(buf);
56171f11376Sdjm }
56271f11376Sdjm 
56371f11376Sdjm static void
56471f11376Sdjm usage(void)
56571f11376Sdjm {
56671f11376Sdjm 	fprintf(stderr, "%s, %s\n", SSH_VERSION, SSH_OPENSSL_VERSION);
56771f11376Sdjm 	fprintf(stderr,
56871f11376Sdjm "usage: sshd [-46DdeGiqTtV] [-C connection_spec] [-c host_cert_file]\n"
56971f11376Sdjm "            [-E log_file] [-f config_file] [-g login_grace_time]\n"
57071f11376Sdjm "            [-h host_key_file] [-o option] [-p port] [-u len]\n"
57171f11376Sdjm 	);
57271f11376Sdjm 	exit(1);
57371f11376Sdjm }
57471f11376Sdjm 
57571f11376Sdjm static void
57671f11376Sdjm parse_hostkeys(struct sshbuf *hostkeys)
57771f11376Sdjm {
57871f11376Sdjm 	int r;
57971f11376Sdjm 	u_int num_keys = 0;
58071f11376Sdjm 	struct sshkey *k;
58171f11376Sdjm 	struct sshbuf *kbuf;
58271f11376Sdjm 	const u_char *cp;
58371f11376Sdjm 	size_t len;
58471f11376Sdjm 
58571f11376Sdjm 	while (sshbuf_len(hostkeys) != 0) {
58671f11376Sdjm 		if (num_keys > 2048)
58771f11376Sdjm 			fatal_f("too many hostkeys");
58871f11376Sdjm 		sensitive_data.host_keys = xrecallocarray(
58971f11376Sdjm 		    sensitive_data.host_keys, num_keys, num_keys + 1,
59071f11376Sdjm 		    sizeof(*sensitive_data.host_pubkeys));
59171f11376Sdjm 		sensitive_data.host_pubkeys = xrecallocarray(
59271f11376Sdjm 		    sensitive_data.host_pubkeys, num_keys, num_keys + 1,
59371f11376Sdjm 		    sizeof(*sensitive_data.host_pubkeys));
59471f11376Sdjm 		sensitive_data.host_certificates = xrecallocarray(
59571f11376Sdjm 		    sensitive_data.host_certificates, num_keys, num_keys + 1,
59671f11376Sdjm 		    sizeof(*sensitive_data.host_certificates));
59771f11376Sdjm 		/* private key */
59871f11376Sdjm 		k = NULL;
59971f11376Sdjm 		if ((r = sshbuf_froms(hostkeys, &kbuf)) != 0)
60071f11376Sdjm 			fatal_fr(r, "extract privkey");
60171f11376Sdjm 		if (sshbuf_len(kbuf) != 0 &&
60271f11376Sdjm 		    (r = sshkey_private_deserialize(kbuf, &k)) != 0)
60371f11376Sdjm 			fatal_fr(r, "parse pubkey");
60471f11376Sdjm 		sensitive_data.host_keys[num_keys] = k;
60571f11376Sdjm 		sshbuf_free(kbuf);
60671f11376Sdjm 		if (k)
60771f11376Sdjm 			debug2_f("privkey %u: %s", num_keys, sshkey_ssh_name(k));
60871f11376Sdjm 		/* public key */
60971f11376Sdjm 		k = NULL;
61071f11376Sdjm 		if ((r = sshbuf_get_string_direct(hostkeys, &cp, &len)) != 0)
61171f11376Sdjm 			fatal_fr(r, "extract pubkey");
61271f11376Sdjm 		if (len != 0 && (r = sshkey_from_blob(cp, len, &k)) != 0)
61371f11376Sdjm 			fatal_fr(r, "parse pubkey");
61471f11376Sdjm 		sensitive_data.host_pubkeys[num_keys] = k;
61571f11376Sdjm 		if (k)
61671f11376Sdjm 			debug2_f("pubkey %u: %s", num_keys, sshkey_ssh_name(k));
61771f11376Sdjm 		/* certificate */
61871f11376Sdjm 		k = NULL;
61971f11376Sdjm 		if ((r = sshbuf_get_string_direct(hostkeys, &cp, &len)) != 0)
62071f11376Sdjm 			fatal_fr(r, "extract pubkey");
62171f11376Sdjm 		if (len != 0 && (r = sshkey_from_blob(cp, len, &k)) != 0)
62271f11376Sdjm 			fatal_fr(r, "parse pubkey");
62371f11376Sdjm 		sensitive_data.host_certificates[num_keys] = k;
62471f11376Sdjm 		if (k)
62571f11376Sdjm 			debug2_f("cert %u: %s", num_keys, sshkey_ssh_name(k));
62671f11376Sdjm 		num_keys++;
62771f11376Sdjm 	}
62871f11376Sdjm 	sensitive_data.num_hostkeys = num_keys;
62971f11376Sdjm }
63071f11376Sdjm 
63171f11376Sdjm static void
63271f11376Sdjm recv_rexec_state(int fd, struct sshbuf *conf, uint64_t *timing_secretp)
63371f11376Sdjm {
63471f11376Sdjm 	struct sshbuf *m, *inc, *hostkeys;
63571f11376Sdjm 	u_char *cp, ver;
63671f11376Sdjm 	size_t len;
63771f11376Sdjm 	int r;
63871f11376Sdjm 	struct include_item *item;
63971f11376Sdjm 
64071f11376Sdjm 	debug3_f("entering fd = %d", fd);
64171f11376Sdjm 
64271f11376Sdjm 	if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
64371f11376Sdjm 		fatal_f("sshbuf_new failed");
64471f11376Sdjm 	if (ssh_msg_recv(fd, m) == -1)
64571f11376Sdjm 		fatal_f("ssh_msg_recv failed");
64671f11376Sdjm 	if ((r = sshbuf_get_u8(m, &ver)) != 0)
64771f11376Sdjm 		fatal_fr(r, "parse version");
64871f11376Sdjm 	if (ver != 0)
64971f11376Sdjm 		fatal_f("rexec version mismatch");
65071f11376Sdjm 	if ((r = sshbuf_get_string(m, &cp, &len)) != 0 || /* XXX _direct */
65171f11376Sdjm 	    (r = sshbuf_get_u64(m, timing_secretp)) != 0 ||
65271f11376Sdjm 	    (r = sshbuf_froms(m, &hostkeys)) != 0 ||
65371f11376Sdjm 	    (r = sshbuf_get_stringb(m, inc)) != 0)
65471f11376Sdjm 		fatal_fr(r, "parse config");
65571f11376Sdjm 
65671f11376Sdjm 	if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
65771f11376Sdjm 		fatal_fr(r, "sshbuf_put");
65871f11376Sdjm 
65971f11376Sdjm 	while (sshbuf_len(inc) != 0) {
66071f11376Sdjm 		item = xcalloc(1, sizeof(*item));
66171f11376Sdjm 		if ((item->contents = sshbuf_new()) == NULL)
66271f11376Sdjm 			fatal_f("sshbuf_new failed");
66371f11376Sdjm 		if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 ||
66471f11376Sdjm 		    (r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 ||
66571f11376Sdjm 		    (r = sshbuf_get_stringb(inc, item->contents)) != 0)
66671f11376Sdjm 			fatal_fr(r, "parse includes");
66771f11376Sdjm 		TAILQ_INSERT_TAIL(&includes, item, entry);
66871f11376Sdjm 	}
66971f11376Sdjm 
67071f11376Sdjm 	parse_hostkeys(hostkeys);
67171f11376Sdjm 
67271f11376Sdjm 	free(cp);
67371f11376Sdjm 	sshbuf_free(m);
67471f11376Sdjm 	sshbuf_free(hostkeys);
67571f11376Sdjm 	sshbuf_free(inc);
67671f11376Sdjm 
67771f11376Sdjm 	debug3_f("done");
67871f11376Sdjm }
67971f11376Sdjm 
68071f11376Sdjm /*
68171f11376Sdjm  * If IP options are supported, make sure there are none (log and
68271f11376Sdjm  * return an error if any are found).  Basically we are worried about
68371f11376Sdjm  * source routing; it can be used to pretend you are somebody
68471f11376Sdjm  * (ip-address) you are not. That itself may be "almost acceptable"
68571f11376Sdjm  * under certain circumstances, but rhosts authentication is useless
68671f11376Sdjm  * if source routing is accepted. Notice also that if we just dropped
68771f11376Sdjm  * source routing here, the other side could use IP spoofing to do
68871f11376Sdjm  * rest of the interaction and could still bypass security.  So we
68971f11376Sdjm  * exit here if we detect any IP options.
69071f11376Sdjm  */
69171f11376Sdjm static void
69271f11376Sdjm check_ip_options(struct ssh *ssh)
69371f11376Sdjm {
69471f11376Sdjm 	int sock_in = ssh_packet_get_connection_in(ssh);
69571f11376Sdjm 	struct sockaddr_storage from;
69671f11376Sdjm 	u_char opts[200];
69771f11376Sdjm 	socklen_t i, option_size = sizeof(opts), fromlen = sizeof(from);
69871f11376Sdjm 	char text[sizeof(opts) * 3 + 1];
69971f11376Sdjm 
70071f11376Sdjm 	memset(&from, 0, sizeof(from));
70171f11376Sdjm 	if (getpeername(sock_in, (struct sockaddr *)&from,
70271f11376Sdjm 	    &fromlen) == -1)
70371f11376Sdjm 		return;
70471f11376Sdjm 	if (from.ss_family != AF_INET)
70571f11376Sdjm 		return;
70671f11376Sdjm 	/* XXX IPv6 options? */
70771f11376Sdjm 
70871f11376Sdjm 	if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts,
70971f11376Sdjm 	    &option_size) >= 0 && option_size != 0) {
71071f11376Sdjm 		text[0] = '\0';
71171f11376Sdjm 		for (i = 0; i < option_size; i++)
71271f11376Sdjm 			snprintf(text + i*3, sizeof(text) - i*3,
71371f11376Sdjm 			    " %2.2x", opts[i]);
71471f11376Sdjm 		fatal("Connection from %.100s port %d with IP opts: %.800s",
71571f11376Sdjm 		    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text);
71671f11376Sdjm 	}
71771f11376Sdjm }
71871f11376Sdjm 
71971f11376Sdjm /* Set the routing domain for this process */
72071f11376Sdjm static void
72171f11376Sdjm set_process_rdomain(struct ssh *ssh, const char *name)
72271f11376Sdjm {
72371f11376Sdjm 	int rtable, ortable = getrtable();
72471f11376Sdjm 	const char *errstr;
72571f11376Sdjm 
72671f11376Sdjm 	if (name == NULL)
72771f11376Sdjm 		return; /* default */
72871f11376Sdjm 
72971f11376Sdjm 	if (strcmp(name, "%D") == 0) {
73071f11376Sdjm 		/* "expands" to routing domain of connection */
73171f11376Sdjm 		if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
73271f11376Sdjm 			return;
73371f11376Sdjm 	}
73471f11376Sdjm 
73571f11376Sdjm 	rtable = (int)strtonum(name, 0, 255, &errstr);
73671f11376Sdjm 	if (errstr != NULL) /* Shouldn't happen */
73771f11376Sdjm 		fatal("Invalid routing domain \"%s\": %s", name, errstr);
73871f11376Sdjm 	if (rtable != ortable && setrtable(rtable) != 0)
73971f11376Sdjm 		fatal("Unable to set routing domain %d: %s",
74071f11376Sdjm 		    rtable, strerror(errno));
74171f11376Sdjm 	debug_f("set routing domain %d (was %d)", rtable, ortable);
74271f11376Sdjm }
74371f11376Sdjm 
74471f11376Sdjm /*
74571f11376Sdjm  * Main program for the daemon.
74671f11376Sdjm  */
74771f11376Sdjm int
74871f11376Sdjm main(int ac, char **av)
74971f11376Sdjm {
75071f11376Sdjm 	struct ssh *ssh = NULL;
75171f11376Sdjm 	extern char *optarg;
75271f11376Sdjm 	extern int optind;
753856b6ee8Sdjm 	int devnull, r, opt, on = 1, remote_port;
75471f11376Sdjm 	int sock_in = -1, sock_out = -1, rexeced_flag = 0, have_key = 0;
75571f11376Sdjm 	const char *remote_ip, *rdomain;
75671f11376Sdjm 	char *line, *laddr, *logfile = NULL;
75771f11376Sdjm 	u_int i;
75871f11376Sdjm 	u_int64_t ibytes, obytes;
75971f11376Sdjm 	mode_t new_umask;
76071f11376Sdjm 	Authctxt *authctxt;
76171f11376Sdjm 	struct connection_info *connection_info = NULL;
76271f11376Sdjm 	sigset_t sigmask;
76371f11376Sdjm 	uint64_t timing_secret = 0;
764873f0a37Sdlg 	struct itimerval itv;
76571f11376Sdjm 
76671f11376Sdjm 	sigemptyset(&sigmask);
76771f11376Sdjm 	sigprocmask(SIG_SETMASK, &sigmask, NULL);
76871f11376Sdjm 
76971f11376Sdjm 	/* Save argv. */
77071f11376Sdjm 	saved_argv = av;
77171f11376Sdjm 
77271f11376Sdjm 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
77371f11376Sdjm 	sanitise_stdfd();
77471f11376Sdjm 
77571f11376Sdjm 	/* Initialize configuration options to their default values. */
77671f11376Sdjm 	initialize_server_options(&options);
77771f11376Sdjm 
77871f11376Sdjm 	/* Parse command-line arguments. */
77971f11376Sdjm 	while ((opt = getopt(ac, av,
78071f11376Sdjm 	    "C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) {
78171f11376Sdjm 		switch (opt) {
78271f11376Sdjm 		case '4':
78371f11376Sdjm 			options.address_family = AF_INET;
78471f11376Sdjm 			break;
78571f11376Sdjm 		case '6':
78671f11376Sdjm 			options.address_family = AF_INET6;
78771f11376Sdjm 			break;
78871f11376Sdjm 		case 'f':
78971f11376Sdjm 			config_file_name = optarg;
79071f11376Sdjm 			break;
79171f11376Sdjm 		case 'c':
79271f11376Sdjm 			servconf_add_hostcert("[command-line]", 0,
79371f11376Sdjm 			    &options, optarg);
79471f11376Sdjm 			break;
79571f11376Sdjm 		case 'd':
79671f11376Sdjm 			if (debug_flag == 0) {
79771f11376Sdjm 				debug_flag = 1;
79871f11376Sdjm 				options.log_level = SYSLOG_LEVEL_DEBUG1;
79971f11376Sdjm 			} else if (options.log_level < SYSLOG_LEVEL_DEBUG3)
80071f11376Sdjm 				options.log_level++;
80171f11376Sdjm 			break;
80271f11376Sdjm 		case 'D':
80371f11376Sdjm 			/* ignore */
80471f11376Sdjm 			break;
80571f11376Sdjm 		case 'E':
80671f11376Sdjm 			logfile = optarg;
80771f11376Sdjm 			/* FALLTHROUGH */
80871f11376Sdjm 		case 'e':
80971f11376Sdjm 			log_stderr = 1;
81071f11376Sdjm 			break;
81171f11376Sdjm 		case 'i':
81271f11376Sdjm 			inetd_flag = 1;
81371f11376Sdjm 			break;
81471f11376Sdjm 		case 'r':
81571f11376Sdjm 			/* ignore */
81671f11376Sdjm 			break;
81771f11376Sdjm 		case 'R':
81871f11376Sdjm 			rexeced_flag = 1;
81971f11376Sdjm 			break;
82071f11376Sdjm 		case 'Q':
82171f11376Sdjm 			/* ignored */
82271f11376Sdjm 			break;
82371f11376Sdjm 		case 'q':
82471f11376Sdjm 			options.log_level = SYSLOG_LEVEL_QUIET;
82571f11376Sdjm 			break;
82671f11376Sdjm 		case 'b':
82771f11376Sdjm 			/* protocol 1, ignored */
82871f11376Sdjm 			break;
82971f11376Sdjm 		case 'p':
83071f11376Sdjm 			options.ports_from_cmdline = 1;
83171f11376Sdjm 			if (options.num_ports >= MAX_PORTS) {
83271f11376Sdjm 				fprintf(stderr, "too many ports.\n");
83371f11376Sdjm 				exit(1);
83471f11376Sdjm 			}
83571f11376Sdjm 			options.ports[options.num_ports++] = a2port(optarg);
83671f11376Sdjm 			if (options.ports[options.num_ports-1] <= 0) {
83771f11376Sdjm 				fprintf(stderr, "Bad port number.\n");
83871f11376Sdjm 				exit(1);
83971f11376Sdjm 			}
84071f11376Sdjm 			break;
84171f11376Sdjm 		case 'g':
84271f11376Sdjm 			if ((options.login_grace_time = convtime(optarg)) == -1) {
84371f11376Sdjm 				fprintf(stderr, "Invalid login grace time.\n");
84471f11376Sdjm 				exit(1);
84571f11376Sdjm 			}
84671f11376Sdjm 			break;
84771f11376Sdjm 		case 'k':
84871f11376Sdjm 			/* protocol 1, ignored */
84971f11376Sdjm 			break;
85071f11376Sdjm 		case 'h':
85171f11376Sdjm 			servconf_add_hostkey("[command-line]", 0,
85271f11376Sdjm 			    &options, optarg, 1);
85371f11376Sdjm 			break;
85471f11376Sdjm 		case 't':
85571f11376Sdjm 		case 'T':
85671f11376Sdjm 		case 'G':
85771f11376Sdjm 			fatal("test/dump modes not supported");
85871f11376Sdjm 			break;
85971f11376Sdjm 		case 'C':
86071f11376Sdjm 			connection_info = server_get_connection_info(ssh, 0, 0);
86171f11376Sdjm 			if (parse_server_match_testspec(connection_info,
86271f11376Sdjm 			    optarg) == -1)
86371f11376Sdjm 				exit(1);
86471f11376Sdjm 			break;
86571f11376Sdjm 		case 'u':
86671f11376Sdjm 			utmp_len = (u_int)strtonum(optarg, 0, HOST_NAME_MAX+1+1, NULL);
86771f11376Sdjm 			if (utmp_len > HOST_NAME_MAX+1) {
86871f11376Sdjm 				fprintf(stderr, "Invalid utmp length.\n");
86971f11376Sdjm 				exit(1);
87071f11376Sdjm 			}
87171f11376Sdjm 			break;
87271f11376Sdjm 		case 'o':
87371f11376Sdjm 			line = xstrdup(optarg);
87471f11376Sdjm 			if (process_server_config_line(&options, line,
87571f11376Sdjm 			    "command-line", 0, NULL, NULL, &includes) != 0)
87671f11376Sdjm 				exit(1);
87771f11376Sdjm 			free(line);
87871f11376Sdjm 			break;
87971f11376Sdjm 		case 'V':
88071f11376Sdjm 			fprintf(stderr, "%s, %s\n",
88171f11376Sdjm 			    SSH_VERSION, SSH_OPENSSL_VERSION);
88271f11376Sdjm 			exit(0);
88371f11376Sdjm 		default:
88471f11376Sdjm 			usage();
88571f11376Sdjm 			break;
88671f11376Sdjm 		}
88771f11376Sdjm 	}
88871f11376Sdjm 
88971f11376Sdjm 	/* Check that there are no remaining arguments. */
89071f11376Sdjm 	if (optind < ac) {
89171f11376Sdjm 		fprintf(stderr, "Extra argument %s.\n", av[optind]);
89271f11376Sdjm 		exit(1);
89371f11376Sdjm 	}
89471f11376Sdjm 
89571f11376Sdjm 	if (!rexeced_flag)
89671f11376Sdjm 		fatal("sshd-session should not be executed directly");
89771f11376Sdjm 
89871f11376Sdjm 	closefrom(REEXEC_MIN_FREE_FD);
89971f11376Sdjm 
900856b6ee8Sdjm 	/* Reserve fds we'll need later for reexec things */
901856b6ee8Sdjm 	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
902856b6ee8Sdjm 		fatal("open %s: %s", _PATH_DEVNULL, strerror(errno));
903856b6ee8Sdjm 	while (devnull < PRIVSEP_MIN_FREE_FD) {
904856b6ee8Sdjm 		if ((devnull = dup(devnull)) == -1)
905856b6ee8Sdjm 			fatal("dup %s: %s", _PATH_DEVNULL, strerror(errno));
906856b6ee8Sdjm 	}
907856b6ee8Sdjm 
90871f11376Sdjm #ifdef WITH_OPENSSL
90971f11376Sdjm 	OpenSSL_add_all_algorithms();
91071f11376Sdjm #endif
91171f11376Sdjm 
91271f11376Sdjm 	/* If requested, redirect the logs to the specified logfile. */
91371f11376Sdjm 	if (logfile != NULL) {
91471f11376Sdjm 		char *cp, pid_s[32];
91571f11376Sdjm 
91671f11376Sdjm 		snprintf(pid_s, sizeof(pid_s), "%ld", (unsigned long)getpid());
91771f11376Sdjm 		cp = percent_expand(logfile,
91871f11376Sdjm 		    "p", pid_s,
91971f11376Sdjm 		    "P", "sshd-session",
92071f11376Sdjm 		    (char *)NULL);
92171f11376Sdjm 		log_redirect_stderr_to(cp);
92271f11376Sdjm 		free(cp);
92371f11376Sdjm 	}
92471f11376Sdjm 
92571f11376Sdjm 	/*
92671f11376Sdjm 	 * Force logging to stderr until we have loaded the private host
92771f11376Sdjm 	 * key (unless started from inetd)
92871f11376Sdjm 	 */
92971f11376Sdjm 	log_init(__progname,
93071f11376Sdjm 	    options.log_level == SYSLOG_LEVEL_NOT_SET ?
93171f11376Sdjm 	    SYSLOG_LEVEL_INFO : options.log_level,
93271f11376Sdjm 	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?
93371f11376Sdjm 	    SYSLOG_FACILITY_AUTH : options.log_facility,
93471f11376Sdjm 	    log_stderr || !inetd_flag || debug_flag);
93571f11376Sdjm 
93671f11376Sdjm 	/* Fetch our configuration */
93771f11376Sdjm 	if ((cfg = sshbuf_new()) == NULL)
93871f11376Sdjm 		fatal("sshbuf_new config buf failed");
93971f11376Sdjm 	setproctitle("%s", "[rexeced]");
94071f11376Sdjm 	recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg, &timing_secret);
941856b6ee8Sdjm 	/* close the fd, but keep the slot reserved */
942856b6ee8Sdjm 	if (dup2(devnull, REEXEC_CONFIG_PASS_FD) == -1)
943856b6ee8Sdjm 		fatal("dup2 devnull->config fd: %s", strerror(errno));
94471f11376Sdjm 	parse_server_config(&options, "rexec", cfg, &includes, NULL, 1);
94571f11376Sdjm 	/* Fill in default values for those options not explicitly set. */
94671f11376Sdjm 	fill_default_server_options(&options);
94771f11376Sdjm 	options.timing_secret = timing_secret;
94871f11376Sdjm 
949*874e263eSdtucker 	/* Reinit logging in case config set Level, Facility or Verbose. */
950*874e263eSdtucker 	log_init(__progname, options.log_level, options.log_facility,
951*874e263eSdtucker 	    log_stderr || !inetd_flag || debug_flag);
952*874e263eSdtucker 
953*874e263eSdtucker 	debug("sshd-session version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION);
954*874e263eSdtucker 
955856b6ee8Sdjm 	if (!debug_flag && !inetd_flag) {
956856b6ee8Sdjm 		if ((startup_pipe = dup(REEXEC_STARTUP_PIPE_FD)) == -1)
957856b6ee8Sdjm 			fatal("internal error: no startup pipe");
958856b6ee8Sdjm 		/* close the fd, but keep the slot reserved */
959856b6ee8Sdjm 		if (dup2(devnull, REEXEC_STARTUP_PIPE_FD) == -1)
960856b6ee8Sdjm 			fatal("dup2 devnull->startup fd: %s", strerror(errno));
961856b6ee8Sdjm 
96271f11376Sdjm 		/*
96371f11376Sdjm 		 * Signal parent that this child is at a point where
96471f11376Sdjm 		 * they can go away if they have a SIGHUP pending.
96571f11376Sdjm 		 */
96671f11376Sdjm 		(void)atomicio(vwrite, startup_pipe, "\0", 1);
96771f11376Sdjm 	}
96871f11376Sdjm 
96971f11376Sdjm 	/* Check that options are sensible */
97071f11376Sdjm 	if (options.authorized_keys_command_user == NULL &&
97171f11376Sdjm 	    (options.authorized_keys_command != NULL &&
97271f11376Sdjm 	    strcasecmp(options.authorized_keys_command, "none") != 0))
97371f11376Sdjm 		fatal("AuthorizedKeysCommand set without "
97471f11376Sdjm 		    "AuthorizedKeysCommandUser");
97571f11376Sdjm 	if (options.authorized_principals_command_user == NULL &&
97671f11376Sdjm 	    (options.authorized_principals_command != NULL &&
97771f11376Sdjm 	    strcasecmp(options.authorized_principals_command, "none") != 0))
97871f11376Sdjm 		fatal("AuthorizedPrincipalsCommand set without "
97971f11376Sdjm 		    "AuthorizedPrincipalsCommandUser");
98071f11376Sdjm 
98171f11376Sdjm 	/*
98271f11376Sdjm 	 * Check whether there is any path through configured auth methods.
98371f11376Sdjm 	 * Unfortunately it is not possible to verify this generally before
98471f11376Sdjm 	 * daemonisation in the presence of Match block, but this catches
98571f11376Sdjm 	 * and warns for trivial misconfigurations that could break login.
98671f11376Sdjm 	 */
98771f11376Sdjm 	if (options.num_auth_methods != 0) {
98871f11376Sdjm 		for (i = 0; i < options.num_auth_methods; i++) {
98971f11376Sdjm 			if (auth2_methods_valid(options.auth_methods[i],
99071f11376Sdjm 			    1) == 0)
99171f11376Sdjm 				break;
99271f11376Sdjm 		}
99371f11376Sdjm 		if (i >= options.num_auth_methods)
99471f11376Sdjm 			fatal("AuthenticationMethods cannot be satisfied by "
99571f11376Sdjm 			    "enabled authentication methods");
99671f11376Sdjm 	}
99771f11376Sdjm 
99871f11376Sdjm #ifdef WITH_OPENSSL
99971f11376Sdjm 	if (options.moduli_file != NULL)
100071f11376Sdjm 		dh_set_moduli_file(options.moduli_file);
100171f11376Sdjm #endif
100271f11376Sdjm 
100371f11376Sdjm 	if (options.host_key_agent) {
100471f11376Sdjm 		if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
100571f11376Sdjm 			setenv(SSH_AUTHSOCKET_ENV_NAME,
100671f11376Sdjm 			    options.host_key_agent, 1);
100771f11376Sdjm 		if ((r = ssh_get_authentication_socket(NULL)) == 0)
100871f11376Sdjm 			have_agent = 1;
100971f11376Sdjm 		else
101071f11376Sdjm 			error_r(r, "Could not connect to agent \"%s\"",
101171f11376Sdjm 			    options.host_key_agent);
101271f11376Sdjm 	}
101371f11376Sdjm 
101471f11376Sdjm 	if (options.num_host_key_files != sensitive_data.num_hostkeys) {
101571f11376Sdjm 		fatal("internal error: hostkeys confused (config %u recvd %u)",
101671f11376Sdjm 		    options.num_host_key_files, sensitive_data.num_hostkeys);
101771f11376Sdjm 	}
101871f11376Sdjm 
101971f11376Sdjm 	for (i = 0; i < options.num_host_key_files; i++) {
102071f11376Sdjm 		if (sensitive_data.host_keys[i] != NULL ||
102171f11376Sdjm 		    (have_agent && sensitive_data.host_pubkeys[i] != NULL)) {
102271f11376Sdjm 			have_key = 1;
102371f11376Sdjm 			break;
102471f11376Sdjm 		}
102571f11376Sdjm 	}
102671f11376Sdjm 	if (!have_key)
10279574f1dcSjsg 		fatal("internal error: monitor received no hostkeys");
102871f11376Sdjm 
102971f11376Sdjm 	/* Ensure that umask disallows at least group and world write */
103071f11376Sdjm 	new_umask = umask(0077) | 0022;
103171f11376Sdjm 	(void) umask(new_umask);
103271f11376Sdjm 
103371f11376Sdjm 	/* Initialize the log (it is reinitialized below in case we forked). */
103471f11376Sdjm 	if (debug_flag)
103571f11376Sdjm 		log_stderr = 1;
103671f11376Sdjm 	log_init(__progname, options.log_level,
103771f11376Sdjm 	    options.log_facility, log_stderr);
103871f11376Sdjm 	for (i = 0; i < options.num_log_verbose; i++)
103971f11376Sdjm 		log_verbose_add(options.log_verbose[i]);
104071f11376Sdjm 
104171f11376Sdjm 	/* Reinitialize the log (because of the fork above). */
104271f11376Sdjm 	log_init(__progname, options.log_level, options.log_facility, log_stderr);
104371f11376Sdjm 
104471f11376Sdjm 	/*
104571f11376Sdjm 	 * Chdir to the root directory so that the current disk can be
104671f11376Sdjm 	 * unmounted if desired.
104771f11376Sdjm 	 */
104871f11376Sdjm 	if (chdir("/") == -1)
104971f11376Sdjm 		error("chdir(\"/\"): %s", strerror(errno));
105071f11376Sdjm 
105171f11376Sdjm 	/* ignore SIGPIPE */
105271f11376Sdjm 	ssh_signal(SIGPIPE, SIG_IGN);
105371f11376Sdjm 
105471f11376Sdjm 	/* Get a connection, either from inetd or rexec */
105571f11376Sdjm 	if (inetd_flag) {
105671f11376Sdjm 		/*
105771f11376Sdjm 		 * NB. must be different fd numbers for the !socket case,
105871f11376Sdjm 		 * as packet_connection_is_on_socket() depends on this.
105971f11376Sdjm 		 */
106071f11376Sdjm 		sock_in = dup(STDIN_FILENO);
106171f11376Sdjm 		sock_out = dup(STDOUT_FILENO);
106271f11376Sdjm 	} else {
106371f11376Sdjm 		/* rexec case; accept()ed socket in ancestor listener */
106471f11376Sdjm 		sock_in = sock_out = dup(STDIN_FILENO);
106571f11376Sdjm 	}
106671f11376Sdjm 
106771f11376Sdjm 	/*
106871f11376Sdjm 	 * We intentionally do not close the descriptors 0, 1, and 2
106971f11376Sdjm 	 * as our code for setting the descriptors won't work if
107071f11376Sdjm 	 * ttyfd happens to be one of those.
107171f11376Sdjm 	 */
107271f11376Sdjm 	if (stdfd_devnull(1, 1, !log_stderr) == -1)
107371f11376Sdjm 		error("stdfd_devnull failed");
107471f11376Sdjm 	debug("network sockets: %d, %d", sock_in, sock_out);
107571f11376Sdjm 
107671f11376Sdjm 	/* This is the child processing a new connection. */
107771f11376Sdjm 	setproctitle("%s", "[accepted]");
107871f11376Sdjm 
107971f11376Sdjm 	/* Executed child processes don't need these. */
108071f11376Sdjm 	fcntl(sock_out, F_SETFD, FD_CLOEXEC);
108171f11376Sdjm 	fcntl(sock_in, F_SETFD, FD_CLOEXEC);
108271f11376Sdjm 
108371f11376Sdjm 	/* We will not restart on SIGHUP since it no longer makes sense. */
108471f11376Sdjm 	ssh_signal(SIGALRM, SIG_DFL);
108571f11376Sdjm 	ssh_signal(SIGHUP, SIG_DFL);
108671f11376Sdjm 	ssh_signal(SIGTERM, SIG_DFL);
108771f11376Sdjm 	ssh_signal(SIGQUIT, SIG_DFL);
108871f11376Sdjm 	ssh_signal(SIGCHLD, SIG_DFL);
108971f11376Sdjm 
109071f11376Sdjm 	/*
109171f11376Sdjm 	 * Register our connection.  This turns encryption off because we do
109271f11376Sdjm 	 * not have a key.
109371f11376Sdjm 	 */
109471f11376Sdjm 	if ((ssh = ssh_packet_set_connection(NULL, sock_in, sock_out)) == NULL)
109571f11376Sdjm 		fatal("Unable to create connection");
109671f11376Sdjm 	the_active_state = ssh;
109771f11376Sdjm 	ssh_packet_set_server(ssh);
109871f11376Sdjm 
109971f11376Sdjm 	check_ip_options(ssh);
110071f11376Sdjm 
110171f11376Sdjm 	/* Prepare the channels layer */
110271f11376Sdjm 	channel_init_channels(ssh);
110371f11376Sdjm 	channel_set_af(ssh, options.address_family);
110471f11376Sdjm 	server_process_channel_timeouts(ssh);
110571f11376Sdjm 	server_process_permitopen(ssh);
110671f11376Sdjm 
110771f11376Sdjm 	/* Set SO_KEEPALIVE if requested. */
110871f11376Sdjm 	if (options.tcp_keep_alive && ssh_packet_connection_is_on_socket(ssh) &&
110971f11376Sdjm 	    setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
111071f11376Sdjm 		error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
111171f11376Sdjm 
111271f11376Sdjm 	if ((remote_port = ssh_remote_port(ssh)) < 0) {
111371f11376Sdjm 		debug("ssh_remote_port failed");
111471f11376Sdjm 		cleanup_exit(255);
111571f11376Sdjm 	}
111671f11376Sdjm 
111771f11376Sdjm 	/*
111871f11376Sdjm 	 * The rest of the code depends on the fact that
111971f11376Sdjm 	 * ssh_remote_ipaddr() caches the remote ip, even if
112071f11376Sdjm 	 * the socket goes away.
112171f11376Sdjm 	 */
112271f11376Sdjm 	remote_ip = ssh_remote_ipaddr(ssh);
112371f11376Sdjm 
112471f11376Sdjm 	rdomain = ssh_packet_rdomain_in(ssh);
112571f11376Sdjm 
112671f11376Sdjm 	/* Log the connection. */
112771f11376Sdjm 	laddr = get_local_ipaddr(sock_in);
112871f11376Sdjm 	verbose("Connection from %s port %d on %s port %d%s%s%s",
112971f11376Sdjm 	    remote_ip, remote_port, laddr,  ssh_local_port(ssh),
113071f11376Sdjm 	    rdomain == NULL ? "" : " rdomain \"",
113171f11376Sdjm 	    rdomain == NULL ? "" : rdomain,
113271f11376Sdjm 	    rdomain == NULL ? "" : "\"");
113371f11376Sdjm 	free(laddr);
113471f11376Sdjm 
113571f11376Sdjm 	/*
113671f11376Sdjm 	 * We don't want to listen forever unless the other side
113771f11376Sdjm 	 * successfully authenticates itself.  So we set up an alarm which is
113871f11376Sdjm 	 * cleared after successful authentication.  A limit of zero
113971f11376Sdjm 	 * indicates no limit. Note that we don't set the alarm in debugging
114071f11376Sdjm 	 * mode; it is just annoying to have the server exit just when you
114171f11376Sdjm 	 * are about to discover the bug.
114271f11376Sdjm 	 */
114371f11376Sdjm 	ssh_signal(SIGALRM, grace_alarm_handler);
1144873f0a37Sdlg 	if (!debug_flag && options.login_grace_time > 0) {
1145873f0a37Sdlg 		int ujitter = arc4random_uniform(4 * 1000000);
1146873f0a37Sdlg 
1147873f0a37Sdlg 		timerclear(&itv.it_interval);
1148873f0a37Sdlg 		itv.it_value.tv_sec = options.login_grace_time;
1149873f0a37Sdlg 		itv.it_value.tv_sec += ujitter / 1000000;
1150873f0a37Sdlg 		itv.it_value.tv_usec = ujitter % 1000000;
1151873f0a37Sdlg 
1152873f0a37Sdlg 		if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
1153873f0a37Sdlg 			fatal("login grace time setitimer failed");
1154873f0a37Sdlg 	}
115571f11376Sdjm 
115671f11376Sdjm 	if ((r = kex_exchange_identification(ssh, -1,
115771f11376Sdjm 	    options.version_addendum)) != 0)
115871f11376Sdjm 		sshpkt_fatal(ssh, r, "banner exchange");
115971f11376Sdjm 
116071f11376Sdjm 	ssh_packet_set_nonblocking(ssh);
116171f11376Sdjm 
116271f11376Sdjm 	/* allocate authentication context */
116371f11376Sdjm 	authctxt = xcalloc(1, sizeof(*authctxt));
116471f11376Sdjm 	ssh->authctxt = authctxt;
116571f11376Sdjm 
116671f11376Sdjm 	/* XXX global for cleanup, access from other modules */
116771f11376Sdjm 	the_authctxt = authctxt;
116871f11376Sdjm 
116971f11376Sdjm 	/* Set default key authentication options */
117071f11376Sdjm 	if ((auth_opts = sshauthopt_new_with_keys_defaults()) == NULL)
117171f11376Sdjm 		fatal("allocation failed");
117271f11376Sdjm 
117371f11376Sdjm 	/* prepare buffer to collect messages to display to user after login */
117471f11376Sdjm 	if ((loginmsg = sshbuf_new()) == NULL)
117571f11376Sdjm 		fatal("sshbuf_new loginmsg failed");
117671f11376Sdjm 	auth_debug_reset();
117771f11376Sdjm 
1178856b6ee8Sdjm 	if (privsep_preauth(ssh) != 1)
1179856b6ee8Sdjm 		fatal("privsep_preauth failed");
118071f11376Sdjm 
1181856b6ee8Sdjm 	/* Now user is authenticated */
118271f11376Sdjm 
118371f11376Sdjm 	/*
118471f11376Sdjm 	 * Cancel the alarm we set to limit the time taken for
118571f11376Sdjm 	 * authentication.
118671f11376Sdjm 	 */
1187873f0a37Sdlg 	timerclear(&itv.it_interval);
1188873f0a37Sdlg 	timerclear(&itv.it_value);
1189873f0a37Sdlg 	if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
1190873f0a37Sdlg 		fatal("login grace time clear failed");
119171f11376Sdjm 	ssh_signal(SIGALRM, SIG_DFL);
119271f11376Sdjm 	authctxt->authenticated = 1;
119371f11376Sdjm 	if (startup_pipe != -1) {
11947965d983Sdjm 		/* signal listener that authentication completed successfully */
11957965d983Sdjm 		(void)atomicio(vwrite, startup_pipe, "\001", 1);
119671f11376Sdjm 		close(startup_pipe);
119771f11376Sdjm 		startup_pipe = -1;
119871f11376Sdjm 	}
119971f11376Sdjm 
120071f11376Sdjm 	if (options.routing_domain != NULL)
120171f11376Sdjm 		set_process_rdomain(ssh, options.routing_domain);
120271f11376Sdjm 
120371f11376Sdjm 	/*
120471f11376Sdjm 	 * In privilege separation, we fork another child and prepare
120571f11376Sdjm 	 * file descriptor passing.
120671f11376Sdjm 	 */
120771f11376Sdjm 	privsep_postauth(ssh, authctxt);
120871f11376Sdjm 	/* the monitor process [priv] will not return */
120971f11376Sdjm 
121071f11376Sdjm 	ssh_packet_set_timeout(ssh, options.client_alive_interval,
121171f11376Sdjm 	    options.client_alive_count_max);
121271f11376Sdjm 
121371f11376Sdjm 	/* Try to send all our hostkeys to the client */
121471f11376Sdjm 	notify_hostkeys(ssh);
121571f11376Sdjm 
121671f11376Sdjm 	/* Start session. */
121771f11376Sdjm 	do_authenticated(ssh, authctxt);
121871f11376Sdjm 
121971f11376Sdjm 	/* The connection has been terminated. */
122071f11376Sdjm 	ssh_packet_get_bytes(ssh, &ibytes, &obytes);
122171f11376Sdjm 	verbose("Transferred: sent %llu, received %llu bytes",
122271f11376Sdjm 	    (unsigned long long)obytes, (unsigned long long)ibytes);
122371f11376Sdjm 
122471f11376Sdjm 	verbose("Closing connection to %.500s port %d", remote_ip, remote_port);
122571f11376Sdjm 	ssh_packet_close(ssh);
122671f11376Sdjm 
122771f11376Sdjm 	mm_terminate();
122871f11376Sdjm 
122971f11376Sdjm 	exit(0);
123071f11376Sdjm }
123171f11376Sdjm 
123271f11376Sdjm int
123371f11376Sdjm sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
123471f11376Sdjm     struct sshkey *pubkey, u_char **signature, size_t *slenp,
123571f11376Sdjm     const u_char *data, size_t dlen, const char *alg)
123671f11376Sdjm {
123771f11376Sdjm 	if (privkey) {
123871f11376Sdjm 		if (mm_sshkey_sign(ssh, privkey, signature, slenp,
123971f11376Sdjm 		    data, dlen, alg, options.sk_provider, NULL,
124071f11376Sdjm 		    ssh->compat) < 0)
124171f11376Sdjm 			fatal_f("privkey sign failed");
124271f11376Sdjm 	} else {
124371f11376Sdjm 		if (mm_sshkey_sign(ssh, pubkey, signature, slenp,
124471f11376Sdjm 		    data, dlen, alg, options.sk_provider, NULL,
124571f11376Sdjm 		    ssh->compat) < 0)
124671f11376Sdjm 			fatal_f("pubkey sign failed");
124771f11376Sdjm 	}
124871f11376Sdjm 	return 0;
124971f11376Sdjm }
125071f11376Sdjm 
125171f11376Sdjm /* server specific fatal cleanup */
125271f11376Sdjm void
125371f11376Sdjm cleanup_exit(int i)
125471f11376Sdjm {
12557965d983Sdjm 	extern int auth_attempted; /* monitor.c */
12567965d983Sdjm 
125771f11376Sdjm 	if (the_active_state != NULL && the_authctxt != NULL) {
125871f11376Sdjm 		do_cleanup(the_active_state, the_authctxt);
125971f11376Sdjm 		if (privsep_is_preauth &&
126071f11376Sdjm 		    pmonitor != NULL && pmonitor->m_pid > 1) {
126171f11376Sdjm 			debug("Killing privsep child %d", pmonitor->m_pid);
126271f11376Sdjm 			if (kill(pmonitor->m_pid, SIGKILL) != 0 &&
126371f11376Sdjm 			    errno != ESRCH) {
126471f11376Sdjm 				error_f("kill(%d): %s", pmonitor->m_pid,
126571f11376Sdjm 				    strerror(errno));
126671f11376Sdjm 			}
126771f11376Sdjm 		}
126871f11376Sdjm 	}
12697965d983Sdjm 	/* Override default fatal exit value when auth was attempted */
12707965d983Sdjm 	if (i == 255 && auth_attempted)
12717965d983Sdjm 		_exit(EXIT_AUTH_ATTEMPTED);
127271f11376Sdjm 	_exit(i);
127371f11376Sdjm }
1274