channels.c revision 181111
1181111Sdes/* $OpenBSD: channels.c,v 1.286 2008/07/16 11:52:19 djm Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * This file contains functions for generic socket connection forwarding.
757429Smarkm * There is also code for initiating connection forwarding for X11 connections,
857429Smarkm * arbitrary tcp/ip connections, and the authentication agent connection.
960573Skris *
1065668Skris * As far as I am concerned, the code I have written for this software
1165668Skris * can be used freely for any purpose.  Any derived versions of this
1265668Skris * software must be clearly marked as such, and if the derived work is
1365668Skris * incompatible with the protocol description in the RFC file, it must be
1465668Skris * called by a name other than "ssh" or "Secure Shell".
1565668Skris *
1660573Skris * SSH2 support added by Markus Friedl.
1792559Sdes * Copyright (c) 1999, 2000, 2001, 2002 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"
4357429Smarkm
44162856Sdes#include <sys/types.h>
45162856Sdes#include <sys/ioctl.h>
46162856Sdes#include <sys/un.h>
47162856Sdes#include <sys/socket.h>
48162856Sdes#ifdef HAVE_SYS_TIME_H
49162856Sdes# include <sys/time.h>
50162856Sdes#endif
51162856Sdes
52162856Sdes#include <netinet/in.h>
53162856Sdes#include <arpa/inet.h>
54162856Sdes
55162856Sdes#include <errno.h>
56162856Sdes#include <netdb.h>
57162856Sdes#include <stdio.h>
58162856Sdes#include <stdlib.h>
59162856Sdes#include <string.h>
60162856Sdes#include <termios.h>
61162856Sdes#include <unistd.h>
62162856Sdes#include <stdarg.h>
63162856Sdes
64181111Sdes#include "openbsd-compat/sys-queue.h"
65162856Sdes#include "xmalloc.h"
6657429Smarkm#include "ssh.h"
6776262Sgreen#include "ssh1.h"
6876262Sgreen#include "ssh2.h"
6957429Smarkm#include "packet.h"
7076262Sgreen#include "log.h"
7176262Sgreen#include "misc.h"
72162856Sdes#include "buffer.h"
7357429Smarkm#include "channels.h"
7457429Smarkm#include "compat.h"
7576262Sgreen#include "canohost.h"
7665668Skris#include "key.h"
7765668Skris#include "authfd.h"
7892559Sdes#include "pathnames.h"
7965668Skris
8092559Sdes/* -- channel core */
8157429Smarkm
8257429Smarkm/*
8357429Smarkm * Pointer to an array containing all allocated channels.  The array is
8457429Smarkm * dynamically extended as needed.
8557429Smarkm */
8692559Sdesstatic Channel **channels = NULL;
8757429Smarkm
8857429Smarkm/*
8957429Smarkm * Size of the channel array.  All slots of the array must always be
9092559Sdes * initialized (at least the type field); unused slots set to NULL
9157429Smarkm */
92137019Sdesstatic u_int channels_alloc = 0;
9357429Smarkm
9457429Smarkm/*
9557429Smarkm * Maximum file descriptor value used in any of the channels.  This is
9692559Sdes * updated in channel_new.
9757429Smarkm */
9876262Sgreenstatic int channel_max_fd = 0;
9957429Smarkm
10057429Smarkm
10192559Sdes/* -- tcp forwarding */
10257429Smarkm
10357429Smarkm/*
10457429Smarkm * Data structure for storing which hosts are permitted for forward requests.
10557429Smarkm * The local sides of any remote forwards are stored in this array to prevent
10657429Smarkm * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
10757429Smarkm * network (which might be behind a firewall).
10857429Smarkm */
10957429Smarkmtypedef struct {
11060573Skris	char *host_to_connect;		/* Connect to 'host'. */
11160573Skris	u_short port_to_connect;	/* Connect to 'port'. */
11260573Skris	u_short listen_port;		/* Remote side should listen port number. */
11357429Smarkm} ForwardPermission;
11457429Smarkm
115162856Sdes/* List of all permitted host/port pairs to connect by the user. */
11657429Smarkmstatic ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
11792559Sdes
118162856Sdes/* List of all permitted host/port pairs to connect by the admin. */
119162856Sdesstatic ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
120162856Sdes
121162856Sdes/* Number of permitted host/port pairs in the array permitted by the user. */
12257429Smarkmstatic int num_permitted_opens = 0;
123162856Sdes
124162856Sdes/* Number of permitted host/port pair in the array permitted by the admin. */
125162856Sdesstatic int num_adm_permitted_opens = 0;
126162856Sdes
12757429Smarkm/*
12857429Smarkm * If this is true, all opens are permitted.  This is the case on the server
12957429Smarkm * on which we have to trust the client anyway, and the user could do
13057429Smarkm * anything after logging in anyway.
13157429Smarkm */
13257429Smarkmstatic int all_opens_permitted = 0;
13357429Smarkm
13457429Smarkm
13592559Sdes/* -- X11 forwarding */
13692559Sdes
13792559Sdes/* Maximum number of fake X11 displays to try. */
13892559Sdes#define MAX_DISPLAYS  1000
13992559Sdes
140149753Sdes/* Saved X11 local (client) display. */
141149753Sdesstatic char *x11_saved_display = NULL;
142149753Sdes
14392559Sdes/* Saved X11 authentication protocol name. */
14492559Sdesstatic char *x11_saved_proto = NULL;
14592559Sdes
14692559Sdes/* Saved X11 authentication data.  This is the real data. */
14792559Sdesstatic char *x11_saved_data = NULL;
14892559Sdesstatic u_int x11_saved_data_len = 0;
14992559Sdes
15092559Sdes/*
15192559Sdes * Fake X11 authentication data.  This is what the server will be sending us;
15292559Sdes * we should replace any occurrences of this by the real data.
15392559Sdes */
154162856Sdesstatic u_char *x11_fake_data = NULL;
15592559Sdesstatic u_int x11_fake_data_len;
15692559Sdes
15792559Sdes
15892559Sdes/* -- agent forwarding */
15992559Sdes
16092559Sdes#define	NUM_SOCKS	10
16192559Sdes
16276262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */
16398941Sdesstatic int IPv4or6 = AF_UNSPEC;
16476262Sgreen
16592559Sdes/* helper */
16692559Sdesstatic void port_open_helper(Channel *c, char *rtype);
16776262Sgreen
168181111Sdes/* non-blocking connect helpers */
169181111Sdesstatic int connect_next(struct channel_connect *);
170181111Sdesstatic void channel_connect_ctx_free(struct channel_connect *);
171181111Sdes
17292559Sdes/* -- channel core */
17357429Smarkm
17460573SkrisChannel *
175157019Sdeschannel_by_id(int id)
17660573Skris{
17760573Skris	Channel *c;
17892559Sdes
179137019Sdes	if (id < 0 || (u_int)id >= channels_alloc) {
180157019Sdes		logit("channel_by_id: %d: bad id", id);
18160573Skris		return NULL;
18260573Skris	}
18392559Sdes	c = channels[id];
18492559Sdes	if (c == NULL) {
185157019Sdes		logit("channel_by_id: %d: bad id: channel free", id);
18660573Skris		return NULL;
18760573Skris	}
18860573Skris	return c;
18960573Skris}
19060573Skris
19157429Smarkm/*
192157019Sdes * Returns the channel if it is allowed to receive protocol messages.
193157019Sdes * Private channels, like listening sockets, may not receive messages.
194157019Sdes */
195157019SdesChannel *
196157019Sdeschannel_lookup(int id)
197157019Sdes{
198157019Sdes	Channel *c;
199157019Sdes
200157019Sdes	if ((c = channel_by_id(id)) == NULL)
201157019Sdes		return (NULL);
202157019Sdes
203162856Sdes	switch (c->type) {
204157019Sdes	case SSH_CHANNEL_X11_OPEN:
205157019Sdes	case SSH_CHANNEL_LARVAL:
206157019Sdes	case SSH_CHANNEL_CONNECTING:
207157019Sdes	case SSH_CHANNEL_DYNAMIC:
208157019Sdes	case SSH_CHANNEL_OPENING:
209157019Sdes	case SSH_CHANNEL_OPEN:
210157019Sdes	case SSH_CHANNEL_INPUT_DRAINING:
211157019Sdes	case SSH_CHANNEL_OUTPUT_DRAINING:
212157019Sdes		return (c);
213157019Sdes	}
214157019Sdes	logit("Non-public channel %d, type %d.", id, c->type);
215157019Sdes	return (NULL);
216157019Sdes}
217157019Sdes
218157019Sdes/*
21960573Skris * Register filedescriptors for a channel, used when allocating a channel or
22060573Skris * when the channel consumer/producer is ready, e.g. shell exec'd
22160573Skris */
22292559Sdesstatic void
22369587Sgreenchannel_register_fds(Channel *c, int rfd, int wfd, int efd,
224181111Sdes    int extusage, int nonblock, int is_tty)
22560573Skris{
22660573Skris	/* Update the maximum file descriptor value. */
22776262Sgreen	channel_max_fd = MAX(channel_max_fd, rfd);
22876262Sgreen	channel_max_fd = MAX(channel_max_fd, wfd);
22976262Sgreen	channel_max_fd = MAX(channel_max_fd, efd);
23076262Sgreen
23160573Skris	/* XXX set close-on-exec -markus */
23260573Skris
23360573Skris	c->rfd = rfd;
23460573Skris	c->wfd = wfd;
23560573Skris	c->sock = (rfd == wfd) ? rfd : -1;
236137019Sdes	c->ctl_fd = -1; /* XXX: set elsewhere */
23760573Skris	c->efd = efd;
23860573Skris	c->extended_usage = extusage;
23969587Sgreen
240181111Sdes	if ((c->isatty = is_tty) != 0)
241124207Sdes		debug2("channel %d: rfd %d isatty", c->self, c->rfd);
242181111Sdes	c->wfd_isatty = is_tty || isatty(c->wfd);
24374500Sgreen
24469587Sgreen	/* enable nonblocking mode */
24569587Sgreen	if (nonblock) {
24669587Sgreen		if (rfd != -1)
24769587Sgreen			set_nonblock(rfd);
24869587Sgreen		if (wfd != -1)
24969587Sgreen			set_nonblock(wfd);
25069587Sgreen		if (efd != -1)
25169587Sgreen			set_nonblock(efd);
25269587Sgreen	}
25360573Skris}
25460573Skris
25560573Skris/*
25657429Smarkm * Allocate a new channel object and set its type and socket. This will cause
25757429Smarkm * remote_name to be freed.
25857429Smarkm */
25992559SdesChannel *
26060573Skrischannel_new(char *ctype, int type, int rfd, int wfd, int efd,
26199063Sdes    u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
26257429Smarkm{
263137019Sdes	int found;
264137019Sdes	u_int i;
26557429Smarkm	Channel *c;
26657429Smarkm
26757429Smarkm	/* Do initial allocation if this is the first call. */
26857429Smarkm	if (channels_alloc == 0) {
26957429Smarkm		channels_alloc = 10;
270162856Sdes		channels = xcalloc(channels_alloc, sizeof(Channel *));
27157429Smarkm		for (i = 0; i < channels_alloc; i++)
27292559Sdes			channels[i] = NULL;
27357429Smarkm	}
27457429Smarkm	/* Try to find a free slot where to put the new channel. */
27557429Smarkm	for (found = -1, i = 0; i < channels_alloc; i++)
27692559Sdes		if (channels[i] == NULL) {
27757429Smarkm			/* Found a free slot. */
278137019Sdes			found = (int)i;
27957429Smarkm			break;
28057429Smarkm		}
281137019Sdes	if (found < 0) {
28257429Smarkm		/* There are no free slots.  Take last+1 slot and expand the array.  */
28357429Smarkm		found = channels_alloc;
28499063Sdes		if (channels_alloc > 10000)
28599063Sdes			fatal("channel_new: internal error: channels_alloc %d "
28699063Sdes			    "too big.", channels_alloc);
287162856Sdes		channels = xrealloc(channels, channels_alloc + 10,
288162856Sdes		    sizeof(Channel *));
289120489Sjoe		channels_alloc += 10;
29069587Sgreen		debug2("channel: expanding %d", channels_alloc);
29157429Smarkm		for (i = found; i < channels_alloc; i++)
29292559Sdes			channels[i] = NULL;
29357429Smarkm	}
29492559Sdes	/* Initialize and return new channel. */
295162856Sdes	c = channels[found] = xcalloc(1, sizeof(Channel));
29657429Smarkm	buffer_init(&c->input);
29757429Smarkm	buffer_init(&c->output);
29860573Skris	buffer_init(&c->extended);
29992559Sdes	c->ostate = CHAN_OUTPUT_OPEN;
30092559Sdes	c->istate = CHAN_INPUT_OPEN;
30192559Sdes	c->flags = 0;
302181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
30357429Smarkm	c->self = found;
30457429Smarkm	c->type = type;
30560573Skris	c->ctype = ctype;
30660573Skris	c->local_window = window;
30760573Skris	c->local_window_max = window;
30860573Skris	c->local_consumed = 0;
30960573Skris	c->local_maxpacket = maxpack;
31057429Smarkm	c->remote_id = -1;
311124207Sdes	c->remote_name = xstrdup(remote_name);
31260573Skris	c->remote_window = 0;
31360573Skris	c->remote_maxpacket = 0;
31492559Sdes	c->force_drain = 0;
31592559Sdes	c->single_connection = 0;
31692559Sdes	c->detach_user = NULL;
317157019Sdes	c->detach_close = 0;
318181111Sdes	c->open_confirm = NULL;
319181111Sdes	c->open_confirm_ctx = NULL;
32065668Skris	c->input_filter = NULL;
321157019Sdes	c->output_filter = NULL;
322181111Sdes	c->filter_ctx = NULL;
323181111Sdes	c->filter_cleanup = NULL;
324181111Sdes	TAILQ_INIT(&c->status_confirms);
32557429Smarkm	debug("channel %d: new [%s]", found, remote_name);
32692559Sdes	return c;
32757429Smarkm}
32892559Sdes
32992559Sdesstatic int
33092559Sdeschannel_find_maxfd(void)
33192559Sdes{
332137019Sdes	u_int i;
333137019Sdes	int max = 0;
33492559Sdes	Channel *c;
33592559Sdes
33692559Sdes	for (i = 0; i < channels_alloc; i++) {
33792559Sdes		c = channels[i];
33892559Sdes		if (c != NULL) {
33992559Sdes			max = MAX(max, c->rfd);
34092559Sdes			max = MAX(max, c->wfd);
34192559Sdes			max = MAX(max, c->efd);
34292559Sdes		}
34392559Sdes	}
34492559Sdes	return max;
34592559Sdes}
34692559Sdes
34760573Skrisint
34892559Sdeschannel_close_fd(int *fdp)
34960573Skris{
35092559Sdes	int ret = 0, fd = *fdp;
35192559Sdes
35292559Sdes	if (fd != -1) {
35392559Sdes		ret = close(fd);
35492559Sdes		*fdp = -1;
35592559Sdes		if (fd == channel_max_fd)
35692559Sdes			channel_max_fd = channel_find_maxfd();
35792559Sdes	}
35892559Sdes	return ret;
35960573Skris}
36057429Smarkm
36160573Skris/* Close all channel fd/socket. */
36292559Sdesstatic void
36360573Skrischannel_close_fds(Channel *c)
36457429Smarkm{
365137019Sdes	debug3("channel %d: close_fds r %d w %d e %d c %d",
366137019Sdes	    c->self, c->rfd, c->wfd, c->efd, c->ctl_fd);
36792559Sdes
36892559Sdes	channel_close_fd(&c->sock);
369137019Sdes	channel_close_fd(&c->ctl_fd);
37092559Sdes	channel_close_fd(&c->rfd);
37192559Sdes	channel_close_fd(&c->wfd);
37292559Sdes	channel_close_fd(&c->efd);
37360573Skris}
37457429Smarkm
37560573Skris/* Free the channel and close its fd/socket. */
37660573Skrisvoid
37792559Sdeschannel_free(Channel *c)
37860573Skris{
37992559Sdes	char *s;
380137019Sdes	u_int i, n;
381181111Sdes	struct channel_confirm *cc;
38276262Sgreen
38392559Sdes	for (n = 0, i = 0; i < channels_alloc; i++)
38492559Sdes		if (channels[i])
38592559Sdes			n++;
386137019Sdes	debug("channel %d: free: %s, nchannels %u", c->self,
38792559Sdes	    c->remote_name ? c->remote_name : "???", n);
38892559Sdes
38992559Sdes	s = channel_open_message();
390124207Sdes	debug3("channel %d: status: %s", c->self, s);
39176262Sgreen	xfree(s);
39276262Sgreen
39360573Skris	if (c->sock != -1)
39460573Skris		shutdown(c->sock, SHUT_RDWR);
395137019Sdes	if (c->ctl_fd != -1)
396137019Sdes		shutdown(c->ctl_fd, SHUT_RDWR);
39760573Skris	channel_close_fds(c);
39860573Skris	buffer_free(&c->input);
39960573Skris	buffer_free(&c->output);
40060573Skris	buffer_free(&c->extended);
40160573Skris	if (c->remote_name) {
40260573Skris		xfree(c->remote_name);
40360573Skris		c->remote_name = NULL;
40460573Skris	}
405181111Sdes	while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
406181111Sdes		if (cc->abandon_cb != NULL)
407181111Sdes			cc->abandon_cb(c, cc->ctx);
408181111Sdes		TAILQ_REMOVE(&c->status_confirms, cc, entry);
409181111Sdes		bzero(cc, sizeof(*cc));
410181111Sdes		xfree(cc);
411181111Sdes	}
412181111Sdes	if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
413181111Sdes		c->filter_cleanup(c->self, c->filter_ctx);
41492559Sdes	channels[c->self] = NULL;
41592559Sdes	xfree(c);
41657429Smarkm}
41757429Smarkm
41892559Sdesvoid
41992559Sdeschannel_free_all(void)
42092559Sdes{
421137019Sdes	u_int i;
42292559Sdes
42392559Sdes	for (i = 0; i < channels_alloc; i++)
42492559Sdes		if (channels[i] != NULL)
42592559Sdes			channel_free(channels[i]);
42692559Sdes}
42792559Sdes
42857429Smarkm/*
42992559Sdes * Closes the sockets/fds of all channels.  This is used to close extra file
43092559Sdes * descriptors after a fork.
43192559Sdes */
43292559Sdesvoid
43392559Sdeschannel_close_all(void)
43492559Sdes{
435137019Sdes	u_int i;
43692559Sdes
43792559Sdes	for (i = 0; i < channels_alloc; i++)
43892559Sdes		if (channels[i] != NULL)
43992559Sdes			channel_close_fds(channels[i]);
44092559Sdes}
44192559Sdes
44292559Sdes/*
44392559Sdes * Stop listening to channels.
44492559Sdes */
44592559Sdesvoid
44692559Sdeschannel_stop_listening(void)
44792559Sdes{
448137019Sdes	u_int i;
44992559Sdes	Channel *c;
45092559Sdes
45192559Sdes	for (i = 0; i < channels_alloc; i++) {
45292559Sdes		c = channels[i];
45392559Sdes		if (c != NULL) {
45492559Sdes			switch (c->type) {
45592559Sdes			case SSH_CHANNEL_AUTH_SOCKET:
45692559Sdes			case SSH_CHANNEL_PORT_LISTENER:
45792559Sdes			case SSH_CHANNEL_RPORT_LISTENER:
45892559Sdes			case SSH_CHANNEL_X11_LISTENER:
45992559Sdes				channel_close_fd(&c->sock);
46092559Sdes				channel_free(c);
46192559Sdes				break;
46292559Sdes			}
46392559Sdes		}
46492559Sdes	}
46592559Sdes}
46692559Sdes
46792559Sdes/*
46892559Sdes * Returns true if no channel has too much buffered data, and false if one or
46992559Sdes * more channel is overfull.
47092559Sdes */
47192559Sdesint
47292559Sdeschannel_not_very_much_buffered_data(void)
47392559Sdes{
47492559Sdes	u_int i;
47592559Sdes	Channel *c;
47692559Sdes
47792559Sdes	for (i = 0; i < channels_alloc; i++) {
47892559Sdes		c = channels[i];
47992559Sdes		if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
48092559Sdes#if 0
48192559Sdes			if (!compat20 &&
48292559Sdes			    buffer_len(&c->input) > packet_get_maxsize()) {
483113911Sdes				debug2("channel %d: big input buffer %d",
48492559Sdes				    c->self, buffer_len(&c->input));
48592559Sdes				return 0;
48692559Sdes			}
48792559Sdes#endif
48892559Sdes			if (buffer_len(&c->output) > packet_get_maxsize()) {
489124207Sdes				debug2("channel %d: big output buffer %u > %u",
49092559Sdes				    c->self, buffer_len(&c->output),
49192559Sdes				    packet_get_maxsize());
49292559Sdes				return 0;
49392559Sdes			}
49492559Sdes		}
49592559Sdes	}
49692559Sdes	return 1;
49792559Sdes}
49892559Sdes
49992559Sdes/* Returns true if any channel is still open. */
50092559Sdesint
50192559Sdeschannel_still_open(void)
50292559Sdes{
503137019Sdes	u_int i;
50492559Sdes	Channel *c;
50592559Sdes
50692559Sdes	for (i = 0; i < channels_alloc; i++) {
50792559Sdes		c = channels[i];
50892559Sdes		if (c == NULL)
50992559Sdes			continue;
51092559Sdes		switch (c->type) {
51192559Sdes		case SSH_CHANNEL_X11_LISTENER:
51292559Sdes		case SSH_CHANNEL_PORT_LISTENER:
51392559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
51492559Sdes		case SSH_CHANNEL_CLOSED:
51592559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
51692559Sdes		case SSH_CHANNEL_DYNAMIC:
51792559Sdes		case SSH_CHANNEL_CONNECTING:
51892559Sdes		case SSH_CHANNEL_ZOMBIE:
51992559Sdes			continue;
52092559Sdes		case SSH_CHANNEL_LARVAL:
52192559Sdes			if (!compat20)
52292559Sdes				fatal("cannot happen: SSH_CHANNEL_LARVAL");
52392559Sdes			continue;
52492559Sdes		case SSH_CHANNEL_OPENING:
52592559Sdes		case SSH_CHANNEL_OPEN:
52692559Sdes		case SSH_CHANNEL_X11_OPEN:
52792559Sdes			return 1;
52892559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
52992559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
53092559Sdes			if (!compat13)
53192559Sdes				fatal("cannot happen: OUT_DRAIN");
53292559Sdes			return 1;
53392559Sdes		default:
53492559Sdes			fatal("channel_still_open: bad channel type %d", c->type);
53592559Sdes			/* NOTREACHED */
53692559Sdes		}
53792559Sdes	}
53892559Sdes	return 0;
53992559Sdes}
54092559Sdes
54192559Sdes/* Returns the id of an open channel suitable for keepaliving */
54292559Sdesint
54392559Sdeschannel_find_open(void)
54492559Sdes{
545137019Sdes	u_int i;
54692559Sdes	Channel *c;
54792559Sdes
54892559Sdes	for (i = 0; i < channels_alloc; i++) {
54992559Sdes		c = channels[i];
550137019Sdes		if (c == NULL || c->remote_id < 0)
55192559Sdes			continue;
55292559Sdes		switch (c->type) {
55392559Sdes		case SSH_CHANNEL_CLOSED:
55492559Sdes		case SSH_CHANNEL_DYNAMIC:
55592559Sdes		case SSH_CHANNEL_X11_LISTENER:
55692559Sdes		case SSH_CHANNEL_PORT_LISTENER:
55792559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
55892559Sdes		case SSH_CHANNEL_OPENING:
55992559Sdes		case SSH_CHANNEL_CONNECTING:
56092559Sdes		case SSH_CHANNEL_ZOMBIE:
56192559Sdes			continue;
56292559Sdes		case SSH_CHANNEL_LARVAL:
56392559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
56492559Sdes		case SSH_CHANNEL_OPEN:
56592559Sdes		case SSH_CHANNEL_X11_OPEN:
56692559Sdes			return i;
56792559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
56892559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
56992559Sdes			if (!compat13)
57092559Sdes				fatal("cannot happen: OUT_DRAIN");
57192559Sdes			return i;
57292559Sdes		default:
57392559Sdes			fatal("channel_find_open: bad channel type %d", c->type);
57492559Sdes			/* NOTREACHED */
57592559Sdes		}
57692559Sdes	}
57792559Sdes	return -1;
57892559Sdes}
57992559Sdes
58092559Sdes
58192559Sdes/*
58292559Sdes * Returns a message describing the currently open forwarded connections,
58392559Sdes * suitable for sending to the client.  The message contains crlf pairs for
58492559Sdes * newlines.
58592559Sdes */
58692559Sdeschar *
58792559Sdeschannel_open_message(void)
58892559Sdes{
58992559Sdes	Buffer buffer;
59092559Sdes	Channel *c;
59192559Sdes	char buf[1024], *cp;
592137019Sdes	u_int i;
59392559Sdes
59492559Sdes	buffer_init(&buffer);
59592559Sdes	snprintf(buf, sizeof buf, "The following connections are open:\r\n");
59692559Sdes	buffer_append(&buffer, buf, strlen(buf));
59792559Sdes	for (i = 0; i < channels_alloc; i++) {
59892559Sdes		c = channels[i];
59992559Sdes		if (c == NULL)
60092559Sdes			continue;
60192559Sdes		switch (c->type) {
60292559Sdes		case SSH_CHANNEL_X11_LISTENER:
60392559Sdes		case SSH_CHANNEL_PORT_LISTENER:
60492559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
60592559Sdes		case SSH_CHANNEL_CLOSED:
60692559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
60792559Sdes		case SSH_CHANNEL_ZOMBIE:
60892559Sdes			continue;
60992559Sdes		case SSH_CHANNEL_LARVAL:
61092559Sdes		case SSH_CHANNEL_OPENING:
61192559Sdes		case SSH_CHANNEL_CONNECTING:
61292559Sdes		case SSH_CHANNEL_DYNAMIC:
61392559Sdes		case SSH_CHANNEL_OPEN:
61492559Sdes		case SSH_CHANNEL_X11_OPEN:
61592559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
61692559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
617137019Sdes			snprintf(buf, sizeof buf,
618137019Sdes			    "  #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n",
61992559Sdes			    c->self, c->remote_name,
62092559Sdes			    c->type, c->remote_id,
62192559Sdes			    c->istate, buffer_len(&c->input),
62292559Sdes			    c->ostate, buffer_len(&c->output),
623137019Sdes			    c->rfd, c->wfd, c->ctl_fd);
62492559Sdes			buffer_append(&buffer, buf, strlen(buf));
62592559Sdes			continue;
62692559Sdes		default:
62792559Sdes			fatal("channel_open_message: bad channel type %d", c->type);
62892559Sdes			/* NOTREACHED */
62992559Sdes		}
63092559Sdes	}
63192559Sdes	buffer_append(&buffer, "\0", 1);
63292559Sdes	cp = xstrdup(buffer_ptr(&buffer));
63392559Sdes	buffer_free(&buffer);
63492559Sdes	return cp;
63592559Sdes}
63692559Sdes
63792559Sdesvoid
63892559Sdeschannel_send_open(int id)
63992559Sdes{
64092559Sdes	Channel *c = channel_lookup(id);
641106130Sdes
64292559Sdes	if (c == NULL) {
643124207Sdes		logit("channel_send_open: %d: bad id", id);
64492559Sdes		return;
64592559Sdes	}
646113911Sdes	debug2("channel %d: send open", id);
64792559Sdes	packet_start(SSH2_MSG_CHANNEL_OPEN);
64892559Sdes	packet_put_cstring(c->ctype);
64992559Sdes	packet_put_int(c->self);
65092559Sdes	packet_put_int(c->local_window);
65192559Sdes	packet_put_int(c->local_maxpacket);
65292559Sdes	packet_send();
65392559Sdes}
65492559Sdes
65592559Sdesvoid
656113911Sdeschannel_request_start(int id, char *service, int wantconfirm)
65792559Sdes{
658113911Sdes	Channel *c = channel_lookup(id);
659106130Sdes
66092559Sdes	if (c == NULL) {
661124207Sdes		logit("channel_request_start: %d: unknown channel id", id);
66292559Sdes		return;
66392559Sdes	}
664137019Sdes	debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
66592559Sdes	packet_start(SSH2_MSG_CHANNEL_REQUEST);
66692559Sdes	packet_put_int(c->remote_id);
66792559Sdes	packet_put_cstring(service);
66892559Sdes	packet_put_char(wantconfirm);
66992559Sdes}
670162856Sdes
67192559Sdesvoid
672181111Sdeschannel_register_status_confirm(int id, channel_confirm_cb *cb,
673181111Sdes    channel_confirm_abandon_cb *abandon_cb, void *ctx)
67492559Sdes{
675181111Sdes	struct channel_confirm *cc;
676181111Sdes	Channel *c;
677181111Sdes
678181111Sdes	if ((c = channel_lookup(id)) == NULL)
679181111Sdes		fatal("channel_register_expect: %d: bad id", id);
680181111Sdes
681181111Sdes	cc = xmalloc(sizeof(*cc));
682181111Sdes	cc->cb = cb;
683181111Sdes	cc->abandon_cb = abandon_cb;
684181111Sdes	cc->ctx = ctx;
685181111Sdes	TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
686181111Sdes}
687181111Sdes
688181111Sdesvoid
689181111Sdeschannel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx)
690181111Sdes{
69192559Sdes	Channel *c = channel_lookup(id);
692106130Sdes
69392559Sdes	if (c == NULL) {
694181111Sdes		logit("channel_register_open_comfirm: %d: bad id", id);
69592559Sdes		return;
69692559Sdes	}
697181111Sdes	c->open_confirm = fn;
698181111Sdes	c->open_confirm_ctx = ctx;
69992559Sdes}
700162856Sdes
70192559Sdesvoid
702157019Sdeschannel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
70392559Sdes{
704157019Sdes	Channel *c = channel_by_id(id);
705106130Sdes
70692559Sdes	if (c == NULL) {
707124207Sdes		logit("channel_register_cleanup: %d: bad id", id);
70892559Sdes		return;
70992559Sdes	}
71092559Sdes	c->detach_user = fn;
711157019Sdes	c->detach_close = do_close;
71292559Sdes}
713162856Sdes
71492559Sdesvoid
71592559Sdeschannel_cancel_cleanup(int id)
71692559Sdes{
717157019Sdes	Channel *c = channel_by_id(id);
718106130Sdes
71992559Sdes	if (c == NULL) {
720124207Sdes		logit("channel_cancel_cleanup: %d: bad id", id);
72192559Sdes		return;
72292559Sdes	}
72392559Sdes	c->detach_user = NULL;
724157019Sdes	c->detach_close = 0;
72592559Sdes}
726162856Sdes
72792559Sdesvoid
728157019Sdeschannel_register_filter(int id, channel_infilter_fn *ifn,
729181111Sdes    channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
73092559Sdes{
73192559Sdes	Channel *c = channel_lookup(id);
732106130Sdes
73392559Sdes	if (c == NULL) {
734124207Sdes		logit("channel_register_filter: %d: bad id", id);
73592559Sdes		return;
73692559Sdes	}
737157019Sdes	c->input_filter = ifn;
738157019Sdes	c->output_filter = ofn;
739181111Sdes	c->filter_ctx = ctx;
740181111Sdes	c->filter_cleanup = cfn;
74192559Sdes}
74292559Sdes
74392559Sdesvoid
74492559Sdeschannel_set_fds(int id, int rfd, int wfd, int efd,
745181111Sdes    int extusage, int nonblock, int is_tty, u_int window_max)
74692559Sdes{
74792559Sdes	Channel *c = channel_lookup(id);
748106130Sdes
74992559Sdes	if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
75092559Sdes		fatal("channel_activate for non-larval channel %d.", id);
751181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
75292559Sdes	c->type = SSH_CHANNEL_OPEN;
75392559Sdes	c->local_window = c->local_window_max = window_max;
75492559Sdes	packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
75592559Sdes	packet_put_int(c->remote_id);
75692559Sdes	packet_put_int(c->local_window);
75792559Sdes	packet_send();
75892559Sdes}
75992559Sdes
76092559Sdes/*
76160573Skris * 'channel_pre*' are called just before select() to add any bits relevant to
76260573Skris * channels in the select bitmasks.
76357429Smarkm */
76460573Skris/*
76560573Skris * 'channel_post*': perform any appropriate operations for channels which
76660573Skris * have events pending.
76760573Skris */
768162856Sdestypedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
76960573Skrischan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
77060573Skrischan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
77157429Smarkm
772162856Sdes/* ARGSUSED */
77392559Sdesstatic void
774162856Sdeschannel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
77557429Smarkm{
77660573Skris	FD_SET(c->sock, readset);
77760573Skris}
77860573Skris
779162856Sdes/* ARGSUSED */
78092559Sdesstatic void
781162856Sdeschannel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
78276262Sgreen{
78376262Sgreen	debug3("channel %d: waiting for connection", c->self);
78476262Sgreen	FD_SET(c->sock, writeset);
78576262Sgreen}
78676262Sgreen
78792559Sdesstatic void
788162856Sdeschannel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
78960573Skris{
79060573Skris	if (buffer_len(&c->input) < packet_get_maxsize())
79160573Skris		FD_SET(c->sock, readset);
79260573Skris	if (buffer_len(&c->output) > 0)
79360573Skris		FD_SET(c->sock, writeset);
79460573Skris}
79560573Skris
79692559Sdesstatic void
797162856Sdeschannel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
79860573Skris{
79992559Sdes	u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
80060573Skris
80160573Skris	if (c->istate == CHAN_INPUT_OPEN &&
80292559Sdes	    limit > 0 &&
803162856Sdes	    buffer_len(&c->input) < limit &&
804162856Sdes	    buffer_check_alloc(&c->input, CHAN_RBUF))
80560573Skris		FD_SET(c->rfd, readset);
80660573Skris	if (c->ostate == CHAN_OUTPUT_OPEN ||
80760573Skris	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
80860573Skris		if (buffer_len(&c->output) > 0) {
80960573Skris			FD_SET(c->wfd, writeset);
81060573Skris		} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
81198684Sdes			if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
812149753Sdes				debug2("channel %d: obuf_empty delayed efd %d/(%d)",
813149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
81498684Sdes			else
81598684Sdes				chan_obuf_empty(c);
81660573Skris		}
81760573Skris	}
81860573Skris	/** XXX check close conditions, too */
819181111Sdes	if (compat20 && c->efd != -1 &&
820181111Sdes	    !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
82160573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
82260573Skris		    buffer_len(&c->extended) > 0)
82360573Skris			FD_SET(c->efd, writeset);
82498684Sdes		else if (!(c->flags & CHAN_EOF_SENT) &&
82598684Sdes		    c->extended_usage == CHAN_EXTENDED_READ &&
82660573Skris		    buffer_len(&c->extended) < c->remote_window)
82760573Skris			FD_SET(c->efd, readset);
82860573Skris	}
829137019Sdes	/* XXX: What about efd? races? */
830137019Sdes	if (compat20 && c->ctl_fd != -1 &&
831137019Sdes	    c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN)
832137019Sdes		FD_SET(c->ctl_fd, readset);
83360573Skris}
83460573Skris
835162856Sdes/* ARGSUSED */
83692559Sdesstatic void
837162856Sdeschannel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
83860573Skris{
83960573Skris	if (buffer_len(&c->input) == 0) {
84060573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
84160573Skris		packet_put_int(c->remote_id);
84260573Skris		packet_send();
84360573Skris		c->type = SSH_CHANNEL_CLOSED;
844124207Sdes		debug2("channel %d: closing after input drain.", c->self);
84560573Skris	}
84660573Skris}
84760573Skris
848162856Sdes/* ARGSUSED */
84992559Sdesstatic void
850162856Sdeschannel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
85160573Skris{
85260573Skris	if (buffer_len(&c->output) == 0)
85392559Sdes		chan_mark_dead(c);
85460573Skris	else
85560573Skris		FD_SET(c->sock, writeset);
85660573Skris}
85760573Skris
85860573Skris/*
85960573Skris * This is a special state for X11 authentication spoofing.  An opened X11
86060573Skris * connection (when authentication spoofing is being done) remains in this
86160573Skris * state until the first packet has been completely read.  The authentication
86260573Skris * data in that packet is then substituted by the real data if it matches the
86360573Skris * fake data, and the channel is put into normal mode.
86460573Skris * XXX All this happens at the client side.
86592559Sdes * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
86660573Skris */
86792559Sdesstatic int
86892559Sdesx11_open_helper(Buffer *b)
86960573Skris{
87076262Sgreen	u_char *ucp;
87176262Sgreen	u_int proto_len, data_len;
87257429Smarkm
87360573Skris	/* Check if the fixed size part of the packet is in buffer. */
87492559Sdes	if (buffer_len(b) < 12)
87560573Skris		return 0;
87657429Smarkm
87760573Skris	/* Parse the lengths of variable-length fields. */
87892559Sdes	ucp = buffer_ptr(b);
87960573Skris	if (ucp[0] == 0x42) {	/* Byte order MSB first. */
88060573Skris		proto_len = 256 * ucp[6] + ucp[7];
88160573Skris		data_len = 256 * ucp[8] + ucp[9];
88260573Skris	} else if (ucp[0] == 0x6c) {	/* Byte order LSB first. */
88360573Skris		proto_len = ucp[6] + 256 * ucp[7];
88460573Skris		data_len = ucp[8] + 256 * ucp[9];
88560573Skris	} else {
886124207Sdes		debug2("Initial X11 packet contains bad byte order byte: 0x%x",
88792559Sdes		    ucp[0]);
88860573Skris		return -1;
88960573Skris	}
89057429Smarkm
89160573Skris	/* Check if the whole packet is in buffer. */
89292559Sdes	if (buffer_len(b) <
89360573Skris	    12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
89460573Skris		return 0;
89557429Smarkm
89660573Skris	/* Check if authentication protocol matches. */
89760573Skris	if (proto_len != strlen(x11_saved_proto) ||
89860573Skris	    memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
899124207Sdes		debug2("X11 connection uses different authentication protocol.");
90060573Skris		return -1;
90160573Skris	}
90260573Skris	/* Check if authentication data matches our fake data. */
90360573Skris	if (data_len != x11_fake_data_len ||
90460573Skris	    memcmp(ucp + 12 + ((proto_len + 3) & ~3),
90560573Skris		x11_fake_data, x11_fake_data_len) != 0) {
906124207Sdes		debug2("X11 auth data does not match fake data.");
90760573Skris		return -1;
90860573Skris	}
90960573Skris	/* Check fake data length */
91060573Skris	if (x11_fake_data_len != x11_saved_data_len) {
91160573Skris		error("X11 fake_data_len %d != saved_data_len %d",
91260573Skris		    x11_fake_data_len, x11_saved_data_len);
91360573Skris		return -1;
91460573Skris	}
91560573Skris	/*
91660573Skris	 * Received authentication protocol and data match
91760573Skris	 * our fake data. Substitute the fake data with real
91860573Skris	 * data.
91960573Skris	 */
92060573Skris	memcpy(ucp + 12 + ((proto_len + 3) & ~3),
92160573Skris	    x11_saved_data, x11_saved_data_len);
92260573Skris	return 1;
92360573Skris}
92457429Smarkm
92592559Sdesstatic void
926162856Sdeschannel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
92760573Skris{
92892559Sdes	int ret = x11_open_helper(&c->output);
929106130Sdes
93060573Skris	if (ret == 1) {
93160573Skris		/* Start normal processing for the channel. */
93260573Skris		c->type = SSH_CHANNEL_OPEN;
93360573Skris		channel_pre_open_13(c, readset, writeset);
93460573Skris	} else if (ret == -1) {
93560573Skris		/*
93660573Skris		 * We have received an X11 connection that has bad
93760573Skris		 * authentication information.
93860573Skris		 */
939124207Sdes		logit("X11 connection rejected because of wrong authentication.");
94060573Skris		buffer_clear(&c->input);
94160573Skris		buffer_clear(&c->output);
94292559Sdes		channel_close_fd(&c->sock);
94360573Skris		c->sock = -1;
94460573Skris		c->type = SSH_CHANNEL_CLOSED;
94560573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
94660573Skris		packet_put_int(c->remote_id);
94760573Skris		packet_send();
94860573Skris	}
94960573Skris}
95057429Smarkm
95192559Sdesstatic void
952162856Sdeschannel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
95360573Skris{
95492559Sdes	int ret = x11_open_helper(&c->output);
95592559Sdes
95692559Sdes	/* c->force_drain = 1; */
95792559Sdes
95860573Skris	if (ret == 1) {
95960573Skris		c->type = SSH_CHANNEL_OPEN;
96092559Sdes		channel_pre_open(c, readset, writeset);
96192559Sdes	} else if (ret == -1) {
962124207Sdes		logit("X11 connection rejected because of wrong authentication.");
963124207Sdes		debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
96492559Sdes		chan_read_failed(c);
96592559Sdes		buffer_clear(&c->input);
96692559Sdes		chan_ibuf_empty(c);
96792559Sdes		buffer_clear(&c->output);
96892559Sdes		/* for proto v1, the peer will send an IEOF */
96960573Skris		if (compat20)
97092559Sdes			chan_write_failed(c);
97160573Skris		else
97292559Sdes			c->type = SSH_CHANNEL_OPEN;
973124207Sdes		debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
97460573Skris	}
97560573Skris}
97657429Smarkm
97776262Sgreen/* try to decode a socks4 header */
978162856Sdes/* ARGSUSED */
97992559Sdesstatic int
980162856Sdeschannel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
98176262Sgreen{
982106130Sdes	char *p, *host;
983149753Sdes	u_int len, have, i, found;
98492559Sdes	char username[256];
98576262Sgreen	struct {
98676262Sgreen		u_int8_t version;
98776262Sgreen		u_int8_t command;
98876262Sgreen		u_int16_t dest_port;
98976262Sgreen		struct in_addr dest_addr;
99076262Sgreen	} s4_req, s4_rsp;
99176262Sgreen
99276262Sgreen	debug2("channel %d: decode socks4", c->self);
99376262Sgreen
99476262Sgreen	have = buffer_len(&c->input);
99576262Sgreen	len = sizeof(s4_req);
99676262Sgreen	if (have < len)
99776262Sgreen		return 0;
99876262Sgreen	p = buffer_ptr(&c->input);
99976262Sgreen	for (found = 0, i = len; i < have; i++) {
100076262Sgreen		if (p[i] == '\0') {
100176262Sgreen			found = 1;
100276262Sgreen			break;
100376262Sgreen		}
100476262Sgreen		if (i > 1024) {
100576262Sgreen			/* the peer is probably sending garbage */
100676262Sgreen			debug("channel %d: decode socks4: too long",
100776262Sgreen			    c->self);
100876262Sgreen			return -1;
100976262Sgreen		}
101076262Sgreen	}
101176262Sgreen	if (!found)
101276262Sgreen		return 0;
101376262Sgreen	buffer_get(&c->input, (char *)&s4_req.version, 1);
101476262Sgreen	buffer_get(&c->input, (char *)&s4_req.command, 1);
101576262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
101676262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
101776262Sgreen	have = buffer_len(&c->input);
101876262Sgreen	p = buffer_ptr(&c->input);
101976262Sgreen	len = strlen(p);
102076262Sgreen	debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
102176262Sgreen	if (len > have)
102276262Sgreen		fatal("channel %d: decode socks4: len %d > have %d",
102376262Sgreen		    c->self, len, have);
102476262Sgreen	strlcpy(username, p, sizeof(username));
102576262Sgreen	buffer_consume(&c->input, len);
102676262Sgreen	buffer_consume(&c->input, 1);		/* trailing '\0' */
102776262Sgreen
102876262Sgreen	host = inet_ntoa(s4_req.dest_addr);
102976262Sgreen	strlcpy(c->path, host, sizeof(c->path));
103076262Sgreen	c->host_port = ntohs(s4_req.dest_port);
103192559Sdes
1032124207Sdes	debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
103376262Sgreen	    c->self, host, c->host_port, s4_req.command);
103476262Sgreen
103576262Sgreen	if (s4_req.command != 1) {
103676262Sgreen		debug("channel %d: cannot handle: socks4 cn %d",
103776262Sgreen		    c->self, s4_req.command);
103876262Sgreen		return -1;
103976262Sgreen	}
104076262Sgreen	s4_rsp.version = 0;			/* vn: 0 for reply */
104176262Sgreen	s4_rsp.command = 90;			/* cd: req granted */
104276262Sgreen	s4_rsp.dest_port = 0;			/* ignored */
104376262Sgreen	s4_rsp.dest_addr.s_addr = INADDR_ANY;	/* ignored */
1044162856Sdes	buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp));
104576262Sgreen	return 1;
104676262Sgreen}
104776262Sgreen
1048124207Sdes/* try to decode a socks5 header */
1049124207Sdes#define SSH_SOCKS5_AUTHDONE	0x1000
1050124207Sdes#define SSH_SOCKS5_NOAUTH	0x00
1051124207Sdes#define SSH_SOCKS5_IPV4		0x01
1052124207Sdes#define SSH_SOCKS5_DOMAIN	0x03
1053124207Sdes#define SSH_SOCKS5_IPV6		0x04
1054124207Sdes#define SSH_SOCKS5_CONNECT	0x01
1055124207Sdes#define SSH_SOCKS5_SUCCESS	0x00
1056124207Sdes
1057162856Sdes/* ARGSUSED */
1058124207Sdesstatic int
1059162856Sdeschannel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1060124207Sdes{
1061124207Sdes	struct {
1062124207Sdes		u_int8_t version;
1063124207Sdes		u_int8_t command;
1064124207Sdes		u_int8_t reserved;
1065124207Sdes		u_int8_t atyp;
1066124207Sdes	} s5_req, s5_rsp;
1067124207Sdes	u_int16_t dest_port;
1068124207Sdes	u_char *p, dest_addr[255+1];
1069162856Sdes	u_int have, need, i, found, nmethods, addrlen, af;
1070124207Sdes
1071124207Sdes	debug2("channel %d: decode socks5", c->self);
1072124207Sdes	p = buffer_ptr(&c->input);
1073124207Sdes	if (p[0] != 0x05)
1074124207Sdes		return -1;
1075124207Sdes	have = buffer_len(&c->input);
1076124207Sdes	if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
1077124207Sdes		/* format: ver | nmethods | methods */
1078126273Sdes		if (have < 2)
1079124207Sdes			return 0;
1080124207Sdes		nmethods = p[1];
1081124207Sdes		if (have < nmethods + 2)
1082124207Sdes			return 0;
1083124207Sdes		/* look for method: "NO AUTHENTICATION REQUIRED" */
1084181111Sdes		for (found = 0, i = 2; i < nmethods + 2; i++) {
1085162856Sdes			if (p[i] == SSH_SOCKS5_NOAUTH) {
1086124207Sdes				found = 1;
1087124207Sdes				break;
1088124207Sdes			}
1089124207Sdes		}
1090124207Sdes		if (!found) {
1091124207Sdes			debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
1092124207Sdes			    c->self);
1093124207Sdes			return -1;
1094124207Sdes		}
1095124207Sdes		buffer_consume(&c->input, nmethods + 2);
1096124207Sdes		buffer_put_char(&c->output, 0x05);		/* version */
1097124207Sdes		buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH);	/* method */
1098124207Sdes		FD_SET(c->sock, writeset);
1099124207Sdes		c->flags |= SSH_SOCKS5_AUTHDONE;
1100124207Sdes		debug2("channel %d: socks5 auth done", c->self);
1101124207Sdes		return 0;				/* need more */
1102124207Sdes	}
1103124207Sdes	debug2("channel %d: socks5 post auth", c->self);
1104124207Sdes	if (have < sizeof(s5_req)+1)
1105124207Sdes		return 0;			/* need more */
1106162856Sdes	memcpy(&s5_req, p, sizeof(s5_req));
1107124207Sdes	if (s5_req.version != 0x05 ||
1108124207Sdes	    s5_req.command != SSH_SOCKS5_CONNECT ||
1109124207Sdes	    s5_req.reserved != 0x00) {
1110124207Sdes		debug2("channel %d: only socks5 connect supported", c->self);
1111124207Sdes		return -1;
1112124207Sdes	}
1113147005Sdes	switch (s5_req.atyp){
1114124207Sdes	case SSH_SOCKS5_IPV4:
1115124207Sdes		addrlen = 4;
1116124207Sdes		af = AF_INET;
1117124207Sdes		break;
1118124207Sdes	case SSH_SOCKS5_DOMAIN:
1119124207Sdes		addrlen = p[sizeof(s5_req)];
1120124207Sdes		af = -1;
1121124207Sdes		break;
1122124207Sdes	case SSH_SOCKS5_IPV6:
1123124207Sdes		addrlen = 16;
1124124207Sdes		af = AF_INET6;
1125124207Sdes		break;
1126124207Sdes	default:
1127124207Sdes		debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
1128124207Sdes		return -1;
1129124207Sdes	}
1130162856Sdes	need = sizeof(s5_req) + addrlen + 2;
1131162856Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1132162856Sdes		need++;
1133162856Sdes	if (have < need)
1134124207Sdes		return 0;
1135124207Sdes	buffer_consume(&c->input, sizeof(s5_req));
1136124207Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1137124207Sdes		buffer_consume(&c->input, 1);    /* host string length */
1138124207Sdes	buffer_get(&c->input, (char *)&dest_addr, addrlen);
1139124207Sdes	buffer_get(&c->input, (char *)&dest_port, 2);
1140124207Sdes	dest_addr[addrlen] = '\0';
1141124207Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1142137019Sdes		strlcpy(c->path, (char *)dest_addr, sizeof(c->path));
1143124207Sdes	else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL)
1144124207Sdes		return -1;
1145124207Sdes	c->host_port = ntohs(dest_port);
1146126273Sdes
1147124207Sdes	debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
1148124207Sdes	    c->self, c->path, c->host_port, s5_req.command);
1149124207Sdes
1150124207Sdes	s5_rsp.version = 0x05;
1151124207Sdes	s5_rsp.command = SSH_SOCKS5_SUCCESS;
1152124207Sdes	s5_rsp.reserved = 0;			/* ignored */
1153124207Sdes	s5_rsp.atyp = SSH_SOCKS5_IPV4;
1154124207Sdes	((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
1155124207Sdes	dest_port = 0;				/* ignored */
1156124207Sdes
1157162856Sdes	buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
1158162856Sdes	buffer_append(&c->output, &dest_addr, sizeof(struct in_addr));
1159162856Sdes	buffer_append(&c->output, &dest_port, sizeof(dest_port));
1160124207Sdes	return 1;
1161124207Sdes}
1162124207Sdes
116376262Sgreen/* dynamic port forwarding */
116492559Sdesstatic void
1165162856Sdeschannel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
116676262Sgreen{
116776262Sgreen	u_char *p;
1168149753Sdes	u_int have;
1169149753Sdes	int ret;
117076262Sgreen
117176262Sgreen	have = buffer_len(&c->input);
117292559Sdes	c->delayed = 0;
117376262Sgreen	debug2("channel %d: pre_dynamic: have %d", c->self, have);
117476262Sgreen	/* buffer_dump(&c->input); */
117576262Sgreen	/* check if the fixed size part of the packet is in buffer. */
1176124207Sdes	if (have < 3) {
117776262Sgreen		/* need more */
117876262Sgreen		FD_SET(c->sock, readset);
117976262Sgreen		return;
118076262Sgreen	}
118176262Sgreen	/* try to guess the protocol */
118276262Sgreen	p = buffer_ptr(&c->input);
118376262Sgreen	switch (p[0]) {
118476262Sgreen	case 0x04:
118576262Sgreen		ret = channel_decode_socks4(c, readset, writeset);
118676262Sgreen		break;
1187124207Sdes	case 0x05:
1188124207Sdes		ret = channel_decode_socks5(c, readset, writeset);
1189124207Sdes		break;
119076262Sgreen	default:
119176262Sgreen		ret = -1;
119276262Sgreen		break;
119376262Sgreen	}
119476262Sgreen	if (ret < 0) {
119592559Sdes		chan_mark_dead(c);
119676262Sgreen	} else if (ret == 0) {
119776262Sgreen		debug2("channel %d: pre_dynamic: need more", c->self);
119876262Sgreen		/* need more */
119976262Sgreen		FD_SET(c->sock, readset);
120076262Sgreen	} else {
120176262Sgreen		/* switch to the next state */
120276262Sgreen		c->type = SSH_CHANNEL_OPENING;
120376262Sgreen		port_open_helper(c, "direct-tcpip");
120476262Sgreen	}
120576262Sgreen}
120676262Sgreen
120760573Skris/* This is our fake X11 server socket. */
1208162856Sdes/* ARGSUSED */
120992559Sdesstatic void
1210162856Sdeschannel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
121160573Skris{
121292559Sdes	Channel *nc;
1213181111Sdes	struct sockaddr_storage addr;
121492559Sdes	int newsock;
121560573Skris	socklen_t addrlen;
121676262Sgreen	char buf[16384], *remote_ipaddr;
121760573Skris	int remote_port;
121857429Smarkm
121960573Skris	if (FD_ISSET(c->sock, readset)) {
122060573Skris		debug("X11 connection requested.");
122160573Skris		addrlen = sizeof(addr);
1222181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
122392559Sdes		if (c->single_connection) {
1224124207Sdes			debug2("single_connection: closing X11 listener.");
122592559Sdes			channel_close_fd(&c->sock);
122692559Sdes			chan_mark_dead(c);
122792559Sdes		}
122860573Skris		if (newsock < 0) {
122960573Skris			error("accept: %.100s", strerror(errno));
123060573Skris			return;
123160573Skris		}
123292559Sdes		set_nodelay(newsock);
123376262Sgreen		remote_ipaddr = get_peer_ipaddr(newsock);
123460573Skris		remote_port = get_peer_port(newsock);
123560573Skris		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
123676262Sgreen		    remote_ipaddr, remote_port);
123757429Smarkm
123892559Sdes		nc = channel_new("accepted x11 socket",
123960573Skris		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
1240124207Sdes		    c->local_window_max, c->local_maxpacket, 0, buf, 1);
124160573Skris		if (compat20) {
124260573Skris			packet_start(SSH2_MSG_CHANNEL_OPEN);
124360573Skris			packet_put_cstring("x11");
124492559Sdes			packet_put_int(nc->self);
124592559Sdes			packet_put_int(nc->local_window_max);
124692559Sdes			packet_put_int(nc->local_maxpacket);
124776262Sgreen			/* originator ipaddr and port */
124876262Sgreen			packet_put_cstring(remote_ipaddr);
124960573Skris			if (datafellows & SSH_BUG_X11FWD) {
1250124207Sdes				debug2("ssh2 x11 bug compat mode");
125157429Smarkm			} else {
125260573Skris				packet_put_int(remote_port);
125357429Smarkm			}
125460573Skris			packet_send();
125560573Skris		} else {
125660573Skris			packet_start(SSH_SMSG_X11_OPEN);
125792559Sdes			packet_put_int(nc->self);
125892559Sdes			if (packet_get_protocol_flags() &
125992559Sdes			    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
126092559Sdes				packet_put_cstring(buf);
126160573Skris			packet_send();
126257429Smarkm		}
126376262Sgreen		xfree(remote_ipaddr);
126457429Smarkm	}
126557429Smarkm}
126657429Smarkm
126792559Sdesstatic void
126876262Sgreenport_open_helper(Channel *c, char *rtype)
126976262Sgreen{
127076262Sgreen	int direct;
127176262Sgreen	char buf[1024];
127276262Sgreen	char *remote_ipaddr = get_peer_ipaddr(c->sock);
1273149753Sdes	int remote_port = get_peer_port(c->sock);
127476262Sgreen
127576262Sgreen	direct = (strcmp(rtype, "direct-tcpip") == 0);
127676262Sgreen
127776262Sgreen	snprintf(buf, sizeof buf,
127876262Sgreen	    "%s: listening port %d for %.100s port %d, "
127976262Sgreen	    "connect from %.200s port %d",
128076262Sgreen	    rtype, c->listening_port, c->path, c->host_port,
128176262Sgreen	    remote_ipaddr, remote_port);
128276262Sgreen
128376262Sgreen	xfree(c->remote_name);
128476262Sgreen	c->remote_name = xstrdup(buf);
128576262Sgreen
128676262Sgreen	if (compat20) {
128776262Sgreen		packet_start(SSH2_MSG_CHANNEL_OPEN);
128876262Sgreen		packet_put_cstring(rtype);
128976262Sgreen		packet_put_int(c->self);
129076262Sgreen		packet_put_int(c->local_window_max);
129176262Sgreen		packet_put_int(c->local_maxpacket);
129276262Sgreen		if (direct) {
129376262Sgreen			/* target host, port */
129476262Sgreen			packet_put_cstring(c->path);
129576262Sgreen			packet_put_int(c->host_port);
129676262Sgreen		} else {
129776262Sgreen			/* listen address, port */
129876262Sgreen			packet_put_cstring(c->path);
129976262Sgreen			packet_put_int(c->listening_port);
130076262Sgreen		}
130176262Sgreen		/* originator host and port */
130276262Sgreen		packet_put_cstring(remote_ipaddr);
1303149753Sdes		packet_put_int((u_int)remote_port);
130476262Sgreen		packet_send();
130576262Sgreen	} else {
130676262Sgreen		packet_start(SSH_MSG_PORT_OPEN);
130776262Sgreen		packet_put_int(c->self);
130876262Sgreen		packet_put_cstring(c->path);
130976262Sgreen		packet_put_int(c->host_port);
131092559Sdes		if (packet_get_protocol_flags() &
131192559Sdes		    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
131276262Sgreen			packet_put_cstring(c->remote_name);
131376262Sgreen		packet_send();
131476262Sgreen	}
131576262Sgreen	xfree(remote_ipaddr);
131676262Sgreen}
131776262Sgreen
1318157019Sdesstatic void
1319157019Sdeschannel_set_reuseaddr(int fd)
1320157019Sdes{
1321157019Sdes	int on = 1;
1322157019Sdes
1323157019Sdes	/*
1324157019Sdes	 * Set socket options.
1325157019Sdes	 * Allow local port reuse in TIME_WAIT.
1326157019Sdes	 */
1327157019Sdes	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1328157019Sdes		error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
1329157019Sdes}
1330157019Sdes
133157429Smarkm/*
133260573Skris * This socket is listening for connections to a forwarded TCP/IP port.
133357429Smarkm */
1334162856Sdes/* ARGSUSED */
133592559Sdesstatic void
1336162856Sdeschannel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
133757429Smarkm{
133876262Sgreen	Channel *nc;
1339181111Sdes	struct sockaddr_storage addr;
134092559Sdes	int newsock, nextstate;
134157429Smarkm	socklen_t addrlen;
134276262Sgreen	char *rtype;
134357429Smarkm
134460573Skris	if (FD_ISSET(c->sock, readset)) {
134560573Skris		debug("Connection to port %d forwarding "
134660573Skris		    "to %.100s port %d requested.",
134760573Skris		    c->listening_port, c->path, c->host_port);
134876262Sgreen
134992559Sdes		if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
135092559Sdes			nextstate = SSH_CHANNEL_OPENING;
135192559Sdes			rtype = "forwarded-tcpip";
135292559Sdes		} else {
135392559Sdes			if (c->host_port == 0) {
135492559Sdes				nextstate = SSH_CHANNEL_DYNAMIC;
135592559Sdes				rtype = "dynamic-tcpip";
135692559Sdes			} else {
135792559Sdes				nextstate = SSH_CHANNEL_OPENING;
135892559Sdes				rtype = "direct-tcpip";
135992559Sdes			}
136092559Sdes		}
136176262Sgreen
136260573Skris		addrlen = sizeof(addr);
1363181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
136460573Skris		if (newsock < 0) {
136560573Skris			error("accept: %.100s", strerror(errno));
136660573Skris			return;
136760573Skris		}
136892559Sdes		set_nodelay(newsock);
1369124207Sdes		nc = channel_new(rtype, nextstate, newsock, newsock, -1,
1370124207Sdes		    c->local_window_max, c->local_maxpacket, 0, rtype, 1);
137176262Sgreen		nc->listening_port = c->listening_port;
137276262Sgreen		nc->host_port = c->host_port;
137376262Sgreen		strlcpy(nc->path, c->path, sizeof(nc->path));
137476262Sgreen
137592559Sdes		if (nextstate == SSH_CHANNEL_DYNAMIC) {
137692559Sdes			/*
137792559Sdes			 * do not call the channel_post handler until
137892559Sdes			 * this flag has been reset by a pre-handler.
137992559Sdes			 * otherwise the FD_ISSET calls might overflow
138092559Sdes			 */
138192559Sdes			nc->delayed = 1;
138292559Sdes		} else {
138376262Sgreen			port_open_helper(nc, rtype);
138492559Sdes		}
138560573Skris	}
138660573Skris}
138757429Smarkm
138860573Skris/*
138960573Skris * This is the authentication agent socket listening for connections from
139060573Skris * clients.
139160573Skris */
1392162856Sdes/* ARGSUSED */
139392559Sdesstatic void
1394162856Sdeschannel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
139560573Skris{
139692559Sdes	Channel *nc;
139792559Sdes	int newsock;
1398181111Sdes	struct sockaddr_storage addr;
139960573Skris	socklen_t addrlen;
140057429Smarkm
140160573Skris	if (FD_ISSET(c->sock, readset)) {
140260573Skris		addrlen = sizeof(addr);
1403181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
140460573Skris		if (newsock < 0) {
140560573Skris			error("accept from auth socket: %.100s", strerror(errno));
140660573Skris			return;
140760573Skris		}
140892559Sdes		nc = channel_new("accepted auth socket",
140976262Sgreen		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
141076262Sgreen		    c->local_window_max, c->local_maxpacket,
1411124207Sdes		    0, "accepted auth socket", 1);
141276262Sgreen		if (compat20) {
141376262Sgreen			packet_start(SSH2_MSG_CHANNEL_OPEN);
141476262Sgreen			packet_put_cstring("auth-agent@openssh.com");
141592559Sdes			packet_put_int(nc->self);
141676262Sgreen			packet_put_int(c->local_window_max);
141776262Sgreen			packet_put_int(c->local_maxpacket);
141876262Sgreen		} else {
141976262Sgreen			packet_start(SSH_SMSG_AGENT_OPEN);
142092559Sdes			packet_put_int(nc->self);
142176262Sgreen		}
142260573Skris		packet_send();
142360573Skris	}
142460573Skris}
142557429Smarkm
1426162856Sdes/* ARGSUSED */
142792559Sdesstatic void
1428162856Sdeschannel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
142976262Sgreen{
1430181111Sdes	int err = 0, sock;
143192559Sdes	socklen_t sz = sizeof(err);
143292559Sdes
143376262Sgreen	if (FD_ISSET(c->sock, writeset)) {
143492559Sdes		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
143592559Sdes			err = errno;
143692559Sdes			error("getsockopt SO_ERROR failed");
143792559Sdes		}
143892559Sdes		if (err == 0) {
1439181111Sdes			debug("channel %d: connected to %s port %d",
1440181111Sdes			    c->self, c->connect_ctx.host, c->connect_ctx.port);
1441181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
144292559Sdes			c->type = SSH_CHANNEL_OPEN;
144392559Sdes			if (compat20) {
144492559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
144592559Sdes				packet_put_int(c->remote_id);
144692559Sdes				packet_put_int(c->self);
144792559Sdes				packet_put_int(c->local_window);
144892559Sdes				packet_put_int(c->local_maxpacket);
144992559Sdes			} else {
145092559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
145192559Sdes				packet_put_int(c->remote_id);
145292559Sdes				packet_put_int(c->self);
145392559Sdes			}
145476262Sgreen		} else {
1455181111Sdes			debug("channel %d: connection failed: %s",
145692559Sdes			    c->self, strerror(err));
1457181111Sdes			/* Try next address, if any */
1458181111Sdes			if ((sock = connect_next(&c->connect_ctx)) > 0) {
1459181111Sdes				close(c->sock);
1460181111Sdes				c->sock = c->rfd = c->wfd = sock;
1461181111Sdes				channel_max_fd = channel_find_maxfd();
1462181111Sdes				return;
1463181111Sdes			}
1464181111Sdes			/* Exhausted all addresses */
1465181111Sdes			error("connect_to %.100s port %d: failed.",
1466181111Sdes			    c->connect_ctx.host, c->connect_ctx.port);
1467181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
146892559Sdes			if (compat20) {
146992559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
147092559Sdes				packet_put_int(c->remote_id);
147192559Sdes				packet_put_int(SSH2_OPEN_CONNECT_FAILED);
147292559Sdes				if (!(datafellows & SSH_BUG_OPENFAILURE)) {
147392559Sdes					packet_put_cstring(strerror(err));
147492559Sdes					packet_put_cstring("");
147592559Sdes				}
147676262Sgreen			} else {
147792559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
147892559Sdes				packet_put_int(c->remote_id);
147976262Sgreen			}
148092559Sdes			chan_mark_dead(c);
148176262Sgreen		}
148292559Sdes		packet_send();
148376262Sgreen	}
148476262Sgreen}
148576262Sgreen
1486162856Sdes/* ARGSUSED */
148792559Sdesstatic int
1488162856Sdeschannel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
148960573Skris{
1490147005Sdes	char buf[CHAN_RBUF];
1491181111Sdes	int len, force;
149257429Smarkm
1493181111Sdes	force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
1494181111Sdes	if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
1495162856Sdes		errno = 0;
149660573Skris		len = read(c->rfd, buf, sizeof(buf));
1497181111Sdes		if (len < 0 && (errno == EINTR ||
1498181111Sdes		    ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
149960573Skris			return 1;
1500162856Sdes#ifndef PTY_ZEROREAD
150178827Sgreen		if (len <= 0) {
1502162856Sdes#else
1503162856Sdes		if ((!c->isatty && len <= 0) ||
1504162856Sdes		    (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
1505162856Sdes#endif
1506124207Sdes			debug2("channel %d: read<=0 rfd %d len %d",
150760573Skris			    c->self, c->rfd, len);
150876262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1509124207Sdes				debug2("channel %d: not open", c->self);
151092559Sdes				chan_mark_dead(c);
151176262Sgreen				return -1;
151276262Sgreen			} else if (compat13) {
151392559Sdes				buffer_clear(&c->output);
151460573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
1515124207Sdes				debug2("channel %d: input draining.", c->self);
151660573Skris			} else {
151760573Skris				chan_read_failed(c);
151857429Smarkm			}
151960573Skris			return -1;
152060573Skris		}
152192559Sdes		if (c->input_filter != NULL) {
152265668Skris			if (c->input_filter(c, buf, len) == -1) {
1523124207Sdes				debug2("channel %d: filter stops", c->self);
152465668Skris				chan_read_failed(c);
152565668Skris			}
1526157019Sdes		} else if (c->datagram) {
1527157019Sdes			buffer_put_string(&c->input, buf, len);
152865668Skris		} else {
152965668Skris			buffer_append(&c->input, buf, len);
153065668Skris		}
153160573Skris	}
153260573Skris	return 1;
153360573Skris}
1534162856Sdes
1535162856Sdes/* ARGSUSED */
153692559Sdesstatic int
1537162856Sdeschannel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
153860573Skris{
153976262Sgreen	struct termios tio;
1540157019Sdes	u_char *data = NULL, *buf;
154192559Sdes	u_int dlen;
154260573Skris	int len;
154360573Skris
154460573Skris	/* Send buffered output data to the socket. */
154560573Skris	if (c->wfd != -1 &&
154660573Skris	    FD_ISSET(c->wfd, writeset) &&
154760573Skris	    buffer_len(&c->output) > 0) {
1548157019Sdes		if (c->output_filter != NULL) {
1549157019Sdes			if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1550157019Sdes				debug2("channel %d: filter stops", c->self);
1551157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1552157019Sdes					chan_mark_dead(c);
1553157019Sdes				else
1554157019Sdes					chan_write_failed(c);
1555157019Sdes				return -1;
1556157019Sdes			}
1557157019Sdes		} else if (c->datagram) {
1558157019Sdes			buf = data = buffer_get_string(&c->output, &dlen);
1559157019Sdes		} else {
1560157019Sdes			buf = data = buffer_ptr(&c->output);
1561157019Sdes			dlen = buffer_len(&c->output);
1562157019Sdes		}
1563157019Sdes
1564157019Sdes		if (c->datagram) {
1565157019Sdes			/* ignore truncated writes, datagrams might get lost */
1566157019Sdes			c->local_consumed += dlen + 4;
1567157019Sdes			len = write(c->wfd, buf, dlen);
1568157019Sdes			xfree(data);
1569181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1570181111Sdes			    errno == EWOULDBLOCK))
1571157019Sdes				return 1;
1572157019Sdes			if (len <= 0) {
1573157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1574157019Sdes					chan_mark_dead(c);
1575157019Sdes				else
1576157019Sdes					chan_write_failed(c);
1577157019Sdes				return -1;
1578157019Sdes			}
1579157019Sdes			return 1;
1580157019Sdes		}
1581106130Sdes#ifdef _AIX
1582126273Sdes		/* XXX: Later AIX versions can't push as much data to tty */
1583126273Sdes		if (compat20 && c->wfd_isatty)
1584126273Sdes			dlen = MIN(dlen, 8*1024);
1585106130Sdes#endif
1586157019Sdes
1587157019Sdes		len = write(c->wfd, buf, dlen);
1588181111Sdes		if (len < 0 &&
1589181111Sdes		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
159060573Skris			return 1;
159160573Skris		if (len <= 0) {
159276262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1593124207Sdes				debug2("channel %d: not open", c->self);
159492559Sdes				chan_mark_dead(c);
159576262Sgreen				return -1;
159676262Sgreen			} else if (compat13) {
159792559Sdes				buffer_clear(&c->output);
1598124207Sdes				debug2("channel %d: input draining.", c->self);
159960573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
160060573Skris			} else {
160160573Skris				chan_write_failed(c);
160257429Smarkm			}
160360573Skris			return -1;
160460573Skris		}
1605157019Sdes		if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
160674500Sgreen			if (tcgetattr(c->wfd, &tio) == 0 &&
160774500Sgreen			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
160874500Sgreen				/*
160974500Sgreen				 * Simulate echo to reduce the impact of
161076262Sgreen				 * traffic analysis. We need to match the
161176262Sgreen				 * size of a SSH2_MSG_CHANNEL_DATA message
1612157019Sdes				 * (4 byte channel id + buf)
161374500Sgreen				 */
161476262Sgreen				packet_send_ignore(4 + len);
161574500Sgreen				packet_send();
161674500Sgreen			}
161774500Sgreen		}
161860573Skris		buffer_consume(&c->output, len);
161960573Skris		if (compat20 && len > 0) {
162060573Skris			c->local_consumed += len;
162160573Skris		}
162260573Skris	}
162360573Skris	return 1;
162460573Skris}
1625162856Sdes
162692559Sdesstatic int
1627162856Sdeschannel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
162860573Skris{
1629147005Sdes	char buf[CHAN_RBUF];
163060573Skris	int len;
163157429Smarkm
163260573Skris/** XXX handle drain efd, too */
163360573Skris	if (c->efd != -1) {
163460573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
163560573Skris		    FD_ISSET(c->efd, writeset) &&
163660573Skris		    buffer_len(&c->extended) > 0) {
163760573Skris			len = write(c->efd, buffer_ptr(&c->extended),
163860573Skris			    buffer_len(&c->extended));
163969587Sgreen			debug2("channel %d: written %d to efd %d",
164060573Skris			    c->self, len, c->efd);
1641181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1642181111Sdes			    errno == EWOULDBLOCK))
164376262Sgreen				return 1;
164476262Sgreen			if (len <= 0) {
164576262Sgreen				debug2("channel %d: closing write-efd %d",
164676262Sgreen				    c->self, c->efd);
164792559Sdes				channel_close_fd(&c->efd);
164876262Sgreen			} else {
164960573Skris				buffer_consume(&c->extended, len);
165060573Skris				c->local_consumed += len;
165157429Smarkm			}
165260573Skris		} else if (c->extended_usage == CHAN_EXTENDED_READ &&
1653181111Sdes		    (c->detach_close || FD_ISSET(c->efd, readset))) {
165460573Skris			len = read(c->efd, buf, sizeof(buf));
165569587Sgreen			debug2("channel %d: read %d from efd %d",
165692559Sdes			    c->self, len, c->efd);
1657181111Sdes			if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
1658181111Sdes			    errno == EWOULDBLOCK) && !c->detach_close)))
165976262Sgreen				return 1;
166076262Sgreen			if (len <= 0) {
166176262Sgreen				debug2("channel %d: closing read-efd %d",
166260573Skris				    c->self, c->efd);
166392559Sdes				channel_close_fd(&c->efd);
166476262Sgreen			} else {
166560573Skris				buffer_append(&c->extended, buf, len);
166676262Sgreen			}
166760573Skris		}
166860573Skris	}
166960573Skris	return 1;
167060573Skris}
1671162856Sdes
1672162856Sdes/* ARGSUSED */
167392559Sdesstatic int
1674162856Sdeschannel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
1675137019Sdes{
1676137019Sdes	char buf[16];
1677137019Sdes	int len;
1678137019Sdes
1679137019Sdes	/* Monitor control fd to detect if the slave client exits */
1680137019Sdes	if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
1681137019Sdes		len = read(c->ctl_fd, buf, sizeof(buf));
1682181111Sdes		if (len < 0 &&
1683181111Sdes		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
1684137019Sdes			return 1;
1685137019Sdes		if (len <= 0) {
1686137019Sdes			debug2("channel %d: ctl read<=0", c->self);
1687137019Sdes			if (c->type != SSH_CHANNEL_OPEN) {
1688137019Sdes				debug2("channel %d: not open", c->self);
1689137019Sdes				chan_mark_dead(c);
1690137019Sdes				return -1;
1691137019Sdes			} else {
1692137019Sdes				chan_read_failed(c);
1693137019Sdes				chan_write_failed(c);
1694137019Sdes			}
1695137019Sdes			return -1;
1696137019Sdes		} else
1697137019Sdes			fatal("%s: unexpected data on ctl fd", __func__);
1698137019Sdes	}
1699137019Sdes	return 1;
1700137019Sdes}
1701162856Sdes
1702137019Sdesstatic int
170376262Sgreenchannel_check_window(Channel *c)
170460573Skris{
170576262Sgreen	if (c->type == SSH_CHANNEL_OPEN &&
170676262Sgreen	    !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
1707181111Sdes	    ((c->local_window_max - c->local_window >
1708181111Sdes	    c->local_maxpacket*3) ||
1709181111Sdes	    c->local_window < c->local_window_max/2) &&
171060573Skris	    c->local_consumed > 0) {
171160573Skris		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
171260573Skris		packet_put_int(c->remote_id);
171360573Skris		packet_put_int(c->local_consumed);
171460573Skris		packet_send();
171569587Sgreen		debug2("channel %d: window %d sent adjust %d",
171660573Skris		    c->self, c->local_window,
171760573Skris		    c->local_consumed);
171860573Skris		c->local_window += c->local_consumed;
171960573Skris		c->local_consumed = 0;
172060573Skris	}
172160573Skris	return 1;
172260573Skris}
172357429Smarkm
172492559Sdesstatic void
1725162856Sdeschannel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
172660573Skris{
172792559Sdes	if (c->delayed)
172892559Sdes		return;
172960573Skris	channel_handle_rfd(c, readset, writeset);
173060573Skris	channel_handle_wfd(c, readset, writeset);
173192559Sdes	if (!compat20)
173292559Sdes		return;
173360573Skris	channel_handle_efd(c, readset, writeset);
1734137019Sdes	channel_handle_ctl(c, readset, writeset);
173576262Sgreen	channel_check_window(c);
173660573Skris}
173760573Skris
1738162856Sdes/* ARGSUSED */
173992559Sdesstatic void
1740162856Sdeschannel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
174160573Skris{
174260573Skris	int len;
1743106130Sdes
174460573Skris	/* Send buffered output data to the socket. */
174560573Skris	if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
174660573Skris		len = write(c->sock, buffer_ptr(&c->output),
174760573Skris			    buffer_len(&c->output));
174860573Skris		if (len <= 0)
174992559Sdes			buffer_clear(&c->output);
175060573Skris		else
175160573Skris			buffer_consume(&c->output, len);
175260573Skris	}
175360573Skris}
175460573Skris
175592559Sdesstatic void
175660573Skrischannel_handler_init_20(void)
175760573Skris{
175892559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
175960573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
176060573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
176176262Sgreen	channel_pre[SSH_CHANNEL_RPORT_LISTENER] =	&channel_pre_listener;
176260573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
176376262Sgreen	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
176476262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
176576262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
176660573Skris
176792559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
176860573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
176976262Sgreen	channel_post[SSH_CHANNEL_RPORT_LISTENER] =	&channel_post_port_listener;
177060573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
177176262Sgreen	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
177276262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
177392559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
177460573Skris}
177560573Skris
177692559Sdesstatic void
177760573Skrischannel_handler_init_13(void)
177860573Skris{
177960573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_13;
178060573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open_13;
178160573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
178260573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
178360573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
178460573Skris	channel_pre[SSH_CHANNEL_INPUT_DRAINING] =	&channel_pre_input_draining;
178560573Skris	channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_pre_output_draining;
178676262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
178776262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
178860573Skris
178992559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
179060573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
179160573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
179260573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
179360573Skris	channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_post_output_drain_13;
179476262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
179592559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
179660573Skris}
179760573Skris
179892559Sdesstatic void
179960573Skrischannel_handler_init_15(void)
180060573Skris{
180192559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
180260573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
180360573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
180460573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
180560573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
180676262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
180776262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
180860573Skris
180960573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
181060573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
181160573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
181292559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
181376262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
181492559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
181560573Skris}
181660573Skris
181792559Sdesstatic void
181860573Skrischannel_handler_init(void)
181960573Skris{
182060573Skris	int i;
1821106130Sdes
182292559Sdes	for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
182360573Skris		channel_pre[i] = NULL;
182460573Skris		channel_post[i] = NULL;
182560573Skris	}
182660573Skris	if (compat20)
182760573Skris		channel_handler_init_20();
182860573Skris	else if (compat13)
182960573Skris		channel_handler_init_13();
183060573Skris	else
183160573Skris		channel_handler_init_15();
183260573Skris}
183360573Skris
183492559Sdes/* gc dead channels */
183592559Sdesstatic void
183692559Sdeschannel_garbage_collect(Channel *c)
183792559Sdes{
183892559Sdes	if (c == NULL)
183992559Sdes		return;
184092559Sdes	if (c->detach_user != NULL) {
1841157019Sdes		if (!chan_is_dead(c, c->detach_close))
184292559Sdes			return;
1843124207Sdes		debug2("channel %d: gc: notify user", c->self);
184492559Sdes		c->detach_user(c->self, NULL);
184592559Sdes		/* if we still have a callback */
184692559Sdes		if (c->detach_user != NULL)
184792559Sdes			return;
1848124207Sdes		debug2("channel %d: gc: user detached", c->self);
184992559Sdes	}
185092559Sdes	if (!chan_is_dead(c, 1))
185192559Sdes		return;
1852124207Sdes	debug2("channel %d: garbage collecting", c->self);
185392559Sdes	channel_free(c);
185492559Sdes}
185592559Sdes
185692559Sdesstatic void
1857162856Sdeschannel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
185860573Skris{
185960573Skris	static int did_init = 0;
1860137019Sdes	u_int i;
186160573Skris	Channel *c;
186260573Skris
186360573Skris	if (!did_init) {
186460573Skris		channel_handler_init();
186560573Skris		did_init = 1;
186660573Skris	}
186760573Skris	for (i = 0; i < channels_alloc; i++) {
186892559Sdes		c = channels[i];
186992559Sdes		if (c == NULL)
187057429Smarkm			continue;
187192559Sdes		if (ftab[c->type] != NULL)
187292559Sdes			(*ftab[c->type])(c, readset, writeset);
187392559Sdes		channel_garbage_collect(c);
187457429Smarkm	}
187557429Smarkm}
187657429Smarkm
187792559Sdes/*
187892559Sdes * Allocate/update select bitmasks and add any bits relevant to channels in
187992559Sdes * select bitmasks.
188092559Sdes */
188160573Skrisvoid
188276262Sgreenchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
1883137019Sdes    u_int *nallocp, int rekeying)
188460573Skris{
1885162856Sdes	u_int n, sz, nfdset;
188676262Sgreen
188776262Sgreen	n = MAX(*maxfdp, channel_max_fd);
188876262Sgreen
1889162856Sdes	nfdset = howmany(n+1, NFDBITS);
1890162856Sdes	/* Explicitly test here, because xrealloc isn't always called */
1891162856Sdes	if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask))
1892162856Sdes		fatal("channel_prepare_select: max_fd (%d) is too large", n);
1893162856Sdes	sz = nfdset * sizeof(fd_mask);
1894162856Sdes
189592559Sdes	/* perhaps check sz < nalloc/2 and shrink? */
189692559Sdes	if (*readsetp == NULL || sz > *nallocp) {
1897162856Sdes		*readsetp = xrealloc(*readsetp, nfdset, sizeof(fd_mask));
1898162856Sdes		*writesetp = xrealloc(*writesetp, nfdset, sizeof(fd_mask));
189992559Sdes		*nallocp = sz;
190076262Sgreen	}
190192559Sdes	*maxfdp = n;
190276262Sgreen	memset(*readsetp, 0, sz);
190376262Sgreen	memset(*writesetp, 0, sz);
190476262Sgreen
190576262Sgreen	if (!rekeying)
190676262Sgreen		channel_handler(channel_pre, *readsetp, *writesetp);
190760573Skris}
190860573Skris
190992559Sdes/*
191092559Sdes * After select, perform any appropriate operations for channels which have
191192559Sdes * events pending.
191292559Sdes */
191360573Skrisvoid
1914162856Sdeschannel_after_select(fd_set *readset, fd_set *writeset)
191560573Skris{
191660573Skris	channel_handler(channel_post, readset, writeset);
191760573Skris}
191860573Skris
191992559Sdes
192076262Sgreen/* If there is data to send to the connection, enqueue some of it now. */
192160573Skrisvoid
192292559Sdeschannel_output_poll(void)
192357429Smarkm{
192460573Skris	Channel *c;
1925137019Sdes	u_int i, len;
192657429Smarkm
192757429Smarkm	for (i = 0; i < channels_alloc; i++) {
192892559Sdes		c = channels[i];
192992559Sdes		if (c == NULL)
193092559Sdes			continue;
193157429Smarkm
193292559Sdes		/*
193392559Sdes		 * We are only interested in channels that can have buffered
193492559Sdes		 * incoming data.
193592559Sdes		 */
193657429Smarkm		if (compat13) {
193760573Skris			if (c->type != SSH_CHANNEL_OPEN &&
193860573Skris			    c->type != SSH_CHANNEL_INPUT_DRAINING)
193957429Smarkm				continue;
194057429Smarkm		} else {
194160573Skris			if (c->type != SSH_CHANNEL_OPEN)
194257429Smarkm				continue;
194357429Smarkm		}
194460573Skris		if (compat20 &&
194560573Skris		    (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
194676262Sgreen			/* XXX is this true? */
194792559Sdes			debug3("channel %d: will not send data after close", c->self);
194860573Skris			continue;
194960573Skris		}
195057429Smarkm
195157429Smarkm		/* Get the amount of buffered data for this channel. */
195276262Sgreen		if ((c->istate == CHAN_INPUT_OPEN ||
195376262Sgreen		    c->istate == CHAN_INPUT_WAIT_DRAIN) &&
195476262Sgreen		    (len = buffer_len(&c->input)) > 0) {
1955157019Sdes			if (c->datagram) {
1956157019Sdes				if (len > 0) {
1957157019Sdes					u_char *data;
1958157019Sdes					u_int dlen;
1959157019Sdes
1960157019Sdes					data = buffer_get_string(&c->input,
1961157019Sdes					    &dlen);
1962157019Sdes					packet_start(SSH2_MSG_CHANNEL_DATA);
1963157019Sdes					packet_put_int(c->remote_id);
1964157019Sdes					packet_put_string(data, dlen);
1965157019Sdes					packet_send();
1966157019Sdes					c->remote_window -= dlen + 4;
1967157019Sdes					xfree(data);
1968157019Sdes				}
1969157019Sdes				continue;
1970157019Sdes			}
197192559Sdes			/*
197292559Sdes			 * Send some data for the other side over the secure
197392559Sdes			 * connection.
197492559Sdes			 */
197560573Skris			if (compat20) {
197660573Skris				if (len > c->remote_window)
197760573Skris					len = c->remote_window;
197860573Skris				if (len > c->remote_maxpacket)
197960573Skris					len = c->remote_maxpacket;
198057429Smarkm			} else {
198160573Skris				if (packet_is_interactive()) {
198260573Skris					if (len > 1024)
198360573Skris						len = 512;
198460573Skris				} else {
198560573Skris					/* Keep the packets at reasonable size. */
198660573Skris					if (len > packet_get_maxsize()/2)
198760573Skris						len = packet_get_maxsize()/2;
198860573Skris				}
198957429Smarkm			}
199060573Skris			if (len > 0) {
199160573Skris				packet_start(compat20 ?
199260573Skris				    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
199360573Skris				packet_put_int(c->remote_id);
199460573Skris				packet_put_string(buffer_ptr(&c->input), len);
199560573Skris				packet_send();
199660573Skris				buffer_consume(&c->input, len);
199760573Skris				c->remote_window -= len;
199860573Skris			}
199960573Skris		} else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
200057429Smarkm			if (compat13)
200157429Smarkm				fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
200257429Smarkm			/*
200357429Smarkm			 * input-buffer is empty and read-socket shutdown:
200498684Sdes			 * tell peer, that we will not send more data: send IEOF.
200598684Sdes			 * hack for extended data: delay EOF if EFD still in use.
200657429Smarkm			 */
200798684Sdes			if (CHANNEL_EFD_INPUT_ACTIVE(c))
2008149753Sdes				debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
2009149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
201098684Sdes			else
201198684Sdes				chan_ibuf_empty(c);
201257429Smarkm		}
201360573Skris		/* Send extended data, i.e. stderr */
201460573Skris		if (compat20 &&
201598684Sdes		    !(c->flags & CHAN_EOF_SENT) &&
201660573Skris		    c->remote_window > 0 &&
201760573Skris		    (len = buffer_len(&c->extended)) > 0 &&
201860573Skris		    c->extended_usage == CHAN_EXTENDED_READ) {
201999063Sdes			debug2("channel %d: rwin %u elen %u euse %d",
202076262Sgreen			    c->self, c->remote_window, buffer_len(&c->extended),
202176262Sgreen			    c->extended_usage);
202260573Skris			if (len > c->remote_window)
202360573Skris				len = c->remote_window;
202460573Skris			if (len > c->remote_maxpacket)
202560573Skris				len = c->remote_maxpacket;
202660573Skris			packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
202760573Skris			packet_put_int(c->remote_id);
202860573Skris			packet_put_int(SSH2_EXTENDED_DATA_STDERR);
202960573Skris			packet_put_string(buffer_ptr(&c->extended), len);
203060573Skris			packet_send();
203160573Skris			buffer_consume(&c->extended, len);
203260573Skris			c->remote_window -= len;
203376262Sgreen			debug2("channel %d: sent ext data %d", c->self, len);
203460573Skris		}
203557429Smarkm	}
203657429Smarkm}
203757429Smarkm
203857429Smarkm
203992559Sdes/* -- protocol input */
204092559Sdes
2041162856Sdes/* ARGSUSED */
204260573Skrisvoid
204392559Sdeschannel_input_data(int type, u_int32_t seq, void *ctxt)
204457429Smarkm{
204557429Smarkm	int id;
204657429Smarkm	char *data;
204776262Sgreen	u_int data_len;
204860573Skris	Channel *c;
204957429Smarkm
205057429Smarkm	/* Get the channel number and verify it. */
205157429Smarkm	id = packet_get_int();
205260573Skris	c = channel_lookup(id);
205360573Skris	if (c == NULL)
205457429Smarkm		packet_disconnect("Received data for nonexistent channel %d.", id);
205557429Smarkm
205657429Smarkm	/* Ignore any data for non-open channels (might happen on close) */
205760573Skris	if (c->type != SSH_CHANNEL_OPEN &&
205860573Skris	    c->type != SSH_CHANNEL_X11_OPEN)
205957429Smarkm		return;
206057429Smarkm
206157429Smarkm	/* Get the data. */
2062181111Sdes	data = packet_get_string_ptr(&data_len);
206360573Skris
2064126273Sdes	/*
2065126273Sdes	 * Ignore data for protocol > 1.3 if output end is no longer open.
2066126273Sdes	 * For protocol 2 the sending side is reducing its window as it sends
2067126273Sdes	 * data, so we must 'fake' consumption of the data in order to ensure
2068126273Sdes	 * that window updates are sent back.  Otherwise the connection might
2069126273Sdes	 * deadlock.
2070126273Sdes	 */
2071126273Sdes	if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
2072126273Sdes		if (compat20) {
2073126273Sdes			c->local_window -= data_len;
2074126273Sdes			c->local_consumed += data_len;
2075126273Sdes		}
2076126273Sdes		return;
2077126273Sdes	}
2078126273Sdes
207992559Sdes	if (compat20) {
208060573Skris		if (data_len > c->local_maxpacket) {
2081124207Sdes			logit("channel %d: rcvd big packet %d, maxpack %d",
208260573Skris			    c->self, data_len, c->local_maxpacket);
208360573Skris		}
208460573Skris		if (data_len > c->local_window) {
2085124207Sdes			logit("channel %d: rcvd too much data %d, win %d",
208660573Skris			    c->self, data_len, c->local_window);
208760573Skris			return;
208860573Skris		}
208960573Skris		c->local_window -= data_len;
209060573Skris	}
2091157019Sdes	if (c->datagram)
2092157019Sdes		buffer_put_string(&c->output, data, data_len);
2093157019Sdes	else
2094157019Sdes		buffer_append(&c->output, data, data_len);
2095181111Sdes	packet_check_eom();
209657429Smarkm}
209792559Sdes
2098162856Sdes/* ARGSUSED */
209960573Skrisvoid
210092559Sdeschannel_input_extended_data(int type, u_int32_t seq, void *ctxt)
210160573Skris{
210260573Skris	int id;
210360573Skris	char *data;
210499063Sdes	u_int data_len, tcode;
210560573Skris	Channel *c;
210657429Smarkm
210760573Skris	/* Get the channel number and verify it. */
210860573Skris	id = packet_get_int();
210960573Skris	c = channel_lookup(id);
211060573Skris
211160573Skris	if (c == NULL)
211260573Skris		packet_disconnect("Received extended_data for bad channel %d.", id);
211360573Skris	if (c->type != SSH_CHANNEL_OPEN) {
2114124207Sdes		logit("channel %d: ext data for non open", id);
211560573Skris		return;
211660573Skris	}
211798684Sdes	if (c->flags & CHAN_EOF_RCVD) {
211898684Sdes		if (datafellows & SSH_BUG_EXTEOF)
211998684Sdes			debug("channel %d: accepting ext data after eof", id);
212098684Sdes		else
212198684Sdes			packet_disconnect("Received extended_data after EOF "
212298684Sdes			    "on channel %d.", id);
212398684Sdes	}
212460573Skris	tcode = packet_get_int();
212560573Skris	if (c->efd == -1 ||
212660573Skris	    c->extended_usage != CHAN_EXTENDED_WRITE ||
212760573Skris	    tcode != SSH2_EXTENDED_DATA_STDERR) {
2128124207Sdes		logit("channel %d: bad ext data", c->self);
212960573Skris		return;
213060573Skris	}
213160573Skris	data = packet_get_string(&data_len);
213292559Sdes	packet_check_eom();
213360573Skris	if (data_len > c->local_window) {
2134124207Sdes		logit("channel %d: rcvd too much extended_data %d, win %d",
213560573Skris		    c->self, data_len, c->local_window);
213660573Skris		xfree(data);
213760573Skris		return;
213860573Skris	}
213969587Sgreen	debug2("channel %d: rcvd ext data %d", c->self, data_len);
214060573Skris	c->local_window -= data_len;
214160573Skris	buffer_append(&c->extended, data, data_len);
214260573Skris	xfree(data);
214360573Skris}
214460573Skris
2145162856Sdes/* ARGSUSED */
214660573Skrisvoid
214792559Sdeschannel_input_ieof(int type, u_int32_t seq, void *ctxt)
214860573Skris{
214960573Skris	int id;
215060573Skris	Channel *c;
215157429Smarkm
215260573Skris	id = packet_get_int();
215392559Sdes	packet_check_eom();
215460573Skris	c = channel_lookup(id);
215560573Skris	if (c == NULL)
215660573Skris		packet_disconnect("Received ieof for nonexistent channel %d.", id);
215760573Skris	chan_rcvd_ieof(c);
215892559Sdes
215992559Sdes	/* XXX force input close */
216092559Sdes	if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
216192559Sdes		debug("channel %d: FORCE input drain", c->self);
216292559Sdes		c->istate = CHAN_INPUT_WAIT_DRAIN;
216392559Sdes		if (buffer_len(&c->input) == 0)
216492559Sdes			chan_ibuf_empty(c);
216592559Sdes	}
216692559Sdes
216760573Skris}
216860573Skris
2169162856Sdes/* ARGSUSED */
217060573Skrisvoid
217192559Sdeschannel_input_close(int type, u_int32_t seq, void *ctxt)
217257429Smarkm{
217360573Skris	int id;
217460573Skris	Channel *c;
217557429Smarkm
217660573Skris	id = packet_get_int();
217792559Sdes	packet_check_eom();
217860573Skris	c = channel_lookup(id);
217960573Skris	if (c == NULL)
218060573Skris		packet_disconnect("Received close for nonexistent channel %d.", id);
218157429Smarkm
218257429Smarkm	/*
218357429Smarkm	 * Send a confirmation that we have closed the channel and no more
218457429Smarkm	 * data is coming for it.
218557429Smarkm	 */
218657429Smarkm	packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
218760573Skris	packet_put_int(c->remote_id);
218857429Smarkm	packet_send();
218957429Smarkm
219057429Smarkm	/*
219157429Smarkm	 * If the channel is in closed state, we have sent a close request,
219257429Smarkm	 * and the other side will eventually respond with a confirmation.
219357429Smarkm	 * Thus, we cannot free the channel here, because then there would be
219457429Smarkm	 * no-one to receive the confirmation.  The channel gets freed when
219557429Smarkm	 * the confirmation arrives.
219657429Smarkm	 */
219760573Skris	if (c->type != SSH_CHANNEL_CLOSED) {
219857429Smarkm		/*
219957429Smarkm		 * Not a closed channel - mark it as draining, which will
220057429Smarkm		 * cause it to be freed later.
220157429Smarkm		 */
220292559Sdes		buffer_clear(&c->input);
220360573Skris		c->type = SSH_CHANNEL_OUTPUT_DRAINING;
220457429Smarkm	}
220557429Smarkm}
220657429Smarkm
220760573Skris/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
2208162856Sdes/* ARGSUSED */
220960573Skrisvoid
221092559Sdeschannel_input_oclose(int type, u_int32_t seq, void *ctxt)
221160573Skris{
221260573Skris	int id = packet_get_int();
221360573Skris	Channel *c = channel_lookup(id);
221492559Sdes
221592559Sdes	packet_check_eom();
221660573Skris	if (c == NULL)
221760573Skris		packet_disconnect("Received oclose for nonexistent channel %d.", id);
221860573Skris	chan_rcvd_oclose(c);
221960573Skris}
222057429Smarkm
2221162856Sdes/* ARGSUSED */
222260573Skrisvoid
222392559Sdeschannel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
222457429Smarkm{
222560573Skris	int id = packet_get_int();
222660573Skris	Channel *c = channel_lookup(id);
222757429Smarkm
222892559Sdes	packet_check_eom();
222960573Skris	if (c == NULL)
223060573Skris		packet_disconnect("Received close confirmation for "
223160573Skris		    "out-of-range channel %d.", id);
223260573Skris	if (c->type != SSH_CHANNEL_CLOSED)
223360573Skris		packet_disconnect("Received close confirmation for "
223460573Skris		    "non-closed channel %d (type %d).", id, c->type);
223592559Sdes	channel_free(c);
223660573Skris}
223757429Smarkm
2238162856Sdes/* ARGSUSED */
223960573Skrisvoid
224092559Sdeschannel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
224160573Skris{
224260573Skris	int id, remote_id;
224360573Skris	Channel *c;
224460573Skris
224560573Skris	id = packet_get_int();
224660573Skris	c = channel_lookup(id);
224760573Skris
224860573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
224960573Skris		packet_disconnect("Received open confirmation for "
225060573Skris		    "non-opening channel %d.", id);
225160573Skris	remote_id = packet_get_int();
225260573Skris	/* Record the remote channel number and mark that the channel is now open. */
225360573Skris	c->remote_id = remote_id;
225460573Skris	c->type = SSH_CHANNEL_OPEN;
225560573Skris
225660573Skris	if (compat20) {
225760573Skris		c->remote_window = packet_get_int();
225860573Skris		c->remote_maxpacket = packet_get_int();
2259181111Sdes		if (c->open_confirm) {
226069587Sgreen			debug2("callback start");
2261181111Sdes			c->open_confirm(c->self, c->open_confirm_ctx);
226269587Sgreen			debug2("callback done");
226360573Skris		}
2264124207Sdes		debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
226560573Skris		    c->remote_window, c->remote_maxpacket);
226657429Smarkm	}
226792559Sdes	packet_check_eom();
226857429Smarkm}
226957429Smarkm
227092559Sdesstatic char *
227192559Sdesreason2txt(int reason)
227292559Sdes{
227392559Sdes	switch (reason) {
227492559Sdes	case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
227592559Sdes		return "administratively prohibited";
227692559Sdes	case SSH2_OPEN_CONNECT_FAILED:
227792559Sdes		return "connect failed";
227892559Sdes	case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
227992559Sdes		return "unknown channel type";
228092559Sdes	case SSH2_OPEN_RESOURCE_SHORTAGE:
228192559Sdes		return "resource shortage";
228292559Sdes	}
228392559Sdes	return "unknown reason";
228492559Sdes}
228592559Sdes
2286162856Sdes/* ARGSUSED */
228760573Skrisvoid
228892559Sdeschannel_input_open_failure(int type, u_int32_t seq, void *ctxt)
228957429Smarkm{
229076262Sgreen	int id, reason;
229176262Sgreen	char *msg = NULL, *lang = NULL;
229260573Skris	Channel *c;
229357429Smarkm
229460573Skris	id = packet_get_int();
229560573Skris	c = channel_lookup(id);
229657429Smarkm
229760573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
229860573Skris		packet_disconnect("Received open failure for "
229960573Skris		    "non-opening channel %d.", id);
230060573Skris	if (compat20) {
230176262Sgreen		reason = packet_get_int();
230292559Sdes		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
230376262Sgreen			msg  = packet_get_string(NULL);
230476262Sgreen			lang = packet_get_string(NULL);
230576262Sgreen		}
2306124207Sdes		logit("channel %d: open failed: %s%s%s", id,
230792559Sdes		    reason2txt(reason), msg ? ": ": "", msg ? msg : "");
230876262Sgreen		if (msg != NULL)
230976262Sgreen			xfree(msg);
231076262Sgreen		if (lang != NULL)
231176262Sgreen			xfree(lang);
231260573Skris	}
231392559Sdes	packet_check_eom();
231460573Skris	/* Free the channel.  This will also close the socket. */
231592559Sdes	channel_free(c);
231657429Smarkm}
231757429Smarkm
2318162856Sdes/* ARGSUSED */
231960573Skrisvoid
232092559Sdeschannel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
232160573Skris{
232260573Skris	Channel *c;
232399063Sdes	int id;
232499063Sdes	u_int adjust;
232557429Smarkm
232660573Skris	if (!compat20)
232760573Skris		return;
232860573Skris
232957429Smarkm	/* Get the channel number and verify it. */
233060573Skris	id = packet_get_int();
233160573Skris	c = channel_lookup(id);
233257429Smarkm
2333157019Sdes	if (c == NULL) {
2334157019Sdes		logit("Received window adjust for non-open channel %d.", id);
233560573Skris		return;
233660573Skris	}
233760573Skris	adjust = packet_get_int();
233892559Sdes	packet_check_eom();
233999063Sdes	debug2("channel %d: rcvd adjust %u", id, adjust);
234060573Skris	c->remote_window += adjust;
234157429Smarkm}
234257429Smarkm
2343162856Sdes/* ARGSUSED */
234460573Skrisvoid
234592559Sdeschannel_input_port_open(int type, u_int32_t seq, void *ctxt)
234657429Smarkm{
234792559Sdes	Channel *c = NULL;
234892559Sdes	u_short host_port;
234992559Sdes	char *host, *originator_string;
2350181111Sdes	int remote_id;
235157429Smarkm
235292559Sdes	remote_id = packet_get_int();
235392559Sdes	host = packet_get_string(NULL);
235492559Sdes	host_port = packet_get_int();
235557429Smarkm
235692559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
235792559Sdes		originator_string = packet_get_string(NULL);
235892559Sdes	} else {
235992559Sdes		originator_string = xstrdup("unknown (remote did not supply name)");
236092559Sdes	}
236192559Sdes	packet_check_eom();
2362181111Sdes	c = channel_connect_to(host, host_port,
2363181111Sdes	    "connected socket", originator_string);
2364124207Sdes	xfree(originator_string);
2365181111Sdes	xfree(host);
236692559Sdes	if (c == NULL) {
236792559Sdes		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
236892559Sdes		packet_put_int(remote_id);
236992559Sdes		packet_send();
2370181111Sdes	} else
2371181111Sdes		c->remote_id = remote_id;
237257429Smarkm}
237357429Smarkm
2374181111Sdes/* ARGSUSED */
2375181111Sdesvoid
2376181111Sdeschannel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2377181111Sdes{
2378181111Sdes	Channel *c;
2379181111Sdes	struct channel_confirm *cc;
2380181111Sdes	int remote_id;
238157429Smarkm
2382181111Sdes	/* Reset keepalive timeout */
2383181111Sdes	keep_alive_timeouts = 0;
2384181111Sdes
2385181111Sdes	remote_id = packet_get_int();
2386181111Sdes	packet_check_eom();
2387181111Sdes
2388181111Sdes	debug2("channel_input_confirm: type %d id %d", type, remote_id);
2389181111Sdes
2390181111Sdes	if ((c = channel_lookup(remote_id)) == NULL) {
2391181111Sdes		logit("channel_input_success_failure: %d: unknown", remote_id);
2392181111Sdes		return;
2393181111Sdes	}
2394181111Sdes	;
2395181111Sdes	if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
2396181111Sdes		return;
2397181111Sdes	cc->cb(type, c, cc->ctx);
2398181111Sdes	TAILQ_REMOVE(&c->status_confirms, cc, entry);
2399181111Sdes	bzero(cc, sizeof(*cc));
2400181111Sdes	xfree(cc);
2401181111Sdes}
2402181111Sdes
240392559Sdes/* -- tcp forwarding */
240457429Smarkm
240592559Sdesvoid
240692559Sdeschannel_set_af(int af)
240776262Sgreen{
240892559Sdes	IPv4or6 = af;
240976262Sgreen}
241076262Sgreen
241192559Sdesstatic int
241292559Sdeschannel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port,
241392559Sdes    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
241457429Smarkm{
241592559Sdes	Channel *c;
2416157019Sdes	int sock, r, success = 0, wildcard = 0, is_client;
241757429Smarkm	struct addrinfo hints, *ai, *aitop;
2418147005Sdes	const char *host, *addr;
241957429Smarkm	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
242057429Smarkm
242192559Sdes	host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
242292559Sdes	    listen_addr : host_to_connect;
2423147005Sdes	is_client = (type == SSH_CHANNEL_PORT_LISTENER);
242457429Smarkm
242592559Sdes	if (host == NULL) {
242692559Sdes		error("No forward host name.");
2427149753Sdes		return 0;
242876262Sgreen	}
242992559Sdes	if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
243076262Sgreen		error("Forward host name too long.");
2431149753Sdes		return 0;
243276262Sgreen	}
243376262Sgreen
243457429Smarkm	/*
2435147005Sdes	 * Determine whether or not a port forward listens to loopback,
2436147005Sdes	 * specified address or wildcard. On the client, a specified bind
2437147005Sdes	 * address will always override gateway_ports. On the server, a
2438147005Sdes	 * gateway_ports of 1 (``yes'') will override the client's
2439147005Sdes	 * specification and force a wildcard bind, whereas a value of 2
2440147005Sdes	 * (``clientspecified'') will bind to whatever address the client
2441147005Sdes	 * asked for.
2442147005Sdes	 *
2443147005Sdes	 * Special-case listen_addrs are:
2444147005Sdes	 *
2445147005Sdes	 * "0.0.0.0"               -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2446147005Sdes	 * "" (empty string), "*"  -> wildcard v4/v6
2447147005Sdes	 * "localhost"             -> loopback v4/v6
2448147005Sdes	 */
2449147005Sdes	addr = NULL;
2450147005Sdes	if (listen_addr == NULL) {
2451147005Sdes		/* No address specified: default to gateway_ports setting */
2452147005Sdes		if (gateway_ports)
2453147005Sdes			wildcard = 1;
2454147005Sdes	} else if (gateway_ports || is_client) {
2455147005Sdes		if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2456181111Sdes		    strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2457147005Sdes		    *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2458147005Sdes		    (!is_client && gateway_ports == 1))
2459147005Sdes			wildcard = 1;
2460147005Sdes		else if (strcmp(listen_addr, "localhost") != 0)
2461147005Sdes			addr = listen_addr;
2462147005Sdes	}
2463147005Sdes
2464147005Sdes	debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
2465147005Sdes	    type, wildcard, (addr == NULL) ? "NULL" : addr);
2466147005Sdes
2467147005Sdes	/*
246857429Smarkm	 * getaddrinfo returns a loopback address if the hostname is
246957429Smarkm	 * set to NULL and hints.ai_flags is not AI_PASSIVE
247057429Smarkm	 */
247157429Smarkm	memset(&hints, 0, sizeof(hints));
247257429Smarkm	hints.ai_family = IPv4or6;
2473147005Sdes	hints.ai_flags = wildcard ? AI_PASSIVE : 0;
247457429Smarkm	hints.ai_socktype = SOCK_STREAM;
247576262Sgreen	snprintf(strport, sizeof strport, "%d", listen_port);
2476147005Sdes	if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
2477147005Sdes		if (addr == NULL) {
2478147005Sdes			/* This really shouldn't happen */
2479147005Sdes			packet_disconnect("getaddrinfo: fatal error: %s",
2480181111Sdes			    ssh_gai_strerror(r));
2481147005Sdes		} else {
2482149753Sdes			error("channel_setup_fwd_listener: "
2483181111Sdes			    "getaddrinfo(%.64s): %s", addr,
2484181111Sdes			    ssh_gai_strerror(r));
2485147005Sdes		}
2486149753Sdes		return 0;
2487147005Sdes	}
248857429Smarkm
248957429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
249057429Smarkm		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
249157429Smarkm			continue;
249257429Smarkm		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
249357429Smarkm		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
249492559Sdes			error("channel_setup_fwd_listener: getnameinfo failed");
249557429Smarkm			continue;
249657429Smarkm		}
249757429Smarkm		/* Create a port to listen for the host. */
2498124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
249957429Smarkm		if (sock < 0) {
250057429Smarkm			/* this is no error since kernel may not support ipv6 */
250157429Smarkm			verbose("socket: %.100s", strerror(errno));
250257429Smarkm			continue;
250357429Smarkm		}
2504106130Sdes
2505157019Sdes		channel_set_reuseaddr(sock);
2506157019Sdes
250757429Smarkm		debug("Local forwarding listening on %s port %s.", ntop, strport);
250857429Smarkm
250957429Smarkm		/* Bind the socket to the address. */
251057429Smarkm		if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
251157429Smarkm			/* address can be in use ipv6 address is already bound */
251298941Sdes			if (!ai->ai_next)
251398941Sdes				error("bind: %.100s", strerror(errno));
251498941Sdes			else
251598941Sdes				verbose("bind: %.100s", strerror(errno));
251698941Sdes
251757429Smarkm			close(sock);
251857429Smarkm			continue;
251957429Smarkm		}
252057429Smarkm		/* Start listening for connections on the socket. */
2521126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
252257429Smarkm			error("listen: %.100s", strerror(errno));
252357429Smarkm			close(sock);
252457429Smarkm			continue;
252557429Smarkm		}
252657429Smarkm		/* Allocate a channel number for the socket. */
252792559Sdes		c = channel_new("port listener", type, sock, sock, -1,
252860573Skris		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2529124207Sdes		    0, "port listener", 1);
253092559Sdes		strlcpy(c->path, host, sizeof(c->path));
253192559Sdes		c->host_port = port_to_connect;
253292559Sdes		c->listening_port = listen_port;
253357429Smarkm		success = 1;
253457429Smarkm	}
253557429Smarkm	if (success == 0)
253692559Sdes		error("channel_setup_fwd_listener: cannot listen to port: %d",
253776262Sgreen		    listen_port);
253857429Smarkm	freeaddrinfo(aitop);
253976262Sgreen	return success;
254057429Smarkm}
254157429Smarkm
2542137019Sdesint
2543137019Sdeschannel_cancel_rport_listener(const char *host, u_short port)
2544137019Sdes{
2545137019Sdes	u_int i;
2546137019Sdes	int found = 0;
2547137019Sdes
2548147005Sdes	for (i = 0; i < channels_alloc; i++) {
2549137019Sdes		Channel *c = channels[i];
2550137019Sdes
2551137019Sdes		if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER &&
2552137019Sdes		    strncmp(c->path, host, sizeof(c->path)) == 0 &&
2553137019Sdes		    c->listening_port == port) {
2554147005Sdes			debug2("%s: close channel %d", __func__, i);
2555137019Sdes			channel_free(c);
2556137019Sdes			found = 1;
2557137019Sdes		}
2558137019Sdes	}
2559137019Sdes
2560137019Sdes	return (found);
2561137019Sdes}
2562137019Sdes
256392559Sdes/* protocol local port fwd, used by ssh (and sshd in v1) */
256492559Sdesint
2565147005Sdeschannel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
256692559Sdes    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
256792559Sdes{
256892559Sdes	return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
2569147005Sdes	    listen_host, listen_port, host_to_connect, port_to_connect,
2570147005Sdes	    gateway_ports);
257192559Sdes}
257292559Sdes
257392559Sdes/* protocol v2 remote port fwd, used by sshd */
257492559Sdesint
257592559Sdeschannel_setup_remote_fwd_listener(const char *listen_address,
257692559Sdes    u_short listen_port, int gateway_ports)
257792559Sdes{
257892559Sdes	return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
257992559Sdes	    listen_address, listen_port, NULL, 0, gateway_ports);
258092559Sdes}
258192559Sdes
258257429Smarkm/*
258357429Smarkm * Initiate forwarding of connections to port "port" on remote host through
258457429Smarkm * the secure channel to host:port from local side.
258557429Smarkm */
258657429Smarkm
2587162856Sdesint
2588147005Sdeschannel_request_remote_forwarding(const char *listen_host, u_short listen_port,
258976262Sgreen    const char *host_to_connect, u_short port_to_connect)
259057429Smarkm{
259192559Sdes	int type, success = 0;
259276262Sgreen
259357429Smarkm	/* Record locally that connection to this host/port is permitted. */
259457429Smarkm	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
259557429Smarkm		fatal("channel_request_remote_forwarding: too many forwards");
259657429Smarkm
259757429Smarkm	/* Send the forward request to the remote side. */
259860573Skris	if (compat20) {
2599147005Sdes		const char *address_to_bind;
2600181111Sdes		if (listen_host == NULL) {
2601181111Sdes			if (datafellows & SSH_BUG_RFWD_ADDR)
2602181111Sdes				address_to_bind = "127.0.0.1";
2603181111Sdes			else
2604181111Sdes				address_to_bind = "localhost";
2605181111Sdes		} else if (*listen_host == '\0' ||
2606181111Sdes			   strcmp(listen_host, "*") == 0) {
2607181111Sdes			if (datafellows & SSH_BUG_RFWD_ADDR)
2608181111Sdes				address_to_bind = "0.0.0.0";
2609181111Sdes			else
2610181111Sdes				address_to_bind = "";
2611181111Sdes		} else
2612147005Sdes			address_to_bind = listen_host;
2613147005Sdes
261460573Skris		packet_start(SSH2_MSG_GLOBAL_REQUEST);
261560573Skris		packet_put_cstring("tcpip-forward");
261698684Sdes		packet_put_char(1);			/* boolean: want reply */
261760573Skris		packet_put_cstring(address_to_bind);
261860573Skris		packet_put_int(listen_port);
261976262Sgreen		packet_send();
262076262Sgreen		packet_write_wait();
262176262Sgreen		/* Assume that server accepts the request */
262276262Sgreen		success = 1;
262360573Skris	} else {
262460573Skris		packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
262560573Skris		packet_put_int(listen_port);
262660573Skris		packet_put_cstring(host_to_connect);
262760573Skris		packet_put_int(port_to_connect);
262860573Skris		packet_send();
262960573Skris		packet_write_wait();
263076262Sgreen
263176262Sgreen		/* Wait for response from the remote side. */
263292559Sdes		type = packet_read();
263376262Sgreen		switch (type) {
263476262Sgreen		case SSH_SMSG_SUCCESS:
263576262Sgreen			success = 1;
263676262Sgreen			break;
263776262Sgreen		case SSH_SMSG_FAILURE:
263876262Sgreen			break;
263976262Sgreen		default:
264076262Sgreen			/* Unknown packet */
264176262Sgreen			packet_disconnect("Protocol error for port forward request:"
264276262Sgreen			    "received packet type %d.", type);
264376262Sgreen		}
264460573Skris	}
264576262Sgreen	if (success) {
264676262Sgreen		permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
264776262Sgreen		permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
264876262Sgreen		permitted_opens[num_permitted_opens].listen_port = listen_port;
264976262Sgreen		num_permitted_opens++;
265076262Sgreen	}
2651162856Sdes	return (success ? 0 : -1);
265257429Smarkm}
265357429Smarkm
265457429Smarkm/*
2655137019Sdes * Request cancellation of remote forwarding of connection host:port from
2656137019Sdes * local side.
2657137019Sdes */
2658137019Sdesvoid
2659147005Sdeschannel_request_rforward_cancel(const char *host, u_short port)
2660137019Sdes{
2661137019Sdes	int i;
2662137019Sdes
2663137019Sdes	if (!compat20)
2664137019Sdes		return;
2665137019Sdes
2666137019Sdes	for (i = 0; i < num_permitted_opens; i++) {
2667137019Sdes		if (permitted_opens[i].host_to_connect != NULL &&
2668137019Sdes		    permitted_opens[i].listen_port == port)
2669137019Sdes			break;
2670137019Sdes	}
2671137019Sdes	if (i >= num_permitted_opens) {
2672137019Sdes		debug("%s: requested forward not found", __func__);
2673137019Sdes		return;
2674137019Sdes	}
2675137019Sdes	packet_start(SSH2_MSG_GLOBAL_REQUEST);
2676137019Sdes	packet_put_cstring("cancel-tcpip-forward");
2677137019Sdes	packet_put_char(0);
2678147005Sdes	packet_put_cstring(host == NULL ? "" : host);
2679137019Sdes	packet_put_int(port);
2680137019Sdes	packet_send();
2681137019Sdes
2682137019Sdes	permitted_opens[i].listen_port = 0;
2683137019Sdes	permitted_opens[i].port_to_connect = 0;
2684157019Sdes	xfree(permitted_opens[i].host_to_connect);
2685137019Sdes	permitted_opens[i].host_to_connect = NULL;
2686137019Sdes}
2687137019Sdes
2688137019Sdes/*
268957429Smarkm * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
269057429Smarkm * listening for the port, and sends back a success reply (or disconnect
2691162856Sdes * message if there was an error).
269257429Smarkm */
2693162856Sdesint
269460573Skrischannel_input_port_forward_request(int is_root, int gateway_ports)
269557429Smarkm{
269657429Smarkm	u_short port, host_port;
2697162856Sdes	int success = 0;
269857429Smarkm	char *hostname;
269957429Smarkm
270057429Smarkm	/* Get arguments from the packet. */
270157429Smarkm	port = packet_get_int();
270257429Smarkm	hostname = packet_get_string(NULL);
270357429Smarkm	host_port = packet_get_int();
270457429Smarkm
270598941Sdes#ifndef HAVE_CYGWIN
270657429Smarkm	/*
270757429Smarkm	 * Check that an unprivileged user is not trying to forward a
270857429Smarkm	 * privileged port.
270957429Smarkm	 */
271057429Smarkm	if (port < IPPORT_RESERVED && !is_root)
2711124207Sdes		packet_disconnect(
2712124207Sdes		    "Requested forwarding of port %d but user is not root.",
2713124207Sdes		    port);
2714124207Sdes	if (host_port == 0)
2715124207Sdes		packet_disconnect("Dynamic forwarding denied.");
271698941Sdes#endif
2717124207Sdes
271876262Sgreen	/* Initiate forwarding */
2719162856Sdes	success = channel_setup_local_fwd_listener(NULL, port, hostname,
2720147005Sdes	    host_port, gateway_ports);
272157429Smarkm
272257429Smarkm	/* Free the argument string. */
272357429Smarkm	xfree(hostname);
2724162856Sdes
2725162856Sdes	return (success ? 0 : -1);
272657429Smarkm}
272757429Smarkm
272876262Sgreen/*
272976262Sgreen * Permits opening to any host/port if permitted_opens[] is empty.  This is
273076262Sgreen * usually called by the server, because the user could connect to any port
273176262Sgreen * anyway, and the server has no way to know but to trust the client anyway.
273276262Sgreen */
273376262Sgreenvoid
273492559Sdeschannel_permit_all_opens(void)
273576262Sgreen{
273676262Sgreen	if (num_permitted_opens == 0)
273776262Sgreen		all_opens_permitted = 1;
273876262Sgreen}
273976262Sgreen
274076262Sgreenvoid
274176262Sgreenchannel_add_permitted_opens(char *host, int port)
274276262Sgreen{
274376262Sgreen	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
2744162856Sdes		fatal("channel_add_permitted_opens: too many forwards");
274576262Sgreen	debug("allow port forwarding to host %s port %d", host, port);
274676262Sgreen
274776262Sgreen	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
274876262Sgreen	permitted_opens[num_permitted_opens].port_to_connect = port;
274976262Sgreen	num_permitted_opens++;
275076262Sgreen
275176262Sgreen	all_opens_permitted = 0;
275276262Sgreen}
275376262Sgreen
2754162856Sdesint
2755162856Sdeschannel_add_adm_permitted_opens(char *host, int port)
2756162856Sdes{
2757162856Sdes	if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
2758162856Sdes		fatal("channel_add_adm_permitted_opens: too many forwards");
2759162856Sdes	debug("config allows port forwarding to host %s port %d", host, port);
2760162856Sdes
2761162856Sdes	permitted_adm_opens[num_adm_permitted_opens].host_to_connect
2762162856Sdes	     = xstrdup(host);
2763162856Sdes	permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
2764162856Sdes	return ++num_adm_permitted_opens;
2765162856Sdes}
2766162856Sdes
276776262Sgreenvoid
276876262Sgreenchannel_clear_permitted_opens(void)
276976262Sgreen{
277076262Sgreen	int i;
277176262Sgreen
277276262Sgreen	for (i = 0; i < num_permitted_opens; i++)
2773137019Sdes		if (permitted_opens[i].host_to_connect != NULL)
2774137019Sdes			xfree(permitted_opens[i].host_to_connect);
277576262Sgreen	num_permitted_opens = 0;
2776162856Sdes}
277776262Sgreen
2778162856Sdesvoid
2779162856Sdeschannel_clear_adm_permitted_opens(void)
2780162856Sdes{
2781162856Sdes	int i;
2782162856Sdes
2783162856Sdes	for (i = 0; i < num_adm_permitted_opens; i++)
2784162856Sdes		if (permitted_adm_opens[i].host_to_connect != NULL)
2785162856Sdes			xfree(permitted_adm_opens[i].host_to_connect);
2786162856Sdes	num_adm_permitted_opens = 0;
278776262Sgreen}
278876262Sgreen
2789181111Sdesvoid
2790181111Sdeschannel_print_adm_permitted_opens(void)
2791181111Sdes{
2792181111Sdes	int i;
2793181111Sdes
2794181111Sdes	for (i = 0; i < num_adm_permitted_opens; i++)
2795181111Sdes		if (permitted_adm_opens[i].host_to_connect != NULL)
2796181111Sdes			printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
2797181111Sdes			    permitted_adm_opens[i].port_to_connect);
2798181111Sdes}
2799181111Sdes
2800181111Sdes/* Try to start non-blocking connect to next host in cctx list */
280192559Sdesstatic int
2802181111Sdesconnect_next(struct channel_connect *cctx)
280360573Skris{
2804181111Sdes	int sock, saved_errno;
280560573Skris	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
280660573Skris
2807181111Sdes	for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
2808181111Sdes		if (cctx->ai->ai_family != AF_INET &&
2809181111Sdes		    cctx->ai->ai_family != AF_INET6)
281060573Skris			continue;
2811181111Sdes		if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
2812181111Sdes		    ntop, sizeof(ntop), strport, sizeof(strport),
2813181111Sdes		    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2814181111Sdes			error("connect_next: getnameinfo failed");
281560573Skris			continue;
281660573Skris		}
2817181111Sdes		if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
2818181111Sdes		    cctx->ai->ai_protocol)) == -1) {
2819181111Sdes			if (cctx->ai->ai_next == NULL)
2820113911Sdes				error("socket: %.100s", strerror(errno));
2821113911Sdes			else
2822113911Sdes				verbose("socket: %.100s", strerror(errno));
282360573Skris			continue;
282460573Skris		}
2825137019Sdes		if (set_nonblock(sock) == -1)
2826137019Sdes			fatal("%s: set_nonblock(%d)", __func__, sock);
2827181111Sdes		if (connect(sock, cctx->ai->ai_addr,
2828181111Sdes		    cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
2829181111Sdes			debug("connect_next: host %.100s ([%.100s]:%s): "
2830181111Sdes			    "%.100s", cctx->host, ntop, strport,
283160573Skris			    strerror(errno));
2832181111Sdes			saved_errno = errno;
283360573Skris			close(sock);
2834181111Sdes			errno = saved_errno;
283576262Sgreen			continue;	/* fail -- try next */
283660573Skris		}
2837181111Sdes		debug("connect_next: host %.100s ([%.100s]:%s) "
2838181111Sdes		    "in progress, fd=%d", cctx->host, ntop, strport, sock);
2839181111Sdes		cctx->ai = cctx->ai->ai_next;
2840181111Sdes		set_nodelay(sock);
2841181111Sdes		return sock;
2842181111Sdes	}
2843181111Sdes	return -1;
2844181111Sdes}
284560573Skris
2846181111Sdesstatic void
2847181111Sdeschannel_connect_ctx_free(struct channel_connect *cctx)
2848181111Sdes{
2849181111Sdes	xfree(cctx->host);
2850181111Sdes	if (cctx->aitop)
2851181111Sdes		freeaddrinfo(cctx->aitop);
2852181111Sdes	bzero(cctx, sizeof(*cctx));
2853181111Sdes	cctx->host = NULL;
2854181111Sdes	cctx->ai = cctx->aitop = NULL;
2855181111Sdes}
2856181111Sdes
2857181111Sdes/* Return CONNECTING channel to remote host, port */
2858181111Sdesstatic Channel *
2859181111Sdesconnect_to(const char *host, u_short port, char *ctype, char *rname)
2860181111Sdes{
2861181111Sdes	struct addrinfo hints;
2862181111Sdes	int gaierr;
2863181111Sdes	int sock = -1;
2864181111Sdes	char strport[NI_MAXSERV];
2865181111Sdes	struct channel_connect cctx;
2866181111Sdes	Channel *c;
2867181111Sdes
2868181111Sdes	memset(&cctx, 0, sizeof(cctx));
2869181111Sdes	memset(&hints, 0, sizeof(hints));
2870181111Sdes	hints.ai_family = IPv4or6;
2871181111Sdes	hints.ai_socktype = SOCK_STREAM;
2872181111Sdes	snprintf(strport, sizeof strport, "%d", port);
2873181111Sdes	if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
2874181111Sdes		error("connect_to %.100s: unknown host (%s)", host,
2875181111Sdes		    ssh_gai_strerror(gaierr));
2876181111Sdes		return NULL;
287760573Skris	}
2878181111Sdes
2879181111Sdes	cctx.host = xstrdup(host);
2880181111Sdes	cctx.port = port;
2881181111Sdes	cctx.ai = cctx.aitop;
2882181111Sdes
2883181111Sdes	if ((sock = connect_next(&cctx)) == -1) {
2884181111Sdes		error("connect to %.100s port %d failed: %s",
2885181111Sdes		    host, port, strerror(errno));
2886181111Sdes		channel_connect_ctx_free(&cctx);
2887181111Sdes		return NULL;
288860573Skris	}
2889181111Sdes	c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
2890181111Sdes	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
2891181111Sdes	c->connect_ctx = cctx;
2892181111Sdes	return c;
289360573Skris}
289476262Sgreen
2895181111SdesChannel *
2896181111Sdeschannel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
289776262Sgreen{
289876262Sgreen	int i;
289976262Sgreen
2900181111Sdes	for (i = 0; i < num_permitted_opens; i++) {
2901137019Sdes		if (permitted_opens[i].host_to_connect != NULL &&
2902181111Sdes		    permitted_opens[i].listen_port == listen_port) {
290376262Sgreen			return connect_to(
290476262Sgreen			    permitted_opens[i].host_to_connect,
2905181111Sdes			    permitted_opens[i].port_to_connect, ctype, rname);
2906181111Sdes		}
2907181111Sdes	}
290876262Sgreen	error("WARNING: Server requests forwarding for unknown listen_port %d",
290976262Sgreen	    listen_port);
2910181111Sdes	return NULL;
291176262Sgreen}
291276262Sgreen
291376262Sgreen/* Check if connecting to that port is permitted and connect. */
2914181111SdesChannel *
2915181111Sdeschannel_connect_to(const char *host, u_short port, char *ctype, char *rname)
291676262Sgreen{
2917162856Sdes	int i, permit, permit_adm = 1;
291876262Sgreen
291976262Sgreen	permit = all_opens_permitted;
292076262Sgreen	if (!permit) {
292176262Sgreen		for (i = 0; i < num_permitted_opens; i++)
2922137019Sdes			if (permitted_opens[i].host_to_connect != NULL &&
2923137019Sdes			    permitted_opens[i].port_to_connect == port &&
292476262Sgreen			    strcmp(permitted_opens[i].host_to_connect, host) == 0)
292576262Sgreen				permit = 1;
2926162856Sdes	}
292776262Sgreen
2928162856Sdes	if (num_adm_permitted_opens > 0) {
2929162856Sdes		permit_adm = 0;
2930162856Sdes		for (i = 0; i < num_adm_permitted_opens; i++)
2931162856Sdes			if (permitted_adm_opens[i].host_to_connect != NULL &&
2932162856Sdes			    permitted_adm_opens[i].port_to_connect == port &&
2933162856Sdes			    strcmp(permitted_adm_opens[i].host_to_connect, host)
2934162856Sdes			    == 0)
2935162856Sdes				permit_adm = 1;
293676262Sgreen	}
2937162856Sdes
2938162856Sdes	if (!permit || !permit_adm) {
2939124207Sdes		logit("Received request to connect to host %.100s port %d, "
294076262Sgreen		    "but the request was denied.", host, port);
2941181111Sdes		return NULL;
294276262Sgreen	}
2943181111Sdes	return connect_to(host, port, ctype, rname);
294476262Sgreen}
294576262Sgreen
2946137019Sdesvoid
2947137019Sdeschannel_send_window_changes(void)
2948137019Sdes{
2949137019Sdes	u_int i;
2950137019Sdes	struct winsize ws;
2951137019Sdes
2952137019Sdes	for (i = 0; i < channels_alloc; i++) {
2953147005Sdes		if (channels[i] == NULL || !channels[i]->client_tty ||
2954137019Sdes		    channels[i]->type != SSH_CHANNEL_OPEN)
2955137019Sdes			continue;
2956137019Sdes		if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
2957137019Sdes			continue;
2958137019Sdes		channel_request_start(i, "window-change", 0);
2959162856Sdes		packet_put_int((u_int)ws.ws_col);
2960162856Sdes		packet_put_int((u_int)ws.ws_row);
2961162856Sdes		packet_put_int((u_int)ws.ws_xpixel);
2962162856Sdes		packet_put_int((u_int)ws.ws_ypixel);
2963137019Sdes		packet_send();
2964137019Sdes	}
2965137019Sdes}
2966137019Sdes
296792559Sdes/* -- X11 forwarding */
296857429Smarkm
296957429Smarkm/*
297057429Smarkm * Creates an internet domain socket for listening for X11 connections.
297199063Sdes * Returns 0 and a suitable display number for the DISPLAY variable
297299063Sdes * stored in display_numberp , or -1 if an error occurs.
297357429Smarkm */
297492559Sdesint
297592559Sdesx11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2976149753Sdes    int single_connection, u_int *display_numberp, int **chanids)
297757429Smarkm{
297892559Sdes	Channel *nc = NULL;
297957429Smarkm	int display_number, sock;
298057429Smarkm	u_short port;
298157429Smarkm	struct addrinfo hints, *ai, *aitop;
298257429Smarkm	char strport[NI_MAXSERV];
298357429Smarkm	int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
298457429Smarkm
2985157019Sdes	if (chanids == NULL)
2986157019Sdes		return -1;
2987157019Sdes
298857429Smarkm	for (display_number = x11_display_offset;
298992559Sdes	    display_number < MAX_DISPLAYS;
299092559Sdes	    display_number++) {
299157429Smarkm		port = 6000 + display_number;
299257429Smarkm		memset(&hints, 0, sizeof(hints));
299357429Smarkm		hints.ai_family = IPv4or6;
299492559Sdes		hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
299557429Smarkm		hints.ai_socktype = SOCK_STREAM;
299657429Smarkm		snprintf(strport, sizeof strport, "%d", port);
299757429Smarkm		if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
2998181111Sdes			error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
299992559Sdes			return -1;
300057429Smarkm		}
300157429Smarkm		for (ai = aitop; ai; ai = ai->ai_next) {
300257429Smarkm			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
300357429Smarkm				continue;
3004124207Sdes			sock = socket(ai->ai_family, ai->ai_socktype,
3005124207Sdes			    ai->ai_protocol);
300657429Smarkm			if (sock < 0) {
300798941Sdes				if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) {
300898941Sdes					error("socket: %.100s", strerror(errno));
3009137019Sdes					freeaddrinfo(aitop);
301098941Sdes					return -1;
301198941Sdes				} else {
301298941Sdes					debug("x11_create_display_inet: Socket family %d not supported",
301398941Sdes						 ai->ai_family);
301498941Sdes					continue;
301598941Sdes				}
301657429Smarkm			}
301798941Sdes#ifdef IPV6_V6ONLY
301898941Sdes			if (ai->ai_family == AF_INET6) {
301998941Sdes				int on = 1;
302098941Sdes				if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
302198941Sdes					error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
302298941Sdes			}
302398941Sdes#endif
3024181111Sdes			if (x11_use_localhost)
3025181111Sdes				channel_set_reuseaddr(sock);
302657429Smarkm			if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
3027124207Sdes				debug2("bind port %d: %.100s", port, strerror(errno));
302857429Smarkm				close(sock);
302998941Sdes
303057429Smarkm				for (n = 0; n < num_socks; n++) {
303157429Smarkm					close(socks[n]);
303257429Smarkm				}
303357429Smarkm				num_socks = 0;
303457429Smarkm				break;
303557429Smarkm			}
303657429Smarkm			socks[num_socks++] = sock;
303757429Smarkm			if (num_socks == NUM_SOCKS)
303857429Smarkm				break;
303957429Smarkm		}
304076262Sgreen		freeaddrinfo(aitop);
304157429Smarkm		if (num_socks > 0)
304257429Smarkm			break;
304357429Smarkm	}
304457429Smarkm	if (display_number >= MAX_DISPLAYS) {
304557429Smarkm		error("Failed to allocate internet-domain X11 display socket.");
304692559Sdes		return -1;
304757429Smarkm	}
304857429Smarkm	/* Start listening for connections on the socket. */
304957429Smarkm	for (n = 0; n < num_socks; n++) {
305057429Smarkm		sock = socks[n];
3051126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
305257429Smarkm			error("listen: %.100s", strerror(errno));
305357429Smarkm			close(sock);
305492559Sdes			return -1;
305557429Smarkm		}
305657429Smarkm	}
305757429Smarkm
305857429Smarkm	/* Allocate a channel for each socket. */
3059162856Sdes	*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
306057429Smarkm	for (n = 0; n < num_socks; n++) {
306157429Smarkm		sock = socks[n];
306292559Sdes		nc = channel_new("x11 listener",
306360573Skris		    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
306460573Skris		    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
3065124207Sdes		    0, "X11 inet listener", 1);
306692559Sdes		nc->single_connection = single_connection;
3067157019Sdes		(*chanids)[n] = nc->self;
306857429Smarkm	}
3069157019Sdes	(*chanids)[n] = -1;
307057429Smarkm
307192559Sdes	/* Return the display number for the DISPLAY environment variable. */
307299063Sdes	*display_numberp = display_number;
307399063Sdes	return (0);
307457429Smarkm}
307557429Smarkm
307692559Sdesstatic int
307776262Sgreenconnect_local_xsocket(u_int dnr)
307857429Smarkm{
307957429Smarkm	int sock;
308057429Smarkm	struct sockaddr_un addr;
308157429Smarkm
308292559Sdes	sock = socket(AF_UNIX, SOCK_STREAM, 0);
308392559Sdes	if (sock < 0)
308492559Sdes		error("socket: %.100s", strerror(errno));
308592559Sdes	memset(&addr, 0, sizeof(addr));
308692559Sdes	addr.sun_family = AF_UNIX;
308792559Sdes	snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr);
3088162856Sdes	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
308992559Sdes		return sock;
309092559Sdes	close(sock);
309157429Smarkm	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
309257429Smarkm	return -1;
309357429Smarkm}
309457429Smarkm
309560573Skrisint
309660573Skrisx11_connect_display(void)
309757429Smarkm{
3098162856Sdes	u_int display_number;
309957429Smarkm	const char *display;
310060573Skris	char buf[1024], *cp;
310157429Smarkm	struct addrinfo hints, *ai, *aitop;
310257429Smarkm	char strport[NI_MAXSERV];
3103162856Sdes	int gaierr, sock = 0;
310457429Smarkm
310557429Smarkm	/* Try to open a socket for the local X server. */
310657429Smarkm	display = getenv("DISPLAY");
310757429Smarkm	if (!display) {
310857429Smarkm		error("DISPLAY not set.");
310960573Skris		return -1;
311057429Smarkm	}
311157429Smarkm	/*
311257429Smarkm	 * Now we decode the value of the DISPLAY variable and make a
311357429Smarkm	 * connection to the real X server.
311457429Smarkm	 */
311557429Smarkm
311657429Smarkm	/*
311757429Smarkm	 * Check if it is a unix domain socket.  Unix domain displays are in
311857429Smarkm	 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
311957429Smarkm	 */
312057429Smarkm	if (strncmp(display, "unix:", 5) == 0 ||
312157429Smarkm	    display[0] == ':') {
312257429Smarkm		/* Connect to the unix domain socket. */
3123162856Sdes		if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
312457429Smarkm			error("Could not parse display number from DISPLAY: %.100s",
312592559Sdes			    display);
312660573Skris			return -1;
312757429Smarkm		}
312857429Smarkm		/* Create a socket. */
312957429Smarkm		sock = connect_local_xsocket(display_number);
313057429Smarkm		if (sock < 0)
313160573Skris			return -1;
313257429Smarkm
313357429Smarkm		/* OK, we now have a connection to the display. */
313460573Skris		return sock;
313557429Smarkm	}
313657429Smarkm	/*
313757429Smarkm	 * Connect to an inet socket.  The DISPLAY value is supposedly
313857429Smarkm	 * hostname:d[.s], where hostname may also be numeric IP address.
313957429Smarkm	 */
314092559Sdes	strlcpy(buf, display, sizeof(buf));
314157429Smarkm	cp = strchr(buf, ':');
314257429Smarkm	if (!cp) {
314357429Smarkm		error("Could not find ':' in DISPLAY: %.100s", display);
314460573Skris		return -1;
314557429Smarkm	}
314657429Smarkm	*cp = 0;
314757429Smarkm	/* buf now contains the host name.  But first we parse the display number. */
3148162856Sdes	if (sscanf(cp + 1, "%u", &display_number) != 1) {
314957429Smarkm		error("Could not parse display number from DISPLAY: %.100s",
315092559Sdes		    display);
315160573Skris		return -1;
315257429Smarkm	}
315357429Smarkm
315457429Smarkm	/* Look up the host address */
315557429Smarkm	memset(&hints, 0, sizeof(hints));
315657429Smarkm	hints.ai_family = IPv4or6;
315757429Smarkm	hints.ai_socktype = SOCK_STREAM;
3158162856Sdes	snprintf(strport, sizeof strport, "%u", 6000 + display_number);
315957429Smarkm	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
3160181111Sdes		error("%.100s: unknown host. (%s)", buf,
3161181111Sdes		ssh_gai_strerror(gaierr));
316260573Skris		return -1;
316357429Smarkm	}
316457429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
316557429Smarkm		/* Create a socket. */
3166124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
316757429Smarkm		if (sock < 0) {
3168124207Sdes			debug2("socket: %.100s", strerror(errno));
316960573Skris			continue;
317060573Skris		}
317160573Skris		/* Connect it to the display. */
317260573Skris		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
3173162856Sdes			debug2("connect %.100s port %u: %.100s", buf,
317460573Skris			    6000 + display_number, strerror(errno));
317560573Skris			close(sock);
317660573Skris			continue;
317760573Skris		}
317860573Skris		/* Success */
317960573Skris		break;
318057429Smarkm	}
318157429Smarkm	freeaddrinfo(aitop);
318257429Smarkm	if (!ai) {
3183162856Sdes		error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
318457429Smarkm		    strerror(errno));
318560573Skris		return -1;
318657429Smarkm	}
318792559Sdes	set_nodelay(sock);
318860573Skris	return sock;
318960573Skris}
319057429Smarkm
319160573Skris/*
319260573Skris * This is called when SSH_SMSG_X11_OPEN is received.  The packet contains
319360573Skris * the remote channel number.  We should do whatever we want, and respond
319460573Skris * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
319560573Skris */
319657429Smarkm
3197162856Sdes/* ARGSUSED */
319860573Skrisvoid
319992559Sdesx11_input_open(int type, u_int32_t seq, void *ctxt)
320060573Skris{
320192559Sdes	Channel *c = NULL;
320292559Sdes	int remote_id, sock = 0;
320360573Skris	char *remote_host;
320457429Smarkm
320592559Sdes	debug("Received X11 open request.");
320657429Smarkm
320792559Sdes	remote_id = packet_get_int();
320892559Sdes
320992559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
321092559Sdes		remote_host = packet_get_string(NULL);
321160573Skris	} else {
321260573Skris		remote_host = xstrdup("unknown (remote did not supply name)");
321360573Skris	}
321492559Sdes	packet_check_eom();
321560573Skris
321660573Skris	/* Obtain a connection to the real X display. */
321760573Skris	sock = x11_connect_display();
321892559Sdes	if (sock != -1) {
321992559Sdes		/* Allocate a channel for this connection. */
322092559Sdes		c = channel_new("connected x11 socket",
322192559Sdes		    SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
322292559Sdes		    remote_host, 1);
322392559Sdes		c->remote_id = remote_id;
322492559Sdes		c->force_drain = 1;
322592559Sdes	}
3226124207Sdes	xfree(remote_host);
322792559Sdes	if (c == NULL) {
322860573Skris		/* Send refusal to the remote host. */
322960573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
323092559Sdes		packet_put_int(remote_id);
323160573Skris	} else {
323260573Skris		/* Send a confirmation to the remote host. */
323360573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
323492559Sdes		packet_put_int(remote_id);
323592559Sdes		packet_put_int(c->self);
323660573Skris	}
323792559Sdes	packet_send();
323857429Smarkm}
323957429Smarkm
324069587Sgreen/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
3241162856Sdes/* ARGSUSED */
324269587Sgreenvoid
324392559Sdesdeny_input_open(int type, u_int32_t seq, void *ctxt)
324469587Sgreen{
324569587Sgreen	int rchan = packet_get_int();
3246106130Sdes
324792559Sdes	switch (type) {
324869587Sgreen	case SSH_SMSG_AGENT_OPEN:
324969587Sgreen		error("Warning: ssh server tried agent forwarding.");
325069587Sgreen		break;
325169587Sgreen	case SSH_SMSG_X11_OPEN:
325269587Sgreen		error("Warning: ssh server tried X11 forwarding.");
325369587Sgreen		break;
325469587Sgreen	default:
325592559Sdes		error("deny_input_open: type %d", type);
325669587Sgreen		break;
325769587Sgreen	}
3258157019Sdes	error("Warning: this is probably a break-in attempt by a malicious server.");
325969587Sgreen	packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
326069587Sgreen	packet_put_int(rchan);
326169587Sgreen	packet_send();
326269587Sgreen}
326369587Sgreen
326457429Smarkm/*
326557429Smarkm * Requests forwarding of X11 connections, generates fake authentication
326657429Smarkm * data, and enables authentication spoofing.
326792559Sdes * This should be called in the client only.
326857429Smarkm */
326960573Skrisvoid
3270149753Sdesx11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
327160573Skris    const char *proto, const char *data)
327257429Smarkm{
327376262Sgreen	u_int data_len = (u_int) strlen(data) / 2;
3274149753Sdes	u_int i, value;
327557429Smarkm	char *new_data;
327657429Smarkm	int screen_number;
327757429Smarkm	const char *cp;
3278137019Sdes	u_int32_t rnd = 0;
327957429Smarkm
3280149753Sdes	if (x11_saved_display == NULL)
3281149753Sdes		x11_saved_display = xstrdup(disp);
3282149753Sdes	else if (strcmp(disp, x11_saved_display) != 0) {
3283149753Sdes		error("x11_request_forwarding_with_spoofing: different "
3284149753Sdes		    "$DISPLAY already forwarded");
3285149753Sdes		return;
3286149753Sdes	}
3287149753Sdes
3288162856Sdes	cp = strchr(disp, ':');
328957429Smarkm	if (cp)
329057429Smarkm		cp = strchr(cp, '.');
329157429Smarkm	if (cp)
3292162856Sdes		screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
329357429Smarkm	else
329457429Smarkm		screen_number = 0;
329557429Smarkm
3296149753Sdes	if (x11_saved_proto == NULL) {
3297149753Sdes		/* Save protocol name. */
3298149753Sdes		x11_saved_proto = xstrdup(proto);
3299149753Sdes		/*
3300149753Sdes		 * Extract real authentication data and generate fake data
3301149753Sdes		 * of the same length.
3302149753Sdes		 */
3303149753Sdes		x11_saved_data = xmalloc(data_len);
3304149753Sdes		x11_fake_data = xmalloc(data_len);
3305149753Sdes		for (i = 0; i < data_len; i++) {
3306149753Sdes			if (sscanf(data + 2 * i, "%2x", &value) != 1)
3307149753Sdes				fatal("x11_request_forwarding: bad "
3308149753Sdes				    "authentication data: %.100s", data);
3309149753Sdes			if (i % 4 == 0)
3310149753Sdes				rnd = arc4random();
3311149753Sdes			x11_saved_data[i] = value;
3312149753Sdes			x11_fake_data[i] = rnd & 0xff;
3313149753Sdes			rnd >>= 8;
3314149753Sdes		}
3315149753Sdes		x11_saved_data_len = data_len;
3316149753Sdes		x11_fake_data_len = data_len;
331757429Smarkm	}
331857429Smarkm
331957429Smarkm	/* Convert the fake data into hex. */
3320149753Sdes	new_data = tohex(x11_fake_data, data_len);
332157429Smarkm
332257429Smarkm	/* Send the request packet. */
332360573Skris	if (compat20) {
332460573Skris		channel_request_start(client_session_id, "x11-req", 0);
332560573Skris		packet_put_char(0);	/* XXX bool single connection */
332660573Skris	} else {
332760573Skris		packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
332860573Skris	}
332960573Skris	packet_put_cstring(proto);
333060573Skris	packet_put_cstring(new_data);
333157429Smarkm	packet_put_int(screen_number);
333257429Smarkm	packet_send();
333357429Smarkm	packet_write_wait();
333457429Smarkm	xfree(new_data);
333557429Smarkm}
333657429Smarkm
333792559Sdes
333892559Sdes/* -- agent forwarding */
333992559Sdes
334057429Smarkm/* Sends a message to the server to request authentication fd forwarding. */
334157429Smarkm
334260573Skrisvoid
334392559Sdesauth_request_forwarding(void)
334457429Smarkm{
334557429Smarkm	packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
334657429Smarkm	packet_send();
334757429Smarkm	packet_write_wait();
334857429Smarkm}
3349