10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 30Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 40Sstevel@tonic-gate * All rights reserved 50Sstevel@tonic-gate * Server main loop for handling the interactive session. 60Sstevel@tonic-gate * 70Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 80Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 90Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 100Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 110Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * SSH2 support by Markus Friedl. 140Sstevel@tonic-gate * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 150Sstevel@tonic-gate * 160Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 170Sstevel@tonic-gate * modification, are permitted provided that the following conditions 180Sstevel@tonic-gate * are met: 190Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 200Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 210Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 220Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 230Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 240Sstevel@tonic-gate * 250Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 260Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 270Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 280Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 290Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 300Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 310Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 320Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 330Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 340Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate /* 376375Sjp161948 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 380Sstevel@tonic-gate * Use is subject to license terms. 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate #include "includes.h" 420Sstevel@tonic-gate RCSID("$OpenBSD: serverloop.c,v 1.104 2002/09/19 16:03:15 stevesk Exp $"); 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include "xmalloc.h" 450Sstevel@tonic-gate #include "packet.h" 460Sstevel@tonic-gate #include "buffer.h" 470Sstevel@tonic-gate #include "log.h" 480Sstevel@tonic-gate #include "servconf.h" 490Sstevel@tonic-gate #include "canohost.h" 500Sstevel@tonic-gate #include "sshpty.h" 510Sstevel@tonic-gate #include "channels.h" 520Sstevel@tonic-gate #include "compat.h" 530Sstevel@tonic-gate #include "ssh1.h" 540Sstevel@tonic-gate #include "ssh2.h" 550Sstevel@tonic-gate #include "auth.h" 560Sstevel@tonic-gate #include "session.h" 570Sstevel@tonic-gate #include "dispatch.h" 580Sstevel@tonic-gate #include "auth-options.h" 590Sstevel@tonic-gate #include "serverloop.h" 600Sstevel@tonic-gate #include "misc.h" 610Sstevel@tonic-gate #include "kex.h" 620Sstevel@tonic-gate 630Sstevel@tonic-gate #ifdef ALTPRIVSEP 640Sstevel@tonic-gate #include "altprivsep.h" 650Sstevel@tonic-gate #endif /* ALTPRIVSEP*/ 660Sstevel@tonic-gate 670Sstevel@tonic-gate extern ServerOptions options; 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* XXX */ 700Sstevel@tonic-gate extern Kex *xxx_kex; 710Sstevel@tonic-gate static Authctxt *xxx_authctxt; 720Sstevel@tonic-gate 730Sstevel@tonic-gate static Buffer stdin_buffer; /* Buffer for stdin data. */ 740Sstevel@tonic-gate static Buffer stdout_buffer; /* Buffer for stdout data. */ 750Sstevel@tonic-gate static Buffer stderr_buffer; /* Buffer for stderr data. */ 760Sstevel@tonic-gate static int fdin; /* Descriptor for stdin (for writing) */ 770Sstevel@tonic-gate static int fdout; /* Descriptor for stdout (for reading); 780Sstevel@tonic-gate May be same number as fdin. */ 790Sstevel@tonic-gate static int fderr; /* Descriptor for stderr. May be -1. */ 800Sstevel@tonic-gate static long stdin_bytes = 0; /* Number of bytes written to stdin. */ 810Sstevel@tonic-gate static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ 820Sstevel@tonic-gate static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ 830Sstevel@tonic-gate static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ 840Sstevel@tonic-gate static int stdin_eof = 0; /* EOF message received from client. */ 850Sstevel@tonic-gate static int fdout_eof = 0; /* EOF encountered reading from fdout. */ 860Sstevel@tonic-gate static int fderr_eof = 0; /* EOF encountered readung from fderr. */ 870Sstevel@tonic-gate static int fdin_is_tty = 0; /* fdin points to a tty. */ 880Sstevel@tonic-gate static int connection_in; /* Connection to client (input). */ 890Sstevel@tonic-gate static int connection_out; /* Connection to client (output). */ 900Sstevel@tonic-gate static int connection_closed = 0; /* Connection to client closed. */ 910Sstevel@tonic-gate static u_int buffer_high; /* "Soft" max buffer size. */ 920Sstevel@tonic-gate static int client_alive_timeouts = 0; 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * This SIGCHLD kludge is used to detect when the child exits. The server 960Sstevel@tonic-gate * will exit after that, as soon as forwarded connections have terminated. 970Sstevel@tonic-gate */ 980Sstevel@tonic-gate 990Sstevel@tonic-gate static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate /* prototypes */ 1020Sstevel@tonic-gate static void server_init_dispatch(void); 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* 1050Sstevel@tonic-gate * we write to this pipe if a SIGCHLD is caught in order to avoid 1060Sstevel@tonic-gate * the race between select() and child_terminated 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate static int notify_pipe[2]; 1090Sstevel@tonic-gate static void 1100Sstevel@tonic-gate notify_setup(void) 1110Sstevel@tonic-gate { 1120Sstevel@tonic-gate if (pipe(notify_pipe) < 0) { 1130Sstevel@tonic-gate error("pipe(notify_pipe) failed %s", strerror(errno)); 1140Sstevel@tonic-gate } else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) || 1150Sstevel@tonic-gate (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) { 1160Sstevel@tonic-gate error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno)); 1170Sstevel@tonic-gate (void) close(notify_pipe[0]); 1180Sstevel@tonic-gate (void) close(notify_pipe[1]); 1190Sstevel@tonic-gate } else { 1200Sstevel@tonic-gate set_nonblock(notify_pipe[0]); 1210Sstevel@tonic-gate set_nonblock(notify_pipe[1]); 1220Sstevel@tonic-gate return; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate notify_pipe[0] = -1; /* read end */ 1250Sstevel@tonic-gate notify_pipe[1] = -1; /* write end */ 1260Sstevel@tonic-gate } 1270Sstevel@tonic-gate static void 1280Sstevel@tonic-gate notify_parent(void) 1290Sstevel@tonic-gate { 1300Sstevel@tonic-gate if (notify_pipe[1] != -1) 1310Sstevel@tonic-gate (void) write(notify_pipe[1], "", 1); 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate static void 1340Sstevel@tonic-gate notify_prepare(fd_set *readset) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate if (notify_pipe[0] != -1) 1370Sstevel@tonic-gate FD_SET(notify_pipe[0], readset); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate static void 1400Sstevel@tonic-gate notify_done(fd_set *readset) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate char c; 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) 1450Sstevel@tonic-gate while (read(notify_pipe[0], &c, 1) != -1) 1460Sstevel@tonic-gate debug2("notify_done: reading"); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static void 1500Sstevel@tonic-gate sigchld_handler(int sig) 1510Sstevel@tonic-gate { 1520Sstevel@tonic-gate int save_errno = errno; 1530Sstevel@tonic-gate debug("Received SIGCHLD."); 1540Sstevel@tonic-gate child_terminated = 1; 1550Sstevel@tonic-gate #ifndef _UNICOS 1560Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 1570Sstevel@tonic-gate #endif 1580Sstevel@tonic-gate notify_parent(); 1590Sstevel@tonic-gate errno = save_errno; 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* 1630Sstevel@tonic-gate * Make packets from buffered stderr data, and buffer it for sending 1640Sstevel@tonic-gate * to the client. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate static void 1670Sstevel@tonic-gate make_packets_from_stderr_data(void) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate int len; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* Send buffered stderr data to the client. */ 1720Sstevel@tonic-gate while (buffer_len(&stderr_buffer) > 0 && 1730Sstevel@tonic-gate packet_not_very_much_data_to_write()) { 1740Sstevel@tonic-gate len = buffer_len(&stderr_buffer); 1750Sstevel@tonic-gate if (packet_is_interactive()) { 1760Sstevel@tonic-gate if (len > 512) 1770Sstevel@tonic-gate len = 512; 1780Sstevel@tonic-gate } else { 1790Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 1800Sstevel@tonic-gate if (len > packet_get_maxsize()) 1810Sstevel@tonic-gate len = packet_get_maxsize(); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate packet_start(SSH_SMSG_STDERR_DATA); 1840Sstevel@tonic-gate packet_put_string(buffer_ptr(&stderr_buffer), len); 1850Sstevel@tonic-gate packet_send(); 1860Sstevel@tonic-gate buffer_consume(&stderr_buffer, len); 1870Sstevel@tonic-gate stderr_bytes += len; 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * Make packets from buffered stdout data, and buffer it for sending to the 1930Sstevel@tonic-gate * client. 1940Sstevel@tonic-gate */ 1950Sstevel@tonic-gate static void 1960Sstevel@tonic-gate make_packets_from_stdout_data(void) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate int len; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* Send buffered stdout data to the client. */ 2010Sstevel@tonic-gate while (buffer_len(&stdout_buffer) > 0 && 2020Sstevel@tonic-gate packet_not_very_much_data_to_write()) { 2030Sstevel@tonic-gate len = buffer_len(&stdout_buffer); 2040Sstevel@tonic-gate if (packet_is_interactive()) { 2050Sstevel@tonic-gate if (len > 512) 2060Sstevel@tonic-gate len = 512; 2070Sstevel@tonic-gate } else { 2080Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 2090Sstevel@tonic-gate if (len > packet_get_maxsize()) 2100Sstevel@tonic-gate len = packet_get_maxsize(); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate packet_start(SSH_SMSG_STDOUT_DATA); 2130Sstevel@tonic-gate packet_put_string(buffer_ptr(&stdout_buffer), len); 2140Sstevel@tonic-gate packet_send(); 2150Sstevel@tonic-gate buffer_consume(&stdout_buffer, len); 2160Sstevel@tonic-gate stdout_bytes += len; 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate static void 2210Sstevel@tonic-gate client_alive_check(void) 2220Sstevel@tonic-gate { 2230Sstevel@tonic-gate static int had_channel = 0; 2240Sstevel@tonic-gate int id; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate id = channel_find_open(); 2270Sstevel@tonic-gate if (id == -1) { 2280Sstevel@tonic-gate if (!had_channel) 2290Sstevel@tonic-gate return; 2300Sstevel@tonic-gate packet_disconnect("No open channels after timeout!"); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate had_channel = 1; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* timeout, check to see how many we have had */ 2350Sstevel@tonic-gate if (++client_alive_timeouts > options.client_alive_count_max) 2360Sstevel@tonic-gate packet_disconnect("Timeout, your session not responding."); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* 2390Sstevel@tonic-gate * send a bogus channel request with "wantreply", 2400Sstevel@tonic-gate * we should get back a failure 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate channel_request_start(id, "keepalive@openssh.com", 1); 2430Sstevel@tonic-gate packet_send(); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Sleep in select() until we can do something. This will initialize the 2480Sstevel@tonic-gate * select masks. Upon return, the masks will indicate which descriptors 2490Sstevel@tonic-gate * have data or can accept data. Optionally, a maximum time can be specified 2500Sstevel@tonic-gate * for the duration of the wait (0 = infinite). 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate static void 2530Sstevel@tonic-gate wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 2540Sstevel@tonic-gate int *nallocp, u_int max_time_milliseconds) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate struct timeval tv, *tvp; 2570Sstevel@tonic-gate int ret; 2580Sstevel@tonic-gate int client_alive_scheduled = 0; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * if using client_alive, set the max timeout accordingly, 2620Sstevel@tonic-gate * and indicate that this particular timeout was for client 2630Sstevel@tonic-gate * alive by setting the client_alive_scheduled flag. 2640Sstevel@tonic-gate * 2650Sstevel@tonic-gate * this could be randomized somewhat to make traffic 2660Sstevel@tonic-gate * analysis more difficult, but we're not doing it yet. 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate if (compat20 && 2690Sstevel@tonic-gate max_time_milliseconds == 0 && options.client_alive_interval) { 2700Sstevel@tonic-gate client_alive_scheduled = 1; 2710Sstevel@tonic-gate max_time_milliseconds = options.client_alive_interval * 1000; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* Allocate and update select() masks for channel descriptors. */ 2750Sstevel@tonic-gate channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if (compat20) { 2780Sstevel@tonic-gate #ifdef ALTPRIVSEP 2790Sstevel@tonic-gate int pipe_fd; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate if ((pipe_fd = altprivsep_get_pipe_fd()) != -1) { 2820Sstevel@tonic-gate *maxfdp = MAX(*maxfdp, pipe_fd); 2830Sstevel@tonic-gate FD_SET(altprivsep_get_pipe_fd(), *readsetp); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 2860Sstevel@tonic-gate #if 0 2870Sstevel@tonic-gate /* wrong: bad condition XXX */ 2880Sstevel@tonic-gate if (channel_not_very_much_buffered_data()) 2890Sstevel@tonic-gate #endif 2900Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 2910Sstevel@tonic-gate } else { 2920Sstevel@tonic-gate /* 2930Sstevel@tonic-gate * Read packets from the client unless we have too much 2940Sstevel@tonic-gate * buffered stdin or channel data. 2950Sstevel@tonic-gate */ 2960Sstevel@tonic-gate if (buffer_len(&stdin_buffer) < buffer_high && 2970Sstevel@tonic-gate channel_not_very_much_buffered_data()) 2980Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * If there is not too much data already buffered going to 3010Sstevel@tonic-gate * the client, try to get some more data from the program. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate if (packet_not_very_much_data_to_write()) { 3040Sstevel@tonic-gate if (!fdout_eof) 3050Sstevel@tonic-gate FD_SET(fdout, *readsetp); 3060Sstevel@tonic-gate if (!fderr_eof) 3070Sstevel@tonic-gate FD_SET(fderr, *readsetp); 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate /* 3100Sstevel@tonic-gate * If we have buffered data, try to write some of that data 3110Sstevel@tonic-gate * to the program. 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate if (fdin != -1 && buffer_len(&stdin_buffer) > 0) 3140Sstevel@tonic-gate FD_SET(fdin, *writesetp); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate notify_prepare(*readsetp); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * If we have buffered packet data going to the client, mark that 3200Sstevel@tonic-gate * descriptor. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate if (packet_have_data_to_write()) 3230Sstevel@tonic-gate FD_SET(connection_out, *writesetp); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * If child has terminated and there is enough buffer space to read 3270Sstevel@tonic-gate * from it, then read as much as is available and exit. 3280Sstevel@tonic-gate */ 3290Sstevel@tonic-gate if (child_terminated && packet_not_very_much_data_to_write()) 3300Sstevel@tonic-gate if (max_time_milliseconds == 0 || client_alive_scheduled) 3310Sstevel@tonic-gate max_time_milliseconds = 100; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (max_time_milliseconds == 0) 3340Sstevel@tonic-gate tvp = NULL; 3350Sstevel@tonic-gate else { 3360Sstevel@tonic-gate tv.tv_sec = max_time_milliseconds / 1000; 3370Sstevel@tonic-gate tv.tv_usec = 1000 * (max_time_milliseconds % 1000); 3380Sstevel@tonic-gate tvp = &tv; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* Wait for something to happen, or the timeout to expire. */ 3420Sstevel@tonic-gate ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (ret == -1) { 3450Sstevel@tonic-gate memset(*readsetp, 0, *nallocp); 3460Sstevel@tonic-gate memset(*writesetp, 0, *nallocp); 3470Sstevel@tonic-gate if (errno != EINTR) 3480Sstevel@tonic-gate error("select: %.100s", strerror(errno)); 3490Sstevel@tonic-gate } else if (ret == 0 && client_alive_scheduled) 3500Sstevel@tonic-gate client_alive_check(); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate notify_done(*readsetp); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * Processes input from the client and the program. Input data is stored 3570Sstevel@tonic-gate * in buffers and processed later. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate static void 3600Sstevel@tonic-gate process_input(fd_set * readset) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate int len; 3630Sstevel@tonic-gate char buf[16384]; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* Read and buffer any input data from the client. */ 3660Sstevel@tonic-gate if (FD_ISSET(connection_in, readset)) { 3670Sstevel@tonic-gate len = read(connection_in, buf, sizeof(buf)); 3680Sstevel@tonic-gate if (len == 0) { 369*7574SJan.Pechanec@Sun.COM if (packet_is_monitor()) { 370*7574SJan.Pechanec@Sun.COM debug("child closed the communication pipe"); 371*7574SJan.Pechanec@Sun.COM } else { 372*7574SJan.Pechanec@Sun.COM verbose("Connection closed by %.100s", 373*7574SJan.Pechanec@Sun.COM get_remote_ipaddr()); 374*7574SJan.Pechanec@Sun.COM } 3750Sstevel@tonic-gate connection_closed = 1; 3760Sstevel@tonic-gate if (compat20) 3770Sstevel@tonic-gate return; 3780Sstevel@tonic-gate fatal_cleanup(); 3790Sstevel@tonic-gate } else if (len < 0) { 3800Sstevel@tonic-gate if (errno != EINTR && errno != EAGAIN) { 3810Sstevel@tonic-gate verbose("Read error from remote host " 3820Sstevel@tonic-gate "%.100s: %.100s", 3830Sstevel@tonic-gate get_remote_ipaddr(), strerror(errno)); 3840Sstevel@tonic-gate fatal_cleanup(); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate } else { 3870Sstevel@tonic-gate /* Buffer any received data. */ 3880Sstevel@tonic-gate packet_process_incoming(buf, len); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate if (compat20) 3920Sstevel@tonic-gate return; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* Read and buffer any available stdout data from the program. */ 3950Sstevel@tonic-gate if (!fdout_eof && FD_ISSET(fdout, readset)) { 3960Sstevel@tonic-gate len = read(fdout, buf, sizeof(buf)); 3970Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 3980Sstevel@tonic-gate /* EMPTY */ 3990Sstevel@tonic-gate } else if (len <= 0) { 4000Sstevel@tonic-gate fdout_eof = 1; 4010Sstevel@tonic-gate } else { 4020Sstevel@tonic-gate buffer_append(&stdout_buffer, buf, len); 4030Sstevel@tonic-gate fdout_bytes += len; 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate /* Read and buffer any available stderr data from the program. */ 4070Sstevel@tonic-gate if (!fderr_eof && FD_ISSET(fderr, readset)) { 4080Sstevel@tonic-gate len = read(fderr, buf, sizeof(buf)); 4090Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 4100Sstevel@tonic-gate /* EMPTY */ 4110Sstevel@tonic-gate } else if (len <= 0) { 4120Sstevel@tonic-gate fderr_eof = 1; 4130Sstevel@tonic-gate } else { 4140Sstevel@tonic-gate buffer_append(&stderr_buffer, buf, len); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * Sends data from internal buffers to client program stdin. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate static void 4230Sstevel@tonic-gate process_output(fd_set * writeset) 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate struct termios tio; 4260Sstevel@tonic-gate u_char *data; 4270Sstevel@tonic-gate u_int dlen; 4280Sstevel@tonic-gate int len; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate /* Write buffered data to program stdin. */ 4310Sstevel@tonic-gate if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { 4320Sstevel@tonic-gate data = buffer_ptr(&stdin_buffer); 4330Sstevel@tonic-gate dlen = buffer_len(&stdin_buffer); 4340Sstevel@tonic-gate len = write(fdin, data, dlen); 4350Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 4360Sstevel@tonic-gate /* EMPTY */ 4370Sstevel@tonic-gate } else if (len <= 0) { 4380Sstevel@tonic-gate if (fdin != fdout) 4390Sstevel@tonic-gate (void) close(fdin); 4400Sstevel@tonic-gate else 4410Sstevel@tonic-gate (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */ 4420Sstevel@tonic-gate fdin = -1; 4430Sstevel@tonic-gate } else { 4440Sstevel@tonic-gate /* Successful write. */ 4450Sstevel@tonic-gate if (fdin_is_tty && dlen >= 1 && data[0] != '\r' && 4460Sstevel@tonic-gate tcgetattr(fdin, &tio) == 0 && 4470Sstevel@tonic-gate !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 4480Sstevel@tonic-gate /* 4490Sstevel@tonic-gate * Simulate echo to reduce the impact of 4500Sstevel@tonic-gate * traffic analysis 4510Sstevel@tonic-gate */ 4520Sstevel@tonic-gate packet_send_ignore(len); 4530Sstevel@tonic-gate packet_send(); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate /* Consume the data from the buffer. */ 4560Sstevel@tonic-gate buffer_consume(&stdin_buffer, len); 4570Sstevel@tonic-gate /* Update the count of bytes written to the program. */ 4580Sstevel@tonic-gate stdin_bytes += len; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate /* Send any buffered packet data to the client. */ 4620Sstevel@tonic-gate if (FD_ISSET(connection_out, writeset)) 4630Sstevel@tonic-gate packet_write_poll(); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * Wait until all buffered output has been sent to the client. 4680Sstevel@tonic-gate * This is used when the program terminates. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate static void 4710Sstevel@tonic-gate drain_output(void) 4720Sstevel@tonic-gate { 4730Sstevel@tonic-gate /* Send any buffered stdout data to the client. */ 4740Sstevel@tonic-gate if (buffer_len(&stdout_buffer) > 0) { 4750Sstevel@tonic-gate packet_start(SSH_SMSG_STDOUT_DATA); 4760Sstevel@tonic-gate packet_put_string(buffer_ptr(&stdout_buffer), 4770Sstevel@tonic-gate buffer_len(&stdout_buffer)); 4780Sstevel@tonic-gate packet_send(); 4790Sstevel@tonic-gate /* Update the count of sent bytes. */ 4800Sstevel@tonic-gate stdout_bytes += buffer_len(&stdout_buffer); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate /* Send any buffered stderr data to the client. */ 4830Sstevel@tonic-gate if (buffer_len(&stderr_buffer) > 0) { 4840Sstevel@tonic-gate packet_start(SSH_SMSG_STDERR_DATA); 4850Sstevel@tonic-gate packet_put_string(buffer_ptr(&stderr_buffer), 4860Sstevel@tonic-gate buffer_len(&stderr_buffer)); 4870Sstevel@tonic-gate packet_send(); 4880Sstevel@tonic-gate /* Update the count of sent bytes. */ 4890Sstevel@tonic-gate stderr_bytes += buffer_len(&stderr_buffer); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate /* Wait until all buffered data has been written to the client. */ 4920Sstevel@tonic-gate packet_write_wait(); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate static void 4960Sstevel@tonic-gate process_buffered_input_packets(void) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL); 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * Performs the interactive session. This handles data transmission between 5030Sstevel@tonic-gate * the client and the program. Note that the notion of stdin, stdout, and 5040Sstevel@tonic-gate * stderr in this function is sort of reversed: this function writes to 5050Sstevel@tonic-gate * stdin (of the child program), and reads from stdout and stderr (of the 5060Sstevel@tonic-gate * child program). 5070Sstevel@tonic-gate */ 5080Sstevel@tonic-gate void 5090Sstevel@tonic-gate server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) 5100Sstevel@tonic-gate { 5110Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 5120Sstevel@tonic-gate int max_fd = 0, nalloc = 0; 5130Sstevel@tonic-gate int wait_status; /* Status returned by wait(). */ 5140Sstevel@tonic-gate pid_t wait_pid; /* pid returned by wait(). */ 5150Sstevel@tonic-gate int waiting_termination = 0; /* Have displayed waiting close message. */ 5160Sstevel@tonic-gate u_int max_time_milliseconds; 5170Sstevel@tonic-gate u_int previous_stdout_buffer_bytes; 5180Sstevel@tonic-gate u_int stdout_buffer_bytes; 5190Sstevel@tonic-gate int type; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate debug("Entering interactive session."); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate /* Initialize the SIGCHLD kludge. */ 5240Sstevel@tonic-gate child_terminated = 0; 5250Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* Initialize our global variables. */ 5280Sstevel@tonic-gate fdin = fdin_arg; 5290Sstevel@tonic-gate fdout = fdout_arg; 5300Sstevel@tonic-gate fderr = fderr_arg; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* nonblocking IO */ 5330Sstevel@tonic-gate set_nonblock(fdin); 5340Sstevel@tonic-gate set_nonblock(fdout); 5350Sstevel@tonic-gate /* we don't have stderr for interactive terminal sessions, see below */ 5360Sstevel@tonic-gate if (fderr != -1) 5370Sstevel@tonic-gate set_nonblock(fderr); 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) 5400Sstevel@tonic-gate fdin_is_tty = 1; 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate connection_in = packet_get_connection_in(); 5430Sstevel@tonic-gate connection_out = packet_get_connection_out(); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate notify_setup(); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate previous_stdout_buffer_bytes = 0; 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate /* Set approximate I/O buffer size. */ 5500Sstevel@tonic-gate if (packet_is_interactive()) 5510Sstevel@tonic-gate buffer_high = 4096; 5520Sstevel@tonic-gate else 5530Sstevel@tonic-gate buffer_high = 64 * 1024; 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate #if 0 5560Sstevel@tonic-gate /* Initialize max_fd to the maximum of the known file descriptors. */ 5570Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 5580Sstevel@tonic-gate max_fd = MAX(max_fd, fdin); 5590Sstevel@tonic-gate max_fd = MAX(max_fd, fdout); 5600Sstevel@tonic-gate if (fderr != -1) 5610Sstevel@tonic-gate max_fd = MAX(max_fd, fderr); 5620Sstevel@tonic-gate #endif 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* Initialize Initialize buffers. */ 5650Sstevel@tonic-gate buffer_init(&stdin_buffer); 5660Sstevel@tonic-gate buffer_init(&stdout_buffer); 5670Sstevel@tonic-gate buffer_init(&stderr_buffer); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * If we have no separate fderr (which is the case when we have a pty 5710Sstevel@tonic-gate * - there we cannot make difference between data sent to stdout and 5720Sstevel@tonic-gate * stderr), indicate that we have seen an EOF from stderr. This way 5730Sstevel@tonic-gate * we don\'t need to check the descriptor everywhere. 5740Sstevel@tonic-gate */ 5750Sstevel@tonic-gate if (fderr == -1) 5760Sstevel@tonic-gate fderr_eof = 1; 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate server_init_dispatch(); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate /* Main loop of the server for the interactive session mode. */ 5810Sstevel@tonic-gate for (;;) { 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* Process buffered packets from the client. */ 5840Sstevel@tonic-gate process_buffered_input_packets(); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate /* 5870Sstevel@tonic-gate * If we have received eof, and there is no more pending 5880Sstevel@tonic-gate * input data, cause a real eof by closing fdin. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { 5910Sstevel@tonic-gate if (fdin != fdout) 5920Sstevel@tonic-gate (void) close(fdin); 5930Sstevel@tonic-gate else 5940Sstevel@tonic-gate (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */ 5950Sstevel@tonic-gate fdin = -1; 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate /* Make packets from buffered stderr data to send to the client. */ 5980Sstevel@tonic-gate make_packets_from_stderr_data(); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* 6010Sstevel@tonic-gate * Make packets from buffered stdout data to send to the 6020Sstevel@tonic-gate * client. If there is very little to send, this arranges to 6030Sstevel@tonic-gate * not send them now, but to wait a short while to see if we 6040Sstevel@tonic-gate * are getting more data. This is necessary, as some systems 6050Sstevel@tonic-gate * wake up readers from a pty after each separate character. 6060Sstevel@tonic-gate */ 6070Sstevel@tonic-gate max_time_milliseconds = 0; 6080Sstevel@tonic-gate stdout_buffer_bytes = buffer_len(&stdout_buffer); 6090Sstevel@tonic-gate if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && 6100Sstevel@tonic-gate stdout_buffer_bytes != previous_stdout_buffer_bytes) { 6110Sstevel@tonic-gate /* try again after a while */ 6120Sstevel@tonic-gate max_time_milliseconds = 10; 6130Sstevel@tonic-gate } else { 6140Sstevel@tonic-gate /* Send it now. */ 6150Sstevel@tonic-gate make_packets_from_stdout_data(); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate /* Send channel data to the client. */ 6200Sstevel@tonic-gate if (packet_not_very_much_data_to_write()) 6210Sstevel@tonic-gate channel_output_poll(); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Bail out of the loop if the program has closed its output 6250Sstevel@tonic-gate * descriptors, and we have no more data to send to the 6260Sstevel@tonic-gate * client, and there is no pending buffered data. 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate if (fdout_eof && fderr_eof && !packet_have_data_to_write() && 6290Sstevel@tonic-gate buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { 6300Sstevel@tonic-gate if (!channel_still_open()) 6310Sstevel@tonic-gate break; 6320Sstevel@tonic-gate if (!waiting_termination) { 6330Sstevel@tonic-gate const char *s = "Waiting for forwarded connections to terminate...\r\n"; 6340Sstevel@tonic-gate char *cp; 6350Sstevel@tonic-gate waiting_termination = 1; 6360Sstevel@tonic-gate buffer_append(&stderr_buffer, s, strlen(s)); 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* Display list of open channels. */ 6390Sstevel@tonic-gate cp = channel_open_message(); 6400Sstevel@tonic-gate buffer_append(&stderr_buffer, cp, strlen(cp)); 6410Sstevel@tonic-gate xfree(cp); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 6450Sstevel@tonic-gate max_fd = MAX(max_fd, fdin); 6460Sstevel@tonic-gate max_fd = MAX(max_fd, fdout); 6470Sstevel@tonic-gate max_fd = MAX(max_fd, fderr); 6480Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* Sleep in select() until we can do something. */ 6510Sstevel@tonic-gate wait_until_can_do_something(&readset, &writeset, &max_fd, 6520Sstevel@tonic-gate &nalloc, max_time_milliseconds); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* Process any channel events. */ 6550Sstevel@tonic-gate channel_after_select(readset, writeset); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* Process input from the client and from program stdout/stderr. */ 6580Sstevel@tonic-gate process_input(readset); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate /* Process output to the client and to program stdin. */ 6610Sstevel@tonic-gate process_output(writeset); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate if (readset) 6640Sstevel@tonic-gate xfree(readset); 6650Sstevel@tonic-gate if (writeset) 6660Sstevel@tonic-gate xfree(writeset); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* Cleanup and termination code. */ 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* Wait until all output has been sent to the client. */ 6710Sstevel@tonic-gate drain_output(); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", 6740Sstevel@tonic-gate stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* Free and clear the buffers. */ 6770Sstevel@tonic-gate buffer_free(&stdin_buffer); 6780Sstevel@tonic-gate buffer_free(&stdout_buffer); 6790Sstevel@tonic-gate buffer_free(&stderr_buffer); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate /* Close the file descriptors. */ 6820Sstevel@tonic-gate if (fdout != -1) 6830Sstevel@tonic-gate (void) close(fdout); 6840Sstevel@tonic-gate fdout = -1; 6850Sstevel@tonic-gate fdout_eof = 1; 6860Sstevel@tonic-gate if (fderr != -1) 6870Sstevel@tonic-gate (void) close(fderr); 6880Sstevel@tonic-gate fderr = -1; 6890Sstevel@tonic-gate fderr_eof = 1; 6900Sstevel@tonic-gate if (fdin != -1) 6910Sstevel@tonic-gate (void) close(fdin); 6920Sstevel@tonic-gate fdin = -1; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate channel_free_all(); 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* We no longer want our SIGCHLD handler to be called. */ 6970Sstevel@tonic-gate mysignal(SIGCHLD, SIG_DFL); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) 7000Sstevel@tonic-gate if (errno != EINTR) 7010Sstevel@tonic-gate packet_disconnect("wait: %.100s", strerror(errno)); 7020Sstevel@tonic-gate if (wait_pid != pid) 7030Sstevel@tonic-gate error("Strange, wait returned pid %ld, expected %ld", 7040Sstevel@tonic-gate (long)wait_pid, (long)pid); 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate /* Check if it exited normally. */ 7070Sstevel@tonic-gate if (WIFEXITED(wait_status)) { 7080Sstevel@tonic-gate /* Yes, normal exit. Get exit status and send it to the client. */ 7090Sstevel@tonic-gate debug("Command exited with status %d.", WEXITSTATUS(wait_status)); 7100Sstevel@tonic-gate packet_start(SSH_SMSG_EXITSTATUS); 7110Sstevel@tonic-gate packet_put_int(WEXITSTATUS(wait_status)); 7120Sstevel@tonic-gate packet_send(); 7130Sstevel@tonic-gate packet_write_wait(); 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * Wait for exit confirmation. Note that there might be 7170Sstevel@tonic-gate * other packets coming before it; however, the program has 7180Sstevel@tonic-gate * already died so we just ignore them. The client is 7190Sstevel@tonic-gate * supposed to respond with the confirmation when it receives 7200Sstevel@tonic-gate * the exit status. 7210Sstevel@tonic-gate */ 7220Sstevel@tonic-gate do { 7230Sstevel@tonic-gate type = packet_read(); 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate while (type != SSH_CMSG_EXIT_CONFIRMATION); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate debug("Received exit confirmation."); 7280Sstevel@tonic-gate return; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate /* Check if the program terminated due to a signal. */ 7310Sstevel@tonic-gate if (WIFSIGNALED(wait_status)) 7320Sstevel@tonic-gate packet_disconnect("Command terminated on signal %d.", 7330Sstevel@tonic-gate WTERMSIG(wait_status)); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* Some weird exit cause. Just exit. */ 7360Sstevel@tonic-gate packet_disconnect("wait returned status %04x.", wait_status); 7370Sstevel@tonic-gate /* NOTREACHED */ 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate static void 7410Sstevel@tonic-gate collect_children(void) 7420Sstevel@tonic-gate { 7430Sstevel@tonic-gate pid_t pid; 7440Sstevel@tonic-gate sigset_t oset, nset; 7450Sstevel@tonic-gate int status; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* block SIGCHLD while we check for dead children */ 7480Sstevel@tonic-gate (void) sigemptyset(&nset); 7490Sstevel@tonic-gate (void) sigaddset(&nset, SIGCHLD); 7500Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 7510Sstevel@tonic-gate if (child_terminated) { 7520Sstevel@tonic-gate while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 7530Sstevel@tonic-gate (pid < 0 && errno == EINTR)) 7540Sstevel@tonic-gate if (pid > 0) 7550Sstevel@tonic-gate session_close_by_pid(pid, status); 7560Sstevel@tonic-gate child_terminated = 0; 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate #ifdef ALTPRIVSEP 7620Sstevel@tonic-gate /* 7630Sstevel@tonic-gate * For ALTPRIVSEP the wait_until_can_do_something function is very 7640Sstevel@tonic-gate * simple: select() on the read side of the pipe, and if there's packets 7650Sstevel@tonic-gate * to send, on the write side, and on the read side of the SIGCHLD 7660Sstevel@tonic-gate * handler pipe. That's it. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate static void 7690Sstevel@tonic-gate aps_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, 7700Sstevel@tonic-gate int *maxfdp, int *nallocp, u_int max_time_milliseconds) 7710Sstevel@tonic-gate { 7720Sstevel@tonic-gate int ret; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * Use channel_prepare_select() to make the fd sets. 7760Sstevel@tonic-gate * 7770Sstevel@tonic-gate * This is cheating, really, since because the last argument in 7780Sstevel@tonic-gate * this call is '1' nothing related to channels will be done -- 7790Sstevel@tonic-gate * we're using this function only to callocate the fd sets. 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 1); 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate if ((connection_in = packet_get_connection_in()) >= 0 && 7840Sstevel@tonic-gate !connection_closed) 7850Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate notify_prepare(*readsetp); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate if ((connection_out = packet_get_connection_out()) >= 0 && 7900Sstevel@tonic-gate packet_have_data_to_write() && !connection_closed) 7910Sstevel@tonic-gate FD_SET(connection_out, *writesetp); 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate /* Wait for something to happen, or the timeout to expire. */ 7940Sstevel@tonic-gate ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if (ret == -1) { 7970Sstevel@tonic-gate memset(*readsetp, 0, *nallocp); 7980Sstevel@tonic-gate memset(*writesetp, 0, *nallocp); 7990Sstevel@tonic-gate if (errno != EINTR) 8000Sstevel@tonic-gate error("select: %.100s", strerror(errno)); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate notify_done(*readsetp); 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate /* 8070Sstevel@tonic-gate * Slightly different than collect_children, aps_collect_child() has 8080Sstevel@tonic-gate * only the unprivileged sshd to wait for, no sessions, no channells, 8090Sstevel@tonic-gate * just one process. 8100Sstevel@tonic-gate */ 8110Sstevel@tonic-gate static int 8120Sstevel@tonic-gate aps_collect_child(pid_t child) 8130Sstevel@tonic-gate { 8140Sstevel@tonic-gate pid_t pid; 8150Sstevel@tonic-gate sigset_t oset, nset; 8160Sstevel@tonic-gate int status; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate /* block SIGCHLD while we check for dead children */ 8190Sstevel@tonic-gate (void) sigemptyset(&nset); 8200Sstevel@tonic-gate (void) sigaddset(&nset, SIGCHLD); 8210Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 8220Sstevel@tonic-gate if (child_terminated) { 8230Sstevel@tonic-gate while ((pid = waitpid(child, &status, WNOHANG)) > 0 || 8240Sstevel@tonic-gate (pid < 0 && errno == EINTR)) 8250Sstevel@tonic-gate if (pid == child) { 8260Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 8270Sstevel@tonic-gate return (1); 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate child_terminated = 0; 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 8320Sstevel@tonic-gate return (0); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate static int killed = 0; 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate static void 8380Sstevel@tonic-gate aps_monitor_kill_handler(int sig) 8390Sstevel@tonic-gate { 8400Sstevel@tonic-gate int save_errno = errno; 8410Sstevel@tonic-gate killed = 1; 8420Sstevel@tonic-gate notify_parent(); 8430Sstevel@tonic-gate mysignal(sig, aps_monitor_kill_handler); 8440Sstevel@tonic-gate errno = save_errno; 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate static void 8480Sstevel@tonic-gate aps_monitor_sigchld_handler(int sig) 8490Sstevel@tonic-gate { 8500Sstevel@tonic-gate int save_errno = errno; 8510Sstevel@tonic-gate debug("Monitor received SIGCHLD."); 8520Sstevel@tonic-gate child_terminated = 1; 8530Sstevel@tonic-gate mysignal(SIGCHLD, aps_monitor_sigchld_handler); 8540Sstevel@tonic-gate notify_parent(); 8550Sstevel@tonic-gate errno = save_errno; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate void 859*7574SJan.Pechanec@Sun.COM aps_monitor_loop(Authctxt *authctxt, pid_t child_pid) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 8620Sstevel@tonic-gate int max_fd, nalloc = 0; 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate debug("Entering monitor loop."); 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Awful hack follows: fake compat20 == 1 to cause process_input() 8680Sstevel@tonic-gate * and process_output() to behave as they would for SSHv2 because that's 8690Sstevel@tonic-gate * the behaviour we need in SSHv2. 8700Sstevel@tonic-gate * 8710Sstevel@tonic-gate * This same hack is done in packet.c 8720Sstevel@tonic-gate */ 8730Sstevel@tonic-gate compat20 = 1; /* causes process_input/output() to ignore stdio */ 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate mysignal(SIGHUP, aps_monitor_kill_handler); 8760Sstevel@tonic-gate mysignal(SIGINT, aps_monitor_kill_handler); 8770Sstevel@tonic-gate mysignal(SIGTERM, aps_monitor_kill_handler); 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate child_terminated = 0; 8800Sstevel@tonic-gate mysignal(SIGCHLD, aps_monitor_sigchld_handler); 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate connection_in = packet_get_connection_in(); 8830Sstevel@tonic-gate connection_out = packet_get_connection_out(); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate notify_setup(); 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 8880Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 8910Sstevel@tonic-gate dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_MAX, 8920Sstevel@tonic-gate &dispatch_protocol_error); 8930Sstevel@tonic-gate dispatch_set(SSH2_PRIV_MSG_ALTPRIVSEP, &aps_input_altpriv_msg); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate for (;;) { 8960Sstevel@tonic-gate process_buffered_input_packets(); 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate aps_wait_until_can_do_something(&readset, &writeset, &max_fd, 8990Sstevel@tonic-gate &nalloc, 0); 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate if (aps_collect_child(child_pid)) 9020Sstevel@tonic-gate break; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate if (killed) { 9050Sstevel@tonic-gate /* fatal cleanups will kill child, audit logout */ 9060Sstevel@tonic-gate log("Monitor killed; exiting"); 9070Sstevel@tonic-gate fatal_cleanup(); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * Unlike server_loop2() we don't care if connection_closed 9120Sstevel@tonic-gate * since we still want to wait for the monitor's child. 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate process_input(readset); 9150Sstevel@tonic-gate process_output(writeset); 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate packet_close(); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 9210Sstevel@tonic-gate 922*7574SJan.Pechanec@Sun.COM /* 923*7574SJan.Pechanec@Sun.COM * This server loop is for unprivileged child only. Our monitor runs its own 924*7574SJan.Pechanec@Sun.COM * aps_monitor_loop() funtion. 925*7574SJan.Pechanec@Sun.COM */ 9260Sstevel@tonic-gate void 9270Sstevel@tonic-gate server_loop2(Authctxt *authctxt) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 9300Sstevel@tonic-gate int rekeying = 0, max_fd, nalloc = 0; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate debug("Entering interactive session for SSH2."); 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 9350Sstevel@tonic-gate child_terminated = 0; 9360Sstevel@tonic-gate connection_in = packet_get_connection_in(); 9370Sstevel@tonic-gate connection_out = packet_get_connection_out(); 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate notify_setup(); 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 9420Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate xxx_authctxt = authctxt; 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate server_init_dispatch(); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate for (;;) { 9490Sstevel@tonic-gate process_buffered_input_packets(); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate rekeying = (xxx_kex != NULL && !xxx_kex->done); 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate if (!rekeying && packet_not_very_much_data_to_write()) 9540Sstevel@tonic-gate channel_output_poll(); 9550Sstevel@tonic-gate wait_until_can_do_something(&readset, &writeset, &max_fd, 9560Sstevel@tonic-gate &nalloc, 0); 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate collect_children(); 9590Sstevel@tonic-gate 9605562Sjp161948 if (!rekeying) { 9610Sstevel@tonic-gate channel_after_select(readset, writeset); 9625562Sjp161948 if (packet_need_rekeying()) { 9636375Sjp161948 debug("rekey limit reached, need rekeying"); 9645562Sjp161948 xxx_kex->done = 0; 9656375Sjp161948 debug("poking the monitor to start " 9666375Sjp161948 "key re-exchange"); 9676375Sjp161948 altprivsep_start_rekex(); 9685562Sjp161948 } 9695562Sjp161948 } 9700Sstevel@tonic-gate #ifdef ALTPRIVSEP 9710Sstevel@tonic-gate else 9726375Sjp161948 altprivsep_process_input(readset); 9730Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate process_input(readset); 9760Sstevel@tonic-gate if (connection_closed) 9770Sstevel@tonic-gate break; 9780Sstevel@tonic-gate process_output(writeset); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate collect_children(); 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate if (readset) 9830Sstevel@tonic-gate xfree(readset); 9840Sstevel@tonic-gate if (writeset) 9850Sstevel@tonic-gate xfree(writeset); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate /* free all channels, no more reads and writes */ 9880Sstevel@tonic-gate channel_free_all(); 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate /* free remaining sessions, e.g. remove wtmp entries */ 9910Sstevel@tonic-gate session_destroy_all(NULL); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate static void 9950Sstevel@tonic-gate server_input_channel_failure(int type, u_int32_t seq, void *ctxt) 9960Sstevel@tonic-gate { 9970Sstevel@tonic-gate debug("Got CHANNEL_FAILURE for keepalive"); 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * reset timeout, since we got a sane answer from the client. 10000Sstevel@tonic-gate * even if this was generated by something other than 10010Sstevel@tonic-gate * the bogus CHANNEL_REQUEST we send for keepalives. 10020Sstevel@tonic-gate */ 10030Sstevel@tonic-gate client_alive_timeouts = 0; 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate static void 10070Sstevel@tonic-gate server_input_stdin_data(int type, u_int32_t seq, void *ctxt) 10080Sstevel@tonic-gate { 10090Sstevel@tonic-gate char *data; 10100Sstevel@tonic-gate u_int data_len; 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate /* Stdin data from the client. Append it to the buffer. */ 10130Sstevel@tonic-gate /* Ignore any data if the client has closed stdin. */ 10140Sstevel@tonic-gate if (fdin == -1) 10150Sstevel@tonic-gate return; 10160Sstevel@tonic-gate data = packet_get_string(&data_len); 10170Sstevel@tonic-gate packet_check_eom(); 10180Sstevel@tonic-gate buffer_append(&stdin_buffer, data, data_len); 10190Sstevel@tonic-gate memset(data, 0, data_len); 10200Sstevel@tonic-gate xfree(data); 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate static void 10240Sstevel@tonic-gate server_input_eof(int type, u_int32_t seq, void *ctxt) 10250Sstevel@tonic-gate { 10260Sstevel@tonic-gate /* 10270Sstevel@tonic-gate * Eof from the client. The stdin descriptor to the 10280Sstevel@tonic-gate * program will be closed when all buffered data has 10290Sstevel@tonic-gate * drained. 10300Sstevel@tonic-gate */ 10310Sstevel@tonic-gate debug("EOF received for stdin."); 10320Sstevel@tonic-gate packet_check_eom(); 10330Sstevel@tonic-gate stdin_eof = 1; 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate static void 10370Sstevel@tonic-gate server_input_window_size(int type, u_int32_t seq, void *ctxt) 10380Sstevel@tonic-gate { 10390Sstevel@tonic-gate int row = packet_get_int(); 10400Sstevel@tonic-gate int col = packet_get_int(); 10410Sstevel@tonic-gate int xpixel = packet_get_int(); 10420Sstevel@tonic-gate int ypixel = packet_get_int(); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate debug("Window change received."); 10450Sstevel@tonic-gate packet_check_eom(); 10460Sstevel@tonic-gate if (fdin != -1) 10470Sstevel@tonic-gate pty_change_window_size(fdin, row, col, xpixel, ypixel); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate static Channel * 10510Sstevel@tonic-gate server_request_direct_tcpip(char *ctype) 10520Sstevel@tonic-gate { 10530Sstevel@tonic-gate Channel *c; 10540Sstevel@tonic-gate int sock; 10550Sstevel@tonic-gate char *target, *originator; 10560Sstevel@tonic-gate int target_port, originator_port; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate target = packet_get_string(NULL); 10590Sstevel@tonic-gate target_port = packet_get_int(); 10600Sstevel@tonic-gate originator = packet_get_string(NULL); 10610Sstevel@tonic-gate originator_port = packet_get_int(); 10620Sstevel@tonic-gate packet_check_eom(); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", 10650Sstevel@tonic-gate originator, originator_port, target, target_port); 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate /* XXX check permission */ 10680Sstevel@tonic-gate sock = channel_connect_to(target, target_port); 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate xfree(target); 10710Sstevel@tonic-gate xfree(originator); 10720Sstevel@tonic-gate if (sock < 0) 10730Sstevel@tonic-gate return NULL; 10740Sstevel@tonic-gate c = channel_new(ctype, SSH_CHANNEL_CONNECTING, 10750Sstevel@tonic-gate sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, 10760Sstevel@tonic-gate CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); 10770Sstevel@tonic-gate return c; 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate static Channel * 10810Sstevel@tonic-gate server_request_session(char *ctype) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate Channel *c; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate debug("input_session_request"); 10860Sstevel@tonic-gate packet_check_eom(); 10870Sstevel@tonic-gate /* 10880Sstevel@tonic-gate * A server session has no fd to read or write until a 10890Sstevel@tonic-gate * CHANNEL_REQUEST for a shell is made, so we set the type to 10900Sstevel@tonic-gate * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all 10910Sstevel@tonic-gate * CHANNEL_REQUEST messages is registered. 10920Sstevel@tonic-gate */ 10930Sstevel@tonic-gate c = channel_new(ctype, SSH_CHANNEL_LARVAL, 10940Sstevel@tonic-gate -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 10950Sstevel@tonic-gate 0, xstrdup("server-session"), 1); 10960Sstevel@tonic-gate if (session_open(xxx_authctxt, c->self) != 1) { 10970Sstevel@tonic-gate debug("session open failed, free channel %d", c->self); 10980Sstevel@tonic-gate channel_free(c); 10990Sstevel@tonic-gate return NULL; 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate channel_register_cleanup(c->self, session_close_by_channel); 11020Sstevel@tonic-gate return c; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate static void 11060Sstevel@tonic-gate server_input_channel_open(int type, u_int32_t seq, void *ctxt) 11070Sstevel@tonic-gate { 11080Sstevel@tonic-gate Channel *c = NULL; 11090Sstevel@tonic-gate char *ctype; 11100Sstevel@tonic-gate int rchan; 11110Sstevel@tonic-gate u_int rmaxpack, rwindow, len; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate ctype = packet_get_string(&len); 11140Sstevel@tonic-gate rchan = packet_get_int(); 11150Sstevel@tonic-gate rwindow = packet_get_int(); 11160Sstevel@tonic-gate rmaxpack = packet_get_int(); 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate debug("server_input_channel_open: ctype %s rchan %d win %d max %d", 11190Sstevel@tonic-gate ctype, rchan, rwindow, rmaxpack); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate if (strcmp(ctype, "session") == 0) { 11220Sstevel@tonic-gate c = server_request_session(ctype); 11230Sstevel@tonic-gate } else if (strcmp(ctype, "direct-tcpip") == 0) { 11240Sstevel@tonic-gate c = server_request_direct_tcpip(ctype); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate if (c != NULL) { 11270Sstevel@tonic-gate debug("server_input_channel_open: confirm %s", ctype); 11280Sstevel@tonic-gate c->remote_id = rchan; 11290Sstevel@tonic-gate c->remote_window = rwindow; 11300Sstevel@tonic-gate c->remote_maxpacket = rmaxpack; 11310Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CONNECTING) { 11320Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 11330Sstevel@tonic-gate packet_put_int(c->remote_id); 11340Sstevel@tonic-gate packet_put_int(c->self); 11350Sstevel@tonic-gate packet_put_int(c->local_window); 11360Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 11370Sstevel@tonic-gate packet_send(); 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate } else { 11400Sstevel@tonic-gate debug("server_input_channel_open: failure %s", ctype); 11410Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 11420Sstevel@tonic-gate packet_put_int(rchan); 11430Sstevel@tonic-gate packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); 11440Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 11450Sstevel@tonic-gate packet_put_cstring("open failed"); 11460Sstevel@tonic-gate packet_put_cstring(""); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate packet_send(); 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate xfree(ctype); 11510Sstevel@tonic-gate } 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate static void 11540Sstevel@tonic-gate server_input_global_request(int type, u_int32_t seq, void *ctxt) 11550Sstevel@tonic-gate { 11560Sstevel@tonic-gate char *rtype; 11570Sstevel@tonic-gate int want_reply; 11580Sstevel@tonic-gate int success = 0; 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate rtype = packet_get_string(NULL); 11610Sstevel@tonic-gate want_reply = packet_get_char(); 11620Sstevel@tonic-gate debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply); 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate /* -R style forwarding */ 11650Sstevel@tonic-gate if (strcmp(rtype, "tcpip-forward") == 0) { 11660Sstevel@tonic-gate struct passwd *pw; 11670Sstevel@tonic-gate char *listen_address; 11680Sstevel@tonic-gate u_short listen_port; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate pw = auth_get_user(); 11710Sstevel@tonic-gate if (pw == NULL) 11720Sstevel@tonic-gate fatal("server_input_global_request: no user"); 11730Sstevel@tonic-gate listen_address = packet_get_string(NULL); /* XXX currently ignored */ 11740Sstevel@tonic-gate listen_port = (u_short)packet_get_int(); 11750Sstevel@tonic-gate debug("server_input_global_request: tcpip-forward listen %s port %d", 11760Sstevel@tonic-gate listen_address, listen_port); 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate /* check permissions */ 11790Sstevel@tonic-gate if (!options.allow_tcp_forwarding || 11800Sstevel@tonic-gate no_port_forwarding_flag 11810Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT 11820Sstevel@tonic-gate || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) 11830Sstevel@tonic-gate #endif 11840Sstevel@tonic-gate ) { 11850Sstevel@tonic-gate success = 0; 11860Sstevel@tonic-gate packet_send_debug("Server has disabled port forwarding."); 11870Sstevel@tonic-gate } else { 11880Sstevel@tonic-gate /* Start listening on the port */ 11890Sstevel@tonic-gate success = channel_setup_remote_fwd_listener( 11900Sstevel@tonic-gate listen_address, listen_port, options.gateway_ports); 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate xfree(listen_address); 11935334Sjp161948 } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { 11945334Sjp161948 char *cancel_address; 11955334Sjp161948 u_short cancel_port; 11965334Sjp161948 11975334Sjp161948 cancel_address = packet_get_string(NULL); 11985334Sjp161948 cancel_port = (u_short)packet_get_int(); 11995334Sjp161948 debug("%s: cancel-tcpip-forward addr %s port %d", __func__, 12005334Sjp161948 cancel_address, cancel_port); 12015334Sjp161948 12025334Sjp161948 success = channel_cancel_rport_listener(cancel_address, 12035334Sjp161948 cancel_port); 12045334Sjp161948 xfree(cancel_address); 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate if (want_reply) { 12070Sstevel@tonic-gate packet_start(success ? 12080Sstevel@tonic-gate SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 12090Sstevel@tonic-gate packet_send(); 12100Sstevel@tonic-gate packet_write_wait(); 12110Sstevel@tonic-gate } 12120Sstevel@tonic-gate xfree(rtype); 12130Sstevel@tonic-gate } 12145334Sjp161948 12150Sstevel@tonic-gate static void 12160Sstevel@tonic-gate server_input_channel_req(int type, u_int32_t seq, void *ctxt) 12170Sstevel@tonic-gate { 12180Sstevel@tonic-gate Channel *c; 12190Sstevel@tonic-gate int id, reply, success = 0; 12200Sstevel@tonic-gate char *rtype; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate id = packet_get_int(); 12230Sstevel@tonic-gate rtype = packet_get_string(NULL); 12240Sstevel@tonic-gate reply = packet_get_char(); 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate debug("server_input_channel_req: channel %d request %s reply %d", 12270Sstevel@tonic-gate id, rtype, reply); 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate if ((c = channel_lookup(id)) == NULL) 12300Sstevel@tonic-gate packet_disconnect("server_input_channel_req: " 12310Sstevel@tonic-gate "unknown channel %d", id); 12320Sstevel@tonic-gate if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) 12330Sstevel@tonic-gate success = session_input_channel_req(c, rtype); 12340Sstevel@tonic-gate if (reply) { 12350Sstevel@tonic-gate packet_start(success ? 12360Sstevel@tonic-gate SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 12370Sstevel@tonic-gate packet_put_int(c->remote_id); 12380Sstevel@tonic-gate packet_send(); 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate xfree(rtype); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate static void 12440Sstevel@tonic-gate server_init_dispatch_20(void) 12450Sstevel@tonic-gate { 12460Sstevel@tonic-gate debug("server_init_dispatch_20"); 12470Sstevel@tonic-gate dispatch_init(&dispatch_protocol_error); 12480Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); 12490Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); 12500Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); 12510Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); 12520Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open); 12530Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 12540Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 12550Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); 12560Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); 12570Sstevel@tonic-gate dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); 12580Sstevel@tonic-gate /* client_alive */ 12590Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure); 12600Sstevel@tonic-gate /* rekeying */ 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate #ifdef ALTPRIVSEP 12630Sstevel@tonic-gate /* unprivileged sshd has a kex packet handler that must not be reset */ 12640Sstevel@tonic-gate debug3("server_init_dispatch_20 -- should we dispatch_set(KEXINIT) here? %d && !%d", 12650Sstevel@tonic-gate packet_is_server(), packet_is_monitor()); 12660Sstevel@tonic-gate if (packet_is_server() && !packet_is_monitor()) { 12670Sstevel@tonic-gate debug3("server_init_dispatch_20 -- skipping dispatch_set(KEXINIT) in unpriv proc"); 12680Sstevel@tonic-gate dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 12690Sstevel@tonic-gate &altprivsep_rekey); 12700Sstevel@tonic-gate return; 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 12730Sstevel@tonic-gate dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate static void 12760Sstevel@tonic-gate server_init_dispatch_13(void) 12770Sstevel@tonic-gate { 12780Sstevel@tonic-gate debug("server_init_dispatch_13"); 12790Sstevel@tonic-gate dispatch_init(NULL); 12800Sstevel@tonic-gate dispatch_set(SSH_CMSG_EOF, &server_input_eof); 12810Sstevel@tonic-gate dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); 12820Sstevel@tonic-gate dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); 12830Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); 12840Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); 12850Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); 12860Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 12870Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 12880Sstevel@tonic-gate dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate static void 12910Sstevel@tonic-gate server_init_dispatch_15(void) 12920Sstevel@tonic-gate { 12930Sstevel@tonic-gate server_init_dispatch_13(); 12940Sstevel@tonic-gate debug("server_init_dispatch_15"); 12950Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); 12960Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate static void 12990Sstevel@tonic-gate server_init_dispatch(void) 13000Sstevel@tonic-gate { 13010Sstevel@tonic-gate if (compat20) 13020Sstevel@tonic-gate server_init_dispatch_20(); 13030Sstevel@tonic-gate else if (compat13) 13040Sstevel@tonic-gate server_init_dispatch_13(); 13050Sstevel@tonic-gate else 13060Sstevel@tonic-gate server_init_dispatch_15(); 13070Sstevel@tonic-gate } 1308