xref: /titanic_41/usr/src/cmd/ssh/sshd/altprivsep.c (revision 549ec3fff108310966327d1dc9004551b63210b7)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "includes.h"
29 #include "atomicio.h"
30 #include "auth.h"
31 #include "bufaux.h"
32 #include "buffer.h"
33 #include "cipher.h"
34 #include "compat.h"
35 #include "dispatch.h"
36 #include "getput.h"
37 #include "kex.h"
38 #include "log.h"
39 #include "mac.h"
40 #include "packet.h"
41 #include "uidswap.h"
42 #include "ssh2.h"
43 #include "sshlogin.h"
44 #include "xmalloc.h"
45 #include "altprivsep.h"
46 #include <fcntl.h>
47 #include <sys/types.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/socket.h>
51 
52 extern Kex *xxx_kex;
53 
54 static Buffer to_monitor;
55 static Buffer from_monitor;
56 
57 /*
58  * Sun's Alternative Privilege Separation basics:
59  *
60  * Abstract
61  * --------
62  *
63  * sshd(1M) fork()s and drops privs in the child while retaining privs
64  * in the parent (a.k.a., the monitor).  The unprivileged sshd and the
65  * monitor talk over a pipe using a simple protocol.
66  *
67  * The monitor protocol is all about having the monitor carry out the
68  * only operations that require privileges OR access to privileged
69  * resources.  These are: utmpx/wtmpx record keeping, auditing, and
70  * SSHv2 re-keying.
71  *
72  * Re-Keying
73  * ---------
74  *
75  * Re-keying is the only protocol version specific aspect of sshd in
76  * which the monitor gets involved.
77  *
78  * The monitor processes all SSHv2 re-key protocol packets, but the
79  * unprivileged sshd process does the transport layer crypto for those
80  * packets.
81  *
82  * The monitor and its unprivileged sshd child process treat
83  * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call
84  * set_newkeys(), but b) the child asks the monitor for the set of
85  * negotiated algorithms, key, IV and what not for the relevant
86  * transport direction and then calls set_newkeys().
87  *
88  * Monitor Protocol
89  * ----------------
90  *
91  * Monitor IPC message formats are similar to SSHv2 messages, minus
92  * compression, encryption, padding and MACs:
93  *
94  *  - 4 octet message length
95  *  - message data
96  *     - 1 octet message type
97  *     - message data
98  *
99  * In broad strokes:
100  *
101  *  - IPC: pipe, exit(2)/wait4(2)
102  *
103  *  - threads: the monitor and child are single-threaded
104  *
105  *  - monitor main loop: a variant of server_loop2(), for re-keying only
106  *  - unpriv child main loop: server_loop2(), as usual
107  *
108  *  - protocol:
109  *     - key exchange packets are always forwarded as is to the monitor
110  *     - newkeys, record_login(), record_logout() are special packets
111  *     using the packet type range reserved for local extensions
112  *
113  *  - the child drops privs and runs like a normal sshd, except that it
114  *  sets dispatch handlers for key exchange packets that forward the
115  *  packets to the monitor
116  *
117  * Event loops:
118  *
119  *  - all monitor protocols are synchronous: because the SSHv2 rekey
120  *  protocols are synchronous and because the other monitor operations
121  *  are synchronous (or have no replies),
122  *
123  *  - server_loop2() is modified to check the monitor pipe for rekey
124  *  packets to forward to the client
125  *
126  *  - and dispatch handlers are set, upon receipt of KEXINIT (and reset
127  *  when NEWKEYS is sent out) to forward incoming rekey packets to the
128  *  monitor.
129  *
130  *  - the monitor runs an event loop not unlike server_loop2() and runs
131  *  key exchanges almost exactly as a pre-altprivsep sshd would
132  *
133  *  - unpriv sshd exit -> monitor cleanup (including audit logout) and exit
134  *
135  *  - fatal() in monitor -> forcibly shutdown() socket and kill/wait for
136  *  child (so that the audit event for the logout better reflects
137  *  reality -- i.e., logged out means logged out, but for bg jobs)
138  *
139  * Message formats:
140  *
141  *  - key exchange packets/replies forwarded "as is"
142  *
143  *  - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a
144  *  sub-type identifier (one octet)
145  *  - private request sub-types include:
146  *     - get new shared secret from last re-key
147  *     - record login  (utmpx/wtmpx), request data contains three arguments:
148  *     pid, ttyname, program name
149  *     - record logout (utmpx/wtmpx), request data contains one argument: pid
150  *
151  * Reply sub-types include:
152  *
153  *  - NOP (for record_login/logout)
154  *  - new shared secret from last re-key
155  */
156 
157 static int aps_started = 0;
158 static int is_monitor = 0;
159 
160 static pid_t monitor_pid, child_pid;
161 static int pipe_fds[2];
162 static int pipe_fd = -1;
163 static Buffer input_pipe, output_pipe; /* for pipe I/O */
164 
165 static Authctxt *xxx_authctxt;
166 
167 /* Monitor functions */
168 extern void aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid);
169 static void aps_record_login(void);
170 static void aps_record_logout(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 readyness 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(Kex *kex, 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 static void aps_send_newkeys(void);
526 
527 /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */
528 /* ARGSUSED */
529 void
530 aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt)
531 {
532 	u_char req_type;
533 
534 	req_type = packet_get_char();
535 
536 	switch (req_type) {
537 	case APS_MSG_NEWKEYS_REQ:
538 		aps_send_newkeys();
539 		break;
540 	case APS_MSG_RECORD_LOGIN:
541 		aps_record_login();
542 		break;
543 	case APS_MSG_RECORD_LOGOUT:
544 		aps_record_logout();
545 		break;
546 	default:
547 		break;
548 	}
549 }
550 
551 /* Monitor-side handlers for APS_MSG_* */
552 static
553 void
554 aps_send_newkeys(void)
555 {
556 	Newkeys *newkeys;
557 	Enc *enc;
558 	Mac *mac;
559 	Comp *comp;
560 	enum kex_modes mode;
561 
562 	/* get direction for which newkeys are wanted */
563 	mode = (enum kex_modes) packet_get_int();
564 	packet_check_eom();
565 
566 	/* get those newkeys */
567 	newkeys = kex_get_newkeys(mode);
568 	enc = &newkeys->enc;
569 	mac = &newkeys->mac;
570 	comp = &newkeys->comp;
571 
572 	/*
573 	 * Negotiated algorithms, client->server and server->client, for
574 	 * cipher, mac and compression.
575 	 */
576 	packet_start(SSH2_PRIV_MSG_ALTPRIVSEP);
577 	packet_put_char(APS_MSG_NEWKEYS_REP);
578 	packet_put_cstring(enc->name);
579 	packet_put_string(enc->key, enc->key_len);
580 	packet_put_string(enc->iv, enc->block_size);
581 	packet_put_cstring(mac->name);
582 	packet_put_string(mac->key, mac->key_len);
583 	packet_put_cstring(comp->name);
584 
585 	packet_send();
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