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