1323124Sdes/* $OpenBSD: serverloop.c,v 1.184 2016/03/07 19:02:43 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Server main loop for handling the interactive session. 765668Skris * 865668Skris * As far as I am concerned, the code I have written for this software 965668Skris * can be used freely for any purpose. Any derived versions of this 1065668Skris * software must be clearly marked as such, and if the derived work is 1165668Skris * incompatible with the protocol description in the RFC file, it must be 1265668Skris * called by a name other than "ssh" or "Secure Shell". 1365668Skris * 1460573Skris * SSH2 support by Markus Friedl. 1592559Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 1665668Skris * 1765668Skris * Redistribution and use in source and binary forms, with or without 1865668Skris * modification, are permitted provided that the following conditions 1965668Skris * are met: 2065668Skris * 1. Redistributions of source code must retain the above copyright 2165668Skris * notice, this list of conditions and the following disclaimer. 2265668Skris * 2. Redistributions in binary form must reproduce the above copyright 2365668Skris * notice, this list of conditions and the following disclaimer in the 2465668Skris * documentation and/or other materials provided with the distribution. 2565668Skris * 2665668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2765668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2865668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2965668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3065668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3165668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3265668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3365668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3465668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3565668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3660573Skris */ 3757429Smarkm 3857429Smarkm#include "includes.h" 3969587Sgreen 40295367Sdes#include <sys/param.h> /* MIN MAX */ 41162856Sdes#include <sys/types.h> 42162856Sdes#include <sys/wait.h> 43162856Sdes#include <sys/socket.h> 44162856Sdes#ifdef HAVE_SYS_TIME_H 45162856Sdes# include <sys/time.h> 46162856Sdes#endif 47162856Sdes 48162856Sdes#include <netinet/in.h> 49162856Sdes 50162856Sdes#include <errno.h> 51162856Sdes#include <fcntl.h> 52162856Sdes#include <pwd.h> 53162856Sdes#include <signal.h> 54162856Sdes#include <string.h> 55162856Sdes#include <termios.h> 56162856Sdes#include <unistd.h> 57162856Sdes#include <stdarg.h> 58162856Sdes 59181111Sdes#include "openbsd-compat/sys-queue.h" 6057429Smarkm#include "xmalloc.h" 6157429Smarkm#include "packet.h" 6257429Smarkm#include "buffer.h" 6376262Sgreen#include "log.h" 64295367Sdes#include "misc.h" 6557429Smarkm#include "servconf.h" 66106130Sdes#include "canohost.h" 6776262Sgreen#include "sshpty.h" 6860573Skris#include "channels.h" 6960573Skris#include "compat.h" 7076262Sgreen#include "ssh1.h" 7160573Skris#include "ssh2.h" 72162856Sdes#include "key.h" 73162856Sdes#include "cipher.h" 74162856Sdes#include "kex.h" 75162856Sdes#include "hostfile.h" 7676262Sgreen#include "auth.h" 7760573Skris#include "session.h" 7860573Skris#include "dispatch.h" 7965668Skris#include "auth-options.h" 8076262Sgreen#include "serverloop.h" 81295367Sdes#include "ssherr.h" 8260573Skris 8369587Sgreenextern ServerOptions options; 8469587Sgreen 8576262Sgreen/* XXX */ 86126277Sdesextern Authctxt *the_authctxt; 87157019Sdesextern int use_privsep; 8876262Sgreen 8957429Smarkmstatic Buffer stdin_buffer; /* Buffer for stdin data. */ 9057429Smarkmstatic Buffer stdout_buffer; /* Buffer for stdout data. */ 9157429Smarkmstatic Buffer stderr_buffer; /* Buffer for stderr data. */ 9257429Smarkmstatic int fdin; /* Descriptor for stdin (for writing) */ 9357429Smarkmstatic int fdout; /* Descriptor for stdout (for reading); 9457429Smarkm May be same number as fdin. */ 9557429Smarkmstatic int fderr; /* Descriptor for stderr. May be -1. */ 9657429Smarkmstatic long stdin_bytes = 0; /* Number of bytes written to stdin. */ 9757429Smarkmstatic long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ 9857429Smarkmstatic long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ 9957429Smarkmstatic long fdout_bytes = 0; /* Number of stdout bytes read from program. */ 10057429Smarkmstatic int stdin_eof = 0; /* EOF message received from client. */ 10157429Smarkmstatic int fdout_eof = 0; /* EOF encountered reading from fdout. */ 10257429Smarkmstatic int fderr_eof = 0; /* EOF encountered readung from fderr. */ 10374500Sgreenstatic int fdin_is_tty = 0; /* fdin points to a tty. */ 10457429Smarkmstatic int connection_in; /* Connection to client (input). */ 10557429Smarkmstatic int connection_out; /* Connection to client (output). */ 10676262Sgreenstatic int connection_closed = 0; /* Connection to client closed. */ 10776262Sgreenstatic u_int buffer_high; /* "Soft" max buffer size. */ 108181111Sdesstatic int no_more_sessions = 0; /* Disallow further sessions. */ 10957429Smarkm 11057429Smarkm/* 11157429Smarkm * This SIGCHLD kludge is used to detect when the child exits. The server 11257429Smarkm * will exit after that, as soon as forwarded connections have terminated. 11357429Smarkm */ 11457429Smarkm 11592559Sdesstatic volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */ 11657429Smarkm 117157019Sdes/* Cleanup on signals (!use_privsep case only) */ 118157019Sdesstatic volatile sig_atomic_t received_sigterm = 0; 119157019Sdes 12092559Sdes/* prototypes */ 12192559Sdesstatic void server_init_dispatch(void); 12260573Skris 12392559Sdes/* 12492559Sdes * we write to this pipe if a SIGCHLD is caught in order to avoid 12592559Sdes * the race between select() and child_terminated 12692559Sdes */ 12792559Sdesstatic int notify_pipe[2]; 12892559Sdesstatic void 12992559Sdesnotify_setup(void) 13057429Smarkm{ 13192559Sdes if (pipe(notify_pipe) < 0) { 13292559Sdes error("pipe(notify_pipe) failed %s", strerror(errno)); 133226046Sdes } else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) || 134226046Sdes (fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) { 13592559Sdes error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno)); 13692559Sdes close(notify_pipe[0]); 13792559Sdes close(notify_pipe[1]); 13892559Sdes } else { 13992559Sdes set_nonblock(notify_pipe[0]); 14092559Sdes set_nonblock(notify_pipe[1]); 14192559Sdes return; 14257429Smarkm } 14392559Sdes notify_pipe[0] = -1; /* read end */ 14492559Sdes notify_pipe[1] = -1; /* write end */ 14557429Smarkm} 14692559Sdesstatic void 14792559Sdesnotify_parent(void) 14857429Smarkm{ 14992559Sdes if (notify_pipe[1] != -1) 150255767Sdes (void)write(notify_pipe[1], "", 1); 15192559Sdes} 15292559Sdesstatic void 15392559Sdesnotify_prepare(fd_set *readset) 15492559Sdes{ 15592559Sdes if (notify_pipe[0] != -1) 15692559Sdes FD_SET(notify_pipe[0], readset); 15792559Sdes} 15892559Sdesstatic void 15992559Sdesnotify_done(fd_set *readset) 16092559Sdes{ 16192559Sdes char c; 16292559Sdes 16392559Sdes if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) 16492559Sdes while (read(notify_pipe[0], &c, 1) != -1) 16592559Sdes debug2("notify_done: reading"); 16692559Sdes} 16792559Sdes 168162856Sdes/*ARGSUSED*/ 16992559Sdesstatic void 17092559Sdessigchld_handler(int sig) 17192559Sdes{ 17260573Skris int save_errno = errno; 17360573Skris child_terminated = 1; 174106130Sdes#ifndef _UNICOS 17598941Sdes mysignal(SIGCHLD, sigchld_handler); 176106130Sdes#endif 17792559Sdes notify_parent(); 17860573Skris errno = save_errno; 17957429Smarkm} 18057429Smarkm 181162856Sdes/*ARGSUSED*/ 182157019Sdesstatic void 183157019Sdessigterm_handler(int sig) 184157019Sdes{ 185157019Sdes received_sigterm = sig; 186157019Sdes} 187157019Sdes 18857429Smarkm/* 18957429Smarkm * Make packets from buffered stderr data, and buffer it for sending 19057429Smarkm * to the client. 19157429Smarkm */ 19292559Sdesstatic void 19376262Sgreenmake_packets_from_stderr_data(void) 19457429Smarkm{ 195124211Sdes u_int len; 19657429Smarkm 19757429Smarkm /* Send buffered stderr data to the client. */ 19857429Smarkm while (buffer_len(&stderr_buffer) > 0 && 19957429Smarkm packet_not_very_much_data_to_write()) { 20057429Smarkm len = buffer_len(&stderr_buffer); 20157429Smarkm if (packet_is_interactive()) { 20257429Smarkm if (len > 512) 20357429Smarkm len = 512; 20457429Smarkm } else { 20557429Smarkm /* Keep the packets at reasonable size. */ 20657429Smarkm if (len > packet_get_maxsize()) 20757429Smarkm len = packet_get_maxsize(); 20857429Smarkm } 20957429Smarkm packet_start(SSH_SMSG_STDERR_DATA); 21057429Smarkm packet_put_string(buffer_ptr(&stderr_buffer), len); 21157429Smarkm packet_send(); 21257429Smarkm buffer_consume(&stderr_buffer, len); 21357429Smarkm stderr_bytes += len; 21457429Smarkm } 21557429Smarkm} 21657429Smarkm 21757429Smarkm/* 21857429Smarkm * Make packets from buffered stdout data, and buffer it for sending to the 21957429Smarkm * client. 22057429Smarkm */ 22192559Sdesstatic void 22276262Sgreenmake_packets_from_stdout_data(void) 22357429Smarkm{ 224124211Sdes u_int len; 22557429Smarkm 22657429Smarkm /* Send buffered stdout data to the client. */ 22757429Smarkm while (buffer_len(&stdout_buffer) > 0 && 22857429Smarkm packet_not_very_much_data_to_write()) { 22957429Smarkm len = buffer_len(&stdout_buffer); 23057429Smarkm if (packet_is_interactive()) { 23157429Smarkm if (len > 512) 23257429Smarkm len = 512; 23357429Smarkm } else { 23457429Smarkm /* Keep the packets at reasonable size. */ 23557429Smarkm if (len > packet_get_maxsize()) 23676262Sgreen len = packet_get_maxsize(); 23757429Smarkm } 23857429Smarkm packet_start(SSH_SMSG_STDOUT_DATA); 23957429Smarkm packet_put_string(buffer_ptr(&stdout_buffer), len); 24057429Smarkm packet_send(); 24157429Smarkm buffer_consume(&stdout_buffer, len); 24257429Smarkm stdout_bytes += len; 24357429Smarkm } 24457429Smarkm} 24557429Smarkm 24692559Sdesstatic void 24792559Sdesclient_alive_check(void) 24892559Sdes{ 249126277Sdes int channel_id; 25092559Sdes 25192559Sdes /* timeout, check to see how many we have had */ 252197679Sdes if (packet_inc_alive_timeouts() > options.client_alive_count_max) { 253164149Sdes logit("Timeout, client not responding."); 254164149Sdes cleanup_exit(255); 255164149Sdes } 25692559Sdes 25792559Sdes /* 258126277Sdes * send a bogus global/channel request with "wantreply", 25992559Sdes * we should get back a failure 26092559Sdes */ 261126277Sdes if ((channel_id = channel_find_open()) == -1) { 262126277Sdes packet_start(SSH2_MSG_GLOBAL_REQUEST); 263126277Sdes packet_put_cstring("keepalive@openssh.com"); 264126277Sdes packet_put_char(1); /* boolean: want reply */ 265126277Sdes } else { 266126277Sdes channel_request_start(channel_id, "keepalive@openssh.com", 1); 267126277Sdes } 26892559Sdes packet_send(); 26992559Sdes} 27092559Sdes 27157429Smarkm/* 27257429Smarkm * Sleep in select() until we can do something. This will initialize the 27357429Smarkm * select masks. Upon return, the masks will indicate which descriptors 27457429Smarkm * have data or can accept data. Optionally, a maximum time can be specified 27557429Smarkm * for the duration of the wait (0 = infinite). 27657429Smarkm */ 27792559Sdesstatic void 27876262Sgreenwait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 279323124Sdes u_int *nallocp, u_int64_t max_time_ms) 28057429Smarkm{ 28157429Smarkm struct timeval tv, *tvp; 28257429Smarkm int ret; 283240075Sdes time_t minwait_secs = 0; 28476262Sgreen int client_alive_scheduled = 0; 285181111Sdes int program_alive_scheduled = 0; 28657429Smarkm 287240075Sdes /* Allocate and update select() masks for channel descriptors. */ 288240075Sdes channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 289240075Sdes &minwait_secs, 0); 290240075Sdes 291323124Sdes /* XXX need proper deadline system for rekey/client alive */ 292240075Sdes if (minwait_secs != 0) 293323124Sdes max_time_ms = MIN(max_time_ms, (u_int)minwait_secs * 1000); 294240075Sdes 29576262Sgreen /* 29692559Sdes * if using client_alive, set the max timeout accordingly, 29776262Sgreen * and indicate that this particular timeout was for client 29876262Sgreen * alive by setting the client_alive_scheduled flag. 29976262Sgreen * 30076262Sgreen * this could be randomized somewhat to make traffic 30192559Sdes * analysis more difficult, but we're not doing it yet. 30276262Sgreen */ 303323124Sdes if (compat20 && options.client_alive_interval) { 304323124Sdes uint64_t keepalive_ms = 305323124Sdes (uint64_t)options.client_alive_interval * 1000; 306323124Sdes 30792559Sdes client_alive_scheduled = 1; 308323124Sdes if (max_time_ms == 0 || max_time_ms > keepalive_ms) 309323124Sdes max_time_ms = keepalive_ms; 31092559Sdes } 31176262Sgreen 31260573Skris if (compat20) { 31392559Sdes#if 0 31460573Skris /* wrong: bad condition XXX */ 31560573Skris if (channel_not_very_much_buffered_data()) 31692559Sdes#endif 31792559Sdes FD_SET(connection_in, *readsetp); 31860573Skris } else { 31961209Skris /* 32061209Skris * Read packets from the client unless we have too much 32161209Skris * buffered stdin or channel data. 32261209Skris */ 32361209Skris if (buffer_len(&stdin_buffer) < buffer_high && 32460573Skris channel_not_very_much_buffered_data()) 32576262Sgreen FD_SET(connection_in, *readsetp); 32661209Skris /* 32761209Skris * If there is not too much data already buffered going to 32861209Skris * the client, try to get some more data from the program. 32961209Skris */ 33061209Skris if (packet_not_very_much_data_to_write()) { 331181111Sdes program_alive_scheduled = child_terminated; 33261209Skris if (!fdout_eof) 33376262Sgreen FD_SET(fdout, *readsetp); 33461209Skris if (!fderr_eof) 33576262Sgreen FD_SET(fderr, *readsetp); 33661209Skris } 33761209Skris /* 33861209Skris * If we have buffered data, try to write some of that data 33961209Skris * to the program. 34061209Skris */ 34161209Skris if (fdin != -1 && buffer_len(&stdin_buffer) > 0) 34276262Sgreen FD_SET(fdin, *writesetp); 34360573Skris } 34492559Sdes notify_prepare(*readsetp); 34557429Smarkm 34657429Smarkm /* 34757429Smarkm * If we have buffered packet data going to the client, mark that 34857429Smarkm * descriptor. 34957429Smarkm */ 35057429Smarkm if (packet_have_data_to_write()) 35176262Sgreen FD_SET(connection_out, *writesetp); 35257429Smarkm 35357429Smarkm /* 35457429Smarkm * If child has terminated and there is enough buffer space to read 35557429Smarkm * from it, then read as much as is available and exit. 35657429Smarkm */ 35757429Smarkm if (child_terminated && packet_not_very_much_data_to_write()) 358323124Sdes if (max_time_ms == 0 || client_alive_scheduled) 359323124Sdes max_time_ms = 100; 36057429Smarkm 361323124Sdes if (max_time_ms == 0) 36257429Smarkm tvp = NULL; 36357429Smarkm else { 364323124Sdes tv.tv_sec = max_time_ms / 1000; 365323124Sdes tv.tv_usec = 1000 * (max_time_ms % 1000); 36657429Smarkm tvp = &tv; 36757429Smarkm } 36857429Smarkm 36957429Smarkm /* Wait for something to happen, or the timeout to expire. */ 37076262Sgreen ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); 37157429Smarkm 37276262Sgreen if (ret == -1) { 37392559Sdes memset(*readsetp, 0, *nallocp); 37492559Sdes memset(*writesetp, 0, *nallocp); 37557429Smarkm if (errno != EINTR) 37657429Smarkm error("select: %.100s", strerror(errno)); 377181111Sdes } else { 378181111Sdes if (ret == 0 && client_alive_scheduled) 379181111Sdes client_alive_check(); 380181111Sdes if (!compat20 && program_alive_scheduled && fdin_is_tty) { 381181111Sdes if (!fdout_eof) 382181111Sdes FD_SET(fdout, *readsetp); 383181111Sdes if (!fderr_eof) 384181111Sdes FD_SET(fderr, *readsetp); 385181111Sdes } 386181111Sdes } 38776262Sgreen 38892559Sdes notify_done(*readsetp); 38957429Smarkm} 39057429Smarkm 39157429Smarkm/* 39257429Smarkm * Processes input from the client and the program. Input data is stored 39357429Smarkm * in buffers and processed later. 39457429Smarkm */ 39592559Sdesstatic void 396162856Sdesprocess_input(fd_set *readset) 39757429Smarkm{ 398323124Sdes struct ssh *ssh = active_state; /* XXX */ 39957429Smarkm int len; 40057429Smarkm char buf[16384]; 40157429Smarkm 40257429Smarkm /* Read and buffer any input data from the client. */ 40357429Smarkm if (FD_ISSET(connection_in, readset)) { 404296781Sdes len = read(connection_in, buf, sizeof(buf)); 40557429Smarkm if (len == 0) { 406323124Sdes verbose("Connection closed by %.100s port %d", 407323124Sdes ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); 40876262Sgreen connection_closed = 1; 40976262Sgreen if (compat20) 41076262Sgreen return; 411126277Sdes cleanup_exit(255); 41261209Skris } else if (len < 0) { 413181111Sdes if (errno != EINTR && errno != EAGAIN && 414181111Sdes errno != EWOULDBLOCK) { 415106130Sdes verbose("Read error from remote host " 416323124Sdes "%.100s port %d: %.100s", 417323124Sdes ssh_remote_ipaddr(ssh), 418323124Sdes ssh_remote_port(ssh), strerror(errno)); 419126277Sdes cleanup_exit(255); 42061209Skris } 42161209Skris } else { 42261209Skris /* Buffer any received data. */ 42361209Skris packet_process_incoming(buf, len); 42457429Smarkm } 42557429Smarkm } 42660573Skris if (compat20) 42760573Skris return; 42860573Skris 42957429Smarkm /* Read and buffer any available stdout data from the program. */ 43057429Smarkm if (!fdout_eof && FD_ISSET(fdout, readset)) { 431162856Sdes errno = 0; 43257429Smarkm len = read(fdout, buf, sizeof(buf)); 433181111Sdes if (len < 0 && (errno == EINTR || ((errno == EAGAIN || 434181111Sdes errno == EWOULDBLOCK) && !child_terminated))) { 43561209Skris /* do nothing */ 436162856Sdes#ifndef PTY_ZEROREAD 43761209Skris } else if (len <= 0) { 438162856Sdes#else 439162856Sdes } else if ((!isatty(fdout) && len <= 0) || 440162856Sdes (isatty(fdout) && (len < 0 || (len == 0 && errno != 0)))) { 441162856Sdes#endif 44257429Smarkm fdout_eof = 1; 44361209Skris } else { 44457429Smarkm buffer_append(&stdout_buffer, buf, len); 44557429Smarkm fdout_bytes += len; 44657429Smarkm } 44757429Smarkm } 44857429Smarkm /* Read and buffer any available stderr data from the program. */ 44957429Smarkm if (!fderr_eof && FD_ISSET(fderr, readset)) { 450162856Sdes errno = 0; 45157429Smarkm len = read(fderr, buf, sizeof(buf)); 452181111Sdes if (len < 0 && (errno == EINTR || ((errno == EAGAIN || 453181111Sdes errno == EWOULDBLOCK) && !child_terminated))) { 45461209Skris /* do nothing */ 455162856Sdes#ifndef PTY_ZEROREAD 45661209Skris } else if (len <= 0) { 457162856Sdes#else 458162856Sdes } else if ((!isatty(fderr) && len <= 0) || 459162856Sdes (isatty(fderr) && (len < 0 || (len == 0 && errno != 0)))) { 460162856Sdes#endif 46157429Smarkm fderr_eof = 1; 46261209Skris } else { 46357429Smarkm buffer_append(&stderr_buffer, buf, len); 46461209Skris } 46557429Smarkm } 46657429Smarkm} 46757429Smarkm 46857429Smarkm/* 46957429Smarkm * Sends data from internal buffers to client program stdin. 47057429Smarkm */ 47192559Sdesstatic void 472162856Sdesprocess_output(fd_set *writeset) 47357429Smarkm{ 47474500Sgreen struct termios tio; 47592559Sdes u_char *data; 47692559Sdes u_int dlen; 47757429Smarkm int len; 47857429Smarkm 47957429Smarkm /* Write buffered data to program stdin. */ 48060573Skris if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { 48192559Sdes data = buffer_ptr(&stdin_buffer); 48292559Sdes dlen = buffer_len(&stdin_buffer); 48392559Sdes len = write(fdin, data, dlen); 484181111Sdes if (len < 0 && 485181111Sdes (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) { 48661209Skris /* do nothing */ 48761209Skris } else if (len <= 0) { 48860573Skris if (fdin != fdout) 48957429Smarkm close(fdin); 49057429Smarkm else 49157429Smarkm shutdown(fdin, SHUT_WR); /* We will no longer send. */ 49257429Smarkm fdin = -1; 49357429Smarkm } else { 49474500Sgreen /* Successful write. */ 49592559Sdes if (fdin_is_tty && dlen >= 1 && data[0] != '\r' && 49692559Sdes tcgetattr(fdin, &tio) == 0 && 49774500Sgreen !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 49874500Sgreen /* 49974500Sgreen * Simulate echo to reduce the impact of 50074500Sgreen * traffic analysis 50174500Sgreen */ 50276262Sgreen packet_send_ignore(len); 50374500Sgreen packet_send(); 50474500Sgreen } 50574500Sgreen /* Consume the data from the buffer. */ 50657429Smarkm buffer_consume(&stdin_buffer, len); 50757429Smarkm /* Update the count of bytes written to the program. */ 50857429Smarkm stdin_bytes += len; 50957429Smarkm } 51057429Smarkm } 51157429Smarkm /* Send any buffered packet data to the client. */ 51257429Smarkm if (FD_ISSET(connection_out, writeset)) 51357429Smarkm packet_write_poll(); 51457429Smarkm} 51557429Smarkm 51657429Smarkm/* 51757429Smarkm * Wait until all buffered output has been sent to the client. 51857429Smarkm * This is used when the program terminates. 51957429Smarkm */ 52092559Sdesstatic void 52176262Sgreendrain_output(void) 52257429Smarkm{ 52357429Smarkm /* Send any buffered stdout data to the client. */ 52457429Smarkm if (buffer_len(&stdout_buffer) > 0) { 52557429Smarkm packet_start(SSH_SMSG_STDOUT_DATA); 52657429Smarkm packet_put_string(buffer_ptr(&stdout_buffer), 52757429Smarkm buffer_len(&stdout_buffer)); 52857429Smarkm packet_send(); 52957429Smarkm /* Update the count of sent bytes. */ 53057429Smarkm stdout_bytes += buffer_len(&stdout_buffer); 53157429Smarkm } 53257429Smarkm /* Send any buffered stderr data to the client. */ 53357429Smarkm if (buffer_len(&stderr_buffer) > 0) { 53457429Smarkm packet_start(SSH_SMSG_STDERR_DATA); 53557429Smarkm packet_put_string(buffer_ptr(&stderr_buffer), 53657429Smarkm buffer_len(&stderr_buffer)); 53757429Smarkm packet_send(); 53857429Smarkm /* Update the count of sent bytes. */ 53957429Smarkm stderr_bytes += buffer_len(&stderr_buffer); 54057429Smarkm } 54157429Smarkm /* Wait until all buffered data has been written to the client. */ 54257429Smarkm packet_write_wait(); 54357429Smarkm} 54457429Smarkm 54592559Sdesstatic void 54676262Sgreenprocess_buffered_input_packets(void) 54760573Skris{ 548295367Sdes dispatch_run(DISPATCH_NONBLOCK, NULL, active_state); 54960573Skris} 55060573Skris 55157429Smarkm/* 55257429Smarkm * Performs the interactive session. This handles data transmission between 55357429Smarkm * the client and the program. Note that the notion of stdin, stdout, and 55457429Smarkm * stderr in this function is sort of reversed: this function writes to 55557429Smarkm * stdin (of the child program), and reads from stdout and stderr (of the 55657429Smarkm * child program). 55757429Smarkm */ 55860573Skrisvoid 55960573Skrisserver_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) 56057429Smarkm{ 56176262Sgreen fd_set *readset = NULL, *writeset = NULL; 562137019Sdes int max_fd = 0; 563137019Sdes u_int nalloc = 0; 56460573Skris int wait_status; /* Status returned by wait(). */ 56560573Skris pid_t wait_pid; /* pid returned by wait(). */ 56657429Smarkm int waiting_termination = 0; /* Have displayed waiting close message. */ 567255767Sdes u_int64_t max_time_milliseconds; 56876262Sgreen u_int previous_stdout_buffer_bytes; 56976262Sgreen u_int stdout_buffer_bytes; 57057429Smarkm int type; 57157429Smarkm 57257429Smarkm debug("Entering interactive session."); 57357429Smarkm 57457429Smarkm /* Initialize the SIGCHLD kludge. */ 57557429Smarkm child_terminated = 0; 57698941Sdes mysignal(SIGCHLD, sigchld_handler); 57757429Smarkm 578157019Sdes if (!use_privsep) { 579157019Sdes signal(SIGTERM, sigterm_handler); 580157019Sdes signal(SIGINT, sigterm_handler); 581157019Sdes signal(SIGQUIT, sigterm_handler); 582157019Sdes } 583157019Sdes 58457429Smarkm /* Initialize our global variables. */ 58557429Smarkm fdin = fdin_arg; 58657429Smarkm fdout = fdout_arg; 58757429Smarkm fderr = fderr_arg; 58861209Skris 58961209Skris /* nonblocking IO */ 59061209Skris set_nonblock(fdin); 59161209Skris set_nonblock(fdout); 59261209Skris /* we don't have stderr for interactive terminal sessions, see below */ 59361209Skris if (fderr != -1) 59461209Skris set_nonblock(fderr); 59561209Skris 59674500Sgreen if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) 59774500Sgreen fdin_is_tty = 1; 59874500Sgreen 59957429Smarkm connection_in = packet_get_connection_in(); 60057429Smarkm connection_out = packet_get_connection_out(); 60157429Smarkm 60292559Sdes notify_setup(); 60392559Sdes 60457429Smarkm previous_stdout_buffer_bytes = 0; 60557429Smarkm 60657429Smarkm /* Set approximate I/O buffer size. */ 60757429Smarkm if (packet_is_interactive()) 60857429Smarkm buffer_high = 4096; 60957429Smarkm else 61057429Smarkm buffer_high = 64 * 1024; 61157429Smarkm 61292559Sdes#if 0 61357429Smarkm /* Initialize max_fd to the maximum of the known file descriptors. */ 61492559Sdes max_fd = MAX(connection_in, connection_out); 61592559Sdes max_fd = MAX(max_fd, fdin); 61692559Sdes max_fd = MAX(max_fd, fdout); 61776262Sgreen if (fderr != -1) 61876262Sgreen max_fd = MAX(max_fd, fderr); 61992559Sdes#endif 62057429Smarkm 62157429Smarkm /* Initialize Initialize buffers. */ 62257429Smarkm buffer_init(&stdin_buffer); 62357429Smarkm buffer_init(&stdout_buffer); 62457429Smarkm buffer_init(&stderr_buffer); 62557429Smarkm 62657429Smarkm /* 62757429Smarkm * If we have no separate fderr (which is the case when we have a pty 62857429Smarkm * - there we cannot make difference between data sent to stdout and 62957429Smarkm * stderr), indicate that we have seen an EOF from stderr. This way 630157019Sdes * we don't need to check the descriptor everywhere. 63157429Smarkm */ 63257429Smarkm if (fderr == -1) 63357429Smarkm fderr_eof = 1; 63457429Smarkm 63560573Skris server_init_dispatch(); 63660573Skris 63757429Smarkm /* Main loop of the server for the interactive session mode. */ 63857429Smarkm for (;;) { 63957429Smarkm 64057429Smarkm /* Process buffered packets from the client. */ 64157429Smarkm process_buffered_input_packets(); 64257429Smarkm 64357429Smarkm /* 64457429Smarkm * If we have received eof, and there is no more pending 64557429Smarkm * input data, cause a real eof by closing fdin. 64657429Smarkm */ 64757429Smarkm if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { 64860573Skris if (fdin != fdout) 64957429Smarkm close(fdin); 65057429Smarkm else 65157429Smarkm shutdown(fdin, SHUT_WR); /* We will no longer send. */ 65257429Smarkm fdin = -1; 65357429Smarkm } 65457429Smarkm /* Make packets from buffered stderr data to send to the client. */ 65557429Smarkm make_packets_from_stderr_data(); 65657429Smarkm 65757429Smarkm /* 65857429Smarkm * Make packets from buffered stdout data to send to the 65957429Smarkm * client. If there is very little to send, this arranges to 66057429Smarkm * not send them now, but to wait a short while to see if we 66157429Smarkm * are getting more data. This is necessary, as some systems 66257429Smarkm * wake up readers from a pty after each separate character. 66357429Smarkm */ 66457429Smarkm max_time_milliseconds = 0; 66557429Smarkm stdout_buffer_bytes = buffer_len(&stdout_buffer); 66657429Smarkm if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && 66757429Smarkm stdout_buffer_bytes != previous_stdout_buffer_bytes) { 66857429Smarkm /* try again after a while */ 66957429Smarkm max_time_milliseconds = 10; 67057429Smarkm } else { 67157429Smarkm /* Send it now. */ 67257429Smarkm make_packets_from_stdout_data(); 67357429Smarkm } 67457429Smarkm previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); 67557429Smarkm 67657429Smarkm /* Send channel data to the client. */ 67757429Smarkm if (packet_not_very_much_data_to_write()) 67857429Smarkm channel_output_poll(); 67957429Smarkm 68057429Smarkm /* 68157429Smarkm * Bail out of the loop if the program has closed its output 68257429Smarkm * descriptors, and we have no more data to send to the 68357429Smarkm * client, and there is no pending buffered data. 68457429Smarkm */ 68557429Smarkm if (fdout_eof && fderr_eof && !packet_have_data_to_write() && 68657429Smarkm buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { 68757429Smarkm if (!channel_still_open()) 68860573Skris break; 68957429Smarkm if (!waiting_termination) { 69057429Smarkm const char *s = "Waiting for forwarded connections to terminate...\r\n"; 69157429Smarkm char *cp; 69257429Smarkm waiting_termination = 1; 69357429Smarkm buffer_append(&stderr_buffer, s, strlen(s)); 69457429Smarkm 69557429Smarkm /* Display list of open channels. */ 69657429Smarkm cp = channel_open_message(); 69757429Smarkm buffer_append(&stderr_buffer, cp, strlen(cp)); 698255767Sdes free(cp); 69957429Smarkm } 70057429Smarkm } 70192559Sdes max_fd = MAX(connection_in, connection_out); 70292559Sdes max_fd = MAX(max_fd, fdin); 70392559Sdes max_fd = MAX(max_fd, fdout); 70492559Sdes max_fd = MAX(max_fd, fderr); 70592559Sdes max_fd = MAX(max_fd, notify_pipe[0]); 70692559Sdes 70757429Smarkm /* Sleep in select() until we can do something. */ 70876262Sgreen wait_until_can_do_something(&readset, &writeset, &max_fd, 70992559Sdes &nalloc, max_time_milliseconds); 71057429Smarkm 711157019Sdes if (received_sigterm) { 712248619Sdes logit("Exiting on signal %d", (int)received_sigterm); 713157019Sdes /* Clean up sessions, utmp, etc. */ 714157019Sdes cleanup_exit(255); 715157019Sdes } 716157019Sdes 71757429Smarkm /* Process any channel events. */ 71876262Sgreen channel_after_select(readset, writeset); 71957429Smarkm 72057429Smarkm /* Process input from the client and from program stdout/stderr. */ 72176262Sgreen process_input(readset); 72257429Smarkm 72357429Smarkm /* Process output to the client and to program stdin. */ 72476262Sgreen process_output(writeset); 72557429Smarkm } 726255767Sdes free(readset); 727255767Sdes free(writeset); 72857429Smarkm 72957429Smarkm /* Cleanup and termination code. */ 73057429Smarkm 73157429Smarkm /* Wait until all output has been sent to the client. */ 73257429Smarkm drain_output(); 73357429Smarkm 734240075Sdes debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", 73592559Sdes stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); 73657429Smarkm 73757429Smarkm /* Free and clear the buffers. */ 73857429Smarkm buffer_free(&stdin_buffer); 73957429Smarkm buffer_free(&stdout_buffer); 74057429Smarkm buffer_free(&stderr_buffer); 74157429Smarkm 74257429Smarkm /* Close the file descriptors. */ 74357429Smarkm if (fdout != -1) 74457429Smarkm close(fdout); 74557429Smarkm fdout = -1; 74657429Smarkm fdout_eof = 1; 74757429Smarkm if (fderr != -1) 74857429Smarkm close(fderr); 74957429Smarkm fderr = -1; 75057429Smarkm fderr_eof = 1; 75157429Smarkm if (fdin != -1) 75257429Smarkm close(fdin); 75357429Smarkm fdin = -1; 75457429Smarkm 75592559Sdes channel_free_all(); 75657429Smarkm 75757429Smarkm /* We no longer want our SIGCHLD handler to be called. */ 75898941Sdes mysignal(SIGCHLD, SIG_DFL); 75957429Smarkm 76098684Sdes while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) 76198684Sdes if (errno != EINTR) 76298684Sdes packet_disconnect("wait: %.100s", strerror(errno)); 76398684Sdes if (wait_pid != pid) 76498684Sdes error("Strange, wait returned pid %ld, expected %ld", 76598684Sdes (long)wait_pid, (long)pid); 76692559Sdes 76757429Smarkm /* Check if it exited normally. */ 76857429Smarkm if (WIFEXITED(wait_status)) { 76957429Smarkm /* Yes, normal exit. Get exit status and send it to the client. */ 77057429Smarkm debug("Command exited with status %d.", WEXITSTATUS(wait_status)); 77157429Smarkm packet_start(SSH_SMSG_EXITSTATUS); 77257429Smarkm packet_put_int(WEXITSTATUS(wait_status)); 77357429Smarkm packet_send(); 77457429Smarkm packet_write_wait(); 77557429Smarkm 77657429Smarkm /* 77757429Smarkm * Wait for exit confirmation. Note that there might be 77857429Smarkm * other packets coming before it; however, the program has 77957429Smarkm * already died so we just ignore them. The client is 78057429Smarkm * supposed to respond with the confirmation when it receives 78157429Smarkm * the exit status. 78257429Smarkm */ 78357429Smarkm do { 78492559Sdes type = packet_read(); 78557429Smarkm } 78657429Smarkm while (type != SSH_CMSG_EXIT_CONFIRMATION); 78757429Smarkm 78857429Smarkm debug("Received exit confirmation."); 78957429Smarkm return; 79057429Smarkm } 79157429Smarkm /* Check if the program terminated due to a signal. */ 79257429Smarkm if (WIFSIGNALED(wait_status)) 79357429Smarkm packet_disconnect("Command terminated on signal %d.", 79457429Smarkm WTERMSIG(wait_status)); 79557429Smarkm 79657429Smarkm /* Some weird exit cause. Just exit. */ 79757429Smarkm packet_disconnect("wait returned status %04x.", wait_status); 79857429Smarkm /* NOTREACHED */ 79957429Smarkm} 80060573Skris 80192559Sdesstatic void 80292559Sdescollect_children(void) 80392559Sdes{ 80492559Sdes pid_t pid; 80592559Sdes sigset_t oset, nset; 80692559Sdes int status; 80792559Sdes 80892559Sdes /* block SIGCHLD while we check for dead children */ 80992559Sdes sigemptyset(&nset); 81092559Sdes sigaddset(&nset, SIGCHLD); 81192559Sdes sigprocmask(SIG_BLOCK, &nset, &oset); 81292559Sdes if (child_terminated) { 813162856Sdes debug("Received SIGCHLD."); 81498684Sdes while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 81598684Sdes (pid < 0 && errno == EINTR)) 81698684Sdes if (pid > 0) 81798684Sdes session_close_by_pid(pid, status); 81892559Sdes child_terminated = 0; 81992559Sdes } 82092559Sdes sigprocmask(SIG_SETMASK, &oset, NULL); 82192559Sdes} 82292559Sdes 82360573Skrisvoid 82492559Sdesserver_loop2(Authctxt *authctxt) 82560573Skris{ 82676262Sgreen fd_set *readset = NULL, *writeset = NULL; 827296781Sdes int max_fd; 828255767Sdes u_int nalloc = 0; 829255767Sdes u_int64_t rekey_timeout_ms = 0; 83060573Skris 83160573Skris debug("Entering interactive session for SSH2."); 83260573Skris 83398941Sdes mysignal(SIGCHLD, sigchld_handler); 83460573Skris child_terminated = 0; 83560573Skris connection_in = packet_get_connection_in(); 83660573Skris connection_out = packet_get_connection_out(); 83776262Sgreen 838157019Sdes if (!use_privsep) { 839157019Sdes signal(SIGTERM, sigterm_handler); 840157019Sdes signal(SIGINT, sigterm_handler); 841157019Sdes signal(SIGQUIT, sigterm_handler); 842157019Sdes } 843157019Sdes 84492559Sdes notify_setup(); 84592559Sdes 84676262Sgreen max_fd = MAX(connection_in, connection_out); 84792559Sdes max_fd = MAX(max_fd, notify_pipe[0]); 84876262Sgreen 84960573Skris server_init_dispatch(); 85060573Skris 85160573Skris for (;;) { 85260573Skris process_buffered_input_packets(); 85376262Sgreen 854296781Sdes if (!ssh_packet_is_rekeying(active_state) && 855296781Sdes packet_not_very_much_data_to_write()) 85660573Skris channel_output_poll(); 857296781Sdes if (options.rekey_interval > 0 && compat20 && 858296781Sdes !ssh_packet_is_rekeying(active_state)) 859255767Sdes rekey_timeout_ms = packet_get_rekey_timeout() * 1000; 860255767Sdes else 861255767Sdes rekey_timeout_ms = 0; 862255767Sdes 86376262Sgreen wait_until_can_do_something(&readset, &writeset, &max_fd, 864255767Sdes &nalloc, rekey_timeout_ms); 86592559Sdes 866157019Sdes if (received_sigterm) { 867248619Sdes logit("Exiting on signal %d", (int)received_sigterm); 868157019Sdes /* Clean up sessions, utmp, etc. */ 869157019Sdes cleanup_exit(255); 870157019Sdes } 871157019Sdes 87292559Sdes collect_children(); 873296781Sdes if (!ssh_packet_is_rekeying(active_state)) 87476262Sgreen channel_after_select(readset, writeset); 87576262Sgreen process_input(readset); 87676262Sgreen if (connection_closed) 87776262Sgreen break; 87876262Sgreen process_output(writeset); 87960573Skris } 88092559Sdes collect_children(); 88192559Sdes 882255767Sdes free(readset); 883255767Sdes free(writeset); 88476262Sgreen 88592559Sdes /* free all channels, no more reads and writes */ 88692559Sdes channel_free_all(); 88792559Sdes 88892559Sdes /* free remaining sessions, e.g. remove wtmp entries */ 88998684Sdes session_destroy_all(NULL); 89060573Skris} 89160573Skris 892295367Sdesstatic int 893126277Sdesserver_input_keep_alive(int type, u_int32_t seq, void *ctxt) 89476262Sgreen{ 895126277Sdes debug("Got %d/%u for keepalive", type, seq); 89692559Sdes /* 89792559Sdes * reset timeout, since we got a sane answer from the client. 89876262Sgreen * even if this was generated by something other than 89976262Sgreen * the bogus CHANNEL_REQUEST we send for keepalives. 90076262Sgreen */ 901197679Sdes packet_set_alive_timeouts(0); 902295367Sdes return 0; 90376262Sgreen} 90476262Sgreen 905295367Sdesstatic int 90692559Sdesserver_input_stdin_data(int type, u_int32_t seq, void *ctxt) 90760573Skris{ 90860573Skris char *data; 90976262Sgreen u_int data_len; 91060573Skris 91160573Skris /* Stdin data from the client. Append it to the buffer. */ 91260573Skris /* Ignore any data if the client has closed stdin. */ 91360573Skris if (fdin == -1) 914295367Sdes return 0; 91560573Skris data = packet_get_string(&data_len); 91692559Sdes packet_check_eom(); 91760573Skris buffer_append(&stdin_buffer, data, data_len); 918264377Sdes explicit_bzero(data, data_len); 919255767Sdes free(data); 920295367Sdes return 0; 92160573Skris} 92260573Skris 923295367Sdesstatic int 92492559Sdesserver_input_eof(int type, u_int32_t seq, void *ctxt) 92560573Skris{ 92660573Skris /* 92760573Skris * Eof from the client. The stdin descriptor to the 92860573Skris * program will be closed when all buffered data has 92960573Skris * drained. 93060573Skris */ 93160573Skris debug("EOF received for stdin."); 93292559Sdes packet_check_eom(); 93360573Skris stdin_eof = 1; 934295367Sdes return 0; 93560573Skris} 93660573Skris 937295367Sdesstatic int 93892559Sdesserver_input_window_size(int type, u_int32_t seq, void *ctxt) 93960573Skris{ 940162856Sdes u_int row = packet_get_int(); 941162856Sdes u_int col = packet_get_int(); 942162856Sdes u_int xpixel = packet_get_int(); 943162856Sdes u_int ypixel = packet_get_int(); 94460573Skris 94560573Skris debug("Window change received."); 94692559Sdes packet_check_eom(); 94760573Skris if (fdin != -1) 94860573Skris pty_change_window_size(fdin, row, col, xpixel, ypixel); 949295367Sdes return 0; 95060573Skris} 95160573Skris 95292559Sdesstatic Channel * 953126277Sdesserver_request_direct_tcpip(void) 95460573Skris{ 955248619Sdes Channel *c = NULL; 95660573Skris char *target, *originator; 957192595Sdes u_short target_port, originator_port; 95860573Skris 95960573Skris target = packet_get_string(NULL); 96060573Skris target_port = packet_get_int(); 96160573Skris originator = packet_get_string(NULL); 96260573Skris originator_port = packet_get_int(); 96392559Sdes packet_check_eom(); 96461209Skris 965181111Sdes debug("server_request_direct_tcpip: originator %s port %d, target %s " 966181111Sdes "port %d", originator, originator_port, target, target_port); 96765668Skris 968248619Sdes /* XXX fine grained permissions */ 969248619Sdes if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && 970248619Sdes !no_port_forwarding_flag) { 971295367Sdes c = channel_connect_to_port(target, target_port, 972248619Sdes "direct-tcpip", "direct-tcpip"); 973248619Sdes } else { 974248619Sdes logit("refused local port forward: " 975248619Sdes "originator %s port %d, target %s port %d", 976248619Sdes originator, originator_port, target, target_port); 977248619Sdes } 978181111Sdes 979255767Sdes free(originator); 980255767Sdes free(target); 981181111Sdes 98292559Sdes return c; 98360573Skris} 98460573Skris 98592559Sdesstatic Channel * 986295367Sdesserver_request_direct_streamlocal(void) 987295367Sdes{ 988295367Sdes Channel *c = NULL; 989295367Sdes char *target, *originator; 990295367Sdes u_short originator_port; 991295367Sdes 992295367Sdes target = packet_get_string(NULL); 993295367Sdes originator = packet_get_string(NULL); 994295367Sdes originator_port = packet_get_int(); 995295367Sdes packet_check_eom(); 996295367Sdes 997295367Sdes debug("server_request_direct_streamlocal: originator %s port %d, target %s", 998295367Sdes originator, originator_port, target); 999295367Sdes 1000295367Sdes /* XXX fine grained permissions */ 1001295367Sdes if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && 1002323124Sdes !no_port_forwarding_flag) { 1003295367Sdes c = channel_connect_to_path(target, 1004295367Sdes "direct-streamlocal@openssh.com", "direct-streamlocal"); 1005295367Sdes } else { 1006295367Sdes logit("refused streamlocal port forward: " 1007295367Sdes "originator %s port %d, target %s", 1008295367Sdes originator, originator_port, target); 1009295367Sdes } 1010295367Sdes 1011295367Sdes free(originator); 1012295367Sdes free(target); 1013295367Sdes 1014295367Sdes return c; 1015295367Sdes} 1016295367Sdes 1017295367Sdesstatic Channel * 1018157019Sdesserver_request_tun(void) 1019157019Sdes{ 1020157019Sdes Channel *c = NULL; 1021157019Sdes int mode, tun; 1022157019Sdes int sock; 1023157019Sdes 1024157019Sdes mode = packet_get_int(); 1025157019Sdes switch (mode) { 1026157019Sdes case SSH_TUNMODE_POINTOPOINT: 1027157019Sdes case SSH_TUNMODE_ETHERNET: 1028157019Sdes break; 1029157019Sdes default: 1030157019Sdes packet_send_debug("Unsupported tunnel device mode."); 1031157019Sdes return NULL; 1032157019Sdes } 1033157019Sdes if ((options.permit_tun & mode) == 0) { 1034157019Sdes packet_send_debug("Server has rejected tunnel device " 1035157019Sdes "forwarding"); 1036157019Sdes return NULL; 1037157019Sdes } 1038157019Sdes 1039157019Sdes tun = packet_get_int(); 1040157019Sdes if (forced_tun_device != -1) { 1041162856Sdes if (tun != SSH_TUNID_ANY && forced_tun_device != tun) 1042157019Sdes goto done; 1043157019Sdes tun = forced_tun_device; 1044157019Sdes } 1045157019Sdes sock = tun_open(tun, mode); 1046157019Sdes if (sock < 0) 1047157019Sdes goto done; 1048294693Sdes c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, 1049294693Sdes CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); 1050157019Sdes c->datagram = 1; 1051157019Sdes#if defined(SSH_TUN_FILTER) 1052157019Sdes if (mode == SSH_TUNMODE_POINTOPOINT) 1053157019Sdes channel_register_filter(c->self, sys_tun_infilter, 1054181111Sdes sys_tun_outfilter, NULL, NULL); 1055157019Sdes#endif 1056157019Sdes 1057157019Sdes done: 1058157019Sdes if (c == NULL) 1059157019Sdes packet_send_debug("Failed to open the tunnel device."); 1060157019Sdes return c; 1061157019Sdes} 1062157019Sdes 1063157019Sdesstatic Channel * 1064126277Sdesserver_request_session(void) 106576262Sgreen{ 106692559Sdes Channel *c; 106776262Sgreen 106876262Sgreen debug("input_session_request"); 106992559Sdes packet_check_eom(); 1070181111Sdes 1071181111Sdes if (no_more_sessions) { 1072181111Sdes packet_disconnect("Possible attack: attempt to open a session " 1073181111Sdes "after additional sessions disabled"); 1074181111Sdes } 1075181111Sdes 107676262Sgreen /* 107776262Sgreen * A server session has no fd to read or write until a 107876262Sgreen * CHANNEL_REQUEST for a shell is made, so we set the type to 107976262Sgreen * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all 108076262Sgreen * CHANNEL_REQUEST messages is registered. 108176262Sgreen */ 1082126277Sdes c = channel_new("session", SSH_CHANNEL_LARVAL, 108392559Sdes -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 1084124211Sdes 0, "server-session", 1); 1085126277Sdes if (session_open(the_authctxt, c->self) != 1) { 108692559Sdes debug("session open failed, free channel %d", c->self); 108792559Sdes channel_free(c); 108892559Sdes return NULL; 108976262Sgreen } 1090157019Sdes channel_register_cleanup(c->self, session_close_by_channel, 0); 109192559Sdes return c; 109276262Sgreen} 109376262Sgreen 1094295367Sdesstatic int 109592559Sdesserver_input_channel_open(int type, u_int32_t seq, void *ctxt) 109660573Skris{ 109760573Skris Channel *c = NULL; 109860573Skris char *ctype; 109960573Skris int rchan; 110099063Sdes u_int rmaxpack, rwindow, len; 110160573Skris 110260573Skris ctype = packet_get_string(&len); 110360573Skris rchan = packet_get_int(); 110460573Skris rwindow = packet_get_int(); 110560573Skris rmaxpack = packet_get_int(); 110660573Skris 110769587Sgreen debug("server_input_channel_open: ctype %s rchan %d win %d max %d", 110860573Skris ctype, rchan, rwindow, rmaxpack); 110960573Skris 111060573Skris if (strcmp(ctype, "session") == 0) { 1111126277Sdes c = server_request_session(); 111260573Skris } else if (strcmp(ctype, "direct-tcpip") == 0) { 1113126277Sdes c = server_request_direct_tcpip(); 1114295367Sdes } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) { 1115295367Sdes c = server_request_direct_streamlocal(); 1116157019Sdes } else if (strcmp(ctype, "tun@openssh.com") == 0) { 1117157019Sdes c = server_request_tun(); 111860573Skris } 111960573Skris if (c != NULL) { 112076262Sgreen debug("server_input_channel_open: confirm %s", ctype); 112160573Skris c->remote_id = rchan; 112260573Skris c->remote_window = rwindow; 112360573Skris c->remote_maxpacket = rmaxpack; 112492559Sdes if (c->type != SSH_CHANNEL_CONNECTING) { 112592559Sdes packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 112692559Sdes packet_put_int(c->remote_id); 112792559Sdes packet_put_int(c->self); 112892559Sdes packet_put_int(c->local_window); 112992559Sdes packet_put_int(c->local_maxpacket); 113092559Sdes packet_send(); 113192559Sdes } 113260573Skris } else { 113376262Sgreen debug("server_input_channel_open: failure %s", ctype); 113460573Skris packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 113560573Skris packet_put_int(rchan); 113660573Skris packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); 113792559Sdes if (!(datafellows & SSH_BUG_OPENFAILURE)) { 113892559Sdes packet_put_cstring("open failed"); 113992559Sdes packet_put_cstring(""); 114092559Sdes } 114160573Skris packet_send(); 114260573Skris } 1143255767Sdes free(ctype); 1144295367Sdes return 0; 114560573Skris} 114660573Skris 1147295367Sdesstatic int 1148295367Sdesserver_input_hostkeys_prove(struct sshbuf **respp) 1149295367Sdes{ 1150295367Sdes struct ssh *ssh = active_state; /* XXX */ 1151295367Sdes struct sshbuf *resp = NULL; 1152295367Sdes struct sshbuf *sigbuf = NULL; 1153295367Sdes struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; 1154295367Sdes int r, ndx, success = 0; 1155295367Sdes const u_char *blob; 1156295367Sdes u_char *sig = 0; 1157295367Sdes size_t blen, slen; 1158295367Sdes 1159295367Sdes if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) 1160295367Sdes fatal("%s: sshbuf_new", __func__); 1161295367Sdes 1162295367Sdes while (ssh_packet_remaining(ssh) > 0) { 1163295367Sdes sshkey_free(key); 1164295367Sdes key = NULL; 1165295367Sdes if ((r = sshpkt_get_string_direct(ssh, &blob, &blen)) != 0 || 1166295367Sdes (r = sshkey_from_blob(blob, blen, &key)) != 0) { 1167295367Sdes error("%s: couldn't parse key: %s", 1168295367Sdes __func__, ssh_err(r)); 1169295367Sdes goto out; 1170295367Sdes } 1171295367Sdes /* 1172295367Sdes * Better check that this is actually one of our hostkeys 1173295367Sdes * before attempting to sign anything with it. 1174295367Sdes */ 1175295367Sdes if ((ndx = ssh->kex->host_key_index(key, 1, ssh)) == -1) { 1176295367Sdes error("%s: unknown host %s key", 1177295367Sdes __func__, sshkey_type(key)); 1178295367Sdes goto out; 1179295367Sdes } 1180295367Sdes /* 1181295367Sdes * XXX refactor: make kex->sign just use an index rather 1182295367Sdes * than passing in public and private keys 1183295367Sdes */ 1184295367Sdes if ((key_prv = get_hostkey_by_index(ndx)) == NULL && 1185295367Sdes (key_pub = get_hostkey_public_by_index(ndx, ssh)) == NULL) { 1186295367Sdes error("%s: can't retrieve hostkey %d", __func__, ndx); 1187295367Sdes goto out; 1188295367Sdes } 1189295367Sdes sshbuf_reset(sigbuf); 1190295367Sdes free(sig); 1191295367Sdes sig = NULL; 1192295367Sdes if ((r = sshbuf_put_cstring(sigbuf, 1193295367Sdes "hostkeys-prove-00@openssh.com")) != 0 || 1194295367Sdes (r = sshbuf_put_string(sigbuf, 1195295367Sdes ssh->kex->session_id, ssh->kex->session_id_len)) != 0 || 1196295367Sdes (r = sshkey_puts(key, sigbuf)) != 0 || 1197295367Sdes (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen, 1198296781Sdes sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), NULL, 0)) != 0 || 1199295367Sdes (r = sshbuf_put_string(resp, sig, slen)) != 0) { 1200295367Sdes error("%s: couldn't prepare signature: %s", 1201295367Sdes __func__, ssh_err(r)); 1202295367Sdes goto out; 1203295367Sdes } 1204295367Sdes } 1205295367Sdes /* Success */ 1206295367Sdes *respp = resp; 1207295367Sdes resp = NULL; /* don't free it */ 1208295367Sdes success = 1; 1209295367Sdes out: 1210295367Sdes free(sig); 1211295367Sdes sshbuf_free(resp); 1212295367Sdes sshbuf_free(sigbuf); 1213295367Sdes sshkey_free(key); 1214295367Sdes return success; 1215295367Sdes} 1216295367Sdes 1217295367Sdesstatic int 121892559Sdesserver_input_global_request(int type, u_int32_t seq, void *ctxt) 121960573Skris{ 122076262Sgreen char *rtype; 122176262Sgreen int want_reply; 1222295367Sdes int r, success = 0, allocated_listen_port = 0; 1223295367Sdes struct sshbuf *resp = NULL; 122476262Sgreen 122576262Sgreen rtype = packet_get_string(NULL); 122676262Sgreen want_reply = packet_get_char(); 122776262Sgreen debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply); 122876262Sgreen 122976262Sgreen /* -R style forwarding */ 123076262Sgreen if (strcmp(rtype, "tcpip-forward") == 0) { 123176262Sgreen struct passwd *pw; 1232295367Sdes struct Forward fwd; 123376262Sgreen 1234126277Sdes pw = the_authctxt->pw; 1235126277Sdes if (pw == NULL || !the_authctxt->valid) 1236126277Sdes fatal("server_input_global_request: no/invalid user"); 1237295367Sdes memset(&fwd, 0, sizeof(fwd)); 1238295367Sdes fwd.listen_host = packet_get_string(NULL); 1239295367Sdes fwd.listen_port = (u_short)packet_get_int(); 124076262Sgreen debug("server_input_global_request: tcpip-forward listen %s port %d", 1241295367Sdes fwd.listen_host, fwd.listen_port); 124276262Sgreen 124376262Sgreen /* check permissions */ 1244248619Sdes if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 || 1245192595Sdes no_port_forwarding_flag || 1246323124Sdes (!want_reply && fwd.listen_port == 0) || 1247323124Sdes (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED && 1248323124Sdes pw->pw_uid != 0)) { 124976262Sgreen success = 0; 125076262Sgreen packet_send_debug("Server has disabled port forwarding."); 125176262Sgreen } else { 125276262Sgreen /* Start listening on the port */ 1253295367Sdes success = channel_setup_remote_fwd_listener(&fwd, 1254295367Sdes &allocated_listen_port, &options.fwd_opts); 125576262Sgreen } 1256295367Sdes free(fwd.listen_host); 1257295367Sdes if ((resp = sshbuf_new()) == NULL) 1258295367Sdes fatal("%s: sshbuf_new", __func__); 1259296781Sdes if (allocated_listen_port != 0 && 1260296781Sdes (r = sshbuf_put_u32(resp, allocated_listen_port)) != 0) 1261295367Sdes fatal("%s: sshbuf_put_u32: %s", __func__, ssh_err(r)); 1262137019Sdes } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { 1263295367Sdes struct Forward fwd; 1264137019Sdes 1265295367Sdes memset(&fwd, 0, sizeof(fwd)); 1266295367Sdes fwd.listen_host = packet_get_string(NULL); 1267295367Sdes fwd.listen_port = (u_short)packet_get_int(); 1268137019Sdes debug("%s: cancel-tcpip-forward addr %s port %d", __func__, 1269295367Sdes fwd.listen_host, fwd.listen_port); 1270137019Sdes 1271295367Sdes success = channel_cancel_rport_listener(&fwd); 1272295367Sdes free(fwd.listen_host); 1273295367Sdes } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) { 1274295367Sdes struct Forward fwd; 1275295367Sdes 1276295367Sdes memset(&fwd, 0, sizeof(fwd)); 1277295367Sdes fwd.listen_path = packet_get_string(NULL); 1278295367Sdes debug("server_input_global_request: streamlocal-forward listen path %s", 1279295367Sdes fwd.listen_path); 1280295367Sdes 1281295367Sdes /* check permissions */ 1282295367Sdes if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 1283323124Sdes || no_port_forwarding_flag) { 1284295367Sdes success = 0; 1285295367Sdes packet_send_debug("Server has disabled port forwarding."); 1286295367Sdes } else { 1287295367Sdes /* Start listening on the socket */ 1288295367Sdes success = channel_setup_remote_fwd_listener( 1289295367Sdes &fwd, NULL, &options.fwd_opts); 1290295367Sdes } 1291295367Sdes free(fwd.listen_path); 1292295367Sdes } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) { 1293295367Sdes struct Forward fwd; 1294295367Sdes 1295295367Sdes memset(&fwd, 0, sizeof(fwd)); 1296295367Sdes fwd.listen_path = packet_get_string(NULL); 1297295367Sdes debug("%s: cancel-streamlocal-forward path %s", __func__, 1298295367Sdes fwd.listen_path); 1299295367Sdes 1300295367Sdes success = channel_cancel_rport_listener(&fwd); 1301295367Sdes free(fwd.listen_path); 1302181111Sdes } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) { 1303181111Sdes no_more_sessions = 1; 1304181111Sdes success = 1; 1305295367Sdes } else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) { 1306295367Sdes success = server_input_hostkeys_prove(&resp); 130776262Sgreen } 130876262Sgreen if (want_reply) { 130976262Sgreen packet_start(success ? 131076262Sgreen SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 1311295367Sdes if (success && resp != NULL) 1312295367Sdes ssh_packet_put_raw(active_state, sshbuf_ptr(resp), 1313295367Sdes sshbuf_len(resp)); 131476262Sgreen packet_send(); 131576262Sgreen packet_write_wait(); 131676262Sgreen } 1317255767Sdes free(rtype); 1318295367Sdes sshbuf_free(resp); 1319295367Sdes return 0; 132076262Sgreen} 1321162856Sdes 1322295367Sdesstatic int 132392559Sdesserver_input_channel_req(int type, u_int32_t seq, void *ctxt) 132492559Sdes{ 132592559Sdes Channel *c; 132692559Sdes int id, reply, success = 0; 132792559Sdes char *rtype; 132876262Sgreen 132992559Sdes id = packet_get_int(); 133092559Sdes rtype = packet_get_string(NULL); 133192559Sdes reply = packet_get_char(); 133292559Sdes 133392559Sdes debug("server_input_channel_req: channel %d request %s reply %d", 133492559Sdes id, rtype, reply); 133592559Sdes 133692559Sdes if ((c = channel_lookup(id)) == NULL) 133792559Sdes packet_disconnect("server_input_channel_req: " 133892559Sdes "unknown channel %d", id); 1339181111Sdes if (!strcmp(rtype, "eow@openssh.com")) { 1340181111Sdes packet_check_eom(); 1341181111Sdes chan_rcvd_eow(c); 1342181111Sdes } else if ((c->type == SSH_CHANNEL_LARVAL || 1343181111Sdes c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0) 134492559Sdes success = session_input_channel_req(c, rtype); 1345295367Sdes if (reply && !(c->flags & CHAN_CLOSE_SENT)) { 134692559Sdes packet_start(success ? 134792559Sdes SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 134892559Sdes packet_put_int(c->remote_id); 134992559Sdes packet_send(); 135092559Sdes } 1351255767Sdes free(rtype); 1352295367Sdes return 0; 135392559Sdes} 135492559Sdes 135592559Sdesstatic void 135676262Sgreenserver_init_dispatch_20(void) 135776262Sgreen{ 135860573Skris debug("server_init_dispatch_20"); 135960573Skris dispatch_init(&dispatch_protocol_error); 136060573Skris dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); 136160573Skris dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); 136260573Skris dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); 136360573Skris dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); 136460573Skris dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open); 136560573Skris dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 136660573Skris dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 136792559Sdes dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); 136860573Skris dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); 136976262Sgreen dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); 137076262Sgreen /* client_alive */ 1371192595Sdes dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive); 1372192595Sdes dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive); 1373126277Sdes dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); 1374126277Sdes dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); 137576262Sgreen /* rekeying */ 137676262Sgreen dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 137760573Skris} 137892559Sdesstatic void 137976262Sgreenserver_init_dispatch_13(void) 138060573Skris{ 138160573Skris debug("server_init_dispatch_13"); 138260573Skris dispatch_init(NULL); 138360573Skris dispatch_set(SSH_CMSG_EOF, &server_input_eof); 138460573Skris dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); 138560573Skris dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); 138660573Skris dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); 138760573Skris dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); 138860573Skris dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); 138960573Skris dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 139060573Skris dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 139160573Skris dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); 139260573Skris} 139392559Sdesstatic void 139476262Sgreenserver_init_dispatch_15(void) 139560573Skris{ 139660573Skris server_init_dispatch_13(); 139760573Skris debug("server_init_dispatch_15"); 139860573Skris dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); 139960573Skris dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); 140060573Skris} 140192559Sdesstatic void 140276262Sgreenserver_init_dispatch(void) 140360573Skris{ 140460573Skris if (compat20) 140560573Skris server_init_dispatch_20(); 140660573Skris else if (compat13) 140760573Skris server_init_dispatch_13(); 140860573Skris else 140960573Skris server_init_dispatch_15(); 141060573Skris} 1411