Home | History | Annotate | Download | only in sshd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  *
     21  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     22  * Use is subject to license terms.
     23  */
     24 
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 #include "includes.h"
     28 #include "atomicio.h"
     29 #include "auth.h"
     30 #include "bufaux.h"
     31 #include "buffer.h"
     32 #include "cipher.h"
     33 #include "compat.h"
     34 #include "dispatch.h"
     35 #include "getput.h"
     36 #include "kex.h"
     37 #include "log.h"
     38 #include "mac.h"
     39 #include "packet.h"
     40 #include "uidswap.h"
     41 #include "ssh2.h"
     42 #include "sshlogin.h"
     43 #include "xmalloc.h"
     44 #include "altprivsep.h"
     45 #include <fcntl.h>
     46 #include <sys/types.h>
     47 #include <sys/types.h>
     48 #include <sys/stat.h>
     49 #include <sys/socket.h>
     50 
     51 extern Kex *xxx_kex;
     52 
     53 static Buffer to_monitor;
     54 static Buffer from_monitor;
     55 
     56 /*
     57  * Sun's Alternative Privilege Separation basics:
     58  *
     59  * Abstract
     60  * --------
     61  *
     62  * sshd(1M) fork()s and drops privs in the child while retaining privs
     63  * in the parent (a.k.a., the monitor).  The unprivileged sshd and the
     64  * monitor talk over a pipe using a simple protocol.
     65  *
     66  * The monitor protocol is all about having the monitor carry out the
     67  * only operations that require privileges OR access to privileged
     68  * resources.  These are: utmpx/wtmpx record keeping, auditing, and
     69  * SSHv2 re-keying.
     70  *
     71  * Re-Keying
     72  * ---------
     73  *
     74  * Re-keying is the only protocol version specific aspect of sshd in
     75  * which the monitor gets involved.
     76  *
     77  * The monitor processes all SSHv2 re-key protocol packets, but the
     78  * unprivileged sshd process does the transport layer crypto for those
     79  * packets.
     80  *
     81  * The monitor and its unprivileged sshd child process treat
     82  * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call
     83  * set_newkeys(), but b) the child asks the monitor for the set of
     84  * negotiated algorithms, key, IV and what not for the relevant
     85  * transport direction and then calls set_newkeys().
     86  *
     87  * Monitor Protocol
     88  * ----------------
     89  *
     90  * Monitor IPC message formats are similar to SSHv2 messages, minus
     91  * compression, encryption, padding and MACs:
     92  *
     93  *  - 4 octet message length
     94  *  - message data
     95  *     - 1 octet message type
     96  *     - message data
     97  *
     98  * In broad strokes:
     99  *
    100  *  - IPC: pipe, exit(2)/wait4(2)
    101  *
    102  *  - threads: the monitor and child are single-threaded
    103  *
    104  *  - monitor main loop: a variant of server_loop2(), for re-keying only
    105  *  - unpriv child main loop: server_loop2(), as usual
    106  *
    107  *  - protocol:
    108  *     - key exchange packets are always forwarded as is to the monitor
    109  *     - newkeys, record_login(), record_logout() are special packets
    110  *     using the packet type range reserved for local extensions
    111  *
    112  *  - the child drops privs and runs like a normal sshd, except that it
    113  *  sets dispatch handlers for key exchange packets that forward the
    114  *  packets to the monitor
    115  *
    116  * Event loops:
    117  *
    118  *  - all monitor protocols are synchronous: because the SSHv2 rekey
    119  *  protocols are synchronous and because the other monitor operations
    120  *  are synchronous (or have no replies),
    121  *
    122  *  - server_loop2() is modified to check the monitor pipe for rekey
    123  *  packets to forward to the client
    124  *
    125  *  - and dispatch handlers are set, upon receipt of KEXINIT (and reset
    126  *  when NEWKEYS is sent out) to forward incoming rekey packets to the
    127  *  monitor.
    128  *
    129  *  - the monitor runs an event loop not unlike server_loop2() and runs
    130  *  key exchanges almost exactly as a pre-altprivsep sshd would
    131  *
    132  *  - unpriv sshd exit -> monitor cleanup (including audit logout) and exit
    133  *
    134  *  - fatal() in monitor -> forcibly shutdown() socket and kill/wait for
    135  *  child (so that the audit event for the logout better reflects
    136  *  reality -- i.e., logged out means logged out, but for bg jobs)
    137  *
    138  * Message formats:
    139  *
    140  *  - key exchange packets/replies forwarded "as is"
    141  *
    142  *  - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a
    143  *  sub-type identifier (one octet)
    144  *  - private request sub-types include:
    145  *     - get new shared secret from last re-key
    146  *     - record login  (utmpx/wtmpx), request data contains three arguments:
    147  *     pid, ttyname, program name
    148  *     - record logout (utmpx/wtmpx), request data contains one argument: pid
    149  *
    150  * Reply sub-types include:
    151  *
    152  *  - NOP (for record_login/logout)
    153  *  - new shared secret from last re-key
    154  */
    155 
    156 static int aps_started = 0;
    157 static int is_monitor = 0;
    158 
    159 static pid_t monitor_pid, child_pid;
    160 static int pipe_fds[2];
    161 static int pipe_fd = -1;
    162 static Buffer input_pipe, output_pipe; /* for pipe I/O */
    163 
    164 static Authctxt *xxx_authctxt;
    165 
    166 /* Monitor functions */
    167 extern void aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid);
    168 static void aps_record_login(void);
    169 static void aps_record_logout(void);
    170 static void aps_start_rekex(void);
    171 
    172 /* Altprivsep packet utilities for communication with the monitor */
    173 static void	altprivsep_packet_start(u_char);
    174 static int	altprivsep_packet_send(void);
    175 static int	altprivsep_fwd_packet(u_char type);
    176 
    177 static int	altprivsep_packet_read(void);
    178 static void	altprivsep_packet_read_expect(int type);
    179 
    180 static void	altprivsep_packet_put_char(int ch);
    181 static void	altprivsep_packet_put_int(u_int value);
    182 static void	altprivsep_packet_put_cstring(const char *str);
    183 static void	altprivsep_packet_put_raw(const void *buf, u_int len);
    184 
    185 static u_int	 altprivsep_packet_get_char(void);
    186 static void	*altprivsep_packet_get_raw(u_int *length_ptr);
    187 static void	*altprivsep_packet_get_string(u_int *length_ptr);
    188 
    189 /*
    190  * Start monitor from privileged sshd process.
    191  *
    192  * Return values are like fork(2); the parent is the monitor.  The caller should
    193  * fatal() on error.
    194  *
    195  * Privileges are dropped, on the unprivileged side, upon success.
    196  */
    197 pid_t
    198 altprivsep_start_monitor(Authctxt *authctxt)
    199 {
    200 	pid_t pid;
    201 	int junk;
    202 
    203 	if (aps_started || authctxt == NULL || authctxt->pw == NULL)
    204 		fatal("Monitor startup failed: missing state");
    205 
    206 	xxx_authctxt = authctxt;
    207 
    208 	packet_set_server();
    209 
    210 	buffer_init(&output_pipe);
    211 	buffer_init(&input_pipe);
    212 
    213 	if (pipe(pipe_fds) != 0) {
    214 		error("Monitor startup failure: could not create pipes: %s",
    215 			strerror(errno));
    216 		return (-1);
    217 	}
    218 
    219 	(void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
    220 	(void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
    221 
    222 	monitor_pid = getpid();
    223 
    224 	if ((pid = fork()) > 0) {
    225 		/* parent */
    226 		child_pid = pid;
    227 
    228 		debug2("Monitor pid %ld, unprivileged child pid %ld",
    229 			monitor_pid, child_pid);
    230 
    231 		(void) close(pipe_fds[1]);
    232 
    233 		pipe_fd = pipe_fds[0];
    234 
    235 		if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
    236 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
    237 
    238 		/* signal readiness of monitor */
    239 		(void) write(pipe_fd, &pid, sizeof (pid));
    240 
    241 		aps_started = 1;
    242 		is_monitor = 1;
    243 
    244 		debug2("Monitor started");
    245 
    246 		set_log_txt_prefix("monitor ");
    247 
    248 		return (pid);
    249 
    250 	}
    251 
    252 	if (pid < 0) {
    253 		debug2("Monitor startup failure: could not fork unprivileged"
    254 			" process:  %s", strerror(errno));
    255 		return (pid);
    256 	}
    257 
    258 	/* caller should drop privs */
    259 
    260 	(void) close(pipe_fds[0]);
    261 
    262 	pipe_fd = pipe_fds[1];
    263 
    264 	/* wait for monitor to be ready */
    265 	debug2("Waiting for monitor");
    266 	(void) read(pipe_fd, &junk, sizeof (junk));
    267 	debug2("Monitor signalled readiness");
    268 
    269 	if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
    270 		error("fcntl O_NONBLOCK: %.100s", strerror(errno));
    271 
    272 	buffer_init(&to_monitor);
    273 	buffer_init(&from_monitor);
    274 
    275 	if (compat20) {
    276 		debug3("Setting handler to forward re-key packets to monitor");
    277 		dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX,
    278 			&altprivsep_rekey);
    279 	}
    280 
    281 	/* AltPrivSep interfaces are set up */
    282 	aps_started = 1;
    283 	return (pid);
    284 }
    285 
    286 int
    287 altprivsep_get_pipe_fd(void)
    288 {
    289 	return (pipe_fd);
    290 }
    291 
    292 void
    293 altprivsep_rekey(int type, u_int32_t seq, void *ctxt)
    294 {
    295 	Kex *kex = (Kex *)ctxt;
    296 
    297 	if (kex == NULL)
    298 		fatal("Missing key exchange context in unprivileged process");
    299 
    300 	debug2("Forwarding re-key packet (%d) to monitor", type);
    301 
    302 	if (type != SSH2_MSG_NEWKEYS)
    303 		if (!altprivsep_fwd_packet(type))
    304 			fatal("Monitor not responding");
    305 
    306 	/* tell server_loop2() that we're re-keying */
    307 	kex->done = 0;
    308 
    309 	/* NEWKEYS is special: get the new keys for client->server direction */
    310 	if (type == SSH2_MSG_NEWKEYS) {
    311 		debug2("Getting new inbound keystate from monitor");
    312 		altprivsep_get_newkeys(MODE_IN);
    313 		kex->done = 1;
    314 	}
    315 }
    316 
    317 void
    318 altprivsep_process_input(fd_set *rset)
    319 {
    320 	void	*data;
    321 	int	 type;
    322 	u_int	 dlen;
    323 
    324 	debug2("Reading from pipe to monitor (%d)", pipe_fd);
    325 
    326 	if (pipe_fd == -1)
    327 		return;
    328 
    329 	if (!FD_ISSET(pipe_fd, rset))
    330 		return;
    331 
    332 	if ((type = altprivsep_packet_read()) == -1)
    333 		fatal("Monitor not responding");
    334 
    335 	if (!compat20)
    336 		return; /* shouldn't happen! but be safe */
    337 
    338 	if (type == 0)
    339 		return;	/* EOF -- nothing to do here */
    340 
    341 	if (type >= SSH2_MSG_MAX)
    342 		fatal("Received garbage from monitor");
    343 
    344 	debug2("Read packet type %d from pipe to monitor", (u_int)type);
    345 
    346 	if (type == SSH2_PRIV_MSG_ALTPRIVSEP)
    347 		return; /* shouldn't happen! */
    348 
    349 	/* NEWKEYS is special: get the new keys for server->client direction */
    350 	if (type == SSH2_MSG_NEWKEYS) {
    351 		debug2("Getting new outbound keystate from monitor");
    352 		packet_start(SSH2_MSG_NEWKEYS);
    353 		packet_send();
    354 		altprivsep_get_newkeys(MODE_OUT);
    355 		return;
    356 	}
    357 
    358 	data = altprivsep_packet_get_raw(&dlen);
    359 
    360 	packet_start((u_char)type);
    361 
    362 	if (data != NULL && dlen > 0)
    363 		packet_put_raw(data, dlen);
    364 
    365 	packet_send();
    366 }
    367 
    368 void
    369 altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid)
    370 {
    371 	aps_monitor_loop(authctxt, pipe_fd, child_pid);
    372 }
    373 
    374 int
    375 altprivsep_started(void)
    376 {
    377 	return (aps_started);
    378 }
    379 
    380 int
    381 altprivsep_is_monitor(void)
    382 {
    383 	return (is_monitor);
    384 }
    385 
    386 /*
    387  * A fatal cleanup function to forcibly shutdown the connection socket
    388  */
    389 void
    390 altprivsep_shutdown_sock(void *arg)
    391 {
    392 	int sock;
    393 
    394 	if (arg == NULL)
    395 		return;
    396 
    397 	sock = *(int *)arg;
    398 
    399 	(void) shutdown(sock, SHUT_RDWR);
    400 }
    401 
    402 /* Calls _to_ monitor from unprivileged process */
    403 static
    404 int
    405 altprivsep_fwd_packet(u_char type)
    406 {
    407 	u_int len;
    408 	void  *data;
    409 
    410 	altprivsep_packet_start(type);
    411 	data = packet_get_raw(&len);
    412 	altprivsep_packet_put_raw(data, len);
    413 
    414 	/* packet_send()s any replies from the monitor to the client */
    415 	return (altprivsep_packet_send());
    416 }
    417 
    418 extern Newkeys *current_keys[MODE_MAX];
    419 
    420 /* To be called from packet.c:set_newkeys() before referencing current_keys */
    421 void
    422 altprivsep_get_newkeys(enum kex_modes mode)
    423 {
    424 	Newkeys	*newkeys;
    425 	Comp	*comp;
    426 	Enc	*enc;
    427 	Mac	*mac;
    428 	u_int	 len;
    429 
    430 	if (!altprivsep_started())
    431 		return;
    432 
    433 	if (altprivsep_is_monitor())
    434 		return; /* shouldn't happen */
    435 
    436 	/* request new keys */
    437 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    438 	altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ);
    439 	altprivsep_packet_put_int((u_int)mode);
    440 	altprivsep_packet_send();
    441 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
    442 	if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP)
    443 		fatal("Received garbage from monitor during re-keying");
    444 
    445 	newkeys = xmalloc(sizeof (*newkeys));
    446 	memset(newkeys, 0, sizeof (*newkeys));
    447 
    448 	enc = &newkeys->enc;
    449 	mac = &newkeys->mac;
    450 	comp = &newkeys->comp;
    451 
    452 	/* Cipher name, key, IV */
    453 	enc->name = altprivsep_packet_get_string(NULL);
    454 	if ((enc->cipher = cipher_by_name(enc->name)) == NULL)
    455 		fatal("Monitor negotiated an unknown cipher during re-key");
    456 
    457 	enc->key = altprivsep_packet_get_string(&enc->key_len);
    458 	enc->iv = altprivsep_packet_get_string(&enc->block_size);
    459 
    460 	/* MAC name */
    461 	mac->name = altprivsep_packet_get_string(NULL);
    462 	if (mac_init(mac, mac->name) < 0)
    463 		fatal("Monitor negotiated an unknown MAC algorithm "
    464 			"during re-key");
    465 
    466 	mac->key = altprivsep_packet_get_string(&len);
    467 	if (len > mac->key_len)
    468 		fatal("%s: bad mac key length: %d > %d", __func__, len,
    469 			mac->key_len);
    470 
    471 	/* Compression algorithm name */
    472 	comp->name = altprivsep_packet_get_string(NULL);
    473 	if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0)
    474 		fatal("Monitor negotiated an unknown compression "
    475 			"algorithm during re-key");
    476 
    477 	comp->type = 0;
    478 	comp->enabled = 0; /* forces compression re-init, as per-spec */
    479 	if (strcmp(comp->name, "zlib") == 0)
    480 		comp->type = 1;
    481 
    482 	/*
    483 	 * Now install new keys
    484 	 *
    485 	 * For now abuse kex.c/packet.c non-interfaces.  Someday, when
    486 	 * the many internal interfaces are parametrized, made reentrant
    487 	 * and thread-safe, made more consistent, and when necessary-but-
    488 	 * currently-missing interfaces are added then this bit of
    489 	 * ugliness can be revisited.
    490 	 *
    491 	 * The ugliness is in the set_newkeys(), its name and the lack
    492 	 * of a (Newkeys *) parameter, which forces us to pass the
    493 	 * newkeys through current_keys[mode].  But this saves us some
    494 	 * lines of code for now, though not comments.
    495 	 *
    496 	 * Also, we've abused, in the code above, knowledge of what
    497 	 * set_newkeys() expects the current_keys[mode] to contain.
    498 	 */
    499 	current_keys[mode] = newkeys;
    500 	set_newkeys(mode);
    501 
    502 }
    503 
    504 void
    505 altprivsep_record_login(pid_t pid, const char *ttyname)
    506 {
    507 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    508 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN);
    509 	altprivsep_packet_put_int(pid);
    510 	altprivsep_packet_put_cstring(ttyname);
    511 	altprivsep_packet_send();
    512 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
    513 }
    514 
    515 void
    516 altprivsep_record_logout(pid_t pid)
    517 {
    518 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    519 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT);
    520 	altprivsep_packet_put_int(pid);
    521 	altprivsep_packet_send();
    522 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
    523 }
    524 
    525 void
    526 altprivsep_start_rekex(void)
    527 {
    528 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    529 	altprivsep_packet_put_char(APS_MSG_START_REKEX);
    530 	altprivsep_packet_send();
    531 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
    532 }
    533 
    534 static void aps_send_newkeys(void);
    535 
    536 /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */
    537 /* ARGSUSED */
    538 void
    539 aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt)
    540 {
    541 	u_char req_type;
    542 
    543 	req_type = packet_get_char();
    544 
    545 	switch (req_type) {
    546 	case APS_MSG_NEWKEYS_REQ:
    547 		aps_send_newkeys();
    548 		break;
    549 	case APS_MSG_RECORD_LOGIN:
    550 		aps_record_login();
    551 		break;
    552 	case APS_MSG_RECORD_LOGOUT:
    553 		aps_record_logout();
    554 		break;
    555 	case APS_MSG_START_REKEX:
    556 		aps_start_rekex();
    557 		break;
    558 	default:
    559 		break;
    560 	}
    561 }
    562 
    563 /* Monitor-side handlers for APS_MSG_* */
    564 static
    565 void
    566 aps_send_newkeys(void)
    567 {
    568 	Newkeys *newkeys;
    569 	Enc *enc;
    570 	Mac *mac;
    571 	Comp *comp;
    572 	enum kex_modes mode;
    573 
    574 	/* get direction for which newkeys are wanted */
    575 	mode = (enum kex_modes) packet_get_int();
    576 	packet_check_eom();
    577 
    578 	/* get those newkeys */
    579 	newkeys = kex_get_newkeys(mode);
    580 	enc = &newkeys->enc;
    581 	mac = &newkeys->mac;
    582 	comp = &newkeys->comp;
    583 
    584 	/*
    585 	 * Negotiated algorithms, client->server and server->client, for
    586 	 * cipher, mac and compression.
    587 	 */
    588 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    589 	packet_put_char(APS_MSG_NEWKEYS_REP);
    590 	packet_put_cstring(enc->name);
    591 	packet_put_string(enc->key, enc->key_len);
    592 	packet_put_string(enc->iv, enc->block_size);
    593 	packet_put_cstring(mac->name);
    594 	packet_put_string(mac->key, mac->key_len);
    595 	packet_put_cstring(comp->name);
    596 
    597 	packet_send();
    598 	free_keys(newkeys);
    599 }
    600 
    601 struct _aps_login_rec {
    602 	pid_t			lr_pid;
    603 	char			*lr_tty;
    604 	struct _aps_login_rec	*next;
    605 };
    606 
    607 typedef struct _aps_login_rec aps_login_rec;
    608 
    609 static aps_login_rec *aps_login_list = NULL;
    610 
    611 static
    612 void
    613 aps_record_login(void)
    614 {
    615 	aps_login_rec	*new_rec;
    616 	struct stat	 sbuf;
    617 	size_t		 proc_path_len;
    618 	char		*proc_path;
    619 
    620 	new_rec = xmalloc(sizeof (aps_login_rec));
    621 	memset(new_rec, 0, sizeof (aps_login_rec));
    622 
    623 	new_rec->lr_pid = packet_get_int();
    624 	new_rec->lr_tty = packet_get_string(NULL);
    625 
    626 	proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid);
    627 	proc_path = xmalloc(proc_path_len + 1);
    628 	(void) snprintf(proc_path, proc_path_len + 1, "/proc/%d",
    629 			new_rec->lr_pid);
    630 
    631 	if (stat(proc_path, &sbuf) ||
    632 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid ||
    633 	    stat(new_rec->lr_tty, &sbuf) < 0 ||
    634 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid) {
    635 		debug2("Spurious record_login request from unprivileged sshd");
    636 		xfree(proc_path);
    637 		xfree(new_rec->lr_tty);
    638 		xfree(new_rec);
    639 		return;
    640 	}
    641 
    642 	/* Insert new record on list */
    643 	new_rec->next = aps_login_list;
    644 	aps_login_list = new_rec;
    645 
    646 	record_login(new_rec->lr_pid, new_rec->lr_tty, NULL,
    647 		xxx_authctxt->user);
    648 
    649 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    650 	packet_send();
    651 
    652 	xfree(proc_path);
    653 }
    654 
    655 static
    656 void
    657 aps_record_logout(void)
    658 {
    659 	aps_login_rec	**p, *q;
    660 	pid_t		 pid;
    661 
    662 	pid = packet_get_int();
    663 	packet_check_eom();
    664 
    665 	for (p = &aps_login_list; *p != NULL; p = &q->next) {
    666 		q = *p;
    667 		if (q->lr_pid == pid) {
    668 			record_logout(q->lr_pid, q->lr_tty, NULL,
    669 				xxx_authctxt->user);
    670 
    671 			/* dequeue */
    672 			*p = q->next;
    673 			xfree(q->lr_tty);
    674 			xfree(q);
    675 			break;
    676 		}
    677 	}
    678 
    679 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    680 	packet_send();
    681 }
    682 
    683 static
    684 void
    685 aps_start_rekex(void)
    686 {
    687 	/*
    688 	 * Send confirmation. We could implement it without that but it doesn't
    689 	 * bring any harm to do that and we are consistent with other subtypes
    690 	 * of our private SSH2_PRIV_MSG_ALTPRIVSEP message type.
    691 	 */
    692 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
    693 	packet_send();
    694 
    695 	/*
    696 	 * KEX_INIT message could be the one that reached the limit. In that
    697 	 * case, it was already forwarded to us from the unnprivileged child,
    698 	 * and maybe even acted upon. Obviously we must not send another
    699 	 * KEX_INIT message.
    700 	 */
    701 	if (!(xxx_kex->flags & KEX_INIT_SENT))
    702 		kex_send_kexinit(xxx_kex);
    703 	else
    704 		debug2("rekeying already in progress");
    705 }
    706 
    707 
    708 /* Utilities for communication with the monitor */
    709 static
    710 void
    711 altprivsep_packet_start(u_char type)
    712 {
    713 	buffer_clear(&to_monitor);
    714 	buffer_put_char(&to_monitor, type);
    715 }
    716 static
    717 void
    718 altprivsep_packet_put_char(int ch)
    719 {
    720 	buffer_put_char(&to_monitor, ch);
    721 }
    722 static
    723 void
    724 altprivsep_packet_put_int(u_int value)
    725 {
    726 	buffer_put_int(&to_monitor, value);
    727 }
    728 static
    729 void
    730 altprivsep_packet_put_cstring(const char *str)
    731 {
    732 	buffer_put_cstring(&to_monitor, str);
    733 }
    734 static
    735 void
    736 altprivsep_packet_put_raw(const void *buf, u_int len)
    737 {
    738 	buffer_append(&to_monitor, buf, len);
    739 }
    740 
    741 /*
    742  * Send a monitor packet to the monitor.  This function is blocking.
    743  *
    744  * Returns -1 if the monitor pipe has been closed earlier, fatal()s if
    745  * there's any other problems.
    746  */
    747 static
    748 int
    749 altprivsep_packet_send(void)
    750 {
    751 	ssize_t len;
    752 	u_int32_t plen;	/* packet length */
    753 	u_char	plen_buf[sizeof (plen)];
    754 	u_char padlen;	/* padding length */
    755 	fd_set *setp;
    756 
    757 	if (pipe_fd == -1)
    758 		return (-1);
    759 
    760 	if ((plen = buffer_len(&to_monitor)) == 0)
    761 		return (0);
    762 
    763 	/*
    764 	 * We talk the SSHv2 binary packet protocol to the monitor,
    765 	 * using the none cipher, mac and compression algorithms.
    766 	 *
    767 	 * But, interestingly, the none cipher has a block size of 8
    768 	 * bytes, thus we must pad the packet.
    769 	 *
    770 	 * Also, encryption includes the packet length, so the padding
    771 	 * must account for that field.  I.e., (sizeof (packet length) +
    772 	 * sizeof (padding length) + packet length + padding length) %
    773 	 * block_size must == 0.
    774 	 *
    775 	 * Also, there must be at least four (4) bytes of padding.
    776 	 */
    777 	padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8;
    778 	if (padlen < 4)
    779 		padlen += 8;
    780 
    781 	/* packet length counts padding and padding length field */
    782 	plen += padlen + sizeof (padlen);
    783 
    784 	PUT_32BIT(plen_buf, plen);
    785 
    786 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
    787 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
    788 	FD_SET(pipe_fd, setp);
    789 
    790 	while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) {
    791 		if (errno == EAGAIN || errno == EINTR)
    792 			continue;
    793 		else
    794 			goto pipe_gone;
    795 	}
    796 
    797 	xfree(setp);
    798 
    799 	/* packet length field */
    800 	len = atomicio(write, pipe_fd, plen_buf, sizeof (plen));
    801 
    802 	if (len != sizeof (plen))
    803 		goto pipe_gone;
    804 
    805 	/* padding length field */
    806 	len = atomicio(write, pipe_fd, &padlen, sizeof (padlen));
    807 
    808 	if (len != sizeof (padlen))
    809 		goto pipe_gone;
    810 
    811 	len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1);
    812 
    813 	if (len != (plen - 1))
    814 		goto pipe_gone;
    815 
    816 	buffer_clear(&to_monitor);
    817 
    818 	return (1);
    819 
    820 pipe_gone:
    821 
    822 	(void) close(pipe_fd);
    823 
    824 	pipe_fd = -1;
    825 
    826 	fatal("Monitor not responding");
    827 
    828 	/* NOTREACHED */
    829 	return (0);
    830 }
    831 
    832 /*
    833  * Read a monitor packet from the monitor.  This function is blocking.
    834  */
    835 static
    836 int
    837 altprivsep_packet_read(void)
    838 {
    839 	ssize_t len = -1;
    840 	u_int32_t plen;
    841 	u_char plen_buf[sizeof (plen)];
    842 	u_char padlen;
    843 	fd_set *setp;
    844 
    845 	if (pipe_fd == -1)
    846 		return (-1);
    847 
    848 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
    849 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
    850 	FD_SET(pipe_fd, setp);
    851 
    852 	while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) {
    853 		if (errno == EAGAIN || errno == EINTR)
    854 			continue;
    855 		else
    856 			goto pipe_gone;
    857 	}
    858 
    859 	xfree(setp);
    860 
    861 	/* packet length field */
    862 	len = atomicio(read, pipe_fd, plen_buf, sizeof (plen));
    863 
    864 	plen = GET_32BIT(plen_buf);
    865 
    866 	if (len != sizeof (plen))
    867 		goto pipe_gone;
    868 
    869 	/* padding length field */
    870 	len = atomicio(read, pipe_fd, &padlen, sizeof (padlen));
    871 
    872 	if (len != sizeof (padlen))
    873 		goto pipe_gone;
    874 
    875 	plen -= sizeof (padlen);
    876 
    877 	buffer_clear(&from_monitor);
    878 	buffer_append_space(&from_monitor, plen);
    879 
    880 	/* packet data + padding */
    881 	len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen);
    882 
    883 	if (len != plen)
    884 		goto pipe_gone;
    885 
    886 	/* remove padding */
    887 	if (padlen > 0)
    888 		buffer_consume_end(&from_monitor, padlen);
    889 
    890 	/* packet type */
    891 	return (buffer_get_char(&from_monitor));
    892 
    893 pipe_gone:
    894 
    895 	(void) close(pipe_fd);
    896 
    897 	pipe_fd = -1;
    898 
    899 	if (len < 0)
    900 		fatal("Monitor not responding");
    901 
    902 	debug2("Monitor pipe closed by monitor");
    903 	return (0);
    904 }
    905 
    906 static
    907 void
    908 altprivsep_packet_read_expect(int expected)
    909 {
    910 	int type;
    911 
    912 	type = altprivsep_packet_read();
    913 
    914 	if (type <= 0)
    915 		fatal("Monitor not responding");
    916 
    917 	if (type != expected)
    918 		fatal("Protocol error in privilege separation; expected "
    919 			"packet type %d, got %d", expected, type);
    920 }
    921 
    922 static
    923 u_int
    924 altprivsep_packet_get_char(void)
    925 {
    926 	return (buffer_get_char(&from_monitor));
    927 }
    928 void
    929 *altprivsep_packet_get_raw(u_int *length_ptr)
    930 {
    931 	if (length_ptr != NULL)
    932 		*length_ptr = buffer_len(&from_monitor);
    933 
    934 	return (buffer_ptr(&from_monitor));
    935 }
    936 void
    937 *altprivsep_packet_get_string(u_int *length_ptr)
    938 {
    939 	return (buffer_get_string(&from_monitor, length_ptr));
    940 }
    941