1258343Sdes/* $OpenBSD: channels.c,v 1.327 2013/11/08 00:39:15 djm Exp $ */
2224638Sbrooks/* $FreeBSD$ */
357429Smarkm/*
457429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
557429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
657429Smarkm *                    All rights reserved
757429Smarkm * This file contains functions for generic socket connection forwarding.
857429Smarkm * There is also code for initiating connection forwarding for X11 connections,
957429Smarkm * arbitrary tcp/ip connections, and the authentication agent connection.
1060573Skris *
1165668Skris * As far as I am concerned, the code I have written for this software
1265668Skris * can be used freely for any purpose.  Any derived versions of this
1365668Skris * software must be clearly marked as such, and if the derived work is
1465668Skris * incompatible with the protocol description in the RFC file, it must be
1565668Skris * called by a name other than "ssh" or "Secure Shell".
1665668Skris *
1760573Skris * SSH2 support added by Markus Friedl.
1892559Sdes * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
1965668Skris * Copyright (c) 1999 Dug Song.  All rights reserved.
2065668Skris * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
2165668Skris *
2265668Skris * Redistribution and use in source and binary forms, with or without
2365668Skris * modification, are permitted provided that the following conditions
2465668Skris * are met:
2565668Skris * 1. Redistributions of source code must retain the above copyright
2665668Skris *    notice, this list of conditions and the following disclaimer.
2765668Skris * 2. Redistributions in binary form must reproduce the above copyright
2865668Skris *    notice, this list of conditions and the following disclaimer in the
2965668Skris *    documentation and/or other materials provided with the distribution.
3065668Skris *
3165668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3265668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3365668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3465668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3565668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3665668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3765668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3865668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3965668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
4065668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4157429Smarkm */
4257429Smarkm
4357429Smarkm#include "includes.h"
4457429Smarkm
45162856Sdes#include <sys/types.h>
46162856Sdes#include <sys/ioctl.h>
47162856Sdes#include <sys/un.h>
48162856Sdes#include <sys/socket.h>
49162856Sdes#ifdef HAVE_SYS_TIME_H
50162856Sdes# include <sys/time.h>
51162856Sdes#endif
52162856Sdes
53162856Sdes#include <netinet/in.h>
54162856Sdes#include <arpa/inet.h>
55162856Sdes
56162856Sdes#include <errno.h>
57204917Sdes#include <fcntl.h>
58162856Sdes#include <netdb.h>
59162856Sdes#include <stdio.h>
60162856Sdes#include <stdlib.h>
61162856Sdes#include <string.h>
62162856Sdes#include <termios.h>
63162856Sdes#include <unistd.h>
64162856Sdes#include <stdarg.h>
65162856Sdes
66181111Sdes#include "openbsd-compat/sys-queue.h"
67162856Sdes#include "xmalloc.h"
6857429Smarkm#include "ssh.h"
6976262Sgreen#include "ssh1.h"
7076262Sgreen#include "ssh2.h"
7157429Smarkm#include "packet.h"
7276262Sgreen#include "log.h"
7376262Sgreen#include "misc.h"
74162856Sdes#include "buffer.h"
7557429Smarkm#include "channels.h"
7657429Smarkm#include "compat.h"
7776262Sgreen#include "canohost.h"
7865668Skris#include "key.h"
7965668Skris#include "authfd.h"
8092559Sdes#include "pathnames.h"
8165668Skris
8292559Sdes/* -- channel core */
8357429Smarkm
8457429Smarkm/*
8557429Smarkm * Pointer to an array containing all allocated channels.  The array is
8657429Smarkm * dynamically extended as needed.
8757429Smarkm */
8892559Sdesstatic Channel **channels = NULL;
8957429Smarkm
9057429Smarkm/*
9157429Smarkm * Size of the channel array.  All slots of the array must always be
9292559Sdes * initialized (at least the type field); unused slots set to NULL
9357429Smarkm */
94137019Sdesstatic u_int channels_alloc = 0;
9557429Smarkm
9657429Smarkm/*
9757429Smarkm * Maximum file descriptor value used in any of the channels.  This is
9892559Sdes * updated in channel_new.
9957429Smarkm */
10076262Sgreenstatic int channel_max_fd = 0;
10157429Smarkm
10257429Smarkm
10392559Sdes/* -- tcp forwarding */
10457429Smarkm
10557429Smarkm/*
10657429Smarkm * Data structure for storing which hosts are permitted for forward requests.
10757429Smarkm * The local sides of any remote forwards are stored in this array to prevent
10857429Smarkm * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
10957429Smarkm * network (which might be behind a firewall).
11057429Smarkm */
11157429Smarkmtypedef struct {
11260573Skris	char *host_to_connect;		/* Connect to 'host'. */
11360573Skris	u_short port_to_connect;	/* Connect to 'port'. */
11460573Skris	u_short listen_port;		/* Remote side should listen port number. */
11557429Smarkm} ForwardPermission;
11657429Smarkm
117162856Sdes/* List of all permitted host/port pairs to connect by the user. */
118215116Sdesstatic ForwardPermission *permitted_opens = NULL;
11992559Sdes
120162856Sdes/* List of all permitted host/port pairs to connect by the admin. */
121215116Sdesstatic ForwardPermission *permitted_adm_opens = NULL;
122162856Sdes
123162856Sdes/* Number of permitted host/port pairs in the array permitted by the user. */
12457429Smarkmstatic int num_permitted_opens = 0;
125162856Sdes
126162856Sdes/* Number of permitted host/port pair in the array permitted by the admin. */
127162856Sdesstatic int num_adm_permitted_opens = 0;
128162856Sdes
129240075Sdes/* special-case port number meaning allow any port */
130240075Sdes#define FWD_PERMIT_ANY_PORT	0
131240075Sdes
13257429Smarkm/*
13357429Smarkm * If this is true, all opens are permitted.  This is the case on the server
13457429Smarkm * on which we have to trust the client anyway, and the user could do
13557429Smarkm * anything after logging in anyway.
13657429Smarkm */
13757429Smarkmstatic int all_opens_permitted = 0;
13857429Smarkm
13957429Smarkm
14092559Sdes/* -- X11 forwarding */
14192559Sdes
14292559Sdes/* Maximum number of fake X11 displays to try. */
14392559Sdes#define MAX_DISPLAYS  1000
14492559Sdes
145149753Sdes/* Saved X11 local (client) display. */
146149753Sdesstatic char *x11_saved_display = NULL;
147149753Sdes
14892559Sdes/* Saved X11 authentication protocol name. */
14992559Sdesstatic char *x11_saved_proto = NULL;
15092559Sdes
15192559Sdes/* Saved X11 authentication data.  This is the real data. */
15292559Sdesstatic char *x11_saved_data = NULL;
15392559Sdesstatic u_int x11_saved_data_len = 0;
15492559Sdes
15592559Sdes/*
15692559Sdes * Fake X11 authentication data.  This is what the server will be sending us;
15792559Sdes * we should replace any occurrences of this by the real data.
15892559Sdes */
159162856Sdesstatic u_char *x11_fake_data = NULL;
16092559Sdesstatic u_int x11_fake_data_len;
16192559Sdes
16292559Sdes
16392559Sdes/* -- agent forwarding */
16492559Sdes
16592559Sdes#define	NUM_SOCKS	10
16692559Sdes
16776262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */
16898941Sdesstatic int IPv4or6 = AF_UNSPEC;
16976262Sgreen
17092559Sdes/* helper */
17192559Sdesstatic void port_open_helper(Channel *c, char *rtype);
17276262Sgreen
173181111Sdes/* non-blocking connect helpers */
174181111Sdesstatic int connect_next(struct channel_connect *);
175181111Sdesstatic void channel_connect_ctx_free(struct channel_connect *);
176181111Sdes
177224638Sbrooks/* -- HPN */
178224638Sbrooks
179224638Sbrooksstatic int hpn_disabled = 0;
180224638Sbrooksstatic u_int buffer_size = CHAN_HPN_MIN_WINDOW_DEFAULT;
181224638Sbrooks
18292559Sdes/* -- channel core */
18357429Smarkm
18460573SkrisChannel *
185157019Sdeschannel_by_id(int id)
18660573Skris{
18760573Skris	Channel *c;
18892559Sdes
189137019Sdes	if (id < 0 || (u_int)id >= channels_alloc) {
190157019Sdes		logit("channel_by_id: %d: bad id", id);
19160573Skris		return NULL;
19260573Skris	}
19392559Sdes	c = channels[id];
19492559Sdes	if (c == NULL) {
195157019Sdes		logit("channel_by_id: %d: bad id: channel free", id);
19660573Skris		return NULL;
19760573Skris	}
19860573Skris	return c;
19960573Skris}
20060573Skris
20157429Smarkm/*
202157019Sdes * Returns the channel if it is allowed to receive protocol messages.
203157019Sdes * Private channels, like listening sockets, may not receive messages.
204157019Sdes */
205157019SdesChannel *
206157019Sdeschannel_lookup(int id)
207157019Sdes{
208157019Sdes	Channel *c;
209157019Sdes
210157019Sdes	if ((c = channel_by_id(id)) == NULL)
211157019Sdes		return (NULL);
212157019Sdes
213162856Sdes	switch (c->type) {
214157019Sdes	case SSH_CHANNEL_X11_OPEN:
215157019Sdes	case SSH_CHANNEL_LARVAL:
216157019Sdes	case SSH_CHANNEL_CONNECTING:
217157019Sdes	case SSH_CHANNEL_DYNAMIC:
218157019Sdes	case SSH_CHANNEL_OPENING:
219157019Sdes	case SSH_CHANNEL_OPEN:
220157019Sdes	case SSH_CHANNEL_INPUT_DRAINING:
221157019Sdes	case SSH_CHANNEL_OUTPUT_DRAINING:
222255767Sdes	case SSH_CHANNEL_ABANDONED:
223157019Sdes		return (c);
224157019Sdes	}
225157019Sdes	logit("Non-public channel %d, type %d.", id, c->type);
226157019Sdes	return (NULL);
227157019Sdes}
228157019Sdes
229157019Sdes/*
23060573Skris * Register filedescriptors for a channel, used when allocating a channel or
23160573Skris * when the channel consumer/producer is ready, e.g. shell exec'd
23260573Skris */
23392559Sdesstatic void
23469587Sgreenchannel_register_fds(Channel *c, int rfd, int wfd, int efd,
235181111Sdes    int extusage, int nonblock, int is_tty)
23660573Skris{
23760573Skris	/* Update the maximum file descriptor value. */
23876262Sgreen	channel_max_fd = MAX(channel_max_fd, rfd);
23976262Sgreen	channel_max_fd = MAX(channel_max_fd, wfd);
24076262Sgreen	channel_max_fd = MAX(channel_max_fd, efd);
24176262Sgreen
242204917Sdes	if (rfd != -1)
243204917Sdes		fcntl(rfd, F_SETFD, FD_CLOEXEC);
244204917Sdes	if (wfd != -1 && wfd != rfd)
245204917Sdes		fcntl(wfd, F_SETFD, FD_CLOEXEC);
246204917Sdes	if (efd != -1 && efd != rfd && efd != wfd)
247204917Sdes		fcntl(efd, F_SETFD, FD_CLOEXEC);
24860573Skris
24960573Skris	c->rfd = rfd;
25060573Skris	c->wfd = wfd;
25160573Skris	c->sock = (rfd == wfd) ? rfd : -1;
25260573Skris	c->efd = efd;
25360573Skris	c->extended_usage = extusage;
25469587Sgreen
255181111Sdes	if ((c->isatty = is_tty) != 0)
256124207Sdes		debug2("channel %d: rfd %d isatty", c->self, c->rfd);
257255767Sdes#ifdef _AIX
258255767Sdes	/* XXX: Later AIX versions can't push as much data to tty */
259181111Sdes	c->wfd_isatty = is_tty || isatty(c->wfd);
260255767Sdes#endif
26174500Sgreen
26269587Sgreen	/* enable nonblocking mode */
26369587Sgreen	if (nonblock) {
26469587Sgreen		if (rfd != -1)
26569587Sgreen			set_nonblock(rfd);
26669587Sgreen		if (wfd != -1)
26769587Sgreen			set_nonblock(wfd);
26869587Sgreen		if (efd != -1)
26969587Sgreen			set_nonblock(efd);
27069587Sgreen	}
27160573Skris}
27260573Skris
27360573Skris/*
27457429Smarkm * Allocate a new channel object and set its type and socket. This will cause
27557429Smarkm * remote_name to be freed.
27657429Smarkm */
27792559SdesChannel *
27860573Skrischannel_new(char *ctype, int type, int rfd, int wfd, int efd,
27999063Sdes    u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
28057429Smarkm{
281137019Sdes	int found;
282137019Sdes	u_int i;
28357429Smarkm	Channel *c;
28457429Smarkm
28557429Smarkm	/* Do initial allocation if this is the first call. */
28657429Smarkm	if (channels_alloc == 0) {
28757429Smarkm		channels_alloc = 10;
288162856Sdes		channels = xcalloc(channels_alloc, sizeof(Channel *));
28957429Smarkm		for (i = 0; i < channels_alloc; i++)
29092559Sdes			channels[i] = NULL;
29157429Smarkm	}
29257429Smarkm	/* Try to find a free slot where to put the new channel. */
29357429Smarkm	for (found = -1, i = 0; i < channels_alloc; i++)
29492559Sdes		if (channels[i] == NULL) {
29557429Smarkm			/* Found a free slot. */
296137019Sdes			found = (int)i;
29757429Smarkm			break;
29857429Smarkm		}
299137019Sdes	if (found < 0) {
30057429Smarkm		/* There are no free slots.  Take last+1 slot and expand the array.  */
30157429Smarkm		found = channels_alloc;
30299063Sdes		if (channels_alloc > 10000)
30399063Sdes			fatal("channel_new: internal error: channels_alloc %d "
30499063Sdes			    "too big.", channels_alloc);
305162856Sdes		channels = xrealloc(channels, channels_alloc + 10,
306162856Sdes		    sizeof(Channel *));
307120489Sjoe		channels_alloc += 10;
30869587Sgreen		debug2("channel: expanding %d", channels_alloc);
30957429Smarkm		for (i = found; i < channels_alloc; i++)
31092559Sdes			channels[i] = NULL;
31157429Smarkm	}
31292559Sdes	/* Initialize and return new channel. */
313162856Sdes	c = channels[found] = xcalloc(1, sizeof(Channel));
31457429Smarkm	buffer_init(&c->input);
31557429Smarkm	buffer_init(&c->output);
31660573Skris	buffer_init(&c->extended);
317192595Sdes	c->path = NULL;
318240075Sdes	c->listening_addr = NULL;
319240075Sdes	c->listening_port = 0;
32092559Sdes	c->ostate = CHAN_OUTPUT_OPEN;
32192559Sdes	c->istate = CHAN_INPUT_OPEN;
32292559Sdes	c->flags = 0;
323181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
324240075Sdes	c->notbefore = 0;
32557429Smarkm	c->self = found;
32657429Smarkm	c->type = type;
32760573Skris	c->ctype = ctype;
328224638Sbrooks	c->dynamic_window = 0;
32960573Skris	c->local_window = window;
33060573Skris	c->local_window_max = window;
33160573Skris	c->local_consumed = 0;
33260573Skris	c->local_maxpacket = maxpack;
33357429Smarkm	c->remote_id = -1;
334124207Sdes	c->remote_name = xstrdup(remote_name);
33560573Skris	c->remote_window = 0;
33660573Skris	c->remote_maxpacket = 0;
33792559Sdes	c->force_drain = 0;
33892559Sdes	c->single_connection = 0;
33992559Sdes	c->detach_user = NULL;
340157019Sdes	c->detach_close = 0;
341181111Sdes	c->open_confirm = NULL;
342181111Sdes	c->open_confirm_ctx = NULL;
34365668Skris	c->input_filter = NULL;
344157019Sdes	c->output_filter = NULL;
345181111Sdes	c->filter_ctx = NULL;
346181111Sdes	c->filter_cleanup = NULL;
347204917Sdes	c->ctl_chan = -1;
348204917Sdes	c->mux_rcb = NULL;
349204917Sdes	c->mux_ctx = NULL;
350215116Sdes	c->mux_pause = 0;
351204917Sdes	c->delayed = 1;		/* prevent call to channel_post handler */
352181111Sdes	TAILQ_INIT(&c->status_confirms);
35357429Smarkm	debug("channel %d: new [%s]", found, remote_name);
35492559Sdes	return c;
35557429Smarkm}
35692559Sdes
35792559Sdesstatic int
35892559Sdeschannel_find_maxfd(void)
35992559Sdes{
360137019Sdes	u_int i;
361137019Sdes	int max = 0;
36292559Sdes	Channel *c;
36392559Sdes
36492559Sdes	for (i = 0; i < channels_alloc; i++) {
36592559Sdes		c = channels[i];
36692559Sdes		if (c != NULL) {
36792559Sdes			max = MAX(max, c->rfd);
36892559Sdes			max = MAX(max, c->wfd);
36992559Sdes			max = MAX(max, c->efd);
37092559Sdes		}
37192559Sdes	}
37292559Sdes	return max;
37392559Sdes}
37492559Sdes
37560573Skrisint
37692559Sdeschannel_close_fd(int *fdp)
37760573Skris{
37892559Sdes	int ret = 0, fd = *fdp;
37992559Sdes
38092559Sdes	if (fd != -1) {
38192559Sdes		ret = close(fd);
38292559Sdes		*fdp = -1;
38392559Sdes		if (fd == channel_max_fd)
38492559Sdes			channel_max_fd = channel_find_maxfd();
38592559Sdes	}
38692559Sdes	return ret;
38760573Skris}
38857429Smarkm
38960573Skris/* Close all channel fd/socket. */
39092559Sdesstatic void
39160573Skrischannel_close_fds(Channel *c)
39257429Smarkm{
39392559Sdes	channel_close_fd(&c->sock);
39492559Sdes	channel_close_fd(&c->rfd);
39592559Sdes	channel_close_fd(&c->wfd);
39692559Sdes	channel_close_fd(&c->efd);
39760573Skris}
39857429Smarkm
39960573Skris/* Free the channel and close its fd/socket. */
40060573Skrisvoid
40192559Sdeschannel_free(Channel *c)
40260573Skris{
40392559Sdes	char *s;
404137019Sdes	u_int i, n;
405181111Sdes	struct channel_confirm *cc;
40676262Sgreen
40792559Sdes	for (n = 0, i = 0; i < channels_alloc; i++)
40892559Sdes		if (channels[i])
40992559Sdes			n++;
410137019Sdes	debug("channel %d: free: %s, nchannels %u", c->self,
41192559Sdes	    c->remote_name ? c->remote_name : "???", n);
41292559Sdes
41392559Sdes	s = channel_open_message();
414124207Sdes	debug3("channel %d: status: %s", c->self, s);
415255767Sdes	free(s);
41676262Sgreen
41760573Skris	if (c->sock != -1)
41860573Skris		shutdown(c->sock, SHUT_RDWR);
41960573Skris	channel_close_fds(c);
42060573Skris	buffer_free(&c->input);
42160573Skris	buffer_free(&c->output);
42260573Skris	buffer_free(&c->extended);
423255767Sdes	free(c->remote_name);
424255767Sdes	c->remote_name = NULL;
425255767Sdes	free(c->path);
426255767Sdes	c->path = NULL;
427255767Sdes	free(c->listening_addr);
428255767Sdes	c->listening_addr = NULL;
429181111Sdes	while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
430181111Sdes		if (cc->abandon_cb != NULL)
431181111Sdes			cc->abandon_cb(c, cc->ctx);
432181111Sdes		TAILQ_REMOVE(&c->status_confirms, cc, entry);
433181111Sdes		bzero(cc, sizeof(*cc));
434255767Sdes		free(cc);
435181111Sdes	}
436181111Sdes	if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
437181111Sdes		c->filter_cleanup(c->self, c->filter_ctx);
43892559Sdes	channels[c->self] = NULL;
439255767Sdes	free(c);
44057429Smarkm}
44157429Smarkm
44292559Sdesvoid
44392559Sdeschannel_free_all(void)
44492559Sdes{
445137019Sdes	u_int i;
44692559Sdes
44792559Sdes	for (i = 0; i < channels_alloc; i++)
44892559Sdes		if (channels[i] != NULL)
44992559Sdes			channel_free(channels[i]);
45092559Sdes}
45192559Sdes
45257429Smarkm/*
45392559Sdes * Closes the sockets/fds of all channels.  This is used to close extra file
45492559Sdes * descriptors after a fork.
45592559Sdes */
45692559Sdesvoid
45792559Sdeschannel_close_all(void)
45892559Sdes{
459137019Sdes	u_int i;
46092559Sdes
46192559Sdes	for (i = 0; i < channels_alloc; i++)
46292559Sdes		if (channels[i] != NULL)
46392559Sdes			channel_close_fds(channels[i]);
46492559Sdes}
46592559Sdes
46692559Sdes/*
46792559Sdes * Stop listening to channels.
46892559Sdes */
46992559Sdesvoid
47092559Sdeschannel_stop_listening(void)
47192559Sdes{
472137019Sdes	u_int i;
47392559Sdes	Channel *c;
47492559Sdes
47592559Sdes	for (i = 0; i < channels_alloc; i++) {
47692559Sdes		c = channels[i];
47792559Sdes		if (c != NULL) {
47892559Sdes			switch (c->type) {
47992559Sdes			case SSH_CHANNEL_AUTH_SOCKET:
48092559Sdes			case SSH_CHANNEL_PORT_LISTENER:
48192559Sdes			case SSH_CHANNEL_RPORT_LISTENER:
48292559Sdes			case SSH_CHANNEL_X11_LISTENER:
48392559Sdes				channel_close_fd(&c->sock);
48492559Sdes				channel_free(c);
48592559Sdes				break;
48692559Sdes			}
48792559Sdes		}
48892559Sdes	}
48992559Sdes}
49092559Sdes
49192559Sdes/*
49292559Sdes * Returns true if no channel has too much buffered data, and false if one or
49392559Sdes * more channel is overfull.
49492559Sdes */
49592559Sdesint
49692559Sdeschannel_not_very_much_buffered_data(void)
49792559Sdes{
49892559Sdes	u_int i;
49992559Sdes	Channel *c;
50092559Sdes
50192559Sdes	for (i = 0; i < channels_alloc; i++) {
50292559Sdes		c = channels[i];
50392559Sdes		if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
50492559Sdes#if 0
50592559Sdes			if (!compat20 &&
50692559Sdes			    buffer_len(&c->input) > packet_get_maxsize()) {
507113911Sdes				debug2("channel %d: big input buffer %d",
50892559Sdes				    c->self, buffer_len(&c->input));
50992559Sdes				return 0;
51092559Sdes			}
51192559Sdes#endif
51292559Sdes			if (buffer_len(&c->output) > packet_get_maxsize()) {
513124207Sdes				debug2("channel %d: big output buffer %u > %u",
51492559Sdes				    c->self, buffer_len(&c->output),
51592559Sdes				    packet_get_maxsize());
51692559Sdes				return 0;
51792559Sdes			}
51892559Sdes		}
51992559Sdes	}
52092559Sdes	return 1;
52192559Sdes}
52292559Sdes
52392559Sdes/* Returns true if any channel is still open. */
52492559Sdesint
52592559Sdeschannel_still_open(void)
52692559Sdes{
527137019Sdes	u_int i;
52892559Sdes	Channel *c;
52992559Sdes
53092559Sdes	for (i = 0; i < channels_alloc; i++) {
53192559Sdes		c = channels[i];
53292559Sdes		if (c == NULL)
53392559Sdes			continue;
53492559Sdes		switch (c->type) {
53592559Sdes		case SSH_CHANNEL_X11_LISTENER:
53692559Sdes		case SSH_CHANNEL_PORT_LISTENER:
53792559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
538204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
53992559Sdes		case SSH_CHANNEL_CLOSED:
54092559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
54192559Sdes		case SSH_CHANNEL_DYNAMIC:
54292559Sdes		case SSH_CHANNEL_CONNECTING:
54392559Sdes		case SSH_CHANNEL_ZOMBIE:
544255767Sdes		case SSH_CHANNEL_ABANDONED:
54592559Sdes			continue;
54692559Sdes		case SSH_CHANNEL_LARVAL:
54792559Sdes			if (!compat20)
54892559Sdes				fatal("cannot happen: SSH_CHANNEL_LARVAL");
54992559Sdes			continue;
55092559Sdes		case SSH_CHANNEL_OPENING:
55192559Sdes		case SSH_CHANNEL_OPEN:
55292559Sdes		case SSH_CHANNEL_X11_OPEN:
553204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
55492559Sdes			return 1;
55592559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
55692559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
55792559Sdes			if (!compat13)
55892559Sdes				fatal("cannot happen: OUT_DRAIN");
55992559Sdes			return 1;
56092559Sdes		default:
56192559Sdes			fatal("channel_still_open: bad channel type %d", c->type);
56292559Sdes			/* NOTREACHED */
56392559Sdes		}
56492559Sdes	}
56592559Sdes	return 0;
56692559Sdes}
56792559Sdes
56892559Sdes/* Returns the id of an open channel suitable for keepaliving */
56992559Sdesint
57092559Sdeschannel_find_open(void)
57192559Sdes{
572137019Sdes	u_int i;
57392559Sdes	Channel *c;
57492559Sdes
57592559Sdes	for (i = 0; i < channels_alloc; i++) {
57692559Sdes		c = channels[i];
577137019Sdes		if (c == NULL || c->remote_id < 0)
57892559Sdes			continue;
57992559Sdes		switch (c->type) {
58092559Sdes		case SSH_CHANNEL_CLOSED:
58192559Sdes		case SSH_CHANNEL_DYNAMIC:
58292559Sdes		case SSH_CHANNEL_X11_LISTENER:
58392559Sdes		case SSH_CHANNEL_PORT_LISTENER:
58492559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
585204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
586204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
58792559Sdes		case SSH_CHANNEL_OPENING:
58892559Sdes		case SSH_CHANNEL_CONNECTING:
58992559Sdes		case SSH_CHANNEL_ZOMBIE:
590255767Sdes		case SSH_CHANNEL_ABANDONED:
59192559Sdes			continue;
59292559Sdes		case SSH_CHANNEL_LARVAL:
59392559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
59492559Sdes		case SSH_CHANNEL_OPEN:
59592559Sdes		case SSH_CHANNEL_X11_OPEN:
59692559Sdes			return i;
59792559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
59892559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
59992559Sdes			if (!compat13)
60092559Sdes				fatal("cannot happen: OUT_DRAIN");
60192559Sdes			return i;
60292559Sdes		default:
60392559Sdes			fatal("channel_find_open: bad channel type %d", c->type);
60492559Sdes			/* NOTREACHED */
60592559Sdes		}
60692559Sdes	}
60792559Sdes	return -1;
60892559Sdes}
60992559Sdes
61092559Sdes
61192559Sdes/*
61292559Sdes * Returns a message describing the currently open forwarded connections,
61392559Sdes * suitable for sending to the client.  The message contains crlf pairs for
61492559Sdes * newlines.
61592559Sdes */
61692559Sdeschar *
61792559Sdeschannel_open_message(void)
61892559Sdes{
61992559Sdes	Buffer buffer;
62092559Sdes	Channel *c;
62192559Sdes	char buf[1024], *cp;
622137019Sdes	u_int i;
62392559Sdes
62492559Sdes	buffer_init(&buffer);
62592559Sdes	snprintf(buf, sizeof buf, "The following connections are open:\r\n");
62692559Sdes	buffer_append(&buffer, buf, strlen(buf));
62792559Sdes	for (i = 0; i < channels_alloc; i++) {
62892559Sdes		c = channels[i];
62992559Sdes		if (c == NULL)
63092559Sdes			continue;
63192559Sdes		switch (c->type) {
63292559Sdes		case SSH_CHANNEL_X11_LISTENER:
63392559Sdes		case SSH_CHANNEL_PORT_LISTENER:
63492559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
63592559Sdes		case SSH_CHANNEL_CLOSED:
63692559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
63792559Sdes		case SSH_CHANNEL_ZOMBIE:
638255767Sdes		case SSH_CHANNEL_ABANDONED:
639204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
640204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
64192559Sdes			continue;
64292559Sdes		case SSH_CHANNEL_LARVAL:
64392559Sdes		case SSH_CHANNEL_OPENING:
64492559Sdes		case SSH_CHANNEL_CONNECTING:
64592559Sdes		case SSH_CHANNEL_DYNAMIC:
64692559Sdes		case SSH_CHANNEL_OPEN:
64792559Sdes		case SSH_CHANNEL_X11_OPEN:
64892559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
64992559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
650137019Sdes			snprintf(buf, sizeof buf,
651204917Sdes			    "  #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cc %d)\r\n",
65292559Sdes			    c->self, c->remote_name,
65392559Sdes			    c->type, c->remote_id,
65492559Sdes			    c->istate, buffer_len(&c->input),
65592559Sdes			    c->ostate, buffer_len(&c->output),
656204917Sdes			    c->rfd, c->wfd, c->ctl_chan);
65792559Sdes			buffer_append(&buffer, buf, strlen(buf));
65892559Sdes			continue;
65992559Sdes		default:
66092559Sdes			fatal("channel_open_message: bad channel type %d", c->type);
66192559Sdes			/* NOTREACHED */
66292559Sdes		}
66392559Sdes	}
66492559Sdes	buffer_append(&buffer, "\0", 1);
66592559Sdes	cp = xstrdup(buffer_ptr(&buffer));
66692559Sdes	buffer_free(&buffer);
66792559Sdes	return cp;
66892559Sdes}
66992559Sdes
67092559Sdesvoid
67192559Sdeschannel_send_open(int id)
67292559Sdes{
67392559Sdes	Channel *c = channel_lookup(id);
674106130Sdes
67592559Sdes	if (c == NULL) {
676124207Sdes		logit("channel_send_open: %d: bad id", id);
67792559Sdes		return;
67892559Sdes	}
679113911Sdes	debug2("channel %d: send open", id);
68092559Sdes	packet_start(SSH2_MSG_CHANNEL_OPEN);
68192559Sdes	packet_put_cstring(c->ctype);
68292559Sdes	packet_put_int(c->self);
68392559Sdes	packet_put_int(c->local_window);
68492559Sdes	packet_put_int(c->local_maxpacket);
68592559Sdes	packet_send();
68692559Sdes}
68792559Sdes
68892559Sdesvoid
689113911Sdeschannel_request_start(int id, char *service, int wantconfirm)
69092559Sdes{
691113911Sdes	Channel *c = channel_lookup(id);
692106130Sdes
69392559Sdes	if (c == NULL) {
694124207Sdes		logit("channel_request_start: %d: unknown channel id", id);
69592559Sdes		return;
69692559Sdes	}
697137019Sdes	debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
69892559Sdes	packet_start(SSH2_MSG_CHANNEL_REQUEST);
69992559Sdes	packet_put_int(c->remote_id);
70092559Sdes	packet_put_cstring(service);
70192559Sdes	packet_put_char(wantconfirm);
70292559Sdes}
703162856Sdes
70492559Sdesvoid
705181111Sdeschannel_register_status_confirm(int id, channel_confirm_cb *cb,
706181111Sdes    channel_confirm_abandon_cb *abandon_cb, void *ctx)
70792559Sdes{
708181111Sdes	struct channel_confirm *cc;
709181111Sdes	Channel *c;
710181111Sdes
711181111Sdes	if ((c = channel_lookup(id)) == NULL)
712181111Sdes		fatal("channel_register_expect: %d: bad id", id);
713181111Sdes
714258343Sdes	cc = xcalloc(1, sizeof(*cc));
715181111Sdes	cc->cb = cb;
716181111Sdes	cc->abandon_cb = abandon_cb;
717181111Sdes	cc->ctx = ctx;
718181111Sdes	TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
719181111Sdes}
720181111Sdes
721181111Sdesvoid
722215116Sdeschannel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
723181111Sdes{
72492559Sdes	Channel *c = channel_lookup(id);
725106130Sdes
72692559Sdes	if (c == NULL) {
727192595Sdes		logit("channel_register_open_confirm: %d: bad id", id);
72892559Sdes		return;
72992559Sdes	}
730181111Sdes	c->open_confirm = fn;
731181111Sdes	c->open_confirm_ctx = ctx;
73292559Sdes}
733162856Sdes
73492559Sdesvoid
735157019Sdeschannel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
73692559Sdes{
737157019Sdes	Channel *c = channel_by_id(id);
738106130Sdes
73992559Sdes	if (c == NULL) {
740124207Sdes		logit("channel_register_cleanup: %d: bad id", id);
74192559Sdes		return;
74292559Sdes	}
74392559Sdes	c->detach_user = fn;
744157019Sdes	c->detach_close = do_close;
74592559Sdes}
746162856Sdes
74792559Sdesvoid
74892559Sdeschannel_cancel_cleanup(int id)
74992559Sdes{
750157019Sdes	Channel *c = channel_by_id(id);
751106130Sdes
75292559Sdes	if (c == NULL) {
753124207Sdes		logit("channel_cancel_cleanup: %d: bad id", id);
75492559Sdes		return;
75592559Sdes	}
75692559Sdes	c->detach_user = NULL;
757157019Sdes	c->detach_close = 0;
75892559Sdes}
759162856Sdes
76092559Sdesvoid
761157019Sdeschannel_register_filter(int id, channel_infilter_fn *ifn,
762181111Sdes    channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
76392559Sdes{
76492559Sdes	Channel *c = channel_lookup(id);
765106130Sdes
76692559Sdes	if (c == NULL) {
767124207Sdes		logit("channel_register_filter: %d: bad id", id);
76892559Sdes		return;
76992559Sdes	}
770157019Sdes	c->input_filter = ifn;
771157019Sdes	c->output_filter = ofn;
772181111Sdes	c->filter_ctx = ctx;
773181111Sdes	c->filter_cleanup = cfn;
77492559Sdes}
77592559Sdes
77692559Sdesvoid
77792559Sdeschannel_set_fds(int id, int rfd, int wfd, int efd,
778181111Sdes    int extusage, int nonblock, int is_tty, u_int window_max)
77992559Sdes{
78092559Sdes	Channel *c = channel_lookup(id);
781106130Sdes
78292559Sdes	if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
78392559Sdes		fatal("channel_activate for non-larval channel %d.", id);
784181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
78592559Sdes	c->type = SSH_CHANNEL_OPEN;
78692559Sdes	c->local_window = c->local_window_max = window_max;
78792559Sdes	packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
78892559Sdes	packet_put_int(c->remote_id);
78992559Sdes	packet_put_int(c->local_window);
79092559Sdes	packet_send();
79192559Sdes}
79292559Sdes
79392559Sdes/*
79460573Skris * 'channel_pre*' are called just before select() to add any bits relevant to
79560573Skris * channels in the select bitmasks.
79657429Smarkm */
79760573Skris/*
79860573Skris * 'channel_post*': perform any appropriate operations for channels which
79960573Skris * have events pending.
80060573Skris */
801162856Sdestypedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
80260573Skrischan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
80360573Skrischan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
80457429Smarkm
805162856Sdes/* ARGSUSED */
80692559Sdesstatic void
807162856Sdeschannel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
80857429Smarkm{
80960573Skris	FD_SET(c->sock, readset);
81060573Skris}
81160573Skris
812162856Sdes/* ARGSUSED */
81392559Sdesstatic void
814162856Sdeschannel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
81576262Sgreen{
81676262Sgreen	debug3("channel %d: waiting for connection", c->self);
81776262Sgreen	FD_SET(c->sock, writeset);
81876262Sgreen}
81976262Sgreen
82092559Sdesstatic void
821162856Sdeschannel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
82260573Skris{
82360573Skris	if (buffer_len(&c->input) < packet_get_maxsize())
82460573Skris		FD_SET(c->sock, readset);
82560573Skris	if (buffer_len(&c->output) > 0)
82660573Skris		FD_SET(c->sock, writeset);
82760573Skris}
82860573Skris
829224638Sbrooksstatic u_int
830224638Sbrookschannel_tcpwinsz(void)
831224638Sbrooks{
832224638Sbrooks	u_int32_t tcpwinsz;
833224638Sbrooks	socklen_t optsz;
834224638Sbrooks	int ret, sd;
835224638Sbrooks	u_int maxlen;
836224638Sbrooks
837224638Sbrooks	/* If we are not on a socket return 128KB. */
838231584Sed	if (!packet_connection_is_on_socket())
839224638Sbrooks		return (128 * 1024);
840224638Sbrooks
841224638Sbrooks	tcpwinsz = 0;
842224638Sbrooks	optsz = sizeof(tcpwinsz);
843224638Sbrooks	sd = packet_get_connection_in();
844224638Sbrooks	ret = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz);
845224638Sbrooks
846224638Sbrooks	/* Return no more than the maximum buffer size. */
847224638Sbrooks	maxlen = buffer_get_max_len();
848224638Sbrooks	if ((ret == 0) && tcpwinsz > maxlen)
849224638Sbrooks		tcpwinsz = maxlen;
850224638Sbrooks	/* In case getsockopt() failed return a minimum. */
851224638Sbrooks	if (tcpwinsz == 0)
852224638Sbrooks		tcpwinsz = CHAN_TCP_WINDOW_DEFAULT;
853224638Sbrooks	debug2("tcpwinsz: %d for connection: %d", tcpwinsz, sd);
854224638Sbrooks	return (tcpwinsz);
855224638Sbrooks}
856224638Sbrooks
85792559Sdesstatic void
858162856Sdeschannel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
85960573Skris{
860224638Sbrooks	u_int limit;
86160573Skris
862224638Sbrooks	/* Check buffer limits. */
863224638Sbrooks	if (!c->tcpwinsz || c->dynamic_window > 0)
864224638Sbrooks		c->tcpwinsz = channel_tcpwinsz();
865224638Sbrooks
866224638Sbrooks	limit = MIN(compat20 ? c->remote_window : packet_get_maxsize(),
867224638Sbrooks	    2 * c->tcpwinsz);
868231584Sed
86960573Skris	if (c->istate == CHAN_INPUT_OPEN &&
87092559Sdes	    limit > 0 &&
871162856Sdes	    buffer_len(&c->input) < limit &&
872162856Sdes	    buffer_check_alloc(&c->input, CHAN_RBUF))
87360573Skris		FD_SET(c->rfd, readset);
87460573Skris	if (c->ostate == CHAN_OUTPUT_OPEN ||
87560573Skris	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
87660573Skris		if (buffer_len(&c->output) > 0) {
87760573Skris			FD_SET(c->wfd, writeset);
87860573Skris		} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
87998684Sdes			if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
880149753Sdes				debug2("channel %d: obuf_empty delayed efd %d/(%d)",
881149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
88298684Sdes			else
88398684Sdes				chan_obuf_empty(c);
88460573Skris		}
88560573Skris	}
88660573Skris	/** XXX check close conditions, too */
887181111Sdes	if (compat20 && c->efd != -1 &&
888181111Sdes	    !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
88960573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
89060573Skris		    buffer_len(&c->extended) > 0)
89160573Skris			FD_SET(c->efd, writeset);
892215116Sdes		else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
893215116Sdes		    (c->extended_usage == CHAN_EXTENDED_READ ||
894215116Sdes		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
89560573Skris		    buffer_len(&c->extended) < c->remote_window)
89660573Skris			FD_SET(c->efd, readset);
89760573Skris	}
898137019Sdes	/* XXX: What about efd? races? */
89960573Skris}
90060573Skris
901162856Sdes/* ARGSUSED */
90292559Sdesstatic void
903162856Sdeschannel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
90460573Skris{
90560573Skris	if (buffer_len(&c->input) == 0) {
90660573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
90760573Skris		packet_put_int(c->remote_id);
90860573Skris		packet_send();
90960573Skris		c->type = SSH_CHANNEL_CLOSED;
910124207Sdes		debug2("channel %d: closing after input drain.", c->self);
91160573Skris	}
91260573Skris}
91360573Skris
914162856Sdes/* ARGSUSED */
91592559Sdesstatic void
916162856Sdeschannel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
91760573Skris{
91860573Skris	if (buffer_len(&c->output) == 0)
91992559Sdes		chan_mark_dead(c);
92060573Skris	else
92160573Skris		FD_SET(c->sock, writeset);
92260573Skris}
92360573Skris
92460573Skris/*
92560573Skris * This is a special state for X11 authentication spoofing.  An opened X11
92660573Skris * connection (when authentication spoofing is being done) remains in this
92760573Skris * state until the first packet has been completely read.  The authentication
92860573Skris * data in that packet is then substituted by the real data if it matches the
92960573Skris * fake data, and the channel is put into normal mode.
93060573Skris * XXX All this happens at the client side.
93192559Sdes * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
93260573Skris */
93392559Sdesstatic int
93492559Sdesx11_open_helper(Buffer *b)
93560573Skris{
93676262Sgreen	u_char *ucp;
93776262Sgreen	u_int proto_len, data_len;
93857429Smarkm
93960573Skris	/* Check if the fixed size part of the packet is in buffer. */
94092559Sdes	if (buffer_len(b) < 12)
94160573Skris		return 0;
94257429Smarkm
94360573Skris	/* Parse the lengths of variable-length fields. */
94492559Sdes	ucp = buffer_ptr(b);
94560573Skris	if (ucp[0] == 0x42) {	/* Byte order MSB first. */
94660573Skris		proto_len = 256 * ucp[6] + ucp[7];
94760573Skris		data_len = 256 * ucp[8] + ucp[9];
94860573Skris	} else if (ucp[0] == 0x6c) {	/* Byte order LSB first. */
94960573Skris		proto_len = ucp[6] + 256 * ucp[7];
95060573Skris		data_len = ucp[8] + 256 * ucp[9];
95160573Skris	} else {
952124207Sdes		debug2("Initial X11 packet contains bad byte order byte: 0x%x",
95392559Sdes		    ucp[0]);
95460573Skris		return -1;
95560573Skris	}
95657429Smarkm
95760573Skris	/* Check if the whole packet is in buffer. */
95892559Sdes	if (buffer_len(b) <
95960573Skris	    12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
96060573Skris		return 0;
96157429Smarkm
96260573Skris	/* Check if authentication protocol matches. */
96360573Skris	if (proto_len != strlen(x11_saved_proto) ||
96460573Skris	    memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
965124207Sdes		debug2("X11 connection uses different authentication protocol.");
96660573Skris		return -1;
96760573Skris	}
96860573Skris	/* Check if authentication data matches our fake data. */
96960573Skris	if (data_len != x11_fake_data_len ||
970215116Sdes	    timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
97160573Skris		x11_fake_data, x11_fake_data_len) != 0) {
972124207Sdes		debug2("X11 auth data does not match fake data.");
97360573Skris		return -1;
97460573Skris	}
97560573Skris	/* Check fake data length */
97660573Skris	if (x11_fake_data_len != x11_saved_data_len) {
97760573Skris		error("X11 fake_data_len %d != saved_data_len %d",
97860573Skris		    x11_fake_data_len, x11_saved_data_len);
97960573Skris		return -1;
98060573Skris	}
98160573Skris	/*
98260573Skris	 * Received authentication protocol and data match
98360573Skris	 * our fake data. Substitute the fake data with real
98460573Skris	 * data.
98560573Skris	 */
98660573Skris	memcpy(ucp + 12 + ((proto_len + 3) & ~3),
98760573Skris	    x11_saved_data, x11_saved_data_len);
98860573Skris	return 1;
98960573Skris}
99057429Smarkm
99192559Sdesstatic void
992162856Sdeschannel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
99360573Skris{
99492559Sdes	int ret = x11_open_helper(&c->output);
995106130Sdes
99660573Skris	if (ret == 1) {
99760573Skris		/* Start normal processing for the channel. */
99860573Skris		c->type = SSH_CHANNEL_OPEN;
99960573Skris		channel_pre_open_13(c, readset, writeset);
100060573Skris	} else if (ret == -1) {
100160573Skris		/*
100260573Skris		 * We have received an X11 connection that has bad
100360573Skris		 * authentication information.
100460573Skris		 */
1005124207Sdes		logit("X11 connection rejected because of wrong authentication.");
100660573Skris		buffer_clear(&c->input);
100760573Skris		buffer_clear(&c->output);
100892559Sdes		channel_close_fd(&c->sock);
100960573Skris		c->sock = -1;
101060573Skris		c->type = SSH_CHANNEL_CLOSED;
101160573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
101260573Skris		packet_put_int(c->remote_id);
101360573Skris		packet_send();
101460573Skris	}
101560573Skris}
101657429Smarkm
101792559Sdesstatic void
1018162856Sdeschannel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
101960573Skris{
102092559Sdes	int ret = x11_open_helper(&c->output);
102192559Sdes
102292559Sdes	/* c->force_drain = 1; */
102392559Sdes
102460573Skris	if (ret == 1) {
102560573Skris		c->type = SSH_CHANNEL_OPEN;
102692559Sdes		channel_pre_open(c, readset, writeset);
102792559Sdes	} else if (ret == -1) {
1028124207Sdes		logit("X11 connection rejected because of wrong authentication.");
1029124207Sdes		debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
103092559Sdes		chan_read_failed(c);
103192559Sdes		buffer_clear(&c->input);
103292559Sdes		chan_ibuf_empty(c);
103392559Sdes		buffer_clear(&c->output);
103492559Sdes		/* for proto v1, the peer will send an IEOF */
103560573Skris		if (compat20)
103692559Sdes			chan_write_failed(c);
103760573Skris		else
103892559Sdes			c->type = SSH_CHANNEL_OPEN;
1039124207Sdes		debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
104060573Skris	}
104160573Skris}
104257429Smarkm
1043204917Sdesstatic void
1044204917Sdeschannel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1045204917Sdes{
1046215116Sdes	if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
1047204917Sdes	    buffer_check_alloc(&c->input, CHAN_RBUF))
1048204917Sdes		FD_SET(c->rfd, readset);
1049204917Sdes	if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
1050204917Sdes		/* clear buffer immediately (discard any partial packet) */
1051204917Sdes		buffer_clear(&c->input);
1052204917Sdes		chan_ibuf_empty(c);
1053204917Sdes		/* Start output drain. XXX just kill chan? */
1054204917Sdes		chan_rcvd_oclose(c);
1055204917Sdes	}
1056204917Sdes	if (c->ostate == CHAN_OUTPUT_OPEN ||
1057204917Sdes	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
1058204917Sdes		if (buffer_len(&c->output) > 0)
1059204917Sdes			FD_SET(c->wfd, writeset);
1060204917Sdes		else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
1061204917Sdes			chan_obuf_empty(c);
1062204917Sdes	}
1063204917Sdes}
1064204917Sdes
106576262Sgreen/* try to decode a socks4 header */
1066162856Sdes/* ARGSUSED */
106792559Sdesstatic int
1068162856Sdeschannel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
106976262Sgreen{
1070106130Sdes	char *p, *host;
1071192595Sdes	u_int len, have, i, found, need;
107292559Sdes	char username[256];
107376262Sgreen	struct {
107476262Sgreen		u_int8_t version;
107576262Sgreen		u_int8_t command;
107676262Sgreen		u_int16_t dest_port;
107776262Sgreen		struct in_addr dest_addr;
107876262Sgreen	} s4_req, s4_rsp;
107976262Sgreen
108076262Sgreen	debug2("channel %d: decode socks4", c->self);
108176262Sgreen
108276262Sgreen	have = buffer_len(&c->input);
108376262Sgreen	len = sizeof(s4_req);
108476262Sgreen	if (have < len)
108576262Sgreen		return 0;
108676262Sgreen	p = buffer_ptr(&c->input);
1087192595Sdes
1088192595Sdes	need = 1;
1089192595Sdes	/* SOCKS4A uses an invalid IP address 0.0.0.x */
1090192595Sdes	if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) {
1091192595Sdes		debug2("channel %d: socks4a request", c->self);
1092192595Sdes		/* ... and needs an extra string (the hostname) */
1093192595Sdes		need = 2;
1094192595Sdes	}
1095192595Sdes	/* Check for terminating NUL on the string(s) */
109676262Sgreen	for (found = 0, i = len; i < have; i++) {
109776262Sgreen		if (p[i] == '\0') {
1098192595Sdes			found++;
1099192595Sdes			if (found == need)
1100192595Sdes				break;
110176262Sgreen		}
110276262Sgreen		if (i > 1024) {
110376262Sgreen			/* the peer is probably sending garbage */
110476262Sgreen			debug("channel %d: decode socks4: too long",
110576262Sgreen			    c->self);
110676262Sgreen			return -1;
110776262Sgreen		}
110876262Sgreen	}
1109192595Sdes	if (found < need)
111076262Sgreen		return 0;
111176262Sgreen	buffer_get(&c->input, (char *)&s4_req.version, 1);
111276262Sgreen	buffer_get(&c->input, (char *)&s4_req.command, 1);
111376262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
111476262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
111576262Sgreen	have = buffer_len(&c->input);
111676262Sgreen	p = buffer_ptr(&c->input);
111776262Sgreen	len = strlen(p);
111876262Sgreen	debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
1119192595Sdes	len++;					/* trailing '\0' */
112076262Sgreen	if (len > have)
112176262Sgreen		fatal("channel %d: decode socks4: len %d > have %d",
112276262Sgreen		    c->self, len, have);
112376262Sgreen	strlcpy(username, p, sizeof(username));
112476262Sgreen	buffer_consume(&c->input, len);
112576262Sgreen
1126255767Sdes	free(c->path);
1127255767Sdes	c->path = NULL;
1128192595Sdes	if (need == 1) {			/* SOCKS4: one string */
1129192595Sdes		host = inet_ntoa(s4_req.dest_addr);
1130192595Sdes		c->path = xstrdup(host);
1131192595Sdes	} else {				/* SOCKS4A: two strings */
1132192595Sdes		have = buffer_len(&c->input);
1133192595Sdes		p = buffer_ptr(&c->input);
1134192595Sdes		len = strlen(p);
1135192595Sdes		debug2("channel %d: decode socks4a: host %s/%d",
1136192595Sdes		    c->self, p, len);
1137192595Sdes		len++;				/* trailing '\0' */
1138192595Sdes		if (len > have)
1139192595Sdes			fatal("channel %d: decode socks4a: len %d > have %d",
1140192595Sdes			    c->self, len, have);
1141192595Sdes		if (len > NI_MAXHOST) {
1142192595Sdes			error("channel %d: hostname \"%.100s\" too long",
1143192595Sdes			    c->self, p);
1144192595Sdes			return -1;
1145192595Sdes		}
1146192595Sdes		c->path = xstrdup(p);
1147192595Sdes		buffer_consume(&c->input, len);
1148192595Sdes	}
114976262Sgreen	c->host_port = ntohs(s4_req.dest_port);
115092559Sdes
1151124207Sdes	debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
1152192595Sdes	    c->self, c->path, c->host_port, s4_req.command);
115376262Sgreen
115476262Sgreen	if (s4_req.command != 1) {
1155192595Sdes		debug("channel %d: cannot handle: %s cn %d",
1156192595Sdes		    c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command);
115776262Sgreen		return -1;
115876262Sgreen	}
115976262Sgreen	s4_rsp.version = 0;			/* vn: 0 for reply */
116076262Sgreen	s4_rsp.command = 90;			/* cd: req granted */
116176262Sgreen	s4_rsp.dest_port = 0;			/* ignored */
116276262Sgreen	s4_rsp.dest_addr.s_addr = INADDR_ANY;	/* ignored */
1163162856Sdes	buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp));
116476262Sgreen	return 1;
116576262Sgreen}
116676262Sgreen
1167124207Sdes/* try to decode a socks5 header */
1168124207Sdes#define SSH_SOCKS5_AUTHDONE	0x1000
1169124207Sdes#define SSH_SOCKS5_NOAUTH	0x00
1170124207Sdes#define SSH_SOCKS5_IPV4		0x01
1171124207Sdes#define SSH_SOCKS5_DOMAIN	0x03
1172124207Sdes#define SSH_SOCKS5_IPV6		0x04
1173124207Sdes#define SSH_SOCKS5_CONNECT	0x01
1174124207Sdes#define SSH_SOCKS5_SUCCESS	0x00
1175124207Sdes
1176162856Sdes/* ARGSUSED */
1177124207Sdesstatic int
1178162856Sdeschannel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1179124207Sdes{
1180124207Sdes	struct {
1181124207Sdes		u_int8_t version;
1182124207Sdes		u_int8_t command;
1183124207Sdes		u_int8_t reserved;
1184124207Sdes		u_int8_t atyp;
1185124207Sdes	} s5_req, s5_rsp;
1186124207Sdes	u_int16_t dest_port;
1187255767Sdes	char dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
1188255767Sdes	u_char *p;
1189162856Sdes	u_int have, need, i, found, nmethods, addrlen, af;
1190124207Sdes
1191124207Sdes	debug2("channel %d: decode socks5", c->self);
1192124207Sdes	p = buffer_ptr(&c->input);
1193124207Sdes	if (p[0] != 0x05)
1194124207Sdes		return -1;
1195124207Sdes	have = buffer_len(&c->input);
1196124207Sdes	if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
1197124207Sdes		/* format: ver | nmethods | methods */
1198126273Sdes		if (have < 2)
1199124207Sdes			return 0;
1200124207Sdes		nmethods = p[1];
1201124207Sdes		if (have < nmethods + 2)
1202124207Sdes			return 0;
1203124207Sdes		/* look for method: "NO AUTHENTICATION REQUIRED" */
1204181111Sdes		for (found = 0, i = 2; i < nmethods + 2; i++) {
1205162856Sdes			if (p[i] == SSH_SOCKS5_NOAUTH) {
1206124207Sdes				found = 1;
1207124207Sdes				break;
1208124207Sdes			}
1209124207Sdes		}
1210124207Sdes		if (!found) {
1211124207Sdes			debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
1212124207Sdes			    c->self);
1213124207Sdes			return -1;
1214124207Sdes		}
1215124207Sdes		buffer_consume(&c->input, nmethods + 2);
1216124207Sdes		buffer_put_char(&c->output, 0x05);		/* version */
1217124207Sdes		buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH);	/* method */
1218124207Sdes		FD_SET(c->sock, writeset);
1219124207Sdes		c->flags |= SSH_SOCKS5_AUTHDONE;
1220124207Sdes		debug2("channel %d: socks5 auth done", c->self);
1221124207Sdes		return 0;				/* need more */
1222124207Sdes	}
1223124207Sdes	debug2("channel %d: socks5 post auth", c->self);
1224124207Sdes	if (have < sizeof(s5_req)+1)
1225124207Sdes		return 0;			/* need more */
1226162856Sdes	memcpy(&s5_req, p, sizeof(s5_req));
1227124207Sdes	if (s5_req.version != 0x05 ||
1228124207Sdes	    s5_req.command != SSH_SOCKS5_CONNECT ||
1229124207Sdes	    s5_req.reserved != 0x00) {
1230124207Sdes		debug2("channel %d: only socks5 connect supported", c->self);
1231124207Sdes		return -1;
1232124207Sdes	}
1233147005Sdes	switch (s5_req.atyp){
1234124207Sdes	case SSH_SOCKS5_IPV4:
1235124207Sdes		addrlen = 4;
1236124207Sdes		af = AF_INET;
1237124207Sdes		break;
1238124207Sdes	case SSH_SOCKS5_DOMAIN:
1239124207Sdes		addrlen = p[sizeof(s5_req)];
1240124207Sdes		af = -1;
1241124207Sdes		break;
1242124207Sdes	case SSH_SOCKS5_IPV6:
1243124207Sdes		addrlen = 16;
1244124207Sdes		af = AF_INET6;
1245124207Sdes		break;
1246124207Sdes	default:
1247124207Sdes		debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
1248124207Sdes		return -1;
1249124207Sdes	}
1250162856Sdes	need = sizeof(s5_req) + addrlen + 2;
1251162856Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1252162856Sdes		need++;
1253162856Sdes	if (have < need)
1254124207Sdes		return 0;
1255124207Sdes	buffer_consume(&c->input, sizeof(s5_req));
1256124207Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1257124207Sdes		buffer_consume(&c->input, 1);    /* host string length */
1258255767Sdes	buffer_get(&c->input, &dest_addr, addrlen);
1259124207Sdes	buffer_get(&c->input, (char *)&dest_port, 2);
1260124207Sdes	dest_addr[addrlen] = '\0';
1261255767Sdes	free(c->path);
1262255767Sdes	c->path = NULL;
1263192595Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
1264192595Sdes		if (addrlen >= NI_MAXHOST) {
1265192595Sdes			error("channel %d: dynamic request: socks5 hostname "
1266192595Sdes			    "\"%.100s\" too long", c->self, dest_addr);
1267192595Sdes			return -1;
1268192595Sdes		}
1269192595Sdes		c->path = xstrdup(dest_addr);
1270192595Sdes	} else {
1271192595Sdes		if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL)
1272192595Sdes			return -1;
1273192595Sdes		c->path = xstrdup(ntop);
1274192595Sdes	}
1275124207Sdes	c->host_port = ntohs(dest_port);
1276126273Sdes
1277124207Sdes	debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
1278124207Sdes	    c->self, c->path, c->host_port, s5_req.command);
1279124207Sdes
1280124207Sdes	s5_rsp.version = 0x05;
1281124207Sdes	s5_rsp.command = SSH_SOCKS5_SUCCESS;
1282124207Sdes	s5_rsp.reserved = 0;			/* ignored */
1283124207Sdes	s5_rsp.atyp = SSH_SOCKS5_IPV4;
1284124207Sdes	dest_port = 0;				/* ignored */
1285124207Sdes
1286162856Sdes	buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
1287255767Sdes	buffer_put_int(&c->output, ntohl(INADDR_ANY)); /* bind address */
1288162856Sdes	buffer_append(&c->output, &dest_port, sizeof(dest_port));
1289124207Sdes	return 1;
1290124207Sdes}
1291124207Sdes
1292204917SdesChannel *
1293204917Sdeschannel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
1294204917Sdes    int in, int out)
1295204917Sdes{
1296204917Sdes	Channel *c;
1297204917Sdes
1298204917Sdes	debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
1299204917Sdes	    port_to_connect);
1300204917Sdes
1301204917Sdes	c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
1302204917Sdes	    -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
1303204917Sdes	    0, "stdio-forward", /*nonblock*/0);
1304204917Sdes
1305204917Sdes	c->path = xstrdup(host_to_connect);
1306204917Sdes	c->host_port = port_to_connect;
1307204917Sdes	c->listening_port = 0;
1308204917Sdes	c->force_drain = 1;
1309204917Sdes
1310204917Sdes	channel_register_fds(c, in, out, -1, 0, 1, 0);
1311204917Sdes	port_open_helper(c, "direct-tcpip");
1312204917Sdes
1313204917Sdes	return c;
1314204917Sdes}
1315204917Sdes
131676262Sgreen/* dynamic port forwarding */
131792559Sdesstatic void
1318162856Sdeschannel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
131976262Sgreen{
132076262Sgreen	u_char *p;
1321149753Sdes	u_int have;
1322149753Sdes	int ret;
132376262Sgreen
132476262Sgreen	have = buffer_len(&c->input);
132576262Sgreen	debug2("channel %d: pre_dynamic: have %d", c->self, have);
132676262Sgreen	/* buffer_dump(&c->input); */
132776262Sgreen	/* check if the fixed size part of the packet is in buffer. */
1328124207Sdes	if (have < 3) {
132976262Sgreen		/* need more */
133076262Sgreen		FD_SET(c->sock, readset);
133176262Sgreen		return;
133276262Sgreen	}
133376262Sgreen	/* try to guess the protocol */
133476262Sgreen	p = buffer_ptr(&c->input);
133576262Sgreen	switch (p[0]) {
133676262Sgreen	case 0x04:
133776262Sgreen		ret = channel_decode_socks4(c, readset, writeset);
133876262Sgreen		break;
1339124207Sdes	case 0x05:
1340124207Sdes		ret = channel_decode_socks5(c, readset, writeset);
1341124207Sdes		break;
134276262Sgreen	default:
134376262Sgreen		ret = -1;
134476262Sgreen		break;
134576262Sgreen	}
134676262Sgreen	if (ret < 0) {
134792559Sdes		chan_mark_dead(c);
134876262Sgreen	} else if (ret == 0) {
134976262Sgreen		debug2("channel %d: pre_dynamic: need more", c->self);
135076262Sgreen		/* need more */
135176262Sgreen		FD_SET(c->sock, readset);
135276262Sgreen	} else {
135376262Sgreen		/* switch to the next state */
135476262Sgreen		c->type = SSH_CHANNEL_OPENING;
135576262Sgreen		port_open_helper(c, "direct-tcpip");
135676262Sgreen	}
135776262Sgreen}
135876262Sgreen
135960573Skris/* This is our fake X11 server socket. */
1360162856Sdes/* ARGSUSED */
136192559Sdesstatic void
1362162856Sdeschannel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
136360573Skris{
136492559Sdes	Channel *nc;
1365181111Sdes	struct sockaddr_storage addr;
1366255767Sdes	int newsock, oerrno;
136760573Skris	socklen_t addrlen;
136876262Sgreen	char buf[16384], *remote_ipaddr;
136960573Skris	int remote_port;
137057429Smarkm
137160573Skris	if (FD_ISSET(c->sock, readset)) {
137260573Skris		debug("X11 connection requested.");
137360573Skris		addrlen = sizeof(addr);
1374181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
137592559Sdes		if (c->single_connection) {
1376255767Sdes			oerrno = errno;
1377124207Sdes			debug2("single_connection: closing X11 listener.");
137892559Sdes			channel_close_fd(&c->sock);
137992559Sdes			chan_mark_dead(c);
1380255767Sdes			errno = oerrno;
138192559Sdes		}
138260573Skris		if (newsock < 0) {
1383255767Sdes			if (errno != EINTR && errno != EWOULDBLOCK &&
1384255767Sdes			    errno != ECONNABORTED)
1385255767Sdes				error("accept: %.100s", strerror(errno));
1386240075Sdes			if (errno == EMFILE || errno == ENFILE)
1387255767Sdes				c->notbefore = monotime() + 1;
138860573Skris			return;
138960573Skris		}
139092559Sdes		set_nodelay(newsock);
139176262Sgreen		remote_ipaddr = get_peer_ipaddr(newsock);
139260573Skris		remote_port = get_peer_port(newsock);
139360573Skris		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
139476262Sgreen		    remote_ipaddr, remote_port);
139557429Smarkm
139692559Sdes		nc = channel_new("accepted x11 socket",
139760573Skris		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
1398124207Sdes		    c->local_window_max, c->local_maxpacket, 0, buf, 1);
139960573Skris		if (compat20) {
140060573Skris			packet_start(SSH2_MSG_CHANNEL_OPEN);
140160573Skris			packet_put_cstring("x11");
140292559Sdes			packet_put_int(nc->self);
140392559Sdes			packet_put_int(nc->local_window_max);
140492559Sdes			packet_put_int(nc->local_maxpacket);
140576262Sgreen			/* originator ipaddr and port */
140676262Sgreen			packet_put_cstring(remote_ipaddr);
140760573Skris			if (datafellows & SSH_BUG_X11FWD) {
1408124207Sdes				debug2("ssh2 x11 bug compat mode");
140957429Smarkm			} else {
141060573Skris				packet_put_int(remote_port);
141157429Smarkm			}
141260573Skris			packet_send();
141360573Skris		} else {
141460573Skris			packet_start(SSH_SMSG_X11_OPEN);
141592559Sdes			packet_put_int(nc->self);
141692559Sdes			if (packet_get_protocol_flags() &
141792559Sdes			    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
141892559Sdes				packet_put_cstring(buf);
141960573Skris			packet_send();
142057429Smarkm		}
1421255767Sdes		free(remote_ipaddr);
142257429Smarkm	}
142357429Smarkm}
142457429Smarkm
142592559Sdesstatic void
142676262Sgreenport_open_helper(Channel *c, char *rtype)
142776262Sgreen{
142876262Sgreen	int direct;
142976262Sgreen	char buf[1024];
143076262Sgreen	char *remote_ipaddr = get_peer_ipaddr(c->sock);
1431149753Sdes	int remote_port = get_peer_port(c->sock);
143276262Sgreen
1433204917Sdes	if (remote_port == -1) {
1434204917Sdes		/* Fake addr/port to appease peers that validate it (Tectia) */
1435255767Sdes		free(remote_ipaddr);
1436204917Sdes		remote_ipaddr = xstrdup("127.0.0.1");
1437204917Sdes		remote_port = 65535;
1438204917Sdes	}
1439204917Sdes
144076262Sgreen	direct = (strcmp(rtype, "direct-tcpip") == 0);
144176262Sgreen
144276262Sgreen	snprintf(buf, sizeof buf,
144376262Sgreen	    "%s: listening port %d for %.100s port %d, "
144476262Sgreen	    "connect from %.200s port %d",
144576262Sgreen	    rtype, c->listening_port, c->path, c->host_port,
144676262Sgreen	    remote_ipaddr, remote_port);
144776262Sgreen
1448255767Sdes	free(c->remote_name);
144976262Sgreen	c->remote_name = xstrdup(buf);
145076262Sgreen
145176262Sgreen	if (compat20) {
145276262Sgreen		packet_start(SSH2_MSG_CHANNEL_OPEN);
145376262Sgreen		packet_put_cstring(rtype);
145476262Sgreen		packet_put_int(c->self);
145576262Sgreen		packet_put_int(c->local_window_max);
145676262Sgreen		packet_put_int(c->local_maxpacket);
145776262Sgreen		if (direct) {
145876262Sgreen			/* target host, port */
145976262Sgreen			packet_put_cstring(c->path);
146076262Sgreen			packet_put_int(c->host_port);
146176262Sgreen		} else {
146276262Sgreen			/* listen address, port */
146376262Sgreen			packet_put_cstring(c->path);
146476262Sgreen			packet_put_int(c->listening_port);
146576262Sgreen		}
146676262Sgreen		/* originator host and port */
146776262Sgreen		packet_put_cstring(remote_ipaddr);
1468149753Sdes		packet_put_int((u_int)remote_port);
146976262Sgreen		packet_send();
147076262Sgreen	} else {
147176262Sgreen		packet_start(SSH_MSG_PORT_OPEN);
147276262Sgreen		packet_put_int(c->self);
147376262Sgreen		packet_put_cstring(c->path);
147476262Sgreen		packet_put_int(c->host_port);
147592559Sdes		if (packet_get_protocol_flags() &
147692559Sdes		    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
147776262Sgreen			packet_put_cstring(c->remote_name);
147876262Sgreen		packet_send();
147976262Sgreen	}
1480255767Sdes	free(remote_ipaddr);
148176262Sgreen}
148276262Sgreen
1483157019Sdesstatic void
1484157019Sdeschannel_set_reuseaddr(int fd)
1485157019Sdes{
1486157019Sdes	int on = 1;
1487157019Sdes
1488157019Sdes	/*
1489157019Sdes	 * Set socket options.
1490157019Sdes	 * Allow local port reuse in TIME_WAIT.
1491157019Sdes	 */
1492157019Sdes	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1493157019Sdes		error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
1494157019Sdes}
1495157019Sdes
149657429Smarkm/*
149760573Skris * This socket is listening for connections to a forwarded TCP/IP port.
149857429Smarkm */
1499162856Sdes/* ARGSUSED */
150092559Sdesstatic void
1501162856Sdeschannel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
150257429Smarkm{
150376262Sgreen	Channel *nc;
1504181111Sdes	struct sockaddr_storage addr;
150592559Sdes	int newsock, nextstate;
150657429Smarkm	socklen_t addrlen;
150776262Sgreen	char *rtype;
150857429Smarkm
150960573Skris	if (FD_ISSET(c->sock, readset)) {
151060573Skris		debug("Connection to port %d forwarding "
151160573Skris		    "to %.100s port %d requested.",
151260573Skris		    c->listening_port, c->path, c->host_port);
151376262Sgreen
151492559Sdes		if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
151592559Sdes			nextstate = SSH_CHANNEL_OPENING;
151692559Sdes			rtype = "forwarded-tcpip";
151792559Sdes		} else {
151892559Sdes			if (c->host_port == 0) {
151992559Sdes				nextstate = SSH_CHANNEL_DYNAMIC;
152092559Sdes				rtype = "dynamic-tcpip";
152192559Sdes			} else {
152292559Sdes				nextstate = SSH_CHANNEL_OPENING;
152392559Sdes				rtype = "direct-tcpip";
152492559Sdes			}
152592559Sdes		}
152676262Sgreen
152760573Skris		addrlen = sizeof(addr);
1528181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
152960573Skris		if (newsock < 0) {
1530255767Sdes			if (errno != EINTR && errno != EWOULDBLOCK &&
1531255767Sdes			    errno != ECONNABORTED)
1532255767Sdes				error("accept: %.100s", strerror(errno));
1533240075Sdes			if (errno == EMFILE || errno == ENFILE)
1534255767Sdes				c->notbefore = monotime() + 1;
153560573Skris			return;
153660573Skris		}
153792559Sdes		set_nodelay(newsock);
1538124207Sdes		nc = channel_new(rtype, nextstate, newsock, newsock, -1,
1539124207Sdes		    c->local_window_max, c->local_maxpacket, 0, rtype, 1);
154076262Sgreen		nc->listening_port = c->listening_port;
154176262Sgreen		nc->host_port = c->host_port;
1542192595Sdes		if (c->path != NULL)
1543192595Sdes			nc->path = xstrdup(c->path);
154476262Sgreen
1545204917Sdes		if (nextstate != SSH_CHANNEL_DYNAMIC)
154676262Sgreen			port_open_helper(nc, rtype);
154760573Skris	}
154860573Skris}
154957429Smarkm
155060573Skris/*
155160573Skris * This is the authentication agent socket listening for connections from
155260573Skris * clients.
155360573Skris */
1554162856Sdes/* ARGSUSED */
155592559Sdesstatic void
1556162856Sdeschannel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
155760573Skris{
155892559Sdes	Channel *nc;
155992559Sdes	int newsock;
1560181111Sdes	struct sockaddr_storage addr;
156160573Skris	socklen_t addrlen;
156257429Smarkm
156360573Skris	if (FD_ISSET(c->sock, readset)) {
156460573Skris		addrlen = sizeof(addr);
1565181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
156660573Skris		if (newsock < 0) {
1567240075Sdes			error("accept from auth socket: %.100s",
1568240075Sdes			    strerror(errno));
1569240075Sdes			if (errno == EMFILE || errno == ENFILE)
1570255767Sdes				c->notbefore = monotime() + 1;
157160573Skris			return;
157260573Skris		}
157392559Sdes		nc = channel_new("accepted auth socket",
157476262Sgreen		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
157576262Sgreen		    c->local_window_max, c->local_maxpacket,
1576124207Sdes		    0, "accepted auth socket", 1);
157776262Sgreen		if (compat20) {
157876262Sgreen			packet_start(SSH2_MSG_CHANNEL_OPEN);
157976262Sgreen			packet_put_cstring("auth-agent@openssh.com");
158092559Sdes			packet_put_int(nc->self);
158176262Sgreen			packet_put_int(c->local_window_max);
158276262Sgreen			packet_put_int(c->local_maxpacket);
158376262Sgreen		} else {
158476262Sgreen			packet_start(SSH_SMSG_AGENT_OPEN);
158592559Sdes			packet_put_int(nc->self);
158676262Sgreen		}
158760573Skris		packet_send();
158860573Skris	}
158960573Skris}
159057429Smarkm
1591162856Sdes/* ARGSUSED */
159292559Sdesstatic void
1593162856Sdeschannel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
159476262Sgreen{
1595181111Sdes	int err = 0, sock;
159692559Sdes	socklen_t sz = sizeof(err);
159792559Sdes
159876262Sgreen	if (FD_ISSET(c->sock, writeset)) {
159992559Sdes		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
160092559Sdes			err = errno;
160192559Sdes			error("getsockopt SO_ERROR failed");
160292559Sdes		}
160392559Sdes		if (err == 0) {
1604181111Sdes			debug("channel %d: connected to %s port %d",
1605181111Sdes			    c->self, c->connect_ctx.host, c->connect_ctx.port);
1606181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
160792559Sdes			c->type = SSH_CHANNEL_OPEN;
160892559Sdes			if (compat20) {
160992559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
161092559Sdes				packet_put_int(c->remote_id);
161192559Sdes				packet_put_int(c->self);
161292559Sdes				packet_put_int(c->local_window);
161392559Sdes				packet_put_int(c->local_maxpacket);
161492559Sdes			} else {
161592559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
161692559Sdes				packet_put_int(c->remote_id);
161792559Sdes				packet_put_int(c->self);
161892559Sdes			}
161976262Sgreen		} else {
1620181111Sdes			debug("channel %d: connection failed: %s",
162192559Sdes			    c->self, strerror(err));
1622181111Sdes			/* Try next address, if any */
1623181111Sdes			if ((sock = connect_next(&c->connect_ctx)) > 0) {
1624181111Sdes				close(c->sock);
1625181111Sdes				c->sock = c->rfd = c->wfd = sock;
1626181111Sdes				channel_max_fd = channel_find_maxfd();
1627181111Sdes				return;
1628181111Sdes			}
1629181111Sdes			/* Exhausted all addresses */
1630181111Sdes			error("connect_to %.100s port %d: failed.",
1631181111Sdes			    c->connect_ctx.host, c->connect_ctx.port);
1632181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
163392559Sdes			if (compat20) {
163492559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
163592559Sdes				packet_put_int(c->remote_id);
163692559Sdes				packet_put_int(SSH2_OPEN_CONNECT_FAILED);
163792559Sdes				if (!(datafellows & SSH_BUG_OPENFAILURE)) {
163892559Sdes					packet_put_cstring(strerror(err));
163992559Sdes					packet_put_cstring("");
164092559Sdes				}
164176262Sgreen			} else {
164292559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
164392559Sdes				packet_put_int(c->remote_id);
164476262Sgreen			}
164592559Sdes			chan_mark_dead(c);
164676262Sgreen		}
164792559Sdes		packet_send();
164876262Sgreen	}
164976262Sgreen}
165076262Sgreen
1651162856Sdes/* ARGSUSED */
165292559Sdesstatic int
1653162856Sdeschannel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
165460573Skris{
1655147005Sdes	char buf[CHAN_RBUF];
1656181111Sdes	int len, force;
165757429Smarkm
1658181111Sdes	force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
1659181111Sdes	if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
1660162856Sdes		errno = 0;
166160573Skris		len = read(c->rfd, buf, sizeof(buf));
1662181111Sdes		if (len < 0 && (errno == EINTR ||
1663181111Sdes		    ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
166460573Skris			return 1;
1665162856Sdes#ifndef PTY_ZEROREAD
166678827Sgreen		if (len <= 0) {
1667162856Sdes#else
1668162856Sdes		if ((!c->isatty && len <= 0) ||
1669162856Sdes		    (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
1670162856Sdes#endif
1671124207Sdes			debug2("channel %d: read<=0 rfd %d len %d",
167260573Skris			    c->self, c->rfd, len);
167376262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1674124207Sdes				debug2("channel %d: not open", c->self);
167592559Sdes				chan_mark_dead(c);
167676262Sgreen				return -1;
167776262Sgreen			} else if (compat13) {
167892559Sdes				buffer_clear(&c->output);
167960573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
1680124207Sdes				debug2("channel %d: input draining.", c->self);
168160573Skris			} else {
168260573Skris				chan_read_failed(c);
168357429Smarkm			}
168460573Skris			return -1;
168560573Skris		}
168692559Sdes		if (c->input_filter != NULL) {
168765668Skris			if (c->input_filter(c, buf, len) == -1) {
1688124207Sdes				debug2("channel %d: filter stops", c->self);
168965668Skris				chan_read_failed(c);
169065668Skris			}
1691157019Sdes		} else if (c->datagram) {
1692157019Sdes			buffer_put_string(&c->input, buf, len);
169365668Skris		} else {
169465668Skris			buffer_append(&c->input, buf, len);
169565668Skris		}
169660573Skris	}
169760573Skris	return 1;
169860573Skris}
1699162856Sdes
1700162856Sdes/* ARGSUSED */
170192559Sdesstatic int
1702162856Sdeschannel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
170360573Skris{
170476262Sgreen	struct termios tio;
1705157019Sdes	u_char *data = NULL, *buf;
1706215116Sdes	u_int dlen, olen = 0;
170760573Skris	int len;
170860573Skris
170960573Skris	/* Send buffered output data to the socket. */
171060573Skris	if (c->wfd != -1 &&
171160573Skris	    FD_ISSET(c->wfd, writeset) &&
171260573Skris	    buffer_len(&c->output) > 0) {
1713215116Sdes		olen = buffer_len(&c->output);
1714157019Sdes		if (c->output_filter != NULL) {
1715157019Sdes			if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1716157019Sdes				debug2("channel %d: filter stops", c->self);
1717157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1718157019Sdes					chan_mark_dead(c);
1719157019Sdes				else
1720157019Sdes					chan_write_failed(c);
1721157019Sdes				return -1;
1722157019Sdes			}
1723157019Sdes		} else if (c->datagram) {
1724157019Sdes			buf = data = buffer_get_string(&c->output, &dlen);
1725157019Sdes		} else {
1726157019Sdes			buf = data = buffer_ptr(&c->output);
1727157019Sdes			dlen = buffer_len(&c->output);
1728157019Sdes		}
1729157019Sdes
1730157019Sdes		if (c->datagram) {
1731157019Sdes			/* ignore truncated writes, datagrams might get lost */
1732157019Sdes			len = write(c->wfd, buf, dlen);
1733255767Sdes			free(data);
1734181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1735181111Sdes			    errno == EWOULDBLOCK))
1736157019Sdes				return 1;
1737157019Sdes			if (len <= 0) {
1738157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1739157019Sdes					chan_mark_dead(c);
1740157019Sdes				else
1741157019Sdes					chan_write_failed(c);
1742157019Sdes				return -1;
1743157019Sdes			}
1744215116Sdes			goto out;
1745157019Sdes		}
1746106130Sdes#ifdef _AIX
1747126273Sdes		/* XXX: Later AIX versions can't push as much data to tty */
1748126273Sdes		if (compat20 && c->wfd_isatty)
1749126273Sdes			dlen = MIN(dlen, 8*1024);
1750106130Sdes#endif
1751157019Sdes
1752157019Sdes		len = write(c->wfd, buf, dlen);
1753181111Sdes		if (len < 0 &&
1754181111Sdes		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
175560573Skris			return 1;
175660573Skris		if (len <= 0) {
175776262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1758124207Sdes				debug2("channel %d: not open", c->self);
175992559Sdes				chan_mark_dead(c);
176076262Sgreen				return -1;
176176262Sgreen			} else if (compat13) {
176292559Sdes				buffer_clear(&c->output);
1763124207Sdes				debug2("channel %d: input draining.", c->self);
176460573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
176560573Skris			} else {
176660573Skris				chan_write_failed(c);
176757429Smarkm			}
176860573Skris			return -1;
176960573Skris		}
1770197679Sdes#ifndef BROKEN_TCGETATTR_ICANON
1771157019Sdes		if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
177274500Sgreen			if (tcgetattr(c->wfd, &tio) == 0 &&
177374500Sgreen			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
177474500Sgreen				/*
177574500Sgreen				 * Simulate echo to reduce the impact of
177676262Sgreen				 * traffic analysis. We need to match the
177776262Sgreen				 * size of a SSH2_MSG_CHANNEL_DATA message
1778157019Sdes				 * (4 byte channel id + buf)
177974500Sgreen				 */
178076262Sgreen				packet_send_ignore(4 + len);
178174500Sgreen				packet_send();
178274500Sgreen			}
178374500Sgreen		}
1784197679Sdes#endif
178560573Skris		buffer_consume(&c->output, len);
178660573Skris	}
1787215116Sdes out:
1788215116Sdes	if (compat20 && olen > 0)
1789215116Sdes		c->local_consumed += olen - buffer_len(&c->output);
179060573Skris	return 1;
179160573Skris}
1792162856Sdes
179392559Sdesstatic int
1794162856Sdeschannel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
179560573Skris{
1796147005Sdes	char buf[CHAN_RBUF];
179760573Skris	int len;
179857429Smarkm
179960573Skris/** XXX handle drain efd, too */
180060573Skris	if (c->efd != -1) {
180160573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
180260573Skris		    FD_ISSET(c->efd, writeset) &&
180360573Skris		    buffer_len(&c->extended) > 0) {
180460573Skris			len = write(c->efd, buffer_ptr(&c->extended),
180560573Skris			    buffer_len(&c->extended));
180669587Sgreen			debug2("channel %d: written %d to efd %d",
180760573Skris			    c->self, len, c->efd);
1808181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1809181111Sdes			    errno == EWOULDBLOCK))
181076262Sgreen				return 1;
181176262Sgreen			if (len <= 0) {
181276262Sgreen				debug2("channel %d: closing write-efd %d",
181376262Sgreen				    c->self, c->efd);
181492559Sdes				channel_close_fd(&c->efd);
181576262Sgreen			} else {
181660573Skris				buffer_consume(&c->extended, len);
181760573Skris				c->local_consumed += len;
181857429Smarkm			}
1819215116Sdes		} else if (c->efd != -1 &&
1820215116Sdes		    (c->extended_usage == CHAN_EXTENDED_READ ||
1821215116Sdes		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
1822181111Sdes		    (c->detach_close || FD_ISSET(c->efd, readset))) {
182360573Skris			len = read(c->efd, buf, sizeof(buf));
182469587Sgreen			debug2("channel %d: read %d from efd %d",
182592559Sdes			    c->self, len, c->efd);
1826181111Sdes			if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
1827181111Sdes			    errno == EWOULDBLOCK) && !c->detach_close)))
182876262Sgreen				return 1;
182976262Sgreen			if (len <= 0) {
183076262Sgreen				debug2("channel %d: closing read-efd %d",
183160573Skris				    c->self, c->efd);
183292559Sdes				channel_close_fd(&c->efd);
183376262Sgreen			} else {
1834215116Sdes				if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
1835215116Sdes					debug3("channel %d: discard efd",
1836215116Sdes					    c->self);
1837215116Sdes				} else
1838215116Sdes					buffer_append(&c->extended, buf, len);
183976262Sgreen			}
184060573Skris		}
184160573Skris	}
184260573Skris	return 1;
184360573Skris}
1844162856Sdes
184592559Sdesstatic int
184676262Sgreenchannel_check_window(Channel *c)
184760573Skris{
184876262Sgreen	if (c->type == SSH_CHANNEL_OPEN &&
184976262Sgreen	    !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
1850181111Sdes	    ((c->local_window_max - c->local_window >
1851181111Sdes	    c->local_maxpacket*3) ||
1852181111Sdes	    c->local_window < c->local_window_max/2) &&
185360573Skris	    c->local_consumed > 0) {
1854224638Sbrooks		u_int addition = 0;
1855224638Sbrooks
1856224638Sbrooks		/* Adjust max window size if we are in a dynamic environment. */
1857224638Sbrooks		if (c->dynamic_window && c->tcpwinsz > c->local_window_max) {
1858224638Sbrooks			/*
1859224638Sbrooks			 * Grow the window somewhat aggressively to maintain
1860224638Sbrooks			 * pressure.
1861224638Sbrooks			 */
1862224638Sbrooks			addition = 1.5 * (c->tcpwinsz - c->local_window_max);
1863224638Sbrooks			c->local_window_max += addition;
1864224638Sbrooks		}
186560573Skris		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
186660573Skris		packet_put_int(c->remote_id);
1867224638Sbrooks		packet_put_int(c->local_consumed + addition);
186860573Skris		packet_send();
186969587Sgreen		debug2("channel %d: window %d sent adjust %d",
187060573Skris		    c->self, c->local_window,
187160573Skris		    c->local_consumed);
1872224638Sbrooks		c->local_window += c->local_consumed + addition;
187360573Skris		c->local_consumed = 0;
187460573Skris	}
187560573Skris	return 1;
187660573Skris}
187757429Smarkm
187892559Sdesstatic void
1879162856Sdeschannel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
188060573Skris{
188160573Skris	channel_handle_rfd(c, readset, writeset);
188260573Skris	channel_handle_wfd(c, readset, writeset);
188392559Sdes	if (!compat20)
188492559Sdes		return;
188560573Skris	channel_handle_efd(c, readset, writeset);
188676262Sgreen	channel_check_window(c);
188760573Skris}
188860573Skris
1889204917Sdesstatic u_int
1890204917Sdesread_mux(Channel *c, u_int need)
1891204917Sdes{
1892204917Sdes	char buf[CHAN_RBUF];
1893204917Sdes	int len;
1894204917Sdes	u_int rlen;
1895204917Sdes
1896204917Sdes	if (buffer_len(&c->input) < need) {
1897204917Sdes		rlen = need - buffer_len(&c->input);
1898204917Sdes		len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF));
1899204917Sdes		if (len <= 0) {
1900204917Sdes			if (errno != EINTR && errno != EAGAIN) {
1901204917Sdes				debug2("channel %d: ctl read<=0 rfd %d len %d",
1902204917Sdes				    c->self, c->rfd, len);
1903204917Sdes				chan_read_failed(c);
1904204917Sdes				return 0;
1905204917Sdes			}
1906204917Sdes		} else
1907204917Sdes			buffer_append(&c->input, buf, len);
1908204917Sdes	}
1909204917Sdes	return buffer_len(&c->input);
1910204917Sdes}
1911204917Sdes
1912204917Sdesstatic void
1913204917Sdeschannel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1914204917Sdes{
1915204917Sdes	u_int need;
1916204917Sdes	ssize_t len;
1917204917Sdes
1918204917Sdes	if (!compat20)
1919204917Sdes		fatal("%s: entered with !compat20", __func__);
1920204917Sdes
1921215116Sdes	if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
1922204917Sdes	    (c->istate == CHAN_INPUT_OPEN ||
1923204917Sdes	    c->istate == CHAN_INPUT_WAIT_DRAIN)) {
1924204917Sdes		/*
1925204917Sdes		 * Don't not read past the precise end of packets to
1926204917Sdes		 * avoid disrupting fd passing.
1927204917Sdes		 */
1928204917Sdes		if (read_mux(c, 4) < 4) /* read header */
1929204917Sdes			return;
1930204917Sdes		need = get_u32(buffer_ptr(&c->input));
1931204917Sdes#define CHANNEL_MUX_MAX_PACKET	(256 * 1024)
1932204917Sdes		if (need > CHANNEL_MUX_MAX_PACKET) {
1933204917Sdes			debug2("channel %d: packet too big %u > %u",
1934204917Sdes			    c->self, CHANNEL_MUX_MAX_PACKET, need);
1935204917Sdes			chan_rcvd_oclose(c);
1936204917Sdes			return;
1937204917Sdes		}
1938204917Sdes		if (read_mux(c, need + 4) < need + 4) /* read body */
1939204917Sdes			return;
1940204917Sdes		if (c->mux_rcb(c) != 0) {
1941204917Sdes			debug("channel %d: mux_rcb failed", c->self);
1942204917Sdes			chan_mark_dead(c);
1943204917Sdes			return;
1944204917Sdes		}
1945204917Sdes	}
1946204917Sdes
1947204917Sdes	if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
1948204917Sdes	    buffer_len(&c->output) > 0) {
1949204917Sdes		len = write(c->wfd, buffer_ptr(&c->output),
1950204917Sdes		    buffer_len(&c->output));
1951204917Sdes		if (len < 0 && (errno == EINTR || errno == EAGAIN))
1952204917Sdes			return;
1953204917Sdes		if (len <= 0) {
1954204917Sdes			chan_mark_dead(c);
1955204917Sdes			return;
1956204917Sdes		}
1957204917Sdes		buffer_consume(&c->output, len);
1958204917Sdes	}
1959204917Sdes}
1960204917Sdes
1961204917Sdesstatic void
1962204917Sdeschannel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
1963204917Sdes{
1964204917Sdes	Channel *nc;
1965204917Sdes	struct sockaddr_storage addr;
1966204917Sdes	socklen_t addrlen;
1967204917Sdes	int newsock;
1968204917Sdes	uid_t euid;
1969204917Sdes	gid_t egid;
1970204917Sdes
1971204917Sdes	if (!FD_ISSET(c->sock, readset))
1972204917Sdes		return;
1973204917Sdes
1974204917Sdes	debug("multiplexing control connection");
1975204917Sdes
1976204917Sdes	/*
1977204917Sdes	 * Accept connection on control socket
1978204917Sdes	 */
1979204917Sdes	memset(&addr, 0, sizeof(addr));
1980204917Sdes	addrlen = sizeof(addr);
1981204917Sdes	if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
1982204917Sdes	    &addrlen)) == -1) {
1983204917Sdes		error("%s accept: %s", __func__, strerror(errno));
1984240075Sdes		if (errno == EMFILE || errno == ENFILE)
1985255767Sdes			c->notbefore = monotime() + 1;
1986204917Sdes		return;
1987204917Sdes	}
1988204917Sdes
1989204917Sdes	if (getpeereid(newsock, &euid, &egid) < 0) {
1990204917Sdes		error("%s getpeereid failed: %s", __func__,
1991204917Sdes		    strerror(errno));
1992204917Sdes		close(newsock);
1993204917Sdes		return;
1994204917Sdes	}
1995204917Sdes	if ((euid != 0) && (getuid() != euid)) {
1996204917Sdes		error("multiplex uid mismatch: peer euid %u != uid %u",
1997204917Sdes		    (u_int)euid, (u_int)getuid());
1998204917Sdes		close(newsock);
1999204917Sdes		return;
2000204917Sdes	}
2001204917Sdes	nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
2002204917Sdes	    newsock, newsock, -1, c->local_window_max,
2003204917Sdes	    c->local_maxpacket, 0, "mux-control", 1);
2004204917Sdes	nc->mux_rcb = c->mux_rcb;
2005204917Sdes	debug3("%s: new mux channel %d fd %d", __func__,
2006204917Sdes	    nc->self, nc->sock);
2007204917Sdes	/* establish state */
2008204917Sdes	nc->mux_rcb(nc);
2009204917Sdes	/* mux state transitions must not elicit protocol messages */
2010204917Sdes	nc->flags |= CHAN_LOCAL;
2011204917Sdes}
2012204917Sdes
2013162856Sdes/* ARGSUSED */
201492559Sdesstatic void
2015162856Sdeschannel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
201660573Skris{
201760573Skris	int len;
2018106130Sdes
201960573Skris	/* Send buffered output data to the socket. */
202060573Skris	if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
202160573Skris		len = write(c->sock, buffer_ptr(&c->output),
202260573Skris			    buffer_len(&c->output));
202360573Skris		if (len <= 0)
202492559Sdes			buffer_clear(&c->output);
202560573Skris		else
202660573Skris			buffer_consume(&c->output, len);
202760573Skris	}
202860573Skris}
202960573Skris
203092559Sdesstatic void
203160573Skrischannel_handler_init_20(void)
203260573Skris{
203392559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
203460573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
203560573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
203676262Sgreen	channel_pre[SSH_CHANNEL_RPORT_LISTENER] =	&channel_pre_listener;
203760573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
203876262Sgreen	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
203976262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
204076262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
2041204917Sdes	channel_pre[SSH_CHANNEL_MUX_LISTENER] =		&channel_pre_listener;
2042204917Sdes	channel_pre[SSH_CHANNEL_MUX_CLIENT] =		&channel_pre_mux_client;
204360573Skris
204492559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
204560573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
204676262Sgreen	channel_post[SSH_CHANNEL_RPORT_LISTENER] =	&channel_post_port_listener;
204760573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
204876262Sgreen	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
204976262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
205092559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
2051204917Sdes	channel_post[SSH_CHANNEL_MUX_LISTENER] =	&channel_post_mux_listener;
2052204917Sdes	channel_post[SSH_CHANNEL_MUX_CLIENT] =		&channel_post_mux_client;
205360573Skris}
205460573Skris
205592559Sdesstatic void
205660573Skrischannel_handler_init_13(void)
205760573Skris{
205860573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_13;
205960573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open_13;
206060573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
206160573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
206260573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
206360573Skris	channel_pre[SSH_CHANNEL_INPUT_DRAINING] =	&channel_pre_input_draining;
206460573Skris	channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_pre_output_draining;
206576262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
206676262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
206760573Skris
206892559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
206960573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
207060573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
207160573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
207260573Skris	channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_post_output_drain_13;
207376262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
207492559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
207560573Skris}
207660573Skris
207792559Sdesstatic void
207860573Skrischannel_handler_init_15(void)
207960573Skris{
208092559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
208160573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
208260573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
208360573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
208460573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
208576262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
208676262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
208760573Skris
208860573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
208960573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
209060573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
209192559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
209276262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
209392559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
209460573Skris}
209560573Skris
209692559Sdesstatic void
209760573Skrischannel_handler_init(void)
209860573Skris{
209960573Skris	int i;
2100106130Sdes
210192559Sdes	for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
210260573Skris		channel_pre[i] = NULL;
210360573Skris		channel_post[i] = NULL;
210460573Skris	}
210560573Skris	if (compat20)
210660573Skris		channel_handler_init_20();
210760573Skris	else if (compat13)
210860573Skris		channel_handler_init_13();
210960573Skris	else
211060573Skris		channel_handler_init_15();
211160573Skris}
211260573Skris
211392559Sdes/* gc dead channels */
211492559Sdesstatic void
211592559Sdeschannel_garbage_collect(Channel *c)
211692559Sdes{
211792559Sdes	if (c == NULL)
211892559Sdes		return;
211992559Sdes	if (c->detach_user != NULL) {
2120157019Sdes		if (!chan_is_dead(c, c->detach_close))
212192559Sdes			return;
2122124207Sdes		debug2("channel %d: gc: notify user", c->self);
212392559Sdes		c->detach_user(c->self, NULL);
212492559Sdes		/* if we still have a callback */
212592559Sdes		if (c->detach_user != NULL)
212692559Sdes			return;
2127124207Sdes		debug2("channel %d: gc: user detached", c->self);
212892559Sdes	}
212992559Sdes	if (!chan_is_dead(c, 1))
213092559Sdes		return;
2131124207Sdes	debug2("channel %d: garbage collecting", c->self);
213292559Sdes	channel_free(c);
213392559Sdes}
213492559Sdes
213592559Sdesstatic void
2136240075Sdeschannel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset,
2137240075Sdes    time_t *unpause_secs)
213860573Skris{
213960573Skris	static int did_init = 0;
2140204917Sdes	u_int i, oalloc;
214160573Skris	Channel *c;
2142240075Sdes	time_t now;
214360573Skris
214460573Skris	if (!did_init) {
214560573Skris		channel_handler_init();
214660573Skris		did_init = 1;
214760573Skris	}
2148255767Sdes	now = monotime();
2149240075Sdes	if (unpause_secs != NULL)
2150240075Sdes		*unpause_secs = 0;
2151204917Sdes	for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
215292559Sdes		c = channels[i];
215392559Sdes		if (c == NULL)
215457429Smarkm			continue;
2155204917Sdes		if (c->delayed) {
2156204917Sdes			if (ftab == channel_pre)
2157204917Sdes				c->delayed = 0;
2158204917Sdes			else
2159204917Sdes				continue;
2160204917Sdes		}
2161240075Sdes		if (ftab[c->type] != NULL) {
2162240075Sdes			/*
2163240075Sdes			 * Run handlers that are not paused.
2164240075Sdes			 */
2165240075Sdes			if (c->notbefore <= now)
2166240075Sdes				(*ftab[c->type])(c, readset, writeset);
2167240075Sdes			else if (unpause_secs != NULL) {
2168240075Sdes				/*
2169240075Sdes				 * Collect the time that the earliest
2170240075Sdes				 * channel comes off pause.
2171240075Sdes				 */
2172240075Sdes				debug3("%s: chan %d: skip for %d more seconds",
2173240075Sdes				    __func__, c->self,
2174240075Sdes				    (int)(c->notbefore - now));
2175240075Sdes				if (*unpause_secs == 0 ||
2176240075Sdes				    (c->notbefore - now) < *unpause_secs)
2177240075Sdes					*unpause_secs = c->notbefore - now;
2178240075Sdes			}
2179240075Sdes		}
218092559Sdes		channel_garbage_collect(c);
218157429Smarkm	}
2182240075Sdes	if (unpause_secs != NULL && *unpause_secs != 0)
2183240075Sdes		debug3("%s: first channel unpauses in %d seconds",
2184240075Sdes		    __func__, (int)*unpause_secs);
218557429Smarkm}
218657429Smarkm
218792559Sdes/*
218892559Sdes * Allocate/update select bitmasks and add any bits relevant to channels in
218992559Sdes * select bitmasks.
219092559Sdes */
219160573Skrisvoid
219276262Sgreenchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2193240075Sdes    u_int *nallocp, time_t *minwait_secs, int rekeying)
219460573Skris{
2195162856Sdes	u_int n, sz, nfdset;
219676262Sgreen
219776262Sgreen	n = MAX(*maxfdp, channel_max_fd);
219876262Sgreen
2199162856Sdes	nfdset = howmany(n+1, NFDBITS);
2200162856Sdes	/* Explicitly test here, because xrealloc isn't always called */
2201162856Sdes	if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask))
2202162856Sdes		fatal("channel_prepare_select: max_fd (%d) is too large", n);
2203162856Sdes	sz = nfdset * sizeof(fd_mask);
2204162856Sdes
220592559Sdes	/* perhaps check sz < nalloc/2 and shrink? */
220692559Sdes	if (*readsetp == NULL || sz > *nallocp) {
2207162856Sdes		*readsetp = xrealloc(*readsetp, nfdset, sizeof(fd_mask));
2208162856Sdes		*writesetp = xrealloc(*writesetp, nfdset, sizeof(fd_mask));
220992559Sdes		*nallocp = sz;
221076262Sgreen	}
221192559Sdes	*maxfdp = n;
221276262Sgreen	memset(*readsetp, 0, sz);
221376262Sgreen	memset(*writesetp, 0, sz);
221476262Sgreen
221576262Sgreen	if (!rekeying)
2216240075Sdes		channel_handler(channel_pre, *readsetp, *writesetp,
2217240075Sdes		    minwait_secs);
221860573Skris}
221960573Skris
222092559Sdes/*
222192559Sdes * After select, perform any appropriate operations for channels which have
222292559Sdes * events pending.
222392559Sdes */
222460573Skrisvoid
2225162856Sdeschannel_after_select(fd_set *readset, fd_set *writeset)
222660573Skris{
2227240075Sdes	channel_handler(channel_post, readset, writeset, NULL);
222860573Skris}
222960573Skris
223092559Sdes
223176262Sgreen/* If there is data to send to the connection, enqueue some of it now. */
223260573Skrisvoid
223392559Sdeschannel_output_poll(void)
223457429Smarkm{
223560573Skris	Channel *c;
2236137019Sdes	u_int i, len;
223757429Smarkm
223857429Smarkm	for (i = 0; i < channels_alloc; i++) {
223992559Sdes		c = channels[i];
224092559Sdes		if (c == NULL)
224192559Sdes			continue;
224257429Smarkm
224392559Sdes		/*
224492559Sdes		 * We are only interested in channels that can have buffered
224592559Sdes		 * incoming data.
224692559Sdes		 */
224757429Smarkm		if (compat13) {
224860573Skris			if (c->type != SSH_CHANNEL_OPEN &&
224960573Skris			    c->type != SSH_CHANNEL_INPUT_DRAINING)
225057429Smarkm				continue;
225157429Smarkm		} else {
225260573Skris			if (c->type != SSH_CHANNEL_OPEN)
225357429Smarkm				continue;
225457429Smarkm		}
225560573Skris		if (compat20 &&
225660573Skris		    (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
225776262Sgreen			/* XXX is this true? */
225892559Sdes			debug3("channel %d: will not send data after close", c->self);
225960573Skris			continue;
226060573Skris		}
226157429Smarkm
226257429Smarkm		/* Get the amount of buffered data for this channel. */
226376262Sgreen		if ((c->istate == CHAN_INPUT_OPEN ||
226476262Sgreen		    c->istate == CHAN_INPUT_WAIT_DRAIN) &&
226576262Sgreen		    (len = buffer_len(&c->input)) > 0) {
2266157019Sdes			if (c->datagram) {
2267157019Sdes				if (len > 0) {
2268157019Sdes					u_char *data;
2269157019Sdes					u_int dlen;
2270157019Sdes
2271157019Sdes					data = buffer_get_string(&c->input,
2272157019Sdes					    &dlen);
2273215116Sdes					if (dlen > c->remote_window ||
2274215116Sdes					    dlen > c->remote_maxpacket) {
2275215116Sdes						debug("channel %d: datagram "
2276215116Sdes						    "too big for channel",
2277215116Sdes						    c->self);
2278255767Sdes						free(data);
2279215116Sdes						continue;
2280215116Sdes					}
2281157019Sdes					packet_start(SSH2_MSG_CHANNEL_DATA);
2282157019Sdes					packet_put_int(c->remote_id);
2283157019Sdes					packet_put_string(data, dlen);
2284157019Sdes					packet_send();
2285157019Sdes					c->remote_window -= dlen + 4;
2286255767Sdes					free(data);
2287157019Sdes				}
2288157019Sdes				continue;
2289157019Sdes			}
229092559Sdes			/*
229192559Sdes			 * Send some data for the other side over the secure
229292559Sdes			 * connection.
229392559Sdes			 */
229460573Skris			if (compat20) {
229560573Skris				if (len > c->remote_window)
229660573Skris					len = c->remote_window;
229760573Skris				if (len > c->remote_maxpacket)
229860573Skris					len = c->remote_maxpacket;
229957429Smarkm			} else {
230060573Skris				if (packet_is_interactive()) {
230160573Skris					if (len > 1024)
230260573Skris						len = 512;
230360573Skris				} else {
230460573Skris					/* Keep the packets at reasonable size. */
230560573Skris					if (len > packet_get_maxsize()/2)
230660573Skris						len = packet_get_maxsize()/2;
230760573Skris				}
230857429Smarkm			}
230960573Skris			if (len > 0) {
231060573Skris				packet_start(compat20 ?
231160573Skris				    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
231260573Skris				packet_put_int(c->remote_id);
231360573Skris				packet_put_string(buffer_ptr(&c->input), len);
231460573Skris				packet_send();
231560573Skris				buffer_consume(&c->input, len);
231660573Skris				c->remote_window -= len;
231760573Skris			}
231860573Skris		} else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
231957429Smarkm			if (compat13)
232057429Smarkm				fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
232157429Smarkm			/*
232257429Smarkm			 * input-buffer is empty and read-socket shutdown:
232398684Sdes			 * tell peer, that we will not send more data: send IEOF.
232498684Sdes			 * hack for extended data: delay EOF if EFD still in use.
232557429Smarkm			 */
232698684Sdes			if (CHANNEL_EFD_INPUT_ACTIVE(c))
2327149753Sdes				debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
2328149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
232998684Sdes			else
233098684Sdes				chan_ibuf_empty(c);
233157429Smarkm		}
233260573Skris		/* Send extended data, i.e. stderr */
233360573Skris		if (compat20 &&
233498684Sdes		    !(c->flags & CHAN_EOF_SENT) &&
233560573Skris		    c->remote_window > 0 &&
233660573Skris		    (len = buffer_len(&c->extended)) > 0 &&
233760573Skris		    c->extended_usage == CHAN_EXTENDED_READ) {
233899063Sdes			debug2("channel %d: rwin %u elen %u euse %d",
233976262Sgreen			    c->self, c->remote_window, buffer_len(&c->extended),
234076262Sgreen			    c->extended_usage);
234160573Skris			if (len > c->remote_window)
234260573Skris				len = c->remote_window;
234360573Skris			if (len > c->remote_maxpacket)
234460573Skris				len = c->remote_maxpacket;
234560573Skris			packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
234660573Skris			packet_put_int(c->remote_id);
234760573Skris			packet_put_int(SSH2_EXTENDED_DATA_STDERR);
234860573Skris			packet_put_string(buffer_ptr(&c->extended), len);
234960573Skris			packet_send();
235060573Skris			buffer_consume(&c->extended, len);
235160573Skris			c->remote_window -= len;
235276262Sgreen			debug2("channel %d: sent ext data %d", c->self, len);
235360573Skris		}
235457429Smarkm	}
235557429Smarkm}
235657429Smarkm
235757429Smarkm
235892559Sdes/* -- protocol input */
235992559Sdes
2360162856Sdes/* ARGSUSED */
236160573Skrisvoid
236292559Sdeschannel_input_data(int type, u_int32_t seq, void *ctxt)
236357429Smarkm{
236457429Smarkm	int id;
236557429Smarkm	char *data;
2366215116Sdes	u_int data_len, win_len;
236760573Skris	Channel *c;
236857429Smarkm
236957429Smarkm	/* Get the channel number and verify it. */
237057429Smarkm	id = packet_get_int();
237160573Skris	c = channel_lookup(id);
237260573Skris	if (c == NULL)
237357429Smarkm		packet_disconnect("Received data for nonexistent channel %d.", id);
237457429Smarkm
237557429Smarkm	/* Ignore any data for non-open channels (might happen on close) */
237660573Skris	if (c->type != SSH_CHANNEL_OPEN &&
237760573Skris	    c->type != SSH_CHANNEL_X11_OPEN)
237857429Smarkm		return;
237957429Smarkm
238057429Smarkm	/* Get the data. */
2381181111Sdes	data = packet_get_string_ptr(&data_len);
2382215116Sdes	win_len = data_len;
2383215116Sdes	if (c->datagram)
2384215116Sdes		win_len += 4;  /* string length header */
238560573Skris
2386126273Sdes	/*
2387126273Sdes	 * Ignore data for protocol > 1.3 if output end is no longer open.
2388126273Sdes	 * For protocol 2 the sending side is reducing its window as it sends
2389126273Sdes	 * data, so we must 'fake' consumption of the data in order to ensure
2390126273Sdes	 * that window updates are sent back.  Otherwise the connection might
2391126273Sdes	 * deadlock.
2392126273Sdes	 */
2393126273Sdes	if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
2394126273Sdes		if (compat20) {
2395215116Sdes			c->local_window -= win_len;
2396215116Sdes			c->local_consumed += win_len;
2397126273Sdes		}
2398126273Sdes		return;
2399126273Sdes	}
2400126273Sdes
240192559Sdes	if (compat20) {
2402215116Sdes		if (win_len > c->local_maxpacket) {
2403124207Sdes			logit("channel %d: rcvd big packet %d, maxpack %d",
2404215116Sdes			    c->self, win_len, c->local_maxpacket);
240560573Skris		}
2406215116Sdes		if (win_len > c->local_window) {
2407124207Sdes			logit("channel %d: rcvd too much data %d, win %d",
2408215116Sdes			    c->self, win_len, c->local_window);
240960573Skris			return;
241060573Skris		}
2411215116Sdes		c->local_window -= win_len;
241260573Skris	}
2413157019Sdes	if (c->datagram)
2414157019Sdes		buffer_put_string(&c->output, data, data_len);
2415157019Sdes	else
2416157019Sdes		buffer_append(&c->output, data, data_len);
2417181111Sdes	packet_check_eom();
241857429Smarkm}
241992559Sdes
2420162856Sdes/* ARGSUSED */
242160573Skrisvoid
242292559Sdeschannel_input_extended_data(int type, u_int32_t seq, void *ctxt)
242360573Skris{
242460573Skris	int id;
242560573Skris	char *data;
242699063Sdes	u_int data_len, tcode;
242760573Skris	Channel *c;
242857429Smarkm
242960573Skris	/* Get the channel number and verify it. */
243060573Skris	id = packet_get_int();
243160573Skris	c = channel_lookup(id);
243260573Skris
243360573Skris	if (c == NULL)
243460573Skris		packet_disconnect("Received extended_data for bad channel %d.", id);
243560573Skris	if (c->type != SSH_CHANNEL_OPEN) {
2436124207Sdes		logit("channel %d: ext data for non open", id);
243760573Skris		return;
243860573Skris	}
243998684Sdes	if (c->flags & CHAN_EOF_RCVD) {
244098684Sdes		if (datafellows & SSH_BUG_EXTEOF)
244198684Sdes			debug("channel %d: accepting ext data after eof", id);
244298684Sdes		else
244398684Sdes			packet_disconnect("Received extended_data after EOF "
244498684Sdes			    "on channel %d.", id);
244598684Sdes	}
244660573Skris	tcode = packet_get_int();
244760573Skris	if (c->efd == -1 ||
244860573Skris	    c->extended_usage != CHAN_EXTENDED_WRITE ||
244960573Skris	    tcode != SSH2_EXTENDED_DATA_STDERR) {
2450124207Sdes		logit("channel %d: bad ext data", c->self);
245160573Skris		return;
245260573Skris	}
245360573Skris	data = packet_get_string(&data_len);
245492559Sdes	packet_check_eom();
245560573Skris	if (data_len > c->local_window) {
2456124207Sdes		logit("channel %d: rcvd too much extended_data %d, win %d",
245760573Skris		    c->self, data_len, c->local_window);
2458255767Sdes		free(data);
245960573Skris		return;
246060573Skris	}
246169587Sgreen	debug2("channel %d: rcvd ext data %d", c->self, data_len);
246260573Skris	c->local_window -= data_len;
246360573Skris	buffer_append(&c->extended, data, data_len);
2464255767Sdes	free(data);
246560573Skris}
246660573Skris
2467162856Sdes/* ARGSUSED */
246860573Skrisvoid
246992559Sdeschannel_input_ieof(int type, u_int32_t seq, void *ctxt)
247060573Skris{
247160573Skris	int id;
247260573Skris	Channel *c;
247357429Smarkm
247460573Skris	id = packet_get_int();
247592559Sdes	packet_check_eom();
247660573Skris	c = channel_lookup(id);
247760573Skris	if (c == NULL)
247860573Skris		packet_disconnect("Received ieof for nonexistent channel %d.", id);
247960573Skris	chan_rcvd_ieof(c);
248092559Sdes
248192559Sdes	/* XXX force input close */
248292559Sdes	if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
248392559Sdes		debug("channel %d: FORCE input drain", c->self);
248492559Sdes		c->istate = CHAN_INPUT_WAIT_DRAIN;
248592559Sdes		if (buffer_len(&c->input) == 0)
248692559Sdes			chan_ibuf_empty(c);
248792559Sdes	}
248892559Sdes
248960573Skris}
249060573Skris
2491162856Sdes/* ARGSUSED */
249260573Skrisvoid
249392559Sdeschannel_input_close(int type, u_int32_t seq, void *ctxt)
249457429Smarkm{
249560573Skris	int id;
249660573Skris	Channel *c;
249757429Smarkm
249860573Skris	id = packet_get_int();
249992559Sdes	packet_check_eom();
250060573Skris	c = channel_lookup(id);
250160573Skris	if (c == NULL)
250260573Skris		packet_disconnect("Received close for nonexistent channel %d.", id);
250357429Smarkm
250457429Smarkm	/*
250557429Smarkm	 * Send a confirmation that we have closed the channel and no more
250657429Smarkm	 * data is coming for it.
250757429Smarkm	 */
250857429Smarkm	packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
250960573Skris	packet_put_int(c->remote_id);
251057429Smarkm	packet_send();
251157429Smarkm
251257429Smarkm	/*
251357429Smarkm	 * If the channel is in closed state, we have sent a close request,
251457429Smarkm	 * and the other side will eventually respond with a confirmation.
251557429Smarkm	 * Thus, we cannot free the channel here, because then there would be
251657429Smarkm	 * no-one to receive the confirmation.  The channel gets freed when
251757429Smarkm	 * the confirmation arrives.
251857429Smarkm	 */
251960573Skris	if (c->type != SSH_CHANNEL_CLOSED) {
252057429Smarkm		/*
252157429Smarkm		 * Not a closed channel - mark it as draining, which will
252257429Smarkm		 * cause it to be freed later.
252357429Smarkm		 */
252492559Sdes		buffer_clear(&c->input);
252560573Skris		c->type = SSH_CHANNEL_OUTPUT_DRAINING;
252657429Smarkm	}
252757429Smarkm}
252857429Smarkm
252960573Skris/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
2530162856Sdes/* ARGSUSED */
253160573Skrisvoid
253292559Sdeschannel_input_oclose(int type, u_int32_t seq, void *ctxt)
253360573Skris{
253460573Skris	int id = packet_get_int();
253560573Skris	Channel *c = channel_lookup(id);
253692559Sdes
253792559Sdes	packet_check_eom();
253860573Skris	if (c == NULL)
253960573Skris		packet_disconnect("Received oclose for nonexistent channel %d.", id);
254060573Skris	chan_rcvd_oclose(c);
254160573Skris}
254257429Smarkm
2543162856Sdes/* ARGSUSED */
254460573Skrisvoid
254592559Sdeschannel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
254657429Smarkm{
254760573Skris	int id = packet_get_int();
254860573Skris	Channel *c = channel_lookup(id);
254957429Smarkm
255092559Sdes	packet_check_eom();
255160573Skris	if (c == NULL)
255260573Skris		packet_disconnect("Received close confirmation for "
255360573Skris		    "out-of-range channel %d.", id);
2554255767Sdes	if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)
255560573Skris		packet_disconnect("Received close confirmation for "
255660573Skris		    "non-closed channel %d (type %d).", id, c->type);
255792559Sdes	channel_free(c);
255860573Skris}
255957429Smarkm
2560162856Sdes/* ARGSUSED */
256160573Skrisvoid
256292559Sdeschannel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
256360573Skris{
256460573Skris	int id, remote_id;
256560573Skris	Channel *c;
256660573Skris
256760573Skris	id = packet_get_int();
256860573Skris	c = channel_lookup(id);
256960573Skris
257060573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
257160573Skris		packet_disconnect("Received open confirmation for "
257260573Skris		    "non-opening channel %d.", id);
257360573Skris	remote_id = packet_get_int();
257460573Skris	/* Record the remote channel number and mark that the channel is now open. */
257560573Skris	c->remote_id = remote_id;
257660573Skris	c->type = SSH_CHANNEL_OPEN;
257760573Skris
257860573Skris	if (compat20) {
257960573Skris		c->remote_window = packet_get_int();
258060573Skris		c->remote_maxpacket = packet_get_int();
2581181111Sdes		if (c->open_confirm) {
258269587Sgreen			debug2("callback start");
2583215116Sdes			c->open_confirm(c->self, 1, c->open_confirm_ctx);
258469587Sgreen			debug2("callback done");
258560573Skris		}
2586124207Sdes		debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
258760573Skris		    c->remote_window, c->remote_maxpacket);
258857429Smarkm	}
258992559Sdes	packet_check_eom();
259057429Smarkm}
259157429Smarkm
259292559Sdesstatic char *
259392559Sdesreason2txt(int reason)
259492559Sdes{
259592559Sdes	switch (reason) {
259692559Sdes	case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
259792559Sdes		return "administratively prohibited";
259892559Sdes	case SSH2_OPEN_CONNECT_FAILED:
259992559Sdes		return "connect failed";
260092559Sdes	case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
260192559Sdes		return "unknown channel type";
260292559Sdes	case SSH2_OPEN_RESOURCE_SHORTAGE:
260392559Sdes		return "resource shortage";
260492559Sdes	}
260592559Sdes	return "unknown reason";
260692559Sdes}
260792559Sdes
2608162856Sdes/* ARGSUSED */
260960573Skrisvoid
261092559Sdeschannel_input_open_failure(int type, u_int32_t seq, void *ctxt)
261157429Smarkm{
261276262Sgreen	int id, reason;
261376262Sgreen	char *msg = NULL, *lang = NULL;
261460573Skris	Channel *c;
261557429Smarkm
261660573Skris	id = packet_get_int();
261760573Skris	c = channel_lookup(id);
261857429Smarkm
261960573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
262060573Skris		packet_disconnect("Received open failure for "
262160573Skris		    "non-opening channel %d.", id);
262260573Skris	if (compat20) {
262376262Sgreen		reason = packet_get_int();
262492559Sdes		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
262576262Sgreen			msg  = packet_get_string(NULL);
262676262Sgreen			lang = packet_get_string(NULL);
262776262Sgreen		}
2628124207Sdes		logit("channel %d: open failed: %s%s%s", id,
262992559Sdes		    reason2txt(reason), msg ? ": ": "", msg ? msg : "");
2630255767Sdes		free(msg);
2631255767Sdes		free(lang);
2632215116Sdes		if (c->open_confirm) {
2633215116Sdes			debug2("callback start");
2634215116Sdes			c->open_confirm(c->self, 0, c->open_confirm_ctx);
2635215116Sdes			debug2("callback done");
2636215116Sdes		}
263760573Skris	}
263892559Sdes	packet_check_eom();
2639192595Sdes	/* Schedule the channel for cleanup/deletion. */
2640192595Sdes	chan_mark_dead(c);
264157429Smarkm}
264257429Smarkm
2643162856Sdes/* ARGSUSED */
264460573Skrisvoid
264592559Sdeschannel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
264660573Skris{
264760573Skris	Channel *c;
264899063Sdes	int id;
264999063Sdes	u_int adjust;
265057429Smarkm
265160573Skris	if (!compat20)
265260573Skris		return;
265360573Skris
265457429Smarkm	/* Get the channel number and verify it. */
265560573Skris	id = packet_get_int();
265660573Skris	c = channel_lookup(id);
265757429Smarkm
2658157019Sdes	if (c == NULL) {
2659157019Sdes		logit("Received window adjust for non-open channel %d.", id);
266060573Skris		return;
266160573Skris	}
266260573Skris	adjust = packet_get_int();
266392559Sdes	packet_check_eom();
266499063Sdes	debug2("channel %d: rcvd adjust %u", id, adjust);
266560573Skris	c->remote_window += adjust;
266657429Smarkm}
266757429Smarkm
2668162856Sdes/* ARGSUSED */
266960573Skrisvoid
267092559Sdeschannel_input_port_open(int type, u_int32_t seq, void *ctxt)
267157429Smarkm{
267292559Sdes	Channel *c = NULL;
267392559Sdes	u_short host_port;
267492559Sdes	char *host, *originator_string;
2675181111Sdes	int remote_id;
267657429Smarkm
267792559Sdes	remote_id = packet_get_int();
267892559Sdes	host = packet_get_string(NULL);
267992559Sdes	host_port = packet_get_int();
268057429Smarkm
268192559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
268292559Sdes		originator_string = packet_get_string(NULL);
268392559Sdes	} else {
268492559Sdes		originator_string = xstrdup("unknown (remote did not supply name)");
268592559Sdes	}
268692559Sdes	packet_check_eom();
2687181111Sdes	c = channel_connect_to(host, host_port,
2688181111Sdes	    "connected socket", originator_string);
2689255767Sdes	free(originator_string);
2690255767Sdes	free(host);
269192559Sdes	if (c == NULL) {
269292559Sdes		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
269392559Sdes		packet_put_int(remote_id);
269492559Sdes		packet_send();
2695181111Sdes	} else
2696181111Sdes		c->remote_id = remote_id;
269757429Smarkm}
269857429Smarkm
2699181111Sdes/* ARGSUSED */
2700181111Sdesvoid
2701181111Sdeschannel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2702181111Sdes{
2703181111Sdes	Channel *c;
2704181111Sdes	struct channel_confirm *cc;
2705192595Sdes	int id;
270657429Smarkm
2707181111Sdes	/* Reset keepalive timeout */
2708197679Sdes	packet_set_alive_timeouts(0);
2709181111Sdes
2710192595Sdes	id = packet_get_int();
2711181111Sdes	packet_check_eom();
2712181111Sdes
2713192595Sdes	debug2("channel_input_status_confirm: type %d id %d", type, id);
2714181111Sdes
2715192595Sdes	if ((c = channel_lookup(id)) == NULL) {
2716192595Sdes		logit("channel_input_status_confirm: %d: unknown", id);
2717181111Sdes		return;
2718181111Sdes	}
2719181111Sdes	;
2720181111Sdes	if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
2721181111Sdes		return;
2722181111Sdes	cc->cb(type, c, cc->ctx);
2723181111Sdes	TAILQ_REMOVE(&c->status_confirms, cc, entry);
2724181111Sdes	bzero(cc, sizeof(*cc));
2725255767Sdes	free(cc);
2726181111Sdes}
2727181111Sdes
272892559Sdes/* -- tcp forwarding */
272957429Smarkm
273092559Sdesvoid
273192559Sdeschannel_set_af(int af)
273276262Sgreen{
273392559Sdes	IPv4or6 = af;
273476262Sgreen}
273576262Sgreen
2736231584Sedvoid
2737224638Sbrookschannel_set_hpn(int disabled, u_int buf_size)
2738224638Sbrooks{
2739231584Sed	hpn_disabled = disabled;
2740224638Sbrooks	buffer_size = buf_size;
2741224638Sbrooks	debug("HPN Disabled: %d, HPN Buffer Size: %d",
2742224638Sbrooks	    hpn_disabled, buffer_size);
2743224638Sbrooks}
2744224638Sbrooks
2745240075Sdes/*
2746240075Sdes * Determine whether or not a port forward listens to loopback, the
2747240075Sdes * specified address or wildcard. On the client, a specified bind
2748240075Sdes * address will always override gateway_ports. On the server, a
2749240075Sdes * gateway_ports of 1 (``yes'') will override the client's specification
2750240075Sdes * and force a wildcard bind, whereas a value of 2 (``clientspecified'')
2751240075Sdes * will bind to whatever address the client asked for.
2752240075Sdes *
2753240075Sdes * Special-case listen_addrs are:
2754240075Sdes *
2755240075Sdes * "0.0.0.0"               -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2756240075Sdes * "" (empty string), "*"  -> wildcard v4/v6
2757240075Sdes * "localhost"             -> loopback v4/v6
2758240075Sdes */
2759240075Sdesstatic const char *
2760240075Sdeschannel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2761240075Sdes    int is_client, int gateway_ports)
2762240075Sdes{
2763240075Sdes	const char *addr = NULL;
2764240075Sdes	int wildcard = 0;
2765240075Sdes
2766240075Sdes	if (listen_addr == NULL) {
2767240075Sdes		/* No address specified: default to gateway_ports setting */
2768240075Sdes		if (gateway_ports)
2769240075Sdes			wildcard = 1;
2770240075Sdes	} else if (gateway_ports || is_client) {
2771240075Sdes		if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2772240075Sdes		    strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2773240075Sdes		    *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2774240075Sdes		    (!is_client && gateway_ports == 1))
2775240075Sdes			wildcard = 1;
2776240075Sdes		else if (strcmp(listen_addr, "localhost") != 0)
2777240075Sdes			addr = listen_addr;
2778240075Sdes	}
2779240075Sdes	if (wildcardp != NULL)
2780240075Sdes		*wildcardp = wildcard;
2781240075Sdes	return addr;
2782240075Sdes}
2783240075Sdes
278492559Sdesstatic int
2785192595Sdeschannel_setup_fwd_listener(int type, const char *listen_addr,
2786192595Sdes    u_short listen_port, int *allocated_listen_port,
278792559Sdes    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
278857429Smarkm{
278992559Sdes	Channel *c;
2790157019Sdes	int sock, r, success = 0, wildcard = 0, is_client;
279157429Smarkm	struct addrinfo hints, *ai, *aitop;
2792147005Sdes	const char *host, *addr;
279357429Smarkm	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
2794192595Sdes	in_port_t *lport_p;
279557429Smarkm
279692559Sdes	host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
279792559Sdes	    listen_addr : host_to_connect;
2798147005Sdes	is_client = (type == SSH_CHANNEL_PORT_LISTENER);
279957429Smarkm
280092559Sdes	if (host == NULL) {
280192559Sdes		error("No forward host name.");
2802149753Sdes		return 0;
280376262Sgreen	}
2804192595Sdes	if (strlen(host) >= NI_MAXHOST) {
280576262Sgreen		error("Forward host name too long.");
2806149753Sdes		return 0;
280776262Sgreen	}
280876262Sgreen
2809240075Sdes	/* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2810240075Sdes	addr = channel_fwd_bind_addr(listen_addr, &wildcard,
2811240075Sdes	    is_client, gateway_ports);
2812147005Sdes	debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
2813147005Sdes	    type, wildcard, (addr == NULL) ? "NULL" : addr);
2814147005Sdes
2815147005Sdes	/*
281657429Smarkm	 * getaddrinfo returns a loopback address if the hostname is
281757429Smarkm	 * set to NULL and hints.ai_flags is not AI_PASSIVE
281857429Smarkm	 */
281957429Smarkm	memset(&hints, 0, sizeof(hints));
282057429Smarkm	hints.ai_family = IPv4or6;
2821147005Sdes	hints.ai_flags = wildcard ? AI_PASSIVE : 0;
282257429Smarkm	hints.ai_socktype = SOCK_STREAM;
282376262Sgreen	snprintf(strport, sizeof strport, "%d", listen_port);
2824147005Sdes	if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
2825147005Sdes		if (addr == NULL) {
2826147005Sdes			/* This really shouldn't happen */
2827147005Sdes			packet_disconnect("getaddrinfo: fatal error: %s",
2828181111Sdes			    ssh_gai_strerror(r));
2829147005Sdes		} else {
2830149753Sdes			error("channel_setup_fwd_listener: "
2831181111Sdes			    "getaddrinfo(%.64s): %s", addr,
2832181111Sdes			    ssh_gai_strerror(r));
2833147005Sdes		}
2834149753Sdes		return 0;
2835147005Sdes	}
2836192595Sdes	if (allocated_listen_port != NULL)
2837192595Sdes		*allocated_listen_port = 0;
283857429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
2839192595Sdes		switch (ai->ai_family) {
2840192595Sdes		case AF_INET:
2841192595Sdes			lport_p = &((struct sockaddr_in *)ai->ai_addr)->
2842192595Sdes			    sin_port;
2843192595Sdes			break;
2844192595Sdes		case AF_INET6:
2845192595Sdes			lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
2846192595Sdes			    sin6_port;
2847192595Sdes			break;
2848192595Sdes		default:
284957429Smarkm			continue;
2850192595Sdes		}
2851192595Sdes		/*
2852192595Sdes		 * If allocating a port for -R forwards, then use the
2853192595Sdes		 * same port for all address families.
2854192595Sdes		 */
2855192595Sdes		if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
2856192595Sdes		    allocated_listen_port != NULL && *allocated_listen_port > 0)
2857192595Sdes			*lport_p = htons(*allocated_listen_port);
2858192595Sdes
285957429Smarkm		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
286057429Smarkm		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
286192559Sdes			error("channel_setup_fwd_listener: getnameinfo failed");
286257429Smarkm			continue;
286357429Smarkm		}
286457429Smarkm		/* Create a port to listen for the host. */
2865124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
286657429Smarkm		if (sock < 0) {
286757429Smarkm			/* this is no error since kernel may not support ipv6 */
286857429Smarkm			verbose("socket: %.100s", strerror(errno));
286957429Smarkm			continue;
287057429Smarkm		}
2871106130Sdes
2872157019Sdes		channel_set_reuseaddr(sock);
2873204917Sdes		if (ai->ai_family == AF_INET6)
2874204917Sdes			sock_set_v6only(sock);
2875157019Sdes
2876192595Sdes		debug("Local forwarding listening on %s port %s.",
2877192595Sdes		    ntop, strport);
287857429Smarkm
287957429Smarkm		/* Bind the socket to the address. */
288057429Smarkm		if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
288157429Smarkm			/* address can be in use ipv6 address is already bound */
288298941Sdes			if (!ai->ai_next)
288398941Sdes				error("bind: %.100s", strerror(errno));
288498941Sdes			else
288598941Sdes				verbose("bind: %.100s", strerror(errno));
288698941Sdes
288757429Smarkm			close(sock);
288857429Smarkm			continue;
288957429Smarkm		}
289057429Smarkm		/* Start listening for connections on the socket. */
2891126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
289257429Smarkm			error("listen: %.100s", strerror(errno));
289357429Smarkm			close(sock);
289457429Smarkm			continue;
289557429Smarkm		}
2896192595Sdes
2897192595Sdes		/*
2898192595Sdes		 * listen_port == 0 requests a dynamically allocated port -
2899192595Sdes		 * record what we got.
2900192595Sdes		 */
2901192595Sdes		if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
2902192595Sdes		    allocated_listen_port != NULL &&
2903192595Sdes		    *allocated_listen_port == 0) {
2904192595Sdes			*allocated_listen_port = get_sock_port(sock, 1);
2905192595Sdes			debug("Allocated listen port %d",
2906192595Sdes			    *allocated_listen_port);
2907192595Sdes		}
2908192595Sdes
2909224638Sbrooks		/*
2910224638Sbrooks		 * Allocate a channel number for the socket.  Explicitly test
2911224638Sbrooks		 * for hpn disabled option.  If true use smaller window size.
2912224638Sbrooks		 */
2913224638Sbrooks		if (hpn_disabled)
2914224638Sbrooks			c = channel_new("port listener", type, sock, sock, -1,
2915224638Sbrooks			    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2916224638Sbrooks			    0, "port listener", 1);
2917231584Sed		else
2918231584Sed			c = channel_new("port listener", type, sock, sock, -1,
2919231584Sed			    buffer_size, CHAN_TCP_PACKET_DEFAULT,
2920231584Sed			    0, "port listener", 1);
2921192595Sdes		c->path = xstrdup(host);
292292559Sdes		c->host_port = port_to_connect;
2923240075Sdes		c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2924240075Sdes		if (listen_port == 0 && allocated_listen_port != NULL &&
2925240075Sdes		    !(datafellows & SSH_BUG_DYNAMIC_RPORT))
2926240075Sdes			c->listening_port = *allocated_listen_port;
2927240075Sdes		else
2928240075Sdes			c->listening_port = listen_port;
292957429Smarkm		success = 1;
293057429Smarkm	}
293157429Smarkm	if (success == 0)
293292559Sdes		error("channel_setup_fwd_listener: cannot listen to port: %d",
293376262Sgreen		    listen_port);
293457429Smarkm	freeaddrinfo(aitop);
293576262Sgreen	return success;
293657429Smarkm}
293757429Smarkm
2938137019Sdesint
2939137019Sdeschannel_cancel_rport_listener(const char *host, u_short port)
2940137019Sdes{
2941137019Sdes	u_int i;
2942137019Sdes	int found = 0;
2943137019Sdes
2944147005Sdes	for (i = 0; i < channels_alloc; i++) {
2945137019Sdes		Channel *c = channels[i];
2946240075Sdes		if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
2947240075Sdes			continue;
2948240075Sdes		if (strcmp(c->path, host) == 0 && c->listening_port == port) {
2949240075Sdes			debug2("%s: close channel %d", __func__, i);
2950240075Sdes			channel_free(c);
2951240075Sdes			found = 1;
2952240075Sdes		}
2953240075Sdes	}
2954137019Sdes
2955240075Sdes	return (found);
2956240075Sdes}
2957240075Sdes
2958240075Sdesint
2959240075Sdeschannel_cancel_lport_listener(const char *lhost, u_short lport,
2960240075Sdes    int cport, int gateway_ports)
2961240075Sdes{
2962240075Sdes	u_int i;
2963240075Sdes	int found = 0;
2964240075Sdes	const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
2965240075Sdes
2966240075Sdes	for (i = 0; i < channels_alloc; i++) {
2967240075Sdes		Channel *c = channels[i];
2968240075Sdes		if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
2969240075Sdes			continue;
2970240075Sdes		if (c->listening_port != lport)
2971240075Sdes			continue;
2972240075Sdes		if (cport == CHANNEL_CANCEL_PORT_STATIC) {
2973240075Sdes			/* skip dynamic forwardings */
2974240075Sdes			if (c->host_port == 0)
2975240075Sdes				continue;
2976240075Sdes		} else {
2977240075Sdes			if (c->host_port != cport)
2978240075Sdes				continue;
2979240075Sdes		}
2980240075Sdes		if ((c->listening_addr == NULL && addr != NULL) ||
2981240075Sdes		    (c->listening_addr != NULL && addr == NULL))
2982240075Sdes			continue;
2983240075Sdes		if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
2984147005Sdes			debug2("%s: close channel %d", __func__, i);
2985137019Sdes			channel_free(c);
2986137019Sdes			found = 1;
2987137019Sdes		}
2988137019Sdes	}
2989137019Sdes
2990137019Sdes	return (found);
2991137019Sdes}
2992137019Sdes
299392559Sdes/* protocol local port fwd, used by ssh (and sshd in v1) */
299492559Sdesint
2995147005Sdeschannel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
299692559Sdes    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
299792559Sdes{
299892559Sdes	return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
2999192595Sdes	    listen_host, listen_port, NULL, host_to_connect, port_to_connect,
3000147005Sdes	    gateway_ports);
300192559Sdes}
300292559Sdes
300392559Sdes/* protocol v2 remote port fwd, used by sshd */
300492559Sdesint
300592559Sdeschannel_setup_remote_fwd_listener(const char *listen_address,
3006192595Sdes    u_short listen_port, int *allocated_listen_port, int gateway_ports)
300792559Sdes{
300892559Sdes	return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
3009192595Sdes	    listen_address, listen_port, allocated_listen_port,
3010192595Sdes	    NULL, 0, gateway_ports);
301192559Sdes}
301292559Sdes
301357429Smarkm/*
3014240075Sdes * Translate the requested rfwd listen host to something usable for
3015240075Sdes * this server.
3016240075Sdes */
3017240075Sdesstatic const char *
3018240075Sdeschannel_rfwd_bind_host(const char *listen_host)
3019240075Sdes{
3020240075Sdes	if (listen_host == NULL) {
3021240075Sdes		if (datafellows & SSH_BUG_RFWD_ADDR)
3022240075Sdes			return "127.0.0.1";
3023240075Sdes		else
3024240075Sdes			return "localhost";
3025240075Sdes	} else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
3026240075Sdes		if (datafellows & SSH_BUG_RFWD_ADDR)
3027240075Sdes			return "0.0.0.0";
3028240075Sdes		else
3029240075Sdes			return "";
3030240075Sdes	} else
3031240075Sdes		return listen_host;
3032240075Sdes}
3033240075Sdes
3034240075Sdes/*
303557429Smarkm * Initiate forwarding of connections to port "port" on remote host through
303657429Smarkm * the secure channel to host:port from local side.
3037240075Sdes * Returns handle (index) for updating the dynamic listen port with
3038240075Sdes * channel_update_permitted_opens().
303957429Smarkm */
3040162856Sdesint
3041147005Sdeschannel_request_remote_forwarding(const char *listen_host, u_short listen_port,
304276262Sgreen    const char *host_to_connect, u_short port_to_connect)
304357429Smarkm{
3044240075Sdes	int type, success = 0, idx = -1;
304576262Sgreen
304657429Smarkm	/* Send the forward request to the remote side. */
304760573Skris	if (compat20) {
304860573Skris		packet_start(SSH2_MSG_GLOBAL_REQUEST);
304960573Skris		packet_put_cstring("tcpip-forward");
3050240075Sdes		packet_put_char(1);		/* boolean: want reply */
3051240075Sdes		packet_put_cstring(channel_rfwd_bind_host(listen_host));
305260573Skris		packet_put_int(listen_port);
305376262Sgreen		packet_send();
305476262Sgreen		packet_write_wait();
305576262Sgreen		/* Assume that server accepts the request */
305676262Sgreen		success = 1;
305760573Skris	} else {
305860573Skris		packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
305960573Skris		packet_put_int(listen_port);
306060573Skris		packet_put_cstring(host_to_connect);
306160573Skris		packet_put_int(port_to_connect);
306260573Skris		packet_send();
306360573Skris		packet_write_wait();
306476262Sgreen
306576262Sgreen		/* Wait for response from the remote side. */
306692559Sdes		type = packet_read();
306776262Sgreen		switch (type) {
306876262Sgreen		case SSH_SMSG_SUCCESS:
306976262Sgreen			success = 1;
307076262Sgreen			break;
307176262Sgreen		case SSH_SMSG_FAILURE:
307276262Sgreen			break;
307376262Sgreen		default:
307476262Sgreen			/* Unknown packet */
307576262Sgreen			packet_disconnect("Protocol error for port forward request:"
307676262Sgreen			    "received packet type %d.", type);
307776262Sgreen		}
307860573Skris	}
307976262Sgreen	if (success) {
3080215116Sdes		/* Record that connection to this host/port is permitted. */
3081215116Sdes		permitted_opens = xrealloc(permitted_opens,
3082215116Sdes		    num_permitted_opens + 1, sizeof(*permitted_opens));
3083240075Sdes		idx = num_permitted_opens++;
3084240075Sdes		permitted_opens[idx].host_to_connect = xstrdup(host_to_connect);
3085240075Sdes		permitted_opens[idx].port_to_connect = port_to_connect;
3086240075Sdes		permitted_opens[idx].listen_port = listen_port;
308776262Sgreen	}
3088240075Sdes	return (idx);
308957429Smarkm}
309057429Smarkm
309157429Smarkm/*
3092137019Sdes * Request cancellation of remote forwarding of connection host:port from
3093137019Sdes * local side.
3094137019Sdes */
3095240075Sdesint
3096147005Sdeschannel_request_rforward_cancel(const char *host, u_short port)
3097137019Sdes{
3098137019Sdes	int i;
3099137019Sdes
3100137019Sdes	if (!compat20)
3101240075Sdes		return -1;
3102137019Sdes
3103137019Sdes	for (i = 0; i < num_permitted_opens; i++) {
3104137019Sdes		if (permitted_opens[i].host_to_connect != NULL &&
3105137019Sdes		    permitted_opens[i].listen_port == port)
3106137019Sdes			break;
3107137019Sdes	}
3108137019Sdes	if (i >= num_permitted_opens) {
3109137019Sdes		debug("%s: requested forward not found", __func__);
3110240075Sdes		return -1;
3111137019Sdes	}
3112137019Sdes	packet_start(SSH2_MSG_GLOBAL_REQUEST);
3113137019Sdes	packet_put_cstring("cancel-tcpip-forward");
3114137019Sdes	packet_put_char(0);
3115240075Sdes	packet_put_cstring(channel_rfwd_bind_host(host));
3116137019Sdes	packet_put_int(port);
3117137019Sdes	packet_send();
3118137019Sdes
3119137019Sdes	permitted_opens[i].listen_port = 0;
3120137019Sdes	permitted_opens[i].port_to_connect = 0;
3121255767Sdes	free(permitted_opens[i].host_to_connect);
3122137019Sdes	permitted_opens[i].host_to_connect = NULL;
3123240075Sdes
3124240075Sdes	return 0;
3125137019Sdes}
3126137019Sdes
3127137019Sdes/*
312857429Smarkm * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
312957429Smarkm * listening for the port, and sends back a success reply (or disconnect
3130162856Sdes * message if there was an error).
313157429Smarkm */
3132162856Sdesint
313360573Skrischannel_input_port_forward_request(int is_root, int gateway_ports)
313457429Smarkm{
313557429Smarkm	u_short port, host_port;
3136162856Sdes	int success = 0;
313757429Smarkm	char *hostname;
313857429Smarkm
313957429Smarkm	/* Get arguments from the packet. */
314057429Smarkm	port = packet_get_int();
314157429Smarkm	hostname = packet_get_string(NULL);
314257429Smarkm	host_port = packet_get_int();
314357429Smarkm
314498941Sdes#ifndef HAVE_CYGWIN
314557429Smarkm	/*
314657429Smarkm	 * Check that an unprivileged user is not trying to forward a
314757429Smarkm	 * privileged port.
314857429Smarkm	 */
314957429Smarkm	if (port < IPPORT_RESERVED && !is_root)
3150124207Sdes		packet_disconnect(
3151124207Sdes		    "Requested forwarding of port %d but user is not root.",
3152124207Sdes		    port);
3153124207Sdes	if (host_port == 0)
3154124207Sdes		packet_disconnect("Dynamic forwarding denied.");
315598941Sdes#endif
3156124207Sdes
315776262Sgreen	/* Initiate forwarding */
3158162856Sdes	success = channel_setup_local_fwd_listener(NULL, port, hostname,
3159147005Sdes	    host_port, gateway_ports);
316057429Smarkm
316157429Smarkm	/* Free the argument string. */
3162255767Sdes	free(hostname);
3163162856Sdes
3164162856Sdes	return (success ? 0 : -1);
316557429Smarkm}
316657429Smarkm
316776262Sgreen/*
316876262Sgreen * Permits opening to any host/port if permitted_opens[] is empty.  This is
316976262Sgreen * usually called by the server, because the user could connect to any port
317076262Sgreen * anyway, and the server has no way to know but to trust the client anyway.
317176262Sgreen */
317276262Sgreenvoid
317392559Sdeschannel_permit_all_opens(void)
317476262Sgreen{
317576262Sgreen	if (num_permitted_opens == 0)
317676262Sgreen		all_opens_permitted = 1;
317776262Sgreen}
317876262Sgreen
317976262Sgreenvoid
318076262Sgreenchannel_add_permitted_opens(char *host, int port)
318176262Sgreen{
318276262Sgreen	debug("allow port forwarding to host %s port %d", host, port);
318376262Sgreen
3184215116Sdes	permitted_opens = xrealloc(permitted_opens,
3185215116Sdes	    num_permitted_opens + 1, sizeof(*permitted_opens));
318676262Sgreen	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
318776262Sgreen	permitted_opens[num_permitted_opens].port_to_connect = port;
318876262Sgreen	num_permitted_opens++;
318976262Sgreen
319076262Sgreen	all_opens_permitted = 0;
319176262Sgreen}
319276262Sgreen
3193240075Sdes/*
3194240075Sdes * Update the listen port for a dynamic remote forward, after
3195240075Sdes * the actual 'newport' has been allocated. If 'newport' < 0 is
3196240075Sdes * passed then they entry will be invalidated.
3197240075Sdes */
3198240075Sdesvoid
3199240075Sdeschannel_update_permitted_opens(int idx, int newport)
3200240075Sdes{
3201240075Sdes	if (idx < 0 || idx >= num_permitted_opens) {
3202240075Sdes		debug("channel_update_permitted_opens: index out of range:"
3203240075Sdes		    " %d num_permitted_opens %d", idx, num_permitted_opens);
3204240075Sdes		return;
3205240075Sdes	}
3206240075Sdes	debug("%s allowed port %d for forwarding to host %s port %d",
3207240075Sdes	    newport > 0 ? "Updating" : "Removing",
3208240075Sdes	    newport,
3209240075Sdes	    permitted_opens[idx].host_to_connect,
3210240075Sdes	    permitted_opens[idx].port_to_connect);
3211240075Sdes	if (newport >= 0)  {
3212240075Sdes		permitted_opens[idx].listen_port =
3213240075Sdes		    (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport;
3214240075Sdes	} else {
3215240075Sdes		permitted_opens[idx].listen_port = 0;
3216240075Sdes		permitted_opens[idx].port_to_connect = 0;
3217255767Sdes		free(permitted_opens[idx].host_to_connect);
3218240075Sdes		permitted_opens[idx].host_to_connect = NULL;
3219240075Sdes	}
3220240075Sdes}
3221240075Sdes
3222162856Sdesint
3223162856Sdeschannel_add_adm_permitted_opens(char *host, int port)
3224162856Sdes{
3225162856Sdes	debug("config allows port forwarding to host %s port %d", host, port);
3226162856Sdes
3227215116Sdes	permitted_adm_opens = xrealloc(permitted_adm_opens,
3228215116Sdes	    num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
3229162856Sdes	permitted_adm_opens[num_adm_permitted_opens].host_to_connect
3230162856Sdes	     = xstrdup(host);
3231162856Sdes	permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
3232162856Sdes	return ++num_adm_permitted_opens;
3233162856Sdes}
3234162856Sdes
323576262Sgreenvoid
3236240075Sdeschannel_disable_adm_local_opens(void)
3237240075Sdes{
3238248619Sdes	channel_clear_adm_permitted_opens();
3239248619Sdes	permitted_adm_opens = xmalloc(sizeof(*permitted_adm_opens));
3240248619Sdes	permitted_adm_opens[num_adm_permitted_opens].host_to_connect = NULL;
3241248619Sdes	num_adm_permitted_opens = 1;
3242240075Sdes}
3243240075Sdes
3244240075Sdesvoid
324576262Sgreenchannel_clear_permitted_opens(void)
324676262Sgreen{
324776262Sgreen	int i;
324876262Sgreen
324976262Sgreen	for (i = 0; i < num_permitted_opens; i++)
3250255767Sdes		free(permitted_opens[i].host_to_connect);
3251255767Sdes	free(permitted_opens);
3252255767Sdes	permitted_opens = NULL;
325376262Sgreen	num_permitted_opens = 0;
3254162856Sdes}
325576262Sgreen
3256162856Sdesvoid
3257162856Sdeschannel_clear_adm_permitted_opens(void)
3258162856Sdes{
3259162856Sdes	int i;
3260162856Sdes
3261162856Sdes	for (i = 0; i < num_adm_permitted_opens; i++)
3262255767Sdes		free(permitted_adm_opens[i].host_to_connect);
3263255767Sdes	free(permitted_adm_opens);
3264255767Sdes	permitted_adm_opens = NULL;
3265162856Sdes	num_adm_permitted_opens = 0;
326676262Sgreen}
326776262Sgreen
3268181111Sdesvoid
3269181111Sdeschannel_print_adm_permitted_opens(void)
3270181111Sdes{
3271181111Sdes	int i;
3272181111Sdes
3273192595Sdes	printf("permitopen");
3274192595Sdes	if (num_adm_permitted_opens == 0) {
3275192595Sdes		printf(" any\n");
3276192595Sdes		return;
3277192595Sdes	}
3278181111Sdes	for (i = 0; i < num_adm_permitted_opens; i++)
3279240075Sdes		if (permitted_adm_opens[i].host_to_connect == NULL)
3280240075Sdes			printf(" none");
3281240075Sdes		else
3282181111Sdes			printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
3283181111Sdes			    permitted_adm_opens[i].port_to_connect);
3284192595Sdes	printf("\n");
3285181111Sdes}
3286181111Sdes
3287240075Sdes/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
3288240075Sdesint
3289240075Sdespermitopen_port(const char *p)
3290240075Sdes{
3291240075Sdes	int port;
3292240075Sdes
3293240075Sdes	if (strcmp(p, "*") == 0)
3294240075Sdes		return FWD_PERMIT_ANY_PORT;
3295240075Sdes	if ((port = a2port(p)) > 0)
3296240075Sdes		return port;
3297240075Sdes	return -1;
3298240075Sdes}
3299240075Sdes
3300240075Sdesstatic int
3301240075Sdesport_match(u_short allowedport, u_short requestedport)
3302240075Sdes{
3303240075Sdes	if (allowedport == FWD_PERMIT_ANY_PORT ||
3304240075Sdes	    allowedport == requestedport)
3305240075Sdes		return 1;
3306240075Sdes	return 0;
3307240075Sdes}
3308240075Sdes
3309181111Sdes/* Try to start non-blocking connect to next host in cctx list */
331092559Sdesstatic int
3311181111Sdesconnect_next(struct channel_connect *cctx)
331260573Skris{
3313181111Sdes	int sock, saved_errno;
331460573Skris	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
331560573Skris
3316181111Sdes	for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
3317181111Sdes		if (cctx->ai->ai_family != AF_INET &&
3318181111Sdes		    cctx->ai->ai_family != AF_INET6)
331960573Skris			continue;
3320181111Sdes		if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
3321181111Sdes		    ntop, sizeof(ntop), strport, sizeof(strport),
3322181111Sdes		    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
3323181111Sdes			error("connect_next: getnameinfo failed");
332460573Skris			continue;
332560573Skris		}
3326181111Sdes		if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
3327181111Sdes		    cctx->ai->ai_protocol)) == -1) {
3328181111Sdes			if (cctx->ai->ai_next == NULL)
3329113911Sdes				error("socket: %.100s", strerror(errno));
3330113911Sdes			else
3331113911Sdes				verbose("socket: %.100s", strerror(errno));
333260573Skris			continue;
333360573Skris		}
3334137019Sdes		if (set_nonblock(sock) == -1)
3335137019Sdes			fatal("%s: set_nonblock(%d)", __func__, sock);
3336181111Sdes		if (connect(sock, cctx->ai->ai_addr,
3337181111Sdes		    cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
3338181111Sdes			debug("connect_next: host %.100s ([%.100s]:%s): "
3339181111Sdes			    "%.100s", cctx->host, ntop, strport,
334060573Skris			    strerror(errno));
3341181111Sdes			saved_errno = errno;
334260573Skris			close(sock);
3343181111Sdes			errno = saved_errno;
334476262Sgreen			continue;	/* fail -- try next */
334560573Skris		}
3346181111Sdes		debug("connect_next: host %.100s ([%.100s]:%s) "
3347181111Sdes		    "in progress, fd=%d", cctx->host, ntop, strport, sock);
3348181111Sdes		cctx->ai = cctx->ai->ai_next;
3349181111Sdes		set_nodelay(sock);
3350181111Sdes		return sock;
3351181111Sdes	}
3352181111Sdes	return -1;
3353181111Sdes}
335460573Skris
3355181111Sdesstatic void
3356181111Sdeschannel_connect_ctx_free(struct channel_connect *cctx)
3357181111Sdes{
3358255767Sdes	free(cctx->host);
3359181111Sdes	if (cctx->aitop)
3360181111Sdes		freeaddrinfo(cctx->aitop);
3361181111Sdes	bzero(cctx, sizeof(*cctx));
3362181111Sdes	cctx->host = NULL;
3363181111Sdes	cctx->ai = cctx->aitop = NULL;
3364181111Sdes}
3365181111Sdes
3366181111Sdes/* Return CONNECTING channel to remote host, port */
3367181111Sdesstatic Channel *
3368181111Sdesconnect_to(const char *host, u_short port, char *ctype, char *rname)
3369181111Sdes{
3370181111Sdes	struct addrinfo hints;
3371181111Sdes	int gaierr;
3372181111Sdes	int sock = -1;
3373181111Sdes	char strport[NI_MAXSERV];
3374181111Sdes	struct channel_connect cctx;
3375181111Sdes	Channel *c;
3376181111Sdes
3377181111Sdes	memset(&cctx, 0, sizeof(cctx));
3378181111Sdes	memset(&hints, 0, sizeof(hints));
3379181111Sdes	hints.ai_family = IPv4or6;
3380181111Sdes	hints.ai_socktype = SOCK_STREAM;
3381181111Sdes	snprintf(strport, sizeof strport, "%d", port);
3382181111Sdes	if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
3383181111Sdes		error("connect_to %.100s: unknown host (%s)", host,
3384181111Sdes		    ssh_gai_strerror(gaierr));
3385181111Sdes		return NULL;
338660573Skris	}
3387181111Sdes
3388181111Sdes	cctx.host = xstrdup(host);
3389181111Sdes	cctx.port = port;
3390181111Sdes	cctx.ai = cctx.aitop;
3391181111Sdes
3392181111Sdes	if ((sock = connect_next(&cctx)) == -1) {
3393181111Sdes		error("connect to %.100s port %d failed: %s",
3394181111Sdes		    host, port, strerror(errno));
3395181111Sdes		channel_connect_ctx_free(&cctx);
3396181111Sdes		return NULL;
339760573Skris	}
3398181111Sdes	c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
3399181111Sdes	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
3400181111Sdes	c->connect_ctx = cctx;
3401181111Sdes	return c;
340260573Skris}
340376262Sgreen
3404181111SdesChannel *
3405181111Sdeschannel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
340676262Sgreen{
340776262Sgreen	int i;
340876262Sgreen
3409181111Sdes	for (i = 0; i < num_permitted_opens; i++) {
3410137019Sdes		if (permitted_opens[i].host_to_connect != NULL &&
3411240075Sdes		    port_match(permitted_opens[i].listen_port, listen_port)) {
341276262Sgreen			return connect_to(
341376262Sgreen			    permitted_opens[i].host_to_connect,
3414181111Sdes			    permitted_opens[i].port_to_connect, ctype, rname);
3415181111Sdes		}
3416181111Sdes	}
341776262Sgreen	error("WARNING: Server requests forwarding for unknown listen_port %d",
341876262Sgreen	    listen_port);
3419181111Sdes	return NULL;
342076262Sgreen}
342176262Sgreen
342276262Sgreen/* Check if connecting to that port is permitted and connect. */
3423181111SdesChannel *
3424181111Sdeschannel_connect_to(const char *host, u_short port, char *ctype, char *rname)
342576262Sgreen{
3426162856Sdes	int i, permit, permit_adm = 1;
342776262Sgreen
342876262Sgreen	permit = all_opens_permitted;
342976262Sgreen	if (!permit) {
343076262Sgreen		for (i = 0; i < num_permitted_opens; i++)
3431137019Sdes			if (permitted_opens[i].host_to_connect != NULL &&
3432240075Sdes			    port_match(permitted_opens[i].port_to_connect, port) &&
343376262Sgreen			    strcmp(permitted_opens[i].host_to_connect, host) == 0)
343476262Sgreen				permit = 1;
3435162856Sdes	}
343676262Sgreen
3437162856Sdes	if (num_adm_permitted_opens > 0) {
3438162856Sdes		permit_adm = 0;
3439162856Sdes		for (i = 0; i < num_adm_permitted_opens; i++)
3440162856Sdes			if (permitted_adm_opens[i].host_to_connect != NULL &&
3441240075Sdes			    port_match(permitted_adm_opens[i].port_to_connect, port) &&
3442162856Sdes			    strcmp(permitted_adm_opens[i].host_to_connect, host)
3443162856Sdes			    == 0)
3444162856Sdes				permit_adm = 1;
344576262Sgreen	}
3446162856Sdes
3447162856Sdes	if (!permit || !permit_adm) {
3448124207Sdes		logit("Received request to connect to host %.100s port %d, "
344976262Sgreen		    "but the request was denied.", host, port);
3450181111Sdes		return NULL;
345176262Sgreen	}
3452181111Sdes	return connect_to(host, port, ctype, rname);
345376262Sgreen}
345476262Sgreen
3455137019Sdesvoid
3456137019Sdeschannel_send_window_changes(void)
3457137019Sdes{
3458137019Sdes	u_int i;
3459137019Sdes	struct winsize ws;
3460137019Sdes
3461137019Sdes	for (i = 0; i < channels_alloc; i++) {
3462147005Sdes		if (channels[i] == NULL || !channels[i]->client_tty ||
3463137019Sdes		    channels[i]->type != SSH_CHANNEL_OPEN)
3464137019Sdes			continue;
3465137019Sdes		if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
3466137019Sdes			continue;
3467137019Sdes		channel_request_start(i, "window-change", 0);
3468162856Sdes		packet_put_int((u_int)ws.ws_col);
3469162856Sdes		packet_put_int((u_int)ws.ws_row);
3470162856Sdes		packet_put_int((u_int)ws.ws_xpixel);
3471162856Sdes		packet_put_int((u_int)ws.ws_ypixel);
3472137019Sdes		packet_send();
3473137019Sdes	}
3474137019Sdes}
3475137019Sdes
347692559Sdes/* -- X11 forwarding */
347757429Smarkm
347857429Smarkm/*
347957429Smarkm * Creates an internet domain socket for listening for X11 connections.
348099063Sdes * Returns 0 and a suitable display number for the DISPLAY variable
348199063Sdes * stored in display_numberp , or -1 if an error occurs.
348257429Smarkm */
348392559Sdesint
348492559Sdesx11_create_display_inet(int x11_display_offset, int x11_use_localhost,
3485149753Sdes    int single_connection, u_int *display_numberp, int **chanids)
348657429Smarkm{
348792559Sdes	Channel *nc = NULL;
348857429Smarkm	int display_number, sock;
348957429Smarkm	u_short port;
349057429Smarkm	struct addrinfo hints, *ai, *aitop;
349157429Smarkm	char strport[NI_MAXSERV];
349257429Smarkm	int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
349357429Smarkm
3494157019Sdes	if (chanids == NULL)
3495157019Sdes		return -1;
3496157019Sdes
349757429Smarkm	for (display_number = x11_display_offset;
349892559Sdes	    display_number < MAX_DISPLAYS;
349992559Sdes	    display_number++) {
350057429Smarkm		port = 6000 + display_number;
350157429Smarkm		memset(&hints, 0, sizeof(hints));
350257429Smarkm		hints.ai_family = IPv4or6;
350392559Sdes		hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
350457429Smarkm		hints.ai_socktype = SOCK_STREAM;
350557429Smarkm		snprintf(strport, sizeof strport, "%d", port);
350657429Smarkm		if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
3507181111Sdes			error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
350892559Sdes			return -1;
350957429Smarkm		}
351057429Smarkm		for (ai = aitop; ai; ai = ai->ai_next) {
351157429Smarkm			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
351257429Smarkm				continue;
3513124207Sdes			sock = socket(ai->ai_family, ai->ai_socktype,
3514124207Sdes			    ai->ai_protocol);
351557429Smarkm			if (sock < 0) {
3516207319Sdes				if ((errno != EINVAL) && (errno != EAFNOSUPPORT)
3517207319Sdes#ifdef EPFNOSUPPORT
3518207319Sdes				    && (errno != EPFNOSUPPORT)
3519207319Sdes#endif
3520207319Sdes				    ) {
352198941Sdes					error("socket: %.100s", strerror(errno));
3522137019Sdes					freeaddrinfo(aitop);
352398941Sdes					return -1;
352498941Sdes				} else {
352598941Sdes					debug("x11_create_display_inet: Socket family %d not supported",
352698941Sdes						 ai->ai_family);
352798941Sdes					continue;
352898941Sdes				}
352957429Smarkm			}
3530204917Sdes			if (ai->ai_family == AF_INET6)
3531204917Sdes				sock_set_v6only(sock);
3532181111Sdes			if (x11_use_localhost)
3533181111Sdes				channel_set_reuseaddr(sock);
353457429Smarkm			if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
3535124207Sdes				debug2("bind port %d: %.100s", port, strerror(errno));
353657429Smarkm				close(sock);
353798941Sdes
353857429Smarkm				for (n = 0; n < num_socks; n++) {
353957429Smarkm					close(socks[n]);
354057429Smarkm				}
354157429Smarkm				num_socks = 0;
354257429Smarkm				break;
354357429Smarkm			}
354457429Smarkm			socks[num_socks++] = sock;
354557429Smarkm			if (num_socks == NUM_SOCKS)
354657429Smarkm				break;
354757429Smarkm		}
354876262Sgreen		freeaddrinfo(aitop);
354957429Smarkm		if (num_socks > 0)
355057429Smarkm			break;
355157429Smarkm	}
355257429Smarkm	if (display_number >= MAX_DISPLAYS) {
355357429Smarkm		error("Failed to allocate internet-domain X11 display socket.");
355492559Sdes		return -1;
355557429Smarkm	}
355657429Smarkm	/* Start listening for connections on the socket. */
355757429Smarkm	for (n = 0; n < num_socks; n++) {
355857429Smarkm		sock = socks[n];
3559126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
356057429Smarkm			error("listen: %.100s", strerror(errno));
356157429Smarkm			close(sock);
356292559Sdes			return -1;
356357429Smarkm		}
356457429Smarkm	}
356557429Smarkm
356657429Smarkm	/* Allocate a channel for each socket. */
3567162856Sdes	*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
356857429Smarkm	for (n = 0; n < num_socks; n++) {
356957429Smarkm		sock = socks[n];
3570224638Sbrooks		if (hpn_disabled)
3571224638Sbrooks			nc = channel_new("x11 listener",
3572224638Sbrooks			    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
3573224638Sbrooks			    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
3574224638Sbrooks			    0, "X11 inet listener", 1);
3575224638Sbrooks		else
3576224638Sbrooks			nc = channel_new("x11 listener",
3577224638Sbrooks			    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
3578224638Sbrooks			    buffer_size, CHAN_X11_PACKET_DEFAULT,
3579224638Sbrooks			    0, "X11 inet listener", 1);
358092559Sdes		nc->single_connection = single_connection;
3581157019Sdes		(*chanids)[n] = nc->self;
358257429Smarkm	}
3583157019Sdes	(*chanids)[n] = -1;
358457429Smarkm
358592559Sdes	/* Return the display number for the DISPLAY environment variable. */
358699063Sdes	*display_numberp = display_number;
358799063Sdes	return (0);
358857429Smarkm}
358957429Smarkm
359092559Sdesstatic int
3591192595Sdesconnect_local_xsocket_path(const char *pathname)
359257429Smarkm{
359357429Smarkm	int sock;
359457429Smarkm	struct sockaddr_un addr;
359557429Smarkm
359692559Sdes	sock = socket(AF_UNIX, SOCK_STREAM, 0);
359792559Sdes	if (sock < 0)
359892559Sdes		error("socket: %.100s", strerror(errno));
359992559Sdes	memset(&addr, 0, sizeof(addr));
360092559Sdes	addr.sun_family = AF_UNIX;
3601192595Sdes	strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
3602162856Sdes	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
360392559Sdes		return sock;
360492559Sdes	close(sock);
360557429Smarkm	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
360657429Smarkm	return -1;
360757429Smarkm}
360857429Smarkm
3609192595Sdesstatic int
3610192595Sdesconnect_local_xsocket(u_int dnr)
3611192595Sdes{
3612192595Sdes	char buf[1024];
3613192595Sdes	snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
3614192595Sdes	return connect_local_xsocket_path(buf);
3615192595Sdes}
3616192595Sdes
361760573Skrisint
361860573Skrisx11_connect_display(void)
361957429Smarkm{
3620162856Sdes	u_int display_number;
362157429Smarkm	const char *display;
362260573Skris	char buf[1024], *cp;
362357429Smarkm	struct addrinfo hints, *ai, *aitop;
362457429Smarkm	char strport[NI_MAXSERV];
3625162856Sdes	int gaierr, sock = 0;
362657429Smarkm
362757429Smarkm	/* Try to open a socket for the local X server. */
362857429Smarkm	display = getenv("DISPLAY");
362957429Smarkm	if (!display) {
363057429Smarkm		error("DISPLAY not set.");
363160573Skris		return -1;
363257429Smarkm	}
363357429Smarkm	/*
363457429Smarkm	 * Now we decode the value of the DISPLAY variable and make a
363557429Smarkm	 * connection to the real X server.
363657429Smarkm	 */
363757429Smarkm
3638192595Sdes	/* Check if the display is from launchd. */
3639192595Sdes#ifdef __APPLE__
3640192595Sdes	if (strncmp(display, "/tmp/launch", 11) == 0) {
3641192595Sdes		sock = connect_local_xsocket_path(display);
3642192595Sdes		if (sock < 0)
3643192595Sdes			return -1;
3644192595Sdes
3645192595Sdes		/* OK, we now have a connection to the display. */
3646192595Sdes		return sock;
3647192595Sdes	}
3648192595Sdes#endif
364957429Smarkm	/*
365057429Smarkm	 * Check if it is a unix domain socket.  Unix domain displays are in
365157429Smarkm	 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
365257429Smarkm	 */
365357429Smarkm	if (strncmp(display, "unix:", 5) == 0 ||
365457429Smarkm	    display[0] == ':') {
365557429Smarkm		/* Connect to the unix domain socket. */
3656162856Sdes		if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
365757429Smarkm			error("Could not parse display number from DISPLAY: %.100s",
365892559Sdes			    display);
365960573Skris			return -1;
366057429Smarkm		}
366157429Smarkm		/* Create a socket. */
366257429Smarkm		sock = connect_local_xsocket(display_number);
366357429Smarkm		if (sock < 0)
366460573Skris			return -1;
366557429Smarkm
366657429Smarkm		/* OK, we now have a connection to the display. */
366760573Skris		return sock;
366857429Smarkm	}
366957429Smarkm	/*
367057429Smarkm	 * Connect to an inet socket.  The DISPLAY value is supposedly
367157429Smarkm	 * hostname:d[.s], where hostname may also be numeric IP address.
367257429Smarkm	 */
367392559Sdes	strlcpy(buf, display, sizeof(buf));
367457429Smarkm	cp = strchr(buf, ':');
367557429Smarkm	if (!cp) {
367657429Smarkm		error("Could not find ':' in DISPLAY: %.100s", display);
367760573Skris		return -1;
367857429Smarkm	}
367957429Smarkm	*cp = 0;
368057429Smarkm	/* buf now contains the host name.  But first we parse the display number. */
3681162856Sdes	if (sscanf(cp + 1, "%u", &display_number) != 1) {
368257429Smarkm		error("Could not parse display number from DISPLAY: %.100s",
368392559Sdes		    display);
368460573Skris		return -1;
368557429Smarkm	}
368657429Smarkm
368757429Smarkm	/* Look up the host address */
368857429Smarkm	memset(&hints, 0, sizeof(hints));
368957429Smarkm	hints.ai_family = IPv4or6;
369057429Smarkm	hints.ai_socktype = SOCK_STREAM;
3691162856Sdes	snprintf(strport, sizeof strport, "%u", 6000 + display_number);
369257429Smarkm	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
3693181111Sdes		error("%.100s: unknown host. (%s)", buf,
3694181111Sdes		ssh_gai_strerror(gaierr));
369560573Skris		return -1;
369657429Smarkm	}
369757429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
369857429Smarkm		/* Create a socket. */
3699124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
370057429Smarkm		if (sock < 0) {
3701124207Sdes			debug2("socket: %.100s", strerror(errno));
370260573Skris			continue;
370360573Skris		}
370460573Skris		/* Connect it to the display. */
370560573Skris		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
3706162856Sdes			debug2("connect %.100s port %u: %.100s", buf,
370760573Skris			    6000 + display_number, strerror(errno));
370860573Skris			close(sock);
370960573Skris			continue;
371060573Skris		}
371160573Skris		/* Success */
371260573Skris		break;
371357429Smarkm	}
371457429Smarkm	freeaddrinfo(aitop);
371557429Smarkm	if (!ai) {
3716162856Sdes		error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
371757429Smarkm		    strerror(errno));
371860573Skris		return -1;
371957429Smarkm	}
372092559Sdes	set_nodelay(sock);
372160573Skris	return sock;
372260573Skris}
372357429Smarkm
372460573Skris/*
372560573Skris * This is called when SSH_SMSG_X11_OPEN is received.  The packet contains
372660573Skris * the remote channel number.  We should do whatever we want, and respond
372760573Skris * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
372860573Skris */
372957429Smarkm
3730162856Sdes/* ARGSUSED */
373160573Skrisvoid
373292559Sdesx11_input_open(int type, u_int32_t seq, void *ctxt)
373360573Skris{
373492559Sdes	Channel *c = NULL;
373592559Sdes	int remote_id, sock = 0;
373660573Skris	char *remote_host;
373757429Smarkm
373892559Sdes	debug("Received X11 open request.");
373957429Smarkm
374092559Sdes	remote_id = packet_get_int();
374192559Sdes
374292559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
374392559Sdes		remote_host = packet_get_string(NULL);
374460573Skris	} else {
374560573Skris		remote_host = xstrdup("unknown (remote did not supply name)");
374660573Skris	}
374792559Sdes	packet_check_eom();
374860573Skris
374960573Skris	/* Obtain a connection to the real X display. */
375060573Skris	sock = x11_connect_display();
375192559Sdes	if (sock != -1) {
375292559Sdes		/* Allocate a channel for this connection. */
375392559Sdes		c = channel_new("connected x11 socket",
375492559Sdes		    SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
375592559Sdes		    remote_host, 1);
375692559Sdes		c->remote_id = remote_id;
375792559Sdes		c->force_drain = 1;
375892559Sdes	}
3759255767Sdes	free(remote_host);
376092559Sdes	if (c == NULL) {
376160573Skris		/* Send refusal to the remote host. */
376260573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
376392559Sdes		packet_put_int(remote_id);
376460573Skris	} else {
376560573Skris		/* Send a confirmation to the remote host. */
376660573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
376792559Sdes		packet_put_int(remote_id);
376892559Sdes		packet_put_int(c->self);
376960573Skris	}
377092559Sdes	packet_send();
377157429Smarkm}
377257429Smarkm
377369587Sgreen/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
3774162856Sdes/* ARGSUSED */
377569587Sgreenvoid
377692559Sdesdeny_input_open(int type, u_int32_t seq, void *ctxt)
377769587Sgreen{
377869587Sgreen	int rchan = packet_get_int();
3779106130Sdes
378092559Sdes	switch (type) {
378169587Sgreen	case SSH_SMSG_AGENT_OPEN:
378269587Sgreen		error("Warning: ssh server tried agent forwarding.");
378369587Sgreen		break;
378469587Sgreen	case SSH_SMSG_X11_OPEN:
378569587Sgreen		error("Warning: ssh server tried X11 forwarding.");
378669587Sgreen		break;
378769587Sgreen	default:
378892559Sdes		error("deny_input_open: type %d", type);
378969587Sgreen		break;
379069587Sgreen	}
3791157019Sdes	error("Warning: this is probably a break-in attempt by a malicious server.");
379269587Sgreen	packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
379369587Sgreen	packet_put_int(rchan);
379469587Sgreen	packet_send();
379569587Sgreen}
379669587Sgreen
379757429Smarkm/*
379857429Smarkm * Requests forwarding of X11 connections, generates fake authentication
379957429Smarkm * data, and enables authentication spoofing.
380092559Sdes * This should be called in the client only.
380157429Smarkm */
380260573Skrisvoid
3803149753Sdesx11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
3804226046Sdes    const char *proto, const char *data, int want_reply)
380557429Smarkm{
380676262Sgreen	u_int data_len = (u_int) strlen(data) / 2;
3807149753Sdes	u_int i, value;
380857429Smarkm	char *new_data;
380957429Smarkm	int screen_number;
381057429Smarkm	const char *cp;
3811137019Sdes	u_int32_t rnd = 0;
381257429Smarkm
3813149753Sdes	if (x11_saved_display == NULL)
3814149753Sdes		x11_saved_display = xstrdup(disp);
3815149753Sdes	else if (strcmp(disp, x11_saved_display) != 0) {
3816149753Sdes		error("x11_request_forwarding_with_spoofing: different "
3817149753Sdes		    "$DISPLAY already forwarded");
3818149753Sdes		return;
3819149753Sdes	}
3820149753Sdes
3821162856Sdes	cp = strchr(disp, ':');
382257429Smarkm	if (cp)
382357429Smarkm		cp = strchr(cp, '.');
382457429Smarkm	if (cp)
3825162856Sdes		screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
382657429Smarkm	else
382757429Smarkm		screen_number = 0;
382857429Smarkm
3829149753Sdes	if (x11_saved_proto == NULL) {
3830149753Sdes		/* Save protocol name. */
3831149753Sdes		x11_saved_proto = xstrdup(proto);
3832149753Sdes		/*
3833149753Sdes		 * Extract real authentication data and generate fake data
3834149753Sdes		 * of the same length.
3835149753Sdes		 */
3836149753Sdes		x11_saved_data = xmalloc(data_len);
3837149753Sdes		x11_fake_data = xmalloc(data_len);
3838149753Sdes		for (i = 0; i < data_len; i++) {
3839149753Sdes			if (sscanf(data + 2 * i, "%2x", &value) != 1)
3840149753Sdes				fatal("x11_request_forwarding: bad "
3841149753Sdes				    "authentication data: %.100s", data);
3842149753Sdes			if (i % 4 == 0)
3843149753Sdes				rnd = arc4random();
3844149753Sdes			x11_saved_data[i] = value;
3845149753Sdes			x11_fake_data[i] = rnd & 0xff;
3846149753Sdes			rnd >>= 8;
3847149753Sdes		}
3848149753Sdes		x11_saved_data_len = data_len;
3849149753Sdes		x11_fake_data_len = data_len;
385057429Smarkm	}
385157429Smarkm
385257429Smarkm	/* Convert the fake data into hex. */
3853149753Sdes	new_data = tohex(x11_fake_data, data_len);
385457429Smarkm
385557429Smarkm	/* Send the request packet. */
385660573Skris	if (compat20) {
3857226046Sdes		channel_request_start(client_session_id, "x11-req", want_reply);
385860573Skris		packet_put_char(0);	/* XXX bool single connection */
385960573Skris	} else {
386060573Skris		packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
386160573Skris	}
386260573Skris	packet_put_cstring(proto);
386360573Skris	packet_put_cstring(new_data);
386457429Smarkm	packet_put_int(screen_number);
386557429Smarkm	packet_send();
386657429Smarkm	packet_write_wait();
3867255767Sdes	free(new_data);
386857429Smarkm}
386957429Smarkm
387092559Sdes
387192559Sdes/* -- agent forwarding */
387292559Sdes
387357429Smarkm/* Sends a message to the server to request authentication fd forwarding. */
387457429Smarkm
387560573Skrisvoid
387692559Sdesauth_request_forwarding(void)
387757429Smarkm{
387857429Smarkm	packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
387957429Smarkm	packet_send();
388057429Smarkm	packet_write_wait();
388157429Smarkm}
3882