summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--auth-options.c11
-rw-r--r--auth.c3
-rw-r--r--channels.c3011
-rw-r--r--channels.h180
-rw-r--r--clientloop.c191
-rw-r--r--clientloop.h31
-rw-r--r--monitor.c5
-rw-r--r--monitor_wrap.c4
-rw-r--r--mux.c193
-rw-r--r--nchan.c114
-rw-r--r--packet.c68
-rw-r--r--packet.h8
-rw-r--r--servconf.c87
-rw-r--r--servconf.h14
-rw-r--r--serverloop.c105
-rw-r--r--serverloop.h6
-rw-r--r--session.c223
-rw-r--r--session.h16
-rw-r--r--ssh.c88
-rw-r--r--sshbuf.h3
-rw-r--r--sshconnect.c38
-rw-r--r--sshconnect.h8
-rw-r--r--sshd.c19
-rw-r--r--ssherr.c4
-rw-r--r--ssherr.h3
25 files changed, 2441 insertions, 1992 deletions
diff --git a/auth-options.c b/auth-options.c
index 0a191dbb..bed00eef 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.73 2017/05/31 10:54:00 markus Exp $ */
+/* $OpenBSD: auth-options.c,v 1.74 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,9 +61,13 @@ char *authorized_principals = NULL;
extern ServerOptions options;
+/* XXX refactor to be stateless */
+
void
auth_clear_options(void)
{
+ struct ssh *ssh = active_state; /* XXX */
+
no_agent_forwarding_flag = 0;
no_port_forwarding_flag = 0;
no_pty_flag = 0;
@@ -81,7 +85,7 @@ auth_clear_options(void)
free(authorized_principals);
authorized_principals = NULL;
forced_tun_device = -1;
- channel_clear_permitted_opens();
+ channel_clear_permitted_opens(ssh);
}
/*
@@ -117,6 +121,7 @@ match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
/*
* return 1 if access is granted, 0 if not.
* side effect: sets key option flags
+ * XXX remove side effects; fill structure instead.
*/
int
auth_parse_options(struct passwd *pw, char *opts, const char *file,
@@ -380,7 +385,7 @@ auth_parse_options(struct passwd *pw, char *opts, const char *file,
goto bad_option;
}
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
- channel_add_permitted_opens(host, port);
+ channel_add_permitted_opens(ssh, host, port);
free(patterns);
goto next_option;
}
diff --git a/auth.c b/auth.c
index 7f073e0f..a4490617 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.123 2017/08/18 05:36:45 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -567,6 +567,7 @@ getpwnamallow(const char *user)
ci->user = user;
parse_server_match_config(&options, ci);
log_change_level(options.log_level);
+ process_permitopen(ssh, &options);
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_setauthdb(user);
diff --git a/channels.c b/channels.c
index d9e81b5f..935625c7 100644
--- a/channels.c
+++ b/channels.c
@@ -55,26 +55,27 @@
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <netdb.h>
+#include <stdarg.h>
#ifdef HAVE_STDINT_H
-#include <stdint.h>
+ #include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
-#include <stdarg.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#include "ssh2.h"
#include "ssherr.h"
+#include "sshbuf.h"
#include "packet.h"
#include "log.h"
#include "misc.h"
-#include "buffer.h"
#include "channels.h"
#include "compat.h"
#include "canohost.h"
@@ -82,28 +83,19 @@
#include "authfd.h"
#include "pathnames.h"
-/* -- channel core */
-
-/*
- * Pointer to an array containing all allocated channels. The array is
- * dynamically extended as needed.
- */
-static Channel **channels = NULL;
-
-/*
- * Size of the channel array. All slots of the array must always be
- * initialized (at least the type field); unused slots set to NULL
- */
-static u_int channels_alloc = 0;
+/* -- agent forwarding */
+#define NUM_SOCKS 10
-/*
- * Maximum file descriptor value used in any of the channels. This is
- * updated in channel_new.
- */
-static int channel_max_fd = 0;
+/* -- tcp forwarding */
+/* special-case port number meaning allow any port */
+#define FWD_PERMIT_ANY_PORT 0
+/* special-case wildcard meaning allow any host */
+#define FWD_PERMIT_ANY_HOST "*"
-/* -- tcp forwarding */
+/* -- X11 forwarding */
+/* Maximum number of fake X11 displays to try. */
+#define MAX_DISPLAYS 1000
/*
* Data structure for storing which hosts are permitted for forward requests.
@@ -123,100 +115,150 @@ typedef struct {
Channel *downstream; /* Downstream mux*/
} ForwardPermission;
-/* List of all permitted host/port pairs to connect by the user. */
-static ForwardPermission *permitted_opens = NULL;
+typedef void chan_fn(struct ssh *, Channel *c,
+ fd_set *readset, fd_set *writeset);
-/* List of all permitted host/port pairs to connect by the admin. */
-static ForwardPermission *permitted_adm_opens = NULL;
-
-/* Number of permitted host/port pairs in the array permitted by the user. */
-static int num_permitted_opens = 0;
+/* Master structure for channels state */
+struct ssh_channels {
+ /*
+ * Pointer to an array containing all allocated channels. The array
+ * is dynamically extended as needed.
+ */
+ Channel **channels;
-/* Number of permitted host/port pair in the array permitted by the admin. */
-static int num_adm_permitted_opens = 0;
+ /*
+ * Size of the channel array. All slots of the array must always be
+ * initialized (at least the type field); unused slots set to NULL
+ */
+ u_int channels_alloc;
-/* special-case port number meaning allow any port */
-#define FWD_PERMIT_ANY_PORT 0
+ /*
+ * Maximum file descriptor value used in any of the channels. This is
+ * updated in channel_new.
+ */
+ int channel_max_fd;
-/* special-case wildcard meaning allow any host */
-#define FWD_PERMIT_ANY_HOST "*"
+ /*
+ * 'channel_pre*' are called just before select() to add any bits
+ * relevant to channels in the select bitmasks.
+ *
+ * 'channel_post*': perform any appropriate operations for
+ * channels which have events pending.
+ */
+ chan_fn **channel_pre;
+ chan_fn **channel_post;
-/*
- * If this is true, all opens are permitted. This is the case on the server
- * on which we have to trust the client anyway, and the user could do
- * anything after logging in anyway.
- */
-static int all_opens_permitted = 0;
+ /* -- tcp forwarding */
+ /* List of all permitted host/port pairs to connect by the user. */
+ ForwardPermission *permitted_opens;
-/* -- X11 forwarding */
+ /* List of all permitted host/port pairs to connect by the admin. */
+ ForwardPermission *permitted_adm_opens;
-/* Maximum number of fake X11 displays to try. */
-#define MAX_DISPLAYS 1000
+ /*
+ * Number of permitted host/port pairs in the array permitted by
+ * the user.
+ */
+ u_int num_permitted_opens;
-/* Saved X11 local (client) display. */
-static char *x11_saved_display = NULL;
+ /*
+ * Number of permitted host/port pair in the array permitted by
+ * the admin.
+ */
+ u_int num_adm_permitted_opens;
-/* Saved X11 authentication protocol name. */
-static char *x11_saved_proto = NULL;
+ /*
+ * If this is true, all opens are permitted. This is the case on
+ * the server on which we have to trust the client anyway, and the
+ * user could do anything after logging in anyway.
+ */
+ int all_opens_permitted;
-/* Saved X11 authentication data. This is the real data. */
-static char *x11_saved_data = NULL;
-static u_int x11_saved_data_len = 0;
+ /* -- X11 forwarding */
-/* Deadline after which all X11 connections are refused */
-static u_int x11_refuse_time;
+ /* Saved X11 local (client) display. */
+ char *x11_saved_display;
-/*
- * Fake X11 authentication data. This is what the server will be sending us;
- * we should replace any occurrences of this by the real data.
- */
-static u_char *x11_fake_data = NULL;
-static u_int x11_fake_data_len;
+ /* Saved X11 authentication protocol name. */
+ char *x11_saved_proto;
+ /* Saved X11 authentication data. This is the real data. */
+ char *x11_saved_data;
+ u_int x11_saved_data_len;
-/* -- agent forwarding */
+ /* Deadline after which all X11 connections are refused */
+ u_int x11_refuse_time;
-#define NUM_SOCKS 10
+ /*
+ * Fake X11 authentication data. This is what the server will be
+ * sending us; we should replace any occurrences of this by the
+ * real data.
+ */
+ u_char *x11_fake_data;
+ u_int x11_fake_data_len;
-/* AF_UNSPEC or AF_INET or AF_INET6 */
-static int IPv4or6 = AF_UNSPEC;
+ /* AF_UNSPEC or AF_INET or AF_INET6 */
+ int IPv4or6;
+};
/* helper */
-static void port_open_helper(Channel *c, char *rtype);
+static void port_open_helper(struct ssh *ssh, Channel *c, char *rtype);
static const char *channel_rfwd_bind_host(const char *listen_host);
/* non-blocking connect helpers */
static int connect_next(struct channel_connect *);
static void channel_connect_ctx_free(struct channel_connect *);
+/* Setup helper */
+static void channel_handler_init(struct ssh_channels *sc);
+
/* -- channel core */
+void
+channel_init_channels(struct ssh *ssh)
+{
+ struct ssh_channels *sc;
+
+ if ((sc = calloc(1, sizeof(*sc))) == NULL ||
+ (sc->channel_pre = calloc(SSH_CHANNEL_MAX_TYPE,
+ sizeof(*sc->channel_pre))) == NULL ||
+ (sc->channel_post = calloc(SSH_CHANNEL_MAX_TYPE,
+ sizeof(*sc->channel_post))) == NULL)
+ fatal("%s: allocation failed", __func__);
+ sc->channels_alloc = 10;
+ sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels));
+ sc->IPv4or6 = AF_UNSPEC;
+ channel_handler_init(sc);
+
+ ssh->chanctxt = sc;
+}
+
Channel *
-channel_by_id(int id)
+channel_by_id(struct ssh *ssh, int id)
{
Channel *c;
- if (id < 0 || (u_int)id >= channels_alloc) {
- logit("channel_by_id: %d: bad id", id);
+ if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) {
+ logit("%s: %d: bad id", __func__, id);
return NULL;
}
- c = channels[id];
+ c = ssh->chanctxt->channels[id];
if (c == NULL) {
- logit("channel_by_id: %d: bad id: channel free", id);
+ logit("%s: %d: bad id: channel free", __func__, id);
return NULL;
}
return c;
}
Channel *
-channel_by_remote_id(int remote_id)
+channel_by_remote_id(struct ssh *ssh, int remote_id)
{
Channel *c;
u_int i;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
if (c != NULL && c->remote_id == remote_id)
return c;
}
@@ -228,12 +270,12 @@ channel_by_remote_id(int remote_id)
* Private channels, like listening sockets, may not receive messages.
*/
Channel *
-channel_lookup(int id)
+channel_lookup(struct ssh *ssh, int id)
{
Channel *c;
- if ((c = channel_by_id(id)) == NULL)
- return (NULL);
+ if ((c = channel_by_id(ssh, id)) == NULL)
+ return NULL;
switch (c->type) {
case SSH_CHANNEL_X11_OPEN:
@@ -244,10 +286,10 @@ channel_lookup(int id)
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_ABANDONED:
case SSH_CHANNEL_MUX_PROXY:
- return (c);
+ return c;
}
logit("Non-public channel %d, type %d.", id, c->type);
- return (NULL);
+ return NULL;
}
/*
@@ -255,13 +297,15 @@ channel_lookup(int id)
* when the channel consumer/producer is ready, e.g. shell exec'd
*/
static void
-channel_register_fds(Channel *c, int rfd, int wfd, int efd,
+channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
int extusage, int nonblock, int is_tty)
{
+ struct ssh_channels *sc = ssh->chanctxt;
+
/* Update the maximum file descriptor value. */
- channel_max_fd = MAXIMUM(channel_max_fd, rfd);
- channel_max_fd = MAXIMUM(channel_max_fd, wfd);
- channel_max_fd = MAXIMUM(channel_max_fd, efd);
+ sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);
+ sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);
+ sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);
if (rfd != -1)
fcntl(rfd, F_SETFD, FD_CLOEXEC);
@@ -299,190 +343,221 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
* remote_name to be freed.
*/
Channel *
-channel_new(char *ctype, int type, int rfd, int wfd, int efd,
+channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
{
- int found;
- u_int i;
+ struct ssh_channels *sc = ssh->chanctxt;
+ u_int i, found;
Channel *c;
- /* Do initial allocation if this is the first call. */
- if (channels_alloc == 0) {
- channels_alloc = 10;
- channels = xcalloc(channels_alloc, sizeof(Channel *));
- for (i = 0; i < channels_alloc; i++)
- channels[i] = NULL;
- }
/* Try to find a free slot where to put the new channel. */
- for (found = -1, i = 0; i < channels_alloc; i++)
- if (channels[i] == NULL) {
+ for (i = 0; i < sc->channels_alloc; i++) {
+ if (sc->channels[i] == NULL) {
/* Found a free slot. */
- found = (int)i;
+ found = i;
break;
}
- if (found < 0) {
- /* There are no free slots. Take last+1 slot and expand the array. */
- found = channels_alloc;
- if (channels_alloc > 10000)
- fatal("channel_new: internal error: channels_alloc %d "
- "too big.", channels_alloc);
- channels = xreallocarray(channels, channels_alloc + 10,
- sizeof(Channel *));
- channels_alloc += 10;
- debug2("channel: expanding %d", channels_alloc);
- for (i = found; i < channels_alloc; i++)
- channels[i] = NULL;
+ }
+ if (i >= sc->channels_alloc) {
+ /*
+ * There are no free slots. Take last+1 slot and expand
+ * the array.
+ */
+ found = sc->channels_alloc;
+ if (sc->channels_alloc > CHANNELS_MAX_CHANNELS)
+ fatal("%s: internal error: channels_alloc %d too big",
+ __func__, sc->channels_alloc);
+ sc->channels = xrecallocarray(sc->channels, sc->channels_alloc,
+ sc->channels_alloc + 10, sizeof(*sc->channels));
+ sc->channels_alloc += 10;
+ debug2("channel: expanding %d", sc->channels_alloc);
}
/* Initialize and return new channel. */
- c = channels[found] = xcalloc(1, sizeof(Channel));
- buffer_init(&c->input);
- buffer_init(&c->output);
- buffer_init(&c->extended);
- c->path = NULL;
- c->listening_addr = NULL;
- c->listening_port = 0;
+ c = sc->channels[found] = xcalloc(1, sizeof(Channel));
+ if ((c->input = sshbuf_new()) == NULL ||
+ (c->output = sshbuf_new()) == NULL ||
+ (c->extended = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
c->ostate = CHAN_OUTPUT_OPEN;
c->istate = CHAN_INPUT_OPEN;
- c->flags = 0;
- channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
- c->notbefore = 0;
+ channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0);
c->self = found;
c->type = type;
c->ctype = ctype;
c->local_window = window;
c->local_window_max = window;
- c->local_consumed = 0;
c->local_maxpacket = maxpack;
c->remote_id = -1;
c->remote_name = xstrdup(remote_name);
- c->remote_window = 0;
- c->remote_maxpacket = 0;
- c->force_drain = 0;
- c->single_connection = 0;
- c->detach_user = NULL;
- c->detach_close = 0;
- c->open_confirm = NULL;
- c->open_confirm_ctx = NULL;
- c->input_filter = NULL;
- c->output_filter = NULL;
- c->filter_ctx = NULL;
- c->filter_cleanup = NULL;
c->ctl_chan = -1;
- c->mux_rcb = NULL;
- c->mux_ctx = NULL;
- c->mux_pause = 0;
c->delayed = 1; /* prevent call to channel_post handler */
TAILQ_INIT(&c->status_confirms);
debug("channel %d: new [%s]", found, remote_name);
return c;
}
-static int
-channel_find_maxfd(void)
+static void
+channel_find_maxfd(struct ssh_channels *sc)
{
u_int i;
int max = 0;
Channel *c;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ for (i = 0; i < sc->channels_alloc; i++) {
+ c = sc->channels[i];
if (c != NULL) {
max = MAXIMUM(max, c->rfd);
max = MAXIMUM(max, c->wfd);
max = MAXIMUM(max, c->efd);
}
}
- return max;
+ sc->channel_max_fd = max;
}
int
-channel_close_fd(int *fdp)
+channel_close_fd(struct ssh *ssh, int *fdp)
{
+ struct ssh_channels *sc = ssh->chanctxt;
int ret = 0, fd = *fdp;
if (fd != -1) {
ret = close(fd);
*fdp = -1;
- if (fd == channel_max_fd)
- channel_max_fd = channel_find_maxfd();
+ if (fd == sc->channel_max_fd)
+ channel_find_maxfd(sc);
}
return ret;
}
/* Close all channel fd/socket. */
static void
-channel_close_fds(Channel *c)
+channel_close_fds(struct ssh *ssh, Channel *c)
+{
+ channel_close_fd(ssh, &c->sock);
+ channel_close_fd(ssh, &c->rfd);
+ channel_close_fd(ssh, &c->wfd);
+ channel_close_fd(ssh, &c->efd);
+}
+
+static void
+fwd_perm_clear(ForwardPermission *fp)
+{
+ free(fp->host_to_connect);
+ free(fp->listen_host);
+ free(fp->listen_path);
+ bzero(fp, sizeof(*fp));
+}
+
+enum { FWDPERM_USER, FWDPERM_ADMIN };
+
+static int
+fwd_perm_list_add(struct ssh *ssh, int which,
+ const char *host_to_connect, int port_to_connect,
+ const char *listen_host, const char *listen_path, int listen_port,
+ Channel *downstream)
+{
+ ForwardPermission **fpl;
+ u_int n, *nfpl;
+
+ switch (which) {
+ case FWDPERM_USER:
+ fpl = &ssh->chanctxt->permitted_opens;
+ nfpl = &ssh->chanctxt->num_permitted_opens;
+ break;
+ case FWDPERM_ADMIN:
+ fpl = &ssh->chanctxt->permitted_adm_opens;
+ nfpl = &ssh->chanctxt->num_adm_permitted_opens;
+ break;
+ default:
+ fatal("%s: invalid list %d", __func__, which);
+ }
+
+ if (*nfpl >= INT_MAX)
+ fatal("%s: overflow", __func__);
+
+ *fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl));
+ n = (*nfpl)++;
+#define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s))
+ (*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect);
+ (*fpl)[n].port_to_connect = port_to_connect;
+ (*fpl)[n].listen_host = MAYBE_DUP(listen_host);
+ (*fpl)[n].listen_path = MAYBE_DUP(listen_path);
+ (*fpl)[n].listen_port = listen_port;
+ (*fpl)[n].downstream = downstream;
+#undef MAYBE_DUP
+ return (int)n;
+}
+
+static void
+mux_remove_remote_forwardings(struct ssh *ssh, Channel *c)
{
- channel_close_fd(&c->sock);
- channel_close_fd(&c->rfd);
- channel_close_fd(&c->wfd);
- channel_close_fd(&c->efd);
+ struct ssh_channels *sc = ssh->chanctxt;
+ ForwardPermission *fp;
+ int r;
+ u_int i;
+
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (fp->downstream != c)
+ continue;
+
+ /* cancel on the server, since mux client is gone */
+ debug("channel %d: cleanup remote forward for %s:%u",
+ c->self, fp->listen_host, fp->listen_port);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+ (r = sshpkt_put_cstring(ssh,
+ "cancel-tcpip-forward")) != 0 ||
+ (r = sshpkt_put_u8(ssh, 0)) != 0 ||
+ (r = sshpkt_put_cstring(ssh,
+ channel_rfwd_bind_host(fp->listen_host))) != 0 ||
+ (r = sshpkt_put_u32(ssh, fp->listen_port)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ fatal("%s: channel %i: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ fwd_perm_clear(fp); /* unregister */
+ }
}
/* Free the channel and close its fd/socket. */
void
-channel_free(Channel *c)
+channel_free(struct ssh *ssh, Channel *c)
{
+ struct ssh_channels *sc = ssh->chanctxt;
char *s;
u_int i, n;
Channel *other;
struct channel_confirm *cc;
- for (n = 0, i = 0; i < channels_alloc; i++) {
- if ((other = channels[i]) != NULL) {
- n++;
-
- /* detach from mux client and prepare for closing */
- if (c->type == SSH_CHANNEL_MUX_CLIENT &&
- other->type == SSH_CHANNEL_MUX_PROXY &&
- other->mux_ctx == c) {
- other->mux_ctx = NULL;
- other->type = SSH_CHANNEL_OPEN;
- other->istate = CHAN_INPUT_CLOSED;
- other->ostate = CHAN_OUTPUT_CLOSED;
- }
+ for (n = 0, i = 0; i < sc->channels_alloc; i++) {
+ if ((other = sc->channels[i]) == NULL)
+ continue;
+ n++;
+ /* detach from mux client and prepare for closing */
+ if (c->type == SSH_CHANNEL_MUX_CLIENT &&
+ other->type == SSH_CHANNEL_MUX_PROXY &&
+ other->mux_ctx == c) {
+ other->mux_ctx = NULL;
+ other->type = SSH_CHANNEL_OPEN;
+ other->istate = CHAN_INPUT_CLOSED;
+ other->ostate = CHAN_OUTPUT_CLOSED;
}
}
debug("channel %d: free: %s, nchannels %u", c->self,
c->remote_name ? c->remote_name : "???", n);
- /* XXX more MUX cleanup: remove remote forwardings */
- if (c->type == SSH_CHANNEL_MUX_CLIENT) {
- for (i = 0; i < (u_int)num_permitted_opens; i++) {
- if (permitted_opens[i].downstream != c)
- continue;
- /* cancel on the server, since mux client is gone */
- debug("channel %d: cleanup remote forward for %s:%u",
- c->self,
- permitted_opens[i].listen_host,
- permitted_opens[i].listen_port);
- packet_start(SSH2_MSG_GLOBAL_REQUEST);
- packet_put_cstring("cancel-tcpip-forward");
- packet_put_char(0);
- packet_put_cstring(channel_rfwd_bind_host(
- permitted_opens[i].listen_host));
- packet_put_int(permitted_opens[i].listen_port);
- packet_send();
- /* unregister */
- permitted_opens[i].listen_port = 0;
- permitted_opens[i].port_to_connect = 0;
- free(permitted_opens[i].host_to_connect);
- permitted_opens[i].host_to_connect = NULL;
- free(permitted_opens[i].listen_host);
- permitted_opens[i].listen_host = NULL;
- permitted_opens[i].listen_path = NULL;
- permitted_opens[i].downstream = NULL;
- }
- }
+ if (c->type == SSH_CHANNEL_MUX_CLIENT)
+ mux_remove_remote_forwardings(ssh, c);
- s = channel_open_message();
+ s = channel_open_message(ssh);
debug3("channel %d: status: %s", c->self, s);
free(s);
- channel_close_fds(c);
- buffer_free(&c->input);
- buffer_free(&c->output);
- buffer_free(&c->extended);
+ channel_close_fds(ssh, c);
+ sshbuf_free(c->input);
+ sshbuf_free(c->output);
+ sshbuf_free(c->extended);
+ c->input = c->output = c->extended = NULL;
free(c->remote_name);
c->remote_name = NULL;
free(c->path);
@@ -491,25 +566,26 @@ channel_free(Channel *c)
c->listening_addr = NULL;
while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
if (cc->abandon_cb != NULL)
- cc->abandon_cb(c, cc->ctx);
+ cc->abandon_cb(ssh, c, cc->ctx);
TAILQ_REMOVE(&c->status_confirms, cc, entry);
explicit_bzero(cc, sizeof(*cc));
free(cc);
}
if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
- c->filter_cleanup(c->self, c->filter_ctx);
- channels[c->self] = NULL;
+ c->filter_cleanup(ssh, c->self, c->filter_ctx);
+ sc->channels[c->self] = NULL;
+ bzero(c, sizeof(*c));
free(c);
}
void
-channel_free_all(void)
+channel_free_all(struct ssh *ssh)
{
u_int i;
- for (i = 0; i < channels_alloc; i++)
- if (channels[i] != NULL)
- channel_free(channels[i]);
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++)
+ if (ssh->chanctxt->channels[i] != NULL)
+ channel_free(ssh, ssh->chanctxt->channels[i]);
}
/*
@@ -517,26 +593,26 @@ channel_free_all(void)
* descriptors after a fork.
*/
void
-channel_close_all(void)
+channel_close_all(struct ssh *ssh)
{
u_int i;
- for (i = 0; i < channels_alloc; i++)
- if (channels[i] != NULL)
- channel_close_fds(channels[i]);
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++)
+ if (ssh->chanctxt->channels[i] != NULL)
+ channel_close_fds(ssh, ssh->chanctxt->channels[i]);
}
/*
* Stop listening to channels.
*/
void
-channel_stop_listening(void)
+channel_stop_listening(struct ssh *ssh)
{
u_int i;
Channel *c;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
if (c != NULL) {
switch (c->type) {
case SSH_CHANNEL_AUTH_SOCKET:
@@ -545,8 +621,8 @@ channel_stop_listening(void)
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
- channel_close_fd(&c->sock);
- channel_free(c);
+ channel_close_fd(ssh, &c->sock);
+ channel_free(ssh, c);
break;
}
}
@@ -558,20 +634,20 @@ channel_stop_listening(void)
* more channel is overfull.
*/
int
-channel_not_very_much_buffered_data(void)
+channel_not_very_much_buffered_data(struct ssh *ssh)
{
u_int i;
+ u_int maxsize = ssh_packet_get_maxsize(ssh);
Channel *c;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
- if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
- if (buffer_len(&c->output) > packet_get_maxsize()) {
- debug2("channel %d: big output buffer %u > %u",
- c->self, buffer_len(&c->output),
- packet_get_maxsize());
- return 0;
- }
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
+ if (c == NULL || c->type != SSH_CHANNEL_OPEN)
+ continue;
+ if (sshbuf_len(c->output) > maxsize) {
+ debug2("channel %d: big output buffer %zu > %u",
+ c->self, sshbuf_len(c->output), maxsize);
+ return 0;
}
}
return 1;
@@ -579,13 +655,13 @@ channel_not_very_much_buffered_data(void)
/* Returns true if any channel is still open. */
int
-channel_still_open(void)
+channel_still_open(struct ssh *ssh)
{
u_int i;
Channel *c;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
if (c == NULL)
continue;
switch (c->type) {
@@ -620,13 +696,13 @@ channel_still_open(void)
/* Returns the id of an open channel suitable for keepaliving */
int
-channel_find_open(void)
+channel_find_open(struct ssh *ssh)
{
u_int i;
Channel *c;
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
if (c == NULL || c->remote_id < 0)
continue;
switch (c->type) {
@@ -664,18 +740,21 @@ channel_find_open(void)
* newlines.
*/
char *
-channel_open_message(void)
+channel_open_message(struct ssh *ssh)
{
- Buffer buffer;
+ struct sshbuf *buf;
Channel *c;
- char buf[1024], *cp;
u_int i;
-
- buffer_init(&buffer);
- snprintf(buf, sizeof buf, "The following connections are open:\r\n");
- buffer_append(&buffer, buf, strlen(buf));
- for (i = 0; i < channels_alloc; i++) {
- c = channels[i];
+ int r;
+ char *ret;
+
+ if ((buf = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new", __func__);
+ if ((r = sshbuf_putf(buf,
+ "The following connections are open:\r\n")) != 0)
+ fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r));
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ c = ssh->chanctxt->channels[i];
if (c == NULL)
continue;
switch (c->type) {
@@ -698,69 +777,85 @@ channel_open_message(void)
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_MUX_PROXY:
case SSH_CHANNEL_MUX_CLIENT:
- snprintf(buf, sizeof buf,
- " #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
+ if ((r = sshbuf_putf(buf, " #%d %.300s "
+ "(t%d r%d i%u/%zu o%u/%zu fd %d/%d cc %d)\r\n",
c->self, c->remote_name,
c->type, c->remote_id,
- c->istate, buffer_len(&c->input),
- c->ostate, buffer_len(&c->output),
- c->rfd, c->wfd, c->ctl_chan);
- buffer_append(&buffer, buf, strlen(buf));
+ c->istate, sshbuf_len(c->input),
+ c->ostate, sshbuf_len(c->output),
+ c->rfd, c->wfd, c->ctl_chan)) != 0)
+ fatal("%s: sshbuf_putf: %s",
+ __func__, ssh_err(r));
continue;
default:
- fatal("channel_open_message: bad channel type %d", c->type);
+ fatal("%s: bad channel type %d", __func__, c->type);
/* NOTREACHED */
}
}
- buffer_append(&buffer, "\0", 1);
- cp = xstrdup((char *)buffer_ptr(&buffer));
- buffer_free(&buffer);
- return cp;
+ if ((ret = sshbuf_dup_string(buf)) == NULL)
+ fatal("%s: sshbuf_dup_string", __func__);
+ sshbuf_free(buf);
+ return ret;
+}
+
+static void
+open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type)
+{
+ int r;
+
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL