1323124Sdes/* $OpenBSD: channels.c,v 1.351 2016/07/19 11:38:53 dtucker Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * This file contains functions for generic socket connection forwarding.
757429Smarkm * There is also code for initiating connection forwarding for X11 connections,
857429Smarkm * arbitrary tcp/ip connections, and the authentication agent connection.
960573Skris *
1065668Skris * As far as I am concerned, the code I have written for this software
1165668Skris * can be used freely for any purpose.  Any derived versions of this
1265668Skris * software must be clearly marked as such, and if the derived work is
1365668Skris * incompatible with the protocol description in the RFC file, it must be
1465668Skris * called by a name other than "ssh" or "Secure Shell".
1565668Skris *
1660573Skris * SSH2 support added by Markus Friedl.
1792559Sdes * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
1865668Skris * Copyright (c) 1999 Dug Song.  All rights reserved.
1965668Skris * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
2065668Skris *
2165668Skris * Redistribution and use in source and binary forms, with or without
2265668Skris * modification, are permitted provided that the following conditions
2365668Skris * are met:
2465668Skris * 1. Redistributions of source code must retain the above copyright
2565668Skris *    notice, this list of conditions and the following disclaimer.
2665668Skris * 2. Redistributions in binary form must reproduce the above copyright
2765668Skris *    notice, this list of conditions and the following disclaimer in the
2865668Skris *    documentation and/or other materials provided with the distribution.
2965668Skris *
3065668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3165668Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3265668Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3365668Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3465668Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3565668Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3665668Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3765668Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3865668Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3965668Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4057429Smarkm */
4157429Smarkm
4257429Smarkm#include "includes.h"
4357429Smarkm
44162856Sdes#include <sys/types.h>
45295367Sdes#include <sys/param.h>	/* MIN MAX */
46295367Sdes#include <sys/stat.h>
47162856Sdes#include <sys/ioctl.h>
48162856Sdes#include <sys/un.h>
49162856Sdes#include <sys/socket.h>
50162856Sdes#ifdef HAVE_SYS_TIME_H
51162856Sdes# include <sys/time.h>
52162856Sdes#endif
53162856Sdes
54162856Sdes#include <netinet/in.h>
55162856Sdes#include <arpa/inet.h>
56162856Sdes
57162856Sdes#include <errno.h>
58204917Sdes#include <fcntl.h>
59162856Sdes#include <netdb.h>
60295367Sdes#ifdef HAVE_STDINT_H
61295367Sdes#include <stdint.h>
62295367Sdes#endif
63162856Sdes#include <stdio.h>
64162856Sdes#include <stdlib.h>
65162856Sdes#include <string.h>
66162856Sdes#include <termios.h>
67162856Sdes#include <unistd.h>
68162856Sdes#include <stdarg.h>
69162856Sdes
70181111Sdes#include "openbsd-compat/sys-queue.h"
71162856Sdes#include "xmalloc.h"
7257429Smarkm#include "ssh.h"
7376262Sgreen#include "ssh1.h"
7476262Sgreen#include "ssh2.h"
7557429Smarkm#include "packet.h"
7676262Sgreen#include "log.h"
7776262Sgreen#include "misc.h"
78162856Sdes#include "buffer.h"
7957429Smarkm#include "channels.h"
8057429Smarkm#include "compat.h"
8176262Sgreen#include "canohost.h"
8265668Skris#include "key.h"
8365668Skris#include "authfd.h"
8492559Sdes#include "pathnames.h"
8565668Skris
8692559Sdes/* -- channel core */
8757429Smarkm
8857429Smarkm/*
8957429Smarkm * Pointer to an array containing all allocated channels.  The array is
9057429Smarkm * dynamically extended as needed.
9157429Smarkm */
9292559Sdesstatic Channel **channels = NULL;
9357429Smarkm
9457429Smarkm/*
9557429Smarkm * Size of the channel array.  All slots of the array must always be
9692559Sdes * initialized (at least the type field); unused slots set to NULL
9757429Smarkm */
98137019Sdesstatic u_int channels_alloc = 0;
9957429Smarkm
10057429Smarkm/*
10157429Smarkm * Maximum file descriptor value used in any of the channels.  This is
10292559Sdes * updated in channel_new.
10357429Smarkm */
10476262Sgreenstatic int channel_max_fd = 0;
10557429Smarkm
10657429Smarkm
10792559Sdes/* -- tcp forwarding */
10857429Smarkm
10957429Smarkm/*
11057429Smarkm * Data structure for storing which hosts are permitted for forward requests.
11157429Smarkm * The local sides of any remote forwards are stored in this array to prevent
11257429Smarkm * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
11357429Smarkm * network (which might be behind a firewall).
11457429Smarkm */
115295367Sdes/* XXX: streamlocal wants a path instead of host:port */
116295367Sdes/*      Overload host_to_connect; we could just make this match Forward */
117295367Sdes/*	XXX - can we use listen_host instead of listen_path? */
11857429Smarkmtypedef struct {
11960573Skris	char *host_to_connect;		/* Connect to 'host'. */
120295367Sdes	int port_to_connect;		/* Connect to 'port'. */
121295367Sdes	char *listen_host;		/* Remote side should listen address. */
122295367Sdes	char *listen_path;		/* Remote side should listen path. */
123295367Sdes	int listen_port;		/* Remote side should listen port. */
12457429Smarkm} ForwardPermission;
12557429Smarkm
126162856Sdes/* List of all permitted host/port pairs to connect by the user. */
127215116Sdesstatic ForwardPermission *permitted_opens = NULL;
12892559Sdes
129162856Sdes/* List of all permitted host/port pairs to connect by the admin. */
130215116Sdesstatic ForwardPermission *permitted_adm_opens = NULL;
131162856Sdes
132162856Sdes/* Number of permitted host/port pairs in the array permitted by the user. */
13357429Smarkmstatic int num_permitted_opens = 0;
134162856Sdes
135162856Sdes/* Number of permitted host/port pair in the array permitted by the admin. */
136162856Sdesstatic int num_adm_permitted_opens = 0;
137162856Sdes
138240075Sdes/* special-case port number meaning allow any port */
139240075Sdes#define FWD_PERMIT_ANY_PORT	0
140240075Sdes
141323124Sdes/* special-case wildcard meaning allow any host */
142323124Sdes#define FWD_PERMIT_ANY_HOST	"*"
143323124Sdes
14457429Smarkm/*
14557429Smarkm * If this is true, all opens are permitted.  This is the case on the server
14657429Smarkm * on which we have to trust the client anyway, and the user could do
14757429Smarkm * anything after logging in anyway.
14857429Smarkm */
14957429Smarkmstatic int all_opens_permitted = 0;
15057429Smarkm
15157429Smarkm
15292559Sdes/* -- X11 forwarding */
15392559Sdes
15492559Sdes/* Maximum number of fake X11 displays to try. */
15592559Sdes#define MAX_DISPLAYS  1000
15692559Sdes
157149753Sdes/* Saved X11 local (client) display. */
158149753Sdesstatic char *x11_saved_display = NULL;
159149753Sdes
16092559Sdes/* Saved X11 authentication protocol name. */
16192559Sdesstatic char *x11_saved_proto = NULL;
16292559Sdes
16392559Sdes/* Saved X11 authentication data.  This is the real data. */
16492559Sdesstatic char *x11_saved_data = NULL;
16592559Sdesstatic u_int x11_saved_data_len = 0;
16692559Sdes
167295367Sdes/* Deadline after which all X11 connections are refused */
168295367Sdesstatic u_int x11_refuse_time;
169295367Sdes
17092559Sdes/*
17192559Sdes * Fake X11 authentication data.  This is what the server will be sending us;
17292559Sdes * we should replace any occurrences of this by the real data.
17392559Sdes */
174162856Sdesstatic u_char *x11_fake_data = NULL;
17592559Sdesstatic u_int x11_fake_data_len;
17692559Sdes
17792559Sdes
17892559Sdes/* -- agent forwarding */
17992559Sdes
18092559Sdes#define	NUM_SOCKS	10
18192559Sdes
18276262Sgreen/* AF_UNSPEC or AF_INET or AF_INET6 */
18398941Sdesstatic int IPv4or6 = AF_UNSPEC;
18476262Sgreen
18592559Sdes/* helper */
18692559Sdesstatic void port_open_helper(Channel *c, char *rtype);
18776262Sgreen
188181111Sdes/* non-blocking connect helpers */
189181111Sdesstatic int connect_next(struct channel_connect *);
190181111Sdesstatic void channel_connect_ctx_free(struct channel_connect *);
191181111Sdes
19292559Sdes/* -- channel core */
19357429Smarkm
19460573SkrisChannel *
195157019Sdeschannel_by_id(int id)
19660573Skris{
19760573Skris	Channel *c;
19892559Sdes
199137019Sdes	if (id < 0 || (u_int)id >= channels_alloc) {
200157019Sdes		logit("channel_by_id: %d: bad id", id);
20160573Skris		return NULL;
20260573Skris	}
20392559Sdes	c = channels[id];
20492559Sdes	if (c == NULL) {
205157019Sdes		logit("channel_by_id: %d: bad id: channel free", id);
20660573Skris		return NULL;
20760573Skris	}
20860573Skris	return c;
20960573Skris}
21060573Skris
21157429Smarkm/*
212157019Sdes * Returns the channel if it is allowed to receive protocol messages.
213157019Sdes * Private channels, like listening sockets, may not receive messages.
214157019Sdes */
215157019SdesChannel *
216157019Sdeschannel_lookup(int id)
217157019Sdes{
218157019Sdes	Channel *c;
219157019Sdes
220157019Sdes	if ((c = channel_by_id(id)) == NULL)
221157019Sdes		return (NULL);
222157019Sdes
223162856Sdes	switch (c->type) {
224157019Sdes	case SSH_CHANNEL_X11_OPEN:
225157019Sdes	case SSH_CHANNEL_LARVAL:
226157019Sdes	case SSH_CHANNEL_CONNECTING:
227157019Sdes	case SSH_CHANNEL_DYNAMIC:
228157019Sdes	case SSH_CHANNEL_OPENING:
229157019Sdes	case SSH_CHANNEL_OPEN:
230157019Sdes	case SSH_CHANNEL_INPUT_DRAINING:
231157019Sdes	case SSH_CHANNEL_OUTPUT_DRAINING:
232255767Sdes	case SSH_CHANNEL_ABANDONED:
233157019Sdes		return (c);
234157019Sdes	}
235157019Sdes	logit("Non-public channel %d, type %d.", id, c->type);
236157019Sdes	return (NULL);
237157019Sdes}
238157019Sdes
239157019Sdes/*
24060573Skris * Register filedescriptors for a channel, used when allocating a channel or
24160573Skris * when the channel consumer/producer is ready, e.g. shell exec'd
24260573Skris */
24392559Sdesstatic void
24469587Sgreenchannel_register_fds(Channel *c, int rfd, int wfd, int efd,
245181111Sdes    int extusage, int nonblock, int is_tty)
24660573Skris{
24760573Skris	/* Update the maximum file descriptor value. */
24876262Sgreen	channel_max_fd = MAX(channel_max_fd, rfd);
24976262Sgreen	channel_max_fd = MAX(channel_max_fd, wfd);
25076262Sgreen	channel_max_fd = MAX(channel_max_fd, efd);
25176262Sgreen
252204917Sdes	if (rfd != -1)
253204917Sdes		fcntl(rfd, F_SETFD, FD_CLOEXEC);
254204917Sdes	if (wfd != -1 && wfd != rfd)
255204917Sdes		fcntl(wfd, F_SETFD, FD_CLOEXEC);
256204917Sdes	if (efd != -1 && efd != rfd && efd != wfd)
257204917Sdes		fcntl(efd, F_SETFD, FD_CLOEXEC);
25860573Skris
25960573Skris	c->rfd = rfd;
26060573Skris	c->wfd = wfd;
26160573Skris	c->sock = (rfd == wfd) ? rfd : -1;
26260573Skris	c->efd = efd;
26360573Skris	c->extended_usage = extusage;
26469587Sgreen
265181111Sdes	if ((c->isatty = is_tty) != 0)
266124207Sdes		debug2("channel %d: rfd %d isatty", c->self, c->rfd);
267255767Sdes#ifdef _AIX
268255767Sdes	/* XXX: Later AIX versions can't push as much data to tty */
269181111Sdes	c->wfd_isatty = is_tty || isatty(c->wfd);
270255767Sdes#endif
27174500Sgreen
27269587Sgreen	/* enable nonblocking mode */
27369587Sgreen	if (nonblock) {
27469587Sgreen		if (rfd != -1)
27569587Sgreen			set_nonblock(rfd);
27669587Sgreen		if (wfd != -1)
27769587Sgreen			set_nonblock(wfd);
27869587Sgreen		if (efd != -1)
27969587Sgreen			set_nonblock(efd);
28069587Sgreen	}
28160573Skris}
28260573Skris
28360573Skris/*
28457429Smarkm * Allocate a new channel object and set its type and socket. This will cause
28557429Smarkm * remote_name to be freed.
28657429Smarkm */
28792559SdesChannel *
28860573Skrischannel_new(char *ctype, int type, int rfd, int wfd, int efd,
28999063Sdes    u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
29057429Smarkm{
291137019Sdes	int found;
292137019Sdes	u_int i;
29357429Smarkm	Channel *c;
29457429Smarkm
29557429Smarkm	/* Do initial allocation if this is the first call. */
29657429Smarkm	if (channels_alloc == 0) {
29757429Smarkm		channels_alloc = 10;
298162856Sdes		channels = xcalloc(channels_alloc, sizeof(Channel *));
29957429Smarkm		for (i = 0; i < channels_alloc; i++)
30092559Sdes			channels[i] = NULL;
30157429Smarkm	}
30257429Smarkm	/* Try to find a free slot where to put the new channel. */
30357429Smarkm	for (found = -1, i = 0; i < channels_alloc; i++)
30492559Sdes		if (channels[i] == NULL) {
30557429Smarkm			/* Found a free slot. */
306137019Sdes			found = (int)i;
30757429Smarkm			break;
30857429Smarkm		}
309137019Sdes	if (found < 0) {
31057429Smarkm		/* There are no free slots.  Take last+1 slot and expand the array.  */
31157429Smarkm		found = channels_alloc;
31299063Sdes		if (channels_alloc > 10000)
31399063Sdes			fatal("channel_new: internal error: channels_alloc %d "
31499063Sdes			    "too big.", channels_alloc);
315295367Sdes		channels = xreallocarray(channels, channels_alloc + 10,
316162856Sdes		    sizeof(Channel *));
317120489Sjoe		channels_alloc += 10;
31869587Sgreen		debug2("channel: expanding %d", channels_alloc);
31957429Smarkm		for (i = found; i < channels_alloc; i++)
32092559Sdes			channels[i] = NULL;
32157429Smarkm	}
32292559Sdes	/* Initialize and return new channel. */
323162856Sdes	c = channels[found] = xcalloc(1, sizeof(Channel));
32457429Smarkm	buffer_init(&c->input);
32557429Smarkm	buffer_init(&c->output);
32660573Skris	buffer_init(&c->extended);
327192595Sdes	c->path = NULL;
328240075Sdes	c->listening_addr = NULL;
329240075Sdes	c->listening_port = 0;
33092559Sdes	c->ostate = CHAN_OUTPUT_OPEN;
33192559Sdes	c->istate = CHAN_INPUT_OPEN;
33292559Sdes	c->flags = 0;
333181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
334240075Sdes	c->notbefore = 0;
33557429Smarkm	c->self = found;
33657429Smarkm	c->type = type;
33760573Skris	c->ctype = ctype;
33860573Skris	c->local_window = window;
33960573Skris	c->local_window_max = window;
34060573Skris	c->local_consumed = 0;
34160573Skris	c->local_maxpacket = maxpack;
34257429Smarkm	c->remote_id = -1;
343124207Sdes	c->remote_name = xstrdup(remote_name);
34460573Skris	c->remote_window = 0;
34560573Skris	c->remote_maxpacket = 0;
34692559Sdes	c->force_drain = 0;
34792559Sdes	c->single_connection = 0;
34892559Sdes	c->detach_user = NULL;
349157019Sdes	c->detach_close = 0;
350181111Sdes	c->open_confirm = NULL;
351181111Sdes	c->open_confirm_ctx = NULL;
35265668Skris	c->input_filter = NULL;
353157019Sdes	c->output_filter = NULL;
354181111Sdes	c->filter_ctx = NULL;
355181111Sdes	c->filter_cleanup = NULL;
356204917Sdes	c->ctl_chan = -1;
357204917Sdes	c->mux_rcb = NULL;
358204917Sdes	c->mux_ctx = NULL;
359215116Sdes	c->mux_pause = 0;
360204917Sdes	c->delayed = 1;		/* prevent call to channel_post handler */
361181111Sdes	TAILQ_INIT(&c->status_confirms);
36257429Smarkm	debug("channel %d: new [%s]", found, remote_name);
36392559Sdes	return c;
36457429Smarkm}
36592559Sdes
36692559Sdesstatic int
36792559Sdeschannel_find_maxfd(void)
36892559Sdes{
369137019Sdes	u_int i;
370137019Sdes	int max = 0;
37192559Sdes	Channel *c;
37292559Sdes
37392559Sdes	for (i = 0; i < channels_alloc; i++) {
37492559Sdes		c = channels[i];
37592559Sdes		if (c != NULL) {
37692559Sdes			max = MAX(max, c->rfd);
37792559Sdes			max = MAX(max, c->wfd);
37892559Sdes			max = MAX(max, c->efd);
37992559Sdes		}
38092559Sdes	}
38192559Sdes	return max;
38292559Sdes}
38392559Sdes
38460573Skrisint
38592559Sdeschannel_close_fd(int *fdp)
38660573Skris{
38792559Sdes	int ret = 0, fd = *fdp;
38892559Sdes
38992559Sdes	if (fd != -1) {
39092559Sdes		ret = close(fd);
39192559Sdes		*fdp = -1;
39292559Sdes		if (fd == channel_max_fd)
39392559Sdes			channel_max_fd = channel_find_maxfd();
39492559Sdes	}
39592559Sdes	return ret;
39660573Skris}
39757429Smarkm
39860573Skris/* Close all channel fd/socket. */
39992559Sdesstatic void
40060573Skrischannel_close_fds(Channel *c)
40157429Smarkm{
40292559Sdes	channel_close_fd(&c->sock);
40392559Sdes	channel_close_fd(&c->rfd);
40492559Sdes	channel_close_fd(&c->wfd);
40592559Sdes	channel_close_fd(&c->efd);
40660573Skris}
40757429Smarkm
40860573Skris/* Free the channel and close its fd/socket. */
40960573Skrisvoid
41092559Sdeschannel_free(Channel *c)
41160573Skris{
41292559Sdes	char *s;
413137019Sdes	u_int i, n;
414181111Sdes	struct channel_confirm *cc;
41576262Sgreen
41692559Sdes	for (n = 0, i = 0; i < channels_alloc; i++)
41792559Sdes		if (channels[i])
41892559Sdes			n++;
419137019Sdes	debug("channel %d: free: %s, nchannels %u", c->self,
42092559Sdes	    c->remote_name ? c->remote_name : "???", n);
42192559Sdes
42292559Sdes	s = channel_open_message();
423124207Sdes	debug3("channel %d: status: %s", c->self, s);
424255767Sdes	free(s);
42576262Sgreen
42660573Skris	if (c->sock != -1)
42760573Skris		shutdown(c->sock, SHUT_RDWR);
42860573Skris	channel_close_fds(c);
42960573Skris	buffer_free(&c->input);
43060573Skris	buffer_free(&c->output);
43160573Skris	buffer_free(&c->extended);
432255767Sdes	free(c->remote_name);
433255767Sdes	c->remote_name = NULL;
434255767Sdes	free(c->path);
435255767Sdes	c->path = NULL;
436255767Sdes	free(c->listening_addr);
437255767Sdes	c->listening_addr = NULL;
438181111Sdes	while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
439181111Sdes		if (cc->abandon_cb != NULL)
440181111Sdes			cc->abandon_cb(c, cc->ctx);
441181111Sdes		TAILQ_REMOVE(&c->status_confirms, cc, entry);
442264377Sdes		explicit_bzero(cc, sizeof(*cc));
443255767Sdes		free(cc);
444181111Sdes	}
445181111Sdes	if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
446181111Sdes		c->filter_cleanup(c->self, c->filter_ctx);
44792559Sdes	channels[c->self] = NULL;
448255767Sdes	free(c);
44957429Smarkm}
45057429Smarkm
45192559Sdesvoid
45292559Sdeschannel_free_all(void)
45392559Sdes{
454137019Sdes	u_int i;
45592559Sdes
45692559Sdes	for (i = 0; i < channels_alloc; i++)
45792559Sdes		if (channels[i] != NULL)
45892559Sdes			channel_free(channels[i]);
45992559Sdes}
46092559Sdes
46157429Smarkm/*
46292559Sdes * Closes the sockets/fds of all channels.  This is used to close extra file
46392559Sdes * descriptors after a fork.
46492559Sdes */
46592559Sdesvoid
46692559Sdeschannel_close_all(void)
46792559Sdes{
468137019Sdes	u_int i;
46992559Sdes
47092559Sdes	for (i = 0; i < channels_alloc; i++)
47192559Sdes		if (channels[i] != NULL)
47292559Sdes			channel_close_fds(channels[i]);
47392559Sdes}
47492559Sdes
47592559Sdes/*
47692559Sdes * Stop listening to channels.
47792559Sdes */
47892559Sdesvoid
47992559Sdeschannel_stop_listening(void)
48092559Sdes{
481137019Sdes	u_int i;
48292559Sdes	Channel *c;
48392559Sdes
48492559Sdes	for (i = 0; i < channels_alloc; i++) {
48592559Sdes		c = channels[i];
48692559Sdes		if (c != NULL) {
48792559Sdes			switch (c->type) {
48892559Sdes			case SSH_CHANNEL_AUTH_SOCKET:
48992559Sdes			case SSH_CHANNEL_PORT_LISTENER:
49092559Sdes			case SSH_CHANNEL_RPORT_LISTENER:
49192559Sdes			case SSH_CHANNEL_X11_LISTENER:
492295367Sdes			case SSH_CHANNEL_UNIX_LISTENER:
493295367Sdes			case SSH_CHANNEL_RUNIX_LISTENER:
49492559Sdes				channel_close_fd(&c->sock);
49592559Sdes				channel_free(c);
49692559Sdes				break;
49792559Sdes			}
49892559Sdes		}
49992559Sdes	}
50092559Sdes}
50192559Sdes
50292559Sdes/*
50392559Sdes * Returns true if no channel has too much buffered data, and false if one or
50492559Sdes * more channel is overfull.
50592559Sdes */
50692559Sdesint
50792559Sdeschannel_not_very_much_buffered_data(void)
50892559Sdes{
50992559Sdes	u_int i;
51092559Sdes	Channel *c;
51192559Sdes
51292559Sdes	for (i = 0; i < channels_alloc; i++) {
51392559Sdes		c = channels[i];
51492559Sdes		if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
51592559Sdes#if 0
51692559Sdes			if (!compat20 &&
51792559Sdes			    buffer_len(&c->input) > packet_get_maxsize()) {
518113911Sdes				debug2("channel %d: big input buffer %d",
51992559Sdes				    c->self, buffer_len(&c->input));
52092559Sdes				return 0;
52192559Sdes			}
52292559Sdes#endif
52392559Sdes			if (buffer_len(&c->output) > packet_get_maxsize()) {
524124207Sdes				debug2("channel %d: big output buffer %u > %u",
52592559Sdes				    c->self, buffer_len(&c->output),
52692559Sdes				    packet_get_maxsize());
52792559Sdes				return 0;
52892559Sdes			}
52992559Sdes		}
53092559Sdes	}
53192559Sdes	return 1;
53292559Sdes}
53392559Sdes
53492559Sdes/* Returns true if any channel is still open. */
53592559Sdesint
53692559Sdeschannel_still_open(void)
53792559Sdes{
538137019Sdes	u_int i;
53992559Sdes	Channel *c;
54092559Sdes
54192559Sdes	for (i = 0; i < channels_alloc; i++) {
54292559Sdes		c = channels[i];
54392559Sdes		if (c == NULL)
54492559Sdes			continue;
54592559Sdes		switch (c->type) {
54692559Sdes		case SSH_CHANNEL_X11_LISTENER:
54792559Sdes		case SSH_CHANNEL_PORT_LISTENER:
54892559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
549204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
55092559Sdes		case SSH_CHANNEL_CLOSED:
55192559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
55292559Sdes		case SSH_CHANNEL_DYNAMIC:
55392559Sdes		case SSH_CHANNEL_CONNECTING:
55492559Sdes		case SSH_CHANNEL_ZOMBIE:
555255767Sdes		case SSH_CHANNEL_ABANDONED:
556295367Sdes		case SSH_CHANNEL_UNIX_LISTENER:
557295367Sdes		case SSH_CHANNEL_RUNIX_LISTENER:
55892559Sdes			continue;
55992559Sdes		case SSH_CHANNEL_LARVAL:
56092559Sdes			if (!compat20)
56192559Sdes				fatal("cannot happen: SSH_CHANNEL_LARVAL");
56292559Sdes			continue;
56392559Sdes		case SSH_CHANNEL_OPENING:
56492559Sdes		case SSH_CHANNEL_OPEN:
56592559Sdes		case SSH_CHANNEL_X11_OPEN:
566204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
56792559Sdes			return 1;
56892559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
56992559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
57092559Sdes			if (!compat13)
57192559Sdes				fatal("cannot happen: OUT_DRAIN");
57292559Sdes			return 1;
57392559Sdes		default:
57492559Sdes			fatal("channel_still_open: bad channel type %d", c->type);
57592559Sdes			/* NOTREACHED */
57692559Sdes		}
57792559Sdes	}
57892559Sdes	return 0;
57992559Sdes}
58092559Sdes
58192559Sdes/* Returns the id of an open channel suitable for keepaliving */
58292559Sdesint
58392559Sdeschannel_find_open(void)
58492559Sdes{
585137019Sdes	u_int i;
58692559Sdes	Channel *c;
58792559Sdes
58892559Sdes	for (i = 0; i < channels_alloc; i++) {
58992559Sdes		c = channels[i];
590137019Sdes		if (c == NULL || c->remote_id < 0)
59192559Sdes			continue;
59292559Sdes		switch (c->type) {
59392559Sdes		case SSH_CHANNEL_CLOSED:
59492559Sdes		case SSH_CHANNEL_DYNAMIC:
59592559Sdes		case SSH_CHANNEL_X11_LISTENER:
59692559Sdes		case SSH_CHANNEL_PORT_LISTENER:
59792559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
598204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
599204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
60092559Sdes		case SSH_CHANNEL_OPENING:
60192559Sdes		case SSH_CHANNEL_CONNECTING:
60292559Sdes		case SSH_CHANNEL_ZOMBIE:
603255767Sdes		case SSH_CHANNEL_ABANDONED:
604295367Sdes		case SSH_CHANNEL_UNIX_LISTENER:
605295367Sdes		case SSH_CHANNEL_RUNIX_LISTENER:
60692559Sdes			continue;
60792559Sdes		case SSH_CHANNEL_LARVAL:
60892559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
60992559Sdes		case SSH_CHANNEL_OPEN:
61092559Sdes		case SSH_CHANNEL_X11_OPEN:
61192559Sdes			return i;
61292559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
61392559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
61492559Sdes			if (!compat13)
61592559Sdes				fatal("cannot happen: OUT_DRAIN");
61692559Sdes			return i;
61792559Sdes		default:
61892559Sdes			fatal("channel_find_open: bad channel type %d", c->type);
61992559Sdes			/* NOTREACHED */
62092559Sdes		}
62192559Sdes	}
62292559Sdes	return -1;
62392559Sdes}
62492559Sdes
62592559Sdes
62692559Sdes/*
62792559Sdes * Returns a message describing the currently open forwarded connections,
62892559Sdes * suitable for sending to the client.  The message contains crlf pairs for
62992559Sdes * newlines.
63092559Sdes */
63192559Sdeschar *
63292559Sdeschannel_open_message(void)
63392559Sdes{
63492559Sdes	Buffer buffer;
63592559Sdes	Channel *c;
63692559Sdes	char buf[1024], *cp;
637137019Sdes	u_int i;
63892559Sdes
63992559Sdes	buffer_init(&buffer);
64092559Sdes	snprintf(buf, sizeof buf, "The following connections are open:\r\n");
64192559Sdes	buffer_append(&buffer, buf, strlen(buf));
64292559Sdes	for (i = 0; i < channels_alloc; i++) {
64392559Sdes		c = channels[i];
64492559Sdes		if (c == NULL)
64592559Sdes			continue;
64692559Sdes		switch (c->type) {
64792559Sdes		case SSH_CHANNEL_X11_LISTENER:
64892559Sdes		case SSH_CHANNEL_PORT_LISTENER:
64992559Sdes		case SSH_CHANNEL_RPORT_LISTENER:
65092559Sdes		case SSH_CHANNEL_CLOSED:
65192559Sdes		case SSH_CHANNEL_AUTH_SOCKET:
65292559Sdes		case SSH_CHANNEL_ZOMBIE:
653255767Sdes		case SSH_CHANNEL_ABANDONED:
654204917Sdes		case SSH_CHANNEL_MUX_CLIENT:
655204917Sdes		case SSH_CHANNEL_MUX_LISTENER:
656295367Sdes		case SSH_CHANNEL_UNIX_LISTENER:
657295367Sdes		case SSH_CHANNEL_RUNIX_LISTENER:
65892559Sdes			continue;
65992559Sdes		case SSH_CHANNEL_LARVAL:
66092559Sdes		case SSH_CHANNEL_OPENING:
66192559Sdes		case SSH_CHANNEL_CONNECTING:
66292559Sdes		case SSH_CHANNEL_DYNAMIC:
66392559Sdes		case SSH_CHANNEL_OPEN:
66492559Sdes		case SSH_CHANNEL_X11_OPEN:
66592559Sdes		case SSH_CHANNEL_INPUT_DRAINING:
66692559Sdes		case SSH_CHANNEL_OUTPUT_DRAINING:
667137019Sdes			snprintf(buf, sizeof buf,
668296781Sdes			    "  #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
66992559Sdes			    c->self, c->remote_name,
67092559Sdes			    c->type, c->remote_id,
67192559Sdes			    c->istate, buffer_len(&c->input),
67292559Sdes			    c->ostate, buffer_len(&c->output),
673204917Sdes			    c->rfd, c->wfd, c->ctl_chan);
67492559Sdes			buffer_append(&buffer, buf, strlen(buf));
67592559Sdes			continue;
67692559Sdes		default:
67792559Sdes			fatal("channel_open_message: bad channel type %d", c->type);
67892559Sdes			/* NOTREACHED */
67992559Sdes		}
68092559Sdes	}
68192559Sdes	buffer_append(&buffer, "\0", 1);
682295367Sdes	cp = xstrdup((char *)buffer_ptr(&buffer));
68392559Sdes	buffer_free(&buffer);
68492559Sdes	return cp;
68592559Sdes}
68692559Sdes
68792559Sdesvoid
68892559Sdeschannel_send_open(int id)
68992559Sdes{
69092559Sdes	Channel *c = channel_lookup(id);
691106130Sdes
69292559Sdes	if (c == NULL) {
693124207Sdes		logit("channel_send_open: %d: bad id", id);
69492559Sdes		return;
69592559Sdes	}
696113911Sdes	debug2("channel %d: send open", id);
69792559Sdes	packet_start(SSH2_MSG_CHANNEL_OPEN);
69892559Sdes	packet_put_cstring(c->ctype);
69992559Sdes	packet_put_int(c->self);
70092559Sdes	packet_put_int(c->local_window);
70192559Sdes	packet_put_int(c->local_maxpacket);
70292559Sdes	packet_send();
70392559Sdes}
70492559Sdes
70592559Sdesvoid
706113911Sdeschannel_request_start(int id, char *service, int wantconfirm)
70792559Sdes{
708113911Sdes	Channel *c = channel_lookup(id);
709106130Sdes
71092559Sdes	if (c == NULL) {
711124207Sdes		logit("channel_request_start: %d: unknown channel id", id);
71292559Sdes		return;
71392559Sdes	}
714137019Sdes	debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
71592559Sdes	packet_start(SSH2_MSG_CHANNEL_REQUEST);
71692559Sdes	packet_put_int(c->remote_id);
71792559Sdes	packet_put_cstring(service);
71892559Sdes	packet_put_char(wantconfirm);
71992559Sdes}
720162856Sdes
72192559Sdesvoid
722181111Sdeschannel_register_status_confirm(int id, channel_confirm_cb *cb,
723181111Sdes    channel_confirm_abandon_cb *abandon_cb, void *ctx)
72492559Sdes{
725181111Sdes	struct channel_confirm *cc;
726181111Sdes	Channel *c;
727181111Sdes
728181111Sdes	if ((c = channel_lookup(id)) == NULL)
729181111Sdes		fatal("channel_register_expect: %d: bad id", id);
730181111Sdes
731258343Sdes	cc = xcalloc(1, sizeof(*cc));
732181111Sdes	cc->cb = cb;
733181111Sdes	cc->abandon_cb = abandon_cb;
734181111Sdes	cc->ctx = ctx;
735181111Sdes	TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
736181111Sdes}
737181111Sdes
738181111Sdesvoid
739215116Sdeschannel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
740181111Sdes{
74192559Sdes	Channel *c = channel_lookup(id);
742106130Sdes
74392559Sdes	if (c == NULL) {
744192595Sdes		logit("channel_register_open_confirm: %d: bad id", id);
74592559Sdes		return;
74692559Sdes	}
747181111Sdes	c->open_confirm = fn;
748181111Sdes	c->open_confirm_ctx = ctx;
74992559Sdes}
750162856Sdes
75192559Sdesvoid
752157019Sdeschannel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
75392559Sdes{
754157019Sdes	Channel *c = channel_by_id(id);
755106130Sdes
75692559Sdes	if (c == NULL) {
757124207Sdes		logit("channel_register_cleanup: %d: bad id", id);
75892559Sdes		return;
75992559Sdes	}
76092559Sdes	c->detach_user = fn;
761157019Sdes	c->detach_close = do_close;
76292559Sdes}
763162856Sdes
76492559Sdesvoid
76592559Sdeschannel_cancel_cleanup(int id)
76692559Sdes{
767157019Sdes	Channel *c = channel_by_id(id);
768106130Sdes
76992559Sdes	if (c == NULL) {
770124207Sdes		logit("channel_cancel_cleanup: %d: bad id", id);
77192559Sdes		return;
77292559Sdes	}
77392559Sdes	c->detach_user = NULL;
774157019Sdes	c->detach_close = 0;
77592559Sdes}
776162856Sdes
77792559Sdesvoid
778157019Sdeschannel_register_filter(int id, channel_infilter_fn *ifn,
779181111Sdes    channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
78092559Sdes{
78192559Sdes	Channel *c = channel_lookup(id);
782106130Sdes
78392559Sdes	if (c == NULL) {
784124207Sdes		logit("channel_register_filter: %d: bad id", id);
78592559Sdes		return;
78692559Sdes	}
787157019Sdes	c->input_filter = ifn;
788157019Sdes	c->output_filter = ofn;
789181111Sdes	c->filter_ctx = ctx;
790181111Sdes	c->filter_cleanup = cfn;
79192559Sdes}
79292559Sdes
79392559Sdesvoid
79492559Sdeschannel_set_fds(int id, int rfd, int wfd, int efd,
795181111Sdes    int extusage, int nonblock, int is_tty, u_int window_max)
79692559Sdes{
79792559Sdes	Channel *c = channel_lookup(id);
798106130Sdes
79992559Sdes	if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
80092559Sdes		fatal("channel_activate for non-larval channel %d.", id);
801181111Sdes	channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
80292559Sdes	c->type = SSH_CHANNEL_OPEN;
80392559Sdes	c->local_window = c->local_window_max = window_max;
80492559Sdes	packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
80592559Sdes	packet_put_int(c->remote_id);
80692559Sdes	packet_put_int(c->local_window);
80792559Sdes	packet_send();
80892559Sdes}
80992559Sdes
81092559Sdes/*
81160573Skris * 'channel_pre*' are called just before select() to add any bits relevant to
81260573Skris * channels in the select bitmasks.
81357429Smarkm */
81460573Skris/*
81560573Skris * 'channel_post*': perform any appropriate operations for channels which
81660573Skris * have events pending.
81760573Skris */
818162856Sdestypedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
81960573Skrischan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
82060573Skrischan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
82157429Smarkm
822162856Sdes/* ARGSUSED */
82392559Sdesstatic void
824162856Sdeschannel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
82557429Smarkm{
82660573Skris	FD_SET(c->sock, readset);
82760573Skris}
82860573Skris
829162856Sdes/* ARGSUSED */
83092559Sdesstatic void
831162856Sdeschannel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
83276262Sgreen{
83376262Sgreen	debug3("channel %d: waiting for connection", c->self);
83476262Sgreen	FD_SET(c->sock, writeset);
83576262Sgreen}
83676262Sgreen
83792559Sdesstatic void
838162856Sdeschannel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
83960573Skris{
84060573Skris	if (buffer_len(&c->input) < packet_get_maxsize())
84160573Skris		FD_SET(c->sock, readset);
84260573Skris	if (buffer_len(&c->output) > 0)
84360573Skris		FD_SET(c->sock, writeset);
84460573Skris}
84560573Skris
84692559Sdesstatic void
847162856Sdeschannel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
84860573Skris{
849294693Sdes	u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
85060573Skris
85160573Skris	if (c->istate == CHAN_INPUT_OPEN &&
85292559Sdes	    limit > 0 &&
853162856Sdes	    buffer_len(&c->input) < limit &&
854162856Sdes	    buffer_check_alloc(&c->input, CHAN_RBUF))
85560573Skris		FD_SET(c->rfd, readset);
85660573Skris	if (c->ostate == CHAN_OUTPUT_OPEN ||
85760573Skris	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
85860573Skris		if (buffer_len(&c->output) > 0) {
85960573Skris			FD_SET(c->wfd, writeset);
86060573Skris		} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
86198684Sdes			if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
862149753Sdes				debug2("channel %d: obuf_empty delayed efd %d/(%d)",
863149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
86498684Sdes			else
86598684Sdes				chan_obuf_empty(c);
86660573Skris		}
86760573Skris	}
86860573Skris	/** XXX check close conditions, too */
869181111Sdes	if (compat20 && c->efd != -1 &&
870181111Sdes	    !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
87160573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
87260573Skris		    buffer_len(&c->extended) > 0)
87360573Skris			FD_SET(c->efd, writeset);
874215116Sdes		else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
875215116Sdes		    (c->extended_usage == CHAN_EXTENDED_READ ||
876215116Sdes		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
87760573Skris		    buffer_len(&c->extended) < c->remote_window)
87860573Skris			FD_SET(c->efd, readset);
87960573Skris	}
880137019Sdes	/* XXX: What about efd? races? */
88160573Skris}
88260573Skris
883162856Sdes/* ARGSUSED */
88492559Sdesstatic void
885162856Sdeschannel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
88660573Skris{
88760573Skris	if (buffer_len(&c->input) == 0) {
88860573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
88960573Skris		packet_put_int(c->remote_id);
89060573Skris		packet_send();
89160573Skris		c->type = SSH_CHANNEL_CLOSED;
892124207Sdes		debug2("channel %d: closing after input drain.", c->self);
89360573Skris	}
89460573Skris}
89560573Skris
896162856Sdes/* ARGSUSED */
89792559Sdesstatic void
898162856Sdeschannel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
89960573Skris{
90060573Skris	if (buffer_len(&c->output) == 0)
90192559Sdes		chan_mark_dead(c);
90260573Skris	else
90360573Skris		FD_SET(c->sock, writeset);
90460573Skris}
90560573Skris
90660573Skris/*
90760573Skris * This is a special state for X11 authentication spoofing.  An opened X11
90860573Skris * connection (when authentication spoofing is being done) remains in this
90960573Skris * state until the first packet has been completely read.  The authentication
91060573Skris * data in that packet is then substituted by the real data if it matches the
91160573Skris * fake data, and the channel is put into normal mode.
91260573Skris * XXX All this happens at the client side.
91392559Sdes * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
91460573Skris */
91592559Sdesstatic int
91692559Sdesx11_open_helper(Buffer *b)
91760573Skris{
91876262Sgreen	u_char *ucp;
91976262Sgreen	u_int proto_len, data_len;
92057429Smarkm
921295367Sdes	/* Is this being called after the refusal deadline? */
922295367Sdes	if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
923295367Sdes		verbose("Rejected X11 connection after ForwardX11Timeout "
924295367Sdes		    "expired");
925295367Sdes		return -1;
926295367Sdes	}
927295367Sdes
92860573Skris	/* Check if the fixed size part of the packet is in buffer. */
92992559Sdes	if (buffer_len(b) < 12)
93060573Skris		return 0;
93157429Smarkm
93260573Skris	/* Parse the lengths of variable-length fields. */
93392559Sdes	ucp = buffer_ptr(b);
93460573Skris	if (ucp[0] == 0x42) {	/* Byte order MSB first. */
93560573Skris		proto_len = 256 * ucp[6] + ucp[7];
93660573Skris		data_len = 256 * ucp[8] + ucp[9];
93760573Skris	} else if (ucp[0] == 0x6c) {	/* Byte order LSB first. */
93860573Skris		proto_len = ucp[6] + 256 * ucp[7];
93960573Skris		data_len = ucp[8] + 256 * ucp[9];
94060573Skris	} else {
941124207Sdes		debug2("Initial X11 packet contains bad byte order byte: 0x%x",
94292559Sdes		    ucp[0]);
94360573Skris		return -1;
94460573Skris	}
94557429Smarkm
94660573Skris	/* Check if the whole packet is in buffer. */
94792559Sdes	if (buffer_len(b) <
94860573Skris	    12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
94960573Skris		return 0;
95057429Smarkm
95160573Skris	/* Check if authentication protocol matches. */
95260573Skris	if (proto_len != strlen(x11_saved_proto) ||
95360573Skris	    memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
954124207Sdes		debug2("X11 connection uses different authentication protocol.");
95560573Skris		return -1;
95660573Skris	}
95760573Skris	/* Check if authentication data matches our fake data. */
95860573Skris	if (data_len != x11_fake_data_len ||
959215116Sdes	    timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
96060573Skris		x11_fake_data, x11_fake_data_len) != 0) {
961124207Sdes		debug2("X11 auth data does not match fake data.");
96260573Skris		return -1;
96360573Skris	}
96460573Skris	/* Check fake data length */
96560573Skris	if (x11_fake_data_len != x11_saved_data_len) {
96660573Skris		error("X11 fake_data_len %d != saved_data_len %d",
96760573Skris		    x11_fake_data_len, x11_saved_data_len);
96860573Skris		return -1;
96960573Skris	}
97060573Skris	/*
97160573Skris	 * Received authentication protocol and data match
97260573Skris	 * our fake data. Substitute the fake data with real
97360573Skris	 * data.
97460573Skris	 */
97560573Skris	memcpy(ucp + 12 + ((proto_len + 3) & ~3),
97660573Skris	    x11_saved_data, x11_saved_data_len);
97760573Skris	return 1;
97860573Skris}
97957429Smarkm
98092559Sdesstatic void
981162856Sdeschannel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
98260573Skris{
98392559Sdes	int ret = x11_open_helper(&c->output);
984106130Sdes
98560573Skris	if (ret == 1) {
98660573Skris		/* Start normal processing for the channel. */
98760573Skris		c->type = SSH_CHANNEL_OPEN;
98860573Skris		channel_pre_open_13(c, readset, writeset);
98960573Skris	} else if (ret == -1) {
99060573Skris		/*
99160573Skris		 * We have received an X11 connection that has bad
99260573Skris		 * authentication information.
99360573Skris		 */
994124207Sdes		logit("X11 connection rejected because of wrong authentication.");
99560573Skris		buffer_clear(&c->input);
99660573Skris		buffer_clear(&c->output);
99792559Sdes		channel_close_fd(&c->sock);
99860573Skris		c->sock = -1;
99960573Skris		c->type = SSH_CHANNEL_CLOSED;
100060573Skris		packet_start(SSH_MSG_CHANNEL_CLOSE);
100160573Skris		packet_put_int(c->remote_id);
100260573Skris		packet_send();
100360573Skris	}
100460573Skris}
100557429Smarkm
100692559Sdesstatic void
1007162856Sdeschannel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
100860573Skris{
100992559Sdes	int ret = x11_open_helper(&c->output);
101092559Sdes
101192559Sdes	/* c->force_drain = 1; */
101292559Sdes
101360573Skris	if (ret == 1) {
101460573Skris		c->type = SSH_CHANNEL_OPEN;
101592559Sdes		channel_pre_open(c, readset, writeset);
101692559Sdes	} else if (ret == -1) {
1017124207Sdes		logit("X11 connection rejected because of wrong authentication.");
1018124207Sdes		debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
101992559Sdes		chan_read_failed(c);
102092559Sdes		buffer_clear(&c->input);
102192559Sdes		chan_ibuf_empty(c);
102292559Sdes		buffer_clear(&c->output);
102392559Sdes		/* for proto v1, the peer will send an IEOF */
102460573Skris		if (compat20)
102592559Sdes			chan_write_failed(c);
102660573Skris		else
102792559Sdes			c->type = SSH_CHANNEL_OPEN;
1028124207Sdes		debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
102960573Skris	}
103060573Skris}
103157429Smarkm
1032204917Sdesstatic void
1033204917Sdeschannel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1034204917Sdes{
1035215116Sdes	if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
1036204917Sdes	    buffer_check_alloc(&c->input, CHAN_RBUF))
1037204917Sdes		FD_SET(c->rfd, readset);
1038204917Sdes	if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
1039204917Sdes		/* clear buffer immediately (discard any partial packet) */
1040204917Sdes		buffer_clear(&c->input);
1041204917Sdes		chan_ibuf_empty(c);
1042204917Sdes		/* Start output drain. XXX just kill chan? */
1043204917Sdes		chan_rcvd_oclose(c);
1044204917Sdes	}
1045204917Sdes	if (c->ostate == CHAN_OUTPUT_OPEN ||
1046204917Sdes	    c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
1047204917Sdes		if (buffer_len(&c->output) > 0)
1048204917Sdes			FD_SET(c->wfd, writeset);
1049204917Sdes		else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
1050204917Sdes			chan_obuf_empty(c);
1051204917Sdes	}
1052204917Sdes}
1053204917Sdes
105476262Sgreen/* try to decode a socks4 header */
1055162856Sdes/* ARGSUSED */
105692559Sdesstatic int
1057162856Sdeschannel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
105876262Sgreen{
1059106130Sdes	char *p, *host;
1060192595Sdes	u_int len, have, i, found, need;
106192559Sdes	char username[256];
106276262Sgreen	struct {
106376262Sgreen		u_int8_t version;
106476262Sgreen		u_int8_t command;
106576262Sgreen		u_int16_t dest_port;
106676262Sgreen		struct in_addr dest_addr;
106776262Sgreen	} s4_req, s4_rsp;
106876262Sgreen
106976262Sgreen	debug2("channel %d: decode socks4", c->self);
107076262Sgreen
107176262Sgreen	have = buffer_len(&c->input);
107276262Sgreen	len = sizeof(s4_req);
107376262Sgreen	if (have < len)
107476262Sgreen		return 0;
1075295367Sdes	p = (char *)buffer_ptr(&c->input);
1076192595Sdes
1077192595Sdes	need = 1;
1078192595Sdes	/* SOCKS4A uses an invalid IP address 0.0.0.x */
1079192595Sdes	if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) {
1080192595Sdes		debug2("channel %d: socks4a request", c->self);
1081192595Sdes		/* ... and needs an extra string (the hostname) */
1082192595Sdes		need = 2;
1083192595Sdes	}
1084192595Sdes	/* Check for terminating NUL on the string(s) */
108576262Sgreen	for (found = 0, i = len; i < have; i++) {
108676262Sgreen		if (p[i] == '\0') {
1087192595Sdes			found++;
1088192595Sdes			if (found == need)
1089192595Sdes				break;
109076262Sgreen		}
109176262Sgreen		if (i > 1024) {
109276262Sgreen			/* the peer is probably sending garbage */
109376262Sgreen			debug("channel %d: decode socks4: too long",
109476262Sgreen			    c->self);
109576262Sgreen			return -1;
109676262Sgreen		}
109776262Sgreen	}
1098192595Sdes	if (found < need)
109976262Sgreen		return 0;
110076262Sgreen	buffer_get(&c->input, (char *)&s4_req.version, 1);
110176262Sgreen	buffer_get(&c->input, (char *)&s4_req.command, 1);
110276262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
110376262Sgreen	buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
110476262Sgreen	have = buffer_len(&c->input);
1105295367Sdes	p = (char *)buffer_ptr(&c->input);
1106264377Sdes	if (memchr(p, '\0', have) == NULL)
1107264377Sdes		fatal("channel %d: decode socks4: user not nul terminated",
1108264377Sdes		    c->self);
110976262Sgreen	len = strlen(p);
111076262Sgreen	debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
1111192595Sdes	len++;					/* trailing '\0' */
111276262Sgreen	if (len > have)
111376262Sgreen		fatal("channel %d: decode socks4: len %d > have %d",
111476262Sgreen		    c->self, len, have);
111576262Sgreen	strlcpy(username, p, sizeof(username));
111676262Sgreen	buffer_consume(&c->input, len);
111776262Sgreen
1118255767Sdes	free(c->path);
1119255767Sdes	c->path = NULL;
1120192595Sdes	if (need == 1) {			/* SOCKS4: one string */
1121192595Sdes		host = inet_ntoa(s4_req.dest_addr);
1122192595Sdes		c->path = xstrdup(host);
1123192595Sdes	} else {				/* SOCKS4A: two strings */
1124192595Sdes		have = buffer_len(&c->input);
1125295367Sdes		p = (char *)buffer_ptr(&c->input);
1126192595Sdes		len = strlen(p);
1127192595Sdes		debug2("channel %d: decode socks4a: host %s/%d",
1128192595Sdes		    c->self, p, len);
1129192595Sdes		len++;				/* trailing '\0' */
1130192595Sdes		if (len > have)
1131192595Sdes			fatal("channel %d: decode socks4a: len %d > have %d",
1132192595Sdes			    c->self, len, have);
1133192595Sdes		if (len > NI_MAXHOST) {
1134192595Sdes			error("channel %d: hostname \"%.100s\" too long",
1135192595Sdes			    c->self, p);
1136192595Sdes			return -1;
1137192595Sdes		}
1138192595Sdes		c->path = xstrdup(p);
1139192595Sdes		buffer_consume(&c->input, len);
1140192595Sdes	}
114176262Sgreen	c->host_port = ntohs(s4_req.dest_port);
114292559Sdes
1143124207Sdes	debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
1144192595Sdes	    c->self, c->path, c->host_port, s4_req.command);
114576262Sgreen
114676262Sgreen	if (s4_req.command != 1) {
1147192595Sdes		debug("channel %d: cannot handle: %s cn %d",
1148192595Sdes		    c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command);
114976262Sgreen		return -1;
115076262Sgreen	}
115176262Sgreen	s4_rsp.version = 0;			/* vn: 0 for reply */
115276262Sgreen	s4_rsp.command = 90;			/* cd: req granted */
115376262Sgreen	s4_rsp.dest_port = 0;			/* ignored */
115476262Sgreen	s4_rsp.dest_addr.s_addr = INADDR_ANY;	/* ignored */
1155162856Sdes	buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp));
115676262Sgreen	return 1;
115776262Sgreen}
115876262Sgreen
1159124207Sdes/* try to decode a socks5 header */
1160124207Sdes#define SSH_SOCKS5_AUTHDONE	0x1000
1161124207Sdes#define SSH_SOCKS5_NOAUTH	0x00
1162124207Sdes#define SSH_SOCKS5_IPV4		0x01
1163124207Sdes#define SSH_SOCKS5_DOMAIN	0x03
1164124207Sdes#define SSH_SOCKS5_IPV6		0x04
1165124207Sdes#define SSH_SOCKS5_CONNECT	0x01
1166124207Sdes#define SSH_SOCKS5_SUCCESS	0x00
1167124207Sdes
1168162856Sdes/* ARGSUSED */
1169124207Sdesstatic int
1170162856Sdeschannel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1171124207Sdes{
1172124207Sdes	struct {
1173124207Sdes		u_int8_t version;
1174124207Sdes		u_int8_t command;
1175124207Sdes		u_int8_t reserved;
1176124207Sdes		u_int8_t atyp;
1177124207Sdes	} s5_req, s5_rsp;
1178124207Sdes	u_int16_t dest_port;
1179255767Sdes	char dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
1180255767Sdes	u_char *p;
1181162856Sdes	u_int have, need, i, found, nmethods, addrlen, af;
1182124207Sdes
1183124207Sdes	debug2("channel %d: decode socks5", c->self);
1184124207Sdes	p = buffer_ptr(&c->input);
1185124207Sdes	if (p[0] != 0x05)
1186124207Sdes		return -1;
1187124207Sdes	have = buffer_len(&c->input);
1188124207Sdes	if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
1189124207Sdes		/* format: ver | nmethods | methods */
1190126273Sdes		if (have < 2)
1191124207Sdes			return 0;
1192124207Sdes		nmethods = p[1];
1193124207Sdes		if (have < nmethods + 2)
1194124207Sdes			return 0;
1195124207Sdes		/* look for method: "NO AUTHENTICATION REQUIRED" */
1196181111Sdes		for (found = 0, i = 2; i < nmethods + 2; i++) {
1197162856Sdes			if (p[i] == SSH_SOCKS5_NOAUTH) {
1198124207Sdes				found = 1;
1199124207Sdes				break;
1200124207Sdes			}
1201124207Sdes		}
1202124207Sdes		if (!found) {
1203124207Sdes			debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
1204124207Sdes			    c->self);
1205124207Sdes			return -1;
1206124207Sdes		}
1207124207Sdes		buffer_consume(&c->input, nmethods + 2);
1208124207Sdes		buffer_put_char(&c->output, 0x05);		/* version */
1209124207Sdes		buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH);	/* method */
1210124207Sdes		FD_SET(c->sock, writeset);
1211124207Sdes		c->flags |= SSH_SOCKS5_AUTHDONE;
1212124207Sdes		debug2("channel %d: socks5 auth done", c->self);
1213124207Sdes		return 0;				/* need more */
1214124207Sdes	}
1215124207Sdes	debug2("channel %d: socks5 post auth", c->self);
1216124207Sdes	if (have < sizeof(s5_req)+1)
1217124207Sdes		return 0;			/* need more */
1218162856Sdes	memcpy(&s5_req, p, sizeof(s5_req));
1219124207Sdes	if (s5_req.version != 0x05 ||
1220124207Sdes	    s5_req.command != SSH_SOCKS5_CONNECT ||
1221124207Sdes	    s5_req.reserved != 0x00) {
1222124207Sdes		debug2("channel %d: only socks5 connect supported", c->self);
1223124207Sdes		return -1;
1224124207Sdes	}
1225147005Sdes	switch (s5_req.atyp){
1226124207Sdes	case SSH_SOCKS5_IPV4:
1227124207Sdes		addrlen = 4;
1228124207Sdes		af = AF_INET;
1229124207Sdes		break;
1230124207Sdes	case SSH_SOCKS5_DOMAIN:
1231124207Sdes		addrlen = p[sizeof(s5_req)];
1232124207Sdes		af = -1;
1233124207Sdes		break;
1234124207Sdes	case SSH_SOCKS5_IPV6:
1235124207Sdes		addrlen = 16;
1236124207Sdes		af = AF_INET6;
1237124207Sdes		break;
1238124207Sdes	default:
1239124207Sdes		debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
1240124207Sdes		return -1;
1241124207Sdes	}
1242162856Sdes	need = sizeof(s5_req) + addrlen + 2;
1243162856Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1244162856Sdes		need++;
1245162856Sdes	if (have < need)
1246124207Sdes		return 0;
1247124207Sdes	buffer_consume(&c->input, sizeof(s5_req));
1248124207Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1249124207Sdes		buffer_consume(&c->input, 1);    /* host string length */
1250255767Sdes	buffer_get(&c->input, &dest_addr, addrlen);
1251124207Sdes	buffer_get(&c->input, (char *)&dest_port, 2);
1252124207Sdes	dest_addr[addrlen] = '\0';
1253255767Sdes	free(c->path);
1254255767Sdes	c->path = NULL;
1255192595Sdes	if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
1256192595Sdes		if (addrlen >= NI_MAXHOST) {
1257192595Sdes			error("channel %d: dynamic request: socks5 hostname "
1258192595Sdes			    "\"%.100s\" too long", c->self, dest_addr);
1259192595Sdes			return -1;
1260192595Sdes		}
1261192595Sdes		c->path = xstrdup(dest_addr);
1262192595Sdes	} else {
1263192595Sdes		if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL)
1264192595Sdes			return -1;
1265192595Sdes		c->path = xstrdup(ntop);
1266192595Sdes	}
1267124207Sdes	c->host_port = ntohs(dest_port);
1268126273Sdes
1269124207Sdes	debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
1270124207Sdes	    c->self, c->path, c->host_port, s5_req.command);
1271124207Sdes
1272124207Sdes	s5_rsp.version = 0x05;
1273124207Sdes	s5_rsp.command = SSH_SOCKS5_SUCCESS;
1274124207Sdes	s5_rsp.reserved = 0;			/* ignored */
1275124207Sdes	s5_rsp.atyp = SSH_SOCKS5_IPV4;
1276124207Sdes	dest_port = 0;				/* ignored */
1277124207Sdes
1278162856Sdes	buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
1279255767Sdes	buffer_put_int(&c->output, ntohl(INADDR_ANY)); /* bind address */
1280162856Sdes	buffer_append(&c->output, &dest_port, sizeof(dest_port));
1281124207Sdes	return 1;
1282124207Sdes}
1283124207Sdes
1284204917SdesChannel *
1285204917Sdeschannel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
1286204917Sdes    int in, int out)
1287204917Sdes{
1288204917Sdes	Channel *c;
1289204917Sdes
1290204917Sdes	debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
1291204917Sdes	    port_to_connect);
1292204917Sdes
1293204917Sdes	c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
1294204917Sdes	    -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
1295204917Sdes	    0, "stdio-forward", /*nonblock*/0);
1296204917Sdes
1297204917Sdes	c->path = xstrdup(host_to_connect);
1298204917Sdes	c->host_port = port_to_connect;
1299204917Sdes	c->listening_port = 0;
1300204917Sdes	c->force_drain = 1;
1301204917Sdes
1302204917Sdes	channel_register_fds(c, in, out, -1, 0, 1, 0);
1303204917Sdes	port_open_helper(c, "direct-tcpip");
1304204917Sdes
1305204917Sdes	return c;
1306204917Sdes}
1307204917Sdes
130876262Sgreen/* dynamic port forwarding */
130992559Sdesstatic void
1310162856Sdeschannel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
131176262Sgreen{
131276262Sgreen	u_char *p;
1313149753Sdes	u_int have;
1314149753Sdes	int ret;
131576262Sgreen
131676262Sgreen	have = buffer_len(&c->input);
131776262Sgreen	debug2("channel %d: pre_dynamic: have %d", c->self, have);
131876262Sgreen	/* buffer_dump(&c->input); */
131976262Sgreen	/* check if the fixed size part of the packet is in buffer. */
1320124207Sdes	if (have < 3) {
132176262Sgreen		/* need more */
132276262Sgreen		FD_SET(c->sock, readset);
132376262Sgreen		return;
132476262Sgreen	}
132576262Sgreen	/* try to guess the protocol */
132676262Sgreen	p = buffer_ptr(&c->input);
132776262Sgreen	switch (p[0]) {
132876262Sgreen	case 0x04:
132976262Sgreen		ret = channel_decode_socks4(c, readset, writeset);
133076262Sgreen		break;
1331124207Sdes	case 0x05:
1332124207Sdes		ret = channel_decode_socks5(c, readset, writeset);
1333124207Sdes		break;
133476262Sgreen	default:
133576262Sgreen		ret = -1;
133676262Sgreen		break;
133776262Sgreen	}
133876262Sgreen	if (ret < 0) {
133992559Sdes		chan_mark_dead(c);
134076262Sgreen	} else if (ret == 0) {
134176262Sgreen		debug2("channel %d: pre_dynamic: need more", c->self);
134276262Sgreen		/* need more */
134376262Sgreen		FD_SET(c->sock, readset);
134476262Sgreen	} else {
134576262Sgreen		/* switch to the next state */
134676262Sgreen		c->type = SSH_CHANNEL_OPENING;
134776262Sgreen		port_open_helper(c, "direct-tcpip");
134876262Sgreen	}
134976262Sgreen}
135076262Sgreen
135160573Skris/* This is our fake X11 server socket. */
1352162856Sdes/* ARGSUSED */
135392559Sdesstatic void
1354162856Sdeschannel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
135560573Skris{
135692559Sdes	Channel *nc;
1357181111Sdes	struct sockaddr_storage addr;
1358255767Sdes	int newsock, oerrno;
135960573Skris	socklen_t addrlen;
136076262Sgreen	char buf[16384], *remote_ipaddr;
136160573Skris	int remote_port;
136257429Smarkm
136360573Skris	if (FD_ISSET(c->sock, readset)) {
136460573Skris		debug("X11 connection requested.");
136560573Skris		addrlen = sizeof(addr);
1366181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
136792559Sdes		if (c->single_connection) {
1368255767Sdes			oerrno = errno;
1369124207Sdes			debug2("single_connection: closing X11 listener.");
137092559Sdes			channel_close_fd(&c->sock);
137192559Sdes			chan_mark_dead(c);
1372255767Sdes			errno = oerrno;
137392559Sdes		}
137460573Skris		if (newsock < 0) {
1375255767Sdes			if (errno != EINTR && errno != EWOULDBLOCK &&
1376255767Sdes			    errno != ECONNABORTED)
1377255767Sdes				error("accept: %.100s", strerror(errno));
1378240075Sdes			if (errno == EMFILE || errno == ENFILE)
1379255767Sdes				c->notbefore = monotime() + 1;
138060573Skris			return;
138160573Skris		}
138292559Sdes		set_nodelay(newsock);
138376262Sgreen		remote_ipaddr = get_peer_ipaddr(newsock);
138460573Skris		remote_port = get_peer_port(newsock);
138560573Skris		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
138676262Sgreen		    remote_ipaddr, remote_port);
138757429Smarkm
138892559Sdes		nc = channel_new("accepted x11 socket",
138960573Skris		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
1390124207Sdes		    c->local_window_max, c->local_maxpacket, 0, buf, 1);
139160573Skris		if (compat20) {
139260573Skris			packet_start(SSH2_MSG_CHANNEL_OPEN);
139360573Skris			packet_put_cstring("x11");
139492559Sdes			packet_put_int(nc->self);
139592559Sdes			packet_put_int(nc->local_window_max);
139692559Sdes			packet_put_int(nc->local_maxpacket);
139776262Sgreen			/* originator ipaddr and port */
139876262Sgreen			packet_put_cstring(remote_ipaddr);
139960573Skris			if (datafellows & SSH_BUG_X11FWD) {
1400124207Sdes				debug2("ssh2 x11 bug compat mode");
140157429Smarkm			} else {
140260573Skris				packet_put_int(remote_port);
140357429Smarkm			}
140460573Skris			packet_send();
140560573Skris		} else {
140660573Skris			packet_start(SSH_SMSG_X11_OPEN);
140792559Sdes			packet_put_int(nc->self);
140892559Sdes			if (packet_get_protocol_flags() &
140992559Sdes			    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
141092559Sdes				packet_put_cstring(buf);
141160573Skris			packet_send();
141257429Smarkm		}
1413255767Sdes		free(remote_ipaddr);
141457429Smarkm	}
141557429Smarkm}
141657429Smarkm
141792559Sdesstatic void
141876262Sgreenport_open_helper(Channel *c, char *rtype)
141976262Sgreen{
142076262Sgreen	char buf[1024];
1421262566Sdes	char *local_ipaddr = get_local_ipaddr(c->sock);
1422323124Sdes	int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock);
142376262Sgreen	char *remote_ipaddr = get_peer_ipaddr(c->sock);
1424149753Sdes	int remote_port = get_peer_port(c->sock);
142576262Sgreen
1426204917Sdes	if (remote_port == -1) {
1427204917Sdes		/* Fake addr/port to appease peers that validate it (Tectia) */
1428255767Sdes		free(remote_ipaddr);
1429204917Sdes		remote_ipaddr = xstrdup("127.0.0.1");
1430204917Sdes		remote_port = 65535;
1431204917Sdes	}
1432204917Sdes
143376262Sgreen	snprintf(buf, sizeof buf,
143476262Sgreen	    "%s: listening port %d for %.100s port %d, "
1435262566Sdes	    "connect from %.200s port %d to %.100s port %d",
143676262Sgreen	    rtype, c->listening_port, c->path, c->host_port,
1437262566Sdes	    remote_ipaddr, remote_port, local_ipaddr, local_port);
143876262Sgreen
1439255767Sdes	free(c->remote_name);
144076262Sgreen	c->remote_name = xstrdup(buf);
144176262Sgreen
144276262Sgreen	if (compat20) {
144376262Sgreen		packet_start(SSH2_MSG_CHANNEL_OPEN);
144476262Sgreen		packet_put_cstring(rtype);
144576262Sgreen		packet_put_int(c->self);
144676262Sgreen		packet_put_int(c->local_window_max);
144776262Sgreen		packet_put_int(c->local_maxpacket);
1448295367Sdes		if (strcmp(rtype, "direct-tcpip") == 0) {
144976262Sgreen			/* target host, port */
145076262Sgreen			packet_put_cstring(c->path);
145176262Sgreen			packet_put_int(c->host_port);
1452295367Sdes		} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
1453295367Sdes			/* target path */
1454295367Sdes			packet_put_cstring(c->path);
1455295367Sdes		} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1456295367Sdes			/* listen path */
1457295367Sdes			packet_put_cstring(c->path);
145876262Sgreen		} else {
145976262Sgreen			/* listen address, port */
146076262Sgreen			packet_put_cstring(c->path);
1461262566Sdes			packet_put_int(local_port);
146276262Sgreen		}
1463295367Sdes		if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1464295367Sdes			/* reserved for future owner/mode info */
1465295367Sdes			packet_put_cstring("");
1466295367Sdes		} else {
1467295367Sdes			/* originator host and port */
1468295367Sdes			packet_put_cstring(remote_ipaddr);
1469295367Sdes			packet_put_int((u_int)remote_port);
1470295367Sdes		}
147176262Sgreen		packet_send();
147276262Sgreen	} else {
147376262Sgreen		packet_start(SSH_MSG_PORT_OPEN);
147476262Sgreen		packet_put_int(c->self);
147576262Sgreen		packet_put_cstring(c->path);
147676262Sgreen		packet_put_int(c->host_port);
147792559Sdes		if (packet_get_protocol_flags() &
147892559Sdes		    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
147976262Sgreen			packet_put_cstring(c->remote_name);
148076262Sgreen		packet_send();
148176262Sgreen	}
1482255767Sdes	free(remote_ipaddr);
1483262566Sdes	free(local_ipaddr);
148476262Sgreen}
148576262Sgreen
1486157019Sdesstatic void
1487157019Sdeschannel_set_reuseaddr(int fd)
1488157019Sdes{
1489157019Sdes	int on = 1;
1490157019Sdes
1491157019Sdes	/*
1492157019Sdes	 * Set socket options.
1493157019Sdes	 * Allow local port reuse in TIME_WAIT.
1494157019Sdes	 */
1495157019Sdes	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1496157019Sdes		error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
1497157019Sdes}
1498157019Sdes
1499295367Sdesvoid
1500295367Sdeschannel_set_x11_refuse_time(u_int refuse_time)
1501295367Sdes{
1502295367Sdes	x11_refuse_time = refuse_time;
1503295367Sdes}
1504295367Sdes
150557429Smarkm/*
150660573Skris * This socket is listening for connections to a forwarded TCP/IP port.
150757429Smarkm */
1508162856Sdes/* ARGSUSED */
150992559Sdesstatic void
1510162856Sdeschannel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
151157429Smarkm{
151276262Sgreen	Channel *nc;
1513181111Sdes	struct sockaddr_storage addr;
151492559Sdes	int newsock, nextstate;
151557429Smarkm	socklen_t addrlen;
151676262Sgreen	char *rtype;
151757429Smarkm
151860573Skris	if (FD_ISSET(c->sock, readset)) {
151960573Skris		debug("Connection to port %d forwarding "
152060573Skris		    "to %.100s port %d requested.",
152160573Skris		    c->listening_port, c->path, c->host_port);
152276262Sgreen
152392559Sdes		if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
152492559Sdes			nextstate = SSH_CHANNEL_OPENING;
152592559Sdes			rtype = "forwarded-tcpip";
1526295367Sdes		} else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
1527295367Sdes			nextstate = SSH_CHANNEL_OPENING;
1528295367Sdes			rtype = "forwarded-streamlocal@openssh.com";
1529295367Sdes		} else if (c->host_port == PORT_STREAMLOCAL) {
1530295367Sdes			nextstate = SSH_CHANNEL_OPENING;
1531295367Sdes			rtype = "direct-streamlocal@openssh.com";
1532295367Sdes		} else if (c->host_port == 0) {
1533295367Sdes			nextstate = SSH_CHANNEL_DYNAMIC;
1534295367Sdes			rtype = "dynamic-tcpip";
153592559Sdes		} else {
1536295367Sdes			nextstate = SSH_CHANNEL_OPENING;
1537295367Sdes			rtype = "direct-tcpip";
153892559Sdes		}
153976262Sgreen
154060573Skris		addrlen = sizeof(addr);
1541181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
154260573Skris		if (newsock < 0) {
1543255767Sdes			if (errno != EINTR && errno != EWOULDBLOCK &&
1544255767Sdes			    errno != ECONNABORTED)
1545255767Sdes				error("accept: %.100s", strerror(errno));
1546240075Sdes			if (errno == EMFILE || errno == ENFILE)
1547255767Sdes				c->notbefore = monotime() + 1;
154860573Skris			return;
154960573Skris		}
1550295367Sdes		if (c->host_port != PORT_STREAMLOCAL)
1551295367Sdes			set_nodelay(newsock);
1552124207Sdes		nc = channel_new(rtype, nextstate, newsock, newsock, -1,
1553124207Sdes		    c->local_window_max, c->local_maxpacket, 0, rtype, 1);
155476262Sgreen		nc->listening_port = c->listening_port;
155576262Sgreen		nc->host_port = c->host_port;
1556192595Sdes		if (c->path != NULL)
1557192595Sdes			nc->path = xstrdup(c->path);
155876262Sgreen
1559204917Sdes		if (nextstate != SSH_CHANNEL_DYNAMIC)
156076262Sgreen			port_open_helper(nc, rtype);
156160573Skris	}
156260573Skris}
156357429Smarkm
156460573Skris/*
156560573Skris * This is the authentication agent socket listening for connections from
156660573Skris * clients.
156760573Skris */
1568162856Sdes/* ARGSUSED */
156992559Sdesstatic void
1570162856Sdeschannel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
157160573Skris{
157292559Sdes	Channel *nc;
157392559Sdes	int newsock;
1574181111Sdes	struct sockaddr_storage addr;
157560573Skris	socklen_t addrlen;
157657429Smarkm
157760573Skris	if (FD_ISSET(c->sock, readset)) {
157860573Skris		addrlen = sizeof(addr);
1579181111Sdes		newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
158060573Skris		if (newsock < 0) {
1581240075Sdes			error("accept from auth socket: %.100s",
1582240075Sdes			    strerror(errno));
1583240075Sdes			if (errno == EMFILE || errno == ENFILE)
1584255767Sdes				c->notbefore = monotime() + 1;
158560573Skris			return;
158660573Skris		}
158792559Sdes		nc = channel_new("accepted auth socket",
158876262Sgreen		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
158976262Sgreen		    c->local_window_max, c->local_maxpacket,
1590124207Sdes		    0, "accepted auth socket", 1);
159176262Sgreen		if (compat20) {
159276262Sgreen			packet_start(SSH2_MSG_CHANNEL_OPEN);
159376262Sgreen			packet_put_cstring("auth-agent@openssh.com");
159492559Sdes			packet_put_int(nc->self);
159576262Sgreen			packet_put_int(c->local_window_max);
159676262Sgreen			packet_put_int(c->local_maxpacket);
159776262Sgreen		} else {
159876262Sgreen			packet_start(SSH_SMSG_AGENT_OPEN);
159992559Sdes			packet_put_int(nc->self);
160076262Sgreen		}
160160573Skris		packet_send();
160260573Skris	}
160360573Skris}
160457429Smarkm
1605162856Sdes/* ARGSUSED */
160692559Sdesstatic void
1607162856Sdeschannel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
160876262Sgreen{
1609181111Sdes	int err = 0, sock;
161092559Sdes	socklen_t sz = sizeof(err);
161192559Sdes
161276262Sgreen	if (FD_ISSET(c->sock, writeset)) {
161392559Sdes		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
161492559Sdes			err = errno;
161592559Sdes			error("getsockopt SO_ERROR failed");
161692559Sdes		}
161792559Sdes		if (err == 0) {
1618181111Sdes			debug("channel %d: connected to %s port %d",
1619181111Sdes			    c->self, c->connect_ctx.host, c->connect_ctx.port);
1620181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
162192559Sdes			c->type = SSH_CHANNEL_OPEN;
162292559Sdes			if (compat20) {
162392559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
162492559Sdes				packet_put_int(c->remote_id);
162592559Sdes				packet_put_int(c->self);
162692559Sdes				packet_put_int(c->local_window);
162792559Sdes				packet_put_int(c->local_maxpacket);
162892559Sdes			} else {
162992559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
163092559Sdes				packet_put_int(c->remote_id);
163192559Sdes				packet_put_int(c->self);
163292559Sdes			}
163376262Sgreen		} else {
1634181111Sdes			debug("channel %d: connection failed: %s",
163592559Sdes			    c->self, strerror(err));
1636181111Sdes			/* Try next address, if any */
1637181111Sdes			if ((sock = connect_next(&c->connect_ctx)) > 0) {
1638181111Sdes				close(c->sock);
1639181111Sdes				c->sock = c->rfd = c->wfd = sock;
1640181111Sdes				channel_max_fd = channel_find_maxfd();
1641181111Sdes				return;
1642181111Sdes			}
1643181111Sdes			/* Exhausted all addresses */
1644181111Sdes			error("connect_to %.100s port %d: failed.",
1645181111Sdes			    c->connect_ctx.host, c->connect_ctx.port);
1646181111Sdes			channel_connect_ctx_free(&c->connect_ctx);
164792559Sdes			if (compat20) {
164892559Sdes				packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
164992559Sdes				packet_put_int(c->remote_id);
165092559Sdes				packet_put_int(SSH2_OPEN_CONNECT_FAILED);
165192559Sdes				if (!(datafellows & SSH_BUG_OPENFAILURE)) {
165292559Sdes					packet_put_cstring(strerror(err));
165392559Sdes					packet_put_cstring("");
165492559Sdes				}
165576262Sgreen			} else {
165692559Sdes				packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
165792559Sdes				packet_put_int(c->remote_id);
165876262Sgreen			}
165992559Sdes			chan_mark_dead(c);
166076262Sgreen		}
166192559Sdes		packet_send();
166276262Sgreen	}
166376262Sgreen}
166476262Sgreen
1665162856Sdes/* ARGSUSED */
166692559Sdesstatic int
1667162856Sdeschannel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
166860573Skris{
1669147005Sdes	char buf[CHAN_RBUF];
1670181111Sdes	int len, force;
167157429Smarkm
1672181111Sdes	force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
1673181111Sdes	if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
1674162856Sdes		errno = 0;
167560573Skris		len = read(c->rfd, buf, sizeof(buf));
1676181111Sdes		if (len < 0 && (errno == EINTR ||
1677181111Sdes		    ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
167860573Skris			return 1;
1679162856Sdes#ifndef PTY_ZEROREAD
168078827Sgreen		if (len <= 0) {
1681162856Sdes#else
1682162856Sdes		if ((!c->isatty && len <= 0) ||
1683162856Sdes		    (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
1684162856Sdes#endif
1685124207Sdes			debug2("channel %d: read<=0 rfd %d len %d",
168660573Skris			    c->self, c->rfd, len);
168776262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1688124207Sdes				debug2("channel %d: not open", c->self);
168992559Sdes				chan_mark_dead(c);
169076262Sgreen				return -1;
169176262Sgreen			} else if (compat13) {
169292559Sdes				buffer_clear(&c->output);
169360573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
1694124207Sdes				debug2("channel %d: input draining.", c->self);
169560573Skris			} else {
169660573Skris				chan_read_failed(c);
169757429Smarkm			}
169860573Skris			return -1;
169960573Skris		}
170092559Sdes		if (c->input_filter != NULL) {
170165668Skris			if (c->input_filter(c, buf, len) == -1) {
1702124207Sdes				debug2("channel %d: filter stops", c->self);
170365668Skris				chan_read_failed(c);
170465668Skris			}
1705157019Sdes		} else if (c->datagram) {
1706157019Sdes			buffer_put_string(&c->input, buf, len);
170765668Skris		} else {
170865668Skris			buffer_append(&c->input, buf, len);
170965668Skris		}
171060573Skris	}
171160573Skris	return 1;
171260573Skris}
1713162856Sdes
1714162856Sdes/* ARGSUSED */
171592559Sdesstatic int
1716162856Sdeschannel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
171760573Skris{
171876262Sgreen	struct termios tio;
1719157019Sdes	u_char *data = NULL, *buf;
1720215116Sdes	u_int dlen, olen = 0;
172160573Skris	int len;
172260573Skris
172360573Skris	/* Send buffered output data to the socket. */
172460573Skris	if (c->wfd != -1 &&
172560573Skris	    FD_ISSET(c->wfd, writeset) &&
172660573Skris	    buffer_len(&c->output) > 0) {
1727215116Sdes		olen = buffer_len(&c->output);
1728157019Sdes		if (c->output_filter != NULL) {
1729157019Sdes			if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1730157019Sdes				debug2("channel %d: filter stops", c->self);
1731157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1732157019Sdes					chan_mark_dead(c);
1733157019Sdes				else
1734157019Sdes					chan_write_failed(c);
1735157019Sdes				return -1;
1736157019Sdes			}
1737157019Sdes		} else if (c->datagram) {
1738157019Sdes			buf = data = buffer_get_string(&c->output, &dlen);
1739157019Sdes		} else {
1740157019Sdes			buf = data = buffer_ptr(&c->output);
1741157019Sdes			dlen = buffer_len(&c->output);
1742157019Sdes		}
1743157019Sdes
1744157019Sdes		if (c->datagram) {
1745157019Sdes			/* ignore truncated writes, datagrams might get lost */
1746157019Sdes			len = write(c->wfd, buf, dlen);
1747255767Sdes			free(data);
1748181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1749181111Sdes			    errno == EWOULDBLOCK))
1750157019Sdes				return 1;
1751157019Sdes			if (len <= 0) {
1752157019Sdes				if (c->type != SSH_CHANNEL_OPEN)
1753157019Sdes					chan_mark_dead(c);
1754157019Sdes				else
1755157019Sdes					chan_write_failed(c);
1756157019Sdes				return -1;
1757157019Sdes			}
1758215116Sdes			goto out;
1759157019Sdes		}
1760106130Sdes#ifdef _AIX
1761126273Sdes		/* XXX: Later AIX versions can't push as much data to tty */
1762126273Sdes		if (compat20 && c->wfd_isatty)
1763126273Sdes			dlen = MIN(dlen, 8*1024);
1764106130Sdes#endif
1765157019Sdes
1766157019Sdes		len = write(c->wfd, buf, dlen);
1767181111Sdes		if (len < 0 &&
1768181111Sdes		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
176960573Skris			return 1;
177060573Skris		if (len <= 0) {
177176262Sgreen			if (c->type != SSH_CHANNEL_OPEN) {
1772124207Sdes				debug2("channel %d: not open", c->self);
177392559Sdes				chan_mark_dead(c);
177476262Sgreen				return -1;
177576262Sgreen			} else if (compat13) {
177692559Sdes				buffer_clear(&c->output);
1777124207Sdes				debug2("channel %d: input draining.", c->self);
177860573Skris				c->type = SSH_CHANNEL_INPUT_DRAINING;
177960573Skris			} else {
178060573Skris				chan_write_failed(c);
178157429Smarkm			}
178260573Skris			return -1;
178360573Skris		}
1784197679Sdes#ifndef BROKEN_TCGETATTR_ICANON
1785157019Sdes		if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
178674500Sgreen			if (tcgetattr(c->wfd, &tio) == 0 &&
178774500Sgreen			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
178874500Sgreen				/*
178974500Sgreen				 * Simulate echo to reduce the impact of
179076262Sgreen				 * traffic analysis. We need to match the
179176262Sgreen				 * size of a SSH2_MSG_CHANNEL_DATA message
1792157019Sdes				 * (4 byte channel id + buf)
179374500Sgreen				 */
179476262Sgreen				packet_send_ignore(4 + len);
179574500Sgreen				packet_send();
179674500Sgreen			}
179774500Sgreen		}
1798197679Sdes#endif
179960573Skris		buffer_consume(&c->output, len);
180060573Skris	}
1801215116Sdes out:
1802215116Sdes	if (compat20 && olen > 0)
1803215116Sdes		c->local_consumed += olen - buffer_len(&c->output);
180460573Skris	return 1;
180560573Skris}
1806162856Sdes
180792559Sdesstatic int
1808162856Sdeschannel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
180960573Skris{
1810147005Sdes	char buf[CHAN_RBUF];
181160573Skris	int len;
181257429Smarkm
181360573Skris/** XXX handle drain efd, too */
181460573Skris	if (c->efd != -1) {
181560573Skris		if (c->extended_usage == CHAN_EXTENDED_WRITE &&
181660573Skris		    FD_ISSET(c->efd, writeset) &&
181760573Skris		    buffer_len(&c->extended) > 0) {
181860573Skris			len = write(c->efd, buffer_ptr(&c->extended),
181960573Skris			    buffer_len(&c->extended));
182069587Sgreen			debug2("channel %d: written %d to efd %d",
182160573Skris			    c->self, len, c->efd);
1822181111Sdes			if (len < 0 && (errno == EINTR || errno == EAGAIN ||
1823181111Sdes			    errno == EWOULDBLOCK))
182476262Sgreen				return 1;
182576262Sgreen			if (len <= 0) {
182676262Sgreen				debug2("channel %d: closing write-efd %d",
182776262Sgreen				    c->self, c->efd);
182892559Sdes				channel_close_fd(&c->efd);
182976262Sgreen			} else {
183060573Skris				buffer_consume(&c->extended, len);
183160573Skris				c->local_consumed += len;
183257429Smarkm			}
1833215116Sdes		} else if (c->efd != -1 &&
1834215116Sdes		    (c->extended_usage == CHAN_EXTENDED_READ ||
1835215116Sdes		    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
1836181111Sdes		    (c->detach_close || FD_ISSET(c->efd, readset))) {
183760573Skris			len = read(c->efd, buf, sizeof(buf));
183869587Sgreen			debug2("channel %d: read %d from efd %d",
183992559Sdes			    c->self, len, c->efd);
1840181111Sdes			if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
1841181111Sdes			    errno == EWOULDBLOCK) && !c->detach_close)))
184276262Sgreen				return 1;
184376262Sgreen			if (len <= 0) {
184476262Sgreen				debug2("channel %d: closing read-efd %d",
184560573Skris				    c->self, c->efd);
184692559Sdes				channel_close_fd(&c->efd);
184776262Sgreen			} else {
1848215116Sdes				if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
1849215116Sdes					debug3("channel %d: discard efd",
1850215116Sdes					    c->self);
1851215116Sdes				} else
1852215116Sdes					buffer_append(&c->extended, buf, len);
185376262Sgreen			}
185460573Skris		}
185560573Skris	}
185660573Skris	return 1;
185760573Skris}
1858162856Sdes
185992559Sdesstatic int
186076262Sgreenchannel_check_window(Channel *c)
186160573Skris{
186276262Sgreen	if (c->type == SSH_CHANNEL_OPEN &&
186376262Sgreen	    !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
1864181111Sdes	    ((c->local_window_max - c->local_window >
1865181111Sdes	    c->local_maxpacket*3) ||
1866181111Sdes	    c->local_window < c->local_window_max/2) &&
186760573Skris	    c->local_consumed > 0) {
186860573Skris		packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
186960573Skris		packet_put_int(c->remote_id);
1870294693Sdes		packet_put_int(c->local_consumed);
187160573Skris		packet_send();
187269587Sgreen		debug2("channel %d: window %d sent adjust %d",
187360573Skris		    c->self, c->local_window,
187460573Skris		    c->local_consumed);
1875294693Sdes		c->local_window += c->local_consumed;
187660573Skris		c->local_consumed = 0;
187760573Skris	}
187860573Skris	return 1;
187960573Skris}
188057429Smarkm
188192559Sdesstatic void
1882162856Sdeschannel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
188360573Skris{
188460573Skris	channel_handle_rfd(c, readset, writeset);
188560573Skris	channel_handle_wfd(c, readset, writeset);
188692559Sdes	if (!compat20)
188792559Sdes		return;
188860573Skris	channel_handle_efd(c, readset, writeset);
188976262Sgreen	channel_check_window(c);
189060573Skris}
189160573Skris
1892204917Sdesstatic u_int
1893204917Sdesread_mux(Channel *c, u_int need)
1894204917Sdes{
1895204917Sdes	char buf[CHAN_RBUF];
1896204917Sdes	int len;
1897204917Sdes	u_int rlen;
1898204917Sdes
1899204917Sdes	if (buffer_len(&c->input) < need) {
1900204917Sdes		rlen = need - buffer_len(&c->input);
1901204917Sdes		len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF));
1902296781Sdes		if (len < 0 && (errno == EINTR || errno == EAGAIN))
1903296781Sdes			return buffer_len(&c->input);
1904204917Sdes		if (len <= 0) {
1905296781Sdes			debug2("channel %d: ctl read<=0 rfd %d len %d",
1906296781Sdes			    c->self, c->rfd, len);
1907296781Sdes			chan_read_failed(c);
1908296781Sdes			return 0;
1909204917Sdes		} else
1910204917Sdes			buffer_append(&c->input, buf, len);
1911204917Sdes	}
1912204917Sdes	return buffer_len(&c->input);
1913204917Sdes}
1914204917Sdes
1915204917Sdesstatic void
1916204917Sdeschannel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1917204917Sdes{
1918204917Sdes	u_int need;
1919204917Sdes	ssize_t len;
1920204917Sdes
1921204917Sdes	if (!compat20)
1922204917Sdes		fatal("%s: entered with !compat20", __func__);
1923204917Sdes
1924215116Sdes	if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
1925204917Sdes	    (c->istate == CHAN_INPUT_OPEN ||
1926204917Sdes	    c->istate == CHAN_INPUT_WAIT_DRAIN)) {
1927204917Sdes		/*
1928204917Sdes		 * Don't not read past the precise end of packets to
1929204917Sdes		 * avoid disrupting fd passing.
1930204917Sdes		 */
1931204917Sdes		if (read_mux(c, 4) < 4) /* read header */
1932204917Sdes			return;
1933204917Sdes		need = get_u32(buffer_ptr(&c->input));
1934204917Sdes#define CHANNEL_MUX_MAX_PACKET	(256 * 1024)
1935204917Sdes		if (need > CHANNEL_MUX_MAX_PACKET) {
1936204917Sdes			debug2("channel %d: packet too big %u > %u",
1937204917Sdes			    c->self, CHANNEL_MUX_MAX_PACKET, need);
1938204917Sdes			chan_rcvd_oclose(c);
1939204917Sdes			return;
1940204917Sdes		}
1941204917Sdes		if (read_mux(c, need + 4) < need + 4) /* read body */
1942204917Sdes			return;
1943204917Sdes		if (c->mux_rcb(c) != 0) {
1944204917Sdes			debug("channel %d: mux_rcb failed", c->self);
1945204917Sdes			chan_mark_dead(c);
1946204917Sdes			return;
1947204917Sdes		}
1948204917Sdes	}
1949204917Sdes
1950204917Sdes	if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
1951204917Sdes	    buffer_len(&c->output) > 0) {
1952204917Sdes		len = write(c->wfd, buffer_ptr(&c->output),
1953204917Sdes		    buffer_len(&c->output));
1954204917Sdes		if (len < 0 && (errno == EINTR || errno == EAGAIN))
1955204917Sdes			return;
1956204917Sdes		if (len <= 0) {
1957204917Sdes			chan_mark_dead(c);
1958204917Sdes			return;
1959204917Sdes		}
1960204917Sdes		buffer_consume(&c->output, len);
1961204917Sdes	}
1962204917Sdes}
1963204917Sdes
1964204917Sdesstatic void
1965204917Sdeschannel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
1966204917Sdes{
1967204917Sdes	Channel *nc;
1968204917Sdes	struct sockaddr_storage addr;
1969204917Sdes	socklen_t addrlen;
1970204917Sdes	int newsock;
1971204917Sdes	uid_t euid;
1972204917Sdes	gid_t egid;
1973204917Sdes
1974204917Sdes	if (!FD_ISSET(c->sock, readset))
1975204917Sdes		return;
1976204917Sdes
1977204917Sdes	debug("multiplexing control connection");
1978204917Sdes
1979204917Sdes	/*
1980204917Sdes	 * Accept connection on control socket
1981204917Sdes	 */
1982204917Sdes	memset(&addr, 0, sizeof(addr));
1983204917Sdes	addrlen = sizeof(addr);
1984204917Sdes	if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
1985204917Sdes	    &addrlen)) == -1) {
1986204917Sdes		error("%s accept: %s", __func__, strerror(errno));
1987240075Sdes		if (errno == EMFILE || errno == ENFILE)
1988255767Sdes			c->notbefore = monotime() + 1;
1989204917Sdes		return;
1990204917Sdes	}
1991204917Sdes
1992204917Sdes	if (getpeereid(newsock, &euid, &egid) < 0) {
1993204917Sdes		error("%s getpeereid failed: %s", __func__,
1994204917Sdes		    strerror(errno));
1995204917Sdes		close(newsock);
1996204917Sdes		return;
1997204917Sdes	}
1998204917Sdes	if ((euid != 0) && (getuid() != euid)) {
1999204917Sdes		error("multiplex uid mismatch: peer euid %u != uid %u",
2000204917Sdes		    (u_int)euid, (u_int)getuid());
2001204917Sdes		close(newsock);
2002204917Sdes		return;
2003204917Sdes	}
2004204917Sdes	nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
2005204917Sdes	    newsock, newsock, -1, c->local_window_max,
2006204917Sdes	    c->local_maxpacket, 0, "mux-control", 1);
2007204917Sdes	nc->mux_rcb = c->mux_rcb;
2008204917Sdes	debug3("%s: new mux channel %d fd %d", __func__,
2009204917Sdes	    nc->self, nc->sock);
2010204917Sdes	/* establish state */
2011204917Sdes	nc->mux_rcb(nc);
2012204917Sdes	/* mux state transitions must not elicit protocol messages */
2013204917Sdes	nc->flags |= CHAN_LOCAL;
2014204917Sdes}
2015204917Sdes
2016162856Sdes/* ARGSUSED */
201792559Sdesstatic void
2018162856Sdeschannel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
201960573Skris{
202060573Skris	int len;
2021106130Sdes
202260573Skris	/* Send buffered output data to the socket. */
202360573Skris	if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
202460573Skris		len = write(c->sock, buffer_ptr(&c->output),
202560573Skris			    buffer_len(&c->output));
202660573Skris		if (len <= 0)
202792559Sdes			buffer_clear(&c->output);
202860573Skris		else
202960573Skris			buffer_consume(&c->output, len);
203060573Skris	}
203160573Skris}
203260573Skris
203392559Sdesstatic void
203460573Skrischannel_handler_init_20(void)
203560573Skris{
203692559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
203760573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
203860573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
203976262Sgreen	channel_pre[SSH_CHANNEL_RPORT_LISTENER] =	&channel_pre_listener;
2040295367Sdes	channel_pre[SSH_CHANNEL_UNIX_LISTENER] =	&channel_pre_listener;
2041295367Sdes	channel_pre[SSH_CHANNEL_RUNIX_LISTENER] =	&channel_pre_listener;
204260573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
204376262Sgreen	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
204476262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
204576262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
2046204917Sdes	channel_pre[SSH_CHANNEL_MUX_LISTENER] =		&channel_pre_listener;
2047204917Sdes	channel_pre[SSH_CHANNEL_MUX_CLIENT] =		&channel_pre_mux_client;
204860573Skris
204992559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
205060573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
205176262Sgreen	channel_post[SSH_CHANNEL_RPORT_LISTENER] =	&channel_post_port_listener;
2052295367Sdes	channel_post[SSH_CHANNEL_UNIX_LISTENER] =	&channel_post_port_listener;
2053295367Sdes	channel_post[SSH_CHANNEL_RUNIX_LISTENER] =	&channel_post_port_listener;
205460573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
205576262Sgreen	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
205676262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
205792559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
2058204917Sdes	channel_post[SSH_CHANNEL_MUX_LISTENER] =	&channel_post_mux_listener;
2059204917Sdes	channel_post[SSH_CHANNEL_MUX_CLIENT] =		&channel_post_mux_client;
206060573Skris}
206160573Skris
206292559Sdesstatic void
206360573Skrischannel_handler_init_13(void)
206460573Skris{
206560573Skris	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_13;
206660573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open_13;
206760573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
206860573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
206960573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
207060573Skris	channel_pre[SSH_CHANNEL_INPUT_DRAINING] =	&channel_pre_input_draining;
207160573Skris	channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_pre_output_draining;
207276262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
207376262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
207460573Skris
207592559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
207660573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
207760573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
207860573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
207960573Skris	channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =	&channel_post_output_drain_13;
208076262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
208192559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
208260573Skris}
208360573Skris
208492559Sdesstatic void
208560573Skrischannel_handler_init_15(void)
208660573Skris{
208792559Sdes	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open;
208860573Skris	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
208960573Skris	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
209060573Skris	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
209160573Skris	channel_pre[SSH_CHANNEL_AUTH_SOCKET] =		&channel_pre_listener;
209276262Sgreen	channel_pre[SSH_CHANNEL_CONNECTING] =		&channel_pre_connecting;
209376262Sgreen	channel_pre[SSH_CHANNEL_DYNAMIC] =		&channel_pre_dynamic;
209460573Skris
209560573Skris	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
209660573Skris	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
209760573Skris	channel_post[SSH_CHANNEL_AUTH_SOCKET] =		&channel_post_auth_listener;
209892559Sdes	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open;
209976262Sgreen	channel_post[SSH_CHANNEL_CONNECTING] =		&channel_post_connecting;
210092559Sdes	channel_post[SSH_CHANNEL_DYNAMIC] =		&channel_post_open;
210160573Skris}
210260573Skris
210392559Sdesstatic void
210460573Skrischannel_handler_init(void)
210560573Skris{
210660573Skris	int i;
2107106130Sdes
210892559Sdes	for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
210960573Skris		channel_pre[i] = NULL;
211060573Skris		channel_post[i] = NULL;
211160573Skris	}
211260573Skris	if (compat20)
211360573Skris		channel_handler_init_20();
211460573Skris	else if (compat13)
211560573Skris		channel_handler_init_13();
211660573Skris	else
211760573Skris		channel_handler_init_15();
211860573Skris}
211960573Skris
212092559Sdes/* gc dead channels */
212192559Sdesstatic void
212292559Sdeschannel_garbage_collect(Channel *c)
212392559Sdes{
212492559Sdes	if (c == NULL)
212592559Sdes		return;
212692559Sdes	if (c->detach_user != NULL) {
2127157019Sdes		if (!chan_is_dead(c, c->detach_close))
212892559Sdes			return;
2129124207Sdes		debug2("channel %d: gc: notify user", c->self);
213092559Sdes		c->detach_user(c->self, NULL);
213192559Sdes		/* if we still have a callback */
213292559Sdes		if (c->detach_user != NULL)
213392559Sdes			return;
2134124207Sdes		debug2("channel %d: gc: user detached", c->self);
213592559Sdes	}
213692559Sdes	if (!chan_is_dead(c, 1))
213792559Sdes		return;
2138124207Sdes	debug2("channel %d: garbage collecting", c->self);
213992559Sdes	channel_free(c);
214092559Sdes}
214192559Sdes
214292559Sdesstatic void
2143240075Sdeschannel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset,
2144240075Sdes    time_t *unpause_secs)
214560573Skris{
214660573Skris	static int did_init = 0;
2147204917Sdes	u_int i, oalloc;
214860573Skris	Channel *c;
2149240075Sdes	time_t now;
215060573Skris
215160573Skris	if (!did_init) {
215260573Skris		channel_handler_init();
215360573Skris		did_init = 1;
215460573Skris	}
2155255767Sdes	now = monotime();
2156240075Sdes	if (unpause_secs != NULL)
2157240075Sdes		*unpause_secs = 0;
2158204917Sdes	for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
215992559Sdes		c = channels[i];
216092559Sdes		if (c == NULL)
216157429Smarkm			continue;
2162204917Sdes		if (c->delayed) {
2163204917Sdes			if (ftab == channel_pre)
2164204917Sdes				c->delayed = 0;
2165204917Sdes			else
2166204917Sdes				continue;
2167204917Sdes		}
2168240075Sdes		if (ftab[c->type] != NULL) {
2169240075Sdes			/*
2170240075Sdes			 * Run handlers that are not paused.
2171240075Sdes			 */
2172240075Sdes			if (c->notbefore <= now)
2173240075Sdes				(*ftab[c->type])(c, readset, writeset);
2174240075Sdes			else if (unpause_secs != NULL) {
2175240075Sdes				/*
2176240075Sdes				 * Collect the time that the earliest
2177240075Sdes				 * channel comes off pause.
2178240075Sdes				 */
2179240075Sdes				debug3("%s: chan %d: skip for %d more seconds",
2180240075Sdes				    __func__, c->self,
2181240075Sdes				    (int)(c->notbefore - now));
2182240075Sdes				if (*unpause_secs == 0 ||
2183240075Sdes				    (c->notbefore - now) < *unpause_secs)
2184240075Sdes					*unpause_secs = c->notbefore - now;
2185240075Sdes			}
2186240075Sdes		}
218792559Sdes		channel_garbage_collect(c);
218857429Smarkm	}
2189240075Sdes	if (unpause_secs != NULL && *unpause_secs != 0)
2190240075Sdes		debug3("%s: first channel unpauses in %d seconds",
2191240075Sdes		    __func__, (int)*unpause_secs);
219257429Smarkm}
219357429Smarkm
219492559Sdes/*
219592559Sdes * Allocate/update select bitmasks and add any bits relevant to channels in
219692559Sdes * select bitmasks.
219792559Sdes */
219860573Skrisvoid
219976262Sgreenchannel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2200240075Sdes    u_int *nallocp, time_t *minwait_secs, int rekeying)
220160573Skris{
2202162856Sdes	u_int n, sz, nfdset;
220376262Sgreen
220476262Sgreen	n = MAX(*maxfdp, channel_max_fd);
220576262Sgreen
2206162856Sdes	nfdset = howmany(n+1, NFDBITS);
2207162856Sdes	/* Explicitly test here, because xrealloc isn't always called */
2208295367Sdes	if (nfdset && SIZE_MAX / nfdset < sizeof(fd_mask))
2209162856Sdes		fatal("channel_prepare_select: max_fd (%d) is too large", n);
2210162856Sdes	sz = nfdset * sizeof(fd_mask);
2211162856Sdes
221292559Sdes	/* perhaps check sz < nalloc/2 and shrink? */
221392559Sdes	if (*readsetp == NULL || sz > *nallocp) {
2214295367Sdes		*readsetp = xreallocarray(*readsetp, nfdset, sizeof(fd_mask));
2215295367Sdes		*writesetp = xreallocarray(*writesetp, nfdset, sizeof(fd_mask));
221692559Sdes		*nallocp = sz;
221776262Sgreen	}
221892559Sdes	*maxfdp = n;
221976262Sgreen	memset(*readsetp, 0, sz);
222076262Sgreen	memset(*writesetp, 0, sz);
222176262Sgreen
222276262Sgreen	if (!rekeying)
2223240075Sdes		channel_handler(channel_pre, *readsetp, *writesetp,
2224240075Sdes		    minwait_secs);
222560573Skris}
222660573Skris
222792559Sdes/*
222892559Sdes * After select, perform any appropriate operations for channels which have
222992559Sdes * events pending.
223092559Sdes */
223160573Skrisvoid
2232162856Sdeschannel_after_select(fd_set *readset, fd_set *writeset)
223360573Skris{
2234240075Sdes	channel_handler(channel_post, readset, writeset, NULL);
223560573Skris}
223660573Skris
223792559Sdes
223876262Sgreen/* If there is data to send to the connection, enqueue some of it now. */
223960573Skrisvoid
224092559Sdeschannel_output_poll(void)
224157429Smarkm{
224260573Skris	Channel *c;
2243137019Sdes	u_int i, len;
224457429Smarkm
224557429Smarkm	for (i = 0; i < channels_alloc; i++) {
224692559Sdes		c = channels[i];
224792559Sdes		if (c == NULL)
224892559Sdes			continue;
224957429Smarkm
225092559Sdes		/*
225192559Sdes		 * We are only interested in channels that can have buffered
225292559Sdes		 * incoming data.
225392559Sdes		 */
225457429Smarkm		if (compat13) {
225560573Skris			if (c->type != SSH_CHANNEL_OPEN &&
225660573Skris			    c->type != SSH_CHANNEL_INPUT_DRAINING)
225757429Smarkm				continue;
225857429Smarkm		} else {
225960573Skris			if (c->type != SSH_CHANNEL_OPEN)
226057429Smarkm				continue;
226157429Smarkm		}
226260573Skris		if (compat20 &&
226360573Skris		    (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
226476262Sgreen			/* XXX is this true? */
226592559Sdes			debug3("channel %d: will not send data after close", c->self);
226660573Skris			continue;
226760573Skris		}
226857429Smarkm
226957429Smarkm		/* Get the amount of buffered data for this channel. */
227076262Sgreen		if ((c->istate == CHAN_INPUT_OPEN ||
227176262Sgreen		    c->istate == CHAN_INPUT_WAIT_DRAIN) &&
227276262Sgreen		    (len = buffer_len(&c->input)) > 0) {
2273157019Sdes			if (c->datagram) {
2274157019Sdes				if (len > 0) {
2275157019Sdes					u_char *data;
2276157019Sdes					u_int dlen;
2277157019Sdes
2278157019Sdes					data = buffer_get_string(&c->input,
2279157019Sdes					    &dlen);
2280215116Sdes					if (dlen > c->remote_window ||
2281215116Sdes					    dlen > c->remote_maxpacket) {
2282215116Sdes						debug("channel %d: datagram "
2283215116Sdes						    "too big for channel",
2284215116Sdes						    c->self);
2285255767Sdes						free(data);
2286215116Sdes						continue;
2287215116Sdes					}
2288157019Sdes					packet_start(SSH2_MSG_CHANNEL_DATA);
2289157019Sdes					packet_put_int(c->remote_id);
2290157019Sdes					packet_put_string(data, dlen);
2291157019Sdes					packet_send();
2292295367Sdes					c->remote_window -= dlen;
2293255767Sdes					free(data);
2294157019Sdes				}
2295157019Sdes				continue;
2296157019Sdes			}
229792559Sdes			/*
229892559Sdes			 * Send some data for the other side over the secure
229992559Sdes			 * connection.
230092559Sdes			 */
230160573Skris			if (compat20) {
230260573Skris				if (len > c->remote_window)
230360573Skris					len = c->remote_window;
230460573Skris				if (len > c->remote_maxpacket)
230560573Skris					len = c->remote_maxpacket;
230657429Smarkm			} else {
230760573Skris				if (packet_is_interactive()) {
230860573Skris					if (len > 1024)
230960573Skris						len = 512;
231060573Skris				} else {
231160573Skris					/* Keep the packets at reasonable size. */
231260573Skris					if (len > packet_get_maxsize()/2)
231360573Skris						len = packet_get_maxsize()/2;
231460573Skris				}
231557429Smarkm			}
231660573Skris			if (len > 0) {
231760573Skris				packet_start(compat20 ?
231860573Skris				    SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
231960573Skris				packet_put_int(c->remote_id);
232060573Skris				packet_put_string(buffer_ptr(&c->input), len);
232160573Skris				packet_send();
232260573Skris				buffer_consume(&c->input, len);
232360573Skris				c->remote_window -= len;
232460573Skris			}
232560573Skris		} else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
232657429Smarkm			if (compat13)
232757429Smarkm				fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
232857429Smarkm			/*
232957429Smarkm			 * input-buffer is empty and read-socket shutdown:
233098684Sdes			 * tell peer, that we will not send more data: send IEOF.
233198684Sdes			 * hack for extended data: delay EOF if EFD still in use.
233257429Smarkm			 */
233398684Sdes			if (CHANNEL_EFD_INPUT_ACTIVE(c))
2334149753Sdes				debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
2335149753Sdes				    c->self, c->efd, buffer_len(&c->extended));
233698684Sdes			else
233798684Sdes				chan_ibuf_empty(c);
233857429Smarkm		}
233960573Skris		/* Send extended data, i.e. stderr */
234060573Skris		if (compat20 &&
234198684Sdes		    !(c->flags & CHAN_EOF_SENT) &&
234260573Skris		    c->remote_window > 0 &&
234360573Skris		    (len = buffer_len(&c->extended)) > 0 &&
234460573Skris		    c->extended_usage == CHAN_EXTENDED_READ) {
234599063Sdes			debug2("channel %d: rwin %u elen %u euse %d",
234676262Sgreen			    c->self, c->remote_window, buffer_len(&c->extended),
234776262Sgreen			    c->extended_usage);
234860573Skris			if (len > c->remote_window)
234960573Skris				len = c->remote_window;
235060573Skris			if (len > c->remote_maxpacket)
235160573Skris				len = c->remote_maxpacket;
235260573Skris			packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
235360573Skris			packet_put_int(c->remote_id);
235460573Skris			packet_put_int(SSH2_EXTENDED_DATA_STDERR);
235560573Skris			packet_put_string(buffer_ptr(&c->extended), len);
235660573Skris			packet_send();
235760573Skris			buffer_consume(&c->extended, len);
235860573Skris			c->remote_window -= len;
235976262Sgreen			debug2("channel %d: sent ext data %d", c->self, len);
236060573Skris		}
236157429Smarkm	}
236257429Smarkm}
236357429Smarkm
236457429Smarkm
236592559Sdes/* -- protocol input */
236692559Sdes
2367162856Sdes/* ARGSUSED */
2368295367Sdesint
236992559Sdeschannel_input_data(int type, u_int32_t seq, void *ctxt)
237057429Smarkm{
237157429Smarkm	int id;
2372295367Sdes	const u_char *data;
2373215116Sdes	u_int data_len, win_len;
237460573Skris	Channel *c;
237557429Smarkm
237657429Smarkm	/* Get the channel number and verify it. */
237757429Smarkm	id = packet_get_int();
237860573Skris	c = channel_lookup(id);
237960573Skris	if (c == NULL)
238057429Smarkm		packet_disconnect("Received data for nonexistent channel %d.", id);
238157429Smarkm
238257429Smarkm	/* Ignore any data for non-open channels (might happen on close) */
238360573Skris	if (c->type != SSH_CHANNEL_OPEN &&
238460573Skris	    c->type != SSH_CHANNEL_X11_OPEN)
2385295367Sdes		return 0;
238657429Smarkm
238757429Smarkm	/* Get the data. */
2388181111Sdes	data = packet_get_string_ptr(&data_len);
2389215116Sdes	win_len = data_len;
2390215116Sdes	if (c->datagram)
2391215116Sdes		win_len += 4;  /* string length header */
239260573Skris
2393126273Sdes	/*
2394126273Sdes	 * Ignore data for protocol > 1.3 if output end is no longer open.
2395126273Sdes	 * For protocol 2 the sending side is reducing its window as it sends
2396126273Sdes	 * data, so we must 'fake' consumption of the data in order to ensure
2397126273Sdes	 * that window updates are sent back.  Otherwise the connection might
2398126273Sdes	 * deadlock.
2399126273Sdes	 */
2400126273Sdes	if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
2401126273Sdes		if (compat20) {
2402215116Sdes			c->local_window -= win_len;
2403215116Sdes			c->local_consumed += win_len;
2404126273Sdes		}
2405295367Sdes		return 0;
2406126273Sdes	}
2407126273Sdes
240892559Sdes	if (compat20) {
2409215116Sdes		if (win_len > c->local_maxpacket) {
2410124207Sdes			logit("channel %d: rcvd big packet %d, maxpack %d",
2411215116Sdes			    c->self, win_len, c->local_maxpacket);
241260573Skris		}
2413215116Sdes		if (win_len > c->local_window) {
2414124207Sdes			logit("channel %d: rcvd too much data %d, win %d",
2415215116Sdes			    c->self, win_len, c->local_window);
2416295367Sdes			return 0;
241760573Skris		}
2418215116Sdes		c->local_window -= win_len;
241960573Skris	}
2420157019Sdes	if (c->datagram)
2421157019Sdes		buffer_put_string(&c->output, data, data_len);
2422157019Sdes	else
2423157019Sdes		buffer_append(&c->output, data, data_len);
2424181111Sdes	packet_check_eom();
2425295367Sdes	return 0;
242657429Smarkm}
242792559Sdes
2428162856Sdes/* ARGSUSED */
2429295367Sdesint
243092559Sdeschannel_input_extended_data(int type, u_int32_t seq, void *ctxt)
243160573Skris{
243260573Skris	int id;
243360573Skris	char *data;
243499063Sdes	u_int data_len, tcode;
243560573Skris	Channel *c;
243657429Smarkm
243760573Skris	/* Get the channel number and verify it. */
243860573Skris	id = packet_get_int();
243960573Skris	c = channel_lookup(id);
244060573Skris
244160573Skris	if (c == NULL)
244260573Skris		packet_disconnect("Received extended_data for bad channel %d.", id);
244360573Skris	if (c->type != SSH_CHANNEL_OPEN) {
2444124207Sdes		logit("channel %d: ext data for non open", id);
2445295367Sdes		return 0;
244660573Skris	}
244798684Sdes	if (c->flags & CHAN_EOF_RCVD) {
244898684Sdes		if (datafellows & SSH_BUG_EXTEOF)
244998684Sdes			debug("channel %d: accepting ext data after eof", id);
245098684Sdes		else
245198684Sdes			packet_disconnect("Received extended_data after EOF "
245298684Sdes			    "on channel %d.", id);
245398684Sdes	}
245460573Skris	tcode = packet_get_int();
245560573Skris	if (c->efd == -1 ||
245660573Skris	    c->extended_usage != CHAN_EXTENDED_WRITE ||
245760573Skris	    tcode != SSH2_EXTENDED_DATA_STDERR) {
2458124207Sdes		logit("channel %d: bad ext data", c->self);
2459295367Sdes		return 0;
246060573Skris	}
246160573Skris	data = packet_get_string(&data_len);
246292559Sdes	packet_check_eom();
246360573Skris	if (data_len > c->local_window) {
2464124207Sdes		logit("channel %d: rcvd too much extended_data %d, win %d",
246560573Skris		    c->self, data_len, c->local_window);
2466255767Sdes		free(data);
2467295367Sdes		return 0;
246860573Skris	}
246969587Sgreen	debug2("channel %d: rcvd ext data %d", c->self, data_len);
247060573Skris	c->local_window -= data_len;
247160573Skris	buffer_append(&c->extended, data, data_len);
2472255767Sdes	free(data);
2473295367Sdes	return 0;
247460573Skris}
247560573Skris
2476162856Sdes/* ARGSUSED */
2477295367Sdesint
247892559Sdeschannel_input_ieof(int type, u_int32_t seq, void *ctxt)
247960573Skris{
248060573Skris	int id;
248160573Skris	Channel *c;
248257429Smarkm
248360573Skris	id = packet_get_int();
248492559Sdes	packet_check_eom();
248560573Skris	c = channel_lookup(id);
248660573Skris	if (c == NULL)
248760573Skris		packet_disconnect("Received ieof for nonexistent channel %d.", id);
248860573Skris	chan_rcvd_ieof(c);
248992559Sdes
249092559Sdes	/* XXX force input close */
249192559Sdes	if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
249292559Sdes		debug("channel %d: FORCE input drain", c->self);
249392559Sdes		c->istate = CHAN_INPUT_WAIT_DRAIN;
249492559Sdes		if (buffer_len(&c->input) == 0)
249592559Sdes			chan_ibuf_empty(c);
249692559Sdes	}
2497295367Sdes	return 0;
249860573Skris}
249960573Skris
2500162856Sdes/* ARGSUSED */
2501295367Sdesint
250292559Sdeschannel_input_close(int type, u_int32_t seq, void *ctxt)
250357429Smarkm{
250460573Skris	int id;
250560573Skris	Channel *c;
250657429Smarkm
250760573Skris	id = packet_get_int();
250892559Sdes	packet_check_eom();
250960573Skris	c = channel_lookup(id);
251060573Skris	if (c == NULL)
251160573Skris		packet_disconnect("Received close for nonexistent channel %d.", id);
251257429Smarkm
251357429Smarkm	/*
251457429Smarkm	 * Send a confirmation that we have closed the channel and no more
251557429Smarkm	 * data is coming for it.
251657429Smarkm	 */
251757429Smarkm	packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
251860573Skris	packet_put_int(c->remote_id);
251957429Smarkm	packet_send();
252057429Smarkm
252157429Smarkm	/*
252257429Smarkm	 * If the channel is in closed state, we have sent a close request,
252357429Smarkm	 * and the other side will eventually respond with a confirmation.
252457429Smarkm	 * Thus, we cannot free the channel here, because then there would be
252557429Smarkm	 * no-one to receive the confirmation.  The channel gets freed when
252657429Smarkm	 * the confirmation arrives.
252757429Smarkm	 */
252860573Skris	if (c->type != SSH_CHANNEL_CLOSED) {
252957429Smarkm		/*
253057429Smarkm		 * Not a closed channel - mark it as draining, which will
253157429Smarkm		 * cause it to be freed later.
253257429Smarkm		 */
253392559Sdes		buffer_clear(&c->input);
253460573Skris		c->type = SSH_CHANNEL_OUTPUT_DRAINING;
253557429Smarkm	}
2536295367Sdes	return 0;
253757429Smarkm}
253857429Smarkm
253960573Skris/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
2540162856Sdes/* ARGSUSED */
2541295367Sdesint
254292559Sdeschannel_input_oclose(int type, u_int32_t seq, void *ctxt)
254360573Skris{
254460573Skris	int id = packet_get_int();
254560573Skris	Channel *c = channel_lookup(id);
254692559Sdes
254792559Sdes	packet_check_eom();
254860573Skris	if (c == NULL)
254960573Skris		packet_disconnect("Received oclose for nonexistent channel %d.", id);
255060573Skris	chan_rcvd_oclose(c);
2551295367Sdes	return 0;
255260573Skris}
255357429Smarkm
2554162856Sdes/* ARGSUSED */
2555295367Sdesint
255692559Sdeschannel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
255757429Smarkm{
255860573Skris	int id = packet_get_int();
255960573Skris	Channel *c = channel_lookup(id);
256057429Smarkm
256192559Sdes	packet_check_eom();
256260573Skris	if (c == NULL)
256360573Skris		packet_disconnect("Received close confirmation for "
256460573Skris		    "out-of-range channel %d.", id);
2565255767Sdes	if (c->type != SSH_CHANNEL_CLOSED && c->type != SSH_CHANNEL_ABANDONED)
256660573Skris		packet_disconnect("Received close confirmation for "
256760573Skris		    "non-closed channel %d (type %d).", id, c->type);
256892559Sdes	channel_free(c);
2569295367Sdes	return 0;
257060573Skris}
257157429Smarkm
2572162856Sdes/* ARGSUSED */
2573295367Sdesint
257492559Sdeschannel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
257560573Skris{
257660573Skris	int id, remote_id;
257760573Skris	Channel *c;
257860573Skris
257960573Skris	id = packet_get_int();
258060573Skris	c = channel_lookup(id);
258160573Skris
258260573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
258360573Skris		packet_disconnect("Received open confirmation for "
258460573Skris		    "non-opening channel %d.", id);
258560573Skris	remote_id = packet_get_int();
258660573Skris	/* Record the remote channel number and mark that the channel is now open. */
258760573Skris	c->remote_id = remote_id;
258860573Skris	c->type = SSH_CHANNEL_OPEN;
258960573Skris
259060573Skris	if (compat20) {
259160573Skris		c->remote_window = packet_get_int();
259260573Skris		c->remote_maxpacket = packet_get_int();
2593181111Sdes		if (c->open_confirm) {
259469587Sgreen			debug2("callback start");
2595215116Sdes			c->open_confirm(c->self, 1, c->open_confirm_ctx);
259669587Sgreen			debug2("callback done");
259760573Skris		}
2598124207Sdes		debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
259960573Skris		    c->remote_window, c->remote_maxpacket);
260057429Smarkm	}
260192559Sdes	packet_check_eom();
2602295367Sdes	return 0;
260357429Smarkm}
260457429Smarkm
260592559Sdesstatic char *
260692559Sdesreason2txt(int reason)
260792559Sdes{
260892559Sdes	switch (reason) {
260992559Sdes	case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED:
261092559Sdes		return "administratively prohibited";
261192559Sdes	case SSH2_OPEN_CONNECT_FAILED:
261292559Sdes		return "connect failed";
261392559Sdes	case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE:
261492559Sdes		return "unknown channel type";
261592559Sdes	case SSH2_OPEN_RESOURCE_SHORTAGE:
261692559Sdes		return "resource shortage";
261792559Sdes	}
261892559Sdes	return "unknown reason";
261992559Sdes}
262092559Sdes
2621162856Sdes/* ARGSUSED */
2622295367Sdesint
262392559Sdeschannel_input_open_failure(int type, u_int32_t seq, void *ctxt)
262457429Smarkm{
262576262Sgreen	int id, reason;
262676262Sgreen	char *msg = NULL, *lang = NULL;
262760573Skris	Channel *c;
262857429Smarkm
262960573Skris	id = packet_get_int();
263060573Skris	c = channel_lookup(id);
263157429Smarkm
263260573Skris	if (c==NULL || c->type != SSH_CHANNEL_OPENING)
263360573Skris		packet_disconnect("Received open failure for "
263460573Skris		    "non-opening channel %d.", id);
263560573Skris	if (compat20) {
263676262Sgreen		reason = packet_get_int();
263792559Sdes		if (!(datafellows & SSH_BUG_OPENFAILURE)) {
263876262Sgreen			msg  = packet_get_string(NULL);
263976262Sgreen			lang = packet_get_string(NULL);
264076262Sgreen		}
2641124207Sdes		logit("channel %d: open failed: %s%s%s", id,
264292559Sdes		    reason2txt(reason), msg ? ": ": "", msg ? msg : "");
2643255767Sdes		free(msg);
2644255767Sdes		free(lang);
2645215116Sdes		if (c->open_confirm) {
2646215116Sdes			debug2("callback start");
2647215116Sdes			c->open_confirm(c->self, 0, c->open_confirm_ctx);
2648215116Sdes			debug2("callback done");
2649215116Sdes		}
265060573Skris	}
265192559Sdes	packet_check_eom();
2652192595Sdes	/* Schedule the channel for cleanup/deletion. */
2653192595Sdes	chan_mark_dead(c);
2654295367Sdes	return 0;
265557429Smarkm}
265657429Smarkm
2657162856Sdes/* ARGSUSED */
2658295367Sdesint
265992559Sdeschannel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
266060573Skris{
266160573Skris	Channel *c;
266299063Sdes	int id;
2663295367Sdes	u_int adjust, tmp;
266457429Smarkm
266560573Skris	if (!compat20)
2666295367Sdes		return 0;
266760573Skris
266857429Smarkm	/* Get the channel number and verify it. */
266960573Skris	id = packet_get_int();
267060573Skris	c = channel_lookup(id);
267157429Smarkm
2672157019Sdes	if (c == NULL) {
2673157019Sdes		logit("Received window adjust for non-open channel %d.", id);
2674295367Sdes		return 0;
267560573Skris	}
267660573Skris	adjust = packet_get_int();
267792559Sdes	packet_check_eom();
267899063Sdes	debug2("channel %d: rcvd adjust %u", id, adjust);
2679295367Sdes	if ((tmp = c->remote_window + adjust) < c->remote_window)
2680295367Sdes		fatal("channel %d: adjust %u overflows remote window %u",
2681295367Sdes		    id, adjust, c->remote_window);
2682295367Sdes	c->remote_window = tmp;
2683295367Sdes	return 0;
268457429Smarkm}
268557429Smarkm
2686162856Sdes/* ARGSUSED */
2687295367Sdesint
268892559Sdeschannel_input_port_open(int type, u_int32_t seq, void *ctxt)
268957429Smarkm{
269092559Sdes	Channel *c = NULL;
269192559Sdes	u_short host_port;
269292559Sdes	char *host, *originator_string;
2693181111Sdes	int remote_id;
269457429Smarkm
269592559Sdes	remote_id = packet_get_int();
269692559Sdes	host = packet_get_string(NULL);
269792559Sdes	host_port = packet_get_int();
269857429Smarkm
269992559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
270092559Sdes		originator_string = packet_get_string(NULL);
270192559Sdes	} else {
270292559Sdes		originator_string = xstrdup("unknown (remote did not supply name)");
270392559Sdes	}
270492559Sdes	packet_check_eom();
2705295367Sdes	c = channel_connect_to_port(host, host_port,
2706181111Sdes	    "connected socket", originator_string);
2707255767Sdes	free(originator_string);
2708255767Sdes	free(host);
270992559Sdes	if (c == NULL) {
271092559Sdes		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
271192559Sdes		packet_put_int(remote_id);
271292559Sdes		packet_send();
2713181111Sdes	} else
2714181111Sdes		c->remote_id = remote_id;
2715295367Sdes	return 0;
271657429Smarkm}
271757429Smarkm
2718181111Sdes/* ARGSUSED */
2719295367Sdesint
2720181111Sdeschannel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
2721181111Sdes{
2722181111Sdes	Channel *c;
2723181111Sdes	struct channel_confirm *cc;
2724192595Sdes	int id;
272557429Smarkm
2726181111Sdes	/* Reset keepalive timeout */
2727197679Sdes	packet_set_alive_timeouts(0);
2728181111Sdes
2729192595Sdes	id = packet_get_int();
2730181111Sdes	packet_check_eom();
2731181111Sdes
2732192595Sdes	debug2("channel_input_status_confirm: type %d id %d", type, id);
2733181111Sdes
2734192595Sdes	if ((c = channel_lookup(id)) == NULL) {
2735192595Sdes		logit("channel_input_status_confirm: %d: unknown", id);
2736295367Sdes		return 0;
2737181111Sdes	}
2738181111Sdes	if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
2739295367Sdes		return 0;
2740181111Sdes	cc->cb(type, c, cc->ctx);
2741181111Sdes	TAILQ_REMOVE(&c->status_confirms, cc, entry);
2742264377Sdes	explicit_bzero(cc, sizeof(*cc));
2743255767Sdes	free(cc);
2744295367Sdes	return 0;
2745181111Sdes}
2746181111Sdes
274792559Sdes/* -- tcp forwarding */
274857429Smarkm
274992559Sdesvoid
275092559Sdeschannel_set_af(int af)
275176262Sgreen{
275292559Sdes	IPv4or6 = af;
275376262Sgreen}
275476262Sgreen
2755224638Sbrooks
2756240075Sdes/*
2757240075Sdes * Determine whether or not a port forward listens to loopback, the
2758240075Sdes * specified address or wildcard. On the client, a specified bind
2759240075Sdes * address will always override gateway_ports. On the server, a
2760240075Sdes * gateway_ports of 1 (``yes'') will override the client's specification
2761240075Sdes * and force a wildcard bind, whereas a value of 2 (``clientspecified'')
2762240075Sdes * will bind to whatever address the client asked for.
2763240075Sdes *
2764240075Sdes * Special-case listen_addrs are:
2765240075Sdes *
2766240075Sdes * "0.0.0.0"               -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2767240075Sdes * "" (empty string), "*"  -> wildcard v4/v6
2768240075Sdes * "localhost"             -> loopback v4/v6
2769295367Sdes * "127.0.0.1" / "::1"     -> accepted even if gateway_ports isn't set
2770240075Sdes */
2771240075Sdesstatic const char *
2772240075Sdeschannel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2773295367Sdes    int is_client, struct ForwardOptions *fwd_opts)
2774240075Sdes{
2775240075Sdes	const char *addr = NULL;
2776240075Sdes	int wildcard = 0;
2777240075Sdes
2778240075Sdes	if (listen_addr == NULL) {
2779240075Sdes		/* No address specified: default to gateway_ports setting */
2780295367Sdes		if (fwd_opts->gateway_ports)
2781240075Sdes			wildcard = 1;
2782295367Sdes	} else if (fwd_opts->gateway_ports || is_client) {
2783240075Sdes		if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2784240075Sdes		    strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2785240075Sdes		    *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2786295367Sdes		    (!is_client && fwd_opts->gateway_ports == 1)) {
2787240075Sdes			wildcard = 1;
2788262566Sdes			/*
2789262566Sdes			 * Notify client if they requested a specific listen
2790262566Sdes			 * address and it was overridden.
2791262566Sdes			 */
2792262566Sdes			if (*listen_addr != '\0' &&
2793262566Sdes			    strcmp(listen_addr, "0.0.0.0") != 0 &&
2794262566Sdes			    strcmp(listen_addr, "*") != 0) {
2795262566Sdes				packet_send_debug("Forwarding listen address "
2796262566Sdes				    "\"%s\" overridden by server "
2797262566Sdes				    "GatewayPorts", listen_addr);
2798262566Sdes			}
2799295367Sdes		} else if (strcmp(listen_addr, "localhost") != 0 ||
2800295367Sdes		    strcmp(listen_addr, "127.0.0.1") == 0 ||
2801295367Sdes		    strcmp(listen_addr, "::1") == 0) {
2802295367Sdes			/* Accept localhost address when GatewayPorts=yes */
2803295367Sdes			addr = listen_addr;
2804262566Sdes		}
2805295367Sdes	} else if (strcmp(listen_addr, "127.0.0.1") == 0 ||
2806295367Sdes	    strcmp(listen_addr, "::1") == 0) {
2807295367Sdes		/*
2808295367Sdes		 * If a specific IPv4/IPv6 localhost address has been
2809295367Sdes		 * requested then accept it even if gateway_ports is in
2810295367Sdes		 * effect. This allows the client to prefer IPv4 or IPv6.
2811295367Sdes		 */
2812295367Sdes		addr = listen_addr;
2813240075Sdes	}
2814240075Sdes	if (wildcardp != NULL)
2815240075Sdes		*wildcardp = wildcard;
2816240075Sdes	return addr;
2817240075Sdes}
2818240075Sdes
281992559Sdesstatic int
2820295367Sdeschannel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
2821295367Sdes    int *allocated_listen_port, struct ForwardOptions *fwd_opts)
282257429Smarkm{
282392559Sdes	Channel *c;
2824157019Sdes	int sock, r, success = 0, wildcard = 0, is_client;
282557429Smarkm	struct addrinfo hints, *ai, *aitop;
2826147005Sdes	const char *host, *addr;
282757429Smarkm	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
2828192595Sdes	in_port_t *lport_p;
282957429Smarkm
2830147005Sdes	is_client = (type == SSH_CHANNEL_PORT_LISTENER);
283157429Smarkm
2832295367Sdes	if (is_client && fwd->connect_path != NULL) {
2833295367Sdes		host = fwd->connect_path;
2834295367Sdes	} else {
2835295367Sdes		host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
2836295367Sdes		    fwd->listen_host : fwd->connect_host;
2837295367Sdes		if (host == NULL) {
2838295367Sdes			error("No forward host name.");
2839295367Sdes			return 0;
2840295367Sdes		}
2841295367Sdes		if (strlen(host) >= NI_MAXHOST) {
2842295367Sdes			error("Forward host name too long.");
2843295367Sdes			return 0;
2844295367Sdes		}
284576262Sgreen	}
284676262Sgreen
2847240075Sdes	/* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2848295367Sdes	addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard,
2849295367Sdes	    is_client, fwd_opts);
2850295367Sdes	debug3("%s: type %d wildcard %d addr %s", __func__,
2851147005Sdes	    type, wildcard, (addr == NULL) ? "NULL" : addr);
2852147005Sdes
2853147005Sdes	/*
285457429Smarkm	 * getaddrinfo returns a loopback address if the hostname is
285557429Smarkm	 * set to NULL and hints.ai_flags is not AI_PASSIVE
285657429Smarkm	 */
285757429Smarkm	memset(&hints, 0, sizeof(hints));
285857429Smarkm	hints.ai_family = IPv4or6;
2859147005Sdes	hints.ai_flags = wildcard ? AI_PASSIVE : 0;
286057429Smarkm	hints.ai_socktype = SOCK_STREAM;
2861295367Sdes	snprintf(strport, sizeof strport, "%d", fwd->listen_port);
2862147005Sdes	if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
2863147005Sdes		if (addr == NULL) {
2864147005Sdes			/* This really shouldn't happen */
2865147005Sdes			packet_disconnect("getaddrinfo: fatal error: %s",
2866181111Sdes			    ssh_gai_strerror(r));
2867147005Sdes		} else {
2868295367Sdes			error("%s: getaddrinfo(%.64s): %s", __func__, addr,
2869181111Sdes			    ssh_gai_strerror(r));
2870147005Sdes		}
2871149753Sdes		return 0;
2872147005Sdes	}
2873192595Sdes	if (allocated_listen_port != NULL)
2874192595Sdes		*allocated_listen_port = 0;
287557429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
2876192595Sdes		switch (ai->ai_family) {
2877192595Sdes		case AF_INET:
2878192595Sdes			lport_p = &((struct sockaddr_in *)ai->ai_addr)->
2879192595Sdes			    sin_port;
2880192595Sdes			break;
2881192595Sdes		case AF_INET6:
2882192595Sdes			lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
2883192595Sdes			    sin6_port;
2884192595Sdes			break;
2885192595Sdes		default:
288657429Smarkm			continue;
2887192595Sdes		}
2888192595Sdes		/*
2889192595Sdes		 * If allocating a port for -R forwards, then use the
2890192595Sdes		 * same port for all address families.
2891192595Sdes		 */
2892295367Sdes		if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2893192595Sdes		    allocated_listen_port != NULL && *allocated_listen_port > 0)
2894192595Sdes			*lport_p = htons(*allocated_listen_port);
2895192595Sdes
289657429Smarkm		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
289757429Smarkm		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2898295367Sdes			error("%s: getnameinfo failed", __func__);
289957429Smarkm			continue;
290057429Smarkm		}
290157429Smarkm		/* Create a port to listen for the host. */
2902124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
290357429Smarkm		if (sock < 0) {
290457429Smarkm			/* this is no error since kernel may not support ipv6 */
290557429Smarkm			verbose("socket: %.100s", strerror(errno));
290657429Smarkm			continue;
290757429Smarkm		}
2908106130Sdes
2909157019Sdes		channel_set_reuseaddr(sock);
2910204917Sdes		if (ai->ai_family == AF_INET6)
2911204917Sdes			sock_set_v6only(sock);
2912157019Sdes
2913192595Sdes		debug("Local forwarding listening on %s port %s.",
2914192595Sdes		    ntop, strport);
291557429Smarkm
291657429Smarkm		/* Bind the socket to the address. */
291757429Smarkm		if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
291857429Smarkm			/* address can be in use ipv6 address is already bound */
291998941Sdes			if (!ai->ai_next)
292098941Sdes				error("bind: %.100s", strerror(errno));
292198941Sdes			else
292298941Sdes				verbose("bind: %.100s", strerror(errno));
292398941Sdes
292457429Smarkm			close(sock);
292557429Smarkm			continue;
292657429Smarkm		}
292757429Smarkm		/* Start listening for connections on the socket. */
2928126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
292957429Smarkm			error("listen: %.100s", strerror(errno));
293057429Smarkm			close(sock);
293157429Smarkm			continue;
293257429Smarkm		}
2933192595Sdes
2934192595Sdes		/*
2935295367Sdes		 * fwd->listen_port == 0 requests a dynamically allocated port -
2936192595Sdes		 * record what we got.
2937192595Sdes		 */
2938295367Sdes		if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2939192595Sdes		    allocated_listen_port != NULL &&
2940192595Sdes		    *allocated_listen_port == 0) {
2941323124Sdes			*allocated_listen_port = get_local_port(sock);
2942192595Sdes			debug("Allocated listen port %d",
2943192595Sdes			    *allocated_listen_port);
2944192595Sdes		}
2945192595Sdes
2946294693Sdes		/* Allocate a channel number for the socket. */
2947294693Sdes		c = channel_new("port listener", type, sock, sock, -1,
2948294693Sdes		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2949294693Sdes		    0, "port listener", 1);
2950192595Sdes		c->path = xstrdup(host);
2951295367Sdes		c->host_port = fwd->connect_port;
2952240075Sdes		c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2953295367Sdes		if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
2954240075Sdes		    !(datafellows & SSH_BUG_DYNAMIC_RPORT))
2955240075Sdes			c->listening_port = *allocated_listen_port;
2956240075Sdes		else
2957295367Sdes			c->listening_port = fwd->listen_port;
295857429Smarkm		success = 1;
295957429Smarkm	}
296057429Smarkm	if (success == 0)
2961295367Sdes		error("%s: cannot listen to port: %d", __func__,
2962295367Sdes		    fwd->listen_port);
296357429Smarkm	freeaddrinfo(aitop);
296476262Sgreen	return success;
296557429Smarkm}
296657429Smarkm
2967295367Sdesstatic int
2968295367Sdeschannel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
2969295367Sdes    struct ForwardOptions *fwd_opts)
2970137019Sdes{
2971295367Sdes	struct sockaddr_un sunaddr;
2972295367Sdes	const char *path;
2973295367Sdes	Channel *c;
2974295367Sdes	int port, sock;
2975295367Sdes	mode_t omask;
2976295367Sdes
2977295367Sdes	switch (type) {
2978295367Sdes	case SSH_CHANNEL_UNIX_LISTENER:
2979295367Sdes		if (fwd->connect_path != NULL) {
2980295367Sdes			if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
2981295367Sdes				error("Local connecting path too long: %s",
2982295367Sdes				    fwd->connect_path);
2983295367Sdes				return 0;
2984295367Sdes			}
2985295367Sdes			path = fwd->connect_path;
2986295367Sdes			port = PORT_STREAMLOCAL;
2987295367Sdes		} else {
2988295367Sdes			if (fwd->connect_host == NULL) {
2989295367Sdes				error("No forward host name.");
2990295367Sdes				return 0;
2991295367Sdes			}
2992295367Sdes			if (strlen(fwd->connect_host) >= NI_MAXHOST) {
2993295367Sdes				error("Forward host name too long.");
2994295367Sdes				return 0;
2995295367Sdes			}
2996295367Sdes			path = fwd->connect_host;
2997295367Sdes			port = fwd->connect_port;
2998295367Sdes		}
2999295367Sdes		break;
3000295367Sdes	case SSH_CHANNEL_RUNIX_LISTENER:
3001295367Sdes		path = fwd->listen_path;
3002295367Sdes		port = PORT_STREAMLOCAL;
3003295367Sdes		break;
3004295367Sdes	default:
3005295367Sdes		error("%s: unexpected channel type %d", __func__, type);
3006295367Sdes		return 0;
3007295367Sdes	}
3008295367Sdes
3009295367Sdes	if (fwd->listen_path == NULL) {
3010295367Sdes		error("No forward path name.");
3011295367Sdes		return 0;
3012295367Sdes	}
3013295367Sdes	if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
3014295367Sdes		error("Local listening path too long: %s", fwd->listen_path);
3015295367Sdes		return 0;
3016295367Sdes	}
3017295367Sdes
3018295367Sdes	debug3("%s: type %d path %s", __func__, type, fwd->listen_path);
3019295367Sdes
3020295367Sdes	/* Start a Unix domain listener. */
3021295367Sdes	omask = umask(fwd_opts->streamlocal_bind_mask);
3022295367Sdes	sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
3023295367Sdes	    fwd_opts->streamlocal_bind_unlink);
3024295367Sdes	umask(omask);
3025295367Sdes	if (sock < 0)
3026295367Sdes		return 0;
3027295367Sdes
3028295367Sdes	debug("Local forwarding listening on path %s.", fwd->listen_path);
3029295367Sdes
3030295367Sdes	/* Allocate a channel number for the socket. */
3031295367Sdes	c = channel_new("unix listener", type, sock, sock, -1,
3032295367Sdes	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
3033295367Sdes	    0, "unix listener", 1);
3034295367Sdes	c->path = xstrdup(path);
3035295367Sdes	c->host_port = port;
3036295367Sdes	c->listening_port = PORT_STREAMLOCAL;
3037295367Sdes	c->listening_addr = xstrdup(fwd->listen_path);
3038295367Sdes	return 1;
3039295367Sdes}
3040295367Sdes
3041295367Sdesstatic int
3042295367Sdeschannel_cancel_rport_listener_tcpip(const char *host, u_short port)
3043295367Sdes{
3044137019Sdes	u_int i;
3045137019Sdes	int found = 0;
3046137019Sdes
3047147005Sdes	for (i = 0; i < channels_alloc; i++) {
3048137019Sdes		Channel *c = channels[i];
3049240075Sdes		if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
3050240075Sdes			continue;
3051240075Sdes		if (strcmp(c->path, host) == 0 && c->listening_port == port) {
3052240075Sdes			debug2("%s: close channel %d", __func__, i);
3053240075Sdes			channel_free(c);
3054240075Sdes			found = 1;
3055240075Sdes		}
3056240075Sdes	}
3057137019Sdes
3058240075Sdes	return (found);
3059240075Sdes}
3060240075Sdes
3061295367Sdesstatic int
3062295367Sdeschannel_cancel_rport_listener_streamlocal(const char *path)
3063295367Sdes{
3064295367Sdes	u_int i;
3065295367Sdes	int found = 0;
3066295367Sdes
3067295367Sdes	for (i = 0; i < channels_alloc; i++) {
3068295367Sdes		Channel *c = channels[i];
3069295367Sdes		if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
3070295367Sdes			continue;
3071295367Sdes		if (c->path == NULL)
3072295367Sdes			continue;
3073295367Sdes		if (strcmp(c->path, path) == 0) {
3074295367Sdes			debug2("%s: close channel %d", __func__, i);
3075295367Sdes			channel_free(c);
3076295367Sdes			found = 1;
3077295367Sdes		}
3078295367Sdes	}
3079295367Sdes
3080295367Sdes	return (found);
3081295367Sdes}
3082295367Sdes
3083240075Sdesint
3084295367Sdeschannel_cancel_rport_listener(struct Forward *fwd)
3085240075Sdes{
3086295367Sdes	if (fwd->listen_path != NULL)
3087295367Sdes		return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
3088295367Sdes	else
3089295367Sdes		return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
3090295367Sdes}
3091295367Sdes
3092295367Sdesstatic int
3093295367Sdeschannel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
3094295367Sdes    int cport, struct ForwardOptions *fwd_opts)
3095295367Sdes{
3096240075Sdes	u_int i;
3097240075Sdes	int found = 0;
3098295367Sdes	const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
3099240075Sdes
3100240075Sdes	for (i = 0; i < channels_alloc; i++) {
3101240075Sdes		Channel *c = channels[i];
3102240075Sdes		if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
3103240075Sdes			continue;
3104240075Sdes		if (c->listening_port != lport)
3105240075Sdes			continue;
3106240075Sdes		if (cport == CHANNEL_CANCEL_PORT_STATIC) {
3107240075Sdes			/* skip dynamic forwardings */
3108240075Sdes			if (c->host_port == 0)
3109240075Sdes				continue;
3110240075Sdes		} else {
3111240075Sdes			if (c->host_port != cport)
3112240075Sdes				continue;
3113240075Sdes		}
3114240075Sdes		if ((c->listening_addr == NULL && addr != NULL) ||
3115240075Sdes		    (c->listening_addr != NULL && addr == NULL))
3116240075Sdes			continue;
3117240075Sdes		if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
3118147005Sdes			debug2("%s: close channel %d", __func__, i);
3119137019Sdes			channel_free(c);
3120137019Sdes			found = 1;
3121137019Sdes		}
3122137019Sdes	}
3123137019Sdes
3124137019Sdes	return (found);
3125137019Sdes}
3126137019Sdes
3127295367Sdesstatic int
3128295367Sdeschannel_cancel_lport_listener_streamlocal(const char *path)
3129295367Sdes{
3130295367Sdes	u_int i;
3131295367Sdes	int found = 0;
3132295367Sdes
3133295367Sdes	if (path == NULL) {
3134295367Sdes		error("%s: no path specified.", __func__);
3135295367Sdes		return 0;
3136295367Sdes	}
3137295367Sdes
3138295367Sdes	for (i = 0; i < channels_alloc; i++) {
3139295367Sdes		Channel *c = channels[i];
3140295367Sdes		if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
3141295367Sdes			continue;
3142295367Sdes		if (c->listening_addr == NULL)
3143295367Sdes			continue;
3144295367Sdes		if (strcmp(c->listening_addr, path) == 0) {
3145295367Sdes			debug2("%s: close channel %d", __func__, i);
3146295367Sdes			channel_free(c);
3147295367Sdes			found = 1;
3148295367Sdes		}
3149295367Sdes	}
3150295367Sdes
3151295367Sdes	return (found);
3152295367Sdes}
3153295367Sdes
3154295367Sdesint
3155295367Sdeschannel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
3156295367Sdes{
3157295367Sdes	if (fwd->listen_path != NULL)
3158295367Sdes		return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
3159295367Sdes	else
3160295367Sdes		return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
3161295367Sdes}
3162295367Sdes
316392559Sdes/* protocol local port fwd, used by ssh (and sshd in v1) */
316492559Sdesint
3165295367Sdeschannel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts)
316692559Sdes{
3167295367Sdes	if (fwd->listen_path != NULL) {
3168295367Sdes		return channel_setup_fwd_listener_streamlocal(
3169295367Sdes		    SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
3170295367Sdes	} else {
3171295367Sdes		return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
3172295367Sdes		    fwd, NULL, fwd_opts);
3173295367Sdes	}
317492559Sdes}
317592559Sdes
317692559Sdes/* protocol v2 remote port fwd, used by sshd */
317792559Sdesint
3178295367Sdeschannel_setup_remote_fwd_listener(struct Forward *fwd,
3179295367Sdes    int *allocated_listen_port, struct ForwardOptions *fwd_opts)
318092559Sdes{
3181295367Sdes	if (fwd->listen_path != NULL) {
3182295367Sdes		return channel_setup_fwd_listener_streamlocal(
3183295367Sdes		    SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
3184295367Sdes	} else {
3185295367Sdes		return channel_setup_fwd_listener_tcpip(
3186295367Sdes		    SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
3187295367Sdes		    fwd_opts);
3188295367Sdes	}
318992559Sdes}
319092559Sdes
319157429Smarkm/*
3192240075Sdes * Translate the requested rfwd listen host to something usable for
3193240075Sdes * this server.
3194240075Sdes */
3195240075Sdesstatic const char *
3196240075Sdeschannel_rfwd_bind_host(const char *listen_host)
3197240075Sdes{
3198240075Sdes	if (listen_host == NULL) {
3199240075Sdes		if (datafellows & SSH_BUG_RFWD_ADDR)
3200240075Sdes			return "127.0.0.1";
3201240075Sdes		else
3202240075Sdes			return "localhost";
3203240075Sdes	} else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
3204240075Sdes		if (datafellows & SSH_BUG_RFWD_ADDR)
3205240075Sdes			return "0.0.0.0";
3206240075Sdes		else
3207240075Sdes			return "";
3208240075Sdes	} else
3209240075Sdes		return listen_host;
3210240075Sdes}
3211240075Sdes
3212240075Sdes/*
321357429Smarkm * Initiate forwarding of connections to port "port" on remote host through
321457429Smarkm * the secure channel to host:port from local side.
3215240075Sdes * Returns handle (index) for updating the dynamic listen port with
3216240075Sdes * channel_update_permitted_opens().
321757429Smarkm */
3218162856Sdesint
3219295367Sdeschannel_request_remote_forwarding(struct Forward *fwd)
322057429Smarkm{
3221240075Sdes	int type, success = 0, idx = -1;
322276262Sgreen
322357429Smarkm	/* Send the forward request to the remote side. */
322460573Skris	if (compat20) {
322560573Skris		packet_start(SSH2_MSG_GLOBAL_REQUEST);
3226295367Sdes		if (fwd->listen_path != NULL) {
3227295367Sdes		    packet_put_cstring("streamlocal-forward@openssh.com");
3228295367Sdes		    packet_put_char(1);		/* boolean: want reply */
3229295367Sdes		    packet_put_cstring(fwd->listen_path);
3230295367Sdes		} else {
3231295367Sdes		    packet_put_cstring("tcpip-forward");
3232295367Sdes		    packet_put_char(1);		/* boolean: want reply */
3233295367Sdes		    packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
3234295367Sdes		    packet_put_int(fwd->listen_port);
3235295367Sdes		}
323676262Sgreen		packet_send();
323776262Sgreen		packet_write_wait();
323876262Sgreen		/* Assume that server accepts the request */
323976262Sgreen		success = 1;
3240295367Sdes	} else if (fwd->listen_path == NULL) {
324160573Skris		packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
3242295367Sdes		packet_put_int(fwd->listen_port);
3243295367Sdes		packet_put_cstring(fwd->connect_host);
3244295367Sdes		packet_put_int(fwd->connect_port);
324560573Skris		packet_send();
324660573Skris		packet_write_wait();
324776262Sgreen
324876262Sgreen		/* Wait for response from the remote side. */
324992559Sdes		type = packet_read();
325076262Sgreen		switch (type) {
325176262Sgreen		case SSH_SMSG_SUCCESS:
325276262Sgreen			success = 1;
325376262Sgreen			break;
325476262Sgreen		case SSH_SMSG_FAILURE:
325576262Sgreen			break;
325676262Sgreen		default:
325776262Sgreen			/* Unknown packet */
325876262Sgreen			packet_disconnect("Protocol error for port forward request:"
325976262Sgreen			    "received packet type %d.", type);
326076262Sgreen		}
3261295367Sdes	} else {
3262295367Sdes		logit("Warning: Server does not support remote stream local forwarding.");
326360573Skris	}
326476262Sgreen	if (success) {
3265215116Sdes		/* Record that connection to this host/port is permitted. */
3266295367Sdes		permitted_opens = xreallocarray(permitted_opens,
3267215116Sdes		    num_permitted_opens + 1, sizeof(*permitted_opens));
3268240075Sdes		idx = num_permitted_opens++;
3269295367Sdes		if (fwd->connect_path != NULL) {
3270295367Sdes			permitted_opens[idx].host_to_connect =
3271295367Sdes			    xstrdup(fwd->connect_path);
3272295367Sdes			permitted_opens[idx].port_to_connect =
3273295367Sdes			    PORT_STREAMLOCAL;
3274295367Sdes		} else {
3275295367Sdes			permitted_opens[idx].host_to_connect =
3276295367Sdes			    xstrdup(fwd->connect_host);
3277295367Sdes			permitted_opens[idx].port_to_connect =
3278295367Sdes			    fwd->connect_port;
3279295367Sdes		}
3280295367Sdes		if (fwd->listen_path != NULL) {
3281295367Sdes			permitted_opens[idx].listen_host = NULL;
3282295367Sdes			permitted_opens[idx].listen_path =
3283295367Sdes			    xstrdup(fwd->listen_path);
3284295367Sdes			permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
3285295367Sdes		} else {
3286295367Sdes			permitted_opens[idx].listen_host =
3287295367Sdes			    fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
3288295367Sdes			permitted_opens[idx].listen_path = NULL;
3289295367Sdes			permitted_opens[idx].listen_port = fwd->listen_port;
3290295367Sdes		}
329176262Sgreen	}
3292240075Sdes	return (idx);
329357429Smarkm}
329457429Smarkm
3295295367Sdesstatic int
3296295367Sdesopen_match(ForwardPermission *allowed_open, const char *requestedhost,
3297295367Sdes    int requestedport)
3298295367Sdes{
3299295367Sdes	if (allowed_open->host_to_connect == NULL)
3300295367Sdes		return 0;
3301295367Sdes	if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT &&
3302295367Sdes	    allowed_open->port_to_connect != requestedport)
3303295367Sdes		return 0;
3304323124Sdes	if (strcmp(allowed_open->host_to_connect, FWD_PERMIT_ANY_HOST) != 0 &&
3305323124Sdes	    strcmp(allowed_open->host_to_connect, requestedhost) != 0)
3306295367Sdes		return 0;
3307295367Sdes	return 1;
3308295367Sdes}
3309295367Sdes
331057429Smarkm/*
3311295367Sdes * Note that in the listen host/port case
3312295367Sdes * we don't support FWD_PERMIT_ANY_PORT and
3313295367Sdes * need to translate between the configured-host (listen_host)
3314295367Sdes * and what we've sent to the remote server (channel_rfwd_bind_host)
3315295367Sdes */
3316295367Sdesstatic int
3317295367Sdesopen_listen_match_tcpip(ForwardPermission *allowed_open,
3318295367Sdes    const char *requestedhost, u_short requestedport, int translate)
3319295367Sdes{
3320295367Sdes	const char *allowed_host;
3321295367Sdes
3322295367Sdes	if (allowed_open->host_to_connect == NULL)
3323295367Sdes		return 0;
3324295367Sdes	if (allowed_open->listen_port != requestedport)
3325295367Sdes		return 0;
3326295367Sdes	if (!translate && allowed_open->listen_host == NULL &&
3327295367Sdes	    requestedhost == NULL)
3328295367Sdes		return 1;
3329295367Sdes	allowed_host = translate ?
3330295367Sdes	    channel_rfwd_bind_host(allowed_open->listen_host) :
3331295367Sdes	    allowed_open->listen_host;
3332295367Sdes	if (allowed_host == NULL ||
3333295367Sdes	    strcmp(allowed_host, requestedhost) != 0)
3334295367Sdes		return 0;
3335295367Sdes	return 1;
3336295367Sdes}
3337295367Sdes
3338295367Sdesstatic int
3339295367Sdesopen_listen_match_streamlocal(ForwardPermission *allowed_open,
3340295367Sdes    const char *requestedpath)
3341295367Sdes{
3342295367Sdes	if (allowed_open->host_to_connect == NULL)
3343295367Sdes		return 0;
3344295367Sdes	if (allowed_open->listen_port != PORT_STREAMLOCAL)
3345295367Sdes		return 0;
3346295367Sdes	if (allowed_open->listen_path == NULL ||
3347295367Sdes	    strcmp(allowed_open->listen_path, requestedpath) != 0)
3348295367Sdes		return 0;
3349295367Sdes	return 1;
3350295367Sdes}
3351295367Sdes
3352295367Sdes/*
3353137019Sdes * Request cancellation of remote forwarding of connection host:port from
3354137019Sdes * local side.
3355137019Sdes */
3356295367Sdesstatic int
3357295367Sdeschannel_request_rforward_cancel_tcpip(const char *host, u_short port)
3358137019Sdes{
3359137019Sdes	int i;
3360137019Sdes
3361137019Sdes	if (!compat20)
3362240075Sdes		return -1;
3363137019Sdes
3364137019Sdes	for (i = 0; i < num_permitted_opens; i++) {
3365295367Sdes		if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
3366137019Sdes			break;
3367137019Sdes	}
3368137019Sdes	if (i >= num_permitted_opens) {
3369137019Sdes		debug("%s: requested forward not found", __func__);
3370240075Sdes		return -1;
3371137019Sdes	}
3372137019Sdes	packet_start(SSH2_MSG_GLOBAL_REQUEST);
3373137019Sdes	packet_put_cstring("cancel-tcpip-forward");
3374137019Sdes	packet_put_char(0);
3375240075Sdes	packet_put_cstring(channel_rfwd_bind_host(host));
3376137019Sdes	packet_put_int(port);
3377137019Sdes	packet_send();
3378137019Sdes
3379137019Sdes	permitted_opens[i].listen_port = 0;
3380137019Sdes	permitted_opens[i].port_to_connect = 0;
3381255767Sdes	free(permitted_opens[i].host_to_connect);
3382137019Sdes	permitted_opens[i].host_to_connect = NULL;
3383295367Sdes	free(permitted_opens[i].listen_host);
3384295367Sdes	permitted_opens[i].listen_host = NULL;
3385295367Sdes	permitted_opens[i].listen_path = NULL;
3386240075Sdes
3387240075Sdes	return 0;
3388137019Sdes}
3389137019Sdes
3390137019Sdes/*
3391295367Sdes * Request cancellation of remote forwarding of Unix domain socket
3392295367Sdes * path from local side.
3393295367Sdes */
3394295367Sdesstatic int
3395295367Sdeschannel_request_rforward_cancel_streamlocal(const char *path)
3396295367Sdes{
3397295367Sdes	int i;
3398295367Sdes
3399295367Sdes	if (!compat20)
3400295367Sdes		return -1;
3401295367Sdes
3402295367Sdes	for (i = 0; i < num_permitted_opens; i++) {
3403295367Sdes		if (open_listen_match_streamlocal(&permitted_opens[i], path))
3404295367Sdes			break;
3405295367Sdes	}
3406295367Sdes	if (i >= num_permitted_opens) {
3407295367Sdes		debug("%s: requested forward not found", __func__);
3408295367Sdes		return -1;
3409295367Sdes	}
3410295367Sdes	packet_start(SSH2_MSG_GLOBAL_REQUEST);
3411295367Sdes	packet_put_cstring("cancel-streamlocal-forward@openssh.com");
3412295367Sdes	packet_put_char(0);
3413295367Sdes	packet_put_cstring(path);
3414295367Sdes	packet_send();
3415295367Sdes
3416295367Sdes	permitted_opens[i].listen_port = 0;
3417295367Sdes	permitted_opens[i].port_to_connect = 0;
3418295367Sdes	free(permitted_opens[i].host_to_connect);
3419295367Sdes	permitted_opens[i].host_to_connect = NULL;
3420295367Sdes	permitted_opens[i].listen_host = NULL;
3421295367Sdes	free(permitted_opens[i].listen_path);
3422295367Sdes	permitted_opens[i].listen_path = NULL;
3423295367Sdes
3424295367Sdes	return 0;
3425295367Sdes}
3426295367Sdes
3427295367Sdes/*
3428295367Sdes * Request cancellation of remote forwarding of a connection from local side.
3429295367Sdes */
3430295367Sdesint
3431295367Sdeschannel_request_rforward_cancel(struct Forward *fwd)
3432295367Sdes{
3433295367Sdes	if (fwd->listen_path != NULL) {
3434295367Sdes		return (channel_request_rforward_cancel_streamlocal(
3435295367Sdes		    fwd->listen_path));
3436295367Sdes	} else {
3437295367Sdes		return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
3438295367Sdes		    fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
3439295367Sdes	}
3440295367Sdes}
3441295367Sdes
3442295367Sdes/*
344357429Smarkm * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
344457429Smarkm * listening for the port, and sends back a success reply (or disconnect
3445162856Sdes * message if there was an error).
344657429Smarkm */
3447162856Sdesint
3448295367Sdeschannel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts)
344957429Smarkm{
3450162856Sdes	int success = 0;
3451295367Sdes	struct Forward fwd;
345257429Smarkm
345357429Smarkm	/* Get arguments from the packet. */
3454295367Sdes	memset(&fwd, 0, sizeof(fwd));
3455295367Sdes	fwd.listen_port = packet_get_int();
3456295367Sdes	fwd.connect_host = packet_get_string(NULL);
3457295367Sdes	fwd.connect_port = packet_get_int();
345857429Smarkm
345998941Sdes#ifndef HAVE_CYGWIN
346057429Smarkm	/*
346157429Smarkm	 * Check that an unprivileged user is not trying to forward a
346257429Smarkm	 * privileged port.
346357429Smarkm	 */
3464295367Sdes	if (fwd.listen_port < IPPORT_RESERVED && !is_root)
3465124207Sdes		packet_disconnect(
3466124207Sdes		    "Requested forwarding of port %d but user is not root.",
3467295367Sdes		    fwd.listen_port);
3468295367Sdes	if (fwd.connect_port == 0)
3469124207Sdes		packet_disconnect("Dynamic forwarding denied.");
347098941Sdes#endif
3471124207Sdes
347276262Sgreen	/* Initiate forwarding */
3473295367Sdes	success = channel_setup_local_fwd_listener(&fwd, fwd_opts);
347457429Smarkm
347557429Smarkm	/* Free the argument string. */
3476295367Sdes	free(fwd.connect_host);
3477162856Sdes
3478162856Sdes	return (success ? 0 : -1);
347957429Smarkm}
348057429Smarkm
348176262Sgreen/*
348276262Sgreen * Permits opening to any host/port if permitted_opens[] is empty.  This is
348376262Sgreen * usually called by the server, because the user could connect to any port
348476262Sgreen * anyway, and the server has no way to know but to trust the client anyway.
348576262Sgreen */
348676262Sgreenvoid
348792559Sdeschannel_permit_all_opens(void)
348876262Sgreen{
348976262Sgreen	if (num_permitted_opens == 0)
349076262Sgreen		all_opens_permitted = 1;
349176262Sgreen}
349276262Sgreen
349376262Sgreenvoid
349476262Sgreenchannel_add_permitted_opens(char *host, int port)
349576262Sgreen{
349676262Sgreen	debug("allow port forwarding to host %s port %d", host, port);
349776262Sgreen
3498295367Sdes	permitted_opens = xreallocarray(permitted_opens,
3499215116Sdes	    num_permitted_opens + 1, sizeof(*permitted_opens));
350076262Sgreen	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
350176262Sgreen	permitted_opens[num_permitted_opens].port_to_connect = port;
3502295367Sdes	permitted_opens[num_permitted_opens].listen_host = NULL;
3503295367Sdes	permitted_opens[num_permitted_opens].listen_path = NULL;
3504295367Sdes	permitted_opens[num_permitted_opens].listen_port = 0;
350576262Sgreen	num_permitted_opens++;
350676262Sgreen
350776262Sgreen	all_opens_permitted = 0;
350876262Sgreen}
350976262Sgreen
3510240075Sdes/*
3511240075Sdes * Update the listen port for a dynamic remote forward, after
3512240075Sdes * the actual 'newport' has been allocated. If 'newport' < 0 is
3513240075Sdes * passed then they entry will be invalidated.
3514240075Sdes */
3515240075Sdesvoid
3516240075Sdeschannel_update_permitted_opens(int idx, int newport)
3517240075Sdes{
3518240075Sdes	if (idx < 0 || idx >= num_permitted_opens) {
3519240075Sdes		debug("channel_update_permitted_opens: index out of range:"
3520240075Sdes		    " %d num_permitted_opens %d", idx, num_permitted_opens);
3521240075Sdes		return;
3522240075Sdes	}
3523240075Sdes	debug("%s allowed port %d for forwarding to host %s port %d",
3524240075Sdes	    newport > 0 ? "Updating" : "Removing",
3525240075Sdes	    newport,
3526240075Sdes	    permitted_opens[idx].host_to_connect,
3527240075Sdes	    permitted_opens[idx].port_to_connect);
3528240075Sdes	if (newport >= 0)  {
3529240075Sdes		permitted_opens[idx].listen_port =
3530240075Sdes		    (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport;
3531240075Sdes	} else {
3532240075Sdes		permitted_opens[idx].listen_port = 0;
3533240075Sdes		permitted_opens[idx].port_to_connect = 0;
3534255767Sdes		free(permitted_opens[idx].host_to_connect);
3535240075Sdes		permitted_opens[idx].host_to_connect = NULL;
3536295367Sdes		free(permitted_opens[idx].listen_host);
3537295367Sdes		permitted_opens[idx].listen_host = NULL;
3538295367Sdes		free(permitted_opens[idx].listen_path);
3539295367Sdes		permitted_opens[idx].listen_path = NULL;
3540240075Sdes	}
3541240075Sdes}
3542240075Sdes
3543162856Sdesint
3544162856Sdeschannel_add_adm_permitted_opens(char *host, int port)
3545162856Sdes{
3546162856Sdes	debug("config allows port forwarding to host %s port %d", host, port);
3547162856Sdes
3548295367Sdes	permitted_adm_opens = xreallocarray(permitted_adm_opens,
3549215116Sdes	    num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
3550162856Sdes	permitted_adm_opens[num_adm_permitted_opens].host_to_connect
3551162856Sdes	     = xstrdup(host);
3552162856Sdes	permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
3553295367Sdes	permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
3554295367Sdes	permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
3555295367Sdes	permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
3556162856Sdes	return ++num_adm_permitted_opens;
3557162856Sdes}
3558162856Sdes
355976262Sgreenvoid
3560240075Sdeschannel_disable_adm_local_opens(void)
3561240075Sdes{
3562248619Sdes	channel_clear_adm_permitted_opens();
3563295367Sdes	permitted_adm_opens = xcalloc(sizeof(*permitted_adm_opens), 1);
3564248619Sdes	permitted_adm_opens[num_adm_permitted_opens].host_to_connect = NULL;
3565248619Sdes	num_adm_permitted_opens = 1;
3566240075Sdes}
3567240075Sdes
3568240075Sdesvoid
356976262Sgreenchannel_clear_permitted_opens(void)
357076262Sgreen{
357176262Sgreen	int i;
357276262Sgreen
3573295367Sdes	for (i = 0; i < num_permitted_opens; i++) {
3574255767Sdes		free(permitted_opens[i].host_to_connect);
3575295367Sdes		free(permitted_opens[i].listen_host);
3576295367Sdes		free(permitted_opens[i].listen_path);
3577295367Sdes	}
3578255767Sdes	free(permitted_opens);
3579255767Sdes	permitted_opens = NULL;
358076262Sgreen	num_permitted_opens = 0;
3581162856Sdes}
358276262Sgreen
3583162856Sdesvoid
3584162856Sdeschannel_clear_adm_permitted_opens(void)
3585162856Sdes{
3586162856Sdes	int i;
3587162856Sdes
3588295367Sdes	for (i = 0; i < num_adm_permitted_opens; i++) {
3589255767Sdes		free(permitted_adm_opens[i].host_to_connect);
3590295367Sdes		free(permitted_adm_opens[i].listen_host);
3591295367Sdes		free(permitted_adm_opens[i].listen_path);
3592295367Sdes	}
3593255767Sdes	free(permitted_adm_opens);
3594255767Sdes	permitted_adm_opens = NULL;
3595162856Sdes	num_adm_permitted_opens = 0;
359676262Sgreen}
359776262Sgreen
3598181111Sdesvoid
3599181111Sdeschannel_print_adm_permitted_opens(void)
3600181111Sdes{
3601181111Sdes	int i;
3602181111Sdes
3603192595Sdes	printf("permitopen");
3604192595Sdes	if (num_adm_permitted_opens == 0) {
3605192595Sdes		printf(" any\n");
3606192595Sdes		return;
3607192595Sdes	}
3608181111Sdes	for (i = 0; i < num_adm_permitted_opens; i++)
3609240075Sdes		if (permitted_adm_opens[i].host_to_connect == NULL)
3610240075Sdes			printf(" none");
3611240075Sdes		else
3612181111Sdes			printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
3613181111Sdes			    permitted_adm_opens[i].port_to_connect);
3614192595Sdes	printf("\n");
3615181111Sdes}
3616181111Sdes
3617240075Sdes/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
3618240075Sdesint
3619240075Sdespermitopen_port(const char *p)
3620240075Sdes{
3621240075Sdes	int port;
3622240075Sdes
3623240075Sdes	if (strcmp(p, "*") == 0)
3624240075Sdes		return FWD_PERMIT_ANY_PORT;
3625240075Sdes	if ((port = a2port(p)) > 0)
3626240075Sdes		return port;
3627240075Sdes	return -1;
3628240075Sdes}
3629240075Sdes
3630181111Sdes/* Try to start non-blocking connect to next host in cctx list */
363192559Sdesstatic int
3632181111Sdesconnect_next(struct channel_connect *cctx)
363360573Skris{
3634181111Sdes	int sock, saved_errno;
3635295367Sdes	struct sockaddr_un *sunaddr;
3636295367Sdes	char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))];
363760573Skris
3638181111Sdes	for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
3639295367Sdes		switch (cctx->ai->ai_family) {
3640295367Sdes		case AF_UNIX:
3641295367Sdes			/* unix:pathname instead of host:port */
3642295367Sdes			sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
3643295367Sdes			strlcpy(ntop, "unix", sizeof(ntop));
3644295367Sdes			strlcpy(strport, sunaddr->sun_path, sizeof(strport));
3645295367Sdes			break;
3646295367Sdes		case AF_INET:
3647295367Sdes		case AF_INET6:
3648295367Sdes			if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
3649295367Sdes			    ntop, sizeof(ntop), strport, sizeof(strport),
3650295367Sdes			    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
3651295367Sdes				error("connect_next: getnameinfo failed");
3652295367Sdes				continue;
3653295367Sdes			}
3654295367Sdes			break;
3655295367Sdes		default:
365660573Skris			continue;
365760573Skris		}
3658181111Sdes		if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
3659181111Sdes		    cctx->ai->ai_protocol)) == -1) {
3660181111Sdes			if (cctx->ai->ai_next == NULL)
3661113911Sdes				error("socket: %.100s", strerror(errno));
3662113911Sdes			else
3663113911Sdes				verbose("socket: %.100s", strerror(errno));
366460573Skris			continue;
366560573Skris		}
3666137019Sdes		if (set_nonblock(sock) == -1)
3667137019Sdes			fatal("%s: set_nonblock(%d)", __func__, sock);
3668181111Sdes		if (connect(sock, cctx->ai->ai_addr,
3669181111Sdes		    cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
3670181111Sdes			debug("connect_next: host %.100s ([%.100s]:%s): "
3671181111Sdes			    "%.100s", cctx->host, ntop, strport,
367260573Skris			    strerror(errno));
3673181111Sdes			saved_errno = errno;
367460573Skris			close(sock);
3675181111Sdes			errno = saved_errno;
367676262Sgreen			continue;	/* fail -- try next */
367760573Skris		}
3678295367Sdes		if (cctx->ai->ai_family != AF_UNIX)
3679295367Sdes			set_nodelay(sock);
3680181111Sdes		debug("connect_next: host %.100s ([%.100s]:%s) "
3681181111Sdes		    "in progress, fd=%d", cctx->host, ntop, strport, sock);
3682181111Sdes		cctx->ai = cctx->ai->ai_next;
3683181111Sdes		return sock;
3684181111Sdes	}
3685181111Sdes	return -1;
3686181111Sdes}
368760573Skris
3688181111Sdesstatic void
3689181111Sdeschannel_connect_ctx_free(struct channel_connect *cctx)
3690181111Sdes{
3691255767Sdes	free(cctx->host);
3692295367Sdes	if (cctx->aitop) {
3693295367Sdes		if (cctx->aitop->ai_family == AF_UNIX)
3694295367Sdes			free(cctx->aitop);
3695295367Sdes		else
3696295367Sdes			freeaddrinfo(cctx->aitop);
3697295367Sdes	}
3698264377Sdes	memset(cctx, 0, sizeof(*cctx));
3699181111Sdes}
3700181111Sdes
3701295367Sdes/* Return CONNECTING channel to remote host:port or local socket path */
3702181111Sdesstatic Channel *
3703295367Sdesconnect_to(const char *name, int port, char *ctype, char *rname)
3704181111Sdes{
3705181111Sdes	struct addrinfo hints;
3706181111Sdes	int gaierr;
3707181111Sdes	int sock = -1;
3708181111Sdes	char strport[NI_MAXSERV];
3709181111Sdes	struct channel_connect cctx;
3710181111Sdes	Channel *c;
3711181111Sdes
3712181111Sdes	memset(&cctx, 0, sizeof(cctx));
3713295367Sdes
3714295367Sdes	if (port == PORT_STREAMLOCAL) {
3715295367Sdes		struct sockaddr_un *sunaddr;
3716295367Sdes		struct addrinfo *ai;
3717295367Sdes
3718295367Sdes		if (strlen(name) > sizeof(sunaddr->sun_path)) {
3719295367Sdes			error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
3720295367Sdes			return (NULL);
3721295367Sdes		}
3722295367Sdes
3723295367Sdes		/*
3724295367Sdes		 * Fake up a struct addrinfo for AF_UNIX connections.
3725295367Sdes		 * channel_connect_ctx_free() must check ai_family
3726295367Sdes		 * and use free() not freeaddirinfo() for AF_UNIX.
3727295367Sdes		 */
3728295367Sdes		ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
3729295367Sdes		memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
3730295367Sdes		ai->ai_addr = (struct sockaddr *)(ai + 1);
3731295367Sdes		ai->ai_addrlen = sizeof(*sunaddr);
3732295367Sdes		ai->ai_family = AF_UNIX;
3733295367Sdes		ai->ai_socktype = SOCK_STREAM;
3734295367Sdes		ai->ai_protocol = PF_UNSPEC;
3735295367Sdes		sunaddr = (struct sockaddr_un *)ai->ai_addr;
3736295367Sdes		sunaddr->sun_family = AF_UNIX;
3737295367Sdes		strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
3738295367Sdes		cctx.aitop = ai;
3739295367Sdes	} else {
3740295367Sdes		memset(&hints, 0, sizeof(hints));
3741295367Sdes		hints.ai_family = IPv4or6;
3742295367Sdes		hints.ai_socktype = SOCK_STREAM;
3743295367Sdes		snprintf(strport, sizeof strport, "%d", port);
3744295367Sdes		if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) {
3745295367Sdes			error("connect_to %.100s: unknown host (%s)", name,
3746295367Sdes			    ssh_gai_strerror(gaierr));
3747295367Sdes			return NULL;
3748295367Sdes		}
374960573Skris	}
3750181111Sdes
3751295367Sdes	cctx.host = xstrdup(name);
3752181111Sdes	cctx.port = port;
3753181111Sdes	cctx.ai = cctx.aitop;
3754181111Sdes
3755181111Sdes	if ((sock = connect_next(&cctx)) == -1) {
3756181111Sdes		error("connect to %.100s port %d failed: %s",
3757295367Sdes		    name, port, strerror(errno));
3758181111Sdes		channel_connect_ctx_free(&cctx);
3759181111Sdes		return NULL;
376060573Skris	}
3761181111Sdes	c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
3762181111Sdes	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
3763181111Sdes	c->connect_ctx = cctx;
3764181111Sdes	return c;
376560573Skris}
376676262Sgreen
3767181111SdesChannel *
3768295367Sdeschannel_connect_by_listen_address(const char *listen_host,
3769295367Sdes    u_short listen_port, char *ctype, char *rname)
377076262Sgreen{
377176262Sgreen	int i;
377276262Sgreen
3773181111Sdes	for (i = 0; i < num_permitted_opens; i++) {
3774295367Sdes		if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
3775295367Sdes		    listen_port, 1)) {
377676262Sgreen			return connect_to(
377776262Sgreen			    permitted_opens[i].host_to_connect,
3778181111Sdes			    permitted_opens[i].port_to_connect, ctype, rname);
3779181111Sdes		}
3780181111Sdes	}
378176262Sgreen	error("WARNING: Server requests forwarding for unknown listen_port %d",
378276262Sgreen	    listen_port);
3783181111Sdes	return NULL;
378476262Sgreen}
378576262Sgreen
3786295367SdesChannel *
3787295367Sdeschannel_connect_by_listen_path(const char *path, char *ctype, char *rname)
3788295367Sdes{
3789295367Sdes	int i;
3790295367Sdes
3791295367Sdes	for (i = 0; i < num_permitted_opens; i++) {
3792295367Sdes		if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
3793295367Sdes			return connect_to(
3794295367Sdes			    permitted_opens[i].host_to_connect,
3795295367Sdes			    permitted_opens[i].port_to_connect, ctype, rname);
3796295367Sdes		}
3797295367Sdes	}
3798295367Sdes	error("WARNING: Server requests forwarding for unknown path %.100s",
3799295367Sdes	    path);
3800295367Sdes	return NULL;
3801295367Sdes}
3802295367Sdes
380376262Sgreen/* Check if connecting to that port is permitted and connect. */
3804181111SdesChannel *
3805295367Sdeschannel_connect_to_port(const char *host, u_short port, char *ctype, char *rname)
380676262Sgreen{
3807162856Sdes	int i, permit, permit_adm = 1;
380876262Sgreen
380976262Sgreen	permit = all_opens_permitted;
381076262Sgreen	if (!permit) {
381176262Sgreen		for (i = 0; i < num_permitted_opens; i++)
3812295367Sdes			if (open_match(&permitted_opens[i], host, port)) {
381376262Sgreen				permit = 1;
3814295367Sdes				break;
3815295367Sdes			}
3816162856Sdes	}
381776262Sgreen
3818162856Sdes	if (num_adm_permitted_opens > 0) {
3819162856Sdes		permit_adm = 0;
3820162856Sdes		for (i = 0; i < num_adm_permitted_opens; i++)
3821295367Sdes			if (open_match(&permitted_adm_opens[i], host, port)) {
3822162856Sdes				permit_adm = 1;
3823295367Sdes				break;
3824295367Sdes			}
382576262Sgreen	}
3826162856Sdes
3827162856Sdes	if (!permit || !permit_adm) {
3828124207Sdes		logit("Received request to connect to host %.100s port %d, "
382976262Sgreen		    "but the request was denied.", host, port);
3830181111Sdes		return NULL;
383176262Sgreen	}
3832181111Sdes	return connect_to(host, port, ctype, rname);
383376262Sgreen}
383476262Sgreen
3835295367Sdes/* Check if connecting to that path is permitted and connect. */
3836295367SdesChannel *
3837295367Sdeschannel_connect_to_path(const char *path, char *ctype, char *rname)
3838295367Sdes{
3839295367Sdes	int i, permit, permit_adm = 1;
3840295367Sdes
3841295367Sdes	permit = all_opens_permitted;
3842295367Sdes	if (!permit) {
3843295367Sdes		for (i = 0; i < num_permitted_opens; i++)
3844295367Sdes			if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
3845295367Sdes				permit = 1;
3846295367Sdes				break;
3847295367Sdes			}
3848295367Sdes	}
3849295367Sdes
3850295367Sdes	if (num_adm_permitted_opens > 0) {
3851295367Sdes		permit_adm = 0;
3852295367Sdes		for (i = 0; i < num_adm_permitted_opens; i++)
3853295367Sdes			if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
3854295367Sdes				permit_adm = 1;
3855295367Sdes				break;
3856295367Sdes			}
3857295367Sdes	}
3858295367Sdes
3859295367Sdes	if (!permit || !permit_adm) {
3860295367Sdes		logit("Received request to connect to path %.100s, "
3861295367Sdes		    "but the request was denied.", path);
3862295367Sdes		return NULL;
3863295367Sdes	}
3864295367Sdes	return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
3865295367Sdes}
3866295367Sdes
3867137019Sdesvoid
3868137019Sdeschannel_send_window_changes(void)
3869137019Sdes{
3870137019Sdes	u_int i;
3871137019Sdes	struct winsize ws;
3872137019Sdes
3873137019Sdes	for (i = 0; i < channels_alloc; i++) {
3874147005Sdes		if (channels[i] == NULL || !channels[i]->client_tty ||
3875137019Sdes		    channels[i]->type != SSH_CHANNEL_OPEN)
3876137019Sdes			continue;
3877137019Sdes		if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
3878137019Sdes			continue;
3879137019Sdes		channel_request_start(i, "window-change", 0);
3880162856Sdes		packet_put_int((u_int)ws.ws_col);
3881162856Sdes		packet_put_int((u_int)ws.ws_row);
3882162856Sdes		packet_put_int((u_int)ws.ws_xpixel);
3883162856Sdes		packet_put_int((u_int)ws.ws_ypixel);
3884137019Sdes		packet_send();
3885137019Sdes	}
3886137019Sdes}
3887137019Sdes
388892559Sdes/* -- X11 forwarding */
388957429Smarkm
389057429Smarkm/*
389157429Smarkm * Creates an internet domain socket for listening for X11 connections.
389299063Sdes * Returns 0 and a suitable display number for the DISPLAY variable
389399063Sdes * stored in display_numberp , or -1 if an error occurs.
389457429Smarkm */
389592559Sdesint
389692559Sdesx11_create_display_inet(int x11_display_offset, int x11_use_localhost,
3897149753Sdes    int single_connection, u_int *display_numberp, int **chanids)
389857429Smarkm{
389992559Sdes	Channel *nc = NULL;
390057429Smarkm	int display_number, sock;
390157429Smarkm	u_short port;
390257429Smarkm	struct addrinfo hints, *ai, *aitop;
390357429Smarkm	char strport[NI_MAXSERV];
390457429Smarkm	int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
390557429Smarkm
3906157019Sdes	if (chanids == NULL)
3907157019Sdes		return -1;
3908157019Sdes
390957429Smarkm	for (display_number = x11_display_offset;
391092559Sdes	    display_number < MAX_DISPLAYS;
391192559Sdes	    display_number++) {
391257429Smarkm		port = 6000 + display_number;
391357429Smarkm		memset(&hints, 0, sizeof(hints));
391457429Smarkm		hints.ai_family = IPv4or6;
391592559Sdes		hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
391657429Smarkm		hints.ai_socktype = SOCK_STREAM;
391757429Smarkm		snprintf(strport, sizeof strport, "%d", port);
391857429Smarkm		if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
3919181111Sdes			error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
392092559Sdes			return -1;
392157429Smarkm		}
392257429Smarkm		for (ai = aitop; ai; ai = ai->ai_next) {
392357429Smarkm			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
392457429Smarkm				continue;
3925124207Sdes			sock = socket(ai->ai_family, ai->ai_socktype,
3926124207Sdes			    ai->ai_protocol);
392757429Smarkm			if (sock < 0) {
3928207319Sdes				if ((errno != EINVAL) && (errno != EAFNOSUPPORT)
3929207319Sdes#ifdef EPFNOSUPPORT
3930207319Sdes				    && (errno != EPFNOSUPPORT)
3931207319Sdes#endif
3932207319Sdes				    ) {
393398941Sdes					error("socket: %.100s", strerror(errno));
3934137019Sdes					freeaddrinfo(aitop);
393598941Sdes					return -1;
393698941Sdes				} else {
393798941Sdes					debug("x11_create_display_inet: Socket family %d not supported",
393898941Sdes						 ai->ai_family);
393998941Sdes					continue;
394098941Sdes				}
394157429Smarkm			}
3942204917Sdes			if (ai->ai_family == AF_INET6)
3943204917Sdes				sock_set_v6only(sock);
3944181111Sdes			if (x11_use_localhost)
3945181111Sdes				channel_set_reuseaddr(sock);
394657429Smarkm			if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
3947124207Sdes				debug2("bind port %d: %.100s", port, strerror(errno));
394857429Smarkm				close(sock);
394998941Sdes
395057429Smarkm				for (n = 0; n < num_socks; n++) {
395157429Smarkm					close(socks[n]);
395257429Smarkm				}
395357429Smarkm				num_socks = 0;
395457429Smarkm				break;
395557429Smarkm			}
395657429Smarkm			socks[num_socks++] = sock;
395757429Smarkm			if (num_socks == NUM_SOCKS)
395857429Smarkm				break;
395957429Smarkm		}
396076262Sgreen		freeaddrinfo(aitop);
396157429Smarkm		if (num_socks > 0)
396257429Smarkm			break;
396357429Smarkm	}
396457429Smarkm	if (display_number >= MAX_DISPLAYS) {
396557429Smarkm		error("Failed to allocate internet-domain X11 display socket.");
396692559Sdes		return -1;
396757429Smarkm	}
396857429Smarkm	/* Start listening for connections on the socket. */
396957429Smarkm	for (n = 0; n < num_socks; n++) {
397057429Smarkm		sock = socks[n];
3971126273Sdes		if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
397257429Smarkm			error("listen: %.100s", strerror(errno));
397357429Smarkm			close(sock);
397492559Sdes			return -1;
397557429Smarkm		}
397657429Smarkm	}
397757429Smarkm
397857429Smarkm	/* Allocate a channel for each socket. */
3979162856Sdes	*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
398057429Smarkm	for (n = 0; n < num_socks; n++) {
398157429Smarkm		sock = socks[n];
3982294693Sdes		nc = channel_new("x11 listener",
3983294693Sdes		    SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
3984294693Sdes		    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
3985294693Sdes		    0, "X11 inet listener", 1);
398692559Sdes		nc->single_connection = single_connection;
3987157019Sdes		(*chanids)[n] = nc->self;
398857429Smarkm	}
3989157019Sdes	(*chanids)[n] = -1;
399057429Smarkm
399192559Sdes	/* Return the display number for the DISPLAY environment variable. */
399299063Sdes	*display_numberp = display_number;
399399063Sdes	return (0);
399457429Smarkm}
399557429Smarkm
399692559Sdesstatic int
3997192595Sdesconnect_local_xsocket_path(const char *pathname)
399857429Smarkm{
399957429Smarkm	int sock;
400057429Smarkm	struct sockaddr_un addr;
400157429Smarkm
400292559Sdes	sock = socket(AF_UNIX, SOCK_STREAM, 0);
400392559Sdes	if (sock < 0)
400492559Sdes		error("socket: %.100s", strerror(errno));
400592559Sdes	memset(&addr, 0, sizeof(addr));
400692559Sdes	addr.sun_family = AF_UNIX;
4007192595Sdes	strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
4008162856Sdes	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
400992559Sdes		return sock;
401092559Sdes	close(sock);
401157429Smarkm	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
401257429Smarkm	return -1;
401357429Smarkm}
401457429Smarkm
4015192595Sdesstatic int
4016192595Sdesconnect_local_xsocket(u_int dnr)
4017192595Sdes{
4018192595Sdes	char buf[1024];
4019192595Sdes	snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
4020192595Sdes	return connect_local_xsocket_path(buf);
4021192595Sdes}
4022192595Sdes
402360573Skrisint
402460573Skrisx11_connect_display(void)
402557429Smarkm{
4026162856Sdes	u_int display_number;
402757429Smarkm	const char *display;
402860573Skris	char buf[1024], *cp;
402957429Smarkm	struct addrinfo hints, *ai, *aitop;
403057429Smarkm	char strport[NI_MAXSERV];
4031162856Sdes	int gaierr, sock = 0;
403257429Smarkm
403357429Smarkm	/* Try to open a socket for the local X server. */
403457429Smarkm	display = getenv("DISPLAY");
403557429Smarkm	if (!display) {
403657429Smarkm		error("DISPLAY not set.");
403760573Skris		return -1;
403857429Smarkm	}
403957429Smarkm	/*
404057429Smarkm	 * Now we decode the value of the DISPLAY variable and make a
404157429Smarkm	 * connection to the real X server.
404257429Smarkm	 */
404357429Smarkm
4044192595Sdes	/* Check if the display is from launchd. */
4045192595Sdes#ifdef __APPLE__
4046192595Sdes	if (strncmp(display, "/tmp/launch", 11) == 0) {
4047192595Sdes		sock = connect_local_xsocket_path(display);
4048192595Sdes		if (sock < 0)
4049192595Sdes			return -1;
4050192595Sdes
4051192595Sdes		/* OK, we now have a connection to the display. */
4052192595Sdes		return sock;
4053192595Sdes	}
4054192595Sdes#endif
405557429Smarkm	/*
405657429Smarkm	 * Check if it is a unix domain socket.  Unix domain displays are in
405757429Smarkm	 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
405857429Smarkm	 */
405957429Smarkm	if (strncmp(display, "unix:", 5) == 0 ||
406057429Smarkm	    display[0] == ':') {
406157429Smarkm		/* Connect to the unix domain socket. */
4062162856Sdes		if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
406357429Smarkm			error("Could not parse display number from DISPLAY: %.100s",
406492559Sdes			    display);
406560573Skris			return -1;
406657429Smarkm		}
406757429Smarkm		/* Create a socket. */
406857429Smarkm		sock = connect_local_xsocket(display_number);
406957429Smarkm		if (sock < 0)
407060573Skris			return -1;
407157429Smarkm
407257429Smarkm		/* OK, we now have a connection to the display. */
407360573Skris		return sock;
407457429Smarkm	}
407557429Smarkm	/*
407657429Smarkm	 * Connect to an inet socket.  The DISPLAY value is supposedly
407757429Smarkm	 * hostname:d[.s], where hostname may also be numeric IP address.
407857429Smarkm	 */
407992559Sdes	strlcpy(buf, display, sizeof(buf));
408057429Smarkm	cp = strchr(buf, ':');
408157429Smarkm	if (!cp) {
408257429Smarkm		error("Could not find ':' in DISPLAY: %.100s", display);
408360573Skris		return -1;
408457429Smarkm	}
408557429Smarkm	*cp = 0;
408657429Smarkm	/* buf now contains the host name.  But first we parse the display number. */
4087162856Sdes	if (sscanf(cp + 1, "%u", &display_number) != 1) {
408857429Smarkm		error("Could not parse display number from DISPLAY: %.100s",
408992559Sdes		    display);
409060573Skris		return -1;
409157429Smarkm	}
409257429Smarkm
409357429Smarkm	/* Look up the host address */
409457429Smarkm	memset(&hints, 0, sizeof(hints));
409557429Smarkm	hints.ai_family = IPv4or6;
409657429Smarkm	hints.ai_socktype = SOCK_STREAM;
4097162856Sdes	snprintf(strport, sizeof strport, "%u", 6000 + display_number);
409857429Smarkm	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
4099181111Sdes		error("%.100s: unknown host. (%s)", buf,
4100181111Sdes		ssh_gai_strerror(gaierr));
410160573Skris		return -1;
410257429Smarkm	}
410357429Smarkm	for (ai = aitop; ai; ai = ai->ai_next) {
410457429Smarkm		/* Create a socket. */
4105124207Sdes		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
410657429Smarkm		if (sock < 0) {
4107124207Sdes			debug2("socket: %.100s", strerror(errno));
410860573Skris			continue;
410960573Skris		}
411060573Skris		/* Connect it to the display. */
411160573Skris		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
4112162856Sdes			debug2("connect %.100s port %u: %.100s", buf,
411360573Skris			    6000 + display_number, strerror(errno));
411460573Skris			close(sock);
411560573Skris			continue;
411660573Skris		}
411760573Skris		/* Success */
411860573Skris		break;
411957429Smarkm	}
412057429Smarkm	freeaddrinfo(aitop);
412157429Smarkm	if (!ai) {
4122162856Sdes		error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
412357429Smarkm		    strerror(errno));
412460573Skris		return -1;
412557429Smarkm	}
412692559Sdes	set_nodelay(sock);
412760573Skris	return sock;
412860573Skris}
412957429Smarkm
413060573Skris/*
413160573Skris * This is called when SSH_SMSG_X11_OPEN is received.  The packet contains
413260573Skris * the remote channel number.  We should do whatever we want, and respond
413360573Skris * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
413460573Skris */
413557429Smarkm
4136162856Sdes/* ARGSUSED */
4137295367Sdesint
413892559Sdesx11_input_open(int type, u_int32_t seq, void *ctxt)
413960573Skris{
414092559Sdes	Channel *c = NULL;
414192559Sdes	int remote_id, sock = 0;
414260573Skris	char *remote_host;
414357429Smarkm
414492559Sdes	debug("Received X11 open request.");
414557429Smarkm
414692559Sdes	remote_id = packet_get_int();
414792559Sdes
414892559Sdes	if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) {
414992559Sdes		remote_host = packet_get_string(NULL);
415060573Skris	} else {
415160573Skris		remote_host = xstrdup("unknown (remote did not supply name)");
415260573Skris	}
415392559Sdes	packet_check_eom();
415460573Skris
415560573Skris	/* Obtain a connection to the real X display. */
415660573Skris	sock = x11_connect_display();
415792559Sdes	if (sock != -1) {
415892559Sdes		/* Allocate a channel for this connection. */
415992559Sdes		c = channel_new("connected x11 socket",
416092559Sdes		    SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0,
416192559Sdes		    remote_host, 1);
416292559Sdes		c->remote_id = remote_id;
416392559Sdes		c->force_drain = 1;
416492559Sdes	}
4165255767Sdes	free(remote_host);
416692559Sdes	if (c == NULL) {
416760573Skris		/* Send refusal to the remote host. */
416860573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
416992559Sdes		packet_put_int(remote_id);
417060573Skris	} else {
417160573Skris		/* Send a confirmation to the remote host. */
417260573Skris		packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
417392559Sdes		packet_put_int(remote_id);
417492559Sdes		packet_put_int(c->self);
417560573Skris	}
417692559Sdes	packet_send();
4177295367Sdes	return 0;
417857429Smarkm}
417957429Smarkm
418069587Sgreen/* dummy protocol handler that denies SSH-1 requests (agent/x11) */
4181162856Sdes/* ARGSUSED */
4182295367Sdesint
418392559Sdesdeny_input_open(int type, u_int32_t seq, void *ctxt)
418469587Sgreen{
418569587Sgreen	int rchan = packet_get_int();
4186106130Sdes
418792559Sdes	switch (type) {
418869587Sgreen	case SSH_SMSG_AGENT_OPEN:
418969587Sgreen		error("Warning: ssh server tried agent forwarding.");
419069587Sgreen		break;
419169587Sgreen	case SSH_SMSG_X11_OPEN:
419269587Sgreen		error("Warning: ssh server tried X11 forwarding.");
419369587Sgreen		break;
419469587Sgreen	default:
419592559Sdes		error("deny_input_open: type %d", type);
419669587Sgreen		break;
419769587Sgreen	}
4198157019Sdes	error("Warning: this is probably a break-in attempt by a malicious server.");
419969587Sgreen	packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
420069587Sgreen	packet_put_int(rchan);
420169587Sgreen	packet_send();
4202295367Sdes	return 0;
420369587Sgreen}
420469587Sgreen
420557429Smarkm/*
420657429Smarkm * Requests forwarding of X11 connections, generates fake authentication
420757429Smarkm * data, and enables authentication spoofing.
420892559Sdes * This should be called in the client only.
420957429Smarkm */
421060573Skrisvoid
4211149753Sdesx11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
4212226046Sdes    const char *proto, const char *data, int want_reply)
421357429Smarkm{
421476262Sgreen	u_int data_len = (u_int) strlen(data) / 2;
4215149753Sdes	u_int i, value;
421657429Smarkm	char *new_data;
421757429Smarkm	int screen_number;
421857429Smarkm	const char *cp;
4219137019Sdes	u_int32_t rnd = 0;
422057429Smarkm
4221149753Sdes	if (x11_saved_display == NULL)
4222149753Sdes		x11_saved_display = xstrdup(disp);
4223149753Sdes	else if (strcmp(disp, x11_saved_display) != 0) {
4224149753Sdes		error("x11_request_forwarding_with_spoofing: different "
4225149753Sdes		    "$DISPLAY already forwarded");
4226149753Sdes		return;
4227149753Sdes	}
4228149753Sdes
4229162856Sdes	cp = strchr(disp, ':');
423057429Smarkm	if (cp)
423157429Smarkm		cp = strchr(cp, '.');
423257429Smarkm	if (cp)
4233162856Sdes		screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
423457429Smarkm	else
423557429Smarkm		screen_number = 0;
423657429Smarkm
4237149753Sdes	if (x11_saved_proto == NULL) {
4238149753Sdes		/* Save protocol name. */
4239149753Sdes		x11_saved_proto = xstrdup(proto);
4240149753Sdes		/*
4241149753Sdes		 * Extract real authentication data and generate fake data
4242149753Sdes		 * of the same length.
4243149753Sdes		 */
4244149753Sdes		x11_saved_data = xmalloc(data_len);
4245149753Sdes		x11_fake_data = xmalloc(data_len);
4246149753Sdes		for (i = 0; i < data_len; i++) {
4247149753Sdes			if (sscanf(data + 2 * i, "%2x", &value) != 1)
4248149753Sdes				fatal("x11_request_forwarding: bad "
4249149753Sdes				    "authentication data: %.100s", data);
4250149753Sdes			if (i % 4 == 0)
4251149753Sdes				rnd = arc4random();
4252149753Sdes			x11_saved_data[i] = value;
4253149753Sdes			x11_fake_data[i] = rnd & 0xff;
4254149753Sdes			rnd >>= 8;
4255149753Sdes		}
4256149753Sdes		x11_saved_data_len = data_len;
4257149753Sdes		x11_fake_data_len = data_len;
425857429Smarkm	}
425957429Smarkm
426057429Smarkm	/* Convert the fake data into hex. */
4261149753Sdes	new_data = tohex(x11_fake_data, data_len);
426257429Smarkm
426357429Smarkm	/* Send the request packet. */
426460573Skris	if (compat20) {
4265226046Sdes		channel_request_start(client_session_id, "x11-req", want_reply);
426660573Skris		packet_put_char(0);	/* XXX bool single connection */
426760573Skris	} else {
426860573Skris		packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
426960573Skris	}
427060573Skris	packet_put_cstring(proto);
427160573Skris	packet_put_cstring(new_data);
427257429Smarkm	packet_put_int(screen_number);
427357429Smarkm	packet_send();
427457429Smarkm	packet_write_wait();
4275255767Sdes	free(new_data);
427657429Smarkm}
427757429Smarkm
427892559Sdes
427992559Sdes/* -- agent forwarding */
428092559Sdes
428157429Smarkm/* Sends a message to the server to request authentication fd forwarding. */
428257429Smarkm
428360573Skrisvoid
428492559Sdesauth_request_forwarding(void)
428557429Smarkm{
428657429Smarkm	packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
428757429Smarkm	packet_send();
428857429Smarkm	packet_write_wait();
428957429Smarkm}
4290