xref: /titanic_50/usr/src/cmd/ssh/sshd/altprivsep.c (revision 4d594c339b4bc590af28251f4d30380f003d6c35)
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 2007 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 
171 /* Altprivsep packet utilities for communication with the monitor */
172 static void	altprivsep_packet_start(u_char);
173 static int	altprivsep_packet_send(void);
174 static int	altprivsep_fwd_packet(u_char type);
175 
176 static int	altprivsep_packet_read(void);
177 static void	altprivsep_packet_read_expect(int type);
178 
179 static void	altprivsep_packet_put_char(int ch);
180 static void	altprivsep_packet_put_int(u_int value);
181 static void	altprivsep_packet_put_cstring(const char *str);
182 static void	altprivsep_packet_put_raw(const void *buf, u_int len);
183 
184 static u_int	 altprivsep_packet_get_char(void);
185 static void	*altprivsep_packet_get_raw(u_int *length_ptr);
186 static void	*altprivsep_packet_get_string(u_int *length_ptr);
187 
188 /*
189  * Start monitor from privileged sshd process.
190  *
191  * Return values are like fork(2); the parent is the monitor.  The caller should
192  * fatal() on error.
193  *
194  * Privileges are dropped, on the unprivileged side, upon success.
195  */
196 pid_t
197 altprivsep_start_monitor(Authctxt *authctxt)
198 {
199 	pid_t pid;
200 	int junk;
201 
202 	if (aps_started || authctxt == NULL || authctxt->pw == NULL)
203 		fatal("Monitor startup failed: missing state");
204 
205 	xxx_authctxt = authctxt;
206 
207 	packet_set_server();
208 
209 	buffer_init(&output_pipe);
210 	buffer_init(&input_pipe);
211 
212 	if (pipe(pipe_fds) != 0) {
213 		error("Monitor startup failure: could not create pipes: %s",
214 			strerror(errno));
215 		return (-1);
216 	}
217 
218 	(void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC);
219 	(void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC);
220 
221 	monitor_pid = getpid();
222 
223 	if ((pid = fork()) > 0) {
224 		/* parent */
225 		child_pid = pid;
226 
227 		debug2("Monitor pid %ld, unprivileged child pid %ld",
228 			monitor_pid, child_pid);
229 
230 		(void) close(pipe_fds[1]);
231 
232 		pipe_fd = pipe_fds[0];
233 
234 		if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
235 			error("fcntl O_NONBLOCK: %.100s", strerror(errno));
236 
237 		/* signal readiness of monitor */
238 		(void) write(pipe_fd, &pid, sizeof (pid));
239 
240 		aps_started = 1;
241 		is_monitor = 1;
242 
243 		debug2("Monitor started");
244 
245 		set_log_txt_prefix("monitor ");
246 
247 		return (pid);
248 
249 	}
250 
251 	if (pid < 0) {
252 		debug2("Monitor startup failure: could not fork unprivileged"
253 			" process:  %s", strerror(errno));
254 		return (pid);
255 	}
256 
257 	/* caller should drop privs */
258 
259 	(void) close(pipe_fds[0]);
260 
261 	pipe_fd = pipe_fds[1];
262 
263 	/* wait for monitor to be ready */
264 	debug2("Waiting for monitor");
265 	(void) read(pipe_fd, &junk, sizeof (junk));
266 	debug2("Monitor signalled readiness");
267 
268 	if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0)
269 		error("fcntl O_NONBLOCK: %.100s", strerror(errno));
270 
271 	buffer_init(&to_monitor);
272 	buffer_init(&from_monitor);
273 
274 	if (compat20) {
275 		debug3("Setting handler to forward re-key packets to monitor");
276 		dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX,
277 			&altprivsep_rekey);
278 	}
279 
280 	/* AltPrivSep interfaces are set up */
281 	aps_started = 1;
282 	return (pid);
283 }
284 
285 int
286 altprivsep_get_pipe_fd(void)
287 {
288 	return (pipe_fd);
289 }
290 
291 void
292 altprivsep_rekey(int type, u_int32_t seq, void *ctxt)
293 {
294 	Kex *kex = (Kex *)ctxt;
295 
296 	if (kex == NULL)
297 		fatal("Missing key exchange context in unprivileged process");
298 
299 	debug2("Forwarding re-key packet (%d) to monitor", type);
300 
301 	if (type != SSH2_MSG_NEWKEYS)
302 		if (!altprivsep_fwd_packet(type))
303 			fatal("Monitor not responding");
304 
305 	/* tell server_loop2() that we're re-keying */
306 	kex->done = 0;
307 
308 	/* NEWKEYS is special: get the new keys for client->server direction */
309 	if (type == SSH2_MSG_NEWKEYS) {
310 		debug2("Getting new inbound keystate from monitor");
311 		altprivsep_get_newkeys(MODE_IN);
312 		kex->done = 1;
313 	}
314 }
315 
316 void
317 altprivsep_process_input(Kex *kex, fd_set *rset)
318 {
319 	void	*data;
320 	int	 type;
321 	u_int	 dlen;
322 
323 	debug2("Reading from pipe to monitor (%d)", pipe_fd);
324 
325 	if (pipe_fd == -1)
326 		return;
327 
328 	if (!FD_ISSET(pipe_fd, rset))
329 		return;
330 
331 	if ((type = altprivsep_packet_read()) == -1)
332 		fatal("Monitor not responding");
333 
334 	if (!compat20)
335 		return; /* shouldn't happen! but be safe */
336 
337 	if (type == 0)
338 		return;	/* EOF -- nothing to do here */
339 
340 	if (type >= SSH2_MSG_MAX)
341 		fatal("Received garbage from monitor");
342 
343 	debug2("Read packet type %d from pipe to monitor", (u_int)type);
344 
345 	if (type == SSH2_PRIV_MSG_ALTPRIVSEP)
346 		return; /* shouldn't happen! */
347 
348 	/* NEWKEYS is special: get the new keys for server->client direction */
349 	if (type == SSH2_MSG_NEWKEYS) {
350 		debug2("Getting new outbound keystate from monitor");
351 		packet_start(SSH2_MSG_NEWKEYS);
352 		packet_send();
353 		altprivsep_get_newkeys(MODE_OUT);
354 		return;
355 	}
356 
357 	data = altprivsep_packet_get_raw(&dlen);
358 
359 	packet_start((u_char)type);
360 
361 	if (data != NULL && dlen > 0)
362 		packet_put_raw(data, dlen);
363 
364 	packet_send();
365 }
366 
367 void
368 altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid)
369 {
370 	aps_monitor_loop(authctxt, pipe_fd, child_pid);
371 }
372 
373 int
374 altprivsep_started(void)
375 {
376 	return (aps_started);
377 }
378 
379 int
380 altprivsep_is_monitor(void)
381 {
382 	return (is_monitor);
383 }
384 
385 /*
386  * A fatal cleanup function to forcibly shutdown the connection socket
387  */
388 void
389 altprivsep_shutdown_sock(void *arg)
390 {
391 	int sock;
392 
393 	if (arg == NULL)
394 		return;
395 
396 	sock = *(int *)arg;
397 
398 	(void) shutdown(sock, SHUT_RDWR);
399 }
400 
401 /* Calls _to_ monitor from unprivileged process */
402 static
403 int
404 altprivsep_fwd_packet(u_char type)
405 {
406 	u_int len;
407 	void  *data;
408 
409 	altprivsep_packet_start(type);
410 	data = packet_get_raw(&len);
411 	altprivsep_packet_put_raw(data, len);
412 
413 	/* packet_send()s any replies from the monitor to the client */
414 	return (altprivsep_packet_send());
415 }
416 
417 extern Newkeys *current_keys[MODE_MAX];
418 
419 /* To be called from packet.c:set_newkeys() before referencing current_keys */
420 void
421 altprivsep_get_newkeys(enum kex_modes mode)
422 {
423 	Newkeys	*newkeys;
424 	Comp	*comp;
425 	Enc	*enc;
426 	Mac	*mac;
427 	u_int	 len;
428 
429 	if (!altprivsep_started())
430 		return;
431 
432 	if (altprivsep_is_monitor())
433 		return; /* shouldn't happen */
434 
435 	/* request new keys */
436 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
437 	altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ);
438 	altprivsep_packet_put_int((u_int)mode);
439 	altprivsep_packet_send();
440 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
441 	if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP)
442 		fatal("Received garbage from monitor during re-keying");
443 
444 	newkeys = xmalloc(sizeof (*newkeys));
445 	memset(newkeys, 0, sizeof (*newkeys));
446 
447 	enc = &newkeys->enc;
448 	mac = &newkeys->mac;
449 	comp = &newkeys->comp;
450 
451 	/* Cipher name, key, IV */
452 	enc->name = altprivsep_packet_get_string(NULL);
453 	if ((enc->cipher = cipher_by_name(enc->name)) == NULL)
454 		fatal("Monitor negotiated an unknown cipher during re-key");
455 
456 	enc->key = altprivsep_packet_get_string(&enc->key_len);
457 	enc->iv = altprivsep_packet_get_string(&enc->block_size);
458 
459 	/* MAC name */
460 	mac->name = altprivsep_packet_get_string(NULL);
461 	if (mac_init(mac, mac->name) < 0)
462 		fatal("Monitor negotiated an unknown MAC algorithm "
463 			"during re-key");
464 
465 	mac->key = altprivsep_packet_get_string(&len);
466 	if (len > mac->key_len)
467 		fatal("%s: bad mac key length: %d > %d", __func__, len,
468 			mac->key_len);
469 
470 	/* Compression algorithm name */
471 	comp->name = altprivsep_packet_get_string(NULL);
472 	if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0)
473 		fatal("Monitor negotiated an unknown compression "
474 			"algorithm during re-key");
475 
476 	comp->type = 0;
477 	comp->enabled = 0; /* forces compression re-init, as per-spec */
478 	if (strcmp(comp->name, "zlib") == 0)
479 		comp->type = 1;
480 
481 	/*
482 	 * Now install new keys
483 	 *
484 	 * For now abuse kex.c/packet.c non-interfaces.  Someday, when
485 	 * the many internal interfaces are parametrized, made reentrant
486 	 * and thread-safe, made more consistent, and when necessary-but-
487 	 * currently-missing interfaces are added then this bit of
488 	 * ugliness can be revisited.
489 	 *
490 	 * The ugliness is in the set_newkeys(), its name and the lack
491 	 * of a (Newkeys *) parameter, which forces us to pass the
492 	 * newkeys through current_keys[mode].  But this saves us some
493 	 * lines of code for now, though not comments.
494 	 *
495 	 * Also, we've abused, in the code above, knowledge of what
496 	 * set_newkeys() expects the current_keys[mode] to contain.
497 	 */
498 	current_keys[mode] = newkeys;
499 	set_newkeys(mode);
500 
501 }
502 
503 void
504 altprivsep_record_login(pid_t pid, const char *ttyname)
505 {
506 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
507 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN);
508 	altprivsep_packet_put_int(pid);
509 	altprivsep_packet_put_cstring(ttyname);
510 	altprivsep_packet_send();
511 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
512 }
513 
514 void
515 altprivsep_record_logout(pid_t pid)
516 {
517 	altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
518 	altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT);
519 	altprivsep_packet_put_int(pid);
520 	altprivsep_packet_send();
521 	altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP);
522 }
523 
524 static void aps_send_newkeys(void);
525 
526 /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */
527 /* ARGSUSED */
528 void
529 aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt)
530 {
531 	u_char req_type;
532 
533 	req_type = packet_get_char();
534 
535 	switch (req_type) {
536 	case APS_MSG_NEWKEYS_REQ:
537 		aps_send_newkeys();
538 		break;
539 	case APS_MSG_RECORD_LOGIN:
540 		aps_record_login();
541 		break;
542 	case APS_MSG_RECORD_LOGOUT:
543 		aps_record_logout();
544 		break;
545 	default:
546 		break;
547 	}
548 }
549 
550 /* Monitor-side handlers for APS_MSG_* */
551 static
552 void
553 aps_send_newkeys(void)
554 {
555 	Newkeys *newkeys;
556 	Enc *enc;
557 	Mac *mac;
558 	Comp *comp;
559 	enum kex_modes mode;
560 
561 	/* get direction for which newkeys are wanted */
562 	mode = (enum kex_modes) packet_get_int();
563 	packet_check_eom();
564 
565 	/* get those newkeys */
566 	newkeys = kex_get_newkeys(mode);
567 	enc = &newkeys->enc;
568 	mac = &newkeys->mac;
569 	comp = &newkeys->comp;
570 
571 	/*
572 	 * Negotiated algorithms, client->server and server->client, for
573 	 * cipher, mac and compression.
574 	 */
575 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
576 	packet_put_char(APS_MSG_NEWKEYS_REP);
577 	packet_put_cstring(enc->name);
578 	packet_put_string(enc->key, enc->key_len);
579 	packet_put_string(enc->iv, enc->block_size);
580 	packet_put_cstring(mac->name);
581 	packet_put_string(mac->key, mac->key_len);
582 	packet_put_cstring(comp->name);
583 
584 	packet_send();
585 	free_keys(newkeys);
586 }
587 
588 struct _aps_login_rec {
589 	pid_t			lr_pid;
590 	char			*lr_tty;
591 	struct _aps_login_rec	*next;
592 };
593 
594 typedef struct _aps_login_rec aps_login_rec;
595 
596 static aps_login_rec *aps_login_list = NULL;
597 
598 static
599 void
600 aps_record_login(void)
601 {
602 	aps_login_rec	*new_rec;
603 	struct stat	 sbuf;
604 	size_t		 proc_path_len;
605 	char		*proc_path;
606 
607 	new_rec = xmalloc(sizeof (aps_login_rec));
608 	memset(new_rec, 0, sizeof (aps_login_rec));
609 
610 	new_rec->lr_pid = packet_get_int();
611 	new_rec->lr_tty = packet_get_string(NULL);
612 
613 	proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid);
614 	proc_path = xmalloc(proc_path_len + 1);
615 	(void) snprintf(proc_path, proc_path_len + 1, "/proc/%d",
616 			new_rec->lr_pid);
617 
618 	if (stat(proc_path, &sbuf) ||
619 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid ||
620 	    stat(new_rec->lr_tty, &sbuf) < 0 ||
621 	    sbuf.st_uid != xxx_authctxt->pw->pw_uid) {
622 		debug2("Spurious record_login request from unprivileged sshd");
623 		xfree(proc_path);
624 		xfree(new_rec->lr_tty);
625 		xfree(new_rec);
626 		return;
627 	}
628 
629 	/* Insert new record on list */
630 	new_rec->next = aps_login_list;
631 	aps_login_list = new_rec;
632 
633 	record_login(new_rec->lr_pid, new_rec->lr_tty, NULL,
634 		xxx_authctxt->user);
635 
636 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
637 	packet_send();
638 
639 	xfree(proc_path);
640 }
641 
642 static
643 void
644 aps_record_logout(void)
645 {
646 	aps_login_rec	**p, *q;
647 	pid_t		 pid;
648 
649 	pid = packet_get_int();
650 	packet_check_eom();
651 
652 	for (p = &aps_login_list; *p != NULL; p = &q->next) {
653 		q = *p;
654 		if (q->lr_pid == pid) {
655 			record_logout(q->lr_pid, q->lr_tty, NULL,
656 				xxx_authctxt->user);
657 
658 			/* dequeue */
659 			*p = q->next;
660 			xfree(q->lr_tty);
661 			xfree(q);
662 			break;
663 		}
664 	}
665 
666 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
667 	packet_send();
668 }
669 
670 /* Utilities for communication with the monitor */
671 static
672 void
673 altprivsep_packet_start(u_char type)
674 {
675 	buffer_clear(&to_monitor);
676 	buffer_put_char(&to_monitor, type);
677 }
678 static
679 void
680 altprivsep_packet_put_char(int ch)
681 {
682 	buffer_put_char(&to_monitor, ch);
683 }
684 static
685 void
686 altprivsep_packet_put_int(u_int value)
687 {
688 	buffer_put_int(&to_monitor, value);
689 }
690 static
691 void
692 altprivsep_packet_put_cstring(const char *str)
693 {
694 	buffer_put_cstring(&to_monitor, str);
695 }
696 static
697 void
698 altprivsep_packet_put_raw(const void *buf, u_int len)
699 {
700 	buffer_append(&to_monitor, buf, len);
701 }
702 
703 /*
704  * Send a monitor packet to the monitor.  This function is blocking.
705  *
706  * Returns -1 if the monitor pipe has been closed earlier, fatal()s if
707  * there's any other problems.
708  */
709 static
710 int
711 altprivsep_packet_send(void)
712 {
713 	ssize_t len;
714 	u_int32_t plen;	/* packet length */
715 	u_char	plen_buf[sizeof (plen)];
716 	u_char padlen;	/* padding length */
717 	fd_set *setp;
718 
719 	if (pipe_fd == -1)
720 		return (-1);
721 
722 	if ((plen = buffer_len(&to_monitor)) == 0)
723 		return (0);
724 
725 	/*
726 	 * We talk the SSHv2 binary packet protocol to the monitor,
727 	 * using the none cipher, mac and compression algorithms.
728 	 *
729 	 * But, interestingly, the none cipher has a block size of 8
730 	 * bytes, thus we must pad the packet.
731 	 *
732 	 * Also, encryption includes the packet length, so the padding
733 	 * must account for that field.  I.e., (sizeof (packet length) +
734 	 * sizeof (padding length) + packet length + padding length) %
735 	 * block_size must == 0.
736 	 *
737 	 * Also, there must be at least four (4) bytes of padding.
738 	 */
739 	padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8;
740 	if (padlen < 4)
741 		padlen += 8;
742 
743 	/* packet length counts padding and padding length field */
744 	plen += padlen + sizeof (padlen);
745 
746 	PUT_32BIT(plen_buf, plen);
747 
748 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
749 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
750 	FD_SET(pipe_fd, setp);
751 
752 	while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) {
753 		if (errno == EAGAIN || errno == EINTR)
754 			continue;
755 		else
756 			goto pipe_gone;
757 	}
758 
759 	xfree(setp);
760 
761 	/* packet length field */
762 	len = atomicio(write, pipe_fd, plen_buf, sizeof (plen));
763 
764 	if (len != sizeof (plen))
765 		goto pipe_gone;
766 
767 	/* padding length field */
768 	len = atomicio(write, pipe_fd, &padlen, sizeof (padlen));
769 
770 	if (len != sizeof (padlen))
771 		goto pipe_gone;
772 
773 	len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1);
774 
775 	if (len != (plen - 1))
776 		goto pipe_gone;
777 
778 	buffer_clear(&to_monitor);
779 
780 	return (1);
781 
782 pipe_gone:
783 
784 	(void) close(pipe_fd);
785 
786 	pipe_fd = -1;
787 
788 	fatal("Monitor not responding");
789 
790 	/* NOTREACHED */
791 	return (0);
792 }
793 
794 /*
795  * Read a monitor packet from the monitor.  This function is blocking.
796  */
797 static
798 int
799 altprivsep_packet_read(void)
800 {
801 	ssize_t len = -1;
802 	u_int32_t plen;
803 	u_char plen_buf[sizeof (plen)];
804 	u_char padlen;
805 	fd_set *setp;
806 
807 	if (pipe_fd == -1)
808 		return (-1);
809 
810 	setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
811 	memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask));
812 	FD_SET(pipe_fd, setp);
813 
814 	while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) {
815 		if (errno == EAGAIN || errno == EINTR)
816 			continue;
817 		else
818 			goto pipe_gone;
819 	}
820 
821 	xfree(setp);
822 
823 	/* packet length field */
824 	len = atomicio(read, pipe_fd, plen_buf, sizeof (plen));
825 
826 	plen = GET_32BIT(plen_buf);
827 
828 	if (len != sizeof (plen))
829 		goto pipe_gone;
830 
831 	/* padding length field */
832 	len = atomicio(read, pipe_fd, &padlen, sizeof (padlen));
833 
834 	if (len != sizeof (padlen))
835 		goto pipe_gone;
836 
837 	plen -= sizeof (padlen);
838 
839 	buffer_clear(&from_monitor);
840 	buffer_append_space(&from_monitor, plen);
841 
842 	/* packet data + padding */
843 	len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen);
844 
845 	if (len != plen)
846 		goto pipe_gone;
847 
848 	/* remove padding */
849 	if (padlen > 0)
850 		buffer_consume_end(&from_monitor, padlen);
851 
852 	/* packet type */
853 	return (buffer_get_char(&from_monitor));
854 
855 pipe_gone:
856 
857 	(void) close(pipe_fd);
858 
859 	pipe_fd = -1;
860 
861 	if (len < 0)
862 		fatal("Monitor not responding");
863 
864 	debug2("Monitor pipe closed by monitor");
865 	return (0);
866 }
867 
868 static
869 void
870 altprivsep_packet_read_expect(int expected)
871 {
872 	int type;
873 
874 	type = altprivsep_packet_read();
875 
876 	if (type <= 0)
877 		fatal("Monitor not responding");
878 
879 	if (type != expected)
880 		fatal("Protocol error in privilege separation; expected "
881 			"packet type %d, got %d", expected, type);
882 }
883 
884 static
885 u_int
886 altprivsep_packet_get_char(void)
887 {
888 	return (buffer_get_char(&from_monitor));
889 }
890 void
891 *altprivsep_packet_get_raw(u_int *length_ptr)
892 {
893 	if (length_ptr != NULL)
894 		*length_ptr = buffer_len(&from_monitor);
895 
896 	return (buffer_ptr(&from_monitor));
897 }
898 void
899 *altprivsep_packet_get_string(u_int *length_ptr)
900 {
901 	return (buffer_get_string(&from_monitor, length_ptr));
902 }
903