xref: /onnv-gate/usr/src/cmd/ssh/sshd/serverloop.c (revision 9845:0d705da26956)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
30Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
40Sstevel@tonic-gate  *                    All rights reserved
50Sstevel@tonic-gate  * Server main loop for handling the interactive session.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
80Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
90Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
100Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
110Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * SSH2 support by Markus Friedl.
140Sstevel@tonic-gate  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
170Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
180Sstevel@tonic-gate  * are met:
190Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
200Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
210Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
220Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
230Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
260Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
270Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
280Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
290Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
300Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
310Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
320Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
330Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
340Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate /*
379600SNobutomo.Nakano@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
380Sstevel@tonic-gate  * Use is subject to license terms.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include "includes.h"
420Sstevel@tonic-gate RCSID("$OpenBSD: serverloop.c,v 1.104 2002/09/19 16:03:15 stevesk Exp $");
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include "xmalloc.h"
450Sstevel@tonic-gate #include "packet.h"
460Sstevel@tonic-gate #include "buffer.h"
470Sstevel@tonic-gate #include "log.h"
480Sstevel@tonic-gate #include "servconf.h"
490Sstevel@tonic-gate #include "canohost.h"
500Sstevel@tonic-gate #include "sshpty.h"
510Sstevel@tonic-gate #include "channels.h"
520Sstevel@tonic-gate #include "compat.h"
530Sstevel@tonic-gate #include "ssh1.h"
540Sstevel@tonic-gate #include "ssh2.h"
550Sstevel@tonic-gate #include "auth.h"
560Sstevel@tonic-gate #include "session.h"
570Sstevel@tonic-gate #include "dispatch.h"
580Sstevel@tonic-gate #include "auth-options.h"
590Sstevel@tonic-gate #include "serverloop.h"
600Sstevel@tonic-gate #include "misc.h"
610Sstevel@tonic-gate #include "kex.h"
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #ifdef ALTPRIVSEP
640Sstevel@tonic-gate #include "altprivsep.h"
650Sstevel@tonic-gate #endif /* ALTPRIVSEP*/
660Sstevel@tonic-gate 
670Sstevel@tonic-gate extern ServerOptions options;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /* XXX */
700Sstevel@tonic-gate extern Kex *xxx_kex;
710Sstevel@tonic-gate static Authctxt *xxx_authctxt;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static Buffer stdin_buffer;	/* Buffer for stdin data. */
740Sstevel@tonic-gate static Buffer stdout_buffer;	/* Buffer for stdout data. */
750Sstevel@tonic-gate static Buffer stderr_buffer;	/* Buffer for stderr data. */
760Sstevel@tonic-gate static int fdin;		/* Descriptor for stdin (for writing) */
770Sstevel@tonic-gate static int fdout;		/* Descriptor for stdout (for reading);
780Sstevel@tonic-gate 				   May be same number as fdin. */
790Sstevel@tonic-gate static int fderr;		/* Descriptor for stderr.  May be -1. */
800Sstevel@tonic-gate static long stdin_bytes = 0;	/* Number of bytes written to stdin. */
810Sstevel@tonic-gate static long stdout_bytes = 0;	/* Number of stdout bytes sent to client. */
820Sstevel@tonic-gate static long stderr_bytes = 0;	/* Number of stderr bytes sent to client. */
830Sstevel@tonic-gate static long fdout_bytes = 0;	/* Number of stdout bytes read from program. */
840Sstevel@tonic-gate static int stdin_eof = 0;	/* EOF message received from client. */
850Sstevel@tonic-gate static int fdout_eof = 0;	/* EOF encountered reading from fdout. */
860Sstevel@tonic-gate static int fderr_eof = 0;	/* EOF encountered readung from fderr. */
870Sstevel@tonic-gate static int fdin_is_tty = 0;	/* fdin points to a tty. */
880Sstevel@tonic-gate static int connection_in;	/* Connection to client (input). */
890Sstevel@tonic-gate static int connection_out;	/* Connection to client (output). */
900Sstevel@tonic-gate static int connection_closed = 0;	/* Connection to client closed. */
910Sstevel@tonic-gate static u_int buffer_high;	/* "Soft" max buffer size. */
920Sstevel@tonic-gate static int client_alive_timeouts = 0;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * This SIGCHLD kludge is used to detect when the child exits.  The server
960Sstevel@tonic-gate  * will exit after that, as soon as forwarded connections have terminated.
970Sstevel@tonic-gate  */
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static volatile sig_atomic_t child_terminated = 0;	/* The child has terminated. */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /* prototypes */
1020Sstevel@tonic-gate static void server_init_dispatch(void);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * we write to this pipe if a SIGCHLD is caught in order to avoid
1060Sstevel@tonic-gate  * the race between select() and child_terminated
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static int notify_pipe[2];
1090Sstevel@tonic-gate static void
notify_setup(void)1100Sstevel@tonic-gate notify_setup(void)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	if (pipe(notify_pipe) < 0) {
1130Sstevel@tonic-gate 		error("pipe(notify_pipe) failed %s", strerror(errno));
114*9845SJan.Pechanec@Sun.COM 	} else if ((fcntl(notify_pipe[0], F_SETFD, FD_CLOEXEC) == -1) ||
115*9845SJan.Pechanec@Sun.COM 	    (fcntl(notify_pipe[1], F_SETFD, FD_CLOEXEC) == -1)) {
1160Sstevel@tonic-gate 		error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
1170Sstevel@tonic-gate 		(void) close(notify_pipe[0]);
1180Sstevel@tonic-gate 		(void) close(notify_pipe[1]);
1190Sstevel@tonic-gate 	} else {
1200Sstevel@tonic-gate 		set_nonblock(notify_pipe[0]);
1210Sstevel@tonic-gate 		set_nonblock(notify_pipe[1]);
1220Sstevel@tonic-gate 		return;
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 	notify_pipe[0] = -1;	/* read end */
1250Sstevel@tonic-gate 	notify_pipe[1] = -1;	/* write end */
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate static void
notify_parent(void)1280Sstevel@tonic-gate notify_parent(void)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	if (notify_pipe[1] != -1)
1310Sstevel@tonic-gate 		(void) write(notify_pipe[1], "", 1);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate static void
notify_prepare(fd_set * readset)1340Sstevel@tonic-gate notify_prepare(fd_set *readset)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	if (notify_pipe[0] != -1)
1370Sstevel@tonic-gate 		FD_SET(notify_pipe[0], readset);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate static void
notify_done(fd_set * readset)1400Sstevel@tonic-gate notify_done(fd_set *readset)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	char c;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
1450Sstevel@tonic-gate 		while (read(notify_pipe[0], &c, 1) != -1)
1460Sstevel@tonic-gate 			debug2("notify_done: reading");
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static void
sigchld_handler(int sig)1500Sstevel@tonic-gate sigchld_handler(int sig)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	int save_errno = errno;
1530Sstevel@tonic-gate 	debug("Received SIGCHLD.");
1540Sstevel@tonic-gate 	child_terminated = 1;
1550Sstevel@tonic-gate #ifndef _UNICOS
1560Sstevel@tonic-gate 	mysignal(SIGCHLD, sigchld_handler);
1570Sstevel@tonic-gate #endif
1580Sstevel@tonic-gate 	notify_parent();
1590Sstevel@tonic-gate 	errno = save_errno;
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * Make packets from buffered stderr data, and buffer it for sending
1640Sstevel@tonic-gate  * to the client.
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate static void
make_packets_from_stderr_data(void)1670Sstevel@tonic-gate make_packets_from_stderr_data(void)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	int len;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	/* Send buffered stderr data to the client. */
1720Sstevel@tonic-gate 	while (buffer_len(&stderr_buffer) > 0 &&
1730Sstevel@tonic-gate 	    packet_not_very_much_data_to_write()) {
1740Sstevel@tonic-gate 		len = buffer_len(&stderr_buffer);
1750Sstevel@tonic-gate 		if (packet_is_interactive()) {
1760Sstevel@tonic-gate 			if (len > 512)
1770Sstevel@tonic-gate 				len = 512;
1780Sstevel@tonic-gate 		} else {
1790Sstevel@tonic-gate 			/* Keep the packets at reasonable size. */
1800Sstevel@tonic-gate 			if (len > packet_get_maxsize())
1810Sstevel@tonic-gate 				len = packet_get_maxsize();
1820Sstevel@tonic-gate 		}
1830Sstevel@tonic-gate 		packet_start(SSH_SMSG_STDERR_DATA);
1840Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&stderr_buffer), len);
1850Sstevel@tonic-gate 		packet_send();
1860Sstevel@tonic-gate 		buffer_consume(&stderr_buffer, len);
1870Sstevel@tonic-gate 		stderr_bytes += len;
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * Make packets from buffered stdout data, and buffer it for sending to the
1930Sstevel@tonic-gate  * client.
1940Sstevel@tonic-gate  */
1950Sstevel@tonic-gate static void
make_packets_from_stdout_data(void)1960Sstevel@tonic-gate make_packets_from_stdout_data(void)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate 	int len;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* Send buffered stdout data to the client. */
2010Sstevel@tonic-gate 	while (buffer_len(&stdout_buffer) > 0 &&
2020Sstevel@tonic-gate 	    packet_not_very_much_data_to_write()) {
2030Sstevel@tonic-gate 		len = buffer_len(&stdout_buffer);
2040Sstevel@tonic-gate 		if (packet_is_interactive()) {
2050Sstevel@tonic-gate 			if (len > 512)
2060Sstevel@tonic-gate 				len = 512;
2070Sstevel@tonic-gate 		} else {
2080Sstevel@tonic-gate 			/* Keep the packets at reasonable size. */
2090Sstevel@tonic-gate 			if (len > packet_get_maxsize())
2100Sstevel@tonic-gate 				len = packet_get_maxsize();
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 		packet_start(SSH_SMSG_STDOUT_DATA);
2130Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&stdout_buffer), len);
2140Sstevel@tonic-gate 		packet_send();
2150Sstevel@tonic-gate 		buffer_consume(&stdout_buffer, len);
2160Sstevel@tonic-gate 		stdout_bytes += len;
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate static void
client_alive_check(void)2210Sstevel@tonic-gate client_alive_check(void)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	static int had_channel = 0;
2240Sstevel@tonic-gate 	int id;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	id = channel_find_open();
2270Sstevel@tonic-gate 	if (id == -1) {
2280Sstevel@tonic-gate 		if (!had_channel)
2290Sstevel@tonic-gate 			return;
2300Sstevel@tonic-gate 		packet_disconnect("No open channels after timeout!");
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 	had_channel = 1;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	/* timeout, check to see how many we have had */
2350Sstevel@tonic-gate 	if (++client_alive_timeouts > options.client_alive_count_max)
2360Sstevel@tonic-gate 		packet_disconnect("Timeout, your session not responding.");
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * send a bogus channel request with "wantreply",
2400Sstevel@tonic-gate 	 * we should get back a failure
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 	channel_request_start(id, "keepalive@openssh.com", 1);
2430Sstevel@tonic-gate 	packet_send();
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * Sleep in select() until we can do something.  This will initialize the
2480Sstevel@tonic-gate  * select masks.  Upon return, the masks will indicate which descriptors
2490Sstevel@tonic-gate  * have data or can accept data.  Optionally, a maximum time can be specified
2500Sstevel@tonic-gate  * for the duration of the wait (0 = infinite).
2510Sstevel@tonic-gate  */
2520Sstevel@tonic-gate static void
wait_until_can_do_something(fd_set ** readsetp,fd_set ** writesetp,int * maxfdp,int * nallocp,u_int max_time_milliseconds)2530Sstevel@tonic-gate wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2540Sstevel@tonic-gate     int *nallocp, u_int max_time_milliseconds)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	struct timeval tv, *tvp;
2570Sstevel@tonic-gate 	int ret;
2580Sstevel@tonic-gate 	int client_alive_scheduled = 0;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/*
2610Sstevel@tonic-gate 	 * if using client_alive, set the max timeout accordingly,
2620Sstevel@tonic-gate 	 * and indicate that this particular timeout was for client
2630Sstevel@tonic-gate 	 * alive by setting the client_alive_scheduled flag.
2640Sstevel@tonic-gate 	 *
2650Sstevel@tonic-gate 	 * this could be randomized somewhat to make traffic
2660Sstevel@tonic-gate 	 * analysis more difficult, but we're not doing it yet.
2670Sstevel@tonic-gate 	 */
2680Sstevel@tonic-gate 	if (compat20 &&
2690Sstevel@tonic-gate 	    max_time_milliseconds == 0 && options.client_alive_interval) {
2700Sstevel@tonic-gate 		client_alive_scheduled = 1;
2710Sstevel@tonic-gate 		max_time_milliseconds = options.client_alive_interval * 1000;
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/* Allocate and update select() masks for channel descriptors. */
2750Sstevel@tonic-gate 	channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if (compat20) {
2780Sstevel@tonic-gate #ifdef ALTPRIVSEP
2790Sstevel@tonic-gate 		int pipe_fd;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 		if ((pipe_fd = altprivsep_get_pipe_fd()) != -1) {
2820Sstevel@tonic-gate 			*maxfdp = MAX(*maxfdp, pipe_fd);
2830Sstevel@tonic-gate 			FD_SET(altprivsep_get_pipe_fd(), *readsetp);
2840Sstevel@tonic-gate 		}
2850Sstevel@tonic-gate #endif /* ALTPRIVSEP */
2860Sstevel@tonic-gate #if 0
2870Sstevel@tonic-gate 		/* wrong: bad condition XXX */
2880Sstevel@tonic-gate 		if (channel_not_very_much_buffered_data())
2890Sstevel@tonic-gate #endif
2900Sstevel@tonic-gate 		FD_SET(connection_in, *readsetp);
2910Sstevel@tonic-gate 	} else {
2920Sstevel@tonic-gate 		/*
2930Sstevel@tonic-gate 		 * Read packets from the client unless we have too much
2940Sstevel@tonic-gate 		 * buffered stdin or channel data.
2950Sstevel@tonic-gate 		 */
2960Sstevel@tonic-gate 		if (buffer_len(&stdin_buffer) < buffer_high &&
2970Sstevel@tonic-gate 		    channel_not_very_much_buffered_data())
2980Sstevel@tonic-gate 			FD_SET(connection_in, *readsetp);
2990Sstevel@tonic-gate 		/*
3000Sstevel@tonic-gate 		 * If there is not too much data already buffered going to
3010Sstevel@tonic-gate 		 * the client, try to get some more data from the program.
3020Sstevel@tonic-gate 		 */
3030Sstevel@tonic-gate 		if (packet_not_very_much_data_to_write()) {
3040Sstevel@tonic-gate 			if (!fdout_eof)
3050Sstevel@tonic-gate 				FD_SET(fdout, *readsetp);
3060Sstevel@tonic-gate 			if (!fderr_eof)
3070Sstevel@tonic-gate 				FD_SET(fderr, *readsetp);
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 		/*
3100Sstevel@tonic-gate 		 * If we have buffered data, try to write some of that data
3110Sstevel@tonic-gate 		 * to the program.
3120Sstevel@tonic-gate 		 */
3130Sstevel@tonic-gate 		if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
3140Sstevel@tonic-gate 			FD_SET(fdin, *writesetp);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	notify_prepare(*readsetp);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	/*
3190Sstevel@tonic-gate 	 * If we have buffered packet data going to the client, mark that
3200Sstevel@tonic-gate 	 * descriptor.
3210Sstevel@tonic-gate 	 */
3220Sstevel@tonic-gate 	if (packet_have_data_to_write())
3230Sstevel@tonic-gate 		FD_SET(connection_out, *writesetp);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * If child has terminated and there is enough buffer space to read
3270Sstevel@tonic-gate 	 * from it, then read as much as is available and exit.
3280Sstevel@tonic-gate 	 */
3290Sstevel@tonic-gate 	if (child_terminated && packet_not_very_much_data_to_write())
3300Sstevel@tonic-gate 		if (max_time_milliseconds == 0 || client_alive_scheduled)
3310Sstevel@tonic-gate 			max_time_milliseconds = 100;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (max_time_milliseconds == 0)
3340Sstevel@tonic-gate 		tvp = NULL;
3350Sstevel@tonic-gate 	else {
3360Sstevel@tonic-gate 		tv.tv_sec = max_time_milliseconds / 1000;
3370Sstevel@tonic-gate 		tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
3380Sstevel@tonic-gate 		tvp = &tv;
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	/* Wait for something to happen, or the timeout to expire. */
3420Sstevel@tonic-gate 	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (ret == -1) {
3450Sstevel@tonic-gate 		memset(*readsetp, 0, *nallocp);
3460Sstevel@tonic-gate 		memset(*writesetp, 0, *nallocp);
3470Sstevel@tonic-gate 		if (errno != EINTR)
3480Sstevel@tonic-gate 			error("select: %.100s", strerror(errno));
3490Sstevel@tonic-gate 	} else if (ret == 0 && client_alive_scheduled)
3500Sstevel@tonic-gate 		client_alive_check();
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	notify_done(*readsetp);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * Processes input from the client and the program.  Input data is stored
3570Sstevel@tonic-gate  * in buffers and processed later.
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate static void
process_input(fd_set * readset)3600Sstevel@tonic-gate process_input(fd_set * readset)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	int len;
3630Sstevel@tonic-gate 	char buf[16384];
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/* Read and buffer any input data from the client. */
3660Sstevel@tonic-gate 	if (FD_ISSET(connection_in, readset)) {
3670Sstevel@tonic-gate 		len = read(connection_in, buf, sizeof(buf));
3680Sstevel@tonic-gate 		if (len == 0) {
3697574SJan.Pechanec@Sun.COM 			if (packet_is_monitor()) {
3707574SJan.Pechanec@Sun.COM 				debug("child closed the communication pipe");
3717574SJan.Pechanec@Sun.COM 			} else {
3727574SJan.Pechanec@Sun.COM 				verbose("Connection closed by %.100s",
3737574SJan.Pechanec@Sun.COM 				    get_remote_ipaddr());
3747574SJan.Pechanec@Sun.COM 			}
3750Sstevel@tonic-gate 			connection_closed = 1;
3760Sstevel@tonic-gate 			if (compat20)
3770Sstevel@tonic-gate 				return;
3780Sstevel@tonic-gate 			fatal_cleanup();
3790Sstevel@tonic-gate 		} else if (len < 0) {
3800Sstevel@tonic-gate 			if (errno != EINTR && errno != EAGAIN) {
3810Sstevel@tonic-gate 				verbose("Read error from remote host "
3820Sstevel@tonic-gate 				    "%.100s: %.100s",
3830Sstevel@tonic-gate 				    get_remote_ipaddr(), strerror(errno));
3840Sstevel@tonic-gate 				fatal_cleanup();
3850Sstevel@tonic-gate 			}
3860Sstevel@tonic-gate 		} else {
3870Sstevel@tonic-gate 			/* Buffer any received data. */
3880Sstevel@tonic-gate 			packet_process_incoming(buf, len);
3890Sstevel@tonic-gate 		}
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 	if (compat20)
3920Sstevel@tonic-gate 		return;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	/* Read and buffer any available stdout data from the program. */
3950Sstevel@tonic-gate 	if (!fdout_eof && FD_ISSET(fdout, readset)) {
3960Sstevel@tonic-gate 		len = read(fdout, buf, sizeof(buf));
3970Sstevel@tonic-gate 		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
3980Sstevel@tonic-gate 			/* EMPTY */
3990Sstevel@tonic-gate 		} else if (len <= 0) {
4000Sstevel@tonic-gate 			fdout_eof = 1;
4010Sstevel@tonic-gate 		} else {
4020Sstevel@tonic-gate 			buffer_append(&stdout_buffer, buf, len);
4030Sstevel@tonic-gate 			fdout_bytes += len;
4040Sstevel@tonic-gate 		}
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 	/* Read and buffer any available stderr data from the program. */
4070Sstevel@tonic-gate 	if (!fderr_eof && FD_ISSET(fderr, readset)) {
4080Sstevel@tonic-gate 		len = read(fderr, buf, sizeof(buf));
4090Sstevel@tonic-gate 		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
4100Sstevel@tonic-gate 			/* EMPTY */
4110Sstevel@tonic-gate 		} else if (len <= 0) {
4120Sstevel@tonic-gate 			fderr_eof = 1;
4130Sstevel@tonic-gate 		} else {
4140Sstevel@tonic-gate 			buffer_append(&stderr_buffer, buf, len);
4150Sstevel@tonic-gate 		}
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * Sends data from internal buffers to client program stdin.
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate static void
process_output(fd_set * writeset)4230Sstevel@tonic-gate process_output(fd_set * writeset)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate 	struct termios tio;
4260Sstevel@tonic-gate 	u_char *data;
4270Sstevel@tonic-gate 	u_int dlen;
4280Sstevel@tonic-gate 	int len;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/* Write buffered data to program stdin. */
4310Sstevel@tonic-gate 	if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
4320Sstevel@tonic-gate 		data = buffer_ptr(&stdin_buffer);
4330Sstevel@tonic-gate 		dlen = buffer_len(&stdin_buffer);
4340Sstevel@tonic-gate 		len = write(fdin, data, dlen);
4350Sstevel@tonic-gate 		if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
4360Sstevel@tonic-gate 			/* EMPTY */
4370Sstevel@tonic-gate 		} else if (len <= 0) {
4380Sstevel@tonic-gate 			if (fdin != fdout)
4390Sstevel@tonic-gate 				(void) close(fdin);
4400Sstevel@tonic-gate 			else
4410Sstevel@tonic-gate 				(void) shutdown(fdin, SHUT_WR); /* We will no longer send. */
4420Sstevel@tonic-gate 			fdin = -1;
4430Sstevel@tonic-gate 		} else {
4440Sstevel@tonic-gate 			/* Successful write. */
4450Sstevel@tonic-gate 			if (fdin_is_tty && dlen >= 1 && data[0] != '\r' &&
4460Sstevel@tonic-gate 			    tcgetattr(fdin, &tio) == 0 &&
4470Sstevel@tonic-gate 			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
4480Sstevel@tonic-gate 				/*
4490Sstevel@tonic-gate 				 * Simulate echo to reduce the impact of
4500Sstevel@tonic-gate 				 * traffic analysis
4510Sstevel@tonic-gate 				 */
4520Sstevel@tonic-gate 				packet_send_ignore(len);
4530Sstevel@tonic-gate 				packet_send();
4540Sstevel@tonic-gate 			}
4550Sstevel@tonic-gate 			/* Consume the data from the buffer. */
4560Sstevel@tonic-gate 			buffer_consume(&stdin_buffer, len);
4570Sstevel@tonic-gate 			/* Update the count of bytes written to the program. */
4580Sstevel@tonic-gate 			stdin_bytes += len;
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 	/* Send any buffered packet data to the client. */
4620Sstevel@tonic-gate 	if (FD_ISSET(connection_out, writeset))
4630Sstevel@tonic-gate 		packet_write_poll();
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate  * Wait until all buffered output has been sent to the client.
4680Sstevel@tonic-gate  * This is used when the program terminates.
4690Sstevel@tonic-gate  */
4700Sstevel@tonic-gate static void
drain_output(void)4710Sstevel@tonic-gate drain_output(void)
4720Sstevel@tonic-gate {
4730Sstevel@tonic-gate 	/* Send any buffered stdout data to the client. */
4740Sstevel@tonic-gate 	if (buffer_len(&stdout_buffer) > 0) {
4750Sstevel@tonic-gate 		packet_start(SSH_SMSG_STDOUT_DATA);
4760Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&stdout_buffer),
4770Sstevel@tonic-gate 				  buffer_len(&stdout_buffer));
4780Sstevel@tonic-gate 		packet_send();
4790Sstevel@tonic-gate 		/* Update the count of sent bytes. */
4800Sstevel@tonic-gate 		stdout_bytes += buffer_len(&stdout_buffer);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 	/* Send any buffered stderr data to the client. */
4830Sstevel@tonic-gate 	if (buffer_len(&stderr_buffer) > 0) {
4840Sstevel@tonic-gate 		packet_start(SSH_SMSG_STDERR_DATA);
4850Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&stderr_buffer),
4860Sstevel@tonic-gate 				  buffer_len(&stderr_buffer));
4870Sstevel@tonic-gate 		packet_send();
4880Sstevel@tonic-gate 		/* Update the count of sent bytes. */
4890Sstevel@tonic-gate 		stderr_bytes += buffer_len(&stderr_buffer);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	/* Wait until all buffered data has been written to the client. */
4920Sstevel@tonic-gate 	packet_write_wait();
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate static void
process_buffered_input_packets(void)4960Sstevel@tonic-gate process_buffered_input_packets(void)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 	dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate /*
5020Sstevel@tonic-gate  * Performs the interactive session.  This handles data transmission between
5030Sstevel@tonic-gate  * the client and the program.  Note that the notion of stdin, stdout, and
5040Sstevel@tonic-gate  * stderr in this function is sort of reversed: this function writes to
5050Sstevel@tonic-gate  * stdin (of the child program), and reads from stdout and stderr (of the
5060Sstevel@tonic-gate  * child program).
5070Sstevel@tonic-gate  */
5080Sstevel@tonic-gate void
server_loop(pid_t pid,int fdin_arg,int fdout_arg,int fderr_arg)5090Sstevel@tonic-gate server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate 	fd_set *readset = NULL, *writeset = NULL;
5120Sstevel@tonic-gate 	int max_fd = 0, nalloc = 0;
5130Sstevel@tonic-gate 	int wait_status;	/* Status returned by wait(). */
5140Sstevel@tonic-gate 	pid_t wait_pid;		/* pid returned by wait(). */
5150Sstevel@tonic-gate 	int waiting_termination = 0;	/* Have displayed waiting close message. */
5160Sstevel@tonic-gate 	u_int max_time_milliseconds;
5170Sstevel@tonic-gate 	u_int previous_stdout_buffer_bytes;
5180Sstevel@tonic-gate 	u_int stdout_buffer_bytes;
5190Sstevel@tonic-gate 	int type;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	debug("Entering interactive session.");
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	/* Initialize the SIGCHLD kludge. */
5240Sstevel@tonic-gate 	child_terminated = 0;
5250Sstevel@tonic-gate 	mysignal(SIGCHLD, sigchld_handler);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	/* Initialize our global variables. */
5280Sstevel@tonic-gate 	fdin = fdin_arg;
5290Sstevel@tonic-gate 	fdout = fdout_arg;
5300Sstevel@tonic-gate 	fderr = fderr_arg;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	/* nonblocking IO */
5330Sstevel@tonic-gate 	set_nonblock(fdin);
5340Sstevel@tonic-gate 	set_nonblock(fdout);
5350Sstevel@tonic-gate 	/* we don't have stderr for interactive terminal sessions, see below */
5360Sstevel@tonic-gate 	if (fderr != -1)
5370Sstevel@tonic-gate 		set_nonblock(fderr);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin))
5400Sstevel@tonic-gate 		fdin_is_tty = 1;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	connection_in = packet_get_connection_in();
5430Sstevel@tonic-gate 	connection_out = packet_get_connection_out();
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	notify_setup();
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	previous_stdout_buffer_bytes = 0;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	/* Set approximate I/O buffer size. */
5500Sstevel@tonic-gate 	if (packet_is_interactive())
5510Sstevel@tonic-gate 		buffer_high = 4096;
5520Sstevel@tonic-gate 	else
5530Sstevel@tonic-gate 		buffer_high = 64 * 1024;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate #if 0
5560Sstevel@tonic-gate 	/* Initialize max_fd to the maximum of the known file descriptors. */
5570Sstevel@tonic-gate 	max_fd = MAX(connection_in, connection_out);
5580Sstevel@tonic-gate 	max_fd = MAX(max_fd, fdin);
5590Sstevel@tonic-gate 	max_fd = MAX(max_fd, fdout);
5600Sstevel@tonic-gate 	if (fderr != -1)
5610Sstevel@tonic-gate 		max_fd = MAX(max_fd, fderr);
5620Sstevel@tonic-gate #endif
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/* Initialize Initialize buffers. */
5650Sstevel@tonic-gate 	buffer_init(&stdin_buffer);
5660Sstevel@tonic-gate 	buffer_init(&stdout_buffer);
5670Sstevel@tonic-gate 	buffer_init(&stderr_buffer);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	/*
5700Sstevel@tonic-gate 	 * If we have no separate fderr (which is the case when we have a pty
5710Sstevel@tonic-gate 	 * - there we cannot make difference between data sent to stdout and
5720Sstevel@tonic-gate 	 * stderr), indicate that we have seen an EOF from stderr.  This way
5730Sstevel@tonic-gate 	 * we don\'t need to check the descriptor everywhere.
5740Sstevel@tonic-gate 	 */
5750Sstevel@tonic-gate 	if (fderr == -1)
5760Sstevel@tonic-gate 		fderr_eof = 1;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	server_init_dispatch();
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/* Main loop of the server for the interactive session mode. */
5810Sstevel@tonic-gate 	for (;;) {
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		/* Process buffered packets from the client. */
5840Sstevel@tonic-gate 		process_buffered_input_packets();
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 		/*
5870Sstevel@tonic-gate 		 * If we have received eof, and there is no more pending
5880Sstevel@tonic-gate 		 * input data, cause a real eof by closing fdin.
5890Sstevel@tonic-gate 		 */
5900Sstevel@tonic-gate 		if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
5910Sstevel@tonic-gate 			if (fdin != fdout)
5920Sstevel@tonic-gate 				(void) close(fdin);
5930Sstevel@tonic-gate 			else
5940Sstevel@tonic-gate 				(void) shutdown(fdin, SHUT_WR); /* We will no longer send. */
5950Sstevel@tonic-gate 			fdin = -1;
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 		/* Make packets from buffered stderr data to send to the client. */
5980Sstevel@tonic-gate 		make_packets_from_stderr_data();
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 		/*
6010Sstevel@tonic-gate 		 * Make packets from buffered stdout data to send to the
6020Sstevel@tonic-gate 		 * client. If there is very little to send, this arranges to
6030Sstevel@tonic-gate 		 * not send them now, but to wait a short while to see if we
6040Sstevel@tonic-gate 		 * are getting more data. This is necessary, as some systems
6050Sstevel@tonic-gate 		 * wake up readers from a pty after each separate character.
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		max_time_milliseconds = 0;
6080Sstevel@tonic-gate 		stdout_buffer_bytes = buffer_len(&stdout_buffer);
6090Sstevel@tonic-gate 		if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
6100Sstevel@tonic-gate 		    stdout_buffer_bytes != previous_stdout_buffer_bytes) {
6110Sstevel@tonic-gate 			/* try again after a while */
6120Sstevel@tonic-gate 			max_time_milliseconds = 10;
6130Sstevel@tonic-gate 		} else {
6140Sstevel@tonic-gate 			/* Send it now. */
6150Sstevel@tonic-gate 			make_packets_from_stdout_data();
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 		previous_stdout_buffer_bytes = buffer_len(&stdout_buffer);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 		/* Send channel data to the client. */
6200Sstevel@tonic-gate 		if (packet_not_very_much_data_to_write())
6210Sstevel@tonic-gate 			channel_output_poll();
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		/*
6240Sstevel@tonic-gate 		 * Bail out of the loop if the program has closed its output
6250Sstevel@tonic-gate 		 * descriptors, and we have no more data to send to the
6260Sstevel@tonic-gate 		 * client, and there is no pending buffered data.
6270Sstevel@tonic-gate 		 */
6280Sstevel@tonic-gate 		if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
6290Sstevel@tonic-gate 		    buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
6300Sstevel@tonic-gate 			if (!channel_still_open())
6310Sstevel@tonic-gate 				break;
6320Sstevel@tonic-gate 			if (!waiting_termination) {
6330Sstevel@tonic-gate 				const char *s = "Waiting for forwarded connections to terminate...\r\n";
6340Sstevel@tonic-gate 				char *cp;
6350Sstevel@tonic-gate 				waiting_termination = 1;
6360Sstevel@tonic-gate 				buffer_append(&stderr_buffer, s, strlen(s));
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 				/* Display list of open channels. */
6390Sstevel@tonic-gate 				cp = channel_open_message();
6400Sstevel@tonic-gate 				buffer_append(&stderr_buffer, cp, strlen(cp));
6410Sstevel@tonic-gate 				xfree(cp);
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 		max_fd = MAX(connection_in, connection_out);
6450Sstevel@tonic-gate 		max_fd = MAX(max_fd, fdin);
6460Sstevel@tonic-gate 		max_fd = MAX(max_fd, fdout);
6470Sstevel@tonic-gate 		max_fd = MAX(max_fd, fderr);
6480Sstevel@tonic-gate 		max_fd = MAX(max_fd, notify_pipe[0]);
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/* Sleep in select() until we can do something. */
6510Sstevel@tonic-gate 		wait_until_can_do_something(&readset, &writeset, &max_fd,
6520Sstevel@tonic-gate 		    &nalloc, max_time_milliseconds);
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		/* Process any channel events. */
6550Sstevel@tonic-gate 		channel_after_select(readset, writeset);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 		/* Process input from the client and from program stdout/stderr. */
6580Sstevel@tonic-gate 		process_input(readset);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		/* Process output to the client and to program stdin. */
6610Sstevel@tonic-gate 		process_output(writeset);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 	if (readset)
6640Sstevel@tonic-gate 		xfree(readset);
6650Sstevel@tonic-gate 	if (writeset)
6660Sstevel@tonic-gate 		xfree(writeset);
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	/* Cleanup and termination code. */
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/* Wait until all output has been sent to the client. */
6710Sstevel@tonic-gate 	drain_output();
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.",
6740Sstevel@tonic-gate 	    stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes);
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/* Free and clear the buffers. */
6770Sstevel@tonic-gate 	buffer_free(&stdin_buffer);
6780Sstevel@tonic-gate 	buffer_free(&stdout_buffer);
6790Sstevel@tonic-gate 	buffer_free(&stderr_buffer);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* Close the file descriptors. */
6820Sstevel@tonic-gate 	if (fdout != -1)
6830Sstevel@tonic-gate 		(void) close(fdout);
6840Sstevel@tonic-gate 	fdout = -1;
6850Sstevel@tonic-gate 	fdout_eof = 1;
6860Sstevel@tonic-gate 	if (fderr != -1)
6870Sstevel@tonic-gate 		(void) close(fderr);
6880Sstevel@tonic-gate 	fderr = -1;
6890Sstevel@tonic-gate 	fderr_eof = 1;
6900Sstevel@tonic-gate 	if (fdin != -1)
6910Sstevel@tonic-gate 		(void) close(fdin);
6920Sstevel@tonic-gate 	fdin = -1;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	channel_free_all();
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/* We no longer want our SIGCHLD handler to be called. */
6970Sstevel@tonic-gate 	mysignal(SIGCHLD, SIG_DFL);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0)
7000Sstevel@tonic-gate 		if (errno != EINTR)
7010Sstevel@tonic-gate 			packet_disconnect("wait: %.100s", strerror(errno));
7020Sstevel@tonic-gate 	if (wait_pid != pid)
7030Sstevel@tonic-gate 		error("Strange, wait returned pid %ld, expected %ld",
7040Sstevel@tonic-gate 		    (long)wait_pid, (long)pid);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/* Check if it exited normally. */
7070Sstevel@tonic-gate 	if (WIFEXITED(wait_status)) {
7080Sstevel@tonic-gate 		/* Yes, normal exit.  Get exit status and send it to the client. */
7090Sstevel@tonic-gate 		debug("Command exited with status %d.", WEXITSTATUS(wait_status));
7100Sstevel@tonic-gate 		packet_start(SSH_SMSG_EXITSTATUS);
7110Sstevel@tonic-gate 		packet_put_int(WEXITSTATUS(wait_status));
7120Sstevel@tonic-gate 		packet_send();
7130Sstevel@tonic-gate 		packet_write_wait();
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 		/*
7160Sstevel@tonic-gate 		 * Wait for exit confirmation.  Note that there might be
7170Sstevel@tonic-gate 		 * other packets coming before it; however, the program has
7180Sstevel@tonic-gate 		 * already died so we just ignore them.  The client is
7190Sstevel@tonic-gate 		 * supposed to respond with the confirmation when it receives
7200Sstevel@tonic-gate 		 * the exit status.
7210Sstevel@tonic-gate 		 */
7220Sstevel@tonic-gate 		do {
7230Sstevel@tonic-gate 			type = packet_read();
7240Sstevel@tonic-gate 		}
7250Sstevel@tonic-gate 		while (type != SSH_CMSG_EXIT_CONFIRMATION);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		debug("Received exit confirmation.");
7280Sstevel@tonic-gate 		return;
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 	/* Check if the program terminated due to a signal. */
7310Sstevel@tonic-gate 	if (WIFSIGNALED(wait_status))
7320Sstevel@tonic-gate 		packet_disconnect("Command terminated on signal %d.",
7330Sstevel@tonic-gate 				  WTERMSIG(wait_status));
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	/* Some weird exit cause.  Just exit. */
7360Sstevel@tonic-gate 	packet_disconnect("wait returned status %04x.", wait_status);
7370Sstevel@tonic-gate 	/* NOTREACHED */
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate static void
collect_children(void)7410Sstevel@tonic-gate collect_children(void)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	pid_t pid;
7440Sstevel@tonic-gate 	sigset_t oset, nset;
7450Sstevel@tonic-gate 	int status;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/* block SIGCHLD while we check for dead children */
7480Sstevel@tonic-gate 	(void) sigemptyset(&nset);
7490Sstevel@tonic-gate 	(void) sigaddset(&nset, SIGCHLD);
7500Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
7510Sstevel@tonic-gate 	if (child_terminated) {
7520Sstevel@tonic-gate 		while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
7530Sstevel@tonic-gate 		    (pid < 0 && errno == EINTR))
7540Sstevel@tonic-gate 			if (pid > 0)
7550Sstevel@tonic-gate 				session_close_by_pid(pid, status);
7560Sstevel@tonic-gate 		child_terminated = 0;
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate #ifdef ALTPRIVSEP
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate  * For ALTPRIVSEP the wait_until_can_do_something function is very
7640Sstevel@tonic-gate  * simple: select() on the read side of the pipe, and if there's packets
7650Sstevel@tonic-gate  * to send, on the write side, and on the read side of the SIGCHLD
7660Sstevel@tonic-gate  * handler pipe.  That's it.
7670Sstevel@tonic-gate  */
7680Sstevel@tonic-gate static void
aps_wait_until_can_do_something(fd_set ** readsetp,fd_set ** writesetp,int * maxfdp,int * nallocp,u_int max_time_milliseconds)7690Sstevel@tonic-gate aps_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
7700Sstevel@tonic-gate 	int *maxfdp, int *nallocp, u_int max_time_milliseconds)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	int ret;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * Use channel_prepare_select() to make the fd sets.
7760Sstevel@tonic-gate 	 *
7770Sstevel@tonic-gate 	 * This is cheating, really, since because the last argument in
7780Sstevel@tonic-gate 	 * this call is '1' nothing related to channels will be done --
7790Sstevel@tonic-gate 	 * we're using this function only to callocate the fd sets.
7800Sstevel@tonic-gate 	 */
7810Sstevel@tonic-gate 	channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 1);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	if ((connection_in = packet_get_connection_in()) >= 0 &&
7840Sstevel@tonic-gate 	    !connection_closed)
7850Sstevel@tonic-gate 		FD_SET(connection_in, *readsetp);
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	notify_prepare(*readsetp);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	if ((connection_out = packet_get_connection_out()) >= 0 &&
7900Sstevel@tonic-gate 	    packet_have_data_to_write() && !connection_closed)
7910Sstevel@tonic-gate 		FD_SET(connection_out, *writesetp);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	/* Wait for something to happen, or the timeout to expire. */
7940Sstevel@tonic-gate 	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL);
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if (ret == -1) {
7970Sstevel@tonic-gate 		memset(*readsetp, 0, *nallocp);
7980Sstevel@tonic-gate 		memset(*writesetp, 0, *nallocp);
7990Sstevel@tonic-gate 		if (errno != EINTR)
8000Sstevel@tonic-gate 			error("select: %.100s", strerror(errno));
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	notify_done(*readsetp);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate /*
8070Sstevel@tonic-gate  * Slightly different than collect_children, aps_collect_child() has
8080Sstevel@tonic-gate  * only the unprivileged sshd to wait for, no sessions, no channells,
8090Sstevel@tonic-gate  * just one process.
8100Sstevel@tonic-gate  */
8110Sstevel@tonic-gate static int
aps_collect_child(pid_t child)8120Sstevel@tonic-gate aps_collect_child(pid_t child)
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate 	pid_t pid;
8150Sstevel@tonic-gate 	sigset_t oset, nset;
8160Sstevel@tonic-gate 	int status;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/* block SIGCHLD while we check for dead children */
8190Sstevel@tonic-gate 	(void) sigemptyset(&nset);
8200Sstevel@tonic-gate 	(void) sigaddset(&nset, SIGCHLD);
8210Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
8220Sstevel@tonic-gate 	if (child_terminated) {
8230Sstevel@tonic-gate 		while ((pid = waitpid(child, &status, WNOHANG)) > 0 ||
8240Sstevel@tonic-gate 		    (pid < 0 && errno == EINTR))
8250Sstevel@tonic-gate 			if (pid == child) {
8260Sstevel@tonic-gate 				(void) sigprocmask(SIG_SETMASK, &oset, NULL);
8270Sstevel@tonic-gate 				return (1);
8280Sstevel@tonic-gate 			}
8290Sstevel@tonic-gate 		child_terminated = 0;
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
8320Sstevel@tonic-gate 	return (0);
8330Sstevel@tonic-gate }
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate static int killed = 0;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate static void
aps_monitor_kill_handler(int sig)8380Sstevel@tonic-gate aps_monitor_kill_handler(int sig)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	int save_errno = errno;
8410Sstevel@tonic-gate 	killed = 1;
8420Sstevel@tonic-gate 	notify_parent();
8430Sstevel@tonic-gate 	mysignal(sig, aps_monitor_kill_handler);
8440Sstevel@tonic-gate 	errno = save_errno;
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate static void
aps_monitor_sigchld_handler(int sig)8480Sstevel@tonic-gate aps_monitor_sigchld_handler(int sig)
8490Sstevel@tonic-gate {
8500Sstevel@tonic-gate 	int save_errno = errno;
8510Sstevel@tonic-gate 	debug("Monitor received SIGCHLD.");
8520Sstevel@tonic-gate 	child_terminated = 1;
8530Sstevel@tonic-gate 	mysignal(SIGCHLD, aps_monitor_sigchld_handler);
8540Sstevel@tonic-gate 	notify_parent();
8550Sstevel@tonic-gate 	errno = save_errno;
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate void
aps_monitor_loop(Authctxt * authctxt,pid_t child_pid)8597574SJan.Pechanec@Sun.COM aps_monitor_loop(Authctxt *authctxt, pid_t child_pid)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	fd_set *readset = NULL, *writeset = NULL;
8620Sstevel@tonic-gate 	int max_fd, nalloc = 0;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	debug("Entering monitor loop.");
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	/*
8670Sstevel@tonic-gate 	 * Awful hack follows: fake compat20 == 1 to cause process_input()
8680Sstevel@tonic-gate 	 * and process_output() to behave as they would for SSHv2 because that's
8690Sstevel@tonic-gate 	 * the behaviour we need in SSHv2.
8700Sstevel@tonic-gate 	 *
8710Sstevel@tonic-gate 	 * This same hack is done in packet.c
8720Sstevel@tonic-gate 	 */
8730Sstevel@tonic-gate 	compat20 = 1; /* causes process_input/output() to ignore stdio */
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	mysignal(SIGHUP, aps_monitor_kill_handler);
8760Sstevel@tonic-gate 	mysignal(SIGINT, aps_monitor_kill_handler);
8770Sstevel@tonic-gate 	mysignal(SIGTERM, aps_monitor_kill_handler);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	child_terminated = 0;
8800Sstevel@tonic-gate 	mysignal(SIGCHLD, aps_monitor_sigchld_handler);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	connection_in = packet_get_connection_in();
8830Sstevel@tonic-gate 	connection_out = packet_get_connection_out();
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	notify_setup();
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	max_fd = MAX(connection_in, connection_out);
8880Sstevel@tonic-gate 	max_fd = MAX(max_fd, notify_pipe[0]);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
8910Sstevel@tonic-gate 	dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_MAX,
8920Sstevel@tonic-gate 		&dispatch_protocol_error);
8930Sstevel@tonic-gate 	dispatch_set(SSH2_PRIV_MSG_ALTPRIVSEP, &aps_input_altpriv_msg);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	for (;;) {
8960Sstevel@tonic-gate 		process_buffered_input_packets();
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 		aps_wait_until_can_do_something(&readset, &writeset, &max_fd,
8990Sstevel@tonic-gate 		    &nalloc, 0);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 		if (aps_collect_child(child_pid))
9020Sstevel@tonic-gate 			break;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 		if (killed) {
9050Sstevel@tonic-gate 			/* fatal cleanups will kill child, audit logout */
9060Sstevel@tonic-gate 			log("Monitor killed; exiting");
9070Sstevel@tonic-gate 			fatal_cleanup();
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 		/*
9110Sstevel@tonic-gate 		 * Unlike server_loop2() we don't care if connection_closed
9120Sstevel@tonic-gate 		 * since we still want to wait for the monitor's child.
9130Sstevel@tonic-gate 		 */
9140Sstevel@tonic-gate 		process_input(readset);
9150Sstevel@tonic-gate 		process_output(writeset);
9160Sstevel@tonic-gate 	}
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	packet_close();
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate #endif /* ALTPRIVSEP */
9210Sstevel@tonic-gate 
9227574SJan.Pechanec@Sun.COM /*
9237574SJan.Pechanec@Sun.COM  * This server loop is for unprivileged child only. Our monitor runs its own
9247574SJan.Pechanec@Sun.COM  * aps_monitor_loop() funtion.
9257574SJan.Pechanec@Sun.COM  */
9260Sstevel@tonic-gate void
server_loop2(Authctxt * authctxt)9270Sstevel@tonic-gate server_loop2(Authctxt *authctxt)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	fd_set *readset = NULL, *writeset = NULL;
9300Sstevel@tonic-gate 	int rekeying = 0, max_fd, nalloc = 0;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	debug("Entering interactive session for SSH2.");
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	mysignal(SIGCHLD, sigchld_handler);
9350Sstevel@tonic-gate 	child_terminated = 0;
9360Sstevel@tonic-gate 	connection_in = packet_get_connection_in();
9370Sstevel@tonic-gate 	connection_out = packet_get_connection_out();
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	notify_setup();
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	max_fd = MAX(connection_in, connection_out);
9420Sstevel@tonic-gate 	max_fd = MAX(max_fd, notify_pipe[0]);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	xxx_authctxt = authctxt;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	server_init_dispatch();
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	for (;;) {
9490Sstevel@tonic-gate 		process_buffered_input_packets();
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		rekeying = (xxx_kex != NULL && !xxx_kex->done);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		if (!rekeying && packet_not_very_much_data_to_write())
9540Sstevel@tonic-gate 			channel_output_poll();
9550Sstevel@tonic-gate 		wait_until_can_do_something(&readset, &writeset, &max_fd,
9560Sstevel@tonic-gate 		    &nalloc, 0);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		collect_children();
9590Sstevel@tonic-gate 
9605562Sjp161948 		if (!rekeying) {
9610Sstevel@tonic-gate 			channel_after_select(readset, writeset);
9625562Sjp161948 			if (packet_need_rekeying()) {
9636375Sjp161948 				debug("rekey limit reached, need rekeying");
9645562Sjp161948 				xxx_kex->done = 0;
9656375Sjp161948 				debug("poking the monitor to start "
9666375Sjp161948 				    "key re-exchange");
9676375Sjp161948 				altprivsep_start_rekex();
9685562Sjp161948 			}
9695562Sjp161948 		}
9700Sstevel@tonic-gate #ifdef ALTPRIVSEP
9710Sstevel@tonic-gate 		else
9726375Sjp161948 			altprivsep_process_input(readset);
9730Sstevel@tonic-gate #endif /* ALTPRIVSEP */
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		process_input(readset);
9760Sstevel@tonic-gate 		if (connection_closed)
9770Sstevel@tonic-gate 			break;
9780Sstevel@tonic-gate 		process_output(writeset);
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 	collect_children();
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	if (readset)
9830Sstevel@tonic-gate 		xfree(readset);
9840Sstevel@tonic-gate 	if (writeset)
9850Sstevel@tonic-gate 		xfree(writeset);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/* free all channels, no more reads and writes */
9880Sstevel@tonic-gate 	channel_free_all();
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	/* free remaining sessions, e.g. remove wtmp entries */
9910Sstevel@tonic-gate 	session_destroy_all(NULL);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate static void
server_input_channel_failure(int type,u_int32_t seq,void * ctxt)9950Sstevel@tonic-gate server_input_channel_failure(int type, u_int32_t seq, void *ctxt)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	debug("Got CHANNEL_FAILURE for keepalive");
9980Sstevel@tonic-gate 	/*
9990Sstevel@tonic-gate 	 * reset timeout, since we got a sane answer from the client.
10000Sstevel@tonic-gate 	 * even if this was generated by something other than
10010Sstevel@tonic-gate 	 * the bogus CHANNEL_REQUEST we send for keepalives.
10020Sstevel@tonic-gate 	 */
10030Sstevel@tonic-gate 	client_alive_timeouts = 0;
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate static void
server_input_stdin_data(int type,u_int32_t seq,void * ctxt)10070Sstevel@tonic-gate server_input_stdin_data(int type, u_int32_t seq, void *ctxt)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	char *data;
10100Sstevel@tonic-gate 	u_int data_len;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	/* Stdin data from the client.  Append it to the buffer. */
10130Sstevel@tonic-gate 	/* Ignore any data if the client has closed stdin. */
10140Sstevel@tonic-gate 	if (fdin == -1)
10150Sstevel@tonic-gate 		return;
10160Sstevel@tonic-gate 	data = packet_get_string(&data_len);
10170Sstevel@tonic-gate 	packet_check_eom();
10180Sstevel@tonic-gate 	buffer_append(&stdin_buffer, data, data_len);
10190Sstevel@tonic-gate 	memset(data, 0, data_len);
10200Sstevel@tonic-gate 	xfree(data);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate static void
server_input_eof(int type,u_int32_t seq,void * ctxt)10240Sstevel@tonic-gate server_input_eof(int type, u_int32_t seq, void *ctxt)
10250Sstevel@tonic-gate {
10260Sstevel@tonic-gate 	/*
10270Sstevel@tonic-gate 	 * Eof from the client.  The stdin descriptor to the
10280Sstevel@tonic-gate 	 * program will be closed when all buffered data has
10290Sstevel@tonic-gate 	 * drained.
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	debug("EOF received for stdin.");
10320Sstevel@tonic-gate 	packet_check_eom();
10330Sstevel@tonic-gate 	stdin_eof = 1;
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate static void
server_input_window_size(int type,u_int32_t seq,void * ctxt)10370Sstevel@tonic-gate server_input_window_size(int type, u_int32_t seq, void *ctxt)
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	int row = packet_get_int();
10400Sstevel@tonic-gate 	int col = packet_get_int();
10410Sstevel@tonic-gate 	int xpixel = packet_get_int();
10420Sstevel@tonic-gate 	int ypixel = packet_get_int();
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	debug("Window change received.");
10450Sstevel@tonic-gate 	packet_check_eom();
10460Sstevel@tonic-gate 	if (fdin != -1)
10470Sstevel@tonic-gate 		pty_change_window_size(fdin, row, col, xpixel, ypixel);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate static Channel *
server_request_direct_tcpip(char * ctype)10510Sstevel@tonic-gate server_request_direct_tcpip(char *ctype)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate 	Channel *c;
10540Sstevel@tonic-gate 	int sock;
10550Sstevel@tonic-gate 	char *target, *originator;
10560Sstevel@tonic-gate 	int target_port, originator_port;
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	target = packet_get_string(NULL);
10590Sstevel@tonic-gate 	target_port = packet_get_int();
10600Sstevel@tonic-gate 	originator = packet_get_string(NULL);
10610Sstevel@tonic-gate 	originator_port = packet_get_int();
10620Sstevel@tonic-gate 	packet_check_eom();
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
10650Sstevel@tonic-gate 	   originator, originator_port, target, target_port);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	/* XXX check permission */
10680Sstevel@tonic-gate 	sock = channel_connect_to(target, target_port);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	xfree(target);
10710Sstevel@tonic-gate 	xfree(originator);
10720Sstevel@tonic-gate 	if (sock < 0)
10730Sstevel@tonic-gate 		return NULL;
10740Sstevel@tonic-gate 	c = channel_new(ctype, SSH_CHANNEL_CONNECTING,
10750Sstevel@tonic-gate 	    sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
10760Sstevel@tonic-gate 	    CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
10770Sstevel@tonic-gate 	return c;
10780Sstevel@tonic-gate }
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate static Channel *
server_request_session(char * ctype)10810Sstevel@tonic-gate server_request_session(char *ctype)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	Channel *c;
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	debug("input_session_request");
10860Sstevel@tonic-gate 	packet_check_eom();
10870Sstevel@tonic-gate 	/*
10880Sstevel@tonic-gate 	 * A server session has no fd to read or write until a
10890Sstevel@tonic-gate 	 * CHANNEL_REQUEST for a shell is made, so we set the type to
10900Sstevel@tonic-gate 	 * SSH_CHANNEL_LARVAL.  Additionally, a callback for handling all
10910Sstevel@tonic-gate 	 * CHANNEL_REQUEST messages is registered.
10920Sstevel@tonic-gate 	 */
10930Sstevel@tonic-gate 	c = channel_new(ctype, SSH_CHANNEL_LARVAL,
10940Sstevel@tonic-gate 	    -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
10950Sstevel@tonic-gate 	    0, xstrdup("server-session"), 1);
10960Sstevel@tonic-gate 	if (session_open(xxx_authctxt, c->self) != 1) {
10970Sstevel@tonic-gate 		debug("session open failed, free channel %d", c->self);
10980Sstevel@tonic-gate 		channel_free(c);
10990Sstevel@tonic-gate 		return NULL;
11000Sstevel@tonic-gate 	}
11010Sstevel@tonic-gate 	channel_register_cleanup(c->self, session_close_by_channel);
11020Sstevel@tonic-gate 	return c;
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate static void
server_input_channel_open(int type,u_int32_t seq,void * ctxt)11060Sstevel@tonic-gate server_input_channel_open(int type, u_int32_t seq, void *ctxt)
11070Sstevel@tonic-gate {
11080Sstevel@tonic-gate 	Channel *c = NULL;
11090Sstevel@tonic-gate 	char *ctype;
11100Sstevel@tonic-gate 	int rchan;
11110Sstevel@tonic-gate 	u_int rmaxpack, rwindow, len;
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	ctype = packet_get_string(&len);
11140Sstevel@tonic-gate 	rchan = packet_get_int();
11150Sstevel@tonic-gate 	rwindow = packet_get_int();
11160Sstevel@tonic-gate 	rmaxpack = packet_get_int();
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	debug("server_input_channel_open: ctype %s rchan %d win %d max %d",
11190Sstevel@tonic-gate 	    ctype, rchan, rwindow, rmaxpack);
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	if (strcmp(ctype, "session") == 0) {
11220Sstevel@tonic-gate 		c = server_request_session(ctype);
11230Sstevel@tonic-gate 	} else if (strcmp(ctype, "direct-tcpip") == 0) {
11240Sstevel@tonic-gate 		c = server_request_direct_tcpip(ctype);
11250Sstevel@tonic-gate 	}
11260Sstevel@tonic-gate 	if (c != NULL) {
11270Sstevel@tonic-gate 		debug("server_input_channel_open: confirm %s", ctype);
11280Sstevel@tonic-gate 		c->remote_id = rchan;
11290Sstevel@tonic-gate 		c->remote_window = rwindow;
11300Sstevel@tonic-gate 		c->remote_maxpacket = rmaxpack;
11310Sstevel@tonic-gate 		if (c->type != SSH_CHANNEL_CONNECTING) {
11320Sstevel@tonic-gate 			packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
11330Sstevel@tonic-gate 			packet_put_int(c->remote_id);
11340Sstevel@tonic-gate 			packet_put_int(c->self);
11350Sstevel@tonic-gate 			packet_put_int(c->local_window);
11360Sstevel@tonic-gate 			packet_put_int(c->local_maxpacket);
11370Sstevel@tonic-gate 			packet_send();
11380Sstevel@tonic-gate 		}
11390Sstevel@tonic-gate 	} else {
11400Sstevel@tonic-gate 		debug("server_input_channel_open: failure %s", ctype);
11410Sstevel@tonic-gate 		packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
11420Sstevel@tonic-gate 		packet_put_int(rchan);
11430Sstevel@tonic-gate 		packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
11440Sstevel@tonic-gate 		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
11459600SNobutomo.Nakano@Sun.COM 			packet_put_utf8_cstring("open failed");
11460Sstevel@tonic-gate 			packet_put_cstring("");
11470Sstevel@tonic-gate 		}
11480Sstevel@tonic-gate 		packet_send();
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 	xfree(ctype);
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate static void
server_input_global_request(int type,u_int32_t seq,void * ctxt)11540Sstevel@tonic-gate server_input_global_request(int type, u_int32_t seq, void *ctxt)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate 	char *rtype;
11570Sstevel@tonic-gate 	int want_reply;
11580Sstevel@tonic-gate 	int success = 0;
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	rtype = packet_get_string(NULL);
11610Sstevel@tonic-gate 	want_reply = packet_get_char();
11620Sstevel@tonic-gate 	debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	/* -R style forwarding */
11650Sstevel@tonic-gate 	if (strcmp(rtype, "tcpip-forward") == 0) {
11660Sstevel@tonic-gate 		struct passwd *pw;
11670Sstevel@tonic-gate 		char *listen_address;
11680Sstevel@tonic-gate 		u_short listen_port;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		pw = auth_get_user();
11710Sstevel@tonic-gate 		if (pw == NULL)
11720Sstevel@tonic-gate 			fatal("server_input_global_request: no user");
11730Sstevel@tonic-gate 		listen_address = packet_get_string(NULL); /* XXX currently ignored */
11740Sstevel@tonic-gate 		listen_port = (u_short)packet_get_int();
11750Sstevel@tonic-gate 		debug("server_input_global_request: tcpip-forward listen %s port %d",
11760Sstevel@tonic-gate 		    listen_address, listen_port);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 		/* check permissions */
11790Sstevel@tonic-gate 		if (!options.allow_tcp_forwarding ||
11800Sstevel@tonic-gate 		    no_port_forwarding_flag
11810Sstevel@tonic-gate #ifndef NO_IPPORT_RESERVED_CONCEPT
11820Sstevel@tonic-gate 		    || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)
11830Sstevel@tonic-gate #endif
11840Sstevel@tonic-gate 		   ) {
11850Sstevel@tonic-gate 			success = 0;
11860Sstevel@tonic-gate 			packet_send_debug("Server has disabled port forwarding.");
11870Sstevel@tonic-gate 		} else {
11880Sstevel@tonic-gate 			/* Start listening on the port */
11890Sstevel@tonic-gate 			success = channel_setup_remote_fwd_listener(
11900Sstevel@tonic-gate 			    listen_address, listen_port, options.gateway_ports);
11910Sstevel@tonic-gate 		}
11920Sstevel@tonic-gate 		xfree(listen_address);
11935334Sjp161948 	} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
11945334Sjp161948 		char *cancel_address;
11955334Sjp161948 		u_short cancel_port;
11965334Sjp161948 
11975334Sjp161948 		cancel_address = packet_get_string(NULL);
11985334Sjp161948 		cancel_port = (u_short)packet_get_int();
11995334Sjp161948 		debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
12005334Sjp161948 		    cancel_address, cancel_port);
12015334Sjp161948 
12025334Sjp161948 		success = channel_cancel_rport_listener(cancel_address,
12035334Sjp161948 		    cancel_port);
12045334Sjp161948 		xfree(cancel_address);
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 	if (want_reply) {
12070Sstevel@tonic-gate 		packet_start(success ?
12080Sstevel@tonic-gate 		    SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
12090Sstevel@tonic-gate 		packet_send();
12100Sstevel@tonic-gate 		packet_write_wait();
12110Sstevel@tonic-gate 	}
12120Sstevel@tonic-gate 	xfree(rtype);
12130Sstevel@tonic-gate }
12145334Sjp161948 
12150Sstevel@tonic-gate static void
server_input_channel_req(int type,u_int32_t seq,void * ctxt)12160Sstevel@tonic-gate server_input_channel_req(int type, u_int32_t seq, void *ctxt)
12170Sstevel@tonic-gate {
12180Sstevel@tonic-gate 	Channel *c;
12190Sstevel@tonic-gate 	int id, reply, success = 0;
12200Sstevel@tonic-gate 	char *rtype;
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	id = packet_get_int();
12230Sstevel@tonic-gate 	rtype = packet_get_string(NULL);
12240Sstevel@tonic-gate 	reply = packet_get_char();
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	debug("server_input_channel_req: channel %d request %s reply %d",
12270Sstevel@tonic-gate 	    id, rtype, reply);
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	if ((c = channel_lookup(id)) == NULL)
12300Sstevel@tonic-gate 		packet_disconnect("server_input_channel_req: "
12310Sstevel@tonic-gate 		    "unknown channel %d", id);
12320Sstevel@tonic-gate 	if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
12330Sstevel@tonic-gate 		success = session_input_channel_req(c, rtype);
12340Sstevel@tonic-gate 	if (reply) {
12350Sstevel@tonic-gate 		packet_start(success ?
12360Sstevel@tonic-gate 		    SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
12370Sstevel@tonic-gate 		packet_put_int(c->remote_id);
12380Sstevel@tonic-gate 		packet_send();
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 	xfree(rtype);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate static void
server_init_dispatch_20(void)12440Sstevel@tonic-gate server_init_dispatch_20(void)
12450Sstevel@tonic-gate {
12460Sstevel@tonic-gate 	debug("server_init_dispatch_20");
12470Sstevel@tonic-gate 	dispatch_init(&dispatch_protocol_error);
12480Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
12490Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
12500Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
12510Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
12520Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
12530Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
12540Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
12550Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
12560Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
12570Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
12580Sstevel@tonic-gate 	/* client_alive */
12590Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
12600Sstevel@tonic-gate 	/* rekeying */
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate #ifdef ALTPRIVSEP
12630Sstevel@tonic-gate 	/* unprivileged sshd has a kex packet handler that must not be reset */
12640Sstevel@tonic-gate 	debug3("server_init_dispatch_20 -- should we dispatch_set(KEXINIT) here? %d && !%d",
12650Sstevel@tonic-gate 		packet_is_server(), packet_is_monitor());
12660Sstevel@tonic-gate 	if (packet_is_server() && !packet_is_monitor()) {
12670Sstevel@tonic-gate 		debug3("server_init_dispatch_20 -- skipping dispatch_set(KEXINIT) in unpriv proc");
12680Sstevel@tonic-gate 		dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX,
12690Sstevel@tonic-gate 			&altprivsep_rekey);
12700Sstevel@tonic-gate 		return;
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate #endif /* ALTPRIVSEP */
12730Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate static void
server_init_dispatch_13(void)12760Sstevel@tonic-gate server_init_dispatch_13(void)
12770Sstevel@tonic-gate {
12780Sstevel@tonic-gate 	debug("server_init_dispatch_13");
12790Sstevel@tonic-gate 	dispatch_init(NULL);
12800Sstevel@tonic-gate 	dispatch_set(SSH_CMSG_EOF, &server_input_eof);
12810Sstevel@tonic-gate 	dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
12820Sstevel@tonic-gate 	dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
12830Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
12840Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
12850Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
12860Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
12870Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
12880Sstevel@tonic-gate 	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate static void
server_init_dispatch_15(void)12910Sstevel@tonic-gate server_init_dispatch_15(void)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate 	server_init_dispatch_13();
12940Sstevel@tonic-gate 	debug("server_init_dispatch_15");
12950Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
12960Sstevel@tonic-gate 	dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate static void
server_init_dispatch(void)12990Sstevel@tonic-gate server_init_dispatch(void)
13000Sstevel@tonic-gate {
13010Sstevel@tonic-gate 	if (compat20)
13020Sstevel@tonic-gate 		server_init_dispatch_20();
13030Sstevel@tonic-gate 	else if (compat13)
13040Sstevel@tonic-gate 		server_init_dispatch_13();
13050Sstevel@tonic-gate 	else
13060Sstevel@tonic-gate 		server_init_dispatch_15();
13070Sstevel@tonic-gate }
1308