xref: /onnv-gate/usr/src/cmd/ssh/sshd/altprivsep.c (revision 12551:b2ba48b14377)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55562Sjp161948  * Common Development and Distribution License (the "License").
65562Sjp161948  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
21*12551SZdenek.Kotala@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate 
247574SJan.Pechanec@Sun.COM #include <fcntl.h>
257574SJan.Pechanec@Sun.COM #include <sys/types.h>
267574SJan.Pechanec@Sun.COM #include <sys/types.h>
277574SJan.Pechanec@Sun.COM #include <sys/stat.h>
287574SJan.Pechanec@Sun.COM #include <sys/socket.h>
297574SJan.Pechanec@Sun.COM 
307574SJan.Pechanec@Sun.COM #include <pwd.h>
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include "includes.h"
330Sstevel@tonic-gate #include "atomicio.h"
340Sstevel@tonic-gate #include "auth.h"
350Sstevel@tonic-gate #include "bufaux.h"
360Sstevel@tonic-gate #include "buffer.h"
370Sstevel@tonic-gate #include "cipher.h"
380Sstevel@tonic-gate #include "compat.h"
390Sstevel@tonic-gate #include "dispatch.h"
400Sstevel@tonic-gate #include "getput.h"
410Sstevel@tonic-gate #include "kex.h"
420Sstevel@tonic-gate #include "log.h"
430Sstevel@tonic-gate #include "mac.h"
440Sstevel@tonic-gate #include "packet.h"
450Sstevel@tonic-gate #include "uidswap.h"
460Sstevel@tonic-gate #include "ssh2.h"
470Sstevel@tonic-gate #include "sshlogin.h"
480Sstevel@tonic-gate #include "xmalloc.h"
490Sstevel@tonic-gate #include "altprivsep.h"
507574SJan.Pechanec@Sun.COM #include "canohost.h"
517574SJan.Pechanec@Sun.COM #include "engine.h"
527574SJan.Pechanec@Sun.COM #include "servconf.h"
537574SJan.Pechanec@Sun.COM 
547574SJan.Pechanec@Sun.COM #ifdef HAVE_BSM
557574SJan.Pechanec@Sun.COM #include "bsmaudit.h"
567574SJan.Pechanec@Sun.COM adt_session_data_t *ah = NULL;
577574SJan.Pechanec@Sun.COM #endif /* HAVE_BSM */
587574SJan.Pechanec@Sun.COM 
597574SJan.Pechanec@Sun.COM #ifdef GSSAPI
607574SJan.Pechanec@Sun.COM #include "ssh-gss.h"
617574SJan.Pechanec@Sun.COM extern Gssctxt *xxx_gssctxt;
627574SJan.Pechanec@Sun.COM #endif /* GSSAPI */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate extern Kex *xxx_kex;
657574SJan.Pechanec@Sun.COM extern u_char *session_id2;
667574SJan.Pechanec@Sun.COM extern int session_id2_len;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static Buffer to_monitor;
690Sstevel@tonic-gate static Buffer from_monitor;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * Sun's Alternative Privilege Separation basics:
730Sstevel@tonic-gate  *
740Sstevel@tonic-gate  * Abstract
750Sstevel@tonic-gate  * --------
760Sstevel@tonic-gate  *
770Sstevel@tonic-gate  * sshd(1M) fork()s and drops privs in the child while retaining privs
780Sstevel@tonic-gate  * in the parent (a.k.a., the monitor).  The unprivileged sshd and the
790Sstevel@tonic-gate  * monitor talk over a pipe using a simple protocol.
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  * The monitor protocol is all about having the monitor carry out the
820Sstevel@tonic-gate  * only operations that require privileges OR access to privileged
830Sstevel@tonic-gate  * resources.  These are: utmpx/wtmpx record keeping, auditing, and
840Sstevel@tonic-gate  * SSHv2 re-keying.
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  * Re-Keying
870Sstevel@tonic-gate  * ---------
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  * Re-keying is the only protocol version specific aspect of sshd in
900Sstevel@tonic-gate  * which the monitor gets involved.
910Sstevel@tonic-gate  *
920Sstevel@tonic-gate  * The monitor processes all SSHv2 re-key protocol packets, but the
930Sstevel@tonic-gate  * unprivileged sshd process does the transport layer crypto for those
940Sstevel@tonic-gate  * packets.
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  * The monitor and its unprivileged sshd child process treat
970Sstevel@tonic-gate  * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call
980Sstevel@tonic-gate  * set_newkeys(), but b) the child asks the monitor for the set of
990Sstevel@tonic-gate  * negotiated algorithms, key, IV and what not for the relevant
1000Sstevel@tonic-gate  * transport direction and then calls set_newkeys().
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * Monitor Protocol
1030Sstevel@tonic-gate  * ----------------
1040Sstevel@tonic-gate  *
1050Sstevel@tonic-gate  * Monitor IPC message formats are similar to SSHv2 messages, minus
1060Sstevel@tonic-gate  * compression, encryption, padding and MACs:
1070Sstevel@tonic-gate  *
1080Sstevel@tonic-gate  *  - 4 octet message length
1090Sstevel@tonic-gate  *  - message data
1100Sstevel@tonic-gate  *     - 1 octet message type
1110Sstevel@tonic-gate  *     - message data
1120Sstevel@tonic-gate  *
1130Sstevel@tonic-gate  * In broad strokes:
1140Sstevel@tonic-gate  *
1150Sstevel@tonic-gate  *  - IPC: pipe, exit(2)/wait4(2)
1160Sstevel@tonic-gate  *
1170Sstevel@tonic-gate  *  - threads: the monitor and child are single-threaded
1180Sstevel@tonic-gate  *
1190Sstevel@tonic-gate  *  - monitor main loop: a variant of server_loop2(), for re-keying only
1200Sstevel@tonic-gate  *  - unpriv child main loop: server_loop2(), as usual
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  *  - protocol:
1230Sstevel@tonic-gate  *     - key exchange packets are always forwarded as is to the monitor
1240Sstevel@tonic-gate  *     - newkeys, record_login(), record_logout() are special packets
1250Sstevel@tonic-gate  *     using the packet type range reserved for local extensions
1260Sstevel@tonic-gate  *
1270Sstevel@tonic-gate  *  - the child drops privs and runs like a normal sshd, except that it
1280Sstevel@tonic-gate  *  sets dispatch handlers for key exchange packets that forward the
1290Sstevel@tonic-gate  *  packets to the monitor
1300Sstevel@tonic-gate  *
1310Sstevel@tonic-gate  * Event loops:
1320Sstevel@tonic-gate  *
1330Sstevel@tonic-gate  *  - all monitor protocols are synchronous: because the SSHv2 rekey
1340Sstevel@tonic-gate  *  protocols are synchronous and because the other monitor operations
1350Sstevel@tonic-gate  *  are synchronous (or have no replies),
1360Sstevel@tonic-gate  *
1370Sstevel@tonic-gate  *  - server_loop2() is modified to check the monitor pipe for rekey
1380Sstevel@tonic-gate  *  packets to forward to the client
1390Sstevel@tonic-gate  *
1400Sstevel@tonic-gate  *  - and dispatch handlers are set, upon receipt of KEXINIT (and reset
1410Sstevel@tonic-gate  *  when NEWKEYS is sent out) to forward incoming rekey packets to the
1420Sstevel@tonic-gate  *  monitor.
1430Sstevel@tonic-gate  *
1440Sstevel@tonic-gate  *  - the monitor runs an event loop not unlike server_loop2() and runs
1450Sstevel@tonic-gate  *  key exchanges almost exactly as a pre-altprivsep sshd would
1460Sstevel@tonic-gate  *
1470Sstevel@tonic-gate  *  - unpriv sshd exit -> monitor cleanup (including audit logout) and exit
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  *  - fatal() in monitor -> forcibly shutdown() socket and kill/wait for
1500Sstevel@tonic-gate  *  child (so that the audit event for the logout better reflects
1510Sstevel@tonic-gate  *  reality -- i.e., logged out means logged out, but for bg jobs)
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  * Message formats:
1540Sstevel@tonic-gate  *
1550Sstevel@tonic-gate  *  - key exchange packets/replies forwarded "as is"
1560Sstevel@tonic-gate  *
1570Sstevel@tonic-gate  *  - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a
1580Sstevel@tonic-gate  *  sub-type identifier (one octet)
1590Sstevel@tonic-gate  *  - private request sub-types include:
1600Sstevel@tonic-gate  *     - get new shared secret from last re-key
1610Sstevel@tonic-gate  *     - record login  (utmpx/wtmpx), request data contains three arguments:
1620Sstevel@tonic-gate  *     pid, ttyname, program name
1630Sstevel@tonic-gate  *     - record logout (utmpx/wtmpx), request data contains one argument: pid
1640Sstevel@tonic-gate  *
1650Sstevel@tonic-gate  * Reply sub-types include:
1660Sstevel@tonic-gate  *
1670Sstevel@tonic-gate  *  - NOP (for record_login/logout)
1680Sstevel@tonic-gate  *  - new shared secret from last re-key
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate static int aps_started = 0;
1720Sstevel@tonic-gate static int is_monitor = 0;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate static pid_t monitor_pid, child_pid;
1750Sstevel@tonic-gate static int pipe_fds[2];
1760Sstevel@tonic-gate static int pipe_fd = -1;
1770Sstevel@tonic-gate static Buffer input_pipe, output_pipe; /* for pipe I/O */
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate static Authctxt *xxx_authctxt;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /* Monitor functions */
1827574SJan.Pechanec@Sun.COM extern void aps_monitor_loop(Authctxt *authctxt, pid_t child_pid);
1830Sstevel@tonic-gate static void aps_record_login(void);
1840Sstevel@tonic-gate static void aps_record_logout(void);
1856375Sjp161948 static void aps_start_rekex(void);
1867574SJan.Pechanec@Sun.COM Authctxt *aps_read_auth_context(void);
1877574SJan.Pechanec@Sun.COM 
1887574SJan.Pechanec@Sun.COM /* main functions for handling the monitor */
1897574SJan.Pechanec@Sun.COM static pid_t	altprivsep_start_monitor(Authctxt **authctxt);
1907574SJan.Pechanec@Sun.COM static void	altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid);
1917574SJan.Pechanec@Sun.COM static int	altprivsep_started(void);
1927574SJan.Pechanec@Sun.COM static int	altprivsep_is_monitor(void);
1937574SJan.Pechanec@Sun.COM 
1947574SJan.Pechanec@Sun.COM /* calls _to_ monitor from unprivileged process */
1957574SJan.Pechanec@Sun.COM static void	altprivsep_get_newkeys(enum kex_modes mode);
1967574SJan.Pechanec@Sun.COM 
1977574SJan.Pechanec@Sun.COM /* monitor-side fatal_cleanup callbacks */
1987574SJan.Pechanec@Sun.COM static void	altprivsep_shutdown_sock(void *arg);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate /* Altprivsep packet utilities for communication with the monitor */
2010Sstevel@tonic-gate static void	altprivsep_packet_start(u_char);
2020Sstevel@tonic-gate static int	altprivsep_packet_send(void);
2030Sstevel@tonic-gate static int	altprivsep_fwd_packet(u_char type);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate static int	altprivsep_packet_read(void);
2060Sstevel@tonic-gate static void	altprivsep_packet_read_expect(int type);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate static void	altprivsep_packet_put_char(int ch);
2090Sstevel@tonic-gate static void	altprivsep_packet_put_int(u_int value);
2100Sstevel@tonic-gate static void	altprivsep_packet_put_cstring(const char *str);
2110Sstevel@tonic-gate static void	altprivsep_packet_put_raw(const void *buf, u_int len);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate static u_int	 altprivsep_packet_get_char(void);
2140Sstevel@tonic-gate static void	*altprivsep_packet_get_raw(u_int *length_ptr);
2150Sstevel@tonic-gate static void	*altprivsep_packet_get_string(u_int *length_ptr);
2160Sstevel@tonic-gate 
2177574SJan.Pechanec@Sun.COM Kex		*prepare_for_ssh2_kex(void);
2187574SJan.Pechanec@Sun.COM 
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate  * Start monitor from privileged sshd process.
2210Sstevel@tonic-gate  *
2220Sstevel@tonic-gate  * Return values are like fork(2); the parent is the monitor.  The caller should
2230Sstevel@tonic-gate  * fatal() on error.
2240Sstevel@tonic-gate  *
2257574SJan.Pechanec@Sun.COM  * Note that the monitor waits until the still privileged child finishes the
2267574SJan.Pechanec@Sun.COM  * authentication. The child drops its privileges after the authentication.
2270Sstevel@tonic-gate  */
2287574SJan.Pechanec@Sun.COM static pid_t
altprivsep_start_monitor(Authctxt ** authctxt)2297574SJan.Pechanec@Sun.COM altprivsep_start_monitor(Authctxt **authctxt)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	pid_t pid;
2320Sstevel@tonic-gate 	int junk;
2330Sstevel@tonic-gate 
2347574SJan.Pechanec@Sun.COM 	if (aps_started)
2350Sstevel@tonic-gate 		fatal("Monitor startup failed: missing state");
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	buffer_init(&output_pipe);
2380Sstevel@tonic-gate 	buffer_init(&input_pipe);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if (pipe(pipe_fds) != 0) {
2410Sstevel@tonic-gate 		error("Monitor startup failure: could not create pipes: %s",
2420Sstevel@tonic-gate 			strerror(errno));
2430Sstevel@tonic-gate 		return (-1);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	(void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
2470Sstevel@tonic-gate 	(void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	monitor_pid = getpid();
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if ((pid = fork()) > 0) {
2527574SJan.Pechanec@Sun.COM 		/*
2537574SJan.Pechanec@Sun.COM 		 * From now on, all debug messages from monitor will have prefix
2547574SJan.Pechanec@Sun.COM 		 * "monitor "
2557574SJan.Pechanec@Sun.COM 		 */
2567574SJan.Pechanec@Sun.COM 		set_log_txt_prefix("monitor ");
2577574SJan.Pechanec@Sun.COM 		(void) prepare_for_ssh2_kex();
2587574SJan.Pechanec@Sun.COM 		packet_set_server();
2590Sstevel@tonic-gate 		/* parent */
2600Sstevel@tonic-gate 		child_pid = pid;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		debug2("Monitor pid %ld, unprivileged child pid %ld",
2630Sstevel@tonic-gate 			monitor_pid, child_pid);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		(void) close(pipe_fds[1]);
2667574SJan.Pechanec@Sun.COM 		pipe_fd = pipe_fds[0];
2670Sstevel@tonic-gate 
2687574SJan.Pechanec@Sun.COM 		/*
2697574SJan.Pechanec@Sun.COM 		 * Signal readiness of the monitor and then read the
2707574SJan.Pechanec@Sun.COM 		 * authentication context from the child.
2717574SJan.Pechanec@Sun.COM 		 */
2727574SJan.Pechanec@Sun.COM 		(void) write(pipe_fd, &pid, sizeof (pid));
2737574SJan.Pechanec@Sun.COM 		packet_set_monitor(pipe_fd);
2747574SJan.Pechanec@Sun.COM 		xxx_authctxt = *authctxt = aps_read_auth_context();
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 		if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
2770Sstevel@tonic-gate 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		aps_started = 1;
2800Sstevel@tonic-gate 		is_monitor = 1;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		debug2("Monitor started");
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		return (pid);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	if (pid < 0) {
2880Sstevel@tonic-gate 		debug2("Monitor startup failure: could not fork unprivileged"
2890Sstevel@tonic-gate 			" process:  %s", strerror(errno));
2900Sstevel@tonic-gate 		return (pid);
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2937574SJan.Pechanec@Sun.COM 	/* this is the child that will later drop privileges */
2940Sstevel@tonic-gate 
2957574SJan.Pechanec@Sun.COM 	/* note that Solaris has bi-directional pipes so one pipe is enough */
2960Sstevel@tonic-gate 	(void) close(pipe_fds[0]);
2970Sstevel@tonic-gate 	pipe_fd = pipe_fds[1];
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/* wait for monitor to be ready */
3000Sstevel@tonic-gate 	debug2("Waiting for monitor");
3010Sstevel@tonic-gate 	(void) read(pipe_fd, &junk, sizeof (junk));
3020Sstevel@tonic-gate 	debug2("Monitor signalled readiness");
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	buffer_init(&to_monitor);
3050Sstevel@tonic-gate 	buffer_init(&from_monitor);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* AltPrivSep interfaces are set up */
3080Sstevel@tonic-gate 	aps_started = 1;
3090Sstevel@tonic-gate 	return (pid);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate int
altprivsep_get_pipe_fd(void)3130Sstevel@tonic-gate altprivsep_get_pipe_fd(void)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	return (pipe_fd);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate 
3187574SJan.Pechanec@Sun.COM /*
3197574SJan.Pechanec@Sun.COM  * This function is used in the unprivileged child for all packets in the range
3207574SJan.Pechanec@Sun.COM  * between SSH2_MSG_KEXINIT and SSH2_MSG_TRANSPORT_MAX.
3217574SJan.Pechanec@Sun.COM  */
3220Sstevel@tonic-gate void
altprivsep_rekey(int type,u_int32_t seq,void * ctxt)3230Sstevel@tonic-gate altprivsep_rekey(int type, u_int32_t seq, void *ctxt)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	Kex *kex = (Kex *)ctxt;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (kex == NULL)
3280Sstevel@tonic-gate 		fatal("Missing key exchange context in unprivileged process");
3290Sstevel@tonic-gate 
3307574SJan.Pechanec@Sun.COM 	if (type != SSH2_MSG_NEWKEYS) {
3317574SJan.Pechanec@Sun.COM 		debug2("Forwarding re-key packet (%d) to monitor", type);
3320Sstevel@tonic-gate 		if (!altprivsep_fwd_packet(type))
333*12551SZdenek.Kotala@Sun.COM 			fatal("altprivsep_rekey: Monitor not responding");
3347574SJan.Pechanec@Sun.COM 	}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/* tell server_loop2() that we're re-keying */
3370Sstevel@tonic-gate 	kex->done = 0;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/* NEWKEYS is special: get the new keys for client->server direction */
3400Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS) {
3417574SJan.Pechanec@Sun.COM 		debug2("received SSH2_MSG_NEWKEYS packet - "
3427574SJan.Pechanec@Sun.COM 		    "getting new inbound keys from the monitor");
3430Sstevel@tonic-gate 		altprivsep_get_newkeys(MODE_IN);
3440Sstevel@tonic-gate 		kex->done = 1;
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate void
altprivsep_process_input(fd_set * rset)3496375Sjp161948 altprivsep_process_input(fd_set *rset)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	void	*data;
3520Sstevel@tonic-gate 	int	 type;
3530Sstevel@tonic-gate 	u_int	 dlen;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	if (pipe_fd == -1)
3560Sstevel@tonic-gate 		return;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	if (!FD_ISSET(pipe_fd, rset))
3590Sstevel@tonic-gate 		return;
3600Sstevel@tonic-gate 
3617574SJan.Pechanec@Sun.COM 	debug2("reading from pipe to monitor (%d)", pipe_fd);
3620Sstevel@tonic-gate 	if ((type = altprivsep_packet_read()) == -1)
363*12551SZdenek.Kotala@Sun.COM 		fatal("altprivsep_process_input: Monitor not responding");
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (!compat20)
3660Sstevel@tonic-gate 		return; /* shouldn't happen! but be safe */
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	if (type == 0)
3690Sstevel@tonic-gate 		return;	/* EOF -- nothing to do here */
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if (type >= SSH2_MSG_MAX)
3720Sstevel@tonic-gate 		fatal("Received garbage from monitor");
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	debug2("Read packet type %d from pipe to monitor", (u_int)type);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (type == SSH2_PRIV_MSG_ALTPRIVSEP)
3770Sstevel@tonic-gate 		return; /* shouldn't happen! */
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	/* NEWKEYS is special: get the new keys for server->client direction */
3800Sstevel@tonic-gate 	if (type == SSH2_MSG_NEWKEYS) {
3817574SJan.Pechanec@Sun.COM 		debug2("forwarding SSH2_MSG_NEWKEYS packet we got from monitor to "
3827574SJan.Pechanec@Sun.COM 		    "the client");
3830Sstevel@tonic-gate 		packet_start(SSH2_MSG_NEWKEYS);
3840Sstevel@tonic-gate 		packet_send();
3857574SJan.Pechanec@Sun.COM 		debug2("getting new outbound keys from the monitor");
3860Sstevel@tonic-gate 		altprivsep_get_newkeys(MODE_OUT);
3870Sstevel@tonic-gate 		return;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	data = altprivsep_packet_get_raw(&dlen);
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	packet_start((u_char)type);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (data != NULL && dlen > 0)
3950Sstevel@tonic-gate 		packet_put_raw(data, dlen);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	packet_send();
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4007574SJan.Pechanec@Sun.COM static void
altprivsep_do_monitor(Authctxt * authctxt,pid_t child_pid)4010Sstevel@tonic-gate altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid)
4020Sstevel@tonic-gate {
4037574SJan.Pechanec@Sun.COM 	aps_monitor_loop(authctxt, child_pid);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4067574SJan.Pechanec@Sun.COM static int
altprivsep_started(void)4070Sstevel@tonic-gate altprivsep_started(void)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate 	return (aps_started);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4127574SJan.Pechanec@Sun.COM static int
altprivsep_is_monitor(void)4130Sstevel@tonic-gate altprivsep_is_monitor(void)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	return (is_monitor);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate  * A fatal cleanup function to forcibly shutdown the connection socket
4200Sstevel@tonic-gate  */
4217574SJan.Pechanec@Sun.COM static void
altprivsep_shutdown_sock(void * arg)4220Sstevel@tonic-gate altprivsep_shutdown_sock(void *arg)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	int sock;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	if (arg == NULL)
4270Sstevel@tonic-gate 		return;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	sock = *(int *)arg;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	(void) shutdown(sock, SHUT_RDWR);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate /* Calls _to_ monitor from unprivileged process */
4357574SJan.Pechanec@Sun.COM static int
altprivsep_fwd_packet(u_char type)4360Sstevel@tonic-gate altprivsep_fwd_packet(u_char type)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	u_int len;
4390Sstevel@tonic-gate 	void  *data;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	altprivsep_packet_start(type);
4420Sstevel@tonic-gate 	data = packet_get_raw(&len);
4430Sstevel@tonic-gate 	altprivsep_packet_put_raw(data, len);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/* packet_send()s any replies from the monitor to the client */
4460Sstevel@tonic-gate 	return (altprivsep_packet_send());
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate extern Newkeys *current_keys[MODE_MAX];
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate /* To be called from packet.c:set_newkeys() before referencing current_keys */
4527574SJan.Pechanec@Sun.COM static void
altprivsep_get_newkeys(enum kex_modes mode)4530Sstevel@tonic-gate altprivsep_get_newkeys(enum kex_modes mode)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	Newkeys	*newkeys;
4560Sstevel@tonic-gate 	Comp	*comp;
4570Sstevel@tonic-gate 	Enc	*enc;
4580Sstevel@tonic-gate 	Mac	*mac;
4590Sstevel@tonic-gate 	u_int	 len;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	if (!altprivsep_started())
4620Sstevel@tonic-gate 		return;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	if (altprivsep_is_monitor())
4650Sstevel@tonic-gate 		return; /* shouldn't happen */
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	/* request new keys */
4680Sstevel@tonic-gate 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
4690Sstevel@tonic-gate 	altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ);
4700Sstevel@tonic-gate 	altprivsep_packet_put_int((u_int)mode);
4710Sstevel@tonic-gate 	altprivsep_packet_send();
4720Sstevel@tonic-gate 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
4730Sstevel@tonic-gate 	if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP)
4740Sstevel@tonic-gate 		fatal("Received garbage from monitor during re-keying");
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	newkeys = xmalloc(sizeof (*newkeys));
4770Sstevel@tonic-gate 	memset(newkeys, 0, sizeof (*newkeys));
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	enc = &newkeys->enc;
4800Sstevel@tonic-gate 	mac = &newkeys->mac;
4810Sstevel@tonic-gate 	comp = &newkeys->comp;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	/* Cipher name, key, IV */
4840Sstevel@tonic-gate 	enc->name = altprivsep_packet_get_string(NULL);
4850Sstevel@tonic-gate 	if ((enc->cipher = cipher_by_name(enc->name)) == NULL)
4860Sstevel@tonic-gate 		fatal("Monitor negotiated an unknown cipher during re-key");
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	enc->key = altprivsep_packet_get_string(&enc->key_len);
4890Sstevel@tonic-gate 	enc->iv = altprivsep_packet_get_string(&enc->block_size);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/* MAC name */
4920Sstevel@tonic-gate 	mac->name = altprivsep_packet_get_string(NULL);
4939486SJan.Pechanec@Sun.COM 	if (mac_setup(mac, mac->name) < 0)
4940Sstevel@tonic-gate 		fatal("Monitor negotiated an unknown MAC algorithm "
4950Sstevel@tonic-gate 			"during re-key");
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	mac->key = altprivsep_packet_get_string(&len);
4980Sstevel@tonic-gate 	if (len > mac->key_len)
4990Sstevel@tonic-gate 		fatal("%s: bad mac key length: %d > %d", __func__, len,
5000Sstevel@tonic-gate 			mac->key_len);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* Compression algorithm name */
5030Sstevel@tonic-gate 	comp->name = altprivsep_packet_get_string(NULL);
5040Sstevel@tonic-gate 	if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0)
5050Sstevel@tonic-gate 		fatal("Monitor negotiated an unknown compression "
5060Sstevel@tonic-gate 			"algorithm during re-key");
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	comp->type = 0;
5090Sstevel@tonic-gate 	comp->enabled = 0; /* forces compression re-init, as per-spec */
5100Sstevel@tonic-gate 	if (strcmp(comp->name, "zlib") == 0)
5110Sstevel@tonic-gate 		comp->type = 1;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * Now install new keys
5150Sstevel@tonic-gate 	 *
5160Sstevel@tonic-gate 	 * For now abuse kex.c/packet.c non-interfaces.  Someday, when
5170Sstevel@tonic-gate 	 * the many internal interfaces are parametrized, made reentrant
5180Sstevel@tonic-gate 	 * and thread-safe, made more consistent, and when necessary-but-
5190Sstevel@tonic-gate 	 * currently-missing interfaces are added then this bit of
5200Sstevel@tonic-gate 	 * ugliness can be revisited.
5210Sstevel@tonic-gate 	 *
5220Sstevel@tonic-gate 	 * The ugliness is in the set_newkeys(), its name and the lack
5230Sstevel@tonic-gate 	 * of a (Newkeys *) parameter, which forces us to pass the
5240Sstevel@tonic-gate 	 * newkeys through current_keys[mode].  But this saves us some
5250Sstevel@tonic-gate 	 * lines of code for now, though not comments.
5260Sstevel@tonic-gate 	 *
5270Sstevel@tonic-gate 	 * Also, we've abused, in the code above, knowledge of what
5280Sstevel@tonic-gate 	 * set_newkeys() expects the current_keys[mode] to contain.
5290Sstevel@tonic-gate 	 */
5300Sstevel@tonic-gate 	current_keys[mode] = newkeys;
5310Sstevel@tonic-gate 	set_newkeys(mode);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate void
altprivsep_record_login(pid_t pid,const char * ttyname)5360Sstevel@tonic-gate altprivsep_record_login(pid_t pid, const char *ttyname)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
5390Sstevel@tonic-gate 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN);
5400Sstevel@tonic-gate 	altprivsep_packet_put_int(pid);
5410Sstevel@tonic-gate 	altprivsep_packet_put_cstring(ttyname);
5420Sstevel@tonic-gate 	altprivsep_packet_send();
5430Sstevel@tonic-gate 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate void
altprivsep_record_logout(pid_t pid)5470Sstevel@tonic-gate altprivsep_record_logout(pid_t pid)
5480Sstevel@tonic-gate {
5490Sstevel@tonic-gate 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
5500Sstevel@tonic-gate 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT);
5510Sstevel@tonic-gate 	altprivsep_packet_put_int(pid);
5520Sstevel@tonic-gate 	altprivsep_packet_send();
5530Sstevel@tonic-gate 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5566375Sjp161948 void
altprivsep_start_rekex(void)5576375Sjp161948 altprivsep_start_rekex(void)
5586375Sjp161948 {
5596375Sjp161948 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
5606375Sjp161948 	altprivsep_packet_put_char(APS_MSG_START_REKEX);
5616375Sjp161948 	altprivsep_packet_send();
5626375Sjp161948 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
5636375Sjp161948 }
5646375Sjp161948 
5657574SJan.Pechanec@Sun.COM /*
5667574SJan.Pechanec@Sun.COM  * The monitor needs some information that its child learns during the
5677574SJan.Pechanec@Sun.COM  * authentication process. Since the child was forked before the key exchange
5687574SJan.Pechanec@Sun.COM  * and authentication started it must send some context to the monitor after the
5697574SJan.Pechanec@Sun.COM  * authentication is finished. Less obvious part - monitor needs the session ID
5707574SJan.Pechanec@Sun.COM  * since it is used in the key generation process after the key (re-)exchange is
5717574SJan.Pechanec@Sun.COM  * finished.
5727574SJan.Pechanec@Sun.COM  */
5737574SJan.Pechanec@Sun.COM void
altprivsep_send_auth_context(Authctxt * authctxt)5747574SJan.Pechanec@Sun.COM altprivsep_send_auth_context(Authctxt *authctxt)
5757574SJan.Pechanec@Sun.COM {
5767574SJan.Pechanec@Sun.COM 	debug("sending auth context to the monitor");
5777574SJan.Pechanec@Sun.COM 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
5787574SJan.Pechanec@Sun.COM 	altprivsep_packet_put_char(APS_MSG_AUTH_CONTEXT);
5797574SJan.Pechanec@Sun.COM 	altprivsep_packet_put_int(authctxt->pw->pw_uid);
5807574SJan.Pechanec@Sun.COM 	altprivsep_packet_put_int(authctxt->pw->pw_gid);
5817574SJan.Pechanec@Sun.COM 	altprivsep_packet_put_cstring(authctxt->pw->pw_name);
5827574SJan.Pechanec@Sun.COM 	altprivsep_packet_put_raw(session_id2, session_id2_len);
5837574SJan.Pechanec@Sun.COM 	debug("will send %d bytes of auth context to the monitor",
5847574SJan.Pechanec@Sun.COM 	    buffer_len(&to_monitor));
5857574SJan.Pechanec@Sun.COM 	altprivsep_packet_send();
5867574SJan.Pechanec@Sun.COM 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
5877574SJan.Pechanec@Sun.COM }
5887574SJan.Pechanec@Sun.COM 
5890Sstevel@tonic-gate static void aps_send_newkeys(void);
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */
5920Sstevel@tonic-gate /* ARGSUSED */
5930Sstevel@tonic-gate void
aps_input_altpriv_msg(int type,u_int32_t seq,void * ctxt)5940Sstevel@tonic-gate aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	u_char req_type;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	req_type = packet_get_char();
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	switch (req_type) {
6010Sstevel@tonic-gate 	case APS_MSG_NEWKEYS_REQ:
6020Sstevel@tonic-gate 		aps_send_newkeys();
6030Sstevel@tonic-gate 		break;
6040Sstevel@tonic-gate 	case APS_MSG_RECORD_LOGIN:
6050Sstevel@tonic-gate 		aps_record_login();
6060Sstevel@tonic-gate 		break;
6070Sstevel@tonic-gate 	case APS_MSG_RECORD_LOGOUT:
6080Sstevel@tonic-gate 		aps_record_logout();
6090Sstevel@tonic-gate 		break;
6106375Sjp161948 	case APS_MSG_START_REKEX:
6116375Sjp161948 		aps_start_rekex();
6126375Sjp161948 		break;
6130Sstevel@tonic-gate 	default:
6140Sstevel@tonic-gate 		break;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /* Monitor-side handlers for APS_MSG_* */
6190Sstevel@tonic-gate static
6200Sstevel@tonic-gate void
aps_send_newkeys(void)6210Sstevel@tonic-gate aps_send_newkeys(void)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate 	Newkeys *newkeys;
6240Sstevel@tonic-gate 	Enc *enc;
6250Sstevel@tonic-gate 	Mac *mac;
6260Sstevel@tonic-gate 	Comp *comp;
6270Sstevel@tonic-gate 	enum kex_modes mode;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/* get direction for which newkeys are wanted */
6300Sstevel@tonic-gate 	mode = (enum kex_modes) packet_get_int();
6310Sstevel@tonic-gate 	packet_check_eom();
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	/* get those newkeys */
6340Sstevel@tonic-gate 	newkeys = kex_get_newkeys(mode);
6350Sstevel@tonic-gate 	enc = &newkeys->enc;
6360Sstevel@tonic-gate 	mac = &newkeys->mac;
6370Sstevel@tonic-gate 	comp = &newkeys->comp;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/*
6400Sstevel@tonic-gate 	 * Negotiated algorithms, client->server and server->client, for
6410Sstevel@tonic-gate 	 * cipher, mac and compression.
6420Sstevel@tonic-gate 	 */
6430Sstevel@tonic-gate 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
6440Sstevel@tonic-gate 	packet_put_char(APS_MSG_NEWKEYS_REP);
6450Sstevel@tonic-gate 	packet_put_cstring(enc->name);
6460Sstevel@tonic-gate 	packet_put_string(enc->key, enc->key_len);
6470Sstevel@tonic-gate 	packet_put_string(enc->iv, enc->block_size);
6480Sstevel@tonic-gate 	packet_put_cstring(mac->name);
6490Sstevel@tonic-gate 	packet_put_string(mac->key, mac->key_len);
6500Sstevel@tonic-gate 	packet_put_cstring(comp->name);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	packet_send();
6535562Sjp161948 	free_keys(newkeys);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate struct _aps_login_rec {
6570Sstevel@tonic-gate 	pid_t			lr_pid;
6580Sstevel@tonic-gate 	char			*lr_tty;
6590Sstevel@tonic-gate 	struct _aps_login_rec	*next;
6600Sstevel@tonic-gate };
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate typedef struct _aps_login_rec aps_login_rec;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate static aps_login_rec *aps_login_list = NULL;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate static
6670Sstevel@tonic-gate void
aps_record_login(void)6680Sstevel@tonic-gate aps_record_login(void)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	aps_login_rec	*new_rec;
6710Sstevel@tonic-gate 	struct stat	 sbuf;
6720Sstevel@tonic-gate 	size_t		 proc_path_len;
6730Sstevel@tonic-gate 	char		*proc_path;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	new_rec = xmalloc(sizeof (aps_login_rec));
6760Sstevel@tonic-gate 	memset(new_rec, 0, sizeof (aps_login_rec));
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	new_rec->lr_pid = packet_get_int();
6790Sstevel@tonic-gate 	new_rec->lr_tty = packet_get_string(NULL);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid);
6820Sstevel@tonic-gate 	proc_path = xmalloc(proc_path_len + 1);
6830Sstevel@tonic-gate 	(void) snprintf(proc_path, proc_path_len + 1, "/proc/%d",
6840Sstevel@tonic-gate 			new_rec->lr_pid);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	if (stat(proc_path, &sbuf) ||
6870Sstevel@tonic-gate 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid ||
6880Sstevel@tonic-gate 	    stat(new_rec->lr_tty, &sbuf) < 0 ||
6890Sstevel@tonic-gate 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid) {
6900Sstevel@tonic-gate 		debug2("Spurious record_login request from unprivileged sshd");
6910Sstevel@tonic-gate 		xfree(proc_path);
6920Sstevel@tonic-gate 		xfree(new_rec->lr_tty);
6930Sstevel@tonic-gate 		xfree(new_rec);
6940Sstevel@tonic-gate 		return;
6950Sstevel@tonic-gate 	}
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	/* Insert new record on list */
6980Sstevel@tonic-gate 	new_rec->next = aps_login_list;
6990Sstevel@tonic-gate 	aps_login_list = new_rec;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	record_login(new_rec->lr_pid, new_rec->lr_tty, NULL,
7020Sstevel@tonic-gate 		xxx_authctxt->user);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
7050Sstevel@tonic-gate 	packet_send();
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	xfree(proc_path);
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate static
7110Sstevel@tonic-gate void
aps_record_logout(void)7120Sstevel@tonic-gate aps_record_logout(void)
7130Sstevel@tonic-gate {
7140Sstevel@tonic-gate 	aps_login_rec	**p, *q;
7150Sstevel@tonic-gate 	pid_t		 pid;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	pid = packet_get_int();
7180Sstevel@tonic-gate 	packet_check_eom();
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	for (p = &aps_login_list; *p != NULL; p = &q->next) {
7210Sstevel@tonic-gate 		q = *p;
7220Sstevel@tonic-gate 		if (q->lr_pid == pid) {
7230Sstevel@tonic-gate 			record_logout(q->lr_pid, q->lr_tty, NULL,
7240Sstevel@tonic-gate 				xxx_authctxt->user);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 			/* dequeue */
7270Sstevel@tonic-gate 			*p = q->next;
7280Sstevel@tonic-gate 			xfree(q->lr_tty);
7290Sstevel@tonic-gate 			xfree(q);
7300Sstevel@tonic-gate 			break;
7310Sstevel@tonic-gate 		}
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
7350Sstevel@tonic-gate 	packet_send();
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate 
7386375Sjp161948 static
7396375Sjp161948 void
aps_start_rekex(void)7406375Sjp161948 aps_start_rekex(void)
7416375Sjp161948 {
7426375Sjp161948 	/*
7436375Sjp161948 	 * Send confirmation. We could implement it without that but it doesn't
7446375Sjp161948 	 * bring any harm to do that and we are consistent with other subtypes
7456375Sjp161948 	 * of our private SSH2_PRIV_MSG_ALTPRIVSEP message type.
7466375Sjp161948 	 */
7476375Sjp161948 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
7486375Sjp161948 	packet_send();
7496375Sjp161948 
7506375Sjp161948 	/*
7516375Sjp161948 	 * KEX_INIT message could be the one that reached the limit. In that
7526375Sjp161948 	 * case, it was already forwarded to us from the unnprivileged child,
7536375Sjp161948 	 * and maybe even acted upon. Obviously we must not send another
7546375Sjp161948 	 * KEX_INIT message.
7556375Sjp161948 	 */
7566375Sjp161948 	if (!(xxx_kex->flags & KEX_INIT_SENT))
7576375Sjp161948 		kex_send_kexinit(xxx_kex);
7586375Sjp161948 	else
7596375Sjp161948 		debug2("rekeying already in progress");
7606375Sjp161948 }
7616375Sjp161948 
7627574SJan.Pechanec@Sun.COM /*
7637574SJan.Pechanec@Sun.COM  * This is the monitor side of altprivsep_send_auth_context().
7647574SJan.Pechanec@Sun.COM  */
7657574SJan.Pechanec@Sun.COM Authctxt *
aps_read_auth_context(void)7667574SJan.Pechanec@Sun.COM aps_read_auth_context(void)
7677574SJan.Pechanec@Sun.COM {
7687574SJan.Pechanec@Sun.COM 	unsigned char *tmp;
7697574SJan.Pechanec@Sun.COM 	Authctxt *authctxt;
7707574SJan.Pechanec@Sun.COM 
7717574SJan.Pechanec@Sun.COM 	/*
7727574SJan.Pechanec@Sun.COM 	 * After the successful authentication we get the context. Getting
7737574SJan.Pechanec@Sun.COM 	 * end-of-file means that authentication failed and we can exit as well.
7747574SJan.Pechanec@Sun.COM 	 */
7757574SJan.Pechanec@Sun.COM 	debug("reading the context from the child");
7767574SJan.Pechanec@Sun.COM 	packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
7777574SJan.Pechanec@Sun.COM 	debug3("got SSH2_PRIV_MSG_ALTPRIVSEP");
7787574SJan.Pechanec@Sun.COM 	if (packet_get_char() != APS_MSG_AUTH_CONTEXT) {
7797574SJan.Pechanec@Sun.COM 		fatal("APS_MSG_AUTH_CONTEXT message subtype expected.");
7807574SJan.Pechanec@Sun.COM 	}
7817574SJan.Pechanec@Sun.COM 
7827574SJan.Pechanec@Sun.COM 	authctxt = xcalloc(1, sizeof(Authctxt));
7837574SJan.Pechanec@Sun.COM 	authctxt->pw = xcalloc(1, sizeof(struct passwd));
7847574SJan.Pechanec@Sun.COM 
7857574SJan.Pechanec@Sun.COM 	/* uid_t and gid_t are integers (UNIX spec) */
7867574SJan.Pechanec@Sun.COM 	authctxt->pw->pw_uid = packet_get_int();
7877574SJan.Pechanec@Sun.COM 	authctxt->pw->pw_gid = packet_get_int();
7887574SJan.Pechanec@Sun.COM 	authctxt->pw->pw_name = packet_get_string(NULL);
7897574SJan.Pechanec@Sun.COM 	authctxt->user = xstrdup(authctxt->pw->pw_name);
7907574SJan.Pechanec@Sun.COM 	debug3("uid/gid/username %d/%d/%s", authctxt->pw->pw_uid,
7917574SJan.Pechanec@Sun.COM 	    authctxt->pw->pw_gid, authctxt->user);
7927574SJan.Pechanec@Sun.COM 	session_id2 = (unsigned char *)packet_get_raw((unsigned int*)&session_id2_len);
7937574SJan.Pechanec@Sun.COM 
7947574SJan.Pechanec@Sun.COM 	/* we don't have this for SSH1. In that case, session_id2_len is 0. */
7957574SJan.Pechanec@Sun.COM 	if (session_id2_len > 0) {
7967574SJan.Pechanec@Sun.COM 		tmp = (unsigned char *)xmalloc(session_id2_len);
7977574SJan.Pechanec@Sun.COM 		memcpy(tmp, session_id2, session_id2_len);
7987574SJan.Pechanec@Sun.COM 		session_id2 = tmp;
7997574SJan.Pechanec@Sun.COM 		debug3("read session ID (%d B)", session_id2_len);
8007574SJan.Pechanec@Sun.COM 		xxx_kex->session_id = tmp;
8017574SJan.Pechanec@Sun.COM 		xxx_kex->session_id_len = session_id2_len;
8027574SJan.Pechanec@Sun.COM 	}
8037574SJan.Pechanec@Sun.COM 	debug("finished reading the context");
8047574SJan.Pechanec@Sun.COM 
8057574SJan.Pechanec@Sun.COM 	/* send confirmation */
8067574SJan.Pechanec@Sun.COM 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
8077574SJan.Pechanec@Sun.COM 	packet_send();
8087574SJan.Pechanec@Sun.COM 
8097574SJan.Pechanec@Sun.COM 	return (authctxt);
8107574SJan.Pechanec@Sun.COM }
8117574SJan.Pechanec@Sun.COM 
8126375Sjp161948 
8130Sstevel@tonic-gate /* Utilities for communication with the monitor */
8147574SJan.Pechanec@Sun.COM static void
altprivsep_packet_start(u_char type)8150Sstevel@tonic-gate altprivsep_packet_start(u_char type)
8160Sstevel@tonic-gate {
8170Sstevel@tonic-gate 	buffer_clear(&to_monitor);
8180Sstevel@tonic-gate 	buffer_put_char(&to_monitor, type);
8190Sstevel@tonic-gate }
8207574SJan.Pechanec@Sun.COM 
8217574SJan.Pechanec@Sun.COM static void
altprivsep_packet_put_char(int ch)8220Sstevel@tonic-gate altprivsep_packet_put_char(int ch)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	buffer_put_char(&to_monitor, ch);
8250Sstevel@tonic-gate }
8267574SJan.Pechanec@Sun.COM 
8277574SJan.Pechanec@Sun.COM static void
altprivsep_packet_put_int(u_int value)8280Sstevel@tonic-gate altprivsep_packet_put_int(u_int value)
8290Sstevel@tonic-gate {
8300Sstevel@tonic-gate 	buffer_put_int(&to_monitor, value);
8310Sstevel@tonic-gate }
8327574SJan.Pechanec@Sun.COM 
8337574SJan.Pechanec@Sun.COM static void
altprivsep_packet_put_cstring(const char * str)8340Sstevel@tonic-gate altprivsep_packet_put_cstring(const char *str)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	buffer_put_cstring(&to_monitor, str);
8370Sstevel@tonic-gate }
8387574SJan.Pechanec@Sun.COM 
8397574SJan.Pechanec@Sun.COM static void
altprivsep_packet_put_raw(const void * buf,u_int len)8400Sstevel@tonic-gate altprivsep_packet_put_raw(const void *buf, u_int len)
8410Sstevel@tonic-gate {
8420Sstevel@tonic-gate 	buffer_append(&to_monitor, buf, len);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate /*
8460Sstevel@tonic-gate  * Send a monitor packet to the monitor.  This function is blocking.
8470Sstevel@tonic-gate  *
8480Sstevel@tonic-gate  * Returns -1 if the monitor pipe has been closed earlier, fatal()s if
8490Sstevel@tonic-gate  * there's any other problems.
8500Sstevel@tonic-gate  */
8517574SJan.Pechanec@Sun.COM static int
altprivsep_packet_send(void)8520Sstevel@tonic-gate altprivsep_packet_send(void)
8530Sstevel@tonic-gate {
8540Sstevel@tonic-gate 	ssize_t len;
8550Sstevel@tonic-gate 	u_int32_t plen;	/* packet length */
8560Sstevel@tonic-gate 	u_char	plen_buf[sizeof (plen)];
8570Sstevel@tonic-gate 	u_char padlen;	/* padding length */
8580Sstevel@tonic-gate 	fd_set *setp;
859*12551SZdenek.Kotala@Sun.COM 	int err;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (pipe_fd == -1)
8620Sstevel@tonic-gate 		return (-1);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	if ((plen = buffer_len(&to_monitor)) == 0)
8650Sstevel@tonic-gate 		return (0);
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * We talk the SSHv2 binary packet protocol to the monitor,
8690Sstevel@tonic-gate 	 * using the none cipher, mac and compression algorithms.
8700Sstevel@tonic-gate 	 *
8710Sstevel@tonic-gate 	 * But, interestingly, the none cipher has a block size of 8
8720Sstevel@tonic-gate 	 * bytes, thus we must pad the packet.
8730Sstevel@tonic-gate 	 *
8740Sstevel@tonic-gate 	 * Also, encryption includes the packet length, so the padding
8750Sstevel@tonic-gate 	 * must account for that field.  I.e., (sizeof (packet length) +
8760Sstevel@tonic-gate 	 * sizeof (padding length) + packet length + padding length) %
8770Sstevel@tonic-gate 	 * block_size must == 0.
8780Sstevel@tonic-gate 	 *
8790Sstevel@tonic-gate 	 * Also, there must be at least four (4) bytes of padding.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8;
8820Sstevel@tonic-gate 	if (padlen < 4)
8830Sstevel@tonic-gate 		padlen += 8;
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/* packet length counts padding and padding length field */
8860Sstevel@tonic-gate 	plen += padlen + sizeof (padlen);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	PUT_32BIT(plen_buf, plen);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
8910Sstevel@tonic-gate 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
8920Sstevel@tonic-gate 	FD_SET(pipe_fd, setp);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) {
8950Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR)
8960Sstevel@tonic-gate 			continue;
8970Sstevel@tonic-gate 		else
8980Sstevel@tonic-gate 			goto pipe_gone;
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	xfree(setp);
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/* packet length field */
9040Sstevel@tonic-gate 	len = atomicio(write, pipe_fd, plen_buf, sizeof (plen));
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (len != sizeof (plen))
9070Sstevel@tonic-gate 		goto pipe_gone;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	/* padding length field */
9100Sstevel@tonic-gate 	len = atomicio(write, pipe_fd, &padlen, sizeof (padlen));
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	if (len != sizeof (padlen))
9130Sstevel@tonic-gate 		goto pipe_gone;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	if (len != (plen - 1))
9180Sstevel@tonic-gate 		goto pipe_gone;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	buffer_clear(&to_monitor);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	return (1);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate pipe_gone:
925*12551SZdenek.Kotala@Sun.COM 
926*12551SZdenek.Kotala@Sun.COM 	err = errno;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	(void) close(pipe_fd);
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	pipe_fd = -1;
9310Sstevel@tonic-gate 
932*12551SZdenek.Kotala@Sun.COM 	fatal("altprvsep_packet_send: Monitor not responding: %.100s",
933*12551SZdenek.Kotala@Sun.COM 	    strerror(err));
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/* NOTREACHED */
9360Sstevel@tonic-gate 	return (0);
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate /*
9400Sstevel@tonic-gate  * Read a monitor packet from the monitor.  This function is blocking.
9410Sstevel@tonic-gate  */
9427574SJan.Pechanec@Sun.COM static int
altprivsep_packet_read(void)9430Sstevel@tonic-gate altprivsep_packet_read(void)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	ssize_t len = -1;
9460Sstevel@tonic-gate 	u_int32_t plen;
9470Sstevel@tonic-gate 	u_char plen_buf[sizeof (plen)];
9480Sstevel@tonic-gate 	u_char padlen;
9490Sstevel@tonic-gate 	fd_set *setp;
950*12551SZdenek.Kotala@Sun.COM 	int err;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	if (pipe_fd == -1)
9530Sstevel@tonic-gate 		return (-1);
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
9560Sstevel@tonic-gate 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
9570Sstevel@tonic-gate 	FD_SET(pipe_fd, setp);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) {
9600Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR)
9610Sstevel@tonic-gate 			continue;
9620Sstevel@tonic-gate 		else
9630Sstevel@tonic-gate 			goto pipe_gone;
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	xfree(setp);
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	/* packet length field */
9690Sstevel@tonic-gate 	len = atomicio(read, pipe_fd, plen_buf, sizeof (plen));
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	plen = GET_32BIT(plen_buf);
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	if (len != sizeof (plen))
9740Sstevel@tonic-gate 		goto pipe_gone;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	/* padding length field */
9770Sstevel@tonic-gate 	len = atomicio(read, pipe_fd, &padlen, sizeof (padlen));
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	if (len != sizeof (padlen))
9800Sstevel@tonic-gate 		goto pipe_gone;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	plen -= sizeof (padlen);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	buffer_clear(&from_monitor);
9850Sstevel@tonic-gate 	buffer_append_space(&from_monitor, plen);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/* packet data + padding */
9880Sstevel@tonic-gate 	len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	if (len != plen)
9910Sstevel@tonic-gate 		goto pipe_gone;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	/* remove padding */
9940Sstevel@tonic-gate 	if (padlen > 0)
9950Sstevel@tonic-gate 		buffer_consume_end(&from_monitor, padlen);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	/* packet type */
9980Sstevel@tonic-gate 	return (buffer_get_char(&from_monitor));
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate pipe_gone:
10010Sstevel@tonic-gate 
1002*12551SZdenek.Kotala@Sun.COM 	err = errno;
1003*12551SZdenek.Kotala@Sun.COM 
10040Sstevel@tonic-gate 	(void) close(pipe_fd);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	pipe_fd = -1;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	if (len < 0)
1009*12551SZdenek.Kotala@Sun.COM 		fatal("altpriv_packet_read: Monitor not responding %.100s",
1010*12551SZdenek.Kotala@Sun.COM 		    strerror(err));
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	debug2("Monitor pipe closed by monitor");
10130Sstevel@tonic-gate 	return (0);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10167574SJan.Pechanec@Sun.COM static void
altprivsep_packet_read_expect(int expected)10170Sstevel@tonic-gate altprivsep_packet_read_expect(int expected)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate 	int type;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	type = altprivsep_packet_read();
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	if (type <= 0)
1024*12551SZdenek.Kotala@Sun.COM 		fatal("altprivsep_packet_read_expect: Monitor not responding");
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	if (type != expected)
10270Sstevel@tonic-gate 		fatal("Protocol error in privilege separation; expected "
10280Sstevel@tonic-gate 			"packet type %d, got %d", expected, type);
10290Sstevel@tonic-gate }
10300Sstevel@tonic-gate 
10317574SJan.Pechanec@Sun.COM static u_int
altprivsep_packet_get_char(void)10320Sstevel@tonic-gate altprivsep_packet_get_char(void)
10330Sstevel@tonic-gate {
10340Sstevel@tonic-gate 	return (buffer_get_char(&from_monitor));
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate void
altprivsep_packet_get_raw(u_int * length_ptr)10370Sstevel@tonic-gate *altprivsep_packet_get_raw(u_int *length_ptr)
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	if (length_ptr != NULL)
10400Sstevel@tonic-gate 		*length_ptr = buffer_len(&from_monitor);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	return (buffer_ptr(&from_monitor));
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate void
altprivsep_packet_get_string(u_int * length_ptr)10450Sstevel@tonic-gate *altprivsep_packet_get_string(u_int *length_ptr)
10460Sstevel@tonic-gate {
10470Sstevel@tonic-gate 	return (buffer_get_string(&from_monitor, length_ptr));
10480Sstevel@tonic-gate }
10497574SJan.Pechanec@Sun.COM 
105010515SJan.Pechanec@Sun.COM /*
105110515SJan.Pechanec@Sun.COM  * Start and execute the code for the monitor which never returns from this
105210515SJan.Pechanec@Sun.COM  * function. The child will return and continue in the caller.
105310515SJan.Pechanec@Sun.COM  */
10547574SJan.Pechanec@Sun.COM void
altprivsep_start_and_do_monitor(int use_engine,int inetd,int newsock,int statup_pipe)10557574SJan.Pechanec@Sun.COM altprivsep_start_and_do_monitor(int use_engine, int inetd, int newsock,
10567574SJan.Pechanec@Sun.COM 	int statup_pipe)
10577574SJan.Pechanec@Sun.COM {
10587574SJan.Pechanec@Sun.COM 	pid_t aps_child;
10597574SJan.Pechanec@Sun.COM 	Authctxt *authctxt;
10607574SJan.Pechanec@Sun.COM 
10617574SJan.Pechanec@Sun.COM 	/*
10627574SJan.Pechanec@Sun.COM 	 * The monitor will packet_close() in packet_set_monitor() called from
10637574SJan.Pechanec@Sun.COM 	 * altprivsep_start_monitor() below to clean up the socket stuff before
10647574SJan.Pechanec@Sun.COM 	 * it switches to pipes for communication to the child. The socket fd is
10657574SJan.Pechanec@Sun.COM 	 * closed there so we must dup it here - monitor needs that socket to
10667574SJan.Pechanec@Sun.COM 	 * shutdown the connection in case of any problem; see comments below.
10677574SJan.Pechanec@Sun.COM 	 * Note that current newsock was assigned to connection_(in|out) which
10687574SJan.Pechanec@Sun.COM 	 * are the variables used in packet_close() to close the communication
10697574SJan.Pechanec@Sun.COM 	 * socket.
10707574SJan.Pechanec@Sun.COM 	 */
10717574SJan.Pechanec@Sun.COM 	newsock = dup(newsock);
10727574SJan.Pechanec@Sun.COM 
10737574SJan.Pechanec@Sun.COM 	if ((aps_child = altprivsep_start_monitor(&authctxt)) == -1)
10747574SJan.Pechanec@Sun.COM 		fatal("Monitor could not be started.");
10757574SJan.Pechanec@Sun.COM 
10767574SJan.Pechanec@Sun.COM 	if (aps_child > 0) {
10777574SJan.Pechanec@Sun.COM 		/* ALTPRIVSEP Monitor */
10787574SJan.Pechanec@Sun.COM 
10797574SJan.Pechanec@Sun.COM 		/*
10807574SJan.Pechanec@Sun.COM 		 * The ALTPRIVSEP monitor here does:
10817574SJan.Pechanec@Sun.COM 		 *
10827574SJan.Pechanec@Sun.COM 		 *  - record keeping and auditing
10837574SJan.Pechanec@Sun.COM 		 *  - PAM cleanup
10847574SJan.Pechanec@Sun.COM 		 */
10857574SJan.Pechanec@Sun.COM 
10867574SJan.Pechanec@Sun.COM 		/* this is for MaxStartups and the child takes care of that */
10877574SJan.Pechanec@Sun.COM 		(void) close(statup_pipe);
10887574SJan.Pechanec@Sun.COM 		(void) pkcs11_engine_load(use_engine);
10897574SJan.Pechanec@Sun.COM 
10907574SJan.Pechanec@Sun.COM 		/*
10917574SJan.Pechanec@Sun.COM 		 * If the monitor fatal()s it will audit/record a logout, so
10927574SJan.Pechanec@Sun.COM 		 * we'd better do something to really mean it: shutdown the
10937574SJan.Pechanec@Sun.COM 		 * socket but leave the child alone -- it's been disconnected
10947574SJan.Pechanec@Sun.COM 		 * and we hope it exits, but killing any pid from a privileged
10957574SJan.Pechanec@Sun.COM 		 * monitor could be dangerous.
10967574SJan.Pechanec@Sun.COM 		 *
10977574SJan.Pechanec@Sun.COM 		 * NOTE: Order matters -- these fatal cleanups must come before
10987574SJan.Pechanec@Sun.COM 		 * the audit logout fatal cleanup as these functions are called
10997574SJan.Pechanec@Sun.COM 		 * in LIFO.
11007574SJan.Pechanec@Sun.COM 		 */
11017574SJan.Pechanec@Sun.COM 		fatal_add_cleanup((void (*)(void *))altprivsep_shutdown_sock,
11027574SJan.Pechanec@Sun.COM 			(void *)&newsock);
11037574SJan.Pechanec@Sun.COM 
11047574SJan.Pechanec@Sun.COM 		if (compat20) {
11057574SJan.Pechanec@Sun.COM 			debug3("Recording SSHv2 session login in wtmpx");
11067574SJan.Pechanec@Sun.COM 			/*
11077574SJan.Pechanec@Sun.COM 			 * record_login() relies on connection_in to be the
11087574SJan.Pechanec@Sun.COM 			 * socket to get the peer address. The problem is that
11097574SJan.Pechanec@Sun.COM 			 * connection_in had to be set to the pipe descriptor in
11107574SJan.Pechanec@Sun.COM 			 * altprivsep_start_monitor(). It's not nice but the
11117574SJan.Pechanec@Sun.COM 			 * easiest way to get the peer's address is to
11127574SJan.Pechanec@Sun.COM 			 * temporarily set connection_in to the socket's file
11137574SJan.Pechanec@Sun.COM 			 * descriptor.
11147574SJan.Pechanec@Sun.COM 			 */
11157574SJan.Pechanec@Sun.COM 			packet_set_fds(inetd == 1 ? -1 : newsock, 0);
11167574SJan.Pechanec@Sun.COM 			record_login(getpid(), NULL, "sshd", authctxt->user);
11177574SJan.Pechanec@Sun.COM 			packet_set_fds(0, 1);
11187574SJan.Pechanec@Sun.COM 		}
11197574SJan.Pechanec@Sun.COM 
11207574SJan.Pechanec@Sun.COM #ifdef HAVE_BSM
11217574SJan.Pechanec@Sun.COM 		/* Initialize the group list, audit sometimes needs it. */
11227574SJan.Pechanec@Sun.COM 		if (initgroups(authctxt->pw->pw_name,
11237574SJan.Pechanec@Sun.COM 		    authctxt->pw->pw_gid) < 0) {
11247574SJan.Pechanec@Sun.COM 			perror("initgroups");
11257574SJan.Pechanec@Sun.COM 			exit (1);
11267574SJan.Pechanec@Sun.COM 		}
11277574SJan.Pechanec@Sun.COM 
11288064SBrent.Paulson@Sun.COM 		/*
11298064SBrent.Paulson@Sun.COM 		 * The monitor process fork()ed before the authentication
11308064SBrent.Paulson@Sun.COM 		 * process started so at this point we have an unaudited
11318064SBrent.Paulson@Sun.COM 		 * context.  Thus we need to obtain the audit session data
11328064SBrent.Paulson@Sun.COM 		 * from the authentication process (aps_child) which will
11338064SBrent.Paulson@Sun.COM 		 * have the correct audit context for the user logging in.
11348064SBrent.Paulson@Sun.COM 		 * To do so we pass along the process-ID of the aps_child
11358064SBrent.Paulson@Sun.COM 		 * process so that it is referenced for this audit session
11368064SBrent.Paulson@Sun.COM 		 * rather than referencing the monitor's unaudited context.
11378064SBrent.Paulson@Sun.COM 		 */
11388064SBrent.Paulson@Sun.COM 		audit_sshd_login(&ah, aps_child);
11397574SJan.Pechanec@Sun.COM 
11407574SJan.Pechanec@Sun.COM 		fatal_add_cleanup((void (*)(void *))audit_sshd_logout,
11418064SBrent.Paulson@Sun.COM 		    (void *)&ah);
11427574SJan.Pechanec@Sun.COM #endif /* HAVE_BSM */
11437574SJan.Pechanec@Sun.COM 
11447574SJan.Pechanec@Sun.COM #ifdef GSSAPI
11457574SJan.Pechanec@Sun.COM 		fatal_add_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds,
11467574SJan.Pechanec@Sun.COM 			(void *)&xxx_gssctxt);
11477574SJan.Pechanec@Sun.COM #endif /* GSSAPI */
11487574SJan.Pechanec@Sun.COM 
11497574SJan.Pechanec@Sun.COM 		altprivsep_do_monitor(authctxt, aps_child);
11507574SJan.Pechanec@Sun.COM 
11517574SJan.Pechanec@Sun.COM 		/* If we got here the connection is dead. */
11527574SJan.Pechanec@Sun.COM 		fatal_remove_cleanup((void (*)(void *))altprivsep_shutdown_sock,
11537574SJan.Pechanec@Sun.COM 			(void *)&newsock);
11547574SJan.Pechanec@Sun.COM 
11557574SJan.Pechanec@Sun.COM 		if (compat20) {
11567574SJan.Pechanec@Sun.COM 			debug3("Recording SSHv2 session logout in wtmpx");
11577574SJan.Pechanec@Sun.COM 			record_logout(getpid(), NULL, "sshd", authctxt->user);
11587574SJan.Pechanec@Sun.COM 		}
11597574SJan.Pechanec@Sun.COM 
11607574SJan.Pechanec@Sun.COM 		/*
11617574SJan.Pechanec@Sun.COM 		 * Make sure the socket is closed. The monitor can't call
11627574SJan.Pechanec@Sun.COM 		 * packet_close here as it's done a packet_set_connection()
11637574SJan.Pechanec@Sun.COM 		 * with the pipe to the child instead of the socket.
11647574SJan.Pechanec@Sun.COM 		 */
11657574SJan.Pechanec@Sun.COM 		(void) shutdown(newsock, SHUT_RDWR);
11667574SJan.Pechanec@Sun.COM 
11677574SJan.Pechanec@Sun.COM #ifdef GSSAPI
11687574SJan.Pechanec@Sun.COM 		fatal_remove_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds,
11697574SJan.Pechanec@Sun.COM 			&xxx_gssctxt);
11707574SJan.Pechanec@Sun.COM 		ssh_gssapi_cleanup_creds(xxx_gssctxt);
11717574SJan.Pechanec@Sun.COM 		ssh_gssapi_server_mechs(NULL); /* release cached mechs list */
11727574SJan.Pechanec@Sun.COM #endif /* GSSAPI */
11737574SJan.Pechanec@Sun.COM 
11747574SJan.Pechanec@Sun.COM #ifdef HAVE_BSM
11757574SJan.Pechanec@Sun.COM 		fatal_remove_cleanup((void (*)(void *))audit_sshd_logout, (void *)&ah);
11767574SJan.Pechanec@Sun.COM 		audit_sshd_logout(&ah);
11777574SJan.Pechanec@Sun.COM #endif /* HAVE_BSM */
11787574SJan.Pechanec@Sun.COM 
11797574SJan.Pechanec@Sun.COM 		exit(0);
11807574SJan.Pechanec@Sun.COM 	} else {
11817574SJan.Pechanec@Sun.COM 		/*
11827574SJan.Pechanec@Sun.COM 		 * This is the child, close the dup()ed file descriptor for a
11837574SJan.Pechanec@Sun.COM 		 * socket. It's not needed in the child.
11847574SJan.Pechanec@Sun.COM 		 */
11857574SJan.Pechanec@Sun.COM 		close(newsock);
11867574SJan.Pechanec@Sun.COM 	}
11877574SJan.Pechanec@Sun.COM }
1188