1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 3*0Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4*0Sstevel@tonic-gate * All rights reserved 5*0Sstevel@tonic-gate * Server main loop for handling the interactive session. 6*0Sstevel@tonic-gate * 7*0Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 8*0Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 9*0Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 10*0Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 11*0Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * SSH2 support by Markus Friedl. 14*0Sstevel@tonic-gate * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 15*0Sstevel@tonic-gate * 16*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 17*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 18*0Sstevel@tonic-gate * are met: 19*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 20*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 21*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 22*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 23*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate /* 37*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 38*0Sstevel@tonic-gate * Use is subject to license terms. 39*0Sstevel@tonic-gate */ 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate #include "includes.h" 42*0Sstevel@tonic-gate RCSID("$OpenBSD: serverloop.c,v 1.104 2002/09/19 16:03:15 stevesk Exp $"); 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #include "xmalloc.h" 47*0Sstevel@tonic-gate #include "packet.h" 48*0Sstevel@tonic-gate #include "buffer.h" 49*0Sstevel@tonic-gate #include "log.h" 50*0Sstevel@tonic-gate #include "servconf.h" 51*0Sstevel@tonic-gate #include "canohost.h" 52*0Sstevel@tonic-gate #include "sshpty.h" 53*0Sstevel@tonic-gate #include "channels.h" 54*0Sstevel@tonic-gate #include "compat.h" 55*0Sstevel@tonic-gate #include "ssh1.h" 56*0Sstevel@tonic-gate #include "ssh2.h" 57*0Sstevel@tonic-gate #include "auth.h" 58*0Sstevel@tonic-gate #include "session.h" 59*0Sstevel@tonic-gate #include "dispatch.h" 60*0Sstevel@tonic-gate #include "auth-options.h" 61*0Sstevel@tonic-gate #include "serverloop.h" 62*0Sstevel@tonic-gate #include "misc.h" 63*0Sstevel@tonic-gate #include "kex.h" 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 66*0Sstevel@tonic-gate #include "altprivsep.h" 67*0Sstevel@tonic-gate #endif /* ALTPRIVSEP*/ 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate extern ServerOptions options; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* XXX */ 72*0Sstevel@tonic-gate extern Kex *xxx_kex; 73*0Sstevel@tonic-gate static Authctxt *xxx_authctxt; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate static Buffer stdin_buffer; /* Buffer for stdin data. */ 76*0Sstevel@tonic-gate static Buffer stdout_buffer; /* Buffer for stdout data. */ 77*0Sstevel@tonic-gate static Buffer stderr_buffer; /* Buffer for stderr data. */ 78*0Sstevel@tonic-gate static int fdin; /* Descriptor for stdin (for writing) */ 79*0Sstevel@tonic-gate static int fdout; /* Descriptor for stdout (for reading); 80*0Sstevel@tonic-gate May be same number as fdin. */ 81*0Sstevel@tonic-gate static int fderr; /* Descriptor for stderr. May be -1. */ 82*0Sstevel@tonic-gate static long stdin_bytes = 0; /* Number of bytes written to stdin. */ 83*0Sstevel@tonic-gate static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ 84*0Sstevel@tonic-gate static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ 85*0Sstevel@tonic-gate static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ 86*0Sstevel@tonic-gate static int stdin_eof = 0; /* EOF message received from client. */ 87*0Sstevel@tonic-gate static int fdout_eof = 0; /* EOF encountered reading from fdout. */ 88*0Sstevel@tonic-gate static int fderr_eof = 0; /* EOF encountered readung from fderr. */ 89*0Sstevel@tonic-gate static int fdin_is_tty = 0; /* fdin points to a tty. */ 90*0Sstevel@tonic-gate static int connection_in; /* Connection to client (input). */ 91*0Sstevel@tonic-gate static int connection_out; /* Connection to client (output). */ 92*0Sstevel@tonic-gate static int connection_closed = 0; /* Connection to client closed. */ 93*0Sstevel@tonic-gate static u_int buffer_high; /* "Soft" max buffer size. */ 94*0Sstevel@tonic-gate static int client_alive_timeouts = 0; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * This SIGCHLD kludge is used to detect when the child exits. The server 98*0Sstevel@tonic-gate * will exit after that, as soon as forwarded connections have terminated. 99*0Sstevel@tonic-gate */ 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */ 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* prototypes */ 104*0Sstevel@tonic-gate static void server_init_dispatch(void); 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* 107*0Sstevel@tonic-gate * we write to this pipe if a SIGCHLD is caught in order to avoid 108*0Sstevel@tonic-gate * the race between select() and child_terminated 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate static int notify_pipe[2]; 111*0Sstevel@tonic-gate static void 112*0Sstevel@tonic-gate notify_setup(void) 113*0Sstevel@tonic-gate { 114*0Sstevel@tonic-gate if (pipe(notify_pipe) < 0) { 115*0Sstevel@tonic-gate error("pipe(notify_pipe) failed %s", strerror(errno)); 116*0Sstevel@tonic-gate } else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) || 117*0Sstevel@tonic-gate (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) { 118*0Sstevel@tonic-gate error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno)); 119*0Sstevel@tonic-gate (void) close(notify_pipe[0]); 120*0Sstevel@tonic-gate (void) close(notify_pipe[1]); 121*0Sstevel@tonic-gate } else { 122*0Sstevel@tonic-gate set_nonblock(notify_pipe[0]); 123*0Sstevel@tonic-gate set_nonblock(notify_pipe[1]); 124*0Sstevel@tonic-gate return; 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate notify_pipe[0] = -1; /* read end */ 127*0Sstevel@tonic-gate notify_pipe[1] = -1; /* write end */ 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate static void 130*0Sstevel@tonic-gate notify_parent(void) 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate if (notify_pipe[1] != -1) 133*0Sstevel@tonic-gate (void) write(notify_pipe[1], "", 1); 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate static void 136*0Sstevel@tonic-gate notify_prepare(fd_set *readset) 137*0Sstevel@tonic-gate { 138*0Sstevel@tonic-gate if (notify_pipe[0] != -1) 139*0Sstevel@tonic-gate FD_SET(notify_pipe[0], readset); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate static void 142*0Sstevel@tonic-gate notify_done(fd_set *readset) 143*0Sstevel@tonic-gate { 144*0Sstevel@tonic-gate char c; 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) 147*0Sstevel@tonic-gate while (read(notify_pipe[0], &c, 1) != -1) 148*0Sstevel@tonic-gate debug2("notify_done: reading"); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate static void 152*0Sstevel@tonic-gate sigchld_handler(int sig) 153*0Sstevel@tonic-gate { 154*0Sstevel@tonic-gate int save_errno = errno; 155*0Sstevel@tonic-gate debug("Received SIGCHLD."); 156*0Sstevel@tonic-gate child_terminated = 1; 157*0Sstevel@tonic-gate #ifndef _UNICOS 158*0Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 159*0Sstevel@tonic-gate #endif 160*0Sstevel@tonic-gate notify_parent(); 161*0Sstevel@tonic-gate errno = save_errno; 162*0Sstevel@tonic-gate } 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * Make packets from buffered stderr data, and buffer it for sending 166*0Sstevel@tonic-gate * to the client. 167*0Sstevel@tonic-gate */ 168*0Sstevel@tonic-gate static void 169*0Sstevel@tonic-gate make_packets_from_stderr_data(void) 170*0Sstevel@tonic-gate { 171*0Sstevel@tonic-gate int len; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* Send buffered stderr data to the client. */ 174*0Sstevel@tonic-gate while (buffer_len(&stderr_buffer) > 0 && 175*0Sstevel@tonic-gate packet_not_very_much_data_to_write()) { 176*0Sstevel@tonic-gate len = buffer_len(&stderr_buffer); 177*0Sstevel@tonic-gate if (packet_is_interactive()) { 178*0Sstevel@tonic-gate if (len > 512) 179*0Sstevel@tonic-gate len = 512; 180*0Sstevel@tonic-gate } else { 181*0Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 182*0Sstevel@tonic-gate if (len > packet_get_maxsize()) 183*0Sstevel@tonic-gate len = packet_get_maxsize(); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate packet_start(SSH_SMSG_STDERR_DATA); 186*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&stderr_buffer), len); 187*0Sstevel@tonic-gate packet_send(); 188*0Sstevel@tonic-gate buffer_consume(&stderr_buffer, len); 189*0Sstevel@tonic-gate stderr_bytes += len; 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* 194*0Sstevel@tonic-gate * Make packets from buffered stdout data, and buffer it for sending to the 195*0Sstevel@tonic-gate * client. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate static void 198*0Sstevel@tonic-gate make_packets_from_stdout_data(void) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate int len; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* Send buffered stdout data to the client. */ 203*0Sstevel@tonic-gate while (buffer_len(&stdout_buffer) > 0 && 204*0Sstevel@tonic-gate packet_not_very_much_data_to_write()) { 205*0Sstevel@tonic-gate len = buffer_len(&stdout_buffer); 206*0Sstevel@tonic-gate if (packet_is_interactive()) { 207*0Sstevel@tonic-gate if (len > 512) 208*0Sstevel@tonic-gate len = 512; 209*0Sstevel@tonic-gate } else { 210*0Sstevel@tonic-gate /* Keep the packets at reasonable size. */ 211*0Sstevel@tonic-gate if (len > packet_get_maxsize()) 212*0Sstevel@tonic-gate len = packet_get_maxsize(); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate packet_start(SSH_SMSG_STDOUT_DATA); 215*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&stdout_buffer), len); 216*0Sstevel@tonic-gate packet_send(); 217*0Sstevel@tonic-gate buffer_consume(&stdout_buffer, len); 218*0Sstevel@tonic-gate stdout_bytes += len; 219*0Sstevel@tonic-gate } 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate static void 223*0Sstevel@tonic-gate client_alive_check(void) 224*0Sstevel@tonic-gate { 225*0Sstevel@tonic-gate static int had_channel = 0; 226*0Sstevel@tonic-gate int id; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate id = channel_find_open(); 229*0Sstevel@tonic-gate if (id == -1) { 230*0Sstevel@tonic-gate if (!had_channel) 231*0Sstevel@tonic-gate return; 232*0Sstevel@tonic-gate packet_disconnect("No open channels after timeout!"); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate had_channel = 1; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* timeout, check to see how many we have had */ 237*0Sstevel@tonic-gate if (++client_alive_timeouts > options.client_alive_count_max) 238*0Sstevel@tonic-gate packet_disconnect("Timeout, your session not responding."); 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * send a bogus channel request with "wantreply", 242*0Sstevel@tonic-gate * we should get back a failure 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate channel_request_start(id, "keepalive@openssh.com", 1); 245*0Sstevel@tonic-gate packet_send(); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * Sleep in select() until we can do something. This will initialize the 250*0Sstevel@tonic-gate * select masks. Upon return, the masks will indicate which descriptors 251*0Sstevel@tonic-gate * have data or can accept data. Optionally, a maximum time can be specified 252*0Sstevel@tonic-gate * for the duration of the wait (0 = infinite). 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate static void 255*0Sstevel@tonic-gate wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 256*0Sstevel@tonic-gate int *nallocp, u_int max_time_milliseconds) 257*0Sstevel@tonic-gate { 258*0Sstevel@tonic-gate struct timeval tv, *tvp; 259*0Sstevel@tonic-gate int ret; 260*0Sstevel@tonic-gate int client_alive_scheduled = 0; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * if using client_alive, set the max timeout accordingly, 264*0Sstevel@tonic-gate * and indicate that this particular timeout was for client 265*0Sstevel@tonic-gate * alive by setting the client_alive_scheduled flag. 266*0Sstevel@tonic-gate * 267*0Sstevel@tonic-gate * this could be randomized somewhat to make traffic 268*0Sstevel@tonic-gate * analysis more difficult, but we're not doing it yet. 269*0Sstevel@tonic-gate */ 270*0Sstevel@tonic-gate if (compat20 && 271*0Sstevel@tonic-gate max_time_milliseconds == 0 && options.client_alive_interval) { 272*0Sstevel@tonic-gate client_alive_scheduled = 1; 273*0Sstevel@tonic-gate max_time_milliseconds = options.client_alive_interval * 1000; 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* Allocate and update select() masks for channel descriptors. */ 277*0Sstevel@tonic-gate channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (compat20) { 280*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 281*0Sstevel@tonic-gate int pipe_fd; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if ((pipe_fd = altprivsep_get_pipe_fd()) != -1) { 284*0Sstevel@tonic-gate *maxfdp = MAX(*maxfdp, pipe_fd); 285*0Sstevel@tonic-gate FD_SET(altprivsep_get_pipe_fd(), *readsetp); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 288*0Sstevel@tonic-gate #if 0 289*0Sstevel@tonic-gate /* wrong: bad condition XXX */ 290*0Sstevel@tonic-gate if (channel_not_very_much_buffered_data()) 291*0Sstevel@tonic-gate #endif 292*0Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 293*0Sstevel@tonic-gate } else { 294*0Sstevel@tonic-gate /* 295*0Sstevel@tonic-gate * Read packets from the client unless we have too much 296*0Sstevel@tonic-gate * buffered stdin or channel data. 297*0Sstevel@tonic-gate */ 298*0Sstevel@tonic-gate if (buffer_len(&stdin_buffer) < buffer_high && 299*0Sstevel@tonic-gate channel_not_very_much_buffered_data()) 300*0Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 301*0Sstevel@tonic-gate /* 302*0Sstevel@tonic-gate * If there is not too much data already buffered going to 303*0Sstevel@tonic-gate * the client, try to get some more data from the program. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate if (packet_not_very_much_data_to_write()) { 306*0Sstevel@tonic-gate if (!fdout_eof) 307*0Sstevel@tonic-gate FD_SET(fdout, *readsetp); 308*0Sstevel@tonic-gate if (!fderr_eof) 309*0Sstevel@tonic-gate FD_SET(fderr, *readsetp); 310*0Sstevel@tonic-gate } 311*0Sstevel@tonic-gate /* 312*0Sstevel@tonic-gate * If we have buffered data, try to write some of that data 313*0Sstevel@tonic-gate * to the program. 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate if (fdin != -1 && buffer_len(&stdin_buffer) > 0) 316*0Sstevel@tonic-gate FD_SET(fdin, *writesetp); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate notify_prepare(*readsetp); 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * If we have buffered packet data going to the client, mark that 322*0Sstevel@tonic-gate * descriptor. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate if (packet_have_data_to_write()) 325*0Sstevel@tonic-gate FD_SET(connection_out, *writesetp); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * If child has terminated and there is enough buffer space to read 329*0Sstevel@tonic-gate * from it, then read as much as is available and exit. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate if (child_terminated && packet_not_very_much_data_to_write()) 332*0Sstevel@tonic-gate if (max_time_milliseconds == 0 || client_alive_scheduled) 333*0Sstevel@tonic-gate max_time_milliseconds = 100; 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate if (max_time_milliseconds == 0) 336*0Sstevel@tonic-gate tvp = NULL; 337*0Sstevel@tonic-gate else { 338*0Sstevel@tonic-gate tv.tv_sec = max_time_milliseconds / 1000; 339*0Sstevel@tonic-gate tv.tv_usec = 1000 * (max_time_milliseconds % 1000); 340*0Sstevel@tonic-gate tvp = &tv; 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* Wait for something to happen, or the timeout to expire. */ 344*0Sstevel@tonic-gate ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate if (ret == -1) { 347*0Sstevel@tonic-gate memset(*readsetp, 0, *nallocp); 348*0Sstevel@tonic-gate memset(*writesetp, 0, *nallocp); 349*0Sstevel@tonic-gate if (errno != EINTR) 350*0Sstevel@tonic-gate error("select: %.100s", strerror(errno)); 351*0Sstevel@tonic-gate } else if (ret == 0 && client_alive_scheduled) 352*0Sstevel@tonic-gate client_alive_check(); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate notify_done(*readsetp); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate /* 358*0Sstevel@tonic-gate * Processes input from the client and the program. Input data is stored 359*0Sstevel@tonic-gate * in buffers and processed later. 360*0Sstevel@tonic-gate */ 361*0Sstevel@tonic-gate static void 362*0Sstevel@tonic-gate process_input(fd_set * readset) 363*0Sstevel@tonic-gate { 364*0Sstevel@tonic-gate int len; 365*0Sstevel@tonic-gate char buf[16384]; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /* Read and buffer any input data from the client. */ 368*0Sstevel@tonic-gate if (FD_ISSET(connection_in, readset)) { 369*0Sstevel@tonic-gate len = read(connection_in, buf, sizeof(buf)); 370*0Sstevel@tonic-gate if (len == 0) { 371*0Sstevel@tonic-gate verbose("Connection closed by %.100s", 372*0Sstevel@tonic-gate get_remote_ipaddr()); 373*0Sstevel@tonic-gate connection_closed = 1; 374*0Sstevel@tonic-gate if (compat20) 375*0Sstevel@tonic-gate return; 376*0Sstevel@tonic-gate fatal_cleanup(); 377*0Sstevel@tonic-gate } else if (len < 0) { 378*0Sstevel@tonic-gate if (errno != EINTR && errno != EAGAIN) { 379*0Sstevel@tonic-gate verbose("Read error from remote host " 380*0Sstevel@tonic-gate "%.100s: %.100s", 381*0Sstevel@tonic-gate get_remote_ipaddr(), strerror(errno)); 382*0Sstevel@tonic-gate fatal_cleanup(); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate } else { 385*0Sstevel@tonic-gate /* Buffer any received data. */ 386*0Sstevel@tonic-gate packet_process_incoming(buf, len); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate if (compat20) 390*0Sstevel@tonic-gate return; 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate /* Read and buffer any available stdout data from the program. */ 393*0Sstevel@tonic-gate if (!fdout_eof && FD_ISSET(fdout, readset)) { 394*0Sstevel@tonic-gate len = read(fdout, buf, sizeof(buf)); 395*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 396*0Sstevel@tonic-gate /* EMPTY */ 397*0Sstevel@tonic-gate } else if (len <= 0) { 398*0Sstevel@tonic-gate fdout_eof = 1; 399*0Sstevel@tonic-gate } else { 400*0Sstevel@tonic-gate buffer_append(&stdout_buffer, buf, len); 401*0Sstevel@tonic-gate fdout_bytes += len; 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate /* Read and buffer any available stderr data from the program. */ 405*0Sstevel@tonic-gate if (!fderr_eof && FD_ISSET(fderr, readset)) { 406*0Sstevel@tonic-gate len = read(fderr, buf, sizeof(buf)); 407*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 408*0Sstevel@tonic-gate /* EMPTY */ 409*0Sstevel@tonic-gate } else if (len <= 0) { 410*0Sstevel@tonic-gate fderr_eof = 1; 411*0Sstevel@tonic-gate } else { 412*0Sstevel@tonic-gate buffer_append(&stderr_buffer, buf, len); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * Sends data from internal buffers to client program stdin. 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate static void 421*0Sstevel@tonic-gate process_output(fd_set * writeset) 422*0Sstevel@tonic-gate { 423*0Sstevel@tonic-gate struct termios tio; 424*0Sstevel@tonic-gate u_char *data; 425*0Sstevel@tonic-gate u_int dlen; 426*0Sstevel@tonic-gate int len; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* Write buffered data to program stdin. */ 429*0Sstevel@tonic-gate if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { 430*0Sstevel@tonic-gate data = buffer_ptr(&stdin_buffer); 431*0Sstevel@tonic-gate dlen = buffer_len(&stdin_buffer); 432*0Sstevel@tonic-gate len = write(fdin, data, dlen); 433*0Sstevel@tonic-gate if (len < 0 && (errno == EINTR || errno == EAGAIN)) { 434*0Sstevel@tonic-gate /* EMPTY */ 435*0Sstevel@tonic-gate } else if (len <= 0) { 436*0Sstevel@tonic-gate if (fdin != fdout) 437*0Sstevel@tonic-gate (void) close(fdin); 438*0Sstevel@tonic-gate else 439*0Sstevel@tonic-gate (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */ 440*0Sstevel@tonic-gate fdin = -1; 441*0Sstevel@tonic-gate } else { 442*0Sstevel@tonic-gate /* Successful write. */ 443*0Sstevel@tonic-gate if (fdin_is_tty && dlen >= 1 && data[0] != '\r' && 444*0Sstevel@tonic-gate tcgetattr(fdin, &tio) == 0 && 445*0Sstevel@tonic-gate !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * Simulate echo to reduce the impact of 448*0Sstevel@tonic-gate * traffic analysis 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate packet_send_ignore(len); 451*0Sstevel@tonic-gate packet_send(); 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate /* Consume the data from the buffer. */ 454*0Sstevel@tonic-gate buffer_consume(&stdin_buffer, len); 455*0Sstevel@tonic-gate /* Update the count of bytes written to the program. */ 456*0Sstevel@tonic-gate stdin_bytes += len; 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate /* Send any buffered packet data to the client. */ 460*0Sstevel@tonic-gate if (FD_ISSET(connection_out, writeset)) 461*0Sstevel@tonic-gate packet_write_poll(); 462*0Sstevel@tonic-gate } 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * Wait until all buffered output has been sent to the client. 466*0Sstevel@tonic-gate * This is used when the program terminates. 467*0Sstevel@tonic-gate */ 468*0Sstevel@tonic-gate static void 469*0Sstevel@tonic-gate drain_output(void) 470*0Sstevel@tonic-gate { 471*0Sstevel@tonic-gate /* Send any buffered stdout data to the client. */ 472*0Sstevel@tonic-gate if (buffer_len(&stdout_buffer) > 0) { 473*0Sstevel@tonic-gate packet_start(SSH_SMSG_STDOUT_DATA); 474*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&stdout_buffer), 475*0Sstevel@tonic-gate buffer_len(&stdout_buffer)); 476*0Sstevel@tonic-gate packet_send(); 477*0Sstevel@tonic-gate /* Update the count of sent bytes. */ 478*0Sstevel@tonic-gate stdout_bytes += buffer_len(&stdout_buffer); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate /* Send any buffered stderr data to the client. */ 481*0Sstevel@tonic-gate if (buffer_len(&stderr_buffer) > 0) { 482*0Sstevel@tonic-gate packet_start(SSH_SMSG_STDERR_DATA); 483*0Sstevel@tonic-gate packet_put_string(buffer_ptr(&stderr_buffer), 484*0Sstevel@tonic-gate buffer_len(&stderr_buffer)); 485*0Sstevel@tonic-gate packet_send(); 486*0Sstevel@tonic-gate /* Update the count of sent bytes. */ 487*0Sstevel@tonic-gate stderr_bytes += buffer_len(&stderr_buffer); 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate /* Wait until all buffered data has been written to the client. */ 490*0Sstevel@tonic-gate packet_write_wait(); 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate static void 494*0Sstevel@tonic-gate process_buffered_input_packets(void) 495*0Sstevel@tonic-gate { 496*0Sstevel@tonic-gate dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * Performs the interactive session. This handles data transmission between 501*0Sstevel@tonic-gate * the client and the program. Note that the notion of stdin, stdout, and 502*0Sstevel@tonic-gate * stderr in this function is sort of reversed: this function writes to 503*0Sstevel@tonic-gate * stdin (of the child program), and reads from stdout and stderr (of the 504*0Sstevel@tonic-gate * child program). 505*0Sstevel@tonic-gate */ 506*0Sstevel@tonic-gate void 507*0Sstevel@tonic-gate server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) 508*0Sstevel@tonic-gate { 509*0Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 510*0Sstevel@tonic-gate int max_fd = 0, nalloc = 0; 511*0Sstevel@tonic-gate int wait_status; /* Status returned by wait(). */ 512*0Sstevel@tonic-gate pid_t wait_pid; /* pid returned by wait(). */ 513*0Sstevel@tonic-gate int waiting_termination = 0; /* Have displayed waiting close message. */ 514*0Sstevel@tonic-gate u_int max_time_milliseconds; 515*0Sstevel@tonic-gate u_int previous_stdout_buffer_bytes; 516*0Sstevel@tonic-gate u_int stdout_buffer_bytes; 517*0Sstevel@tonic-gate int type; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate debug("Entering interactive session."); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* Initialize the SIGCHLD kludge. */ 522*0Sstevel@tonic-gate child_terminated = 0; 523*0Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate /* Initialize our global variables. */ 526*0Sstevel@tonic-gate fdin = fdin_arg; 527*0Sstevel@tonic-gate fdout = fdout_arg; 528*0Sstevel@tonic-gate fderr = fderr_arg; 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate /* nonblocking IO */ 531*0Sstevel@tonic-gate set_nonblock(fdin); 532*0Sstevel@tonic-gate set_nonblock(fdout); 533*0Sstevel@tonic-gate /* we don't have stderr for interactive terminal sessions, see below */ 534*0Sstevel@tonic-gate if (fderr != -1) 535*0Sstevel@tonic-gate set_nonblock(fderr); 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) 538*0Sstevel@tonic-gate fdin_is_tty = 1; 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate connection_in = packet_get_connection_in(); 541*0Sstevel@tonic-gate connection_out = packet_get_connection_out(); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate notify_setup(); 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate previous_stdout_buffer_bytes = 0; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate /* Set approximate I/O buffer size. */ 548*0Sstevel@tonic-gate if (packet_is_interactive()) 549*0Sstevel@tonic-gate buffer_high = 4096; 550*0Sstevel@tonic-gate else 551*0Sstevel@tonic-gate buffer_high = 64 * 1024; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate #if 0 554*0Sstevel@tonic-gate /* Initialize max_fd to the maximum of the known file descriptors. */ 555*0Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 556*0Sstevel@tonic-gate max_fd = MAX(max_fd, fdin); 557*0Sstevel@tonic-gate max_fd = MAX(max_fd, fdout); 558*0Sstevel@tonic-gate if (fderr != -1) 559*0Sstevel@tonic-gate max_fd = MAX(max_fd, fderr); 560*0Sstevel@tonic-gate #endif 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate /* Initialize Initialize buffers. */ 563*0Sstevel@tonic-gate buffer_init(&stdin_buffer); 564*0Sstevel@tonic-gate buffer_init(&stdout_buffer); 565*0Sstevel@tonic-gate buffer_init(&stderr_buffer); 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * If we have no separate fderr (which is the case when we have a pty 569*0Sstevel@tonic-gate * - there we cannot make difference between data sent to stdout and 570*0Sstevel@tonic-gate * stderr), indicate that we have seen an EOF from stderr. This way 571*0Sstevel@tonic-gate * we don\'t need to check the descriptor everywhere. 572*0Sstevel@tonic-gate */ 573*0Sstevel@tonic-gate if (fderr == -1) 574*0Sstevel@tonic-gate fderr_eof = 1; 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate server_init_dispatch(); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* Main loop of the server for the interactive session mode. */ 579*0Sstevel@tonic-gate for (;;) { 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* Process buffered packets from the client. */ 582*0Sstevel@tonic-gate process_buffered_input_packets(); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * If we have received eof, and there is no more pending 586*0Sstevel@tonic-gate * input data, cause a real eof by closing fdin. 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { 589*0Sstevel@tonic-gate if (fdin != fdout) 590*0Sstevel@tonic-gate (void) close(fdin); 591*0Sstevel@tonic-gate else 592*0Sstevel@tonic-gate (void) shutdown(fdin, SHUT_WR); /* We will no longer send. */ 593*0Sstevel@tonic-gate fdin = -1; 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate /* Make packets from buffered stderr data to send to the client. */ 596*0Sstevel@tonic-gate make_packets_from_stderr_data(); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * Make packets from buffered stdout data to send to the 600*0Sstevel@tonic-gate * client. If there is very little to send, this arranges to 601*0Sstevel@tonic-gate * not send them now, but to wait a short while to see if we 602*0Sstevel@tonic-gate * are getting more data. This is necessary, as some systems 603*0Sstevel@tonic-gate * wake up readers from a pty after each separate character. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate max_time_milliseconds = 0; 606*0Sstevel@tonic-gate stdout_buffer_bytes = buffer_len(&stdout_buffer); 607*0Sstevel@tonic-gate if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && 608*0Sstevel@tonic-gate stdout_buffer_bytes != previous_stdout_buffer_bytes) { 609*0Sstevel@tonic-gate /* try again after a while */ 610*0Sstevel@tonic-gate max_time_milliseconds = 10; 611*0Sstevel@tonic-gate } else { 612*0Sstevel@tonic-gate /* Send it now. */ 613*0Sstevel@tonic-gate make_packets_from_stdout_data(); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate /* Send channel data to the client. */ 618*0Sstevel@tonic-gate if (packet_not_very_much_data_to_write()) 619*0Sstevel@tonic-gate channel_output_poll(); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* 622*0Sstevel@tonic-gate * Bail out of the loop if the program has closed its output 623*0Sstevel@tonic-gate * descriptors, and we have no more data to send to the 624*0Sstevel@tonic-gate * client, and there is no pending buffered data. 625*0Sstevel@tonic-gate */ 626*0Sstevel@tonic-gate if (fdout_eof && fderr_eof && !packet_have_data_to_write() && 627*0Sstevel@tonic-gate buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { 628*0Sstevel@tonic-gate if (!channel_still_open()) 629*0Sstevel@tonic-gate break; 630*0Sstevel@tonic-gate if (!waiting_termination) { 631*0Sstevel@tonic-gate const char *s = "Waiting for forwarded connections to terminate...\r\n"; 632*0Sstevel@tonic-gate char *cp; 633*0Sstevel@tonic-gate waiting_termination = 1; 634*0Sstevel@tonic-gate buffer_append(&stderr_buffer, s, strlen(s)); 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate /* Display list of open channels. */ 637*0Sstevel@tonic-gate cp = channel_open_message(); 638*0Sstevel@tonic-gate buffer_append(&stderr_buffer, cp, strlen(cp)); 639*0Sstevel@tonic-gate xfree(cp); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 643*0Sstevel@tonic-gate max_fd = MAX(max_fd, fdin); 644*0Sstevel@tonic-gate max_fd = MAX(max_fd, fdout); 645*0Sstevel@tonic-gate max_fd = MAX(max_fd, fderr); 646*0Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* Sleep in select() until we can do something. */ 649*0Sstevel@tonic-gate wait_until_can_do_something(&readset, &writeset, &max_fd, 650*0Sstevel@tonic-gate &nalloc, max_time_milliseconds); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate /* Process any channel events. */ 653*0Sstevel@tonic-gate channel_after_select(readset, writeset); 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* Process input from the client and from program stdout/stderr. */ 656*0Sstevel@tonic-gate process_input(readset); 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* Process output to the client and to program stdin. */ 659*0Sstevel@tonic-gate process_output(writeset); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate if (readset) 662*0Sstevel@tonic-gate xfree(readset); 663*0Sstevel@tonic-gate if (writeset) 664*0Sstevel@tonic-gate xfree(writeset); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate /* Cleanup and termination code. */ 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate /* Wait until all output has been sent to the client. */ 669*0Sstevel@tonic-gate drain_output(); 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", 672*0Sstevel@tonic-gate stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate /* Free and clear the buffers. */ 675*0Sstevel@tonic-gate buffer_free(&stdin_buffer); 676*0Sstevel@tonic-gate buffer_free(&stdout_buffer); 677*0Sstevel@tonic-gate buffer_free(&stderr_buffer); 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate /* Close the file descriptors. */ 680*0Sstevel@tonic-gate if (fdout != -1) 681*0Sstevel@tonic-gate (void) close(fdout); 682*0Sstevel@tonic-gate fdout = -1; 683*0Sstevel@tonic-gate fdout_eof = 1; 684*0Sstevel@tonic-gate if (fderr != -1) 685*0Sstevel@tonic-gate (void) close(fderr); 686*0Sstevel@tonic-gate fderr = -1; 687*0Sstevel@tonic-gate fderr_eof = 1; 688*0Sstevel@tonic-gate if (fdin != -1) 689*0Sstevel@tonic-gate (void) close(fdin); 690*0Sstevel@tonic-gate fdin = -1; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate channel_free_all(); 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate /* We no longer want our SIGCHLD handler to be called. */ 695*0Sstevel@tonic-gate mysignal(SIGCHLD, SIG_DFL); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) 698*0Sstevel@tonic-gate if (errno != EINTR) 699*0Sstevel@tonic-gate packet_disconnect("wait: %.100s", strerror(errno)); 700*0Sstevel@tonic-gate if (wait_pid != pid) 701*0Sstevel@tonic-gate error("Strange, wait returned pid %ld, expected %ld", 702*0Sstevel@tonic-gate (long)wait_pid, (long)pid); 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate /* Check if it exited normally. */ 705*0Sstevel@tonic-gate if (WIFEXITED(wait_status)) { 706*0Sstevel@tonic-gate /* Yes, normal exit. Get exit status and send it to the client. */ 707*0Sstevel@tonic-gate debug("Command exited with status %d.", WEXITSTATUS(wait_status)); 708*0Sstevel@tonic-gate packet_start(SSH_SMSG_EXITSTATUS); 709*0Sstevel@tonic-gate packet_put_int(WEXITSTATUS(wait_status)); 710*0Sstevel@tonic-gate packet_send(); 711*0Sstevel@tonic-gate packet_write_wait(); 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate /* 714*0Sstevel@tonic-gate * Wait for exit confirmation. Note that there might be 715*0Sstevel@tonic-gate * other packets coming before it; however, the program has 716*0Sstevel@tonic-gate * already died so we just ignore them. The client is 717*0Sstevel@tonic-gate * supposed to respond with the confirmation when it receives 718*0Sstevel@tonic-gate * the exit status. 719*0Sstevel@tonic-gate */ 720*0Sstevel@tonic-gate do { 721*0Sstevel@tonic-gate type = packet_read(); 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate while (type != SSH_CMSG_EXIT_CONFIRMATION); 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate debug("Received exit confirmation."); 726*0Sstevel@tonic-gate return; 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate /* Check if the program terminated due to a signal. */ 729*0Sstevel@tonic-gate if (WIFSIGNALED(wait_status)) 730*0Sstevel@tonic-gate packet_disconnect("Command terminated on signal %d.", 731*0Sstevel@tonic-gate WTERMSIG(wait_status)); 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate /* Some weird exit cause. Just exit. */ 734*0Sstevel@tonic-gate packet_disconnect("wait returned status %04x.", wait_status); 735*0Sstevel@tonic-gate /* NOTREACHED */ 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate static void 739*0Sstevel@tonic-gate collect_children(void) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate pid_t pid; 742*0Sstevel@tonic-gate sigset_t oset, nset; 743*0Sstevel@tonic-gate int status; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* block SIGCHLD while we check for dead children */ 746*0Sstevel@tonic-gate (void) sigemptyset(&nset); 747*0Sstevel@tonic-gate (void) sigaddset(&nset, SIGCHLD); 748*0Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 749*0Sstevel@tonic-gate if (child_terminated) { 750*0Sstevel@tonic-gate while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 751*0Sstevel@tonic-gate (pid < 0 && errno == EINTR)) 752*0Sstevel@tonic-gate if (pid > 0) 753*0Sstevel@tonic-gate session_close_by_pid(pid, status); 754*0Sstevel@tonic-gate child_terminated = 0; 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 760*0Sstevel@tonic-gate /* 761*0Sstevel@tonic-gate * For ALTPRIVSEP the wait_until_can_do_something function is very 762*0Sstevel@tonic-gate * simple: select() on the read side of the pipe, and if there's packets 763*0Sstevel@tonic-gate * to send, on the write side, and on the read side of the SIGCHLD 764*0Sstevel@tonic-gate * handler pipe. That's it. 765*0Sstevel@tonic-gate */ 766*0Sstevel@tonic-gate static void 767*0Sstevel@tonic-gate aps_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, 768*0Sstevel@tonic-gate int *maxfdp, int *nallocp, u_int max_time_milliseconds) 769*0Sstevel@tonic-gate { 770*0Sstevel@tonic-gate int ret; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate /* 773*0Sstevel@tonic-gate * Use channel_prepare_select() to make the fd sets. 774*0Sstevel@tonic-gate * 775*0Sstevel@tonic-gate * This is cheating, really, since because the last argument in 776*0Sstevel@tonic-gate * this call is '1' nothing related to channels will be done -- 777*0Sstevel@tonic-gate * we're using this function only to callocate the fd sets. 778*0Sstevel@tonic-gate */ 779*0Sstevel@tonic-gate channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 1); 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate if ((connection_in = packet_get_connection_in()) >= 0 && 782*0Sstevel@tonic-gate !connection_closed) 783*0Sstevel@tonic-gate FD_SET(connection_in, *readsetp); 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate notify_prepare(*readsetp); 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate if ((connection_out = packet_get_connection_out()) >= 0 && 788*0Sstevel@tonic-gate packet_have_data_to_write() && !connection_closed) 789*0Sstevel@tonic-gate FD_SET(connection_out, *writesetp); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* Wait for something to happen, or the timeout to expire. */ 792*0Sstevel@tonic-gate ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate if (ret == -1) { 795*0Sstevel@tonic-gate memset(*readsetp, 0, *nallocp); 796*0Sstevel@tonic-gate memset(*writesetp, 0, *nallocp); 797*0Sstevel@tonic-gate if (errno != EINTR) 798*0Sstevel@tonic-gate error("select: %.100s", strerror(errno)); 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate notify_done(*readsetp); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate /* 805*0Sstevel@tonic-gate * Slightly different than collect_children, aps_collect_child() has 806*0Sstevel@tonic-gate * only the unprivileged sshd to wait for, no sessions, no channells, 807*0Sstevel@tonic-gate * just one process. 808*0Sstevel@tonic-gate */ 809*0Sstevel@tonic-gate static int 810*0Sstevel@tonic-gate aps_collect_child(pid_t child) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate pid_t pid; 813*0Sstevel@tonic-gate sigset_t oset, nset; 814*0Sstevel@tonic-gate int status; 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* block SIGCHLD while we check for dead children */ 817*0Sstevel@tonic-gate (void) sigemptyset(&nset); 818*0Sstevel@tonic-gate (void) sigaddset(&nset, SIGCHLD); 819*0Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 820*0Sstevel@tonic-gate if (child_terminated) { 821*0Sstevel@tonic-gate while ((pid = waitpid(child, &status, WNOHANG)) > 0 || 822*0Sstevel@tonic-gate (pid < 0 && errno == EINTR)) 823*0Sstevel@tonic-gate if (pid == child) { 824*0Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 825*0Sstevel@tonic-gate return (1); 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate child_terminated = 0; 828*0Sstevel@tonic-gate } 829*0Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &oset, NULL); 830*0Sstevel@tonic-gate return (0); 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate static int killed = 0; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate static void 836*0Sstevel@tonic-gate aps_monitor_kill_handler(int sig) 837*0Sstevel@tonic-gate { 838*0Sstevel@tonic-gate int save_errno = errno; 839*0Sstevel@tonic-gate killed = 1; 840*0Sstevel@tonic-gate notify_parent(); 841*0Sstevel@tonic-gate mysignal(sig, aps_monitor_kill_handler); 842*0Sstevel@tonic-gate errno = save_errno; 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate static void 846*0Sstevel@tonic-gate aps_monitor_sigchld_handler(int sig) 847*0Sstevel@tonic-gate { 848*0Sstevel@tonic-gate int save_errno = errno; 849*0Sstevel@tonic-gate debug("Monitor received SIGCHLD."); 850*0Sstevel@tonic-gate child_terminated = 1; 851*0Sstevel@tonic-gate mysignal(SIGCHLD, aps_monitor_sigchld_handler); 852*0Sstevel@tonic-gate notify_parent(); 853*0Sstevel@tonic-gate errno = save_errno; 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate void 857*0Sstevel@tonic-gate aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid) 858*0Sstevel@tonic-gate { 859*0Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 860*0Sstevel@tonic-gate int max_fd, nalloc = 0; 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate debug("Entering monitor loop."); 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate /* 865*0Sstevel@tonic-gate * Awful hack follows: fake compat20 == 1 to cause process_input() 866*0Sstevel@tonic-gate * and process_output() to behave as they would for SSHv2 because that's 867*0Sstevel@tonic-gate * the behaviour we need in SSHv2. 868*0Sstevel@tonic-gate * 869*0Sstevel@tonic-gate * This same hack is done in packet.c 870*0Sstevel@tonic-gate */ 871*0Sstevel@tonic-gate compat20 = 1; /* causes process_input/output() to ignore stdio */ 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate mysignal(SIGHUP, aps_monitor_kill_handler); 874*0Sstevel@tonic-gate mysignal(SIGINT, aps_monitor_kill_handler); 875*0Sstevel@tonic-gate mysignal(SIGTERM, aps_monitor_kill_handler); 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate child_terminated = 0; 878*0Sstevel@tonic-gate mysignal(SIGCHLD, aps_monitor_sigchld_handler); 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate packet_set_monitor(pipe); 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate connection_in = packet_get_connection_in(); 883*0Sstevel@tonic-gate connection_out = packet_get_connection_out(); 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate notify_setup(); 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 888*0Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 891*0Sstevel@tonic-gate dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_MAX, 892*0Sstevel@tonic-gate &dispatch_protocol_error); 893*0Sstevel@tonic-gate dispatch_set(SSH2_PRIV_MSG_ALTPRIVSEP, &aps_input_altpriv_msg); 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate for (;;) { 896*0Sstevel@tonic-gate process_buffered_input_packets(); 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate aps_wait_until_can_do_something(&readset, &writeset, &max_fd, 899*0Sstevel@tonic-gate &nalloc, 0); 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate if (aps_collect_child(child_pid)) 902*0Sstevel@tonic-gate break; 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate if (killed) { 905*0Sstevel@tonic-gate /* fatal cleanups will kill child, audit logout */ 906*0Sstevel@tonic-gate log("Monitor killed; exiting"); 907*0Sstevel@tonic-gate fatal_cleanup(); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate /* 911*0Sstevel@tonic-gate * Unlike server_loop2() we don't care if connection_closed 912*0Sstevel@tonic-gate * since we still want to wait for the monitor's child. 913*0Sstevel@tonic-gate */ 914*0Sstevel@tonic-gate process_input(readset); 915*0Sstevel@tonic-gate process_output(writeset); 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate packet_close(); 919*0Sstevel@tonic-gate } 920*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate void 923*0Sstevel@tonic-gate server_loop2(Authctxt *authctxt) 924*0Sstevel@tonic-gate { 925*0Sstevel@tonic-gate fd_set *readset = NULL, *writeset = NULL; 926*0Sstevel@tonic-gate int rekeying = 0, max_fd, nalloc = 0; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate debug("Entering interactive session for SSH2."); 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate mysignal(SIGCHLD, sigchld_handler); 931*0Sstevel@tonic-gate child_terminated = 0; 932*0Sstevel@tonic-gate connection_in = packet_get_connection_in(); 933*0Sstevel@tonic-gate connection_out = packet_get_connection_out(); 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate notify_setup(); 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate max_fd = MAX(connection_in, connection_out); 938*0Sstevel@tonic-gate max_fd = MAX(max_fd, notify_pipe[0]); 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate xxx_authctxt = authctxt; 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate server_init_dispatch(); 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate for (;;) { 945*0Sstevel@tonic-gate process_buffered_input_packets(); 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate rekeying = (xxx_kex != NULL && !xxx_kex->done); 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate if (!rekeying && packet_not_very_much_data_to_write()) 950*0Sstevel@tonic-gate channel_output_poll(); 951*0Sstevel@tonic-gate wait_until_can_do_something(&readset, &writeset, &max_fd, 952*0Sstevel@tonic-gate &nalloc, 0); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate collect_children(); 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate if (!rekeying) 957*0Sstevel@tonic-gate channel_after_select(readset, writeset); 958*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 959*0Sstevel@tonic-gate else 960*0Sstevel@tonic-gate altprivsep_process_input(xxx_kex, readset); 961*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate process_input(readset); 964*0Sstevel@tonic-gate if (connection_closed) 965*0Sstevel@tonic-gate break; 966*0Sstevel@tonic-gate process_output(writeset); 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate collect_children(); 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate if (readset) 971*0Sstevel@tonic-gate xfree(readset); 972*0Sstevel@tonic-gate if (writeset) 973*0Sstevel@tonic-gate xfree(writeset); 974*0Sstevel@tonic-gate 975*0Sstevel@tonic-gate /* free all channels, no more reads and writes */ 976*0Sstevel@tonic-gate channel_free_all(); 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate /* free remaining sessions, e.g. remove wtmp entries */ 979*0Sstevel@tonic-gate session_destroy_all(NULL); 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate static void 983*0Sstevel@tonic-gate server_input_channel_failure(int type, u_int32_t seq, void *ctxt) 984*0Sstevel@tonic-gate { 985*0Sstevel@tonic-gate debug("Got CHANNEL_FAILURE for keepalive"); 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * reset timeout, since we got a sane answer from the client. 988*0Sstevel@tonic-gate * even if this was generated by something other than 989*0Sstevel@tonic-gate * the bogus CHANNEL_REQUEST we send for keepalives. 990*0Sstevel@tonic-gate */ 991*0Sstevel@tonic-gate client_alive_timeouts = 0; 992*0Sstevel@tonic-gate } 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate static void 996*0Sstevel@tonic-gate server_input_stdin_data(int type, u_int32_t seq, void *ctxt) 997*0Sstevel@tonic-gate { 998*0Sstevel@tonic-gate char *data; 999*0Sstevel@tonic-gate u_int data_len; 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate /* Stdin data from the client. Append it to the buffer. */ 1002*0Sstevel@tonic-gate /* Ignore any data if the client has closed stdin. */ 1003*0Sstevel@tonic-gate if (fdin == -1) 1004*0Sstevel@tonic-gate return; 1005*0Sstevel@tonic-gate data = packet_get_string(&data_len); 1006*0Sstevel@tonic-gate packet_check_eom(); 1007*0Sstevel@tonic-gate buffer_append(&stdin_buffer, data, data_len); 1008*0Sstevel@tonic-gate memset(data, 0, data_len); 1009*0Sstevel@tonic-gate xfree(data); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate static void 1013*0Sstevel@tonic-gate server_input_eof(int type, u_int32_t seq, void *ctxt) 1014*0Sstevel@tonic-gate { 1015*0Sstevel@tonic-gate /* 1016*0Sstevel@tonic-gate * Eof from the client. The stdin descriptor to the 1017*0Sstevel@tonic-gate * program will be closed when all buffered data has 1018*0Sstevel@tonic-gate * drained. 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate debug("EOF received for stdin."); 1021*0Sstevel@tonic-gate packet_check_eom(); 1022*0Sstevel@tonic-gate stdin_eof = 1; 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate static void 1026*0Sstevel@tonic-gate server_input_window_size(int type, u_int32_t seq, void *ctxt) 1027*0Sstevel@tonic-gate { 1028*0Sstevel@tonic-gate int row = packet_get_int(); 1029*0Sstevel@tonic-gate int col = packet_get_int(); 1030*0Sstevel@tonic-gate int xpixel = packet_get_int(); 1031*0Sstevel@tonic-gate int ypixel = packet_get_int(); 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate debug("Window change received."); 1034*0Sstevel@tonic-gate packet_check_eom(); 1035*0Sstevel@tonic-gate if (fdin != -1) 1036*0Sstevel@tonic-gate pty_change_window_size(fdin, row, col, xpixel, ypixel); 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate static Channel * 1040*0Sstevel@tonic-gate server_request_direct_tcpip(char *ctype) 1041*0Sstevel@tonic-gate { 1042*0Sstevel@tonic-gate Channel *c; 1043*0Sstevel@tonic-gate int sock; 1044*0Sstevel@tonic-gate char *target, *originator; 1045*0Sstevel@tonic-gate int target_port, originator_port; 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate target = packet_get_string(NULL); 1048*0Sstevel@tonic-gate target_port = packet_get_int(); 1049*0Sstevel@tonic-gate originator = packet_get_string(NULL); 1050*0Sstevel@tonic-gate originator_port = packet_get_int(); 1051*0Sstevel@tonic-gate packet_check_eom(); 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", 1054*0Sstevel@tonic-gate originator, originator_port, target, target_port); 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate /* XXX check permission */ 1057*0Sstevel@tonic-gate sock = channel_connect_to(target, target_port); 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate xfree(target); 1060*0Sstevel@tonic-gate xfree(originator); 1061*0Sstevel@tonic-gate if (sock < 0) 1062*0Sstevel@tonic-gate return NULL; 1063*0Sstevel@tonic-gate c = channel_new(ctype, SSH_CHANNEL_CONNECTING, 1064*0Sstevel@tonic-gate sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, 1065*0Sstevel@tonic-gate CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); 1066*0Sstevel@tonic-gate return c; 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate static Channel * 1070*0Sstevel@tonic-gate server_request_session(char *ctype) 1071*0Sstevel@tonic-gate { 1072*0Sstevel@tonic-gate Channel *c; 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate debug("input_session_request"); 1075*0Sstevel@tonic-gate packet_check_eom(); 1076*0Sstevel@tonic-gate /* 1077*0Sstevel@tonic-gate * A server session has no fd to read or write until a 1078*0Sstevel@tonic-gate * CHANNEL_REQUEST for a shell is made, so we set the type to 1079*0Sstevel@tonic-gate * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all 1080*0Sstevel@tonic-gate * CHANNEL_REQUEST messages is registered. 1081*0Sstevel@tonic-gate */ 1082*0Sstevel@tonic-gate c = channel_new(ctype, SSH_CHANNEL_LARVAL, 1083*0Sstevel@tonic-gate -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 1084*0Sstevel@tonic-gate 0, xstrdup("server-session"), 1); 1085*0Sstevel@tonic-gate if (session_open(xxx_authctxt, c->self) != 1) { 1086*0Sstevel@tonic-gate debug("session open failed, free channel %d", c->self); 1087*0Sstevel@tonic-gate channel_free(c); 1088*0Sstevel@tonic-gate return NULL; 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate channel_register_cleanup(c->self, session_close_by_channel); 1091*0Sstevel@tonic-gate return c; 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate static void 1095*0Sstevel@tonic-gate server_input_channel_open(int type, u_int32_t seq, void *ctxt) 1096*0Sstevel@tonic-gate { 1097*0Sstevel@tonic-gate Channel *c = NULL; 1098*0Sstevel@tonic-gate char *ctype; 1099*0Sstevel@tonic-gate int rchan; 1100*0Sstevel@tonic-gate u_int rmaxpack, rwindow, len; 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate ctype = packet_get_string(&len); 1103*0Sstevel@tonic-gate rchan = packet_get_int(); 1104*0Sstevel@tonic-gate rwindow = packet_get_int(); 1105*0Sstevel@tonic-gate rmaxpack = packet_get_int(); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate debug("server_input_channel_open: ctype %s rchan %d win %d max %d", 1108*0Sstevel@tonic-gate ctype, rchan, rwindow, rmaxpack); 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate if (strcmp(ctype, "session") == 0) { 1111*0Sstevel@tonic-gate c = server_request_session(ctype); 1112*0Sstevel@tonic-gate } else if (strcmp(ctype, "direct-tcpip") == 0) { 1113*0Sstevel@tonic-gate c = server_request_direct_tcpip(ctype); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate if (c != NULL) { 1116*0Sstevel@tonic-gate debug("server_input_channel_open: confirm %s", ctype); 1117*0Sstevel@tonic-gate c->remote_id = rchan; 1118*0Sstevel@tonic-gate c->remote_window = rwindow; 1119*0Sstevel@tonic-gate c->remote_maxpacket = rmaxpack; 1120*0Sstevel@tonic-gate if (c->type != SSH_CHANNEL_CONNECTING) { 1121*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 1122*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1123*0Sstevel@tonic-gate packet_put_int(c->self); 1124*0Sstevel@tonic-gate packet_put_int(c->local_window); 1125*0Sstevel@tonic-gate packet_put_int(c->local_maxpacket); 1126*0Sstevel@tonic-gate packet_send(); 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate } else { 1129*0Sstevel@tonic-gate debug("server_input_channel_open: failure %s", ctype); 1130*0Sstevel@tonic-gate packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 1131*0Sstevel@tonic-gate packet_put_int(rchan); 1132*0Sstevel@tonic-gate packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); 1133*0Sstevel@tonic-gate if (!(datafellows & SSH_BUG_OPENFAILURE)) { 1134*0Sstevel@tonic-gate packet_put_cstring("open failed"); 1135*0Sstevel@tonic-gate packet_put_cstring(""); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate packet_send(); 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate xfree(ctype); 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate static void 1143*0Sstevel@tonic-gate server_input_global_request(int type, u_int32_t seq, void *ctxt) 1144*0Sstevel@tonic-gate { 1145*0Sstevel@tonic-gate char *rtype; 1146*0Sstevel@tonic-gate int want_reply; 1147*0Sstevel@tonic-gate int success = 0; 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate rtype = packet_get_string(NULL); 1150*0Sstevel@tonic-gate want_reply = packet_get_char(); 1151*0Sstevel@tonic-gate debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply); 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate /* -R style forwarding */ 1154*0Sstevel@tonic-gate if (strcmp(rtype, "tcpip-forward") == 0) { 1155*0Sstevel@tonic-gate struct passwd *pw; 1156*0Sstevel@tonic-gate char *listen_address; 1157*0Sstevel@tonic-gate u_short listen_port; 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate pw = auth_get_user(); 1160*0Sstevel@tonic-gate if (pw == NULL) 1161*0Sstevel@tonic-gate fatal("server_input_global_request: no user"); 1162*0Sstevel@tonic-gate listen_address = packet_get_string(NULL); /* XXX currently ignored */ 1163*0Sstevel@tonic-gate listen_port = (u_short)packet_get_int(); 1164*0Sstevel@tonic-gate debug("server_input_global_request: tcpip-forward listen %s port %d", 1165*0Sstevel@tonic-gate listen_address, listen_port); 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate /* check permissions */ 1168*0Sstevel@tonic-gate if (!options.allow_tcp_forwarding || 1169*0Sstevel@tonic-gate no_port_forwarding_flag 1170*0Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT 1171*0Sstevel@tonic-gate || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) 1172*0Sstevel@tonic-gate #endif 1173*0Sstevel@tonic-gate ) { 1174*0Sstevel@tonic-gate success = 0; 1175*0Sstevel@tonic-gate packet_send_debug("Server has disabled port forwarding."); 1176*0Sstevel@tonic-gate } else { 1177*0Sstevel@tonic-gate /* Start listening on the port */ 1178*0Sstevel@tonic-gate success = channel_setup_remote_fwd_listener( 1179*0Sstevel@tonic-gate listen_address, listen_port, options.gateway_ports); 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate xfree(listen_address); 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate if (want_reply) { 1185*0Sstevel@tonic-gate packet_start(success ? 1186*0Sstevel@tonic-gate SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 1187*0Sstevel@tonic-gate packet_send(); 1188*0Sstevel@tonic-gate packet_write_wait(); 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate xfree(rtype); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate static void 1193*0Sstevel@tonic-gate server_input_channel_req(int type, u_int32_t seq, void *ctxt) 1194*0Sstevel@tonic-gate { 1195*0Sstevel@tonic-gate Channel *c; 1196*0Sstevel@tonic-gate int id, reply, success = 0; 1197*0Sstevel@tonic-gate char *rtype; 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate id = packet_get_int(); 1200*0Sstevel@tonic-gate rtype = packet_get_string(NULL); 1201*0Sstevel@tonic-gate reply = packet_get_char(); 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate debug("server_input_channel_req: channel %d request %s reply %d", 1204*0Sstevel@tonic-gate id, rtype, reply); 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate if ((c = channel_lookup(id)) == NULL) 1207*0Sstevel@tonic-gate packet_disconnect("server_input_channel_req: " 1208*0Sstevel@tonic-gate "unknown channel %d", id); 1209*0Sstevel@tonic-gate if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) 1210*0Sstevel@tonic-gate success = session_input_channel_req(c, rtype); 1211*0Sstevel@tonic-gate if (reply) { 1212*0Sstevel@tonic-gate packet_start(success ? 1213*0Sstevel@tonic-gate SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 1214*0Sstevel@tonic-gate packet_put_int(c->remote_id); 1215*0Sstevel@tonic-gate packet_send(); 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate xfree(rtype); 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate static void 1221*0Sstevel@tonic-gate server_init_dispatch_20(void) 1222*0Sstevel@tonic-gate { 1223*0Sstevel@tonic-gate debug("server_init_dispatch_20"); 1224*0Sstevel@tonic-gate dispatch_init(&dispatch_protocol_error); 1225*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); 1226*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); 1227*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); 1228*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); 1229*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open); 1230*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 1231*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 1232*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); 1233*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); 1234*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); 1235*0Sstevel@tonic-gate /* client_alive */ 1236*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure); 1237*0Sstevel@tonic-gate /* rekeying */ 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate #ifdef ALTPRIVSEP 1240*0Sstevel@tonic-gate /* unprivileged sshd has a kex packet handler that must not be reset */ 1241*0Sstevel@tonic-gate debug3("server_init_dispatch_20 -- should we dispatch_set(KEXINIT) here? %d && !%d", 1242*0Sstevel@tonic-gate packet_is_server(), packet_is_monitor()); 1243*0Sstevel@tonic-gate if (packet_is_server() && !packet_is_monitor()) { 1244*0Sstevel@tonic-gate debug3("server_init_dispatch_20 -- skipping dispatch_set(KEXINIT) in unpriv proc"); 1245*0Sstevel@tonic-gate dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 1246*0Sstevel@tonic-gate &altprivsep_rekey); 1247*0Sstevel@tonic-gate return; 1248*0Sstevel@tonic-gate } 1249*0Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 1250*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1251*0Sstevel@tonic-gate } 1252*0Sstevel@tonic-gate static void 1253*0Sstevel@tonic-gate server_init_dispatch_13(void) 1254*0Sstevel@tonic-gate { 1255*0Sstevel@tonic-gate debug("server_init_dispatch_13"); 1256*0Sstevel@tonic-gate dispatch_init(NULL); 1257*0Sstevel@tonic-gate dispatch_set(SSH_CMSG_EOF, &server_input_eof); 1258*0Sstevel@tonic-gate dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); 1259*0Sstevel@tonic-gate dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); 1260*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); 1261*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); 1262*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); 1263*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 1264*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 1265*0Sstevel@tonic-gate dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate static void 1268*0Sstevel@tonic-gate server_init_dispatch_15(void) 1269*0Sstevel@tonic-gate { 1270*0Sstevel@tonic-gate server_init_dispatch_13(); 1271*0Sstevel@tonic-gate debug("server_init_dispatch_15"); 1272*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); 1273*0Sstevel@tonic-gate dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); 1274*0Sstevel@tonic-gate } 1275*0Sstevel@tonic-gate static void 1276*0Sstevel@tonic-gate server_init_dispatch(void) 1277*0Sstevel@tonic-gate { 1278*0Sstevel@tonic-gate if (compat20) 1279*0Sstevel@tonic-gate server_init_dispatch_20(); 1280*0Sstevel@tonic-gate else if (compat13) 1281*0Sstevel@tonic-gate server_init_dispatch_13(); 1282*0Sstevel@tonic-gate else 1283*0Sstevel@tonic-gate server_init_dispatch_15(); 1284*0Sstevel@tonic-gate } 1285