clientloop.c revision 113908
1139749Simp/* 286752Sfjoe * Author: Tatu Ylonen <ylo@cs.hut.fi> 386752Sfjoe * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 486752Sfjoe * All rights reserved 586752Sfjoe * The main loop for the interactive session (client side). 686752Sfjoe * 786752Sfjoe * As far as I am concerned, the code I have written for this software 886752Sfjoe * can be used freely for any purpose. Any derived versions of this 986752Sfjoe * software must be clearly marked as such, and if the derived work is 1086752Sfjoe * incompatible with the protocol description in the RFC file, it must be 1186752Sfjoe * called by a name other than "ssh" or "Secure Shell". 1286752Sfjoe * 1386752Sfjoe * 1486752Sfjoe * Copyright (c) 1999 Theo de Raadt. All rights reserved. 1586752Sfjoe * 1686752Sfjoe * Redistribution and use in source and binary forms, with or without 1786752Sfjoe * modification, are permitted provided that the following conditions 1886752Sfjoe * are met: 1986752Sfjoe * 1. Redistributions of source code must retain the above copyright 2086752Sfjoe * notice, this list of conditions and the following disclaimer. 2186752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 2286752Sfjoe * notice, this list of conditions and the following disclaimer in the 2386752Sfjoe * documentation and/or other materials provided with the distribution. 2486752Sfjoe * 2586752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2686752Sfjoe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2786752Sfjoe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2886752Sfjoe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29119419Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30119419Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31119419Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3286752Sfjoe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3386752Sfjoe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3486752Sfjoe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3586752Sfjoe * 3686752Sfjoe * 3786752Sfjoe * SSH2 support added by Markus Friedl. 3886752Sfjoe * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. 3986752Sfjoe * 4086752Sfjoe * Redistribution and use in source and binary forms, with or without 4186752Sfjoe * modification, are permitted provided that the following conditions 4286752Sfjoe * are met: 4386752Sfjoe * 1. Redistributions of source code must retain the above copyright 4486752Sfjoe * notice, this list of conditions and the following disclaimer. 4586752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 4686752Sfjoe * notice, this list of conditions and the following disclaimer in the 4786752Sfjoe * documentation and/or other materials provided with the distribution. 4886752Sfjoe * 4986752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 5086752Sfjoe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5186752Sfjoe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 5286752Sfjoe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5386752Sfjoe * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5486752Sfjoe * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5586752Sfjoe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5686752Sfjoe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5786752Sfjoe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5886752Sfjoe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5986752Sfjoe */ 6086752Sfjoe 6186752Sfjoe#include "includes.h" 6286752SfjoeRCSID("$OpenBSD: clientloop.c,v 1.107 2003/04/01 10:22:21 markus Exp $"); 6386752Sfjoe 6486752Sfjoe#include "ssh.h" 65180263Sjhb#include "ssh1.h" 6686752Sfjoe#include "ssh2.h" 6786752Sfjoe#include "xmalloc.h" 6886752Sfjoe#include "packet.h" 6986752Sfjoe#include "buffer.h" 7086752Sfjoe#include "compat.h" 71164033Srwatson#include "channels.h" 7286752Sfjoe#include "dispatch.h" 7386752Sfjoe#include "buffer.h" 7486752Sfjoe#include "bufaux.h" 75101400Sfjoe#include "key.h" 7686752Sfjoe#include "kex.h" 77101400Sfjoe#include "log.h" 78101400Sfjoe#include "readconf.h" 79101400Sfjoe#include "clientloop.h" 80101400Sfjoe#include "authfd.h" 8186752Sfjoe#include "atomicio.h" 82257176Sglebius#include "sshtty.h" 83152315Sru#include "misc.h" 8486752Sfjoe#include "readpass.h" 8586752Sfjoe 86147256Sbrooks/* import options */ 8786752Sfjoeextern Options options; 8886752Sfjoe 8986752Sfjoe/* Flag indicating that stdin should be redirected from /dev/null. */ 9086752Sfjoeextern int stdin_null_flag; 9186752Sfjoe 92180263Sjhb/* 9386752Sfjoe * Name of the host we are connecting to. This is the name given on the 94180263Sjhb * command line, or the HostName specified for the user-supplied name in a 9586752Sfjoe * configuration file. 9686752Sfjoe */ 9786752Sfjoeextern char *host; 9886752Sfjoe 9986752Sfjoe/* 10086752Sfjoe * Flag to indicate that we have received a window change signal which has 10186752Sfjoe * not yet been processed. This will cause a message indicating the new 10286752Sfjoe * window size to be sent to the server a little later. This is volatile 10386752Sfjoe * because this is updated in a signal handler. 10486752Sfjoe */ 10586752Sfjoestatic volatile sig_atomic_t received_window_change_signal = 0; 10686752Sfjoestatic volatile sig_atomic_t received_signal = 0; 10786752Sfjoe 10886752Sfjoe/* Flag indicating whether the user\'s terminal is in non-blocking mode. */ 10986752Sfjoestatic int in_non_blocking_mode = 0; 11086752Sfjoe 11186752Sfjoe/* Common data for the client loop code. */ 11286752Sfjoestatic int quit_pending; /* Set to non-zero to quit the client loop. */ 11386752Sfjoestatic int escape_char; /* Escape character. */ 11486752Sfjoestatic int escape_pending; /* Last character was the escape character */ 11586752Sfjoestatic int last_was_cr; /* Last character was a newline. */ 11686752Sfjoestatic int exit_status; /* Used to store the exit status of the command. */ 11786752Sfjoestatic int stdin_eof; /* EOF has been encountered on standard error. */ 11886752Sfjoestatic Buffer stdin_buffer; /* Buffer for stdin data. */ 11986752Sfjoestatic Buffer stdout_buffer; /* Buffer for stdout data. */ 12086752Sfjoestatic Buffer stderr_buffer; /* Buffer for stderr data. */ 12186752Sfjoestatic u_long stdin_bytes, stdout_bytes, stderr_bytes; 12286752Sfjoestatic u_int buffer_high;/* Soft max buffer size. */ 12386752Sfjoestatic int connection_in; /* Connection to server (input). */ 12486752Sfjoestatic int connection_out; /* Connection to server (output). */ 12586752Sfjoestatic int need_rekeying; /* Set to non-zero if rekeying is requested. */ 12686752Sfjoestatic int session_closed = 0; /* In SSH2: login session closed. */ 12786752Sfjoe 12886752Sfjoestatic void client_init_dispatch(void); 129180263Sjhbint session_ident = -1; 130180263Sjhb 131180263Sjhb/*XXX*/ 13286752Sfjoeextern Kex *xxx_kex; 13386752Sfjoe 13486752Sfjoe/* Restores stdin to blocking mode. */ 13586752Sfjoe 13686752Sfjoestatic void 13786752Sfjoeleave_non_blocking(void) 13886752Sfjoe{ 139101400Sfjoe if (in_non_blocking_mode) { 140101400Sfjoe (void) fcntl(fileno(stdin), F_SETFL, 0); 141101400Sfjoe in_non_blocking_mode = 0; 142101400Sfjoe fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL); 14386752Sfjoe } 14486752Sfjoe} 14586752Sfjoe 14686752Sfjoe/* Puts stdin terminal in non-blocking mode. */ 14786752Sfjoe 148101400Sfjoestatic void 149101400Sfjoeenter_non_blocking(void) 150101400Sfjoe{ 151101400Sfjoe in_non_blocking_mode = 1; 15286752Sfjoe (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); 15386752Sfjoe fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL); 15486752Sfjoe} 15586752Sfjoe 15686752Sfjoe/* 157101400Sfjoe * Signal handler for the window change signal (SIGWINCH). This just sets a 158101400Sfjoe * flag indicating that the window has changed. 159101400Sfjoe */ 160101400Sfjoe 16186752Sfjoestatic void 16286752Sfjoewindow_change_handler(int sig) 16386752Sfjoe{ 16486752Sfjoe received_window_change_signal = 1; 16586752Sfjoe signal(SIGWINCH, window_change_handler); 166101400Sfjoe} 167101400Sfjoe 168101400Sfjoe/* 169101400Sfjoe * Signal handler for signals that cause the program to terminate. These 17086752Sfjoe * signals must be trapped to restore terminal modes. 17186752Sfjoe */ 17286752Sfjoe 17386752Sfjoestatic void 17486752Sfjoesignal_handler(int sig) 17586752Sfjoe{ 17686752Sfjoe received_signal = sig; 17786752Sfjoe quit_pending = 1; 17886752Sfjoe} 17986752Sfjoe 18086752Sfjoe/* 18186752Sfjoe * Returns current time in seconds from Jan 1, 1970 with the maximum 18286752Sfjoe * available resolution. 18386752Sfjoe */ 18486752Sfjoe 18586752Sfjoestatic double 18686752Sfjoeget_current_time(void) 18786752Sfjoe{ 18886752Sfjoe struct timeval tv; 18986752Sfjoe gettimeofday(&tv, NULL); 19086752Sfjoe return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; 19186752Sfjoe} 19286752Sfjoe 19386752Sfjoe/* 19486752Sfjoe * This is called when the interactive is entered. This checks if there is 19586752Sfjoe * an EOF coming on stdin. We must check this explicitly, as select() does 19686752Sfjoe * not appear to wake up when redirecting from /dev/null. 19786752Sfjoe */ 19886752Sfjoe 19986752Sfjoestatic void 20086752Sfjoeclient_check_initial_eof_on_stdin(void) 20186752Sfjoe{ 20286752Sfjoe int len; 20386752Sfjoe char buf[1]; 20486752Sfjoe 20586752Sfjoe /* 20686752Sfjoe * If standard input is to be "redirected from /dev/null", we simply 20786752Sfjoe * mark that we have seen an EOF and send an EOF message to the 20886752Sfjoe * server. Otherwise, we try to read a single character; it appears 20986752Sfjoe * that for some files, such /dev/null, select() never wakes up for 21086752Sfjoe * read for this descriptor, which means that we never get EOF. This 21186752Sfjoe * way we will get the EOF if stdin comes from /dev/null or similar. 21286752Sfjoe */ 21386752Sfjoe if (stdin_null_flag) { 21486752Sfjoe /* Fake EOF on stdin. */ 21586752Sfjoe debug("Sending eof."); 21686752Sfjoe stdin_eof = 1; 21786752Sfjoe packet_start(SSH_CMSG_EOF); 21886752Sfjoe packet_send(); 21986752Sfjoe } else { 22086752Sfjoe enter_non_blocking(); 221180263Sjhb 22286752Sfjoe /* Check for immediate EOF on stdin. */ 22386752Sfjoe len = read(fileno(stdin), buf, 1); 22486752Sfjoe if (len == 0) { 22586752Sfjoe /* EOF. Record that we have seen it and send EOF to server. */ 22686752Sfjoe debug("Sending eof."); 227147256Sbrooks stdin_eof = 1; 228147256Sbrooks packet_start(SSH_CMSG_EOF); 229180263Sjhb packet_send(); 23086752Sfjoe } else if (len > 0) { 23186752Sfjoe /* 23286752Sfjoe * Got data. We must store the data in the buffer, 233121752Sbrooks * and also process it as an escape character if 234121752Sbrooks * appropriate. 235121816Sbrooks */ 236121752Sbrooks if ((u_char) buf[0] == escape_char) 237121752Sbrooks escape_pending = 1; 238121752Sbrooks else 239207554Ssobomax buffer_append(&stdin_buffer, buf, 1); 24086752Sfjoe } 241121752Sbrooks leave_non_blocking(); 242121752Sbrooks } 243121752Sbrooks} 244121752Sbrooks 24586752Sfjoe 246180263Sjhb/* 247180263Sjhb * Make packets from buffered stdin data, and buffer them for sending to the 248180263Sjhb * connection. 249180263Sjhb */ 250147256Sbrooks 25186752Sfjoestatic void 25286752Sfjoeclient_make_packets_from_stdin_data(void) 253263102Sglebius{ 25486752Sfjoe u_int len; 25586752Sfjoe 25686752Sfjoe /* Send buffered stdin data to the server. */ 25786752Sfjoe while (buffer_len(&stdin_buffer) > 0 && 258180263Sjhb packet_not_very_much_data_to_write()) { 25986752Sfjoe len = buffer_len(&stdin_buffer); 26086752Sfjoe /* Keep the packets at reasonable size. */ 261180263Sjhb if (len > packet_get_maxsize()) 262180263Sjhb len = packet_get_maxsize(); 263180263Sjhb packet_start(SSH_CMSG_STDIN_DATA); 264180263Sjhb packet_put_string(buffer_ptr(&stdin_buffer), len); 265180263Sjhb packet_send(); 266180263Sjhb buffer_consume(&stdin_buffer, len); 267180263Sjhb stdin_bytes += len; 268180263Sjhb /* If we have a pending EOF, send it now. */ 269180263Sjhb if (stdin_eof && buffer_len(&stdin_buffer) == 0) { 270180263Sjhb packet_start(SSH_CMSG_EOF); 271180263Sjhb packet_send(); 272180263Sjhb } 273180263Sjhb } 274180263Sjhb} 275180263Sjhb 276180263Sjhb/* 277180263Sjhb * Checks if the client window has changed, and sends a packet about it to 278180263Sjhb * the server if so. The actual change is detected elsewhere (by a software 279180263Sjhb * interrupt on Unix); this just checks the flag and sends a message if 280180263Sjhb * appropriate. 281180263Sjhb */ 282180263Sjhb 283180263Sjhbstatic void 284180263Sjhbclient_check_window_change(void) 285180263Sjhb{ 286180263Sjhb struct winsize ws; 287180263Sjhb 28886752Sfjoe if (! received_window_change_signal) 28986752Sfjoe return; 29086752Sfjoe /** XXX race */ 29186752Sfjoe received_window_change_signal = 0; 29286752Sfjoe 29386752Sfjoe if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) 294180263Sjhb return; 295180263Sjhb 296180263Sjhb debug2("client_check_window_change: changed"); 297180263Sjhb 298180263Sjhb if (compat20) { 299180263Sjhb channel_request_start(session_ident, "window-change", 0); 300180263Sjhb packet_put_int(ws.ws_col); 301180263Sjhb packet_put_int(ws.ws_row); 302180263Sjhb packet_put_int(ws.ws_xpixel); 303180263Sjhb packet_put_int(ws.ws_ypixel); 30486752Sfjoe packet_send(); 30586752Sfjoe } else { 306147256Sbrooks packet_start(SSH_CMSG_WINDOW_SIZE); 30786752Sfjoe packet_put_int(ws.ws_row); 30886752Sfjoe packet_put_int(ws.ws_col); 30986752Sfjoe packet_put_int(ws.ws_xpixel); 31086752Sfjoe packet_put_int(ws.ws_ypixel); 31186752Sfjoe packet_send(); 312148887Srwatson } 31386752Sfjoe} 31486752Sfjoe 31586752Sfjoe/* 316180263Sjhb * Waits until the client can do something (some data becomes available on 31786752Sfjoe * one of the file descriptors). 318148887Srwatson */ 319148887Srwatson 32086752Sfjoestatic void 32186752Sfjoeclient_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, 322180263Sjhb int *maxfdp, int *nallocp, int rekeying) 32386752Sfjoe{ 32486752Sfjoe /* Add any selections by the channel mechanism. */ 32586752Sfjoe channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); 32686752Sfjoe 32786752Sfjoe if (!compat20) { 32886752Sfjoe /* Read from the connection, unless our buffers are full. */ 329180263Sjhb if (buffer_len(&stdout_buffer) < buffer_high && 330180263Sjhb buffer_len(&stderr_buffer) < buffer_high && 331180263Sjhb channel_not_very_much_buffered_data()) 332180263Sjhb FD_SET(connection_in, *readsetp); 333180263Sjhb /* 334180263Sjhb * Read from stdin, unless we have seen EOF or have very much 335180263Sjhb * buffered data to send to the server. 336180263Sjhb */ 337180263Sjhb if (!stdin_eof && packet_not_very_much_data_to_write()) 338180263Sjhb FD_SET(fileno(stdin), *readsetp); 339180263Sjhb 34086752Sfjoe /* Select stdout/stderr if have data in buffer. */ 34186752Sfjoe if (buffer_len(&stdout_buffer) > 0) 34286752Sfjoe FD_SET(fileno(stdout), *writesetp); 34386752Sfjoe if (buffer_len(&stderr_buffer) > 0) 34486752Sfjoe FD_SET(fileno(stderr), *writesetp); 34586752Sfjoe } else { 34686752Sfjoe /* channel_prepare_select could have closed the last channel */ 34786752Sfjoe if (session_closed && !channel_still_open() && 34886752Sfjoe !packet_have_data_to_write()) { 34986752Sfjoe /* clear mask since we did not call select() */ 35086752Sfjoe memset(*readsetp, 0, *nallocp); 35186752Sfjoe memset(*writesetp, 0, *nallocp); 35286752Sfjoe return; 35386752Sfjoe } else { 35486752Sfjoe FD_SET(connection_in, *readsetp); 35586752Sfjoe } 356180263Sjhb } 357180263Sjhb 35886752Sfjoe /* Select server connection if have data to write to the server. */ 35986752Sfjoe if (packet_have_data_to_write()) 36086752Sfjoe FD_SET(connection_out, *writesetp); 36186752Sfjoe 36286752Sfjoe /* 36386752Sfjoe * Wait for something to happen. This will suspend the process until 36486752Sfjoe * some selected descriptor can be read, written, or has some other 36586752Sfjoe * event pending. Note: if you want to implement SSH_MSG_IGNORE 36686752Sfjoe * messages to fool traffic analysis, this might be the place to do 36786752Sfjoe * it: just have a random timeout for the select, and send a random 36886752Sfjoe * SSH_MSG_IGNORE packet when the timeout expires. 36986752Sfjoe */ 37086752Sfjoe 37186752Sfjoe if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { 37286752Sfjoe char buf[100]; 37386752Sfjoe 37486752Sfjoe /* 37586752Sfjoe * We have to clear the select masks, because we return. 37686752Sfjoe * We have to return, because the mainloop checks for the flags 37786752Sfjoe * set by the signal handlers. 37886752Sfjoe */ 37986752Sfjoe memset(*readsetp, 0, *nallocp); 38086752Sfjoe memset(*writesetp, 0, *nallocp); 38186752Sfjoe 38286752Sfjoe if (errno == EINTR) 38386752Sfjoe return; 38486752Sfjoe /* Note: we might still have data in the buffers. */ 38586752Sfjoe snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); 38686752Sfjoe buffer_append(&stderr_buffer, buf, strlen(buf)); 387180263Sjhb quit_pending = 1; 38886752Sfjoe } 38986752Sfjoe} 39086752Sfjoe 39186752Sfjoestatic void 392180263Sjhbclient_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) 393180263Sjhb{ 394180263Sjhb struct winsize oldws, newws; 395180263Sjhb 396180263Sjhb /* Flush stdout and stderr buffers. */ 397180263Sjhb if (buffer_len(bout) > 0) 398180263Sjhb atomicio(write, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); 399180263Sjhb if (buffer_len(berr) > 0) 400180263Sjhb atomicio(write, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); 40186752Sfjoe 40286752Sfjoe leave_raw_mode(); 40386752Sfjoe 40486752Sfjoe /* 40586752Sfjoe * Free (and clear) the buffer to reduce the amount of data that gets 40686752Sfjoe * written to swap. 40786752Sfjoe */ 40886752Sfjoe buffer_free(bin); 40986752Sfjoe buffer_free(bout); 41086752Sfjoe buffer_free(berr); 41186752Sfjoe 41286752Sfjoe /* Save old window size. */ 41386752Sfjoe ioctl(fileno(stdin), TIOCGWINSZ, &oldws); 41486752Sfjoe 41586752Sfjoe /* Send the suspend signal to the program itself. */ 41686752Sfjoe kill(getpid(), SIGTSTP); 41786752Sfjoe 41886752Sfjoe /* Check if the window size has changed. */ 41986752Sfjoe if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && 42086752Sfjoe (oldws.ws_row != newws.ws_row || 42186752Sfjoe oldws.ws_col != newws.ws_col || 42286752Sfjoe oldws.ws_xpixel != newws.ws_xpixel || 42386752Sfjoe oldws.ws_ypixel != newws.ws_ypixel)) 42486752Sfjoe received_window_change_signal = 1; 42586752Sfjoe 42686752Sfjoe /* OK, we have been continued by the user. Reinitialize buffers. */ 42786752Sfjoe buffer_init(bin); 42886752Sfjoe buffer_init(bout); 42986752Sfjoe buffer_init(berr); 43086752Sfjoe 431180263Sjhb enter_raw_mode(); 43286752Sfjoe} 43386752Sfjoe 43486752Sfjoestatic void 43586752Sfjoeclient_process_net_input(fd_set * readset) 436101393Sfjoe{ 43786752Sfjoe int len; 43886752Sfjoe char buf[8192]; 439101393Sfjoe 44086752Sfjoe /* 44186752Sfjoe * Read input from the server, and add any such data to the buffer of 44286752Sfjoe * the packet subsystem. 44386752Sfjoe */ 44486752Sfjoe if (FD_ISSET(connection_in, readset)) { 44586752Sfjoe /* Read as much as possible. */ 44686752Sfjoe len = read(connection_in, buf, sizeof(buf)); 44786752Sfjoe if (len == 0) { 44886752Sfjoe /* Received EOF. The remote host has closed the connection. */ 44986752Sfjoe snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", 45086752Sfjoe host); 45186752Sfjoe buffer_append(&stderr_buffer, buf, strlen(buf)); 45286752Sfjoe quit_pending = 1; 45386752Sfjoe return; 45486752Sfjoe } 45586752Sfjoe /* 45686752Sfjoe * There is a kernel bug on Solaris that causes select to 45786752Sfjoe * sometimes wake up even though there is no data available. 45886752Sfjoe */ 45986752Sfjoe if (len < 0 && (errno == EAGAIN || errno == EINTR)) 460101393Sfjoe len = 0; 461101393Sfjoe 462101393Sfjoe if (len < 0) { 46386752Sfjoe /* An error has encountered. Perhaps there is a network problem. */ 46486752Sfjoe snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", 465171243Speter host, strerror(errno)); 466171243Speter buffer_append(&stderr_buffer, buf, strlen(buf)); 46786752Sfjoe quit_pending = 1; 468171243Speter return; 46986752Sfjoe } 47086752Sfjoe packet_process_incoming(buf, len); 47186752Sfjoe } 47286752Sfjoe} 47386752Sfjoe 47486752Sfjoestatic void 47586752Sfjoeprocess_cmdline(void) 47686752Sfjoe{ 47786752Sfjoe void (*handler)(int); 47886752Sfjoe char *s, *cmd; 47986752Sfjoe u_short fwd_port, fwd_host_port; 48086752Sfjoe char buf[1024], sfwd_port[6], sfwd_host_port[6]; 48186752Sfjoe int local = 0; 48286752Sfjoe 48386752Sfjoe leave_raw_mode(); 48486752Sfjoe handler = signal(SIGINT, SIG_IGN); 48586752Sfjoe cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); 48686752Sfjoe if (s == NULL) 48786752Sfjoe goto out; 48886752Sfjoe while (*s && isspace(*s)) 48986752Sfjoe s++; 49086752Sfjoe if (*s == 0) 49186752Sfjoe goto out; 49286752Sfjoe if (strlen(s) < 2 || s[0] != '-' || !(s[1] == 'L' || s[1] == 'R')) { 49386752Sfjoe log("Invalid command."); 49486752Sfjoe goto out; 49586752Sfjoe } 49686752Sfjoe if (s[1] == 'L') 49786752Sfjoe local = 1; 49886752Sfjoe if (!local && !compat20) { 49986752Sfjoe log("Not supported for SSH protocol version 1."); 50086752Sfjoe goto out; 50186752Sfjoe } 50286752Sfjoe s += 2; 50386752Sfjoe while (*s && isspace(*s)) 50486752Sfjoe s++; 50586752Sfjoe 50686752Sfjoe if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]", 50786752Sfjoe sfwd_port, buf, sfwd_host_port) != 3 && 50886752Sfjoe sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]", 50986752Sfjoe sfwd_port, buf, sfwd_host_port) != 3) { 51086752Sfjoe log("Bad forwarding specification."); 51186752Sfjoe goto out; 51286752Sfjoe } 51386752Sfjoe if ((fwd_port = a2port(sfwd_port)) == 0 || 51486752Sfjoe (fwd_host_port = a2port(sfwd_host_port)) == 0) { 51586752Sfjoe log("Bad forwarding port(s)."); 51686752Sfjoe goto out; 51786752Sfjoe } 51886752Sfjoe if (local) { 51986752Sfjoe if (channel_setup_local_fwd_listener(fwd_port, buf, 52086752Sfjoe fwd_host_port, options.gateway_ports) < 0) { 52186752Sfjoe log("Port forwarding failed."); 52286752Sfjoe goto out; 52386752Sfjoe } 52486752Sfjoe } else 52586752Sfjoe channel_request_remote_forwarding(fwd_port, buf, 52686752Sfjoe fwd_host_port); 52786752Sfjoe log("Forwarding port."); 52886752Sfjoeout: 52986752Sfjoe signal(SIGINT, handler); 53086752Sfjoe enter_raw_mode(); 53186752Sfjoe if (cmd) 53286752Sfjoe xfree(cmd); 53386752Sfjoe} 53486752Sfjoe 53586752Sfjoe/* process the characters one by one */ 53686752Sfjoestatic int 53786752Sfjoeprocess_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) 53886752Sfjoe{ 53986752Sfjoe char string[1024]; 54086752Sfjoe pid_t pid; 54186752Sfjoe int bytes = 0; 54286752Sfjoe u_int i; 54386752Sfjoe u_char ch; 54486752Sfjoe char *s; 54586752Sfjoe 54686752Sfjoe for (i = 0; i < len; i++) { 54786752Sfjoe /* Get one character at a time. */ 54886752Sfjoe ch = buf[i]; 54986752Sfjoe 55086752Sfjoe if (escape_pending) { 55186752Sfjoe /* We have previously seen an escape character. */ 55286752Sfjoe /* Clear the flag now. */ 55386752Sfjoe escape_pending = 0; 55486752Sfjoe 55586752Sfjoe /* Process the escaped character. */ 55686752Sfjoe switch (ch) { 55786752Sfjoe case '.': 55886752Sfjoe /* Terminate the connection. */ 55986752Sfjoe snprintf(string, sizeof string, "%c.\r\n", escape_char); 56086752Sfjoe buffer_append(berr, string, strlen(string)); 56186752Sfjoe 56286752Sfjoe quit_pending = 1; 56386752Sfjoe return -1; 56486752Sfjoe 56586752Sfjoe case 'Z' - 64: 56686752Sfjoe /* Suspend the program. */ 56786752Sfjoe /* Print a message to that effect to the user. */ 56886752Sfjoe snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); 569101393Sfjoe buffer_append(berr, string, strlen(string)); 570101393Sfjoe 571101393Sfjoe /* Restore terminal modes and suspend. */ 57286752Sfjoe client_suspend_self(bin, bout, berr); 57386752Sfjoe 57486752Sfjoe /* We have been continued. */ 57586752Sfjoe continue; 57686752Sfjoe 57786752Sfjoe case 'R': 57886752Sfjoe if (compat20) { 57986752Sfjoe if (datafellows & SSH_BUG_NOREKEY) 58086752Sfjoe log("Server does not support re-keying"); 58186752Sfjoe else 58286752Sfjoe need_rekeying = 1; 58386752Sfjoe } 58486752Sfjoe continue; 58586752Sfjoe 58686752Sfjoe case '&': 58786752Sfjoe /* 58886752Sfjoe * Detach the program (continue to serve connections, 58986752Sfjoe * but put in background and no more new connections). 59086752Sfjoe */ 59186752Sfjoe /* Restore tty modes. */ 59286752Sfjoe leave_raw_mode(); 59386752Sfjoe 59486752Sfjoe /* Stop listening for new connections. */ 59586752Sfjoe channel_stop_listening(); 59686752Sfjoe 59786752Sfjoe snprintf(string, sizeof string, 59886752Sfjoe "%c& [backgrounded]\n", escape_char); 59986752Sfjoe buffer_append(berr, string, strlen(string)); 60086752Sfjoe 60186752Sfjoe /* Fork into background. */ 60286752Sfjoe pid = fork(); 60386752Sfjoe if (pid < 0) { 60486752Sfjoe error("fork: %.100s", strerror(errno)); 60586752Sfjoe continue; 60686752Sfjoe } 60786752Sfjoe if (pid != 0) { /* This is the parent. */ 60886752Sfjoe /* The parent just exits. */ 60986752Sfjoe exit(0); 610298955Spfg } 61186752Sfjoe /* The child continues serving connections. */ 61286752Sfjoe if (compat20) { 61386752Sfjoe buffer_append(bin, "\004", 1); 61486752Sfjoe /* fake EOF on stdin */ 615271849Sglebius return -1; 61686752Sfjoe } else if (!stdin_eof) { 61786752Sfjoe /* 61886752Sfjoe * Sending SSH_CMSG_EOF alone does not always appear 61986752Sfjoe * to be enough. So we try to send an EOF character 62086752Sfjoe * first. 62186752Sfjoe */ 62286752Sfjoe packet_start(SSH_CMSG_STDIN_DATA); 62386752Sfjoe packet_put_string("\004", 1); 62486752Sfjoe packet_send(); 62586752Sfjoe /* Close stdin. */ 62686752Sfjoe stdin_eof = 1; 627271849Sglebius if (buffer_len(bin) == 0) { 62886752Sfjoe packet_start(SSH_CMSG_EOF); 62986752Sfjoe packet_send(); 63086752Sfjoe } 63186752Sfjoe } 63286752Sfjoe continue; 63386752Sfjoe 63486752Sfjoe case '?': 63586752Sfjoe snprintf(string, sizeof string, 63686752Sfjoe"%c?\r\n\ 63786752SfjoeSupported escape sequences:\r\n\ 63886752Sfjoe%c. - terminate connection\r\n\ 63986752Sfjoe%cC - open a command line\r\n\ 64086752Sfjoe%cR - Request rekey (SSH protocol 2 only)\r\n\ 641271849Sglebius%c^Z - suspend ssh\r\n\ 64286752Sfjoe%c# - list forwarded connections\r\n\ 64386752Sfjoe%c& - background ssh (when waiting for connections to terminate)\r\n\ 64486752Sfjoe%c? - this message\r\n\ 64586752Sfjoe%c%c - send the escape character by typing it twice\r\n\ 64686752Sfjoe(Note that escapes are only recognized immediately after newline.)\r\n", 64786752Sfjoe escape_char, escape_char, escape_char, escape_char, 64886752Sfjoe escape_char, escape_char, escape_char, escape_char, 64986752Sfjoe escape_char, escape_char); 65086752Sfjoe buffer_append(berr, string, strlen(string)); 65186752Sfjoe continue; 65286752Sfjoe 65386752Sfjoe case '#': 654101393Sfjoe snprintf(string, sizeof string, "%c#\r\n", escape_char); 655101393Sfjoe buffer_append(berr, string, strlen(string)); 656101393Sfjoe s = channel_open_message(); 657101393Sfjoe buffer_append(berr, s, strlen(s)); 65886752Sfjoe xfree(s); 65986752Sfjoe continue; 66086752Sfjoe 66186752Sfjoe case 'C': 66286752Sfjoe process_cmdline(); 66386752Sfjoe continue; 66486752Sfjoe 66586752Sfjoe default: 66686752Sfjoe if (ch != escape_char) { 66786752Sfjoe buffer_put_char(bin, escape_char); 66886752Sfjoe bytes++; 66986752Sfjoe } 67086752Sfjoe /* Escaped characters fall through here */ 67186752Sfjoe break; 67286752Sfjoe } 67386752Sfjoe } else { 67486752Sfjoe /* 67586752Sfjoe * The previous character was not an escape char. Check if this 67686752Sfjoe * is an escape. 67786752Sfjoe */ 67886752Sfjoe if (last_was_cr && ch == escape_char) { 67986752Sfjoe /* It is. Set the flag and continue to next character. */ 68086752Sfjoe escape_pending = 1; 68186752Sfjoe continue; 68286752Sfjoe } 68386752Sfjoe } 68486752Sfjoe 68586752Sfjoe /* 68686752Sfjoe * Normal character. Record whether it was a newline, 68786752Sfjoe * and append it to the buffer. 68886752Sfjoe */ 68986752Sfjoe last_was_cr = (ch == '\r' || ch == '\n'); 69086752Sfjoe buffer_put_char(bin, ch); 69186752Sfjoe bytes++; 692271849Sglebius } 69386752Sfjoe return bytes; 69486752Sfjoe} 69586752Sfjoe 69686752Sfjoestatic void 69786752Sfjoeclient_process_input(fd_set * readset) 69886752Sfjoe{ 69986752Sfjoe int len; 70086752Sfjoe char buf[8192]; 70186752Sfjoe 70286752Sfjoe /* Read input from stdin. */ 70386752Sfjoe if (FD_ISSET(fileno(stdin), readset)) { 70486752Sfjoe /* Read as much as possible. */ 70586752Sfjoe len = read(fileno(stdin), buf, sizeof(buf)); 70686752Sfjoe if (len < 0 && (errno == EAGAIN || errno == EINTR)) 70786752Sfjoe return; /* we'll try again later */ 70886752Sfjoe if (len <= 0) { 70986752Sfjoe /* 71086752Sfjoe * Received EOF or error. They are treated 71186752Sfjoe * similarly, except that an error message is printed 71286752Sfjoe * if it was an error condition. 71386752Sfjoe */ 71486752Sfjoe if (len < 0) { 71586752Sfjoe snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); 71686752Sfjoe buffer_append(&stderr_buffer, buf, strlen(buf)); 71786752Sfjoe } 71886752Sfjoe /* Mark that we have seen EOF. */ 719147256Sbrooks stdin_eof = 1; 72086752Sfjoe /* 72186752Sfjoe * Send an EOF message to the server unless there is 72286752Sfjoe * data in the buffer. If there is data in the 72386752Sfjoe * buffer, no message will be sent now. Code 72486752Sfjoe * elsewhere will send the EOF when the buffer 725148887Srwatson * becomes empty if stdin_eof is set. 72686752Sfjoe */ 72786752Sfjoe if (buffer_len(&stdin_buffer) == 0) { 72886752Sfjoe packet_start(SSH_CMSG_EOF); 72986752Sfjoe packet_send(); 73086752Sfjoe } 73186752Sfjoe } else if (escape_char == SSH_ESCAPECHAR_NONE) { 73286752Sfjoe /* 73386752Sfjoe * Normal successful read, and no escape character. 73486752Sfjoe * Just append the data to buffer. 73586752Sfjoe */ 73686752Sfjoe buffer_append(&stdin_buffer, buf, len); 73786752Sfjoe } else { 73886752Sfjoe /* 73986752Sfjoe * Normal, successful read. But we have an escape character 74086752Sfjoe * and have to process the characters one by one. 741298646Spfg */ 74286752Sfjoe if (process_escapes(&stdin_buffer, &stdout_buffer, 74386752Sfjoe &stderr_buffer, buf, len) == -1) 74486752Sfjoe return; 745148887Srwatson } 746147256Sbrooks } 74786752Sfjoe} 74886752Sfjoe 74986752Sfjoestatic void 75086752Sfjoeclient_process_output(fd_set * writeset) 75186752Sfjoe{ 75286752Sfjoe int len; 75386752Sfjoe char buf[100]; 75486752Sfjoe 75586752Sfjoe /* Write buffered output to stdout. */ 75686752Sfjoe if (FD_ISSET(fileno(stdout), writeset)) { 75786752Sfjoe /* Write as much data as possible. */ 758271849Sglebius len = write(fileno(stdout), buffer_ptr(&stdout_buffer), 75986752Sfjoe buffer_len(&stdout_buffer)); 76086752Sfjoe if (len <= 0) { 76186752Sfjoe if (errno == EINTR || errno == EAGAIN) 762147256Sbrooks len = 0; 76386752Sfjoe else { 76486752Sfjoe /* 76586752Sfjoe * An error or EOF was encountered. Put an 766271849Sglebius * error message to stderr buffer. 76786752Sfjoe */ 76886752Sfjoe snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); 76986752Sfjoe buffer_append(&stderr_buffer, buf, strlen(buf)); 77086752Sfjoe quit_pending = 1; 77186752Sfjoe return; 77286752Sfjoe } 773148887Srwatson } 77486752Sfjoe /* Consume printed data from the buffer. */ 77586752Sfjoe buffer_consume(&stdout_buffer, len); 77686752Sfjoe stdout_bytes += len; 77786752Sfjoe } 77886752Sfjoe /* Write buffered output to stderr. */ 77986752Sfjoe if (FD_ISSET(fileno(stderr), writeset)) { 78086752Sfjoe /* Write as much data as possible. */ 78186752Sfjoe len = write(fileno(stderr), buffer_ptr(&stderr_buffer), 78286752Sfjoe buffer_len(&stderr_buffer)); 78386752Sfjoe if (len <= 0) { 78486752Sfjoe if (errno == EINTR || errno == EAGAIN) 78586752Sfjoe len = 0; 78686752Sfjoe else { 78786752Sfjoe /* EOF or error, but can't even print error message. */ 78886752Sfjoe quit_pending = 1; 78986752Sfjoe return; 79086752Sfjoe } 79186752Sfjoe } 79286752Sfjoe /* Consume printed characters from the buffer. */ 79386752Sfjoe buffer_consume(&stderr_buffer, len); 79486752Sfjoe stderr_bytes += len; 79586752Sfjoe } 79686752Sfjoe} 79786752Sfjoe 79886752Sfjoe/* 79986752Sfjoe * Get packets from the connection input buffer, and process them as long as 80086752Sfjoe * there are packets available. 80186752Sfjoe * 80286752Sfjoe * Any unknown packets received during the actual 80386752Sfjoe * session cause the session to terminate. This is 80486752Sfjoe * intended to make debugging easier since no 80586752Sfjoe * confirmations are sent. Any compatible protocol 80686752Sfjoe * extensions must be negotiated during the 80786752Sfjoe * preparatory phase. 80886752Sfjoe */ 80986752Sfjoe 81086752Sfjoestatic void 81186752Sfjoeclient_process_buffered_input_packets(void) 81286752Sfjoe{ 81386752Sfjoe dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); 81486752Sfjoe} 81586752Sfjoe 81686752Sfjoe/* scan buf[] for '~' before sending data to the peer */ 81786752Sfjoe 81886752Sfjoestatic int 81986752Sfjoesimple_escape_filter(Channel *c, char *buf, int len) 82086752Sfjoe{ 82186752Sfjoe /* XXX we assume c->extended is writeable */ 82286752Sfjoe return process_escapes(&c->input, &c->output, &c->extended, buf, len); 82386752Sfjoe} 82486752Sfjoe 82586752Sfjoestatic void 82686752Sfjoeclient_channel_closed(int id, void *arg) 82786752Sfjoe{ 82886752Sfjoe if (id != session_ident) 82986752Sfjoe error("client_channel_closed: id %d != session_ident %d", 83086752Sfjoe id, session_ident); 83186752Sfjoe channel_cancel_cleanup(id); 83286752Sfjoe session_closed = 1; 83386752Sfjoe if (in_raw_mode()) 83486752Sfjoe leave_raw_mode(); 83586752Sfjoe} 83686752Sfjoe 83786752Sfjoe/* 83886752Sfjoe * Implements the interactive session with the server. This is called after 83986752Sfjoe * the user has been authenticated, and a command has been started on the 84086752Sfjoe * remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character 84186752Sfjoe * used as an escape character for terminating or suspending the session. 84286752Sfjoe */ 84386752Sfjoe 84486752Sfjoeint 84586752Sfjoeclient_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) 84686752Sfjoe{ 84786752Sfjoe fd_set *readset = NULL, *writeset = NULL; 84886752Sfjoe double start_time, total_time; 84986752Sfjoe int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0; 85086752Sfjoe char buf[100]; 85186752Sfjoe 85286752Sfjoe debug("Entering interactive session."); 85386752Sfjoe 85486752Sfjoe start_time = get_current_time(); 85586752Sfjoe 85686752Sfjoe /* Initialize variables. */ 85786752Sfjoe escape_pending = 0; 85886752Sfjoe last_was_cr = 1; 85986752Sfjoe exit_status = -1; 86086752Sfjoe stdin_eof = 0; 86186752Sfjoe buffer_high = 64 * 1024; 86286752Sfjoe connection_in = packet_get_connection_in(); 86386752Sfjoe connection_out = packet_get_connection_out(); 86486752Sfjoe max_fd = MAX(connection_in, connection_out); 86586752Sfjoe 86686752Sfjoe if (!compat20) { 867243857Sglebius /* enable nonblocking unless tty */ 86886752Sfjoe if (!isatty(fileno(stdin))) 869147256Sbrooks set_nonblock(fileno(stdin)); 87086752Sfjoe if (!isatty(fileno(stdout))) 87186752Sfjoe set_nonblock(fileno(stdout)); 87286752Sfjoe if (!isatty(fileno(stderr))) 87386752Sfjoe set_nonblock(fileno(stderr)); 87486752Sfjoe max_fd = MAX(max_fd, fileno(stdin)); 87586752Sfjoe max_fd = MAX(max_fd, fileno(stdout)); 87686752Sfjoe max_fd = MAX(max_fd, fileno(stderr)); 87786752Sfjoe } 87886752Sfjoe stdin_bytes = 0; 87986752Sfjoe stdout_bytes = 0; 88086752Sfjoe stderr_bytes = 0; 881276750Srwatson quit_pending = 0; 88286752Sfjoe escape_char = escape_char_arg; 88386752Sfjoe 88486752Sfjoe /* Initialize buffers. */ 88586752Sfjoe buffer_init(&stdin_buffer); 88686752Sfjoe buffer_init(&stdout_buffer); 88786752Sfjoe buffer_init(&stderr_buffer); 88886752Sfjoe 88986752Sfjoe client_init_dispatch(); 89086752Sfjoe 89186752Sfjoe /* 89286752Sfjoe * Set signal handlers, (e.g. to restore non-blocking mode) 89386752Sfjoe * but don't overwrite SIG_IGN, matches behaviour from rsh(1) 89486752Sfjoe */ 89586752Sfjoe if (signal(SIGINT, SIG_IGN) != SIG_IGN) 89686752Sfjoe signal(SIGINT, signal_handler); 89786752Sfjoe if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 89886752Sfjoe signal(SIGQUIT, signal_handler); 89986752Sfjoe if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 90086752Sfjoe signal(SIGTERM, signal_handler); 90186752Sfjoe if (have_pty) 902147256Sbrooks signal(SIGWINCH, window_change_handler); 90386752Sfjoe 90486752Sfjoe if (have_pty) 90586752Sfjoe enter_raw_mode(); 906106937Ssam 90786752Sfjoe if (compat20) { 908180263Sjhb session_ident = ssh2_chan_id; 90986752Sfjoe if (escape_char != SSH_ESCAPECHAR_NONE) 910180263Sjhb channel_register_filter(session_ident, 911106937Ssam simple_escape_filter); 912180263Sjhb if (session_ident != -1) 91386752Sfjoe channel_register_cleanup(session_ident, 91486752Sfjoe client_channel_closed); 91586752Sfjoe } else { 91686752Sfjoe /* Check if we should immediately send eof on stdin. */ 91786752Sfjoe client_check_initial_eof_on_stdin(); 91886752Sfjoe } 91986752Sfjoe 92086752Sfjoe /* Main loop of the client for the interactive session mode. */ 92186752Sfjoe while (!quit_pending) { 92286752Sfjoe 92386752Sfjoe /* Process buffered packets sent by the server. */ 92486752Sfjoe client_process_buffered_input_packets(); 92586752Sfjoe 92686752Sfjoe if (compat20 && session_closed && !channel_still_open()) 92786752Sfjoe break; 92886752Sfjoe 929180263Sjhb rekeying = (xxx_kex != NULL && !xxx_kex->done); 93086752Sfjoe 93186752Sfjoe if (rekeying) { 93286752Sfjoe debug("rekeying in progress"); 93386752Sfjoe } else { 93486752Sfjoe /* 93586752Sfjoe * Make packets of buffered stdin data, and buffer 93686752Sfjoe * them for sending to the server. 93786752Sfjoe */ 93886752Sfjoe if (!compat20) 93986752Sfjoe client_make_packets_from_stdin_data(); 94086752Sfjoe 94186752Sfjoe /* 94286752Sfjoe * Make packets from buffered channel data, and 94386752Sfjoe * enqueue them for sending to the server. 94486752Sfjoe */ 94586752Sfjoe if (packet_not_very_much_data_to_write()) 94686752Sfjoe channel_output_poll(); 94786752Sfjoe 948180263Sjhb /* 949180263Sjhb * Check if the window size has changed, and buffer a 95086752Sfjoe * message about it to the server if so. 95186752Sfjoe */ 95286752Sfjoe client_check_window_change(); 95386752Sfjoe 95486752Sfjoe if (quit_pending) 95586752Sfjoe break; 95686752Sfjoe } 95786752Sfjoe /* 95886752Sfjoe * Wait until we have something to do (something becomes 95986752Sfjoe * available on one of the descriptors). 96086752Sfjoe */ 96186752Sfjoe max_fd2 = max_fd; 96286752Sfjoe client_wait_until_can_do_something(&readset, &writeset, 96386752Sfjoe &max_fd2, &nalloc, rekeying); 96486752Sfjoe 96586752Sfjoe if (quit_pending) 96686752Sfjoe break; 96786752Sfjoe 96886752Sfjoe /* Do channel operations unless rekeying in progress. */ 96986752Sfjoe if (!rekeying) { 97086752Sfjoe channel_after_select(readset, writeset); 97186752Sfjoe 97286752Sfjoe if (need_rekeying) { 97386752Sfjoe debug("user requests rekeying"); 97486752Sfjoe xxx_kex->done = 0; 97586752Sfjoe kex_send_kexinit(xxx_kex); 97686752Sfjoe need_rekeying = 0; 97786752Sfjoe } 97886752Sfjoe } 97986752Sfjoe 98086752Sfjoe /* Buffer input from the connection. */ 98186752Sfjoe client_process_net_input(readset); 98286752Sfjoe 98386752Sfjoe if (quit_pending) 98486752Sfjoe break; 98586752Sfjoe 98686752Sfjoe if (!compat20) { 98786752Sfjoe /* Buffer data from stdin */ 98886752Sfjoe client_process_input(readset); 98986752Sfjoe /* 99086752Sfjoe * Process output to stdout and stderr. Output to 99186752Sfjoe * the connection is processed elsewhere (above). 99286752Sfjoe */ 99386752Sfjoe client_process_output(writeset); 99486752Sfjoe } 99586752Sfjoe 99686752Sfjoe /* Send as much buffered packet data as possible to the sender. */ 99786752Sfjoe if (FD_ISSET(connection_out, writeset)) 998147256Sbrooks packet_write_poll(); 999101400Sfjoe } 1000147256Sbrooks if (readset) 1001101400Sfjoe xfree(readset); 1002101400Sfjoe if (writeset) 1003147256Sbrooks xfree(writeset); 1004147256Sbrooks 100586752Sfjoe /* Terminate the session. */ 100686752Sfjoe 100786752Sfjoe /* Stop watching for window change. */ 100886752Sfjoe if (have_pty) 100986752Sfjoe signal(SIGWINCH, SIG_DFL); 1010180263Sjhb 1011180263Sjhb channel_free_all(); 1012180263Sjhb 101386752Sfjoe if (have_pty) 1014180263Sjhb leave_raw_mode(); 1015180263Sjhb 1016180263Sjhb /* restore blocking io */ 1017180263Sjhb if (!isatty(fileno(stdin))) 1018180263Sjhb unset_nonblock(fileno(stdin)); 1019180263Sjhb if (!isatty(fileno(stdout))) 102086752Sfjoe unset_nonblock(fileno(stdout)); 102186752Sfjoe if (!isatty(fileno(stderr))) 102286752Sfjoe unset_nonblock(fileno(stderr)); 1023101400Sfjoe 102486752Sfjoe if (received_signal) { 1025180263Sjhb if (in_non_blocking_mode) /* XXX */ 1026101400Sfjoe leave_non_blocking(); 1027101400Sfjoe fatal("Killed by signal %d.", (int) received_signal); 1028101400Sfjoe } 1029101400Sfjoe 1030101400Sfjoe /* 1031101400Sfjoe * In interactive mode (with pseudo tty) display a message indicating 1032101400Sfjoe * that the connection has been closed. 1033101400Sfjoe */ 1034180263Sjhb if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { 1035101400Sfjoe snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); 103686752Sfjoe buffer_append(&stderr_buffer, buf, strlen(buf)); 103786752Sfjoe } 1038180263Sjhb 103986752Sfjoe /* Output any buffered data for stdout. */ 104086752Sfjoe while (buffer_len(&stdout_buffer) > 0) { 104186752Sfjoe len = write(fileno(stdout), buffer_ptr(&stdout_buffer), 104286752Sfjoe buffer_len(&stdout_buffer)); 104386752Sfjoe if (len <= 0) { 104486752Sfjoe error("Write failed flushing stdout buffer."); 104586752Sfjoe break; 104686752Sfjoe } 104786752Sfjoe buffer_consume(&stdout_buffer, len); 104886752Sfjoe stdout_bytes += len; 104986752Sfjoe } 105086752Sfjoe 105186752Sfjoe /* Output any buffered data for stderr. */ 105286752Sfjoe while (buffer_len(&stderr_buffer) > 0) { 105386752Sfjoe len = write(fileno(stderr), buffer_ptr(&stderr_buffer), 105486752Sfjoe buffer_len(&stderr_buffer)); 105586752Sfjoe if (len <= 0) { 105686752Sfjoe error("Write failed flushing stderr buffer."); 105786752Sfjoe break; 105886752Sfjoe } 105986752Sfjoe buffer_consume(&stderr_buffer, len); 106086752Sfjoe stderr_bytes += len; 106186752Sfjoe } 106286752Sfjoe 106386752Sfjoe /* Clear and free any buffers. */ 106486752Sfjoe memset(buf, 0, sizeof(buf)); 106586752Sfjoe buffer_free(&stdin_buffer); 106686752Sfjoe buffer_free(&stdout_buffer); 106786752Sfjoe buffer_free(&stderr_buffer); 106886752Sfjoe 106986752Sfjoe /* Report bytes transferred, and transfer rates. */ 107086752Sfjoe total_time = get_current_time() - start_time; 107186752Sfjoe debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", 107286752Sfjoe stdin_bytes, stdout_bytes, stderr_bytes, total_time); 107386752Sfjoe if (total_time > 0) 107486752Sfjoe debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", 107586752Sfjoe stdin_bytes / total_time, stdout_bytes / total_time, 107686752Sfjoe stderr_bytes / total_time); 107786752Sfjoe 107886752Sfjoe /* Return the exit status of the program. */ 107986752Sfjoe debug("Exit status %d", exit_status); 108086752Sfjoe return exit_status; 108186752Sfjoe} 108286752Sfjoe 108386752Sfjoe/*********/ 108486752Sfjoe 108586752Sfjoestatic void 108686752Sfjoeclient_input_stdout_data(int type, u_int32_t seq, void *ctxt) 108786752Sfjoe{ 108886752Sfjoe u_int data_len; 108986752Sfjoe char *data = packet_get_string(&data_len); 109086752Sfjoe packet_check_eom(); 109186752Sfjoe buffer_append(&stdout_buffer, data, data_len); 109286752Sfjoe memset(data, 0, data_len); 109386752Sfjoe xfree(data); 109486752Sfjoe} 109586752Sfjoestatic void 109686752Sfjoeclient_input_stderr_data(int type, u_int32_t seq, void *ctxt) 109793593Sjhb{ 109886752Sfjoe u_int data_len; 109986752Sfjoe char *data = packet_get_string(&data_len); 1100180263Sjhb packet_check_eom(); 110186752Sfjoe buffer_append(&stderr_buffer, data, data_len); 110286752Sfjoe memset(data, 0, data_len); 110386752Sfjoe xfree(data); 110493593Sjhb} 110586752Sfjoestatic void 110686752Sfjoeclient_input_exit_status(int type, u_int32_t seq, void *ctxt) 110786752Sfjoe{ 110886752Sfjoe exit_status = packet_get_int(); 110986752Sfjoe packet_check_eom(); 111086752Sfjoe /* Acknowledge the exit. */ 111186752Sfjoe packet_start(SSH_CMSG_EXIT_CONFIRMATION); 111286752Sfjoe packet_send(); 1113180263Sjhb /* 111486752Sfjoe * Must wait for packet to be sent since we are 1115148887Srwatson * exiting the loop. 1116180263Sjhb */ 111786752Sfjoe packet_write_wait(); 1118148887Srwatson /* Flag that we want to exit. */ 111986752Sfjoe quit_pending = 1; 112086752Sfjoe} 112186752Sfjoe 1122180263Sjhbstatic Channel * 112386752Sfjoeclient_request_forwarded_tcpip(const char *request_type, int rchan) 112486752Sfjoe{ 112586752Sfjoe Channel *c = NULL; 112686752Sfjoe char *listen_address, *originator_address; 112786752Sfjoe int listen_port, originator_port; 112886752Sfjoe int sock; 112986752Sfjoe 113086752Sfjoe /* Get rest of the packet */ 113186752Sfjoe listen_address = packet_get_string(NULL); 113286752Sfjoe listen_port = packet_get_int(); 113386752Sfjoe originator_address = packet_get_string(NULL); 113486752Sfjoe originator_port = packet_get_int(); 113586752Sfjoe packet_check_eom(); 113686752Sfjoe 113786752Sfjoe debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", 113886752Sfjoe listen_address, listen_port, originator_address, originator_port); 113986752Sfjoe 1140180263Sjhb sock = channel_connect_by_listen_address(listen_port); 1141152315Sru if (sock < 0) { 114286752Sfjoe xfree(originator_address); 114386752Sfjoe xfree(listen_address); 114486752Sfjoe return NULL; 114586752Sfjoe } 1146180263Sjhb c = channel_new("forwarded-tcpip", 1147332161Sbrooks SSH_CHANNEL_CONNECTING, sock, sock, -1, 114886752Sfjoe CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, 114986752Sfjoe xstrdup(originator_address), 1); 115086752Sfjoe xfree(originator_address); 1151180263Sjhb xfree(listen_address); 1152180263Sjhb return c; 1153180263Sjhb} 1154180263Sjhb 1155180263Sjhbstatic Channel * 1156337909Sbrooksclient_request_x11(const char *request_type, int rchan) 1157180263Sjhb{ 1158180263Sjhb Channel *c = NULL; 115986752Sfjoe char *originator; 116086752Sfjoe int originator_port; 116186752Sfjoe int sock; 116286752Sfjoe 1163164033Srwatson if (!options.forward_x11) { 116486752Sfjoe error("Warning: ssh server tried X11 forwarding."); 116586752Sfjoe error("Warning: this is probably a break in attempt by a malicious server."); 1166332161Sbrooks return NULL; 1167180263Sjhb } 116886752Sfjoe originator = packet_get_string(NULL); 116986752Sfjoe if (datafellows & SSH_BUG_X11FWD) { 117086752Sfjoe debug2("buggy server: x11 request w/o originator_port"); 117186752Sfjoe originator_port = 0; 117286752Sfjoe } else { 117386752Sfjoe originator_port = packet_get_int(); 117486752Sfjoe } 117586752Sfjoe packet_check_eom(); 117686752Sfjoe /* XXX check permission */ 117786752Sfjoe debug("client_request_x11: request from %s %d", originator, 117886752Sfjoe originator_port); 1179152315Sru xfree(originator); 118086752Sfjoe sock = x11_connect_display(); 118186752Sfjoe if (sock < 0) 118286752Sfjoe return NULL; 1183180263Sjhb c = channel_new("x11", 118486752Sfjoe SSH_CHANNEL_X11_OPEN, sock, sock, -1, 118586752Sfjoe CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, 118686752Sfjoe xstrdup("x11"), 1); 1187180263Sjhb c->force_drain = 1; 1188164033Srwatson return c; 118986752Sfjoe} 1190180263Sjhb 119186752Sfjoestatic Channel * 119286752Sfjoeclient_request_agent(const char *request_type, int rchan) 119386752Sfjoe{ 1194106937Ssam Channel *c = NULL; 1195106937Ssam int sock; 119686752Sfjoe 119786752Sfjoe if (!options.forward_agent) { 119886752Sfjoe error("Warning: ssh server tried agent forwarding."); 119986752Sfjoe error("Warning: this is probably a break in attempt by a malicious server."); 120086752Sfjoe return NULL; 120186752Sfjoe } 120286752Sfjoe sock = ssh_get_authentication_socket(); 120386752Sfjoe if (sock < 0) 120486752Sfjoe return NULL; 120586752Sfjoe c = channel_new("authentication agent connection", 120686752Sfjoe SSH_CHANNEL_OPEN, sock, sock, -1, 120786752Sfjoe CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, 120886752Sfjoe xstrdup("authentication agent connection"), 1); 120986752Sfjoe c->force_drain = 1; 121086752Sfjoe return c; 121186752Sfjoe} 1212103844Salfred 121386752Sfjoe/* XXXX move to generic input handler */ 121486752Sfjoestatic void 121586752Sfjoeclient_input_channel_open(int type, u_int32_t seq, void *ctxt) 121686752Sfjoe{ 121786752Sfjoe Channel *c = NULL; 121886752Sfjoe char *ctype; 121986752Sfjoe int rchan; 122086752Sfjoe u_int rmaxpack, rwindow, len; 122186752Sfjoe 122286752Sfjoe ctype = packet_get_string(&len); 122386752Sfjoe rchan = packet_get_int(); 122486752Sfjoe rwindow = packet_get_int(); 122586752Sfjoe rmaxpack = packet_get_int(); 122686752Sfjoe 122786752Sfjoe debug("client_input_channel_open: ctype %s rchan %d win %d max %d", 122886752Sfjoe ctype, rchan, rwindow, rmaxpack); 122986752Sfjoe 123086752Sfjoe if (strcmp(ctype, "forwarded-tcpip") == 0) { 123186752Sfjoe c = client_request_forwarded_tcpip(ctype, rchan); 123286752Sfjoe } else if (strcmp(ctype, "x11") == 0) { 123386752Sfjoe c = client_request_x11(ctype, rchan); 123486752Sfjoe } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { 123586752Sfjoe c = client_request_agent(ctype, rchan); 123686752Sfjoe } 123786752Sfjoe/* XXX duplicate : */ 123886752Sfjoe if (c != NULL) { 123986752Sfjoe debug("confirm %s", ctype); 124086752Sfjoe c->remote_id = rchan; 124186752Sfjoe c->remote_window = rwindow; 124286752Sfjoe c->remote_maxpacket = rmaxpack; 124386752Sfjoe if (c->type != SSH_CHANNEL_CONNECTING) { 124486752Sfjoe packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); 124586752Sfjoe packet_put_int(c->remote_id); 124686752Sfjoe packet_put_int(c->self); 124786752Sfjoe packet_put_int(c->local_window); 124886752Sfjoe packet_put_int(c->local_maxpacket); 124986752Sfjoe packet_send(); 125086752Sfjoe } 125186752Sfjoe } else { 125286752Sfjoe debug("failure %s", ctype); 125386752Sfjoe packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); 125486752Sfjoe packet_put_int(rchan); 125586752Sfjoe packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); 125686752Sfjoe if (!(datafellows & SSH_BUG_OPENFAILURE)) { 125786752Sfjoe packet_put_cstring("open failed"); 125886752Sfjoe packet_put_cstring(""); 125986752Sfjoe } 126086752Sfjoe packet_send(); 126186752Sfjoe } 126286752Sfjoe xfree(ctype); 126386752Sfjoe} 126486752Sfjoestatic void 126586752Sfjoeclient_input_channel_req(int type, u_int32_t seq, void *ctxt) 126686752Sfjoe{ 126786752Sfjoe Channel *c = NULL; 126886752Sfjoe int id, reply, success = 0; 126986752Sfjoe char *rtype; 127086752Sfjoe 127186752Sfjoe id = packet_get_int(); 127286752Sfjoe rtype = packet_get_string(NULL); 127386752Sfjoe reply = packet_get_char(); 127486752Sfjoe 127586752Sfjoe debug("client_input_channel_req: channel %d rtype %s reply %d", 127686752Sfjoe id, rtype, reply); 127786752Sfjoe 1278 if (session_ident == -1) { 1279 error("client_input_channel_req: no channel %d", session_ident); 1280 } else if (id != session_ident) { 1281 error("client_input_channel_req: channel %d: wrong channel: %d", 1282 session_ident, id); 1283 } 1284 c = channel_lookup(id); 1285 if (c == NULL) { 1286 error("client_input_channel_req: channel %d: unknown channel", id); 1287 } else if (strcmp(rtype, "exit-status") == 0) { 1288 success = 1; 1289 exit_status = packet_get_int(); 1290 packet_check_eom(); 1291 } 1292 if (reply) { 1293 packet_start(success ? 1294 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); 1295 packet_put_int(c->remote_id); 1296 packet_send(); 1297 } 1298 xfree(rtype); 1299} 1300static void 1301client_input_global_request(int type, u_int32_t seq, void *ctxt) 1302{ 1303 char *rtype; 1304 int want_reply; 1305 int success = 0; 1306 1307 rtype = packet_get_string(NULL); 1308 want_reply = packet_get_char(); 1309 debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply); 1310 if (want_reply) { 1311 packet_start(success ? 1312 SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); 1313 packet_send(); 1314 packet_write_wait(); 1315 } 1316 xfree(rtype); 1317} 1318 1319static void 1320client_init_dispatch_20(void) 1321{ 1322 dispatch_init(&dispatch_protocol_error); 1323 1324 dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); 1325 dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); 1326 dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); 1327 dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); 1328 dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open); 1329 dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 1330 dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 1331 dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); 1332 dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); 1333 dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); 1334 1335 /* rekeying */ 1336 dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); 1337 1338 /* global request reply messages */ 1339 dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); 1340 dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); 1341} 1342static void 1343client_init_dispatch_13(void) 1344{ 1345 dispatch_init(NULL); 1346 dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); 1347 dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); 1348 dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); 1349 dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); 1350 dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); 1351 dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); 1352 dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); 1353 dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); 1354 dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); 1355 1356 dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? 1357 &auth_input_open_request : &deny_input_open); 1358 dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? 1359 &x11_input_open : &deny_input_open); 1360} 1361static void 1362client_init_dispatch_15(void) 1363{ 1364 client_init_dispatch_13(); 1365 dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); 1366 dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); 1367} 1368static void 1369client_init_dispatch(void) 1370{ 1371 if (compat20) 1372 client_init_dispatch_20(); 1373 else if (compat13) 1374 client_init_dispatch_13(); 1375 else 1376 client_init_dispatch_15(); 1377} 1378