channels.c revision 78827
157429Smarkm/*
257429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
357429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
457429Smarkm *                    All rights reserved
557429Smarkm * This file contains functions for generic socket connection forwarding.
657429Smarkm * There is also code for initiating connection forwarding for X11 connections,
757429Smarkm * arbitrary tcp/ip connections, and the authentication agent connection.
860573Skris *
965668Skris * As far as I am concerned, the code I have written for this software
1065668Skris * can be used freely for any purpose.  Any derived versions of this
1165668Skris * software must be clearly marked as such, and if the derived work is
1265668Skris * incompatible with the protocol description in the RFC file, it must be
1365668Skris * called by a name other than "ssh" or "Secure Shell".
1465668Skris *
1565668Skris *
1660573Skris * SSH2 support added by Markus Friedl.
1765668Skris * Copyright (c) 1999,2000 Markus Friedl.  All rights reserved.
1865668Skris * Copyright (c) 1999 Dug Song.  All rights reserved.
1965668Skris * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
2065668Skris *
2165668Skris * Redistribution and use in source and binary forms, with or without
2265668Skris * modification, are permitted provided that the following conditions
2365668Skris * are met:
2465668Skris * 1. Redistributions of source code must retain the above copyright
2565668Skris *    notice, this list of conditions and the following disclaimer.
2665668Skris * 2. Redistributions in binary form must reproduce the above copyright
2765668Skris *    notice, this list of conditions and the following disclaimer in the
2865668Skris *    documentation and/or other materials provided with the distribution.
2965668Skris *
3065668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3165668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3265668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3365668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3465668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3565668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3665668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3765668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3865668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3965668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4057429Smarkm */
4157429Smarkm
4257429Smarkm#include "includes.h"
4376262SgreenRCSID("$OpenBSD: channels.c,v 1.109 2001/04/17 12:55:03 markus Exp $");
4474500SgreenRCSID("$FreeBSD: head/crypto/openssh/channels.c 78827 2001-06-26 15:15:22Z green $");
4557429Smarkm
4676262Sgreen#include <openssl/rsa.h>
4776262Sgreen#include <openssl/dsa.h>
4876262Sgreen
4957429Smarkm#include "ssh.h"
5076262Sgreen#include "ssh1.h"
5176262Sgreen#include "ssh2.h"
5257429Smarkm#include "packet.h"
5357429Smarkm#include "xmalloc.h"
5457429Smarkm#include "buffer.h"
5576262Sgreen#include "bufaux.h"
5657429Smarkm#include "uidswap.h"
5776262Sgreen#include "log.h"
5876262Sgreen#include "misc.h"
5957429Smarkm#include "channels.h"
6057429Smarkm#include "nchan.h"
6157429Smarkm#include "compat.h"
6276262Sgreen#include "canohost.h"
6365668Skris#include "key.h"
6465668Skris#include "authfd.h"
6565668Skris
6657429Smarkm/* Maximum number of fake X11 displays to try. */
6757429Smarkm#define MAX_DISPLAYS  1000
6857429Smarkm
6957429Smarkm/* Max len of agent socket */
7057429Smarkm#define MAX_SOCKET_NAME 100
7157429Smarkm
7257429Smarkm/*
7357429Smarkm * Pointer to an array containing all allocated channels.  The array is
7457429Smarkm * dynamically extended as needed.
7557429Smarkm */
7657429Smarkmstatic Channel *channels = NULL;
7757429Smarkm
7857429Smarkm/*
7957429Smarkm * Size of the channel array.  All slots of the array must always be
8057429Smarkm * initialized (at least the type field); unused slots are marked with type
8157429Smarkm * SSH_CHANNEL_FREE.
8257429Smarkm */
8357429Smarkmstatic int channels_alloc = 0;
8457429Smarkm
8557429Smarkm/*
8657429Smarkm * Maximum file descriptor value used in any of the channels.  This is
8757429Smarkm * updated in channel_allocate.
8857429Smarkm */
8976262Sgreenstatic int channel_max_fd = 0;
9057429Smarkm
9157429Smarkm/* Name and directory of socket for authentication agent forwarding. */
9257429Smarkmstatic char *channel_forwarded_auth_socket_name = NULL;
9357429Smarkmstatic char *channel_forwarded_auth_socket_dir = NULL;
9457429Smarkm
9557429Smarkm/* Saved X11 authentication protocol name. */
9657429Smarkmchar *x11_saved_proto = NULL;
9757429Smarkm
9857429Smarkm/* Saved X11 authentication data.  This is the real data. */
9957429Smarkmchar *x11_saved_data = NULL;
10076262Sgreenu_int x11_saved_data_len = 0;
10157429Smarkm
10257429Smarkm/*
10357429Smarkm * Fake X11 authentication data.  This is what the server will be sending us;
10457429Smarkm * we should replace any occurrences of this by the real data.
10557429Smarkm */
10657429Smarkmchar *x11_fake_data = NULL;
10776262Sgreenu_int x11_fake_data_len;
10857429Smarkm
10957429Smarkm/*
11057429Smarkm * Data structure for storing which hosts are permitted for forward requests.
11157429Smarkm * The local sides of any remote forwards are stored in this array to prevent
11257429Smarkm * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
11357429Smarkm * network (which might be behind a firewall).
11457429Smarkm */
11557429Smarkmtypedef struct {
11660573Skris	char *host_to_connect;		/* Connect to 'host'. */
11760573Skris	u_short port_to_connect;	/* Connect to 'port'. */
11860573Skris	u_short listen_port;		/* Remote side should listen port number. */
11957429Smarkm} ForwardPermission;
12057429Smarkm
12157429Smarkm/* List of all permitted host/port pairs to connect. */
12257429Smarkmstatic ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
12357429Smarkm/* Number of permitted host/port pairs in the array. */
12457429Smarkmstatic int num_permitted_opens = 0;
12557429Smarkm/*
12657429Smarkm * If this is true, all opens are permitted.  This is the case on the server
12757429Smarkm * on which we have to trust the client anyway, and the user could do
12857429Smarkm * anything after logging in anyway.
12957429Smarkm */
13057429Smarkmstatic int all_opens_permitted = 0;
13157429Smarkm
13257429Smarkm/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
13357429Smarkmstatic int have_hostname_in_open = 0;
13457429Smarkm
13576262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */
13676262Sgreenextern int IPv4or6;
13776262Sgreen
13876262Sgreenvoid	 port_open_helper(Channel *c, char *rtype);
13976262Sgreen
14057429Smarkm/* Sets specific protocol options. */
14157429Smarkm
14260573Skrisvoid
14357429Smarkmchannel_set_options(int hostname_in_open)
14457429Smarkm{
14557429Smarkm	have_hostname_in_open = hostname_in_open;
14657429Smarkm}
14757429Smarkm
14860573Skris/* lookup channel by id */
14960573Skris
15060573SkrisChannel *
15160573Skrischannel_lookup(int id)
15260573Skris{
15360573Skris	Channel *c;
15465668Skris	if (id < 0 || id > channels_alloc) {
15560573Skris		log("channel_lookup: %d: bad id", id);
15660573Skris		return NULL;
15760573Skris	}
15860573Skris	c = &channels[id];
15960573Skris	if (c->type == SSH_CHANNEL_FREE) {
16060573Skris		log("channel_lookup: %d: bad id: channel free", id);
16160573Skris		return NULL;
16260573Skris	}
16360573Skris	return c;
16460573Skris}
16560573Skris
16657429Smarkm/*
16760573Skris * Register filedescriptors for a channel, used when allocating a channel or
16860573Skris * when the channel consumer/producer is ready, e.g. shell exec'd
16960573Skris */
17060573Skris
17160573Skrisvoid
17269587Sgreenchannel_register_fds(Channel *c, int rfd, int wfd, int efd,
17369587Sgreen    int extusage, int nonblock)
17460573Skris{
17560573Skris	/* Update the maximum file descriptor value. */
17676262Sgreen	channel_max_fd = MAX(channel_max_fd, rfd);
17776262Sgreen	channel_max_fd = MAX(channel_max_fd, wfd);
17876262Sgreen	channel_max_fd = MAX(channel_max_fd, efd);
17976262Sgreen
18060573Skris	/* XXX set close-on-exec -markus */
18160573Skris
18260573Skris	c->rfd = rfd;
18360573Skris	c->wfd = wfd;
18460573Skris	c->sock = (rfd == wfd) ? rfd : -1;
18560573Skris	c->efd = efd;
18660573Skris	c->extended_usage = extusage;
18769587Sgreen
18874500Sgreen	/* XXX ugly hack: nonblock is only set by the server */
18974500Sgreen	if (nonblock && isatty(c->rfd)) {
19076262Sgreen		debug("channel %d: rfd %d isatty", c->self, c->rfd);
19174500Sgreen		c->isatty = 1;
19274500Sgreen		if (!isatty(c->wfd)) {
19376262Sgreen			error("channel %d: wfd %d is not a tty?",
19474500Sgreen			    c->self, c->wfd);
19574500Sgreen		}
19674500Sgreen	} else {
19774500Sgreen		c->isatty = 0;
19874500Sgreen	}
19974500Sgreen
20069587Sgreen	/* enable nonblocking mode */
20169587Sgreen	if (nonblock) {
20269587Sgreen		if (rfd != -1)
20369587Sgreen			set_nonblock(rfd);
20469587Sgreen		if (wfd != -1)
20569587Sgreen			set_nonblock(wfd);
20669587Sgreen		if (efd != -1)
20769587Sgreen			set_nonblock(efd);
20869587Sgreen	}
20960573Skris}
21060573Skris
21160573Skris/*
21257429Smarkm * Allocate a new channel object and set its type and socket. This will cause
21357429Smarkm * remote_name to be freed.
21457429Smarkm */
21557429Smarkm
21660573Skrisint
21760573Skrischannel_new(char *ctype, int type, int rfd, int wfd, int efd,
21869587Sgreen    int window, int maxpack, int extusage, char *remote_name, int nonblock)
21957429Smarkm{
22057429Smarkm	int i, found;
22157429Smarkm	Channel *c;
22257429Smarkm
22357429Smarkm	/* Do initial allocation if this is the first call. */
22457429Smarkm	if (channels_alloc == 0) {
22560573Skris		chan_init();
22657429Smarkm		channels_alloc = 10;
22757429Smarkm		channels = xmalloc(channels_alloc * sizeof(Channel));
22857429Smarkm		for (i = 0; i < channels_alloc; i++)
22957429Smarkm			channels[i].type = SSH_CHANNEL_FREE;
23057429Smarkm		/*
23157429Smarkm		 * Kludge: arrange a call to channel_stop_listening if we
23257429Smarkm		 * terminate with fatal().
23357429Smarkm		 */
23457429Smarkm		fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
23557429Smarkm	}
23657429Smarkm	/* Try to find a free slot where to put the new channel. */
23757429Smarkm	for (found = -1, i = 0; i < channels_alloc; i++)
23857429Smarkm		if (channels[i].type == SSH_CHANNEL_FREE) {
23957429Smarkm			/* Found a free slot. */
24057429Smarkm			found = i;
24157429Smarkm			break;
24257429Smarkm		}
24357429Smarkm	if (found == -1) {
24457429Smarkm		/* There are no free slots.  Take last+1 slot and expand the array.  */
24557429Smarkm		found = channels_alloc;
24657429Smarkm		channels_alloc += 10;
24769587Sgreen		debug2("channel: expanding %d", channels_alloc);
24857429Smarkm		channels = xrealloc(channels, channels_alloc * sizeof(Channel));
24957429Smarkm		for (i = found; i < channels_alloc; i++)
25057429Smarkm			channels[i].type = SSH_CHANNEL_FREE;
25157429Smarkm	}
25257429Smarkm	/* Initialize and return new channel number. */
25357429Smarkm	c = &channels[found];
25457429Smarkm	buffer_init(&c->input);
25557429Smarkm	buffer_init(&c->output);
25660573Skris	buffer_init(&c->extended);
25757429Smarkm	chan_init_iostates(c);
25869587Sgreen	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
25957429Smarkm	c->self = found;
26057429Smarkm	c->type = type;
26160573Skris	c->ctype = ctype;
26260573Skris	c->local_window = window;
26360573Skris	c->local_window_max = window;
26460573Skris	c->local_consumed = 0;
26560573Skris	c->local_maxpacket = maxpack;
26657429Smarkm	c->remote_id = -1;
26757429Smarkm	c->remote_name = remote_name;
26860573Skris	c->remote_window = 0;
26960573Skris	c->remote_maxpacket = 0;
27060573Skris	c->cb_fn = NULL;
27160573Skris	c->cb_arg = NULL;
27260573Skris	c->cb_event = 0;
27360573Skris	c->dettach_user = NULL;
27465668Skris	c->input_filter = NULL;
27557429Smarkm	debug("channel %d: new [%s]", found, remote_name);
27657429Smarkm	return found;
27757429Smarkm}
27860573Skris/* old interface XXX */
27960573Skrisint
28060573Skrischannel_allocate(int type, int sock, char *remote_name)
28160573Skris{
28269587Sgreen	return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name, 1);
28360573Skris}
28457429Smarkm
28557429Smarkm
28660573Skris/* Close all channel fd/socket. */
28760573Skris
28860573Skrisvoid
28960573Skrischannel_close_fds(Channel *c)
29057429Smarkm{
29160573Skris	if (c->sock != -1) {
29260573Skris		close(c->sock);
29360573Skris		c->sock = -1;
29460573Skris	}
29560573Skris	if (c->rfd != -1) {
29660573Skris		close(c->rfd);
29760573Skris		c->rfd = -1;
29860573Skris	}
29960573Skris	if (c->wfd != -1) {
30060573Skris		close(c->wfd);
30160573Skris		c->wfd = -1;
30260573Skris	}
30360573Skris	if (c->efd != -1) {
30460573Skris		close(c->efd);
30560573Skris		c->efd = -1;
30660573Skris	}
30760573Skris}
30857429Smarkm
30960573Skris/* Free the channel and close its fd/socket. */
31060573Skris
31160573Skrisvoid
31260573Skrischannel_free(int id)
31360573Skris{
31460573Skris	Channel *c = channel_lookup(id);
31576262Sgreen	char *s = channel_open_message();
31676262Sgreen
31760573Skris	if (c == NULL)
31860573Skris		packet_disconnect("channel free: bad local channel %d", id);
31976262Sgreen	debug("channel_free: channel %d: status: %s", id, s);
32076262Sgreen	xfree(s);
32176262Sgreen
32260573Skris	if (c->dettach_user != NULL) {
32360573Skris		debug("channel_free: channel %d: dettaching channel user", id);
32460573Skris		c->dettach_user(c->self, NULL);
32557429Smarkm	}
32660573Skris	if (c->sock != -1)
32760573Skris		shutdown(c->sock, SHUT_RDWR);
32860573Skris	channel_close_fds(c);
32960573Skris	buffer_free(&c->input);
33060573Skris	buffer_free(&c->output);
33160573Skris	buffer_free(&c->extended);
33260573Skris	c->type = SSH_CHANNEL_FREE;
33360573Skris	if (c->remote_name) {
33460573Skris		xfree(c->remote_name);
33560573Skris		c->remote_name = NULL;
33660573Skris	}
33757429Smarkm}
33857429Smarkm
33957429Smarkm/*
34060573Skris * 'channel_pre*' are called just before select() to add any bits relevant to
34160573Skris * channels in the select bitmasks.
34257429Smarkm */
34360573Skris/*
34460573Skris * 'channel_post*': perform any appropriate operations for channels which
34560573Skris * have events pending.
34660573Skris */
34760573Skristypedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);
34860573Skrischan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
34960573Skrischan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
35057429Smarkm
35160573Skrisvoid
35260573Skrischannel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)
35357429Smarkm{
35460573Skris	FD_SET(c->sock, readset);
35560573Skris}
35660573Skris
35760573Skrisvoid
35876262Sgreenchannel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset)
35976262Sgreen{
36076262Sgreen	debug3("channel %d: waiting for connection", c->self);
36176262Sgreen	FD_SET(c->sock, writeset);
36276262Sgreen}
36376262Sgreen
36476262Sgreenvoid
36560573Skrischannel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
36660573Skris{
36760573Skris	if (buffer_len(&c->input) < packet_get_maxsize())
36860573Skris		FD_SET(c->sock, readset);
36960573Skris	if (buffer_len(&c->output) > 0)
37060573Skris		FD_SET(c->sock, writeset);
37160573Skris}
37260573Skris
37360573Skrisvoid
37460573Skrischannel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
37560573Skris{
37660573Skris	/* test whether sockets are 'alive' for read/write */
37760573Skris	if (c->istate == CHAN_INPUT_OPEN)
37860573Skris		if (buffer_len(&c->input) < packet_get_maxsize())
37960573Skris			FD_SET(c->sock, readset);
38060573Skris	if (c->ostate == CHAN_OUTPUT_OPEN ||
38160573Skris	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
38260573Skris		if (buffer_len(&c->output) > 0) {
38360573Skris			FD_SET(c->sock, writeset);
38460573Skris		} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
38560573Skris			chan_obuf_empty(c);
38660573Skris		}
38760573Skris	}
38860573Skris}
38960573Skris
39060573Skrisvoid
39160573Skrischannel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
39260573Skris{
39360573Skris	if (c->istate == CHAN_INPUT_OPEN &&
39460573Skris	    c->remote_window > 0 &&
39560573Skris	    buffer_len(&c->input) < c->remote_window)
39660573Skris		FD_SET(c->rfd, readset);
39760573Skris	if (c->ostate == CHAN_OUTPUT_OPEN ||
39860573Skris	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
39960573Skris		if (buffer_len(&c->output) > 0) {
40060573Skris			FD_SET(c->wfd, writeset);
40160573Skris		} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
40260573Skris			chan_obuf_empty(c);
40360573Skris		}
40460573Skris	}
40560573Skris	/** XXX check close conditions, too */
40660573Skris	if (c->efd != -1) {
40760573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
40860573Skris		    buffer_len(&c->extended) > 0)
40960573Skris			FD_SET(c->efd, writeset);
41060573Skris		else if (c->extended_usage == CHAN_EXTENDED_READ &&
41160573Skris		    buffer_len(&c->extended) < c->remote_window)
41260573Skris			FD_SET(c->efd, readset);
41360573Skris	}
41460573Skris}
41560573Skris
41660573Skrisvoid
41760573Skrischannel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
41860573Skris{
41960573Skris	if (buffer_len(&c->input) == 0) {
42060573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
42160573Skris		packet_put_int(c->remote_id);
42260573Skris		packet_send();
42360573Skris		c->type = SSH_CHANNEL_CLOSED;
42476262Sgreen		debug("channel %d: closing after input drain.", c->self);
42560573Skris	}
42660573Skris}
42760573Skris
42860573Skrisvoid
42960573Skrischannel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
43060573Skris{
43160573Skris	if (buffer_len(&c->output) == 0)
43260573Skris		channel_free(c->self);
43360573Skris	else
43460573Skris		FD_SET(c->sock, writeset);
43560573Skris}
43660573Skris
43760573Skris/*
43860573Skris * This is a special state for X11 authentication spoofing.  An opened X11
43960573Skris * connection (when authentication spoofing is being done) remains in this
44060573Skris * state until the first packet has been completely read.  The authentication
44160573Skris * data in that packet is then substituted by the real data if it matches the
44260573Skris * fake data, and the channel is put into normal mode.
44360573Skris * XXX All this happens at the client side.
44460573Skris */
44560573Skrisint
44660573Skrisx11_open_helper(Channel *c)
44760573Skris{
44876262Sgreen	u_char *ucp;
44976262Sgreen	u_int proto_len, data_len;
45057429Smarkm
45160573Skris	/* Check if the fixed size part of the packet is in buffer. */
45260573Skris	if (buffer_len(&c->output) < 12)
45360573Skris		return 0;
45457429Smarkm
45560573Skris	/* Parse the lengths of variable-length fields. */
45676262Sgreen	ucp = (u_char *) buffer_ptr(&c->output);
45760573Skris	if (ucp[0] == 0x42) {	/* Byte order MSB first. */
45860573Skris		proto_len = 256 * ucp[6] + ucp[7];
45960573Skris		data_len = 256 * ucp[8] + ucp[9];
46060573Skris	} else if (ucp[0] == 0x6c) {	/* Byte order LSB first. */
46160573Skris		proto_len = ucp[6] + 256 * ucp[7];
46260573Skris		data_len = ucp[8] + 256 * ucp[9];
46360573Skris	} else {
46460573Skris		debug("Initial X11 packet contains bad byte order byte: 0x%x",
46560573Skris		      ucp[0]);
46660573Skris		return -1;
46760573Skris	}
46857429Smarkm
46960573Skris	/* Check if the whole packet is in buffer. */
47060573Skris	if (buffer_len(&c->output) <
47160573Skris	    12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
47260573Skris		return 0;
47357429Smarkm
47460573Skris	/* Check if authentication protocol matches. */
47560573Skris	if (proto_len != strlen(x11_saved_proto) ||
47660573Skris	    memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
47760573Skris		debug("X11 connection uses different authentication protocol.");
47860573Skris		return -1;
47960573Skris	}
48060573Skris	/* Check if authentication data matches our fake data. */
48160573Skris	if (data_len != x11_fake_data_len ||
48260573Skris	    memcmp(ucp + 12 + ((proto_len + 3) & ~3),
48360573Skris		x11_fake_data, x11_fake_data_len) != 0) {
48460573Skris		debug("X11 auth data does not match fake data.");
48560573Skris		return -1;
48660573Skris	}
48760573Skris	/* Check fake data length */
48860573Skris	if (x11_fake_data_len != x11_saved_data_len) {
48960573Skris		error("X11 fake_data_len %d != saved_data_len %d",
49060573Skris		    x11_fake_data_len, x11_saved_data_len);
49160573Skris		return -1;
49260573Skris	}
49360573Skris	/*
49460573Skris	 * Received authentication protocol and data match
49560573Skris	 * our fake data. Substitute the fake data with real
49660573Skris	 * data.
49760573Skris	 */
49860573Skris	memcpy(ucp + 12 + ((proto_len + 3) & ~3),
49960573Skris	    x11_saved_data, x11_saved_data_len);
50060573Skris	return 1;
50160573Skris}
50257429Smarkm
50360573Skrisvoid
50460573Skrischannel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
50560573Skris{
50660573Skris	int ret = x11_open_helper(c);
50760573Skris	if (ret == 1) {
50860573Skris		/* Start normal processing for the channel. */
50960573Skris		c->type = SSH_CHANNEL_OPEN;
51060573Skris		channel_pre_open_13(c, readset, writeset);
51160573Skris	} else if (ret == -1) {
51260573Skris		/*
51360573Skris		 * We have received an X11 connection that has bad
51460573Skris		 * authentication information.
51560573Skris		 */
51676262Sgreen		log("X11 connection rejected because of wrong authentication.");
51760573Skris		buffer_clear(&c->input);
51860573Skris		buffer_clear(&c->output);
51960573Skris		close(c->sock);
52060573Skris		c->sock = -1;
52160573Skris		c->type = SSH_CHANNEL_CLOSED;
52260573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
52360573Skris		packet_put_int(c->remote_id);
52460573Skris		packet_send();
52560573Skris	}
52660573Skris}
52757429Smarkm
52860573Skrisvoid
52960573Skrischannel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
53060573Skris{
53160573Skris	int ret = x11_open_helper(c);
53260573Skris	if (ret == 1) {
53360573Skris		c->type = SSH_CHANNEL_OPEN;
53460573Skris		if (compat20)
53560573Skris			channel_pre_open_20(c, readset, writeset);
53660573Skris		else
53760573Skris			channel_pre_open_15(c, readset, writeset);
53860573Skris	} else if (ret == -1) {
53960573Skris		debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
54060573Skris		chan_read_failed(c);	/** force close? */
54160573Skris		chan_write_failed(c);
54260573Skris		debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
54360573Skris	}
54460573Skris}
54557429Smarkm
54676262Sgreen/* try to decode a socks4 header */
54776262Sgreenint
54876262Sgreenchannel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
54976262Sgreen{
55076262Sgreen	u_char *p, *host;
55176262Sgreen	int len, have, i, found;
55276262Sgreen	char username[256];
55376262Sgreen	struct {
55476262Sgreen		u_int8_t version;
55576262Sgreen		u_int8_t command;
55676262Sgreen		u_int16_t dest_port;
55776262Sgreen		struct in_addr dest_addr;
55876262Sgreen	} s4_req, s4_rsp;
55976262Sgreen
56076262Sgreen	debug2("channel %d: decode socks4", c->self);
56176262Sgreen
56276262Sgreen	have = buffer_len(&c->input);
56376262Sgreen	len = sizeof(s4_req);
56476262Sgreen	if (have < len)
56576262Sgreen		return 0;
56676262Sgreen	p = buffer_ptr(&c->input);
56776262Sgreen	for (found = 0, i = len; i < have; i++) {
56876262Sgreen		if (p[i] == '\0') {
56976262Sgreen			found = 1;
57076262Sgreen			break;
57176262Sgreen		}
57276262Sgreen		if (i > 1024) {
57376262Sgreen			/* the peer is probably sending garbage */
57476262Sgreen			debug("channel %d: decode socks4: too long",
57576262Sgreen			    c->self);
57676262Sgreen			return -1;
57776262Sgreen		}
57876262Sgreen	}
57976262Sgreen	if (!found)
58076262Sgreen		return 0;
58176262Sgreen	buffer_get(&c->input, (char *)&s4_req.version, 1);
58276262Sgreen	buffer_get(&c->input, (char *)&s4_req.command, 1);
58376262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
58476262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
58576262Sgreen	have = buffer_len(&c->input);
58676262Sgreen	p = buffer_ptr(&c->input);
58776262Sgreen	len = strlen(p);
58876262Sgreen	debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
58976262Sgreen	if (len > have)
59076262Sgreen		fatal("channel %d: decode socks4: len %d > have %d",
59176262Sgreen		    c->self, len, have);
59276262Sgreen	strlcpy(username, p, sizeof(username));
59376262Sgreen	buffer_consume(&c->input, len);
59476262Sgreen	buffer_consume(&c->input, 1);		/* trailing '\0' */
59576262Sgreen
59676262Sgreen	host = inet_ntoa(s4_req.dest_addr);
59776262Sgreen	strlcpy(c->path, host, sizeof(c->path));
59876262Sgreen	c->host_port = ntohs(s4_req.dest_port);
59976262Sgreen
60076262Sgreen	debug("channel %d: dynamic request: socks4 host %s port %u command %u",
60176262Sgreen	    c->self, host, c->host_port, s4_req.command);
60276262Sgreen
60376262Sgreen	if (s4_req.command != 1) {
60476262Sgreen		debug("channel %d: cannot handle: socks4 cn %d",
60576262Sgreen		    c->self, s4_req.command);
60676262Sgreen		return -1;
60776262Sgreen	}
60876262Sgreen	s4_rsp.version = 0;			/* vn: 0 for reply */
60976262Sgreen	s4_rsp.command = 90;			/* cd: req granted */
61076262Sgreen	s4_rsp.dest_port = 0;			/* ignored */
61176262Sgreen	s4_rsp.dest_addr.s_addr = INADDR_ANY;	/* ignored */
61276262Sgreen	buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));
61376262Sgreen	return 1;
61476262Sgreen}
61576262Sgreen
61676262Sgreen/* dynamic port forwarding */
61776262Sgreenvoid
61876262Sgreenchannel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
61976262Sgreen{
62076262Sgreen	u_char *p;
62176262Sgreen	int have, ret;
62276262Sgreen
62376262Sgreen	have = buffer_len(&c->input);
62476262Sgreen
62576262Sgreen	debug2("channel %d: pre_dynamic: have %d", c->self, have);
62676262Sgreen	/* buffer_dump(&c->input); */
62776262Sgreen	/* check if the fixed size part of the packet is in buffer. */
62876262Sgreen	if (have < 4) {
62976262Sgreen		/* need more */
63076262Sgreen		FD_SET(c->sock, readset);
63176262Sgreen		return;
63276262Sgreen	}
63376262Sgreen	/* try to guess the protocol */
63476262Sgreen	p = buffer_ptr(&c->input);
63576262Sgreen	switch (p[0]) {
63676262Sgreen	case 0x04:
63776262Sgreen		ret = channel_decode_socks4(c, readset, writeset);
63876262Sgreen		break;
63976262Sgreen	default:
64076262Sgreen		ret = -1;
64176262Sgreen		break;
64276262Sgreen	}
64376262Sgreen	if (ret < 0) {
64476262Sgreen		channel_free(c->self);
64576262Sgreen	} else if (ret == 0) {
64676262Sgreen		debug2("channel %d: pre_dynamic: need more", c->self);
64776262Sgreen		/* need more */
64876262Sgreen		FD_SET(c->sock, readset);
64976262Sgreen	} else {
65076262Sgreen		/* switch to the next state */
65176262Sgreen		c->type = SSH_CHANNEL_OPENING;
65276262Sgreen		port_open_helper(c, "direct-tcpip");
65376262Sgreen	}
65476262Sgreen}
65576262Sgreen
65660573Skris/* This is our fake X11 server socket. */
65760573Skrisvoid
65860573Skrischannel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
65960573Skris{
66060573Skris	struct sockaddr addr;
66160573Skris	int newsock, newch;
66260573Skris	socklen_t addrlen;
66376262Sgreen	char buf[16384], *remote_ipaddr;
66460573Skris	int remote_port;
66557429Smarkm
66660573Skris	if (FD_ISSET(c->sock, readset)) {
66760573Skris		debug("X11 connection requested.");
66860573Skris		addrlen = sizeof(addr);
66960573Skris		newsock = accept(c->sock, &addr, &addrlen);
67060573Skris		if (newsock < 0) {
67160573Skris			error("accept: %.100s", strerror(errno));
67260573Skris			return;
67360573Skris		}
67476262Sgreen		remote_ipaddr = get_peer_ipaddr(newsock);
67560573Skris		remote_port = get_peer_port(newsock);
67660573Skris		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
67776262Sgreen		    remote_ipaddr, remote_port);
67857429Smarkm
67960573Skris		newch = channel_new("x11",
68060573Skris		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
68160573Skris		    c->local_window_max, c->local_maxpacket,
68269587Sgreen		    0, xstrdup(buf), 1);
68360573Skris		if (compat20) {
68460573Skris			packet_start(SSH2_MSG_CHANNEL_OPEN);
68560573Skris			packet_put_cstring("x11");
68660573Skris			packet_put_int(newch);
68760573Skris			packet_put_int(c->local_window_max);
68860573Skris			packet_put_int(c->local_maxpacket);
68976262Sgreen			/* originator ipaddr and port */
69076262Sgreen			packet_put_cstring(remote_ipaddr);
69160573Skris			if (datafellows & SSH_BUG_X11FWD) {
69260573Skris				debug("ssh2 x11 bug compat mode");
69357429Smarkm			} else {
69460573Skris				packet_put_int(remote_port);
69557429Smarkm			}
69660573Skris			packet_send();
69760573Skris		} else {
69860573Skris			packet_start(SSH_SMSG_X11_OPEN);
69960573Skris			packet_put_int(newch);
70060573Skris			if (have_hostname_in_open)
70160573Skris				packet_put_string(buf, strlen(buf));
70260573Skris			packet_send();
70357429Smarkm		}
70476262Sgreen		xfree(remote_ipaddr);
70557429Smarkm	}
70657429Smarkm}
70757429Smarkm
70876262Sgreenvoid
70976262Sgreenport_open_helper(Channel *c, char *rtype)
71076262Sgreen{
71176262Sgreen	int direct;
71276262Sgreen	char buf[1024];
71376262Sgreen	char *remote_ipaddr = get_peer_ipaddr(c->sock);
71476262Sgreen	u_short remote_port = get_peer_port(c->sock);
71576262Sgreen
71676262Sgreen	direct = (strcmp(rtype, "direct-tcpip") == 0);
71776262Sgreen
71876262Sgreen	snprintf(buf, sizeof buf,
71976262Sgreen	    "%s: listening port %d for %.100s port %d, "
72076262Sgreen	    "connect from %.200s port %d",
72176262Sgreen	    rtype, c->listening_port, c->path, c->host_port,
72276262Sgreen	    remote_ipaddr, remote_port);
72376262Sgreen
72476262Sgreen	xfree(c->remote_name);
72576262Sgreen	c->remote_name = xstrdup(buf);
72676262Sgreen
72776262Sgreen	if (compat20) {
72876262Sgreen		packet_start(SSH2_MSG_CHANNEL_OPEN);
72976262Sgreen		packet_put_cstring(rtype);
73076262Sgreen		packet_put_int(c->self);
73176262Sgreen		packet_put_int(c->local_window_max);
73276262Sgreen		packet_put_int(c->local_maxpacket);
73376262Sgreen		if (direct) {
73476262Sgreen			/* target host, port */
73576262Sgreen			packet_put_cstring(c->path);
73676262Sgreen			packet_put_int(c->host_port);
73776262Sgreen		} else {
73876262Sgreen			/* listen address, port */
73976262Sgreen			packet_put_cstring(c->path);
74076262Sgreen			packet_put_int(c->listening_port);
74176262Sgreen		}
74276262Sgreen		/* originator host and port */
74376262Sgreen		packet_put_cstring(remote_ipaddr);
74476262Sgreen		packet_put_int(remote_port);
74576262Sgreen		packet_send();
74676262Sgreen	} else {
74776262Sgreen		packet_start(SSH_MSG_PORT_OPEN);
74876262Sgreen		packet_put_int(c->self);
74976262Sgreen		packet_put_cstring(c->path);
75076262Sgreen		packet_put_int(c->host_port);
75176262Sgreen		if (have_hostname_in_open)
75276262Sgreen			packet_put_cstring(c->remote_name);
75376262Sgreen		packet_send();
75476262Sgreen	}
75576262Sgreen	xfree(remote_ipaddr);
75676262Sgreen}
75776262Sgreen
75857429Smarkm/*
75960573Skris * This socket is listening for connections to a forwarded TCP/IP port.
76057429Smarkm */
76160573Skrisvoid
76260573Skrischannel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
76357429Smarkm{
76476262Sgreen	Channel *nc;
76557429Smarkm	struct sockaddr addr;
76676262Sgreen	int newsock, newch, nextstate;
76757429Smarkm	socklen_t addrlen;
76876262Sgreen	char *rtype;
76957429Smarkm
77060573Skris	if (FD_ISSET(c->sock, readset)) {
77160573Skris		debug("Connection to port %d forwarding "
77260573Skris		    "to %.100s port %d requested.",
77360573Skris		    c->listening_port, c->path, c->host_port);
77476262Sgreen
77576262Sgreen		rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
77676262Sgreen		    "forwarded-tcpip" : "direct-tcpip";
77776262Sgreen		nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC :
77876262Sgreen		    SSH_CHANNEL_OPENING;
77976262Sgreen
78060573Skris		addrlen = sizeof(addr);
78160573Skris		newsock = accept(c->sock, &addr, &addrlen);
78260573Skris		if (newsock < 0) {
78360573Skris			error("accept: %.100s", strerror(errno));
78460573Skris			return;
78560573Skris		}
78676262Sgreen		newch = channel_new(rtype,
78776262Sgreen		    nextstate, newsock, newsock, -1,
78860573Skris		    c->local_window_max, c->local_maxpacket,
78976262Sgreen		    0, xstrdup(rtype), 1);
79076262Sgreen
79176262Sgreen		nc = channel_lookup(newch);
79276262Sgreen		if (nc == NULL) {
79376262Sgreen			error("xxx: no new channel:");
79476262Sgreen			return;
79560573Skris		}
79676262Sgreen		nc->listening_port = c->listening_port;
79776262Sgreen		nc->host_port = c->host_port;
79876262Sgreen		strlcpy(nc->path, c->path, sizeof(nc->path));
79976262Sgreen
80076262Sgreen		if (nextstate != SSH_CHANNEL_DYNAMIC)
80176262Sgreen			port_open_helper(nc, rtype);
80260573Skris	}
80360573Skris}
80457429Smarkm
80560573Skris/*
80660573Skris * This is the authentication agent socket listening for connections from
80760573Skris * clients.
80860573Skris */
80960573Skrisvoid
81060573Skrischannel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
81160573Skris{
81260573Skris	struct sockaddr addr;
81360573Skris	int newsock, newch;
81460573Skris	socklen_t addrlen;
81557429Smarkm
81660573Skris	if (FD_ISSET(c->sock, readset)) {
81760573Skris		addrlen = sizeof(addr);
81860573Skris		newsock = accept(c->sock, &addr, &addrlen);
81960573Skris		if (newsock < 0) {
82060573Skris			error("accept from auth socket: %.100s", strerror(errno));
82160573Skris			return;
82260573Skris		}
82376262Sgreen		newch = channel_new("accepted auth socket",
82476262Sgreen		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
82576262Sgreen		    c->local_window_max, c->local_maxpacket,
82676262Sgreen		    0, xstrdup("accepted auth socket"), 1);
82776262Sgreen		if (compat20) {
82876262Sgreen			packet_start(SSH2_MSG_CHANNEL_OPEN);
82976262Sgreen			packet_put_cstring("auth-agent@openssh.com");
83076262Sgreen			packet_put_int(newch);
83176262Sgreen			packet_put_int(c->local_window_max);
83276262Sgreen			packet_put_int(c->local_maxpacket);
83376262Sgreen		} else {
83476262Sgreen			packet_start(SSH_SMSG_AGENT_OPEN);
83576262Sgreen			packet_put_int(newch);
83676262Sgreen		}
83760573Skris		packet_send();
83860573Skris	}
83960573Skris}
84057429Smarkm
84176262Sgreenvoid
84276262Sgreenchannel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset)
84376262Sgreen{
84476262Sgreen	if (FD_ISSET(c->sock, writeset)) {
84576262Sgreen		int err = 0;
84676262Sgreen		int sz = sizeof(err);
84776262Sgreen		c->type = SSH_CHANNEL_OPEN;
84876262Sgreen		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) {
84976262Sgreen			debug("getsockopt SO_ERROR failed");
85076262Sgreen		} else {
85176262Sgreen			if (err == 0) {
85276262Sgreen				debug("channel %d: connected)", c->self);
85376262Sgreen			} else {
85476262Sgreen				debug("channel %d: not connected: %s",
85576262Sgreen				    c->self, strerror(err));
85676262Sgreen				chan_read_failed(c);
85776262Sgreen				chan_write_failed(c);
85876262Sgreen			}
85976262Sgreen		}
86076262Sgreen	}
86176262Sgreen}
86276262Sgreen
86360573Skrisint
86460573Skrischannel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
86560573Skris{
86660573Skris	char buf[16*1024];
86760573Skris	int len;
86857429Smarkm
86960573Skris	if (c->rfd != -1 &&
87060573Skris	    FD_ISSET(c->rfd, readset)) {
87160573Skris		len = read(c->rfd, buf, sizeof(buf));
87260573Skris		if (len < 0 && (errno == EINTR || errno == EAGAIN))
87360573Skris			return 1;
87478827Sgreen		if (len <= 0) {
87578827Sgreen			debug("channel %d: read<=0 rfd %d len %d",
87660573Skris			    c->self, c->rfd, len);
87776262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
87876262Sgreen				debug("channel %d: not open", c->self);
87976262Sgreen				channel_free(c->self);
88076262Sgreen				return -1;
88176262Sgreen			} else if (compat13) {
88260573Skris				buffer_consume(&c->output, buffer_len(&c->output));
88360573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
88476262Sgreen				debug("channel %d: status set to input draining.", c->self);
88560573Skris			} else {
88660573Skris				chan_read_failed(c);
88757429Smarkm			}
88860573Skris			return -1;
88960573Skris		}
89065668Skris		if(c->input_filter != NULL) {
89165668Skris			if (c->input_filter(c, buf, len) == -1) {
89276262Sgreen				debug("channel %d: filter stops", c->self);
89365668Skris				chan_read_failed(c);
89465668Skris			}
89565668Skris		} else {
89665668Skris			buffer_append(&c->input, buf, len);
89765668Skris		}
89860573Skris	}
89960573Skris	return 1;
90060573Skris}
90160573Skrisint
90260573Skrischannel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
90360573Skris{
90476262Sgreen	struct termios tio;
90560573Skris	int len;
90660573Skris
90760573Skris	/* Send buffered output data to the socket. */
90860573Skris	if (c->wfd != -1 &&
90960573Skris	    FD_ISSET(c->wfd, writeset) &&
91060573Skris	    buffer_len(&c->output) > 0) {
91160573Skris		len = write(c->wfd, buffer_ptr(&c->output),
91260573Skris		    buffer_len(&c->output));
91360573Skris		if (len < 0 && (errno == EINTR || errno == EAGAIN))
91460573Skris			return 1;
91560573Skris		if (len <= 0) {
91676262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
91776262Sgreen				debug("channel %d: not open", c->self);
91876262Sgreen				channel_free(c->self);
91976262Sgreen				return -1;
92076262Sgreen			} else if (compat13) {
92160573Skris				buffer_consume(&c->output, buffer_len(&c->output));
92276262Sgreen				debug("channel %d: status set to input draining.", c->self);
92360573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
92460573Skris			} else {
92560573Skris				chan_write_failed(c);
92657429Smarkm			}
92760573Skris			return -1;
92860573Skris		}
92974500Sgreen		if (compat20 && c->isatty) {
93074500Sgreen			if (tcgetattr(c->wfd, &tio) == 0 &&
93174500Sgreen			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
93274500Sgreen				/*
93374500Sgreen				 * Simulate echo to reduce the impact of
93476262Sgreen				 * traffic analysis. We need to match the
93576262Sgreen				 * size of a SSH2_MSG_CHANNEL_DATA message
93676262Sgreen				 * (4 byte channel id + data)
93774500Sgreen				 */
93876262Sgreen				packet_send_ignore(4 + len);
93974500Sgreen				packet_send();
94074500Sgreen			}
94174500Sgreen		}
94260573Skris		buffer_consume(&c->output, len);
94360573Skris		if (compat20 && len > 0) {
94460573Skris			c->local_consumed += len;
94560573Skris		}
94660573Skris	}
94760573Skris	return 1;
94860573Skris}
94960573Skrisint
95060573Skrischannel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
95160573Skris{
95260573Skris	char buf[16*1024];
95360573Skris	int len;
95457429Smarkm
95560573Skris/** XXX handle drain efd, too */
95660573Skris	if (c->efd != -1) {
95760573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
95860573Skris		    FD_ISSET(c->efd, writeset) &&
95960573Skris		    buffer_len(&c->extended) > 0) {
96060573Skris			len = write(c->efd, buffer_ptr(&c->extended),
96160573Skris			    buffer_len(&c->extended));
96269587Sgreen			debug2("channel %d: written %d to efd %d",
96360573Skris			    c->self, len, c->efd);
96476262Sgreen			if (len < 0 && (errno == EINTR || errno == EAGAIN))
96576262Sgreen				return 1;
96676262Sgreen			if (len <= 0) {
96776262Sgreen				debug2("channel %d: closing write-efd %d",
96876262Sgreen				    c->self, c->efd);
96976262Sgreen				close(c->efd);
97076262Sgreen				c->efd = -1;
97176262Sgreen			} else {
97260573Skris				buffer_consume(&c->extended, len);
97360573Skris				c->local_consumed += len;
97457429Smarkm			}
97560573Skris		} else if (c->extended_usage == CHAN_EXTENDED_READ &&
97660573Skris		    FD_ISSET(c->efd, readset)) {
97760573Skris			len = read(c->efd, buf, sizeof(buf));
97869587Sgreen			debug2("channel %d: read %d from efd %d",
97960573Skris			     c->self, len, c->efd);
98076262Sgreen			if (len < 0 && (errno == EINTR || errno == EAGAIN))
98176262Sgreen				return 1;
98276262Sgreen			if (len <= 0) {
98376262Sgreen				debug2("channel %d: closing read-efd %d",
98460573Skris				    c->self, c->efd);
98560573Skris				close(c->efd);
98660573Skris				c->efd = -1;
98776262Sgreen			} else {
98860573Skris				buffer_append(&c->extended, buf, len);
98976262Sgreen			}
99060573Skris		}
99160573Skris	}
99260573Skris	return 1;
99360573Skris}
99460573Skrisint
99576262Sgreenchannel_check_window(Channel *c)
99660573Skris{
99776262Sgreen	if (c->type == SSH_CHANNEL_OPEN &&
99876262Sgreen	    !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
99960573Skris	    c->local_window < c->local_window_max/2 &&
100060573Skris	    c->local_consumed > 0) {
100160573Skris		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
100260573Skris		packet_put_int(c->remote_id);
100360573Skris		packet_put_int(c->local_consumed);
100460573Skris		packet_send();
100569587Sgreen		debug2("channel %d: window %d sent adjust %d",
100660573Skris		    c->self, c->local_window,
100760573Skris		    c->local_consumed);
100860573Skris		c->local_window += c->local_consumed;
100960573Skris		c->local_consumed = 0;
101060573Skris	}
101160573Skris	return 1;
101260573Skris}
101357429Smarkm
101460573Skrisvoid
101560573Skrischannel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
101660573Skris{
101760573Skris	channel_handle_rfd(c, readset, writeset);
101860573Skris	channel_handle_wfd(c, readset, writeset);
101960573Skris}
102060573Skris
102160573Skrisvoid
102260573Skrischannel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset)
102360573Skris{
102460573Skris	channel_handle_rfd(c, readset, writeset);
102560573Skris	channel_handle_wfd(c, readset, writeset);
102660573Skris	channel_handle_efd(c, readset, writeset);
102776262Sgreen
102876262Sgreen	channel_check_window(c);
102960573Skris}
103060573Skris
103160573Skrisvoid
103260573Skrischannel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
103360573Skris{
103460573Skris	int len;
103560573Skris	/* Send buffered output data to the socket. */
103660573Skris	if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
103760573Skris		len = write(c->sock, buffer_ptr(&c->output),
103860573Skris			    buffer_len(&c->output));
103960573Skris		if (len <= 0)
104060573Skris			buffer_consume(&c->output, buffer_len(&c->output));
104160573Skris		else
104260573Skris			buffer_consume(&c->output, len);
104360573Skris	}
104460573Skris}
104560573Skris
104660573Skrisvoid
104760573Skrischannel_handler_init_20(void)
104860573Skris{
104960573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_20;
105060573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
105160573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
105276262Sgreen	channel_pre[SSH_CHANNEL_RPORT_LISTENER] =	&channel_pre_listener;
105360573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
105476262Sgreen	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
105576262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
105676262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
105760573Skris
105860573Skris	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open_2;
105960573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
106076262Sgreen	channel_post[SSH_CHANNEL_RPORT_LISTENER] =	&channel_post_port_listener;
106160573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
106276262Sgreen	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
106376262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
106476262Sgreen	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open_2;
106560573Skris}
106660573Skris
106760573Skrisvoid
106860573Skrischannel_handler_init_13(void)
106960573Skris{
107060573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_13;
107160573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open_13;
107260573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
107360573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
107460573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
107560573Skris	channel_pre[SSH_CHANNEL_INPUT_DRAINING] =	&channel_pre_input_draining;
107660573Skris	channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_pre_output_draining;
107776262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
107876262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
107960573Skris
108060573Skris	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open_1;
108160573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
108260573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
108360573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
108460573Skris	channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_post_output_drain_13;
108576262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
108676262Sgreen	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open_1;
108760573Skris}
108860573Skris
108960573Skrisvoid
109060573Skrischannel_handler_init_15(void)
109160573Skris{
109260573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_15;
109360573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
109460573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
109560573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
109660573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
109776262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
109876262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
109960573Skris
110060573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
110160573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
110260573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
110360573Skris	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open_1;
110476262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
110576262Sgreen	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open_1;
110660573Skris}
110760573Skris
110860573Skrisvoid
110960573Skrischannel_handler_init(void)
111060573Skris{
111160573Skris	int i;
111260573Skris	for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
111360573Skris		channel_pre[i] = NULL;
111460573Skris		channel_post[i] = NULL;
111560573Skris	}
111660573Skris	if (compat20)
111760573Skris		channel_handler_init_20();
111860573Skris	else if (compat13)
111960573Skris		channel_handler_init_13();
112060573Skris	else
112160573Skris		channel_handler_init_15();
112260573Skris}
112360573Skris
112460573Skrisvoid
112560573Skrischannel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
112660573Skris{
112760573Skris	static int did_init = 0;
112860573Skris	int i;
112960573Skris	Channel *c;
113060573Skris
113160573Skris	if (!did_init) {
113260573Skris		channel_handler_init();
113360573Skris		did_init = 1;
113460573Skris	}
113560573Skris	for (i = 0; i < channels_alloc; i++) {
113660573Skris		c = &channels[i];
113760573Skris		if (c->type == SSH_CHANNEL_FREE)
113857429Smarkm			continue;
113960573Skris		if (ftab[c->type] == NULL)
114060573Skris			continue;
114160573Skris		(*ftab[c->type])(c, readset, writeset);
114276262Sgreen		if (chan_is_dead(c)) {
114376262Sgreen			/*
114476262Sgreen			 * we have to remove the fd's from the select mask
114576262Sgreen			 * before the channels are free'd and the fd's are
114676262Sgreen			 * closed
114776262Sgreen			 */
114876262Sgreen			if (c->wfd != -1)
114976262Sgreen				FD_CLR(c->wfd, writeset);
115076262Sgreen			if (c->rfd != -1)
115176262Sgreen				FD_CLR(c->rfd, readset);
115276262Sgreen			if (c->efd != -1) {
115376262Sgreen				if (c->extended_usage == CHAN_EXTENDED_READ)
115476262Sgreen					FD_CLR(c->efd, readset);
115576262Sgreen				if (c->extended_usage == CHAN_EXTENDED_WRITE)
115676262Sgreen					FD_CLR(c->efd, writeset);
115776262Sgreen			}
115876262Sgreen			channel_free(c->self);
115976262Sgreen		}
116057429Smarkm	}
116157429Smarkm}
116257429Smarkm
116360573Skrisvoid
116476262Sgreenchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
116576262Sgreen    int rekeying)
116660573Skris{
116776262Sgreen	int n;
116876262Sgreen	u_int sz;
116976262Sgreen
117076262Sgreen	n = MAX(*maxfdp, channel_max_fd);
117176262Sgreen
117276262Sgreen	sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
117376262Sgreen	if (*readsetp == NULL || n > *maxfdp) {
117476262Sgreen		if (*readsetp)
117576262Sgreen			xfree(*readsetp);
117676262Sgreen		if (*writesetp)
117776262Sgreen			xfree(*writesetp);
117876262Sgreen		*readsetp = xmalloc(sz);
117976262Sgreen		*writesetp = xmalloc(sz);
118076262Sgreen		*maxfdp = n;
118176262Sgreen	}
118276262Sgreen	memset(*readsetp, 0, sz);
118376262Sgreen	memset(*writesetp, 0, sz);
118476262Sgreen
118576262Sgreen	if (!rekeying)
118676262Sgreen		channel_handler(channel_pre, *readsetp, *writesetp);
118760573Skris}
118860573Skris
118960573Skrisvoid
119060573Skrischannel_after_select(fd_set * readset, fd_set * writeset)
119160573Skris{
119260573Skris	channel_handler(channel_post, readset, writeset);
119360573Skris}
119460573Skris
119576262Sgreen/* If there is data to send to the connection, enqueue some of it now. */
119657429Smarkm
119760573Skrisvoid
119857429Smarkmchannel_output_poll()
119957429Smarkm{
120057429Smarkm	int len, i;
120160573Skris	Channel *c;
120257429Smarkm
120357429Smarkm	for (i = 0; i < channels_alloc; i++) {
120460573Skris		c = &channels[i];
120557429Smarkm
120657429Smarkm		/* We are only interested in channels that can have buffered incoming data. */
120757429Smarkm		if (compat13) {
120860573Skris			if (c->type != SSH_CHANNEL_OPEN &&
120960573Skris			    c->type != SSH_CHANNEL_INPUT_DRAINING)
121057429Smarkm				continue;
121157429Smarkm		} else {
121260573Skris			if (c->type != SSH_CHANNEL_OPEN)
121357429Smarkm				continue;
121457429Smarkm		}
121560573Skris		if (compat20 &&
121660573Skris		    (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
121776262Sgreen			/* XXX is this true? */
121876262Sgreen			debug2("channel %d: no data after CLOSE", c->self);
121960573Skris			continue;
122060573Skris		}
122157429Smarkm
122257429Smarkm		/* Get the amount of buffered data for this channel. */
122376262Sgreen		if ((c->istate == CHAN_INPUT_OPEN ||
122476262Sgreen		    c->istate == CHAN_INPUT_WAIT_DRAIN) &&
122576262Sgreen		    (len = buffer_len(&c->input)) > 0) {
122657429Smarkm			/* Send some data for the other side over the secure connection. */
122760573Skris			if (compat20) {
122860573Skris				if (len > c->remote_window)
122960573Skris					len = c->remote_window;
123060573Skris				if (len > c->remote_maxpacket)
123160573Skris					len = c->remote_maxpacket;
123257429Smarkm			} else {
123360573Skris				if (packet_is_interactive()) {
123460573Skris					if (len > 1024)
123560573Skris						len = 512;
123660573Skris				} else {
123760573Skris					/* Keep the packets at reasonable size. */
123860573Skris					if (len > packet_get_maxsize()/2)
123960573Skris						len = packet_get_maxsize()/2;
124060573Skris				}
124157429Smarkm			}
124260573Skris			if (len > 0) {
124360573Skris				packet_start(compat20 ?
124460573Skris				    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
124560573Skris				packet_put_int(c->remote_id);
124660573Skris				packet_put_string(buffer_ptr(&c->input), len);
124760573Skris				packet_send();
124860573Skris				buffer_consume(&c->input, len);
124960573Skris				c->remote_window -= len;
125060573Skris			}
125160573Skris		} else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
125257429Smarkm			if (compat13)
125357429Smarkm				fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
125457429Smarkm			/*
125557429Smarkm			 * input-buffer is empty and read-socket shutdown:
125657429Smarkm			 * tell peer, that we will not send more data: send IEOF
125757429Smarkm			 */
125860573Skris			chan_ibuf_empty(c);
125957429Smarkm		}
126060573Skris		/* Send extended data, i.e. stderr */
126160573Skris		if (compat20 &&
126260573Skris		    c->remote_window > 0 &&
126360573Skris		    (len = buffer_len(&c->extended)) > 0 &&
126460573Skris		    c->extended_usage == CHAN_EXTENDED_READ) {
126576262Sgreen			debug2("channel %d: rwin %d elen %d euse %d",
126676262Sgreen			    c->self, c->remote_window, buffer_len(&c->extended),
126776262Sgreen			    c->extended_usage);
126860573Skris			if (len > c->remote_window)
126960573Skris				len = c->remote_window;
127060573Skris			if (len > c->remote_maxpacket)
127160573Skris				len = c->remote_maxpacket;
127260573Skris			packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
127360573Skris			packet_put_int(c->remote_id);
127460573Skris			packet_put_int(SSH2_EXTENDED_DATA_STDERR);
127560573Skris			packet_put_string(buffer_ptr(&c->extended), len);
127660573Skris			packet_send();
127760573Skris			buffer_consume(&c->extended, len);
127860573Skris			c->remote_window -= len;
127976262Sgreen			debug2("channel %d: sent ext data %d", c->self, len);
128060573Skris		}
128157429Smarkm	}
128257429Smarkm}
128357429Smarkm
128457429Smarkm/*
128557429Smarkm * This is called when a packet of type CHANNEL_DATA has just been received.
128657429Smarkm * The message type has already been consumed, but channel number and data is
128757429Smarkm * still there.
128857429Smarkm */
128957429Smarkm
129060573Skrisvoid
129169587Sgreenchannel_input_data(int type, int plen, void *ctxt)
129257429Smarkm{
129357429Smarkm	int id;
129457429Smarkm	char *data;
129576262Sgreen	u_int data_len;
129660573Skris	Channel *c;
129757429Smarkm
129857429Smarkm	/* Get the channel number and verify it. */
129957429Smarkm	id = packet_get_int();
130060573Skris	c = channel_lookup(id);
130160573Skris	if (c == NULL)
130257429Smarkm		packet_disconnect("Received data for nonexistent channel %d.", id);
130357429Smarkm
130457429Smarkm	/* Ignore any data for non-open channels (might happen on close) */
130560573Skris	if (c->type != SSH_CHANNEL_OPEN &&
130660573Skris	    c->type != SSH_CHANNEL_X11_OPEN)
130757429Smarkm		return;
130857429Smarkm
130957429Smarkm	/* same for protocol 1.5 if output end is no longer open */
131060573Skris	if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN)
131157429Smarkm		return;
131257429Smarkm
131357429Smarkm	/* Get the data. */
131457429Smarkm	data = packet_get_string(&data_len);
131560573Skris	packet_done();
131660573Skris
131760573Skris	if (compat20){
131860573Skris		if (data_len > c->local_maxpacket) {
131960573Skris			log("channel %d: rcvd big packet %d, maxpack %d",
132060573Skris			    c->self, data_len, c->local_maxpacket);
132160573Skris		}
132260573Skris		if (data_len > c->local_window) {
132360573Skris			log("channel %d: rcvd too much data %d, win %d",
132460573Skris			    c->self, data_len, c->local_window);
132560573Skris			xfree(data);
132660573Skris			return;
132760573Skris		}
132860573Skris		c->local_window -= data_len;
132960573Skris	}else{
133060573Skris		packet_integrity_check(plen, 4 + 4 + data_len, type);
133160573Skris	}
133260573Skris	buffer_append(&c->output, data, data_len);
133357429Smarkm	xfree(data);
133457429Smarkm}
133560573Skrisvoid
133669587Sgreenchannel_input_extended_data(int type, int plen, void *ctxt)
133760573Skris{
133860573Skris	int id;
133960573Skris	int tcode;
134060573Skris	char *data;
134176262Sgreen	u_int data_len;
134260573Skris	Channel *c;
134357429Smarkm
134460573Skris	/* Get the channel number and verify it. */
134560573Skris	id = packet_get_int();
134660573Skris	c = channel_lookup(id);
134760573Skris
134860573Skris	if (c == NULL)
134960573Skris		packet_disconnect("Received extended_data for bad channel %d.", id);
135060573Skris	if (c->type != SSH_CHANNEL_OPEN) {
135160573Skris		log("channel %d: ext data for non open", id);
135260573Skris		return;
135360573Skris	}
135460573Skris	tcode = packet_get_int();
135560573Skris	if (c->efd == -1 ||
135660573Skris	    c->extended_usage != CHAN_EXTENDED_WRITE ||
135760573Skris	    tcode != SSH2_EXTENDED_DATA_STDERR) {
135860573Skris		log("channel %d: bad ext data", c->self);
135960573Skris		return;
136060573Skris	}
136160573Skris	data = packet_get_string(&data_len);
136260573Skris	packet_done();
136360573Skris	if (data_len > c->local_window) {
136460573Skris		log("channel %d: rcvd too much extended_data %d, win %d",
136560573Skris		    c->self, data_len, c->local_window);
136660573Skris		xfree(data);
136760573Skris		return;
136860573Skris	}
136969587Sgreen	debug2("channel %d: rcvd ext data %d", c->self, data_len);
137060573Skris	c->local_window -= data_len;
137160573Skris	buffer_append(&c->extended, data, data_len);
137260573Skris	xfree(data);
137360573Skris}
137460573Skris
137560573Skris
137657429Smarkm/*
137757429Smarkm * Returns true if no channel has too much buffered data, and false if one or
137857429Smarkm * more channel is overfull.
137957429Smarkm */
138057429Smarkm
138160573Skrisint
138257429Smarkmchannel_not_very_much_buffered_data()
138357429Smarkm{
138476262Sgreen	u_int i;
138560573Skris	Channel *c;
138657429Smarkm
138757429Smarkm	for (i = 0; i < channels_alloc; i++) {
138860573Skris		c = &channels[i];
138960573Skris		if (c->type == SSH_CHANNEL_OPEN) {
139060573Skris			if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
139160573Skris				debug("channel %d: big input buffer %d",
139260573Skris				    c->self, buffer_len(&c->input));
139357429Smarkm				return 0;
139460573Skris			}
139560573Skris			if (buffer_len(&c->output) > packet_get_maxsize()) {
139660573Skris				debug("channel %d: big output buffer %d",
139760573Skris				    c->self, buffer_len(&c->output));
139857429Smarkm				return 0;
139960573Skris			}
140057429Smarkm		}
140157429Smarkm	}
140257429Smarkm	return 1;
140357429Smarkm}
140457429Smarkm
140560573Skrisvoid
140669587Sgreenchannel_input_ieof(int type, int plen, void *ctxt)
140760573Skris{
140860573Skris	int id;
140960573Skris	Channel *c;
141057429Smarkm
141160573Skris	packet_integrity_check(plen, 4, type);
141260573Skris
141360573Skris	id = packet_get_int();
141460573Skris	c = channel_lookup(id);
141560573Skris	if (c == NULL)
141660573Skris		packet_disconnect("Received ieof for nonexistent channel %d.", id);
141760573Skris	chan_rcvd_ieof(c);
141860573Skris}
141960573Skris
142060573Skrisvoid
142169587Sgreenchannel_input_close(int type, int plen, void *ctxt)
142257429Smarkm{
142360573Skris	int id;
142460573Skris	Channel *c;
142557429Smarkm
142660573Skris	packet_integrity_check(plen, 4, type);
142757429Smarkm
142860573Skris	id = packet_get_int();
142960573Skris	c = channel_lookup(id);
143060573Skris	if (c == NULL)
143160573Skris		packet_disconnect("Received close for nonexistent channel %d.", id);
143257429Smarkm
143357429Smarkm	/*
143457429Smarkm	 * Send a confirmation that we have closed the channel and no more
143557429Smarkm	 * data is coming for it.
143657429Smarkm	 */
143757429Smarkm	packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
143860573Skris	packet_put_int(c->remote_id);
143957429Smarkm	packet_send();
144057429Smarkm
144157429Smarkm	/*
144257429Smarkm	 * If the channel is in closed state, we have sent a close request,
144357429Smarkm	 * and the other side will eventually respond with a confirmation.
144457429Smarkm	 * Thus, we cannot free the channel here, because then there would be
144557429Smarkm	 * no-one to receive the confirmation.  The channel gets freed when
144657429Smarkm	 * the confirmation arrives.
144757429Smarkm	 */
144860573Skris	if (c->type != SSH_CHANNEL_CLOSED) {
144957429Smarkm		/*
145057429Smarkm		 * Not a closed channel - mark it as draining, which will
145157429Smarkm		 * cause it to be freed later.
145257429Smarkm		 */
145360573Skris		buffer_consume(&c->input, buffer_len(&c->input));
145460573Skris		c->type = SSH_CHANNEL_OUTPUT_DRAINING;
145557429Smarkm	}
145657429Smarkm}
145757429Smarkm
145860573Skris/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
145960573Skrisvoid
146069587Sgreenchannel_input_oclose(int type, int plen, void *ctxt)
146160573Skris{
146260573Skris	int id = packet_get_int();
146360573Skris	Channel *c = channel_lookup(id);
146460573Skris	packet_integrity_check(plen, 4, type);
146560573Skris	if (c == NULL)
146660573Skris		packet_disconnect("Received oclose for nonexistent channel %d.", id);
146760573Skris	chan_rcvd_oclose(c);
146860573Skris}
146957429Smarkm
147060573Skrisvoid
147169587Sgreenchannel_input_close_confirmation(int type, int plen, void *ctxt)
147257429Smarkm{
147360573Skris	int id = packet_get_int();
147460573Skris	Channel *c = channel_lookup(id);
147557429Smarkm
147660573Skris	packet_done();
147760573Skris	if (c == NULL)
147860573Skris		packet_disconnect("Received close confirmation for "
147960573Skris		    "out-of-range channel %d.", id);
148060573Skris	if (c->type != SSH_CHANNEL_CLOSED)
148160573Skris		packet_disconnect("Received close confirmation for "
148260573Skris		    "non-closed channel %d (type %d).", id, c->type);
148360573Skris	channel_free(c->self);
148460573Skris}
148557429Smarkm
148660573Skrisvoid
148769587Sgreenchannel_input_open_confirmation(int type, int plen, void *ctxt)
148860573Skris{
148960573Skris	int id, remote_id;
149060573Skris	Channel *c;
149160573Skris
149260573Skris	if (!compat20)
149360573Skris		packet_integrity_check(plen, 4 + 4, type);
149460573Skris
149560573Skris	id = packet_get_int();
149660573Skris	c = channel_lookup(id);
149760573Skris
149860573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
149960573Skris		packet_disconnect("Received open confirmation for "
150060573Skris		    "non-opening channel %d.", id);
150160573Skris	remote_id = packet_get_int();
150260573Skris	/* Record the remote channel number and mark that the channel is now open. */
150360573Skris	c->remote_id = remote_id;
150460573Skris	c->type = SSH_CHANNEL_OPEN;
150560573Skris
150660573Skris	if (compat20) {
150760573Skris		c->remote_window = packet_get_int();
150860573Skris		c->remote_maxpacket = packet_get_int();
150960573Skris		packet_done();
151060573Skris		if (c->cb_fn != NULL && c->cb_event == type) {
151169587Sgreen			debug2("callback start");
151260573Skris			c->cb_fn(c->self, c->cb_arg);
151369587Sgreen			debug2("callback done");
151460573Skris		}
151560573Skris		debug("channel %d: open confirm rwindow %d rmax %d", c->self,
151660573Skris		    c->remote_window, c->remote_maxpacket);
151757429Smarkm	}
151857429Smarkm}
151957429Smarkm
152060573Skrisvoid
152169587Sgreenchannel_input_open_failure(int type, int plen, void *ctxt)
152257429Smarkm{
152376262Sgreen	int id, reason;
152476262Sgreen	char *msg = NULL, *lang = NULL;
152560573Skris	Channel *c;
152657429Smarkm
152760573Skris	if (!compat20)
152860573Skris		packet_integrity_check(plen, 4, type);
152957429Smarkm
153060573Skris	id = packet_get_int();
153160573Skris	c = channel_lookup(id);
153257429Smarkm
153360573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
153460573Skris		packet_disconnect("Received open failure for "
153560573Skris		    "non-opening channel %d.", id);
153660573Skris	if (compat20) {
153776262Sgreen		reason = packet_get_int();
153876262Sgreen		if (packet_remaining() > 0) {
153976262Sgreen			msg  = packet_get_string(NULL);
154076262Sgreen			lang = packet_get_string(NULL);
154176262Sgreen		}
154260573Skris		packet_done();
154376262Sgreen		log("channel_open_failure: %d: reason %d %s", id,
154476262Sgreen		    reason, msg ? msg : "<no additional info>");
154576262Sgreen		if (msg != NULL)
154676262Sgreen			xfree(msg);
154776262Sgreen		if (lang != NULL)
154876262Sgreen			xfree(lang);
154960573Skris	}
155060573Skris	/* Free the channel.  This will also close the socket. */
155160573Skris	channel_free(id);
155257429Smarkm}
155357429Smarkm
155460573Skrisvoid
155569587Sgreenchannel_input_channel_request(int type, int plen, void *ctxt)
155660573Skris{
155760573Skris	int id;
155860573Skris	Channel *c;
155957429Smarkm
156060573Skris	id = packet_get_int();
156160573Skris	c = channel_lookup(id);
156260573Skris
156360573Skris	if (c == NULL ||
156460573Skris	    (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
156560573Skris		packet_disconnect("Received request for "
156660573Skris		    "non-open channel %d.", id);
156760573Skris	if (c->cb_fn != NULL && c->cb_event == type) {
156869587Sgreen		debug2("callback start");
156960573Skris		c->cb_fn(c->self, c->cb_arg);
157069587Sgreen		debug2("callback done");
157160573Skris	} else {
157260573Skris		char *service = packet_get_string(NULL);
157376262Sgreen		debug("channel %d: rcvd request for %s", c->self, service);
157469587Sgreen		debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
157560573Skris		xfree(service);
157660573Skris	}
157760573Skris}
157860573Skris
157960573Skrisvoid
158069587Sgreenchannel_input_window_adjust(int type, int plen, void *ctxt)
158157429Smarkm{
158260573Skris	Channel *c;
158360573Skris	int id, adjust;
158457429Smarkm
158560573Skris	if (!compat20)
158660573Skris		return;
158760573Skris
158857429Smarkm	/* Get the channel number and verify it. */
158960573Skris	id = packet_get_int();
159060573Skris	c = channel_lookup(id);
159157429Smarkm
159260573Skris	if (c == NULL || c->type != SSH_CHANNEL_OPEN) {
159360573Skris		log("Received window adjust for "
159460573Skris		    "non-open channel %d.", id);
159560573Skris		return;
159660573Skris	}
159760573Skris	adjust = packet_get_int();
159860573Skris	packet_done();
159969587Sgreen	debug2("channel %d: rcvd adjust %d", id, adjust);
160060573Skris	c->remote_window += adjust;
160157429Smarkm}
160257429Smarkm
160357429Smarkm/*
160457429Smarkm * Stops listening for channels, and removes any unix domain sockets that we
160557429Smarkm * might have.
160657429Smarkm */
160757429Smarkm
160860573Skrisvoid
160957429Smarkmchannel_stop_listening()
161057429Smarkm{
161157429Smarkm	int i;
161257429Smarkm	for (i = 0; i < channels_alloc; i++) {
161357429Smarkm		switch (channels[i].type) {
161457429Smarkm		case SSH_CHANNEL_AUTH_SOCKET:
161557429Smarkm			close(channels[i].sock);
161677925Sgreen			/* auth_sock_cleanup_proc deletes the socket */
161757429Smarkm			channel_free(i);
161857429Smarkm			break;
161957429Smarkm		case SSH_CHANNEL_PORT_LISTENER:
162076262Sgreen		case SSH_CHANNEL_RPORT_LISTENER:
162157429Smarkm		case SSH_CHANNEL_X11_LISTENER:
162257429Smarkm			close(channels[i].sock);
162357429Smarkm			channel_free(i);
162457429Smarkm			break;
162557429Smarkm		default:
162657429Smarkm			break;
162757429Smarkm		}
162857429Smarkm	}
162957429Smarkm}
163057429Smarkm
163157429Smarkm/*
163260573Skris * Closes the sockets/fds of all channels.  This is used to close extra file
163357429Smarkm * descriptors after a fork.
163457429Smarkm */
163557429Smarkm
163660573Skrisvoid
163757429Smarkmchannel_close_all()
163857429Smarkm{
163957429Smarkm	int i;
164060573Skris	for (i = 0; i < channels_alloc; i++)
164157429Smarkm		if (channels[i].type != SSH_CHANNEL_FREE)
164260573Skris			channel_close_fds(&channels[i]);
164357429Smarkm}
164457429Smarkm
164557429Smarkm/* Returns true if any channel is still open. */
164657429Smarkm
164760573Skrisint
164857429Smarkmchannel_still_open()
164957429Smarkm{
165076262Sgreen	u_int i;
165157429Smarkm	for (i = 0; i < channels_alloc; i++)
165257429Smarkm		switch (channels[i].type) {
165357429Smarkm		case SSH_CHANNEL_FREE:
165457429Smarkm		case SSH_CHANNEL_X11_LISTENER:
165557429Smarkm		case SSH_CHANNEL_PORT_LISTENER:
165676262Sgreen		case SSH_CHANNEL_RPORT_LISTENER:
165757429Smarkm		case SSH_CHANNEL_CLOSED:
165857429Smarkm		case SSH_CHANNEL_AUTH_SOCKET:
165976262Sgreen		case SSH_CHANNEL_DYNAMIC:
166076262Sgreen		case SSH_CHANNEL_CONNECTING: 	/* XXX ??? */
166157429Smarkm			continue;
166260573Skris		case SSH_CHANNEL_LARVAL:
166360573Skris			if (!compat20)
166460573Skris				fatal("cannot happen: SSH_CHANNEL_LARVAL");
166560573Skris			continue;
166657429Smarkm		case SSH_CHANNEL_OPENING:
166757429Smarkm		case SSH_CHANNEL_OPEN:
166857429Smarkm		case SSH_CHANNEL_X11_OPEN:
166957429Smarkm			return 1;
167057429Smarkm		case SSH_CHANNEL_INPUT_DRAINING:
167157429Smarkm		case SSH_CHANNEL_OUTPUT_DRAINING:
167257429Smarkm			if (!compat13)
167357429Smarkm				fatal("cannot happen: OUT_DRAIN");
167457429Smarkm			return 1;
167557429Smarkm		default:
167657429Smarkm			fatal("channel_still_open: bad channel type %d", channels[i].type);
167757429Smarkm			/* NOTREACHED */
167857429Smarkm		}
167957429Smarkm	return 0;
168057429Smarkm}
168157429Smarkm
168276262Sgreen/* Returns the id of an open channel suitable for keepaliving */
168376262Sgreen
168476262Sgreenint
168576262Sgreenchannel_find_open()
168676262Sgreen{
168776262Sgreen	u_int i;
168876262Sgreen	for (i = 0; i < channels_alloc; i++)
168976262Sgreen		switch (channels[i].type) {
169076262Sgreen		case SSH_CHANNEL_CLOSED:
169176262Sgreen		case SSH_CHANNEL_DYNAMIC:
169276262Sgreen		case SSH_CHANNEL_FREE:
169376262Sgreen		case SSH_CHANNEL_X11_LISTENER:
169476262Sgreen		case SSH_CHANNEL_PORT_LISTENER:
169576262Sgreen		case SSH_CHANNEL_RPORT_LISTENER:
169676262Sgreen		case SSH_CHANNEL_OPENING:
169776262Sgreen			continue;
169876262Sgreen		case SSH_CHANNEL_LARVAL:
169976262Sgreen		case SSH_CHANNEL_AUTH_SOCKET:
170076262Sgreen		case SSH_CHANNEL_CONNECTING: 	/* XXX ??? */
170176262Sgreen		case SSH_CHANNEL_OPEN:
170276262Sgreen		case SSH_CHANNEL_X11_OPEN:
170376262Sgreen			return i;
170476262Sgreen		case SSH_CHANNEL_INPUT_DRAINING:
170576262Sgreen		case SSH_CHANNEL_OUTPUT_DRAINING:
170676262Sgreen			if (!compat13)
170776262Sgreen				fatal("cannot happen: OUT_DRAIN");
170876262Sgreen			return i;
170976262Sgreen		default:
171076262Sgreen			fatal("channel_find_open: bad channel type %d", channels[i].type);
171176262Sgreen			/* NOTREACHED */
171276262Sgreen		}
171376262Sgreen	return -1;
171476262Sgreen}
171576262Sgreen
171676262Sgreen
171757429Smarkm/*
171857429Smarkm * Returns a message describing the currently open forwarded connections,
171957429Smarkm * suitable for sending to the client.  The message contains crlf pairs for
172057429Smarkm * newlines.
172157429Smarkm */
172257429Smarkm
172357429Smarkmchar *
172457429Smarkmchannel_open_message()
172557429Smarkm{
172657429Smarkm	Buffer buffer;
172757429Smarkm	int i;
172857429Smarkm	char buf[512], *cp;
172957429Smarkm
173057429Smarkm	buffer_init(&buffer);
173157429Smarkm	snprintf(buf, sizeof buf, "The following connections are open:\r\n");
173257429Smarkm	buffer_append(&buffer, buf, strlen(buf));
173357429Smarkm	for (i = 0; i < channels_alloc; i++) {
173457429Smarkm		Channel *c = &channels[i];
173557429Smarkm		switch (c->type) {
173657429Smarkm		case SSH_CHANNEL_FREE:
173757429Smarkm		case SSH_CHANNEL_X11_LISTENER:
173857429Smarkm		case SSH_CHANNEL_PORT_LISTENER:
173976262Sgreen		case SSH_CHANNEL_RPORT_LISTENER:
174057429Smarkm		case SSH_CHANNEL_CLOSED:
174157429Smarkm		case SSH_CHANNEL_AUTH_SOCKET:
174257429Smarkm			continue;
174360573Skris		case SSH_CHANNEL_LARVAL:
174457429Smarkm		case SSH_CHANNEL_OPENING:
174576262Sgreen		case SSH_CHANNEL_CONNECTING:
174676262Sgreen		case SSH_CHANNEL_DYNAMIC:
174757429Smarkm		case SSH_CHANNEL_OPEN:
174857429Smarkm		case SSH_CHANNEL_X11_OPEN:
174957429Smarkm		case SSH_CHANNEL_INPUT_DRAINING:
175057429Smarkm		case SSH_CHANNEL_OUTPUT_DRAINING:
175160573Skris			snprintf(buf, sizeof buf, "  #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
175257429Smarkm			    c->self, c->remote_name,
175357429Smarkm			    c->type, c->remote_id,
175457429Smarkm			    c->istate, buffer_len(&c->input),
175560573Skris			    c->ostate, buffer_len(&c->output),
175660573Skris			    c->rfd, c->wfd);
175757429Smarkm			buffer_append(&buffer, buf, strlen(buf));
175857429Smarkm			continue;
175957429Smarkm		default:
176060573Skris			fatal("channel_open_message: bad channel type %d", c->type);
176157429Smarkm			/* NOTREACHED */
176257429Smarkm		}
176357429Smarkm	}
176457429Smarkm	buffer_append(&buffer, "\0", 1);
176557429Smarkm	cp = xstrdup(buffer_ptr(&buffer));
176657429Smarkm	buffer_free(&buffer);
176757429Smarkm	return cp;
176857429Smarkm}
176957429Smarkm
177057429Smarkm/*
177157429Smarkm * Initiate forwarding of connections to local port "port" through the secure
177257429Smarkm * channel to host:port from remote side.
177357429Smarkm */
177476262Sgreenint
177576262Sgreenchannel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
177676262Sgreen    u_short port_to_connect, int gateway_ports)
177776262Sgreen{
177876262Sgreen	return channel_request_forwarding(
177976262Sgreen	    NULL, listen_port,
178076262Sgreen	    host_to_connect, port_to_connect,
178176262Sgreen	    gateway_ports, /*remote_fwd*/ 0);
178276262Sgreen}
178357429Smarkm
178476262Sgreen/*
178576262Sgreen * If 'remote_fwd' is true we have a '-R style' listener for protocol 2
178676262Sgreen * (SSH_CHANNEL_RPORT_LISTENER).
178776262Sgreen */
178876262Sgreenint
178976262Sgreenchannel_request_forwarding(
179076262Sgreen    const char *listen_address, u_short listen_port,
179176262Sgreen    const char *host_to_connect, u_short port_to_connect,
179276262Sgreen    int gateway_ports, int remote_fwd)
179357429Smarkm{
179476262Sgreen	int success, ch, sock, on = 1, ctype;
179557429Smarkm	struct addrinfo hints, *ai, *aitop;
179657429Smarkm	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
179776262Sgreen	const char *host;
179857429Smarkm	struct linger linger;
179957429Smarkm
180076262Sgreen	success = 0;
180157429Smarkm
180276262Sgreen	if (remote_fwd) {
180376262Sgreen		host = listen_address;
180476262Sgreen		ctype = SSH_CHANNEL_RPORT_LISTENER;
180576262Sgreen	} else {
180676262Sgreen		host = host_to_connect;
180776262Sgreen		ctype  =SSH_CHANNEL_PORT_LISTENER;
180876262Sgreen	}
180976262Sgreen
181076262Sgreen	if (strlen(host) > sizeof(channels[0].path) - 1) {
181176262Sgreen		error("Forward host name too long.");
181276262Sgreen		return success;
181376262Sgreen	}
181476262Sgreen
181576262Sgreen	/* XXX listen_address is currently ignored */
181657429Smarkm	/*
181757429Smarkm	 * getaddrinfo returns a loopback address if the hostname is
181857429Smarkm	 * set to NULL and hints.ai_flags is not AI_PASSIVE
181957429Smarkm	 */
182057429Smarkm	memset(&hints, 0, sizeof(hints));
182157429Smarkm	hints.ai_family = IPv4or6;
182257429Smarkm	hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
182357429Smarkm	hints.ai_socktype = SOCK_STREAM;
182476262Sgreen	snprintf(strport, sizeof strport, "%d", listen_port);
182557429Smarkm	if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
182657429Smarkm		packet_disconnect("getaddrinfo: fatal error");
182757429Smarkm
182857429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
182957429Smarkm		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
183057429Smarkm			continue;
183157429Smarkm		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
183257429Smarkm		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
183376262Sgreen			error("channel_request_forwarding: getnameinfo failed");
183457429Smarkm			continue;
183557429Smarkm		}
183657429Smarkm		/* Create a port to listen for the host. */
183757429Smarkm		sock = socket(ai->ai_family, SOCK_STREAM, 0);
183857429Smarkm		if (sock < 0) {
183957429Smarkm			/* this is no error since kernel may not support ipv6 */
184057429Smarkm			verbose("socket: %.100s", strerror(errno));
184157429Smarkm			continue;
184257429Smarkm		}
184357429Smarkm		/*
184457429Smarkm		 * Set socket options.  We would like the socket to disappear
184557429Smarkm		 * as soon as it has been closed for whatever reason.
184657429Smarkm		 */
184757429Smarkm		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
184857429Smarkm		linger.l_onoff = 1;
184957429Smarkm		linger.l_linger = 5;
185057429Smarkm		setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
185157429Smarkm		debug("Local forwarding listening on %s port %s.", ntop, strport);
185257429Smarkm
185357429Smarkm		/* Bind the socket to the address. */
185457429Smarkm		if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
185557429Smarkm			/* address can be in use ipv6 address is already bound */
185657429Smarkm			verbose("bind: %.100s", strerror(errno));
185757429Smarkm			close(sock);
185857429Smarkm			continue;
185957429Smarkm		}
186057429Smarkm		/* Start listening for connections on the socket. */
186157429Smarkm		if (listen(sock, 5) < 0) {
186257429Smarkm			error("listen: %.100s", strerror(errno));
186357429Smarkm			close(sock);
186457429Smarkm			continue;
186557429Smarkm		}
186657429Smarkm		/* Allocate a channel number for the socket. */
186776262Sgreen		ch = channel_new("port listener", ctype, sock, sock, -1,
186860573Skris		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
186969587Sgreen		    0, xstrdup("port listener"), 1);
187057429Smarkm		strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
187176262Sgreen		channels[ch].host_port = port_to_connect;
187276262Sgreen		channels[ch].listening_port = listen_port;
187357429Smarkm		success = 1;
187457429Smarkm	}
187557429Smarkm	if (success == 0)
187676262Sgreen		error("channel_request_forwarding: cannot listen to port: %d",
187776262Sgreen		    listen_port);
187857429Smarkm	freeaddrinfo(aitop);
187976262Sgreen	return success;
188057429Smarkm}
188157429Smarkm
188257429Smarkm/*
188357429Smarkm * Initiate forwarding of connections to port "port" on remote host through
188457429Smarkm * the secure channel to host:port from local side.
188557429Smarkm */
188657429Smarkm
188760573Skrisvoid
188876262Sgreenchannel_request_remote_forwarding(u_short listen_port,
188976262Sgreen    const char *host_to_connect, u_short port_to_connect)
189057429Smarkm{
189176262Sgreen	int payload_len, type, success = 0;
189276262Sgreen
189357429Smarkm	/* Record locally that connection to this host/port is permitted. */
189457429Smarkm	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
189557429Smarkm		fatal("channel_request_remote_forwarding: too many forwards");
189657429Smarkm
189757429Smarkm	/* Send the forward request to the remote side. */
189860573Skris	if (compat20) {
189960573Skris		const char *address_to_bind = "0.0.0.0";
190060573Skris		packet_start(SSH2_MSG_GLOBAL_REQUEST);
190160573Skris		packet_put_cstring("tcpip-forward");
190260573Skris		packet_put_char(0);			/* boolean: want reply */
190360573Skris		packet_put_cstring(address_to_bind);
190460573Skris		packet_put_int(listen_port);
190576262Sgreen		packet_send();
190676262Sgreen		packet_write_wait();
190776262Sgreen		/* Assume that server accepts the request */
190876262Sgreen		success = 1;
190960573Skris	} else {
191060573Skris		packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
191160573Skris		packet_put_int(listen_port);
191260573Skris		packet_put_cstring(host_to_connect);
191360573Skris		packet_put_int(port_to_connect);
191460573Skris		packet_send();
191560573Skris		packet_write_wait();
191676262Sgreen
191776262Sgreen		/* Wait for response from the remote side. */
191876262Sgreen		type = packet_read(&payload_len);
191976262Sgreen		switch (type) {
192076262Sgreen		case SSH_SMSG_SUCCESS:
192176262Sgreen			success = 1;
192276262Sgreen			break;
192376262Sgreen		case SSH_SMSG_FAILURE:
192476262Sgreen			log("Warning: Server denied remote port forwarding.");
192576262Sgreen			break;
192676262Sgreen		default:
192776262Sgreen			/* Unknown packet */
192876262Sgreen			packet_disconnect("Protocol error for port forward request:"
192976262Sgreen			    "received packet type %d.", type);
193076262Sgreen		}
193160573Skris	}
193276262Sgreen	if (success) {
193376262Sgreen		permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
193476262Sgreen		permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
193576262Sgreen		permitted_opens[num_permitted_opens].listen_port = listen_port;
193676262Sgreen		num_permitted_opens++;
193776262Sgreen	}
193857429Smarkm}
193957429Smarkm
194057429Smarkm/*
194157429Smarkm * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
194257429Smarkm * listening for the port, and sends back a success reply (or disconnect
194357429Smarkm * message if there was an error).  This never returns if there was an error.
194457429Smarkm */
194557429Smarkm
194660573Skrisvoid
194760573Skrischannel_input_port_forward_request(int is_root, int gateway_ports)
194857429Smarkm{
194957429Smarkm	u_short port, host_port;
195057429Smarkm	char *hostname;
195157429Smarkm
195257429Smarkm	/* Get arguments from the packet. */
195357429Smarkm	port = packet_get_int();
195457429Smarkm	hostname = packet_get_string(NULL);
195557429Smarkm	host_port = packet_get_int();
195657429Smarkm
195757429Smarkm	/*
195857429Smarkm	 * Check that an unprivileged user is not trying to forward a
195957429Smarkm	 * privileged port.
196057429Smarkm	 */
196157429Smarkm	if (port < IPPORT_RESERVED && !is_root)
196257429Smarkm		packet_disconnect("Requested forwarding of port %d but user is not root.",
196357429Smarkm				  port);
196476262Sgreen	/* Initiate forwarding */
196560573Skris	channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
196657429Smarkm
196757429Smarkm	/* Free the argument string. */
196857429Smarkm	xfree(hostname);
196957429Smarkm}
197057429Smarkm
197176262Sgreen/*
197276262Sgreen * Permits opening to any host/port if permitted_opens[] is empty.  This is
197376262Sgreen * usually called by the server, because the user could connect to any port
197476262Sgreen * anyway, and the server has no way to know but to trust the client anyway.
197576262Sgreen */
197676262Sgreenvoid
197776262Sgreenchannel_permit_all_opens()
197876262Sgreen{
197976262Sgreen	if (num_permitted_opens == 0)
198076262Sgreen		all_opens_permitted = 1;
198176262Sgreen}
198276262Sgreen
198376262Sgreenvoid
198476262Sgreenchannel_add_permitted_opens(char *host, int port)
198576262Sgreen{
198676262Sgreen	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
198776262Sgreen		fatal("channel_request_remote_forwarding: too many forwards");
198876262Sgreen	debug("allow port forwarding to host %s port %d", host, port);
198976262Sgreen
199076262Sgreen	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
199176262Sgreen	permitted_opens[num_permitted_opens].port_to_connect = port;
199276262Sgreen	num_permitted_opens++;
199376262Sgreen
199476262Sgreen	all_opens_permitted = 0;
199576262Sgreen}
199676262Sgreen
199776262Sgreenvoid
199876262Sgreenchannel_clear_permitted_opens(void)
199976262Sgreen{
200076262Sgreen	int i;
200176262Sgreen
200276262Sgreen	for (i = 0; i < num_permitted_opens; i++)
200376262Sgreen		xfree(permitted_opens[i].host_to_connect);
200476262Sgreen	num_permitted_opens = 0;
200576262Sgreen
200676262Sgreen}
200776262Sgreen
200876262Sgreen
200976262Sgreen/* return socket to remote host, port */
201060573Skrisint
201176262Sgreenconnect_to(const char *host, u_short port)
201260573Skris{
201360573Skris	struct addrinfo hints, *ai, *aitop;
201460573Skris	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
201560573Skris	int gaierr;
201660573Skris	int sock = -1;
201760573Skris
201860573Skris	memset(&hints, 0, sizeof(hints));
201960573Skris	hints.ai_family = IPv4or6;
202060573Skris	hints.ai_socktype = SOCK_STREAM;
202176262Sgreen	snprintf(strport, sizeof strport, "%d", port);
202260573Skris	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
202376262Sgreen		error("connect_to %.100s: unknown host (%s)", host,
202476262Sgreen		    gai_strerror(gaierr));
202560573Skris		return -1;
202660573Skris	}
202760573Skris	for (ai = aitop; ai; ai = ai->ai_next) {
202860573Skris		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
202960573Skris			continue;
203060573Skris		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
203160573Skris		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
203276262Sgreen			error("connect_to: getnameinfo failed");
203360573Skris			continue;
203460573Skris		}
203560573Skris		sock = socket(ai->ai_family, SOCK_STREAM, 0);
203660573Skris		if (sock < 0) {
203760573Skris			error("socket: %.100s", strerror(errno));
203860573Skris			continue;
203960573Skris		}
204076262Sgreen		if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
204176262Sgreen			fatal("connect_to: F_SETFL: %s", strerror(errno));
204276262Sgreen		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
204376262Sgreen		    errno != EINPROGRESS) {
204476262Sgreen			error("connect_to %.100s port %s: %.100s", ntop, strport,
204560573Skris			    strerror(errno));
204660573Skris			close(sock);
204776262Sgreen			continue;	/* fail -- try next */
204860573Skris		}
204960573Skris		break; /* success */
205060573Skris
205160573Skris	}
205260573Skris	freeaddrinfo(aitop);
205360573Skris	if (!ai) {
205476262Sgreen		error("connect_to %.100s port %d: failed.", host, port);
205560573Skris		return -1;
205660573Skris	}
205760573Skris	/* success */
205860573Skris	return sock;
205960573Skris}
206076262Sgreen
206176262Sgreenint
206276262Sgreenchannel_connect_by_listen_adress(u_short listen_port)
206376262Sgreen{
206476262Sgreen	int i;
206576262Sgreen
206676262Sgreen	for (i = 0; i < num_permitted_opens; i++)
206776262Sgreen		if (permitted_opens[i].listen_port == listen_port)
206876262Sgreen			return connect_to(
206976262Sgreen			    permitted_opens[i].host_to_connect,
207076262Sgreen			    permitted_opens[i].port_to_connect);
207176262Sgreen	error("WARNING: Server requests forwarding for unknown listen_port %d",
207276262Sgreen	    listen_port);
207376262Sgreen	return -1;
207476262Sgreen}
207576262Sgreen
207676262Sgreen/* Check if connecting to that port is permitted and connect. */
207776262Sgreenint
207876262Sgreenchannel_connect_to(const char *host, u_short port)
207976262Sgreen{
208076262Sgreen	int i, permit;
208176262Sgreen
208276262Sgreen	permit = all_opens_permitted;
208376262Sgreen	if (!permit) {
208476262Sgreen		for (i = 0; i < num_permitted_opens; i++)
208576262Sgreen			if (permitted_opens[i].port_to_connect == port &&
208676262Sgreen			    strcmp(permitted_opens[i].host_to_connect, host) == 0)
208776262Sgreen				permit = 1;
208876262Sgreen
208976262Sgreen	}
209076262Sgreen	if (!permit) {
209176262Sgreen		log("Received request to connect to host %.100s port %d, "
209276262Sgreen		    "but the request was denied.", host, port);
209376262Sgreen		return -1;
209476262Sgreen	}
209576262Sgreen	return connect_to(host, port);
209676262Sgreen}
209776262Sgreen
209857429Smarkm/*
209957429Smarkm * This is called after receiving PORT_OPEN message.  This attempts to
210057429Smarkm * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
210157429Smarkm * or CHANNEL_OPEN_FAILURE.
210257429Smarkm */
210357429Smarkm
210460573Skrisvoid
210569587Sgreenchannel_input_port_open(int type, int plen, void *ctxt)
210657429Smarkm{
210757429Smarkm	u_short host_port;
210857429Smarkm	char *host, *originator_string;
210976262Sgreen	int remote_channel, sock = -1, newch;
211057429Smarkm
211157429Smarkm	remote_channel = packet_get_int();
211276262Sgreen	host = packet_get_string(NULL);
211357429Smarkm	host_port = packet_get_int();
211457429Smarkm
211557429Smarkm	if (have_hostname_in_open) {
211676262Sgreen		originator_string = packet_get_string(NULL);
211757429Smarkm	} else {
211857429Smarkm		originator_string = xstrdup("unknown (remote did not supply name)");
211957429Smarkm	}
212076262Sgreen	packet_done();
212176262Sgreen	sock = channel_connect_to(host, host_port);
212276262Sgreen	if (sock != -1) {
212376262Sgreen		newch = channel_allocate(SSH_CHANNEL_CONNECTING,
212476262Sgreen		    sock, originator_string);
212560573Skris		channels[newch].remote_id = remote_channel;
212657429Smarkm
212776262Sgreen		/*XXX delay answer? */
212860573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
212960573Skris		packet_put_int(remote_channel);
213060573Skris		packet_put_int(newch);
213160573Skris		packet_send();
213260573Skris	} else {
213360573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
213460573Skris		packet_put_int(remote_channel);
213560573Skris		packet_send();
213657429Smarkm	}
213757429Smarkm	xfree(host);
213857429Smarkm}
213957429Smarkm
214057429Smarkm/*
214157429Smarkm * Creates an internet domain socket for listening for X11 connections.
214257429Smarkm * Returns a suitable value for the DISPLAY variable, or NULL if an error
214357429Smarkm * occurs.
214457429Smarkm */
214557429Smarkm
214657429Smarkm#define	NUM_SOCKS	10
214757429Smarkm
214857429Smarkmchar *
214957429Smarkmx11_create_display_inet(int screen_number, int x11_display_offset)
215057429Smarkm{
215157429Smarkm	int display_number, sock;
215257429Smarkm	u_short port;
215357429Smarkm	struct addrinfo hints, *ai, *aitop;
215457429Smarkm	char strport[NI_MAXSERV];
215557429Smarkm	int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
215657429Smarkm	char display[512];
215757429Smarkm	char hostname[MAXHOSTNAMELEN];
215857429Smarkm
215957429Smarkm	for (display_number = x11_display_offset;
216057429Smarkm	     display_number < MAX_DISPLAYS;
216157429Smarkm	     display_number++) {
216257429Smarkm		port = 6000 + display_number;
216357429Smarkm		memset(&hints, 0, sizeof(hints));
216457429Smarkm		hints.ai_family = IPv4or6;
216557429Smarkm		hints.ai_flags = AI_PASSIVE;		/* XXX loopback only ? */
216657429Smarkm		hints.ai_socktype = SOCK_STREAM;
216757429Smarkm		snprintf(strport, sizeof strport, "%d", port);
216857429Smarkm		if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
216957429Smarkm			error("getaddrinfo: %.100s", gai_strerror(gaierr));
217057429Smarkm			return NULL;
217157429Smarkm		}
217257429Smarkm		for (ai = aitop; ai; ai = ai->ai_next) {
217357429Smarkm			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
217457429Smarkm				continue;
217557429Smarkm			sock = socket(ai->ai_family, SOCK_STREAM, 0);
217657429Smarkm			if (sock < 0) {
217757429Smarkm				error("socket: %.100s", strerror(errno));
217857429Smarkm				return NULL;
217957429Smarkm			}
218057429Smarkm			if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
218157429Smarkm				debug("bind port %d: %.100s", port, strerror(errno));
218257429Smarkm				shutdown(sock, SHUT_RDWR);
218357429Smarkm				close(sock);
218457429Smarkm				for (n = 0; n < num_socks; n++) {
218557429Smarkm					shutdown(socks[n], SHUT_RDWR);
218657429Smarkm					close(socks[n]);
218757429Smarkm				}
218857429Smarkm				num_socks = 0;
218957429Smarkm				break;
219057429Smarkm			}
219157429Smarkm			socks[num_socks++] = sock;
219257429Smarkm			if (num_socks == NUM_SOCKS)
219357429Smarkm				break;
219457429Smarkm		}
219576262Sgreen		freeaddrinfo(aitop);
219657429Smarkm		if (num_socks > 0)
219757429Smarkm			break;
219857429Smarkm	}
219957429Smarkm	if (display_number >= MAX_DISPLAYS) {
220057429Smarkm		error("Failed to allocate internet-domain X11 display socket.");
220157429Smarkm		return NULL;
220257429Smarkm	}
220357429Smarkm	/* Start listening for connections on the socket. */
220457429Smarkm	for (n = 0; n < num_socks; n++) {
220557429Smarkm		sock = socks[n];
220657429Smarkm		if (listen(sock, 5) < 0) {
220757429Smarkm			error("listen: %.100s", strerror(errno));
220857429Smarkm			shutdown(sock, SHUT_RDWR);
220957429Smarkm			close(sock);
221057429Smarkm			return NULL;
221157429Smarkm		}
221257429Smarkm	}
221357429Smarkm
221457429Smarkm	/* Set up a suitable value for the DISPLAY variable. */
221557429Smarkm	if (gethostname(hostname, sizeof(hostname)) < 0)
221657429Smarkm		fatal("gethostname: %.100s", strerror(errno));
221757429Smarkm	snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
221857429Smarkm		 display_number, screen_number);
221957429Smarkm
222057429Smarkm	/* Allocate a channel for each socket. */
222157429Smarkm	for (n = 0; n < num_socks; n++) {
222257429Smarkm		sock = socks[n];
222360573Skris		(void) channel_new("x11 listener",
222460573Skris		    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
222560573Skris		    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
222669587Sgreen		    0, xstrdup("X11 inet listener"), 1);
222757429Smarkm	}
222857429Smarkm
222957429Smarkm	/* Return a suitable value for the DISPLAY environment variable. */
223057429Smarkm	return xstrdup(display);
223157429Smarkm}
223257429Smarkm
223357429Smarkm#ifndef X_UNIX_PATH
223457429Smarkm#define X_UNIX_PATH "/tmp/.X11-unix/X"
223557429Smarkm#endif
223657429Smarkm
223757429Smarkmstatic
223857429Smarkmint
223976262Sgreenconnect_local_xsocket(u_int dnr)
224057429Smarkm{
224157429Smarkm	static const char *const x_sockets[] = {
224257429Smarkm		X_UNIX_PATH "%u",
224357429Smarkm		"/var/X/.X11-unix/X" "%u",
224457429Smarkm		"/usr/spool/sockets/X11/" "%u",
224557429Smarkm		NULL
224657429Smarkm	};
224757429Smarkm	int sock;
224857429Smarkm	struct sockaddr_un addr;
224957429Smarkm	const char *const * path;
225057429Smarkm
225157429Smarkm	for (path = x_sockets; *path; ++path) {
225257429Smarkm		sock = socket(AF_UNIX, SOCK_STREAM, 0);
225357429Smarkm		if (sock < 0)
225457429Smarkm			error("socket: %.100s", strerror(errno));
225557429Smarkm		memset(&addr, 0, sizeof(addr));
225657429Smarkm		addr.sun_family = AF_UNIX;
225757429Smarkm		snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr);
225857429Smarkm		if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0)
225957429Smarkm			return sock;
226057429Smarkm		close(sock);
226157429Smarkm	}
226257429Smarkm	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
226357429Smarkm	return -1;
226457429Smarkm}
226557429Smarkm
226660573Skrisint
226760573Skrisx11_connect_display(void)
226857429Smarkm{
226960573Skris	int display_number, sock = 0;
227057429Smarkm	const char *display;
227160573Skris	char buf[1024], *cp;
227257429Smarkm	struct addrinfo hints, *ai, *aitop;
227357429Smarkm	char strport[NI_MAXSERV];
227457429Smarkm	int gaierr;
227557429Smarkm
227657429Smarkm	/* Try to open a socket for the local X server. */
227757429Smarkm	display = getenv("DISPLAY");
227857429Smarkm	if (!display) {
227957429Smarkm		error("DISPLAY not set.");
228060573Skris		return -1;
228157429Smarkm	}
228257429Smarkm	/*
228357429Smarkm	 * Now we decode the value of the DISPLAY variable and make a
228457429Smarkm	 * connection to the real X server.
228557429Smarkm	 */
228657429Smarkm
228757429Smarkm	/*
228857429Smarkm	 * Check if it is a unix domain socket.  Unix domain displays are in
228957429Smarkm	 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
229057429Smarkm	 */
229157429Smarkm	if (strncmp(display, "unix:", 5) == 0 ||
229257429Smarkm	    display[0] == ':') {
229357429Smarkm		/* Connect to the unix domain socket. */
229457429Smarkm		if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
229557429Smarkm			error("Could not parse display number from DISPLAY: %.100s",
229657429Smarkm			      display);
229760573Skris			return -1;
229857429Smarkm		}
229957429Smarkm		/* Create a socket. */
230057429Smarkm		sock = connect_local_xsocket(display_number);
230157429Smarkm		if (sock < 0)
230260573Skris			return -1;
230357429Smarkm
230457429Smarkm		/* OK, we now have a connection to the display. */
230560573Skris		return sock;
230657429Smarkm	}
230757429Smarkm	/*
230857429Smarkm	 * Connect to an inet socket.  The DISPLAY value is supposedly
230957429Smarkm	 * hostname:d[.s], where hostname may also be numeric IP address.
231057429Smarkm	 */
231157429Smarkm	strncpy(buf, display, sizeof(buf));
231257429Smarkm	buf[sizeof(buf) - 1] = 0;
231357429Smarkm	cp = strchr(buf, ':');
231457429Smarkm	if (!cp) {
231557429Smarkm		error("Could not find ':' in DISPLAY: %.100s", display);
231660573Skris		return -1;
231757429Smarkm	}
231857429Smarkm	*cp = 0;
231957429Smarkm	/* buf now contains the host name.  But first we parse the display number. */
232057429Smarkm	if (sscanf(cp + 1, "%d", &display_number) != 1) {
232157429Smarkm		error("Could not parse display number from DISPLAY: %.100s",
232257429Smarkm		      display);
232360573Skris		return -1;
232457429Smarkm	}
232557429Smarkm
232657429Smarkm	/* Look up the host address */
232757429Smarkm	memset(&hints, 0, sizeof(hints));
232857429Smarkm	hints.ai_family = IPv4or6;
232957429Smarkm	hints.ai_socktype = SOCK_STREAM;
233057429Smarkm	snprintf(strport, sizeof strport, "%d", 6000 + display_number);
233157429Smarkm	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
233257429Smarkm		error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
233360573Skris		return -1;
233457429Smarkm	}
233557429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
233657429Smarkm		/* Create a socket. */
233757429Smarkm		sock = socket(ai->ai_family, SOCK_STREAM, 0);
233857429Smarkm		if (sock < 0) {
233957429Smarkm			debug("socket: %.100s", strerror(errno));
234060573Skris			continue;
234160573Skris		}
234260573Skris		/* Connect it to the display. */
234360573Skris		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
234460573Skris			debug("connect %.100s port %d: %.100s", buf,
234560573Skris			    6000 + display_number, strerror(errno));
234660573Skris			close(sock);
234760573Skris			continue;
234860573Skris		}
234960573Skris		/* Success */
235060573Skris		break;
235157429Smarkm	}
235257429Smarkm	freeaddrinfo(aitop);
235357429Smarkm	if (!ai) {
235460573Skris		error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
235557429Smarkm		    strerror(errno));
235660573Skris		return -1;
235757429Smarkm	}
235860573Skris	return sock;
235960573Skris}
236057429Smarkm
236160573Skris/*
236260573Skris * This is called when SSH_SMSG_X11_OPEN is received.  The packet contains
236360573Skris * the remote channel number.  We should do whatever we want, and respond
236460573Skris * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
236560573Skris */
236657429Smarkm
236760573Skrisvoid
236869587Sgreenx11_input_open(int type, int plen, void *ctxt)
236960573Skris{
237060573Skris	int remote_channel, sock = 0, newch;
237160573Skris	char *remote_host;
237276262Sgreen	u_int remote_len;
237357429Smarkm
237460573Skris	/* Get remote channel number. */
237560573Skris	remote_channel = packet_get_int();
237657429Smarkm
237760573Skris	/* Get remote originator name. */
237860573Skris	if (have_hostname_in_open) {
237960573Skris		remote_host = packet_get_string(&remote_len);
238060573Skris		remote_len += 4;
238160573Skris	} else {
238260573Skris		remote_host = xstrdup("unknown (remote did not supply name)");
238360573Skris		remote_len = 0;
238460573Skris	}
238560573Skris
238660573Skris	debug("Received X11 open request.");
238760573Skris	packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN);
238860573Skris
238960573Skris	/* Obtain a connection to the real X display. */
239060573Skris	sock = x11_connect_display();
239160573Skris	if (sock == -1) {
239260573Skris		/* Send refusal to the remote host. */
239360573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
239460573Skris		packet_put_int(remote_channel);
239560573Skris		packet_send();
239660573Skris	} else {
239760573Skris		/* Allocate a channel for this connection. */
239860573Skris		newch = channel_allocate(
239960573Skris		     (x11_saved_proto == NULL) ?
240060573Skris		     SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN,
240160573Skris		     sock, remote_host);
240260573Skris		channels[newch].remote_id = remote_channel;
240360573Skris
240460573Skris		/* Send a confirmation to the remote host. */
240560573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
240660573Skris		packet_put_int(remote_channel);
240760573Skris		packet_put_int(newch);
240860573Skris		packet_send();
240960573Skris	}
241057429Smarkm}
241157429Smarkm
241269587Sgreen/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
241369587Sgreenvoid
241469587Sgreendeny_input_open(int type, int plen, void *ctxt)
241569587Sgreen{
241669587Sgreen	int rchan = packet_get_int();
241769587Sgreen	switch(type){
241869587Sgreen	case SSH_SMSG_AGENT_OPEN:
241969587Sgreen		error("Warning: ssh server tried agent forwarding.");
242069587Sgreen		break;
242169587Sgreen	case SSH_SMSG_X11_OPEN:
242269587Sgreen		error("Warning: ssh server tried X11 forwarding.");
242369587Sgreen		break;
242469587Sgreen	default:
242569587Sgreen		error("deny_input_open: type %d plen %d", type, plen);
242669587Sgreen		break;
242769587Sgreen	}
242869587Sgreen	error("Warning: this is probably a break in attempt by a malicious server.");
242969587Sgreen	packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
243069587Sgreen	packet_put_int(rchan);
243169587Sgreen	packet_send();
243269587Sgreen}
243369587Sgreen
243457429Smarkm/*
243557429Smarkm * Requests forwarding of X11 connections, generates fake authentication
243657429Smarkm * data, and enables authentication spoofing.
243757429Smarkm */
243857429Smarkm
243960573Skrisvoid
244060573Skrisx11_request_forwarding_with_spoofing(int client_session_id,
244160573Skris    const char *proto, const char *data)
244257429Smarkm{
244376262Sgreen	u_int data_len = (u_int) strlen(data) / 2;
244476262Sgreen	u_int i, value, len;
244557429Smarkm	char *new_data;
244657429Smarkm	int screen_number;
244757429Smarkm	const char *cp;
244857429Smarkm	u_int32_t rand = 0;
244957429Smarkm
245057429Smarkm	cp = getenv("DISPLAY");
245157429Smarkm	if (cp)
245257429Smarkm		cp = strchr(cp, ':');
245357429Smarkm	if (cp)
245457429Smarkm		cp = strchr(cp, '.');
245557429Smarkm	if (cp)
245657429Smarkm		screen_number = atoi(cp + 1);
245757429Smarkm	else
245857429Smarkm		screen_number = 0;
245957429Smarkm
246057429Smarkm	/* Save protocol name. */
246157429Smarkm	x11_saved_proto = xstrdup(proto);
246257429Smarkm
246357429Smarkm	/*
246457429Smarkm	 * Extract real authentication data and generate fake data of the
246557429Smarkm	 * same length.
246657429Smarkm	 */
246757429Smarkm	x11_saved_data = xmalloc(data_len);
246857429Smarkm	x11_fake_data = xmalloc(data_len);
246957429Smarkm	for (i = 0; i < data_len; i++) {
247057429Smarkm		if (sscanf(data + 2 * i, "%2x", &value) != 1)
247157429Smarkm			fatal("x11_request_forwarding: bad authentication data: %.100s", data);
247257429Smarkm		if (i % 4 == 0)
247357429Smarkm			rand = arc4random();
247457429Smarkm		x11_saved_data[i] = value;
247557429Smarkm		x11_fake_data[i] = rand & 0xff;
247657429Smarkm		rand >>= 8;
247757429Smarkm	}
247857429Smarkm	x11_saved_data_len = data_len;
247957429Smarkm	x11_fake_data_len = data_len;
248057429Smarkm
248157429Smarkm	/* Convert the fake data into hex. */
248276262Sgreen	len = 2 * data_len + 1;
248376262Sgreen	new_data = xmalloc(len);
248457429Smarkm	for (i = 0; i < data_len; i++)
248576262Sgreen		snprintf(new_data + 2 * i, len - 2 * i,
248676262Sgreen		    "%02x", (u_char) x11_fake_data[i]);
248757429Smarkm
248857429Smarkm	/* Send the request packet. */
248960573Skris	if (compat20) {
249060573Skris		channel_request_start(client_session_id, "x11-req", 0);
249160573Skris		packet_put_char(0);	/* XXX bool single connection */
249260573Skris	} else {
249360573Skris		packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
249460573Skris	}
249560573Skris	packet_put_cstring(proto);
249660573Skris	packet_put_cstring(new_data);
249757429Smarkm	packet_put_int(screen_number);
249857429Smarkm	packet_send();
249957429Smarkm	packet_write_wait();
250057429Smarkm	xfree(new_data);
250157429Smarkm}
250257429Smarkm
250357429Smarkm/* Sends a message to the server to request authentication fd forwarding. */
250457429Smarkm
250560573Skrisvoid
250657429Smarkmauth_request_forwarding()
250757429Smarkm{
250857429Smarkm	packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
250957429Smarkm	packet_send();
251057429Smarkm	packet_write_wait();
251157429Smarkm}
251257429Smarkm
251357429Smarkm/*
251457429Smarkm * Returns the name of the forwarded authentication socket.  Returns NULL if
251557429Smarkm * there is no forwarded authentication socket.  The returned value points to
251657429Smarkm * a static buffer.
251757429Smarkm */
251857429Smarkm
251957429Smarkmchar *
252057429Smarkmauth_get_socket_name()
252157429Smarkm{
252257429Smarkm	return channel_forwarded_auth_socket_name;
252357429Smarkm}
252457429Smarkm
252557429Smarkm/* removes the agent forwarding socket */
252657429Smarkm
252760573Skrisvoid
252877925Sgreenauth_sock_cleanup_proc(void *_pw)
252957429Smarkm{
253077925Sgreen	struct passwd *pw = _pw;
253177925Sgreen
253277925Sgreen	if (channel_forwarded_auth_socket_name) {
253377925Sgreen		temporarily_use_uid(pw);
253477925Sgreen		unlink(channel_forwarded_auth_socket_name);
253577925Sgreen		rmdir(channel_forwarded_auth_socket_dir);
253677925Sgreen		channel_forwarded_auth_socket_name = NULL;
253777925Sgreen		restore_uid();
253877925Sgreen	}
253957429Smarkm}
254057429Smarkm
254157429Smarkm/*
254261199Skris * This is called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
254357429Smarkm * This starts forwarding authentication requests.
254457429Smarkm */
254557429Smarkm
254661199Skrisint
254757429Smarkmauth_input_request_forwarding(struct passwd * pw)
254857429Smarkm{
254957429Smarkm	int sock, newch;
255057429Smarkm	struct sockaddr_un sunaddr;
255157429Smarkm
255257429Smarkm	if (auth_get_socket_name() != NULL)
255357429Smarkm		fatal("Protocol error: authentication forwarding requested twice.");
255457429Smarkm
255557429Smarkm	/* Temporarily drop privileged uid for mkdir/bind. */
255676262Sgreen	temporarily_use_uid(pw);
255757429Smarkm
255857429Smarkm	/* Allocate a buffer for the socket name, and format the name. */
255957429Smarkm	channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME);
256057429Smarkm	channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME);
256157429Smarkm	strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME);
256257429Smarkm
256357429Smarkm	/* Create private directory for socket */
256461199Skris	if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) {
256561199Skris		packet_send_debug("Agent forwarding disabled: mkdtemp() failed: %.100s",
256661199Skris		    strerror(errno));
256761199Skris		restore_uid();
256861199Skris		xfree(channel_forwarded_auth_socket_name);
256961199Skris		xfree(channel_forwarded_auth_socket_dir);
257061199Skris		channel_forwarded_auth_socket_name = NULL;
257161199Skris		channel_forwarded_auth_socket_dir = NULL;
257261199Skris		return 0;
257361199Skris	}
257457429Smarkm	snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d",
257557429Smarkm		 channel_forwarded_auth_socket_dir, (int) getpid());
257657429Smarkm
257777925Sgreen	/* delete agent socket on fatal() */
257877925Sgreen	fatal_add_cleanup(auth_sock_cleanup_proc, pw);
257977925Sgreen
258057429Smarkm	/* Create the socket. */
258157429Smarkm	sock = socket(AF_UNIX, SOCK_STREAM, 0);
258257429Smarkm	if (sock < 0)
258357429Smarkm		packet_disconnect("socket: %.100s", strerror(errno));
258457429Smarkm
258557429Smarkm	/* Bind it to the name. */
258657429Smarkm	memset(&sunaddr, 0, sizeof(sunaddr));
258757429Smarkm	sunaddr.sun_family = AF_UNIX;
258857429Smarkm	strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name,
258957429Smarkm		sizeof(sunaddr.sun_path));
259057429Smarkm
259157429Smarkm	if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
259257429Smarkm		packet_disconnect("bind: %.100s", strerror(errno));
259357429Smarkm
259457429Smarkm	/* Restore the privileged uid. */
259557429Smarkm	restore_uid();
259657429Smarkm
259757429Smarkm	/* Start listening on the socket. */
259857429Smarkm	if (listen(sock, 5) < 0)
259957429Smarkm		packet_disconnect("listen: %.100s", strerror(errno));
260057429Smarkm
260157429Smarkm	/* Allocate a channel for the authentication agent socket. */
260276262Sgreen	newch = channel_new("auth socket",
260376262Sgreen	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
260476262Sgreen	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
260576262Sgreen	    0, xstrdup("auth socket"), 1);
260676262Sgreen
260757429Smarkm	strlcpy(channels[newch].path, channel_forwarded_auth_socket_name,
260857429Smarkm	    sizeof(channels[newch].path));
260961199Skris	return 1;
261057429Smarkm}
261157429Smarkm
261257429Smarkm/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
261357429Smarkm
261460573Skrisvoid
261569587Sgreenauth_input_open_request(int type, int plen, void *ctxt)
261657429Smarkm{
261757429Smarkm	int remch, sock, newch;
261857429Smarkm	char *dummyname;
261957429Smarkm
262060573Skris	packet_integrity_check(plen, 4, type);
262160573Skris
262257429Smarkm	/* Read the remote channel number from the message. */
262357429Smarkm	remch = packet_get_int();
262457429Smarkm
262557429Smarkm	/*
262657429Smarkm	 * Get a connection to the local authentication agent (this may again
262757429Smarkm	 * get forwarded).
262857429Smarkm	 */
262957429Smarkm	sock = ssh_get_authentication_socket();
263057429Smarkm
263157429Smarkm	/*
263257429Smarkm	 * If we could not connect the agent, send an error message back to
263357429Smarkm	 * the server. This should never happen unless the agent dies,
263457429Smarkm	 * because authentication forwarding is only enabled if we have an
263557429Smarkm	 * agent.
263657429Smarkm	 */
263757429Smarkm	if (sock < 0) {
263857429Smarkm		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
263957429Smarkm		packet_put_int(remch);
264057429Smarkm		packet_send();
264157429Smarkm		return;
264257429Smarkm	}
264357429Smarkm	debug("Forwarding authentication connection.");
264457429Smarkm
264557429Smarkm	/*
264657429Smarkm	 * Dummy host name.  This will be freed when the channel is freed; it
264757429Smarkm	 * will still be valid in the packet_put_string below since the
264857429Smarkm	 * channel cannot yet be freed at that point.
264957429Smarkm	 */
265057429Smarkm	dummyname = xstrdup("authentication agent connection");
265157429Smarkm
265257429Smarkm	newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
265357429Smarkm	channels[newch].remote_id = remch;
265457429Smarkm
265557429Smarkm	/* Send a confirmation to the remote host. */
265657429Smarkm	packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
265757429Smarkm	packet_put_int(remch);
265857429Smarkm	packet_put_int(newch);
265957429Smarkm	packet_send();
266057429Smarkm}
266160573Skris
266260573Skrisvoid
266360573Skrischannel_start_open(int id)
266460573Skris{
266560573Skris	Channel *c = channel_lookup(id);
266660573Skris	if (c == NULL) {
266760573Skris		log("channel_open: %d: bad id", id);
266860573Skris		return;
266960573Skris	}
267060573Skris	debug("send channel open %d", id);
267160573Skris	packet_start(SSH2_MSG_CHANNEL_OPEN);
267260573Skris	packet_put_cstring(c->ctype);
267360573Skris	packet_put_int(c->self);
267460573Skris	packet_put_int(c->local_window);
267560573Skris	packet_put_int(c->local_maxpacket);
267660573Skris}
267760573Skrisvoid
267860573Skrischannel_open(int id)
267960573Skris{
268060573Skris	/* XXX REMOVE ME */
268160573Skris	channel_start_open(id);
268260573Skris	packet_send();
268360573Skris}
268460573Skrisvoid
268560573Skrischannel_request(int id, char *service, int wantconfirm)
268660573Skris{
268760573Skris	channel_request_start(id, service, wantconfirm);
268860573Skris	packet_send();
268960573Skris	debug("channel request %d: %s", id, service) ;
269060573Skris}
269160573Skrisvoid
269260573Skrischannel_request_start(int id, char *service, int wantconfirm)
269360573Skris{
269460573Skris	Channel *c = channel_lookup(id);
269560573Skris	if (c == NULL) {
269660573Skris		log("channel_request: %d: bad id", id);
269760573Skris		return;
269860573Skris	}
269960573Skris	packet_start(SSH2_MSG_CHANNEL_REQUEST);
270060573Skris	packet_put_int(c->remote_id);
270160573Skris	packet_put_cstring(service);
270260573Skris	packet_put_char(wantconfirm);
270360573Skris}
270460573Skrisvoid
270560573Skrischannel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
270660573Skris{
270760573Skris	Channel *c = channel_lookup(id);
270860573Skris	if (c == NULL) {
270960573Skris		log("channel_register_callback: %d: bad id", id);
271060573Skris		return;
271160573Skris	}
271260573Skris	c->cb_event = mtype;
271360573Skris	c->cb_fn = fn;
271460573Skris	c->cb_arg = arg;
271560573Skris}
271660573Skrisvoid
271760573Skrischannel_register_cleanup(int id, channel_callback_fn *fn)
271860573Skris{
271960573Skris	Channel *c = channel_lookup(id);
272060573Skris	if (c == NULL) {
272160573Skris		log("channel_register_cleanup: %d: bad id", id);
272260573Skris		return;
272360573Skris	}
272460573Skris	c->dettach_user = fn;
272560573Skris}
272660573Skrisvoid
272760573Skrischannel_cancel_cleanup(int id)
272860573Skris{
272960573Skris	Channel *c = channel_lookup(id);
273060573Skris	if (c == NULL) {
273160573Skris		log("channel_cancel_cleanup: %d: bad id", id);
273260573Skris		return;
273360573Skris	}
273460573Skris	c->dettach_user = NULL;
273560573Skris}
273676262Sgreenvoid
273765668Skrischannel_register_filter(int id, channel_filter_fn *fn)
273865668Skris{
273965668Skris	Channel *c = channel_lookup(id);
274065668Skris	if (c == NULL) {
274165668Skris		log("channel_register_filter: %d: bad id", id);
274265668Skris		return;
274365668Skris	}
274465668Skris	c->input_filter = fn;
274565668Skris}
274660573Skris
274760573Skrisvoid
274869587Sgreenchannel_set_fds(int id, int rfd, int wfd, int efd,
274969587Sgreen    int extusage, int nonblock)
275060573Skris{
275160573Skris	Channel *c = channel_lookup(id);
275260573Skris	if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
275360573Skris		fatal("channel_activate for non-larval channel %d.", id);
275469587Sgreen	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
275560573Skris	c->type = SSH_CHANNEL_OPEN;
275660573Skris	/* XXX window size? */
275765668Skris	c->local_window = c->local_window_max = c->local_maxpacket * 2;
275860573Skris	packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
275960573Skris	packet_put_int(c->remote_id);
276060573Skris	packet_put_int(c->local_window);
276160573Skris	packet_send();
276260573Skris}
2763