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