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*8caf082fSJan Pechanec * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 227c478bd9Sstevel@tonic-gate * Use is subject to license terms. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 25cd7d5fafSJan Pechanec #include <fcntl.h> 26cd7d5fafSJan Pechanec #include <sys/types.h> 27cd7d5fafSJan Pechanec #include <sys/types.h> 28cd7d5fafSJan Pechanec #include <sys/stat.h> 29cd7d5fafSJan Pechanec #include <sys/socket.h> 30cd7d5fafSJan Pechanec 31cd7d5fafSJan Pechanec #include <pwd.h> 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include "includes.h" 347c478bd9Sstevel@tonic-gate #include "atomicio.h" 357c478bd9Sstevel@tonic-gate #include "auth.h" 367c478bd9Sstevel@tonic-gate #include "bufaux.h" 377c478bd9Sstevel@tonic-gate #include "buffer.h" 387c478bd9Sstevel@tonic-gate #include "cipher.h" 397c478bd9Sstevel@tonic-gate #include "compat.h" 407c478bd9Sstevel@tonic-gate #include "dispatch.h" 417c478bd9Sstevel@tonic-gate #include "getput.h" 427c478bd9Sstevel@tonic-gate #include "kex.h" 437c478bd9Sstevel@tonic-gate #include "log.h" 447c478bd9Sstevel@tonic-gate #include "mac.h" 457c478bd9Sstevel@tonic-gate #include "packet.h" 467c478bd9Sstevel@tonic-gate #include "uidswap.h" 477c478bd9Sstevel@tonic-gate #include "ssh2.h" 487c478bd9Sstevel@tonic-gate #include "sshlogin.h" 497c478bd9Sstevel@tonic-gate #include "xmalloc.h" 507c478bd9Sstevel@tonic-gate #include "altprivsep.h" 51cd7d5fafSJan Pechanec #include "canohost.h" 52cd7d5fafSJan Pechanec #include "engine.h" 53cd7d5fafSJan Pechanec #include "servconf.h" 54cd7d5fafSJan Pechanec 55cd7d5fafSJan Pechanec #ifdef HAVE_BSM 56cd7d5fafSJan Pechanec #include "bsmaudit.h" 57cd7d5fafSJan Pechanec adt_session_data_t *ah = NULL; 58cd7d5fafSJan Pechanec #endif /* HAVE_BSM */ 59cd7d5fafSJan Pechanec 60cd7d5fafSJan Pechanec #ifdef GSSAPI 61cd7d5fafSJan Pechanec #include "ssh-gss.h" 62cd7d5fafSJan Pechanec extern Gssctxt *xxx_gssctxt; 63cd7d5fafSJan Pechanec #endif /* GSSAPI */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate extern Kex *xxx_kex; 66cd7d5fafSJan Pechanec extern u_char *session_id2; 67cd7d5fafSJan Pechanec extern int session_id2_len; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static Buffer to_monitor; 707c478bd9Sstevel@tonic-gate static Buffer from_monitor; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * Sun's Alternative Privilege Separation basics: 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * Abstract 767c478bd9Sstevel@tonic-gate * -------- 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * sshd(1M) fork()s and drops privs in the child while retaining privs 797c478bd9Sstevel@tonic-gate * in the parent (a.k.a., the monitor). The unprivileged sshd and the 807c478bd9Sstevel@tonic-gate * monitor talk over a pipe using a simple protocol. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * The monitor protocol is all about having the monitor carry out the 837c478bd9Sstevel@tonic-gate * only operations that require privileges OR access to privileged 847c478bd9Sstevel@tonic-gate * resources. These are: utmpx/wtmpx record keeping, auditing, and 857c478bd9Sstevel@tonic-gate * SSHv2 re-keying. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * Re-Keying 887c478bd9Sstevel@tonic-gate * --------- 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Re-keying is the only protocol version specific aspect of sshd in 917c478bd9Sstevel@tonic-gate * which the monitor gets involved. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * The monitor processes all SSHv2 re-key protocol packets, but the 947c478bd9Sstevel@tonic-gate * unprivileged sshd process does the transport layer crypto for those 957c478bd9Sstevel@tonic-gate * packets. 967c478bd9Sstevel@tonic-gate * 977c478bd9Sstevel@tonic-gate * The monitor and its unprivileged sshd child process treat 987c478bd9Sstevel@tonic-gate * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call 997c478bd9Sstevel@tonic-gate * set_newkeys(), but b) the child asks the monitor for the set of 1007c478bd9Sstevel@tonic-gate * negotiated algorithms, key, IV and what not for the relevant 1017c478bd9Sstevel@tonic-gate * transport direction and then calls set_newkeys(). 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * Monitor Protocol 1047c478bd9Sstevel@tonic-gate * ---------------- 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * Monitor IPC message formats are similar to SSHv2 messages, minus 1077c478bd9Sstevel@tonic-gate * compression, encryption, padding and MACs: 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * - 4 octet message length 1107c478bd9Sstevel@tonic-gate * - message data 1117c478bd9Sstevel@tonic-gate * - 1 octet message type 1127c478bd9Sstevel@tonic-gate * - message data 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * In broad strokes: 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * - IPC: pipe, exit(2)/wait4(2) 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * - threads: the monitor and child are single-threaded 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * - monitor main loop: a variant of server_loop2(), for re-keying only 1217c478bd9Sstevel@tonic-gate * - unpriv child main loop: server_loop2(), as usual 1227c478bd9Sstevel@tonic-gate * 1237c478bd9Sstevel@tonic-gate * - protocol: 1247c478bd9Sstevel@tonic-gate * - key exchange packets are always forwarded as is to the monitor 1257c478bd9Sstevel@tonic-gate * - newkeys, record_login(), record_logout() are special packets 1267c478bd9Sstevel@tonic-gate * using the packet type range reserved for local extensions 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * - the child drops privs and runs like a normal sshd, except that it 1297c478bd9Sstevel@tonic-gate * sets dispatch handlers for key exchange packets that forward the 1307c478bd9Sstevel@tonic-gate * packets to the monitor 1317c478bd9Sstevel@tonic-gate * 1327c478bd9Sstevel@tonic-gate * Event loops: 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * - all monitor protocols are synchronous: because the SSHv2 rekey 1357c478bd9Sstevel@tonic-gate * protocols are synchronous and because the other monitor operations 1367c478bd9Sstevel@tonic-gate * are synchronous (or have no replies), 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * - server_loop2() is modified to check the monitor pipe for rekey 1397c478bd9Sstevel@tonic-gate * packets to forward to the client 1407c478bd9Sstevel@tonic-gate * 1417c478bd9Sstevel@tonic-gate * - and dispatch handlers are set, upon receipt of KEXINIT (and reset 1427c478bd9Sstevel@tonic-gate * when NEWKEYS is sent out) to forward incoming rekey packets to the 1437c478bd9Sstevel@tonic-gate * monitor. 1447c478bd9Sstevel@tonic-gate * 1457c478bd9Sstevel@tonic-gate * - the monitor runs an event loop not unlike server_loop2() and runs 1467c478bd9Sstevel@tonic-gate * key exchanges almost exactly as a pre-altprivsep sshd would 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * - unpriv sshd exit -> monitor cleanup (including audit logout) and exit 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * - fatal() in monitor -> forcibly shutdown() socket and kill/wait for 1517c478bd9Sstevel@tonic-gate * child (so that the audit event for the logout better reflects 1527c478bd9Sstevel@tonic-gate * reality -- i.e., logged out means logged out, but for bg jobs) 1537c478bd9Sstevel@tonic-gate * 1547c478bd9Sstevel@tonic-gate * Message formats: 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * - key exchange packets/replies forwarded "as is" 1577c478bd9Sstevel@tonic-gate * 1587c478bd9Sstevel@tonic-gate * - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a 1597c478bd9Sstevel@tonic-gate * sub-type identifier (one octet) 1607c478bd9Sstevel@tonic-gate * - private request sub-types include: 1617c478bd9Sstevel@tonic-gate * - get new shared secret from last re-key 1627c478bd9Sstevel@tonic-gate * - record login (utmpx/wtmpx), request data contains three arguments: 1637c478bd9Sstevel@tonic-gate * pid, ttyname, program name 1647c478bd9Sstevel@tonic-gate * - record logout (utmpx/wtmpx), request data contains one argument: pid 1657c478bd9Sstevel@tonic-gate * 1667c478bd9Sstevel@tonic-gate * Reply sub-types include: 1677c478bd9Sstevel@tonic-gate * 1687c478bd9Sstevel@tonic-gate * - NOP (for record_login/logout) 1697c478bd9Sstevel@tonic-gate * - new shared secret from last re-key 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static int aps_started = 0; 1737c478bd9Sstevel@tonic-gate static int is_monitor = 0; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate static pid_t monitor_pid, child_pid; 1767c478bd9Sstevel@tonic-gate static int pipe_fds[2]; 1777c478bd9Sstevel@tonic-gate static int pipe_fd = -1; 1787c478bd9Sstevel@tonic-gate static Buffer input_pipe, output_pipe; /* for pipe I/O */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate static Authctxt *xxx_authctxt; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* Monitor functions */ 183cd7d5fafSJan Pechanec extern void aps_monitor_loop(Authctxt *authctxt, pid_t child_pid); 1847c478bd9Sstevel@tonic-gate static void aps_record_login(void); 1857c478bd9Sstevel@tonic-gate static void aps_record_logout(void); 186dbe3f931Sjp161948 static void aps_start_rekex(void); 187cd7d5fafSJan Pechanec Authctxt *aps_read_auth_context(void); 188cd7d5fafSJan Pechanec 189cd7d5fafSJan Pechanec /* main functions for handling the monitor */ 190cd7d5fafSJan Pechanec static pid_t altprivsep_start_monitor(Authctxt **authctxt); 191cd7d5fafSJan Pechanec static void altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid); 192cd7d5fafSJan Pechanec static int altprivsep_started(void); 193cd7d5fafSJan Pechanec static int altprivsep_is_monitor(void); 194cd7d5fafSJan Pechanec 195cd7d5fafSJan Pechanec /* calls _to_ monitor from unprivileged process */ 196cd7d5fafSJan Pechanec static void altprivsep_get_newkeys(enum kex_modes mode); 197cd7d5fafSJan Pechanec 198cd7d5fafSJan Pechanec /* monitor-side fatal_cleanup callbacks */ 199cd7d5fafSJan Pechanec static void altprivsep_shutdown_sock(void *arg); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* Altprivsep packet utilities for communication with the monitor */ 2027c478bd9Sstevel@tonic-gate static void altprivsep_packet_start(u_char); 2037c478bd9Sstevel@tonic-gate static int altprivsep_packet_send(void); 2047c478bd9Sstevel@tonic-gate static int altprivsep_fwd_packet(u_char type); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate static int altprivsep_packet_read(void); 2077c478bd9Sstevel@tonic-gate static void altprivsep_packet_read_expect(int type); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_char(int ch); 2107c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_int(u_int value); 2117c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_cstring(const char *str); 2127c478bd9Sstevel@tonic-gate static void altprivsep_packet_put_raw(const void *buf, u_int len); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate static u_int altprivsep_packet_get_char(void); 2157c478bd9Sstevel@tonic-gate static void *altprivsep_packet_get_raw(u_int *length_ptr); 2167c478bd9Sstevel@tonic-gate static void *altprivsep_packet_get_string(u_int *length_ptr); 2177c478bd9Sstevel@tonic-gate 218cd7d5fafSJan Pechanec Kex *prepare_for_ssh2_kex(void); 219cd7d5fafSJan Pechanec 2207c478bd9Sstevel@tonic-gate /* 2217c478bd9Sstevel@tonic-gate * Start monitor from privileged sshd process. 2227c478bd9Sstevel@tonic-gate * 2237c478bd9Sstevel@tonic-gate * Return values are like fork(2); the parent is the monitor. The caller should 2247c478bd9Sstevel@tonic-gate * fatal() on error. 2257c478bd9Sstevel@tonic-gate * 226cd7d5fafSJan Pechanec * Note that the monitor waits until the still privileged child finishes the 227cd7d5fafSJan Pechanec * authentication. The child drops its privileges after the authentication. 2287c478bd9Sstevel@tonic-gate */ 229cd7d5fafSJan Pechanec static pid_t 230cd7d5fafSJan Pechanec altprivsep_start_monitor(Authctxt **authctxt) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate pid_t pid; 2337c478bd9Sstevel@tonic-gate int junk; 2347c478bd9Sstevel@tonic-gate 235cd7d5fafSJan Pechanec if (aps_started) 2367c478bd9Sstevel@tonic-gate fatal("Monitor startup failed: missing state"); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate buffer_init(&output_pipe); 2397c478bd9Sstevel@tonic-gate buffer_init(&input_pipe); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (pipe(pipe_fds) != 0) { 2427c478bd9Sstevel@tonic-gate error("Monitor startup failure: could not create pipes: %s", 2437c478bd9Sstevel@tonic-gate strerror(errno)); 2447c478bd9Sstevel@tonic-gate return (-1); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC); 2487c478bd9Sstevel@tonic-gate (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC); 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate monitor_pid = getpid(); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if ((pid = fork()) > 0) { 253cd7d5fafSJan Pechanec /* 254cd7d5fafSJan Pechanec * From now on, all debug messages from monitor will have prefix 255cd7d5fafSJan Pechanec * "monitor " 256cd7d5fafSJan Pechanec */ 257cd7d5fafSJan Pechanec set_log_txt_prefix("monitor "); 258cd7d5fafSJan Pechanec (void) prepare_for_ssh2_kex(); 259cd7d5fafSJan Pechanec packet_set_server(); 2607c478bd9Sstevel@tonic-gate /* parent */ 2617c478bd9Sstevel@tonic-gate child_pid = pid; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate debug2("Monitor pid %ld, unprivileged child pid %ld", 2647c478bd9Sstevel@tonic-gate monitor_pid, child_pid); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate (void) close(pipe_fds[1]); 2677c478bd9Sstevel@tonic-gate pipe_fd = pipe_fds[0]; 2687c478bd9Sstevel@tonic-gate 269cd7d5fafSJan Pechanec /* 270cd7d5fafSJan Pechanec * Signal readiness of the monitor and then read the 271cd7d5fafSJan Pechanec * authentication context from the child. 272cd7d5fafSJan Pechanec */ 273cd7d5fafSJan Pechanec (void) write(pipe_fd, &pid, sizeof (pid)); 274cd7d5fafSJan Pechanec packet_set_monitor(pipe_fd); 275cd7d5fafSJan Pechanec xxx_authctxt = *authctxt = aps_read_auth_context(); 276cd7d5fafSJan Pechanec 2777c478bd9Sstevel@tonic-gate if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 2787c478bd9Sstevel@tonic-gate error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate aps_started = 1; 2817c478bd9Sstevel@tonic-gate is_monitor = 1; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate debug2("Monitor started"); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate return (pid); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if (pid < 0) { 2897c478bd9Sstevel@tonic-gate debug2("Monitor startup failure: could not fork unprivileged" 2907c478bd9Sstevel@tonic-gate " process: %s", strerror(errno)); 2917c478bd9Sstevel@tonic-gate return (pid); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 294cd7d5fafSJan Pechanec /* this is the child that will later drop privileges */ 2957c478bd9Sstevel@tonic-gate 296cd7d5fafSJan Pechanec /* note that Solaris has bi-directional pipes so one pipe is enough */ 2977c478bd9Sstevel@tonic-gate (void) close(pipe_fds[0]); 2987c478bd9Sstevel@tonic-gate pipe_fd = pipe_fds[1]; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* wait for monitor to be ready */ 3017c478bd9Sstevel@tonic-gate debug2("Waiting for monitor"); 3027c478bd9Sstevel@tonic-gate (void) read(pipe_fd, &junk, sizeof (junk)); 3037c478bd9Sstevel@tonic-gate debug2("Monitor signalled readiness"); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate buffer_init(&to_monitor); 3067c478bd9Sstevel@tonic-gate buffer_init(&from_monitor); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* AltPrivSep interfaces are set up */ 3097c478bd9Sstevel@tonic-gate aps_started = 1; 3107c478bd9Sstevel@tonic-gate return (pid); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate int 3147c478bd9Sstevel@tonic-gate altprivsep_get_pipe_fd(void) 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate return (pipe_fd); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 319cd7d5fafSJan Pechanec /* 320cd7d5fafSJan Pechanec * This function is used in the unprivileged child for all packets in the range 321cd7d5fafSJan Pechanec * between SSH2_MSG_KEXINIT and SSH2_MSG_TRANSPORT_MAX. 322cd7d5fafSJan Pechanec */ 3237c478bd9Sstevel@tonic-gate void 3247c478bd9Sstevel@tonic-gate altprivsep_rekey(int type, u_int32_t seq, void *ctxt) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate Kex *kex = (Kex *)ctxt; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (kex == NULL) 3297c478bd9Sstevel@tonic-gate fatal("Missing key exchange context in unprivileged process"); 3307c478bd9Sstevel@tonic-gate 331cd7d5fafSJan Pechanec if (type != SSH2_MSG_NEWKEYS) { 3327c478bd9Sstevel@tonic-gate debug2("Forwarding re-key packet (%d) to monitor", type); 3337c478bd9Sstevel@tonic-gate if (!altprivsep_fwd_packet(type)) 3347c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 335cd7d5fafSJan Pechanec } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* tell server_loop2() that we're re-keying */ 3387c478bd9Sstevel@tonic-gate kex->done = 0; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* NEWKEYS is special: get the new keys for client->server direction */ 3417c478bd9Sstevel@tonic-gate if (type == SSH2_MSG_NEWKEYS) { 342cd7d5fafSJan Pechanec debug2("received SSH2_MSG_NEWKEYS packet - " 343cd7d5fafSJan Pechanec "getting new inbound keys from the monitor"); 3447c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(MODE_IN); 3457c478bd9Sstevel@tonic-gate kex->done = 1; 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate void 350dbe3f931Sjp161948 altprivsep_process_input(fd_set *rset) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate void *data; 3537c478bd9Sstevel@tonic-gate int type; 3547c478bd9Sstevel@tonic-gate u_int dlen; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 3577c478bd9Sstevel@tonic-gate return; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (!FD_ISSET(pipe_fd, rset)) 3607c478bd9Sstevel@tonic-gate return; 3617c478bd9Sstevel@tonic-gate 362cd7d5fafSJan Pechanec debug2("reading from pipe to monitor (%d)", pipe_fd); 3637c478bd9Sstevel@tonic-gate if ((type = altprivsep_packet_read()) == -1) 3647c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (!compat20) 3677c478bd9Sstevel@tonic-gate return; /* shouldn't happen! but be safe */ 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate if (type == 0) 3707c478bd9Sstevel@tonic-gate return; /* EOF -- nothing to do here */ 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (type >= SSH2_MSG_MAX) 3737c478bd9Sstevel@tonic-gate fatal("Received garbage from monitor"); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate debug2("Read packet type %d from pipe to monitor", (u_int)type); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate if (type == SSH2_PRIV_MSG_ALTPRIVSEP) 3787c478bd9Sstevel@tonic-gate return; /* shouldn't happen! */ 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* NEWKEYS is special: get the new keys for server->client direction */ 3817c478bd9Sstevel@tonic-gate if (type == SSH2_MSG_NEWKEYS) { 382cd7d5fafSJan Pechanec debug2("forwarding SSH2_MSG_NEWKEYS packet we got from monitor to " 383cd7d5fafSJan Pechanec "the client"); 3847c478bd9Sstevel@tonic-gate packet_start(SSH2_MSG_NEWKEYS); 3857c478bd9Sstevel@tonic-gate packet_send(); 386cd7d5fafSJan Pechanec debug2("getting new outbound keys from the monitor"); 3877c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(MODE_OUT); 3887c478bd9Sstevel@tonic-gate return; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate data = altprivsep_packet_get_raw(&dlen); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate packet_start((u_char)type); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate if (data != NULL && dlen > 0) 3967c478bd9Sstevel@tonic-gate packet_put_raw(data, dlen); 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate packet_send(); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 401cd7d5fafSJan Pechanec static void 4027c478bd9Sstevel@tonic-gate altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid) 4037c478bd9Sstevel@tonic-gate { 404cd7d5fafSJan Pechanec aps_monitor_loop(authctxt, child_pid); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 407cd7d5fafSJan Pechanec static int 4087c478bd9Sstevel@tonic-gate altprivsep_started(void) 4097c478bd9Sstevel@tonic-gate { 4107c478bd9Sstevel@tonic-gate return (aps_started); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 413cd7d5fafSJan Pechanec static int 4147c478bd9Sstevel@tonic-gate altprivsep_is_monitor(void) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate return (is_monitor); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * A fatal cleanup function to forcibly shutdown the connection socket 4217c478bd9Sstevel@tonic-gate */ 422cd7d5fafSJan Pechanec static void 4237c478bd9Sstevel@tonic-gate altprivsep_shutdown_sock(void *arg) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate int sock; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if (arg == NULL) 4287c478bd9Sstevel@tonic-gate return; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate sock = *(int *)arg; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate (void) shutdown(sock, SHUT_RDWR); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* Calls _to_ monitor from unprivileged process */ 436cd7d5fafSJan Pechanec static int 4377c478bd9Sstevel@tonic-gate altprivsep_fwd_packet(u_char type) 4387c478bd9Sstevel@tonic-gate { 4397c478bd9Sstevel@tonic-gate u_int len; 4407c478bd9Sstevel@tonic-gate void *data; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate altprivsep_packet_start(type); 4437c478bd9Sstevel@tonic-gate data = packet_get_raw(&len); 4447c478bd9Sstevel@tonic-gate altprivsep_packet_put_raw(data, len); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* packet_send()s any replies from the monitor to the client */ 4477c478bd9Sstevel@tonic-gate return (altprivsep_packet_send()); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate extern Newkeys *current_keys[MODE_MAX]; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* To be called from packet.c:set_newkeys() before referencing current_keys */ 453cd7d5fafSJan Pechanec static void 4547c478bd9Sstevel@tonic-gate altprivsep_get_newkeys(enum kex_modes mode) 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate Newkeys *newkeys; 4577c478bd9Sstevel@tonic-gate Comp *comp; 4587c478bd9Sstevel@tonic-gate Enc *enc; 4597c478bd9Sstevel@tonic-gate Mac *mac; 4607c478bd9Sstevel@tonic-gate u_int len; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if (!altprivsep_started()) 4637c478bd9Sstevel@tonic-gate return; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate if (altprivsep_is_monitor()) 4667c478bd9Sstevel@tonic-gate return; /* shouldn't happen */ 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* request new keys */ 4697c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 4707c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ); 4717c478bd9Sstevel@tonic-gate altprivsep_packet_put_int((u_int)mode); 4727c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 4737c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 4747c478bd9Sstevel@tonic-gate if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP) 4757c478bd9Sstevel@tonic-gate fatal("Received garbage from monitor during re-keying"); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate newkeys = xmalloc(sizeof (*newkeys)); 4787c478bd9Sstevel@tonic-gate memset(newkeys, 0, sizeof (*newkeys)); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate enc = &newkeys->enc; 4817c478bd9Sstevel@tonic-gate mac = &newkeys->mac; 4827c478bd9Sstevel@tonic-gate comp = &newkeys->comp; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* Cipher name, key, IV */ 4857c478bd9Sstevel@tonic-gate enc->name = altprivsep_packet_get_string(NULL); 4867c478bd9Sstevel@tonic-gate if ((enc->cipher = cipher_by_name(enc->name)) == NULL) 4877c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown cipher during re-key"); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate enc->key = altprivsep_packet_get_string(&enc->key_len); 4907c478bd9Sstevel@tonic-gate enc->iv = altprivsep_packet_get_string(&enc->block_size); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* MAC name */ 4937c478bd9Sstevel@tonic-gate mac->name = altprivsep_packet_get_string(NULL); 494*8caf082fSJan Pechanec if (mac_setup(mac, mac->name) < 0) 4957c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown MAC algorithm " 4967c478bd9Sstevel@tonic-gate "during re-key"); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate mac->key = altprivsep_packet_get_string(&len); 4997c478bd9Sstevel@tonic-gate if (len > mac->key_len) 5007c478bd9Sstevel@tonic-gate fatal("%s: bad mac key length: %d > %d", __func__, len, 5017c478bd9Sstevel@tonic-gate mac->key_len); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* Compression algorithm name */ 5047c478bd9Sstevel@tonic-gate comp->name = altprivsep_packet_get_string(NULL); 5057c478bd9Sstevel@tonic-gate if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0) 5067c478bd9Sstevel@tonic-gate fatal("Monitor negotiated an unknown compression " 5077c478bd9Sstevel@tonic-gate "algorithm during re-key"); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate comp->type = 0; 5107c478bd9Sstevel@tonic-gate comp->enabled = 0; /* forces compression re-init, as per-spec */ 5117c478bd9Sstevel@tonic-gate if (strcmp(comp->name, "zlib") == 0) 5127c478bd9Sstevel@tonic-gate comp->type = 1; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Now install new keys 5167c478bd9Sstevel@tonic-gate * 5177c478bd9Sstevel@tonic-gate * For now abuse kex.c/packet.c non-interfaces. Someday, when 5187c478bd9Sstevel@tonic-gate * the many internal interfaces are parametrized, made reentrant 5197c478bd9Sstevel@tonic-gate * and thread-safe, made more consistent, and when necessary-but- 5207c478bd9Sstevel@tonic-gate * currently-missing interfaces are added then this bit of 5217c478bd9Sstevel@tonic-gate * ugliness can be revisited. 5227c478bd9Sstevel@tonic-gate * 5237c478bd9Sstevel@tonic-gate * The ugliness is in the set_newkeys(), its name and the lack 5247c478bd9Sstevel@tonic-gate * of a (Newkeys *) parameter, which forces us to pass the 5257c478bd9Sstevel@tonic-gate * newkeys through current_keys[mode]. But this saves us some 5267c478bd9Sstevel@tonic-gate * lines of code for now, though not comments. 5277c478bd9Sstevel@tonic-gate * 5287c478bd9Sstevel@tonic-gate * Also, we've abused, in the code above, knowledge of what 5297c478bd9Sstevel@tonic-gate * set_newkeys() expects the current_keys[mode] to contain. 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate current_keys[mode] = newkeys; 5327c478bd9Sstevel@tonic-gate set_newkeys(mode); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate void 5377c478bd9Sstevel@tonic-gate altprivsep_record_login(pid_t pid, const char *ttyname) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 5407c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN); 5417c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(pid); 5427c478bd9Sstevel@tonic-gate altprivsep_packet_put_cstring(ttyname); 5437c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 5447c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate void 5487c478bd9Sstevel@tonic-gate altprivsep_record_logout(pid_t pid) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 5517c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT); 5527c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(pid); 5537c478bd9Sstevel@tonic-gate altprivsep_packet_send(); 5547c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 557dbe3f931Sjp161948 void 558dbe3f931Sjp161948 altprivsep_start_rekex(void) 559dbe3f931Sjp161948 { 560dbe3f931Sjp161948 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 561dbe3f931Sjp161948 altprivsep_packet_put_char(APS_MSG_START_REKEX); 562dbe3f931Sjp161948 altprivsep_packet_send(); 563dbe3f931Sjp161948 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 564dbe3f931Sjp161948 } 565dbe3f931Sjp161948 566cd7d5fafSJan Pechanec /* 567cd7d5fafSJan Pechanec * The monitor needs some information that its child learns during the 568cd7d5fafSJan Pechanec * authentication process. Since the child was forked before the key exchange 569cd7d5fafSJan Pechanec * and authentication started it must send some context to the monitor after the 570cd7d5fafSJan Pechanec * authentication is finished. Less obvious part - monitor needs the session ID 571cd7d5fafSJan Pechanec * since it is used in the key generation process after the key (re-)exchange is 572cd7d5fafSJan Pechanec * finished. 573cd7d5fafSJan Pechanec */ 574cd7d5fafSJan Pechanec void 575cd7d5fafSJan Pechanec altprivsep_send_auth_context(Authctxt *authctxt) 576cd7d5fafSJan Pechanec { 577cd7d5fafSJan Pechanec debug("sending auth context to the monitor"); 578cd7d5fafSJan Pechanec altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 579cd7d5fafSJan Pechanec altprivsep_packet_put_char(APS_MSG_AUTH_CONTEXT); 580cd7d5fafSJan Pechanec altprivsep_packet_put_int(authctxt->pw->pw_uid); 581cd7d5fafSJan Pechanec altprivsep_packet_put_int(authctxt->pw->pw_gid); 582cd7d5fafSJan Pechanec altprivsep_packet_put_cstring(authctxt->pw->pw_name); 583cd7d5fafSJan Pechanec altprivsep_packet_put_raw(session_id2, session_id2_len); 584cd7d5fafSJan Pechanec debug("will send %d bytes of auth context to the monitor", 585cd7d5fafSJan Pechanec buffer_len(&to_monitor)); 586cd7d5fafSJan Pechanec altprivsep_packet_send(); 587cd7d5fafSJan Pechanec altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 588cd7d5fafSJan Pechanec } 589cd7d5fafSJan Pechanec 5907c478bd9Sstevel@tonic-gate static void aps_send_newkeys(void); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */ 5937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5947c478bd9Sstevel@tonic-gate void 5957c478bd9Sstevel@tonic-gate aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate u_char req_type; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate req_type = packet_get_char(); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate switch (req_type) { 6027c478bd9Sstevel@tonic-gate case APS_MSG_NEWKEYS_REQ: 6037c478bd9Sstevel@tonic-gate aps_send_newkeys(); 6047c478bd9Sstevel@tonic-gate break; 6057c478bd9Sstevel@tonic-gate case APS_MSG_RECORD_LOGIN: 6067c478bd9Sstevel@tonic-gate aps_record_login(); 6077c478bd9Sstevel@tonic-gate break; 6087c478bd9Sstevel@tonic-gate case APS_MSG_RECORD_LOGOUT: 6097c478bd9Sstevel@tonic-gate aps_record_logout(); 6107c478bd9Sstevel@tonic-gate break; 611dbe3f931Sjp161948 case APS_MSG_START_REKEX: 612dbe3f931Sjp161948 aps_start_rekex(); 613dbe3f931Sjp161948 break; 6147c478bd9Sstevel@tonic-gate default: 6157c478bd9Sstevel@tonic-gate break; 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* Monitor-side handlers for APS_MSG_* */ 6207c478bd9Sstevel@tonic-gate static 6217c478bd9Sstevel@tonic-gate void 6227c478bd9Sstevel@tonic-gate aps_send_newkeys(void) 6237c478bd9Sstevel@tonic-gate { 6247c478bd9Sstevel@tonic-gate Newkeys *newkeys; 6257c478bd9Sstevel@tonic-gate Enc *enc; 6267c478bd9Sstevel@tonic-gate Mac *mac; 6277c478bd9Sstevel@tonic-gate Comp *comp; 6287c478bd9Sstevel@tonic-gate enum kex_modes mode; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate /* get direction for which newkeys are wanted */ 6317c478bd9Sstevel@tonic-gate mode = (enum kex_modes) packet_get_int(); 6327c478bd9Sstevel@tonic-gate packet_check_eom(); 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* get those newkeys */ 6357c478bd9Sstevel@tonic-gate newkeys = kex_get_newkeys(mode); 6367c478bd9Sstevel@tonic-gate enc = &newkeys->enc; 6377c478bd9Sstevel@tonic-gate mac = &newkeys->mac; 6387c478bd9Sstevel@tonic-gate comp = &newkeys->comp; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Negotiated algorithms, client->server and server->client, for 6427c478bd9Sstevel@tonic-gate * cipher, mac and compression. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 6457c478bd9Sstevel@tonic-gate packet_put_char(APS_MSG_NEWKEYS_REP); 6467c478bd9Sstevel@tonic-gate packet_put_cstring(enc->name); 6477c478bd9Sstevel@tonic-gate packet_put_string(enc->key, enc->key_len); 6487c478bd9Sstevel@tonic-gate packet_put_string(enc->iv, enc->block_size); 6497c478bd9Sstevel@tonic-gate packet_put_cstring(mac->name); 6507c478bd9Sstevel@tonic-gate packet_put_string(mac->key, mac->key_len); 6517c478bd9Sstevel@tonic-gate packet_put_cstring(comp->name); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate packet_send(); 6549a8058b5Sjp161948 free_keys(newkeys); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate struct _aps_login_rec { 6587c478bd9Sstevel@tonic-gate pid_t lr_pid; 6597c478bd9Sstevel@tonic-gate char *lr_tty; 6607c478bd9Sstevel@tonic-gate struct _aps_login_rec *next; 6617c478bd9Sstevel@tonic-gate }; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate typedef struct _aps_login_rec aps_login_rec; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate static aps_login_rec *aps_login_list = NULL; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate static 6687c478bd9Sstevel@tonic-gate void 6697c478bd9Sstevel@tonic-gate aps_record_login(void) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate aps_login_rec *new_rec; 6727c478bd9Sstevel@tonic-gate struct stat sbuf; 6737c478bd9Sstevel@tonic-gate size_t proc_path_len; 6747c478bd9Sstevel@tonic-gate char *proc_path; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate new_rec = xmalloc(sizeof (aps_login_rec)); 6777c478bd9Sstevel@tonic-gate memset(new_rec, 0, sizeof (aps_login_rec)); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate new_rec->lr_pid = packet_get_int(); 6807c478bd9Sstevel@tonic-gate new_rec->lr_tty = packet_get_string(NULL); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid); 6837c478bd9Sstevel@tonic-gate proc_path = xmalloc(proc_path_len + 1); 6847c478bd9Sstevel@tonic-gate (void) snprintf(proc_path, proc_path_len + 1, "/proc/%d", 6857c478bd9Sstevel@tonic-gate new_rec->lr_pid); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (stat(proc_path, &sbuf) || 6887c478bd9Sstevel@tonic-gate sbuf.st_uid != xxx_authctxt->pw->pw_uid || 6897c478bd9Sstevel@tonic-gate stat(new_rec->lr_tty, &sbuf) < 0 || 6907c478bd9Sstevel@tonic-gate sbuf.st_uid != xxx_authctxt->pw->pw_uid) { 6917c478bd9Sstevel@tonic-gate debug2("Spurious record_login request from unprivileged sshd"); 6927c478bd9Sstevel@tonic-gate xfree(proc_path); 6937c478bd9Sstevel@tonic-gate xfree(new_rec->lr_tty); 6947c478bd9Sstevel@tonic-gate xfree(new_rec); 6957c478bd9Sstevel@tonic-gate return; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* Insert new record on list */ 6997c478bd9Sstevel@tonic-gate new_rec->next = aps_login_list; 7007c478bd9Sstevel@tonic-gate aps_login_list = new_rec; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate record_login(new_rec->lr_pid, new_rec->lr_tty, NULL, 7037c478bd9Sstevel@tonic-gate xxx_authctxt->user); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 7067c478bd9Sstevel@tonic-gate packet_send(); 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate xfree(proc_path); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate static 7127c478bd9Sstevel@tonic-gate void 7137c478bd9Sstevel@tonic-gate aps_record_logout(void) 7147c478bd9Sstevel@tonic-gate { 7157c478bd9Sstevel@tonic-gate aps_login_rec **p, *q; 7167c478bd9Sstevel@tonic-gate pid_t pid; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate pid = packet_get_int(); 7197c478bd9Sstevel@tonic-gate packet_check_eom(); 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate for (p = &aps_login_list; *p != NULL; p = &q->next) { 7227c478bd9Sstevel@tonic-gate q = *p; 7237c478bd9Sstevel@tonic-gate if (q->lr_pid == pid) { 7247c478bd9Sstevel@tonic-gate record_logout(q->lr_pid, q->lr_tty, NULL, 7257c478bd9Sstevel@tonic-gate xxx_authctxt->user); 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* dequeue */ 7287c478bd9Sstevel@tonic-gate *p = q->next; 7297c478bd9Sstevel@tonic-gate xfree(q->lr_tty); 7307c478bd9Sstevel@tonic-gate xfree(q); 7317c478bd9Sstevel@tonic-gate break; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 7367c478bd9Sstevel@tonic-gate packet_send(); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 739dbe3f931Sjp161948 static 740dbe3f931Sjp161948 void 741dbe3f931Sjp161948 aps_start_rekex(void) 742dbe3f931Sjp161948 { 743dbe3f931Sjp161948 /* 744dbe3f931Sjp161948 * Send confirmation. We could implement it without that but it doesn't 745dbe3f931Sjp161948 * bring any harm to do that and we are consistent with other subtypes 746dbe3f931Sjp161948 * of our private SSH2_PRIV_MSG_ALTPRIVSEP message type. 747dbe3f931Sjp161948 */ 748dbe3f931Sjp161948 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 749dbe3f931Sjp161948 packet_send(); 750dbe3f931Sjp161948 751dbe3f931Sjp161948 /* 752dbe3f931Sjp161948 * KEX_INIT message could be the one that reached the limit. In that 753dbe3f931Sjp161948 * case, it was already forwarded to us from the unnprivileged child, 754dbe3f931Sjp161948 * and maybe even acted upon. Obviously we must not send another 755dbe3f931Sjp161948 * KEX_INIT message. 756dbe3f931Sjp161948 */ 757dbe3f931Sjp161948 if (!(xxx_kex->flags & KEX_INIT_SENT)) 758dbe3f931Sjp161948 kex_send_kexinit(xxx_kex); 759dbe3f931Sjp161948 else 760dbe3f931Sjp161948 debug2("rekeying already in progress"); 761dbe3f931Sjp161948 } 762dbe3f931Sjp161948 763cd7d5fafSJan Pechanec /* 764cd7d5fafSJan Pechanec * This is the monitor side of altprivsep_send_auth_context(). 765cd7d5fafSJan Pechanec */ 766cd7d5fafSJan Pechanec Authctxt * 767cd7d5fafSJan Pechanec aps_read_auth_context(void) 768cd7d5fafSJan Pechanec { 769cd7d5fafSJan Pechanec unsigned char *tmp; 770cd7d5fafSJan Pechanec Authctxt *authctxt; 771cd7d5fafSJan Pechanec 772cd7d5fafSJan Pechanec /* 773cd7d5fafSJan Pechanec * After the successful authentication we get the context. Getting 774cd7d5fafSJan Pechanec * end-of-file means that authentication failed and we can exit as well. 775cd7d5fafSJan Pechanec */ 776cd7d5fafSJan Pechanec debug("reading the context from the child"); 777cd7d5fafSJan Pechanec packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 778cd7d5fafSJan Pechanec debug3("got SSH2_PRIV_MSG_ALTPRIVSEP"); 779cd7d5fafSJan Pechanec if (packet_get_char() != APS_MSG_AUTH_CONTEXT) { 780cd7d5fafSJan Pechanec fatal("APS_MSG_AUTH_CONTEXT message subtype expected."); 781cd7d5fafSJan Pechanec } 782cd7d5fafSJan Pechanec 783cd7d5fafSJan Pechanec authctxt = xcalloc(1, sizeof(Authctxt)); 784cd7d5fafSJan Pechanec authctxt->pw = xcalloc(1, sizeof(struct passwd)); 785cd7d5fafSJan Pechanec 786cd7d5fafSJan Pechanec /* uid_t and gid_t are integers (UNIX spec) */ 787cd7d5fafSJan Pechanec authctxt->pw->pw_uid = packet_get_int(); 788cd7d5fafSJan Pechanec authctxt->pw->pw_gid = packet_get_int(); 789cd7d5fafSJan Pechanec authctxt->pw->pw_name = packet_get_string(NULL); 790cd7d5fafSJan Pechanec authctxt->user = xstrdup(authctxt->pw->pw_name); 791cd7d5fafSJan Pechanec debug3("uid/gid/username %d/%d/%s", authctxt->pw->pw_uid, 792cd7d5fafSJan Pechanec authctxt->pw->pw_gid, authctxt->user); 793cd7d5fafSJan Pechanec session_id2 = (unsigned char *)packet_get_raw((unsigned int*)&session_id2_len); 794cd7d5fafSJan Pechanec 795cd7d5fafSJan Pechanec /* we don't have this for SSH1. In that case, session_id2_len is 0. */ 796cd7d5fafSJan Pechanec if (session_id2_len > 0) { 797cd7d5fafSJan Pechanec tmp = (unsigned char *)xmalloc(session_id2_len); 798cd7d5fafSJan Pechanec memcpy(tmp, session_id2, session_id2_len); 799cd7d5fafSJan Pechanec session_id2 = tmp; 800cd7d5fafSJan Pechanec debug3("read session ID (%d B)", session_id2_len); 801cd7d5fafSJan Pechanec xxx_kex->session_id = tmp; 802cd7d5fafSJan Pechanec xxx_kex->session_id_len = session_id2_len; 803cd7d5fafSJan Pechanec } 804cd7d5fafSJan Pechanec debug("finished reading the context"); 805cd7d5fafSJan Pechanec 806cd7d5fafSJan Pechanec /* send confirmation */ 807cd7d5fafSJan Pechanec packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 808cd7d5fafSJan Pechanec packet_send(); 809cd7d5fafSJan Pechanec 810cd7d5fafSJan Pechanec return (authctxt); 811cd7d5fafSJan Pechanec } 812cd7d5fafSJan Pechanec 813dbe3f931Sjp161948 8147c478bd9Sstevel@tonic-gate /* Utilities for communication with the monitor */ 815cd7d5fafSJan Pechanec static void 8167c478bd9Sstevel@tonic-gate altprivsep_packet_start(u_char type) 8177c478bd9Sstevel@tonic-gate { 8187c478bd9Sstevel@tonic-gate buffer_clear(&to_monitor); 8197c478bd9Sstevel@tonic-gate buffer_put_char(&to_monitor, type); 8207c478bd9Sstevel@tonic-gate } 821cd7d5fafSJan Pechanec 822cd7d5fafSJan Pechanec static void 8237c478bd9Sstevel@tonic-gate altprivsep_packet_put_char(int ch) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate buffer_put_char(&to_monitor, ch); 8267c478bd9Sstevel@tonic-gate } 827cd7d5fafSJan Pechanec 828cd7d5fafSJan Pechanec static void 8297c478bd9Sstevel@tonic-gate altprivsep_packet_put_int(u_int value) 8307c478bd9Sstevel@tonic-gate { 8317c478bd9Sstevel@tonic-gate buffer_put_int(&to_monitor, value); 8327c478bd9Sstevel@tonic-gate } 833cd7d5fafSJan Pechanec 834cd7d5fafSJan Pechanec static void 8357c478bd9Sstevel@tonic-gate altprivsep_packet_put_cstring(const char *str) 8367c478bd9Sstevel@tonic-gate { 8377c478bd9Sstevel@tonic-gate buffer_put_cstring(&to_monitor, str); 8387c478bd9Sstevel@tonic-gate } 839cd7d5fafSJan Pechanec 840cd7d5fafSJan Pechanec static void 8417c478bd9Sstevel@tonic-gate altprivsep_packet_put_raw(const void *buf, u_int len) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate buffer_append(&to_monitor, buf, len); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate /* 8477c478bd9Sstevel@tonic-gate * Send a monitor packet to the monitor. This function is blocking. 8487c478bd9Sstevel@tonic-gate * 8497c478bd9Sstevel@tonic-gate * Returns -1 if the monitor pipe has been closed earlier, fatal()s if 8507c478bd9Sstevel@tonic-gate * there's any other problems. 8517c478bd9Sstevel@tonic-gate */ 852cd7d5fafSJan Pechanec static int 8537c478bd9Sstevel@tonic-gate altprivsep_packet_send(void) 8547c478bd9Sstevel@tonic-gate { 8557c478bd9Sstevel@tonic-gate ssize_t len; 8567c478bd9Sstevel@tonic-gate u_int32_t plen; /* packet length */ 8577c478bd9Sstevel@tonic-gate u_char plen_buf[sizeof (plen)]; 8587c478bd9Sstevel@tonic-gate u_char padlen; /* padding length */ 8597c478bd9Sstevel@tonic-gate fd_set *setp; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 8627c478bd9Sstevel@tonic-gate return (-1); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate if ((plen = buffer_len(&to_monitor)) == 0) 8657c478bd9Sstevel@tonic-gate return (0); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * We talk the SSHv2 binary packet protocol to the monitor, 8697c478bd9Sstevel@tonic-gate * using the none cipher, mac and compression algorithms. 8707c478bd9Sstevel@tonic-gate * 8717c478bd9Sstevel@tonic-gate * But, interestingly, the none cipher has a block size of 8 8727c478bd9Sstevel@tonic-gate * bytes, thus we must pad the packet. 8737c478bd9Sstevel@tonic-gate * 8747c478bd9Sstevel@tonic-gate * Also, encryption includes the packet length, so the padding 8757c478bd9Sstevel@tonic-gate * must account for that field. I.e., (sizeof (packet length) + 8767c478bd9Sstevel@tonic-gate * sizeof (padding length) + packet length + padding length) % 8777c478bd9Sstevel@tonic-gate * block_size must == 0. 8787c478bd9Sstevel@tonic-gate * 8797c478bd9Sstevel@tonic-gate * Also, there must be at least four (4) bytes of padding. 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8; 8827c478bd9Sstevel@tonic-gate if (padlen < 4) 8837c478bd9Sstevel@tonic-gate padlen += 8; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* packet length counts padding and padding length field */ 8867c478bd9Sstevel@tonic-gate plen += padlen + sizeof (padlen); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate PUT_32BIT(plen_buf, plen); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 8917c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 8927c478bd9Sstevel@tonic-gate FD_SET(pipe_fd, setp); 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) { 8957c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 8967c478bd9Sstevel@tonic-gate continue; 8977c478bd9Sstevel@tonic-gate else 8987c478bd9Sstevel@tonic-gate goto pipe_gone; 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate xfree(setp); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* packet length field */ 9047c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, plen_buf, sizeof (plen)); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (len != sizeof (plen)) 9077c478bd9Sstevel@tonic-gate goto pipe_gone; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* padding length field */ 9107c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, &padlen, sizeof (padlen)); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (len != sizeof (padlen)) 9137c478bd9Sstevel@tonic-gate goto pipe_gone; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1); 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate if (len != (plen - 1)) 9187c478bd9Sstevel@tonic-gate goto pipe_gone; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate buffer_clear(&to_monitor); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate return (1); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate pipe_gone: 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate (void) close(pipe_fd); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate pipe_fd = -1; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* NOTREACHED */ 9337c478bd9Sstevel@tonic-gate return (0); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Read a monitor packet from the monitor. This function is blocking. 9387c478bd9Sstevel@tonic-gate */ 939cd7d5fafSJan Pechanec static int 9407c478bd9Sstevel@tonic-gate altprivsep_packet_read(void) 9417c478bd9Sstevel@tonic-gate { 9427c478bd9Sstevel@tonic-gate ssize_t len = -1; 9437c478bd9Sstevel@tonic-gate u_int32_t plen; 9447c478bd9Sstevel@tonic-gate u_char plen_buf[sizeof (plen)]; 9457c478bd9Sstevel@tonic-gate u_char padlen; 9467c478bd9Sstevel@tonic-gate fd_set *setp; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (pipe_fd == -1) 9497c478bd9Sstevel@tonic-gate return (-1); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 9527c478bd9Sstevel@tonic-gate memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 9537c478bd9Sstevel@tonic-gate FD_SET(pipe_fd, setp); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) { 9567c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) 9577c478bd9Sstevel@tonic-gate continue; 9587c478bd9Sstevel@tonic-gate else 9597c478bd9Sstevel@tonic-gate goto pipe_gone; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate xfree(setp); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* packet length field */ 9657c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, plen_buf, sizeof (plen)); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate plen = GET_32BIT(plen_buf); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate if (len != sizeof (plen)) 9707c478bd9Sstevel@tonic-gate goto pipe_gone; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /* padding length field */ 9737c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, &padlen, sizeof (padlen)); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate if (len != sizeof (padlen)) 9767c478bd9Sstevel@tonic-gate goto pipe_gone; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate plen -= sizeof (padlen); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate buffer_clear(&from_monitor); 9817c478bd9Sstevel@tonic-gate buffer_append_space(&from_monitor, plen); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* packet data + padding */ 9847c478bd9Sstevel@tonic-gate len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate if (len != plen) 9877c478bd9Sstevel@tonic-gate goto pipe_gone; 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* remove padding */ 9907c478bd9Sstevel@tonic-gate if (padlen > 0) 9917c478bd9Sstevel@tonic-gate buffer_consume_end(&from_monitor, padlen); 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate /* packet type */ 9947c478bd9Sstevel@tonic-gate return (buffer_get_char(&from_monitor)); 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate pipe_gone: 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate (void) close(pipe_fd); 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate pipe_fd = -1; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate if (len < 0) 10037c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate debug2("Monitor pipe closed by monitor"); 10067c478bd9Sstevel@tonic-gate return (0); 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 1009cd7d5fafSJan Pechanec static void 10107c478bd9Sstevel@tonic-gate altprivsep_packet_read_expect(int expected) 10117c478bd9Sstevel@tonic-gate { 10127c478bd9Sstevel@tonic-gate int type; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate type = altprivsep_packet_read(); 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate if (type <= 0) 10177c478bd9Sstevel@tonic-gate fatal("Monitor not responding"); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate if (type != expected) 10207c478bd9Sstevel@tonic-gate fatal("Protocol error in privilege separation; expected " 10217c478bd9Sstevel@tonic-gate "packet type %d, got %d", expected, type); 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 1024cd7d5fafSJan Pechanec static u_int 10257c478bd9Sstevel@tonic-gate altprivsep_packet_get_char(void) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate return (buffer_get_char(&from_monitor)); 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate void 10307c478bd9Sstevel@tonic-gate *altprivsep_packet_get_raw(u_int *length_ptr) 10317c478bd9Sstevel@tonic-gate { 10327c478bd9Sstevel@tonic-gate if (length_ptr != NULL) 10337c478bd9Sstevel@tonic-gate *length_ptr = buffer_len(&from_monitor); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate return (buffer_ptr(&from_monitor)); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate void 10387c478bd9Sstevel@tonic-gate *altprivsep_packet_get_string(u_int *length_ptr) 10397c478bd9Sstevel@tonic-gate { 10407c478bd9Sstevel@tonic-gate return (buffer_get_string(&from_monitor, length_ptr)); 10417c478bd9Sstevel@tonic-gate } 1042cd7d5fafSJan Pechanec 1043cd7d5fafSJan Pechanec void 1044cd7d5fafSJan Pechanec altprivsep_start_and_do_monitor(int use_engine, int inetd, int newsock, 1045cd7d5fafSJan Pechanec int statup_pipe) 1046cd7d5fafSJan Pechanec { 1047cd7d5fafSJan Pechanec pid_t aps_child; 1048cd7d5fafSJan Pechanec Authctxt *authctxt; 1049cd7d5fafSJan Pechanec 1050cd7d5fafSJan Pechanec /* 1051cd7d5fafSJan Pechanec * The monitor will packet_close() in packet_set_monitor() called from 1052cd7d5fafSJan Pechanec * altprivsep_start_monitor() below to clean up the socket stuff before 1053cd7d5fafSJan Pechanec * it switches to pipes for communication to the child. The socket fd is 1054cd7d5fafSJan Pechanec * closed there so we must dup it here - monitor needs that socket to 1055cd7d5fafSJan Pechanec * shutdown the connection in case of any problem; see comments below. 1056cd7d5fafSJan Pechanec * Note that current newsock was assigned to connection_(in|out) which 1057cd7d5fafSJan Pechanec * are the variables used in packet_close() to close the communication 1058cd7d5fafSJan Pechanec * socket. 1059cd7d5fafSJan Pechanec */ 1060cd7d5fafSJan Pechanec newsock = dup(newsock); 1061cd7d5fafSJan Pechanec 1062cd7d5fafSJan Pechanec if ((aps_child = altprivsep_start_monitor(&authctxt)) == -1) 1063cd7d5fafSJan Pechanec fatal("Monitor could not be started."); 1064cd7d5fafSJan Pechanec 1065cd7d5fafSJan Pechanec if (aps_child > 0) { 1066cd7d5fafSJan Pechanec /* ALTPRIVSEP Monitor */ 1067cd7d5fafSJan Pechanec 1068cd7d5fafSJan Pechanec /* 1069cd7d5fafSJan Pechanec * The ALTPRIVSEP monitor here does: 1070cd7d5fafSJan Pechanec * 1071cd7d5fafSJan Pechanec * - record keeping and auditing 1072cd7d5fafSJan Pechanec * - PAM cleanup 1073cd7d5fafSJan Pechanec */ 1074cd7d5fafSJan Pechanec 1075cd7d5fafSJan Pechanec /* 1076cd7d5fafSJan Pechanec * Alarm signal handler is for our child only since that's the 1077cd7d5fafSJan Pechanec * one that does the authentication. 1078cd7d5fafSJan Pechanec */ 1079cd7d5fafSJan Pechanec (void) alarm(0); 1080cd7d5fafSJan Pechanec (void) signal(SIGALRM, SIG_DFL); 1081cd7d5fafSJan Pechanec /* this is for MaxStartups and the child takes care of that */ 1082cd7d5fafSJan Pechanec (void) close(statup_pipe); 1083cd7d5fafSJan Pechanec (void) pkcs11_engine_load(use_engine); 1084cd7d5fafSJan Pechanec 1085cd7d5fafSJan Pechanec /* 1086cd7d5fafSJan Pechanec * If the monitor fatal()s it will audit/record a logout, so 1087cd7d5fafSJan Pechanec * we'd better do something to really mean it: shutdown the 1088cd7d5fafSJan Pechanec * socket but leave the child alone -- it's been disconnected 1089cd7d5fafSJan Pechanec * and we hope it exits, but killing any pid from a privileged 1090cd7d5fafSJan Pechanec * monitor could be dangerous. 1091cd7d5fafSJan Pechanec * 1092cd7d5fafSJan Pechanec * NOTE: Order matters -- these fatal cleanups must come before 1093cd7d5fafSJan Pechanec * the audit logout fatal cleanup as these functions are called 1094cd7d5fafSJan Pechanec * in LIFO. 1095cd7d5fafSJan Pechanec */ 1096cd7d5fafSJan Pechanec fatal_add_cleanup((void (*)(void *))altprivsep_shutdown_sock, 1097cd7d5fafSJan Pechanec (void *)&newsock); 1098cd7d5fafSJan Pechanec 1099cd7d5fafSJan Pechanec if (compat20) { 1100cd7d5fafSJan Pechanec debug3("Recording SSHv2 session login in wtmpx"); 1101cd7d5fafSJan Pechanec /* 1102cd7d5fafSJan Pechanec * record_login() relies on connection_in to be the 1103cd7d5fafSJan Pechanec * socket to get the peer address. The problem is that 1104cd7d5fafSJan Pechanec * connection_in had to be set to the pipe descriptor in 1105cd7d5fafSJan Pechanec * altprivsep_start_monitor(). It's not nice but the 1106cd7d5fafSJan Pechanec * easiest way to get the peer's address is to 1107cd7d5fafSJan Pechanec * temporarily set connection_in to the socket's file 1108cd7d5fafSJan Pechanec * descriptor. 1109cd7d5fafSJan Pechanec */ 1110cd7d5fafSJan Pechanec packet_set_fds(inetd == 1 ? -1 : newsock, 0); 1111cd7d5fafSJan Pechanec record_login(getpid(), NULL, "sshd", authctxt->user); 1112cd7d5fafSJan Pechanec packet_set_fds(0, 1); 1113cd7d5fafSJan Pechanec } 1114cd7d5fafSJan Pechanec 1115cd7d5fafSJan Pechanec #ifdef HAVE_BSM 1116cd7d5fafSJan Pechanec /* Initialize the group list, audit sometimes needs it. */ 1117cd7d5fafSJan Pechanec if (initgroups(authctxt->pw->pw_name, 1118cd7d5fafSJan Pechanec authctxt->pw->pw_gid) < 0) { 1119cd7d5fafSJan Pechanec perror("initgroups"); 1120cd7d5fafSJan Pechanec exit (1); 1121cd7d5fafSJan Pechanec } 1122cd7d5fafSJan Pechanec 1123bca3984eSBrent Paulson /* 1124bca3984eSBrent Paulson * The monitor process fork()ed before the authentication 1125bca3984eSBrent Paulson * process started so at this point we have an unaudited 1126bca3984eSBrent Paulson * context. Thus we need to obtain the audit session data 1127bca3984eSBrent Paulson * from the authentication process (aps_child) which will 1128bca3984eSBrent Paulson * have the correct audit context for the user logging in. 1129bca3984eSBrent Paulson * To do so we pass along the process-ID of the aps_child 1130bca3984eSBrent Paulson * process so that it is referenced for this audit session 1131bca3984eSBrent Paulson * rather than referencing the monitor's unaudited context. 1132bca3984eSBrent Paulson */ 1133bca3984eSBrent Paulson audit_sshd_login(&ah, aps_child); 1134cd7d5fafSJan Pechanec 1135cd7d5fafSJan Pechanec fatal_add_cleanup((void (*)(void *))audit_sshd_logout, 1136cd7d5fafSJan Pechanec (void *)&ah); 1137cd7d5fafSJan Pechanec #endif /* HAVE_BSM */ 1138cd7d5fafSJan Pechanec 1139cd7d5fafSJan Pechanec #ifdef GSSAPI 1140cd7d5fafSJan Pechanec fatal_add_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds, 1141cd7d5fafSJan Pechanec (void *)&xxx_gssctxt); 1142cd7d5fafSJan Pechanec #endif /* GSSAPI */ 1143cd7d5fafSJan Pechanec 1144cd7d5fafSJan Pechanec altprivsep_do_monitor(authctxt, aps_child); 1145cd7d5fafSJan Pechanec 1146cd7d5fafSJan Pechanec /* If we got here the connection is dead. */ 1147cd7d5fafSJan Pechanec fatal_remove_cleanup((void (*)(void *))altprivsep_shutdown_sock, 1148cd7d5fafSJan Pechanec (void *)&newsock); 1149cd7d5fafSJan Pechanec 1150cd7d5fafSJan Pechanec if (compat20) { 1151cd7d5fafSJan Pechanec debug3("Recording SSHv2 session logout in wtmpx"); 1152cd7d5fafSJan Pechanec record_logout(getpid(), NULL, "sshd", authctxt->user); 1153cd7d5fafSJan Pechanec } 1154cd7d5fafSJan Pechanec 1155cd7d5fafSJan Pechanec /* 1156cd7d5fafSJan Pechanec * Make sure the socket is closed. The monitor can't call 1157cd7d5fafSJan Pechanec * packet_close here as it's done a packet_set_connection() 1158cd7d5fafSJan Pechanec * with the pipe to the child instead of the socket. 1159cd7d5fafSJan Pechanec */ 1160cd7d5fafSJan Pechanec (void) shutdown(newsock, SHUT_RDWR); 1161cd7d5fafSJan Pechanec 1162cd7d5fafSJan Pechanec #ifdef GSSAPI 1163cd7d5fafSJan Pechanec fatal_remove_cleanup((void (*)(void *))ssh_gssapi_cleanup_creds, 1164cd7d5fafSJan Pechanec &xxx_gssctxt); 1165cd7d5fafSJan Pechanec ssh_gssapi_cleanup_creds(xxx_gssctxt); 1166cd7d5fafSJan Pechanec ssh_gssapi_server_mechs(NULL); /* release cached mechs list */ 1167cd7d5fafSJan Pechanec #endif /* GSSAPI */ 1168cd7d5fafSJan Pechanec 1169cd7d5fafSJan Pechanec #ifdef HAVE_BSM 1170cd7d5fafSJan Pechanec fatal_remove_cleanup((void (*)(void *))audit_sshd_logout, (void *)&ah); 1171cd7d5fafSJan Pechanec audit_sshd_logout(&ah); 1172cd7d5fafSJan Pechanec #endif /* HAVE_BSM */ 1173cd7d5fafSJan Pechanec 1174cd7d5fafSJan Pechanec exit(0); 1175cd7d5fafSJan Pechanec } else { 1176cd7d5fafSJan Pechanec /* 1177cd7d5fafSJan Pechanec * This is the child, close the dup()ed file descriptor for a 1178cd7d5fafSJan Pechanec * socket. It's not needed in the child. 1179cd7d5fafSJan Pechanec */ 1180cd7d5fafSJan Pechanec close(newsock); 1181cd7d5fafSJan Pechanec } 1182cd7d5fafSJan Pechanec } 1183