17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 59a8058b5Sjp161948 * Common Development and Distribution License (the "License"). 69a8058b5Sjp161948 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate * 21*dbe3f931Sjp161948 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 227c478bd9Sstevel@tonic-gate * Use is subject to license terms. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include "includes.h" 287c478bd9Sstevel@tonic-gate #include "atomicio.h" 297c478bd9Sstevel@tonic-gate #include "auth.h" 307c478bd9Sstevel@tonic-gate #include "bufaux.h" 317c478bd9Sstevel@tonic-gate #include "buffer.h" 327c478bd9Sstevel@tonic-gate #include "cipher.h" 337c478bd9Sstevel@tonic-gate #include "compat.h" 347c478bd9Sstevel@tonic-gate #include "dispatch.h" 357c478bd9Sstevel@tonic-gate #include "getput.h" 367c478bd9Sstevel@tonic-gate #include "kex.h" 377c478bd9Sstevel@tonic-gate #include "log.h" 387c478bd9Sstevel@tonic-gate #include "mac.h" 397c478bd9Sstevel@tonic-gate #include "packet.h" 407c478bd9Sstevel@tonic-gate #include "uidswap.h" 417c478bd9Sstevel@tonic-gate #include "ssh2.h" 427c478bd9Sstevel@tonic-gate #include "sshlogin.h" 437c478bd9Sstevel@tonic-gate #include "xmalloc.h" 447c478bd9Sstevel@tonic-gate #include "altprivsep.h" 457c478bd9Sstevel@tonic-gate #include <fcntl.h> 467c478bd9Sstevel@tonic-gate #include <sys/types.h> 477c478bd9Sstevel@tonic-gate #include <sys/types.h> 487c478bd9Sstevel@tonic-gate #include <sys/stat.h> 497c478bd9Sstevel@tonic-gate #include <sys/socket.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate extern Kex *xxx_kex; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static Buffer to_monitor; 547c478bd9Sstevel@tonic-gate static Buffer from_monitor; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Sun's Alternative Privilege Separation basics: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * Abstract 607c478bd9Sstevel@tonic-gate * -------- 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * sshd(1M) fork()s and drops privs in the child while retaining privs 637c478bd9Sstevel@tonic-gate * in the parent (a.k.a., the monitor). The unprivileged sshd and the 647c478bd9Sstevel@tonic-gate * monitor talk over a pipe using a simple protocol. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * The monitor protocol is all about having the monitor carry out the 677c478bd9Sstevel@tonic-gate * only operations that require privileges OR access to privileged 687c478bd9Sstevel@tonic-gate * resources. These are: utmpx/wtmpx record keeping, auditing, and 697c478bd9Sstevel@tonic-gate * SSHv2 re-keying. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * Re-Keying 727c478bd9Sstevel@tonic-gate * --------- 737c478bd9Sstevel@tonic-gate * 747c478bd9Sstevel@tonic-gate * Re-keying is the only protocol version specific aspect of sshd in 757c478bd9Sstevel@tonic-gate * which the monitor gets involved. 767c478bd9Sstevel@tonic-gate * 777c478bd9Sstevel@tonic-gate * The monitor processes all SSHv2 re-key protocol packets, but the 787c478bd9Sstevel@tonic-gate * unprivileged sshd process does the transport layer crypto for those 797c478bd9Sstevel@tonic-gate * packets. 807c478bd9Sstevel@tonic-gate * 817c478bd9Sstevel@tonic-gate * The monitor and its unprivileged sshd child process treat 827c478bd9Sstevel@tonic-gate * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call 837c478bd9Sstevel@tonic-gate * set_newkeys(), but b) the child asks the monitor for the set of 847c478bd9Sstevel@tonic-gate * negotiated algorithms, key, IV and what not for the relevant 857c478bd9Sstevel@tonic-gate * transport direction and then calls set_newkeys(). 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * Monitor Protocol 887c478bd9Sstevel@tonic-gate * ---------------- 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Monitor IPC message formats are similar to SSHv2 messages, minus 917c478bd9Sstevel@tonic-gate * compression, encryption, padding and MACs: 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * - 4 octet message length 947c478bd9Sstevel@tonic-gate * - message data 957c478bd9Sstevel@tonic-gate * - 1 octet message type 967c478bd9Sstevel@tonic-gate * - message data 977c478bd9Sstevel@tonic-gate * 987c478bd9Sstevel@tonic-gate * In broad strokes: 997c478bd9Sstevel@tonic-gate * 1007c478bd9Sstevel@tonic-gate * - IPC: pipe, exit(2)/wait4(2) 1017c478bd9Sstevel@tonic-gate * 1027c478bd9Sstevel@tonic-gate * - threads: the monitor and child are single-threaded 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * - monitor main loop: a variant of server_loop2(), for re-keying only 1057c478bd9Sstevel@tonic-gate * - unpriv child main loop: server_loop2(), as usual 1067c478bd9Sstevel@tonic-gate * 1077c478bd9Sstevel@tonic-gate * - protocol: 1087c478bd9Sstevel@tonic-gate * - key exchange packets are always forwarded as is to the monitor 1097c478bd9Sstevel@tonic-gate * - newkeys, record_login(), record_logout() are special packets 1107c478bd9Sstevel@tonic-gate * using the packet type range reserved for local extensions 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * - the child drops privs and runs like a normal sshd, except that it 1137c478bd9Sstevel@tonic-gate * sets dispatch handlers for key exchange packets that forward the 1147c478bd9Sstevel@tonic-gate * packets to the monitor 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * Event loops: 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * - all monitor protocols are synchronous: because the SSHv2 rekey 1197c478bd9Sstevel@tonic-gate * protocols are synchronous and because the other monitor operations 1207c478bd9Sstevel@tonic-gate * are synchronous (or have no replies), 1217c478bd9Sstevel@tonic-gate * 1227c478bd9Sstevel@tonic-gate * - server_loop2() is modified to check the monitor pipe for rekey 1237c478bd9Sstevel@tonic-gate * packets to forward to the client 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * - and dispatch handlers are set, upon receipt of KEXINIT (and reset 1267c478bd9Sstevel@tonic-gate * when NEWKEYS is sent out) to forward incoming rekey packets to the 1277c478bd9Sstevel@tonic-gate * monitor. 1287c478bd9Sstevel@tonic-gate * 1297c478bd9Sstevel@tonic-gate * - the monitor runs an event loop not unlike server_loop2() and runs 1307c478bd9Sstevel@tonic-gate * key exchanges almost exactly as a pre-altprivsep sshd would 1317c478bd9Sstevel@tonic-gate * 1327c478bd9Sstevel@tonic-gate * - unpriv sshd exit -> monitor cleanup (including audit logout) and exit 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * - fatal() in monitor -> forcibly shutdown() socket and kill/wait for 1357c478bd9Sstevel@tonic-gate * child (so that the audit event for the logout better reflects 1367c478bd9Sstevel@tonic-gate * reality -- i.e., logged out means logged out, but for bg jobs) 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * Message formats: 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * - key exchange packets/replies forwarded "as is" 1417c478bd9Sstevel@tonic-gate * 1427c478bd9Sstevel@tonic-gate * - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a 1437c478bd9Sstevel@tonic-gate * sub-type identifier (one octet) 1447c478bd9Sstevel@tonic-gate * - private request sub-types include: 1457c478bd9Sstevel@tonic-gate * - get new shared secret from last re-key 1467c478bd9Sstevel@tonic-gate * - record login (utmpx/wtmpx), request data contains three arguments: 1477c478bd9Sstevel@tonic-gate * pid, ttyname, program name 1487c478bd9Sstevel@tonic-gate * - record logout (utmpx/wtmpx), request data contains one argument: pid 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * Reply sub-types include: 1517c478bd9Sstevel@tonic-gate * 1527c478bd9Sstevel@tonic-gate * - NOP (for record_login/logout) 1537c478bd9Sstevel@tonic-gate * - new shared secret from last re-key 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static int aps_started = 0; 1577c478bd9Sstevel@tonic-gate static int is_monitor = 0; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static pid_t monitor_pid, child_pid; 1607c478bd9Sstevel@tonic-gate static int pipe_fds[2]; 1617c478bd9Sstevel@tonic-gate static int pipe_fd = -1; 1627c478bd9Sstevel@tonic-gate static Buffer input_pipe, output_pipe; /* for pipe I/O */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate static Authctxt *xxx_authctxt; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* Monitor functions */ 1677c478bd9Sstevel@tonic-gate extern void aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid); 1687c478bd9Sstevel@tonic-gate static void aps_record_login(void); 1697c478bd9Sstevel@tonic-gate static void aps_record_logout(void); 170*dbe3f931Sjp161948 static void aps_start_rekex(void); 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* Altprivsep packet utilities for communication with the monitor */ 1737c478bd9Sstevel@tonic-gate static void altprivsep_packet_start(u_char); 1747c478bd9Sstevel@tonic-gate static int altprivsep_packet_send(void); 1757c478bd9Sstevel@tonic-gate static int altprivsep_fwd_packet(u_char type); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static int altprivsep_packet_read(void); 1787c478bd9Sstevel@tonic-gate static void altprivsep_packet_read_expect(int type); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_char(int ch); 1817c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_int(u_int value); 1827c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_cstring(const char *str); 1837c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_raw(const void *buf, u_int len); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate static u_int altprivsep_packet_get_char(void); 1867c478bd9Sstevel@tonic-gate static void *altprivsep_packet_get_raw(u_int *length_ptr); 1877c478bd9Sstevel@tonic-gate static void *altprivsep_packet_get_string(u_int *length_ptr); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * Start monitor from privileged sshd process. 1917c478bd9Sstevel@tonic-gate * 1927c478bd9Sstevel@tonic-gate * Return values are like fork(2); the parent is the monitor. The caller should 1937c478bd9Sstevel@tonic-gate * fatal() on error. 1947c478bd9Sstevel@tonic-gate * 1957c478bd9Sstevel@tonic-gate * Privileges are dropped, on the unprivileged side, upon success. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate pid_t 1987c478bd9Sstevel@tonic-gate altprivsep_start_monitor(Authctxt *authctxt) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate pid_t pid; 2017c478bd9Sstevel@tonic-gate int junk; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (aps_started || authctxt == NULL || authctxt->pw == NULL) 2047c478bd9Sstevel@tonic-gate fatal("Monitor startup failed: missing state"); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate xxx_authctxt = authctxt; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate packet_set_server(); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate buffer_init(&output_pipe); 2117c478bd9Sstevel@tonic-gate buffer_init(&input_pipe); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate if (pipe(pipe_fds) != 0) { 2147c478bd9Sstevel@tonic-gate error("Monitor startup failure: could not create pipes: %s", 2157c478bd9Sstevel@tonic-gate strerror(errno)); 2167c478bd9Sstevel@tonic-gate return (-1); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC); 2207c478bd9Sstevel@tonic-gate (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate monitor_pid = getpid(); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if ((pid = fork()) > 0) { 2257c478bd9Sstevel@tonic-gate /* parent */ 2267c478bd9Sstevel@tonic-gate child_pid = pid; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate debug2("Monitor pid %ld, unprivileged child pid %ld", 2297c478bd9Sstevel@tonic-gate monitor_pid, child_pid); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate (void) close(pipe_fds[1]); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate pipe_fd = pipe_fds[0]; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 2367c478bd9Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 2377c478bd9Sstevel@tonic-gate 2389a8058b5Sjp161948 /* signal readiness of monitor */ 2397c478bd9Sstevel@tonic-gate (void) write(pipe_fd, &pid, sizeof (pid)); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate aps_started = 1; 2427c478bd9Sstevel@tonic-gate is_monitor = 1; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate debug2("Monitor started"); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate set_log_txt_prefix("monitor "); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate return (pid); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (pid < 0) { 2537c478bd9Sstevel@tonic-gate debug2("Monitor startup failure: could not fork unprivileged" 2547c478bd9Sstevel@tonic-gate " process: %s", strerror(errno)); 2557c478bd9Sstevel@tonic-gate return (pid); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* caller should drop privs */ 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate (void) close(pipe_fds[0]); 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate pipe_fd = pipe_fds[1]; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* wait for monitor to be ready */ 2657c478bd9Sstevel@tonic-gate debug2("Waiting for monitor"); 2667c478bd9Sstevel@tonic-gate (void) read(pipe_fd, &junk, sizeof (junk)); 2677c478bd9Sstevel@tonic-gate debug2("Monitor signalled readiness"); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 2707c478bd9Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate buffer_init(&to_monitor); 2737c478bd9Sstevel@tonic-gate buffer_init(&from_monitor); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (compat20) { 2767c478bd9Sstevel@tonic-gate debug3("Setting handler to forward re-key packets to monitor"); 2777c478bd9Sstevel@tonic-gate dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 2787c478bd9Sstevel@tonic-gate &altprivsep_rekey); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* AltPrivSep interfaces are set up */ 2827c478bd9Sstevel@tonic-gate aps_started = 1; 2837c478bd9Sstevel@tonic-gate return (pid); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate int 2877c478bd9Sstevel@tonic-gate altprivsep_get_pipe_fd(void) 2887c478bd9Sstevel@tonic-gate { 2897c478bd9Sstevel@tonic-gate return (pipe_fd); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate void 2937c478bd9Sstevel@tonic-gate altprivsep_rekey(int type, u_int32_t seq, void *ctxt) 2947c478bd9Sstevel@tonic-gate { 2957c478bd9Sstevel@tonic-gate Kex *kex = (Kex *)ctxt; 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate if (kex == NULL) 2987c478bd9Sstevel@tonic-gate fatal("Missing key exchange context in unprivileged process"); 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate debug2("Forwarding re-key packet (%d) to monitor", type); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate if (type != SSH2_MSG_NEWKEYS) 3037c478bd9Sstevel@tonic-gate if (!altprivsep_fwd_packet(type)) 3047c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* tell server_loop2() that we're re-keying */ 3077c478bd9Sstevel@tonic-gate kex->done = 0; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* NEWKEYS is special: get the new keys for client->server direction */ 3107c478bd9Sstevel@tonic-gate if (type == SSH2_MSG_NEWKEYS) { 3117c478bd9Sstevel@tonic-gate debug2("Getting new inbound keystate from monitor"); 3127c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(MODE_IN); 3137c478bd9Sstevel@tonic-gate kex->done = 1; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate void 318*dbe3f931Sjp161948 altprivsep_process_input(fd_set *rset) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate void *data; 3217c478bd9Sstevel@tonic-gate int type; 3227c478bd9Sstevel@tonic-gate u_int dlen; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate debug2("Reading from pipe to monitor (%d)", pipe_fd); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 3277c478bd9Sstevel@tonic-gate return; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate if (!FD_ISSET(pipe_fd, rset)) 3307c478bd9Sstevel@tonic-gate return; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate if ((type = altprivsep_packet_read()) == -1) 3337c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (!compat20) 3367c478bd9Sstevel@tonic-gate return; /* shouldn't happen! but be safe */ 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (type == 0) 3397c478bd9Sstevel@tonic-gate return; /* EOF -- nothing to do here */ 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate if (type >= SSH2_MSG_MAX) 3427c478bd9Sstevel@tonic-gate fatal("Received garbage from monitor"); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate debug2("Read packet type %d from pipe to monitor", (u_int)type); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (type == SSH2_PRIV_MSG_ALTPRIVSEP) 3477c478bd9Sstevel@tonic-gate return; /* shouldn't happen! */ 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* NEWKEYS is special: get the new keys for server->client direction */ 3507c478bd9Sstevel@tonic-gate if (type == SSH2_MSG_NEWKEYS) { 3517c478bd9Sstevel@tonic-gate debug2("Getting new outbound keystate from monitor"); 3527c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_NEWKEYS); 3537c478bd9Sstevel@tonic-gate packet_send(); 3547c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(MODE_OUT); 3557c478bd9Sstevel@tonic-gate return; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate data = altprivsep_packet_get_raw(&dlen); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate packet_start((u_char)type); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (data != NULL && dlen > 0) 3637c478bd9Sstevel@tonic-gate packet_put_raw(data, dlen); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate packet_send(); 3667c478bd9Sstevel@tonic-gate } 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate void 3697c478bd9Sstevel@tonic-gate altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid) 3707c478bd9Sstevel@tonic-gate { 3717c478bd9Sstevel@tonic-gate aps_monitor_loop(authctxt, pipe_fd, child_pid); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate int 3757c478bd9Sstevel@tonic-gate altprivsep_started(void) 3767c478bd9Sstevel@tonic-gate { 3777c478bd9Sstevel@tonic-gate return (aps_started); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate int 3817c478bd9Sstevel@tonic-gate altprivsep_is_monitor(void) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate return (is_monitor); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * A fatal cleanup function to forcibly shutdown the connection socket 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate void 3907c478bd9Sstevel@tonic-gate altprivsep_shutdown_sock(void *arg) 3917c478bd9Sstevel@tonic-gate { 3927c478bd9Sstevel@tonic-gate int sock; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate if (arg == NULL) 3957c478bd9Sstevel@tonic-gate return; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate sock = *(int *)arg; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate (void) shutdown(sock, SHUT_RDWR); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* Calls _to_ monitor from unprivileged process */ 4037c478bd9Sstevel@tonic-gate static 4047c478bd9Sstevel@tonic-gate int 4057c478bd9Sstevel@tonic-gate altprivsep_fwd_packet(u_char type) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate u_int len; 4087c478bd9Sstevel@tonic-gate void *data; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate altprivsep_packet_start(type); 4117c478bd9Sstevel@tonic-gate data = packet_get_raw(&len); 4127c478bd9Sstevel@tonic-gate altprivsep_packet_put_raw(data, len); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* packet_send()s any replies from the monitor to the client */ 4157c478bd9Sstevel@tonic-gate return (altprivsep_packet_send()); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate extern Newkeys *current_keys[MODE_MAX]; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* To be called from packet.c:set_newkeys() before referencing current_keys */ 4217c478bd9Sstevel@tonic-gate void 4227c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(enum kex_modes mode) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate Newkeys *newkeys; 4257c478bd9Sstevel@tonic-gate Comp *comp; 4267c478bd9Sstevel@tonic-gate Enc *enc; 4277c478bd9Sstevel@tonic-gate Mac *mac; 4287c478bd9Sstevel@tonic-gate u_int len; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate if (!altprivsep_started()) 4317c478bd9Sstevel@tonic-gate return; 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (altprivsep_is_monitor()) 4347c478bd9Sstevel@tonic-gate return; /* shouldn't happen */ 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* request new keys */ 4377c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 4387c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ); 4397c478bd9Sstevel@tonic-gate altprivsep_packet_put_int((u_int)mode); 4407c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 4417c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 4427c478bd9Sstevel@tonic-gate if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP) 4437c478bd9Sstevel@tonic-gate fatal("Received garbage from monitor during re-keying"); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate newkeys = xmalloc(sizeof (*newkeys)); 4467c478bd9Sstevel@tonic-gate memset(newkeys, 0, sizeof (*newkeys)); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate enc = &newkeys->enc; 4497c478bd9Sstevel@tonic-gate mac = &newkeys->mac; 4507c478bd9Sstevel@tonic-gate comp = &newkeys->comp; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* Cipher name, key, IV */ 4537c478bd9Sstevel@tonic-gate enc->name = altprivsep_packet_get_string(NULL); 4547c478bd9Sstevel@tonic-gate if ((enc->cipher = cipher_by_name(enc->name)) == NULL) 4557c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown cipher during re-key"); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate enc->key = altprivsep_packet_get_string(&enc->key_len); 4587c478bd9Sstevel@tonic-gate enc->iv = altprivsep_packet_get_string(&enc->block_size); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* MAC name */ 4617c478bd9Sstevel@tonic-gate mac->name = altprivsep_packet_get_string(NULL); 4627c478bd9Sstevel@tonic-gate if (mac_init(mac, mac->name) < 0) 4637c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown MAC algorithm " 4647c478bd9Sstevel@tonic-gate "during re-key"); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate mac->key = altprivsep_packet_get_string(&len); 4677c478bd9Sstevel@tonic-gate if (len > mac->key_len) 4687c478bd9Sstevel@tonic-gate fatal("%s: bad mac key length: %d > %d", __func__, len, 4697c478bd9Sstevel@tonic-gate mac->key_len); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* Compression algorithm name */ 4727c478bd9Sstevel@tonic-gate comp->name = altprivsep_packet_get_string(NULL); 4737c478bd9Sstevel@tonic-gate if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0) 4747c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown compression " 4757c478bd9Sstevel@tonic-gate "algorithm during re-key"); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate comp->type = 0; 4787c478bd9Sstevel@tonic-gate comp->enabled = 0; /* forces compression re-init, as per-spec */ 4797c478bd9Sstevel@tonic-gate if (strcmp(comp->name, "zlib") == 0) 4807c478bd9Sstevel@tonic-gate comp->type = 1; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Now install new keys 4847c478bd9Sstevel@tonic-gate * 4857c478bd9Sstevel@tonic-gate * For now abuse kex.c/packet.c non-interfaces. Someday, when 4867c478bd9Sstevel@tonic-gate * the many internal interfaces are parametrized, made reentrant 4877c478bd9Sstevel@tonic-gate * and thread-safe, made more consistent, and when necessary-but- 4887c478bd9Sstevel@tonic-gate * currently-missing interfaces are added then this bit of 4897c478bd9Sstevel@tonic-gate * ugliness can be revisited. 4907c478bd9Sstevel@tonic-gate * 4917c478bd9Sstevel@tonic-gate * The ugliness is in the set_newkeys(), its name and the lack 4927c478bd9Sstevel@tonic-gate * of a (Newkeys *) parameter, which forces us to pass the 4937c478bd9Sstevel@tonic-gate * newkeys through current_keys[mode]. But this saves us some 4947c478bd9Sstevel@tonic-gate * lines of code for now, though not comments. 4957c478bd9Sstevel@tonic-gate * 4967c478bd9Sstevel@tonic-gate * Also, we've abused, in the code above, knowledge of what 4977c478bd9Sstevel@tonic-gate * set_newkeys() expects the current_keys[mode] to contain. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate current_keys[mode] = newkeys; 5007c478bd9Sstevel@tonic-gate set_newkeys(mode); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate void 5057c478bd9Sstevel@tonic-gate altprivsep_record_login(pid_t pid, const char *ttyname) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 5087c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN); 5097c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(pid); 5107c478bd9Sstevel@tonic-gate altprivsep_packet_put_cstring(ttyname); 5117c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 5127c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate void 5167c478bd9Sstevel@tonic-gate altprivsep_record_logout(pid_t pid) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 5197c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT); 5207c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(pid); 5217c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 5227c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 525*dbe3f931Sjp161948 void 526*dbe3f931Sjp161948 altprivsep_start_rekex(void) 527*dbe3f931Sjp161948 { 528*dbe3f931Sjp161948 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 529*dbe3f931Sjp161948 altprivsep_packet_put_char(APS_MSG_START_REKEX); 530*dbe3f931Sjp161948 altprivsep_packet_send(); 531*dbe3f931Sjp161948 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 532*dbe3f931Sjp161948 } 533*dbe3f931Sjp161948 5347c478bd9Sstevel@tonic-gate static void aps_send_newkeys(void); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */ 5377c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5387c478bd9Sstevel@tonic-gate void 5397c478bd9Sstevel@tonic-gate aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt) 5407c478bd9Sstevel@tonic-gate { 5417c478bd9Sstevel@tonic-gate u_char req_type; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate req_type = packet_get_char(); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate switch (req_type) { 5467c478bd9Sstevel@tonic-gate case APS_MSG_NEWKEYS_REQ: 5477c478bd9Sstevel@tonic-gate aps_send_newkeys(); 5487c478bd9Sstevel@tonic-gate break; 5497c478bd9Sstevel@tonic-gate case APS_MSG_RECORD_LOGIN: 5507c478bd9Sstevel@tonic-gate aps_record_login(); 5517c478bd9Sstevel@tonic-gate break; 5527c478bd9Sstevel@tonic-gate case APS_MSG_RECORD_LOGOUT: 5537c478bd9Sstevel@tonic-gate aps_record_logout(); 5547c478bd9Sstevel@tonic-gate break; 555*dbe3f931Sjp161948 case APS_MSG_START_REKEX: 556*dbe3f931Sjp161948 aps_start_rekex(); 557*dbe3f931Sjp161948 break; 5587c478bd9Sstevel@tonic-gate default: 5597c478bd9Sstevel@tonic-gate break; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate /* Monitor-side handlers for APS_MSG_* */ 5647c478bd9Sstevel@tonic-gate static 5657c478bd9Sstevel@tonic-gate void 5667c478bd9Sstevel@tonic-gate aps_send_newkeys(void) 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate Newkeys *newkeys; 5697c478bd9Sstevel@tonic-gate Enc *enc; 5707c478bd9Sstevel@tonic-gate Mac *mac; 5717c478bd9Sstevel@tonic-gate Comp *comp; 5727c478bd9Sstevel@tonic-gate enum kex_modes mode; 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate /* get direction for which newkeys are wanted */ 5757c478bd9Sstevel@tonic-gate mode = (enum kex_modes) packet_get_int(); 5767c478bd9Sstevel@tonic-gate packet_check_eom(); 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* get those newkeys */ 5797c478bd9Sstevel@tonic-gate newkeys = kex_get_newkeys(mode); 5807c478bd9Sstevel@tonic-gate enc = &newkeys->enc; 5817c478bd9Sstevel@tonic-gate mac = &newkeys->mac; 5827c478bd9Sstevel@tonic-gate comp = &newkeys->comp; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * Negotiated algorithms, client->server and server->client, for 5867c478bd9Sstevel@tonic-gate * cipher, mac and compression. 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 5897c478bd9Sstevel@tonic-gate packet_put_char(APS_MSG_NEWKEYS_REP); 5907c478bd9Sstevel@tonic-gate packet_put_cstring(enc->name); 5917c478bd9Sstevel@tonic-gate packet_put_string(enc->key, enc->key_len); 5927c478bd9Sstevel@tonic-gate packet_put_string(enc->iv, enc->block_size); 5937c478bd9Sstevel@tonic-gate packet_put_cstring(mac->name); 5947c478bd9Sstevel@tonic-gate packet_put_string(mac->key, mac->key_len); 5957c478bd9Sstevel@tonic-gate packet_put_cstring(comp->name); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate packet_send(); 5989a8058b5Sjp161948 free_keys(newkeys); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate struct _aps_login_rec { 6027c478bd9Sstevel@tonic-gate pid_t lr_pid; 6037c478bd9Sstevel@tonic-gate char *lr_tty; 6047c478bd9Sstevel@tonic-gate struct _aps_login_rec *next; 6057c478bd9Sstevel@tonic-gate }; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate typedef struct _aps_login_rec aps_login_rec; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate static aps_login_rec *aps_login_list = NULL; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate static 6127c478bd9Sstevel@tonic-gate void 6137c478bd9Sstevel@tonic-gate aps_record_login(void) 6147c478bd9Sstevel@tonic-gate { 6157c478bd9Sstevel@tonic-gate aps_login_rec *new_rec; 6167c478bd9Sstevel@tonic-gate struct stat sbuf; 6177c478bd9Sstevel@tonic-gate size_t proc_path_len; 6187c478bd9Sstevel@tonic-gate char *proc_path; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate new_rec = xmalloc(sizeof (aps_login_rec)); 6217c478bd9Sstevel@tonic-gate memset(new_rec, 0, sizeof (aps_login_rec)); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate new_rec->lr_pid = packet_get_int(); 6247c478bd9Sstevel@tonic-gate new_rec->lr_tty = packet_get_string(NULL); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid); 6277c478bd9Sstevel@tonic-gate proc_path = xmalloc(proc_path_len + 1); 6287c478bd9Sstevel@tonic-gate (void) snprintf(proc_path, proc_path_len + 1, "/proc/%d", 6297c478bd9Sstevel@tonic-gate new_rec->lr_pid); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (stat(proc_path, &sbuf) || 6327c478bd9Sstevel@tonic-gate sbuf.st_uid != xxx_authctxt->pw->pw_uid || 6337c478bd9Sstevel@tonic-gate stat(new_rec->lr_tty, &sbuf) < 0 || 6347c478bd9Sstevel@tonic-gate sbuf.st_uid != xxx_authctxt->pw->pw_uid) { 6357c478bd9Sstevel@tonic-gate debug2("Spurious record_login request from unprivileged sshd"); 6367c478bd9Sstevel@tonic-gate xfree(proc_path); 6377c478bd9Sstevel@tonic-gate xfree(new_rec->lr_tty); 6387c478bd9Sstevel@tonic-gate xfree(new_rec); 6397c478bd9Sstevel@tonic-gate return; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* Insert new record on list */ 6437c478bd9Sstevel@tonic-gate new_rec->next = aps_login_list; 6447c478bd9Sstevel@tonic-gate aps_login_list = new_rec; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate record_login(new_rec->lr_pid, new_rec->lr_tty, NULL, 6477c478bd9Sstevel@tonic-gate xxx_authctxt->user); 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 6507c478bd9Sstevel@tonic-gate packet_send(); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate xfree(proc_path); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate static 6567c478bd9Sstevel@tonic-gate void 6577c478bd9Sstevel@tonic-gate aps_record_logout(void) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate aps_login_rec **p, *q; 6607c478bd9Sstevel@tonic-gate pid_t pid; 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate pid = packet_get_int(); 6637c478bd9Sstevel@tonic-gate packet_check_eom(); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate for (p = &aps_login_list; *p != NULL; p = &q->next) { 6667c478bd9Sstevel@tonic-gate q = *p; 6677c478bd9Sstevel@tonic-gate if (q->lr_pid == pid) { 6687c478bd9Sstevel@tonic-gate record_logout(q->lr_pid, q->lr_tty, NULL, 6697c478bd9Sstevel@tonic-gate xxx_authctxt->user); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* dequeue */ 6727c478bd9Sstevel@tonic-gate *p = q->next; 6737c478bd9Sstevel@tonic-gate xfree(q->lr_tty); 6747c478bd9Sstevel@tonic-gate xfree(q); 6757c478bd9Sstevel@tonic-gate break; 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 6807c478bd9Sstevel@tonic-gate packet_send(); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 683*dbe3f931Sjp161948 static 684*dbe3f931Sjp161948 void 685*dbe3f931Sjp161948 aps_start_rekex(void) 686*dbe3f931Sjp161948 { 687*dbe3f931Sjp161948 /* 688*dbe3f931Sjp161948 * Send confirmation. We could implement it without that but it doesn't 689*dbe3f931Sjp161948 * bring any harm to do that and we are consistent with other subtypes 690*dbe3f931Sjp161948 * of our private SSH2_PRIV_MSG_ALTPRIVSEP message type. 691*dbe3f931Sjp161948 */ 692*dbe3f931Sjp161948 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 693*dbe3f931Sjp161948 packet_send(); 694*dbe3f931Sjp161948 695*dbe3f931Sjp161948 /* 696*dbe3f931Sjp161948 * KEX_INIT message could be the one that reached the limit. In that 697*dbe3f931Sjp161948 * case, it was already forwarded to us from the unnprivileged child, 698*dbe3f931Sjp161948 * and maybe even acted upon. Obviously we must not send another 699*dbe3f931Sjp161948 * KEX_INIT message. 700*dbe3f931Sjp161948 */ 701*dbe3f931Sjp161948 if (!(xxx_kex->flags & KEX_INIT_SENT)) 702*dbe3f931Sjp161948 kex_send_kexinit(xxx_kex); 703*dbe3f931Sjp161948 else 704*dbe3f931Sjp161948 debug2("rekeying already in progress"); 705*dbe3f931Sjp161948 } 706*dbe3f931Sjp161948 707*dbe3f931Sjp161948 7087c478bd9Sstevel@tonic-gate /* Utilities for communication with the monitor */ 7097c478bd9Sstevel@tonic-gate static 7107c478bd9Sstevel@tonic-gate void 7117c478bd9Sstevel@tonic-gate altprivsep_packet_start(u_char type) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate buffer_clear(&to_monitor); 7147c478bd9Sstevel@tonic-gate buffer_put_char(&to_monitor, type); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate static 7177c478bd9Sstevel@tonic-gate void 7187c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(int ch) 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate buffer_put_char(&to_monitor, ch); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate static 7237c478bd9Sstevel@tonic-gate void 7247c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(u_int value) 7257c478bd9Sstevel@tonic-gate { 7267c478bd9Sstevel@tonic-gate buffer_put_int(&to_monitor, value); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate static 7297c478bd9Sstevel@tonic-gate void 7307c478bd9Sstevel@tonic-gate altprivsep_packet_put_cstring(const char *str) 7317c478bd9Sstevel@tonic-gate { 7327c478bd9Sstevel@tonic-gate buffer_put_cstring(&to_monitor, str); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate static 7357c478bd9Sstevel@tonic-gate void 7367c478bd9Sstevel@tonic-gate altprivsep_packet_put_raw(const void *buf, u_int len) 7377c478bd9Sstevel@tonic-gate { 7387c478bd9Sstevel@tonic-gate buffer_append(&to_monitor, buf, len); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * Send a monitor packet to the monitor. This function is blocking. 7437c478bd9Sstevel@tonic-gate * 7447c478bd9Sstevel@tonic-gate * Returns -1 if the monitor pipe has been closed earlier, fatal()s if 7457c478bd9Sstevel@tonic-gate * there's any other problems. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate static 7487c478bd9Sstevel@tonic-gate int 7497c478bd9Sstevel@tonic-gate altprivsep_packet_send(void) 7507c478bd9Sstevel@tonic-gate { 7517c478bd9Sstevel@tonic-gate ssize_t len; 7527c478bd9Sstevel@tonic-gate u_int32_t plen; /* packet length */ 7537c478bd9Sstevel@tonic-gate u_char plen_buf[sizeof (plen)]; 7547c478bd9Sstevel@tonic-gate u_char padlen; /* padding length */ 7557c478bd9Sstevel@tonic-gate fd_set *setp; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 7587c478bd9Sstevel@tonic-gate return (-1); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate if ((plen = buffer_len(&to_monitor)) == 0) 7617c478bd9Sstevel@tonic-gate return (0); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * We talk the SSHv2 binary packet protocol to the monitor, 7657c478bd9Sstevel@tonic-gate * using the none cipher, mac and compression algorithms. 7667c478bd9Sstevel@tonic-gate * 7677c478bd9Sstevel@tonic-gate * But, interestingly, the none cipher has a block size of 8 7687c478bd9Sstevel@tonic-gate * bytes, thus we must pad the packet. 7697c478bd9Sstevel@tonic-gate * 7707c478bd9Sstevel@tonic-gate * Also, encryption includes the packet length, so the padding 7717c478bd9Sstevel@tonic-gate * must account for that field. I.e., (sizeof (packet length) + 7727c478bd9Sstevel@tonic-gate * sizeof (padding length) + packet length + padding length) % 7737c478bd9Sstevel@tonic-gate * block_size must == 0. 7747c478bd9Sstevel@tonic-gate * 7757c478bd9Sstevel@tonic-gate * Also, there must be at least four (4) bytes of padding. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8; 7787c478bd9Sstevel@tonic-gate if (padlen < 4) 7797c478bd9Sstevel@tonic-gate padlen += 8; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* packet length counts padding and padding length field */ 7827c478bd9Sstevel@tonic-gate plen += padlen + sizeof (padlen); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate PUT_32BIT(plen_buf, plen); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 7877c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 7887c478bd9Sstevel@tonic-gate FD_SET(pipe_fd, setp); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) { 7917c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 7927c478bd9Sstevel@tonic-gate continue; 7937c478bd9Sstevel@tonic-gate else 7947c478bd9Sstevel@tonic-gate goto pipe_gone; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate xfree(setp); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* packet length field */ 8007c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, plen_buf, sizeof (plen)); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if (len != sizeof (plen)) 8037c478bd9Sstevel@tonic-gate goto pipe_gone; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* padding length field */ 8067c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, &padlen, sizeof (padlen)); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate if (len != sizeof (padlen)) 8097c478bd9Sstevel@tonic-gate goto pipe_gone; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate if (len != (plen - 1)) 8147c478bd9Sstevel@tonic-gate goto pipe_gone; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate buffer_clear(&to_monitor); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate return (1); 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate pipe_gone: 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate (void) close(pipe_fd); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate pipe_fd = -1; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate /* NOTREACHED */ 8297c478bd9Sstevel@tonic-gate return (0); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * Read a monitor packet from the monitor. This function is blocking. 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate static 8367c478bd9Sstevel@tonic-gate int 8377c478bd9Sstevel@tonic-gate altprivsep_packet_read(void) 8387c478bd9Sstevel@tonic-gate { 8397c478bd9Sstevel@tonic-gate ssize_t len = -1; 8407c478bd9Sstevel@tonic-gate u_int32_t plen; 8417c478bd9Sstevel@tonic-gate u_char plen_buf[sizeof (plen)]; 8427c478bd9Sstevel@tonic-gate u_char padlen; 8437c478bd9Sstevel@tonic-gate fd_set *setp; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 8467c478bd9Sstevel@tonic-gate return (-1); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 8497c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 8507c478bd9Sstevel@tonic-gate FD_SET(pipe_fd, setp); 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) { 8537c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 8547c478bd9Sstevel@tonic-gate continue; 8557c478bd9Sstevel@tonic-gate else 8567c478bd9Sstevel@tonic-gate goto pipe_gone; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate xfree(setp); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* packet length field */ 8627c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, plen_buf, sizeof (plen)); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate plen = GET_32BIT(plen_buf); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate if (len != sizeof (plen)) 8677c478bd9Sstevel@tonic-gate goto pipe_gone; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* padding length field */ 8707c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, &padlen, sizeof (padlen)); 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate if (len != sizeof (padlen)) 8737c478bd9Sstevel@tonic-gate goto pipe_gone; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate plen -= sizeof (padlen); 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate buffer_clear(&from_monitor); 8787c478bd9Sstevel@tonic-gate buffer_append_space(&from_monitor, plen); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* packet data + padding */ 8817c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate if (len != plen) 8847c478bd9Sstevel@tonic-gate goto pipe_gone; 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* remove padding */ 8877c478bd9Sstevel@tonic-gate if (padlen > 0) 8887c478bd9Sstevel@tonic-gate buffer_consume_end(&from_monitor, padlen); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* packet type */ 8917c478bd9Sstevel@tonic-gate return (buffer_get_char(&from_monitor)); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate pipe_gone: 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate (void) close(pipe_fd); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate pipe_fd = -1; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate if (len < 0) 9007c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate debug2("Monitor pipe closed by monitor"); 9037c478bd9Sstevel@tonic-gate return (0); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate static 9077c478bd9Sstevel@tonic-gate void 9087c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(int expected) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate int type; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate type = altprivsep_packet_read(); 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate if (type <= 0) 9157c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (type != expected) 9187c478bd9Sstevel@tonic-gate fatal("Protocol error in privilege separation; expected " 9197c478bd9Sstevel@tonic-gate "packet type %d, got %d", expected, type); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate static 9237c478bd9Sstevel@tonic-gate u_int 9247c478bd9Sstevel@tonic-gate altprivsep_packet_get_char(void) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate return (buffer_get_char(&from_monitor)); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate void 9297c478bd9Sstevel@tonic-gate *altprivsep_packet_get_raw(u_int *length_ptr) 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate if (length_ptr != NULL) 9327c478bd9Sstevel@tonic-gate *length_ptr = buffer_len(&from_monitor); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate return (buffer_ptr(&from_monitor)); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate void 9377c478bd9Sstevel@tonic-gate *altprivsep_packet_get_string(u_int *length_ptr) 9387c478bd9Sstevel@tonic-gate { 9397c478bd9Sstevel@tonic-gate return (buffer_get_string(&from_monitor, length_ptr)); 9407c478bd9Sstevel@tonic-gate } 941