summaryrefslogtreecommitdiff
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_OPEN)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, type)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
+ fatal("%s: channel %i: open: %s", where, c->self, ssh_err(r));
+ }
}
void
-channel_send_open(int id)
+channel_send_open(struct ssh *ssh, int id)
{
- Channel *c = channel_lookup(id);
+ Channel *c = channel_lookup(ssh, id);
+ int r;
if (c == NULL) {
logit("channel_send_open: %d: bad id", id);
return;
}
debug2("channel %d: send open", id);
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring(c->ctype);
- packet_put_int(c->self);
- packet_put_int(c->local_window);
- packet_put_int(c->local_maxpacket);
- packet_send();
+ open_preamble(ssh, __func__, c, c->ctype);
+ if ((r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
}
void
-channel_request_start(int id, char *service, int wantconfirm)
+channel_request_start(struct ssh *ssh, int id, char *service, int wantconfirm)
{
- Channel *c = channel_lookup(id);
+ Channel *c = channel_lookup(ssh, id);
+ int r;
if (c == NULL) {
- logit("channel_request_start: %d: unknown channel id", id);
+ logit("%s: %d: unknown channel id", __func__, id);
return;
}
debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
- packet_start(SSH2_MSG_CHANNEL_REQUEST);
- packet_put_int(c->remote_id);
- packet_put_cstring(service);
- packet_put_char(wantconfirm);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, service)) != 0 ||
+ (r = sshpkt_put_u8(ssh, wantconfirm)) != 0) {
+ fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
+ }
}
void
-channel_register_status_confirm(int id, channel_confirm_cb *cb,
- channel_confirm_abandon_cb *abandon_cb, void *ctx)
+channel_register_status_confirm(struct ssh *ssh, int id,
+ channel_confirm_cb *cb, channel_confirm_abandon_cb *abandon_cb, void *ctx)
{
struct channel_confirm *cc;
Channel *c;
- if ((c = channel_lookup(id)) == NULL)
- fatal("channel_register_expect: %d: bad id", id);
+ if ((c = channel_lookup(ssh, id)) == NULL)
+ fatal("%s: %d: bad id", __func__, id);
cc = xcalloc(1, sizeof(*cc));
cc->cb = cb;
@@ -770,12 +865,13 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb,
}
void
-channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
+channel_register_open_confirm(struct ssh *ssh, int id,
+ channel_open_fn *fn, void *ctx)
{
- Channel *c = channel_lookup(id);
+ Channel *c = channel_lookup(ssh, id);
if (c == NULL) {
- logit("channel_register_open_confirm: %d: bad id", id);
+ logit("%s: %d: bad id", __func__, id);
return;
}
c->open_confirm = fn;
@@ -783,12 +879,13 @@ channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
}
void
-channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
+channel_register_cleanup(struct ssh *ssh, int id,
+ channel_callback_fn *fn, int do_close)
{
- Channel *c = channel_by_id(id);
+ Channel *c = channel_by_id(ssh, id);
if (c == NULL) {
- logit("channel_register_cleanup: %d: bad id", id);
+ logit("%s: %d: bad id", __func__, id);
return;
}
c->detach_user = fn;
@@ -796,12 +893,12 @@ channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
}
void
-channel_cancel_cleanup(int id)
+channel_cancel_cleanup(struct ssh *ssh, int id)
{
- Channel *c = channel_by_id(id);
+ Channel *c = channel_by_id(ssh, id);
if (c == NULL) {
- logit("channel_cancel_cleanup: %d: bad id", id);
+ logit("%s: %d: bad id", __func__, id);
return;
}
c->detach_user = NULL;
@@ -809,13 +906,13 @@ channel_cancel_cleanup(int id)
}
void
-channel_register_filter(int id, channel_infilter_fn *ifn,
+channel_register_filter(struct ssh *ssh, int id, channel_infilter_fn *ifn,
channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
{
- Channel *c = channel_lookup(id);
+ Channel *c = channel_lookup(ssh, id);
if (c == NULL) {
- logit("channel_register_filter: %d: bad id", id);
+ logit("%s: %d: bad id", __func__, id);
return;
}
c->input_filter = ifn;
@@ -825,79 +922,72 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
}
void
-channel_set_fds(int id, int rfd, int wfd, int efd,
+channel_set_fds(struct ssh *ssh, int id, int rfd, int wfd, int efd,
int extusage, int nonblock, int is_tty, u_int window_max)
{
- Channel *c = channel_lookup(id);
+ Channel *c = channel_lookup(ssh, id);
+ int r;
if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
fatal("channel_activate for non-larval channel %d.", id);
- channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
+ channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty);
c->type = SSH_CHANNEL_OPEN;
c->local_window = c->local_window_max = window_max;
- packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
- packet_put_int(c->remote_id);
- packet_put_int(c->local_window);
- packet_send();
-}
-/*
- * '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.
- */
-typedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
-chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
-chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
+}
-/* ARGSUSED */
static void
-channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_listener(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
FD_SET(c->sock, readset);
}
-/* ARGSUSED */
static void
-channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_connecting(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
debug3("channel %d: waiting for connection", c->self);
FD_SET(c->sock, writeset);
}
static void
-channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_open(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
if (c->istate == CHAN_INPUT_OPEN &&
c->remote_window > 0 &&
- buffer_len(&c->input) < c->remote_window &&
- buffer_check_alloc(&c->input, CHAN_RBUF))
+ sshbuf_len(c->input) < c->remote_window &&
+ sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
FD_SET(c->rfd, readset);
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- if (buffer_len(&c->output) > 0) {
+ if (sshbuf_len(c->output) > 0) {
FD_SET(c->wfd, writeset);
} else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
- debug2("channel %d: obuf_empty delayed efd %d/(%d)",
- c->self, c->efd, buffer_len(&c->extended));
+ debug2("channel %d: "
+ "obuf_empty delayed efd %d/(%zu)", c->self,
+ c->efd, sshbuf_len(c->extended));
else
- chan_obuf_empty(c);
+ chan_obuf_empty(ssh, c);
}
}
/** XXX check close conditions, too */
if (c->efd != -1 && !(c->istate == CHAN_INPUT_CLOSED &&
c->ostate == CHAN_OUTPUT_CLOSED)) {
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
- buffer_len(&c->extended) > 0)
+ sshbuf_len(c->extended) > 0)
FD_SET(c->efd, writeset);
else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
(c->extended_usage == CHAN_EXTENDED_READ ||
c->extended_usage == CHAN_EXTENDED_IGNORE) &&
- buffer_len(&c->extended) < c->remote_window)
+ sshbuf_len(c->extended) < c->remote_window)
FD_SET(c->efd, readset);
}
/* XXX: What about efd? races? */
@@ -913,24 +1003,26 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
* Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
*/
static int
-x11_open_helper(Buffer *b)
+x11_open_helper(struct ssh *ssh, struct sshbuf *b)
{
+ struct ssh_channels *sc = ssh->chanctxt;
u_char *ucp;
u_int proto_len, data_len;
/* Is this being called after the refusal deadline? */
- if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
+ if (sc->x11_refuse_time != 0 &&
+ (u_int)monotime() >= sc->x11_refuse_time) {
verbose("Rejected X11 connection after ForwardX11Timeout "
"expired");
return -1;
}
/* Check if the fixed size part of the packet is in buffer. */
- if (buffer_len(b) < 12)
+ if (sshbuf_len(b) < 12)
return 0;
/* Parse the lengths of variable-length fields. */
- ucp = buffer_ptr(b);
+ ucp = sshbuf_mutable_ptr(b);
if (ucp[0] == 0x42) { /* Byte order MSB first. */
proto_len = 256 * ucp[6] + ucp[7];
data_len = 256 * ucp[8] + ucp[9];
@@ -944,27 +1036,27 @@ x11_open_helper(Buffer *b)
}
/* Check if the whole packet is in buffer. */
- if (buffer_len(b) <
+ if (sshbuf_len(b) <
12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
return 0;
/* Check if authentication protocol matches. */
- if (proto_len != strlen(x11_saved_proto) ||
- memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
+ if (proto_len != strlen(sc->x11_saved_proto) ||
+ memcmp(ucp + 12, sc->x11_saved_proto, proto_len) != 0) {
debug2("X11 connection uses different authentication protocol.");
return -1;
}
/* Check if authentication data matches our fake data. */
- if (data_len != x11_fake_data_len ||
+ if (data_len != sc->x11_fake_data_len ||
timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
- x11_fake_data, x11_fake_data_len) != 0) {
+ sc->x11_fake_data, sc->x11_fake_data_len) != 0) {
debug2("X11 auth data does not match fake data.");
return -1;
}
/* Check fake data length */
- if (x11_fake_data_len != x11_saved_data_len) {
+ if (sc->x11_fake_data_len != sc->x11_saved_data_len) {
error("X11 fake_data_len %d != saved_data_len %d",
- x11_fake_data_len, x11_saved_data_len);
+ sc->x11_fake_data_len, sc->x11_saved_data_len);
return -1;
}
/*
@@ -973,60 +1065,64 @@ x11_open_helper(Buffer *b)
* data.
*/
memcpy(ucp + 12 + ((proto_len + 3) & ~3),
- x11_saved_data, x11_saved_data_len);
+ sc->x11_saved_data, sc->x11_saved_data_len);
return 1;
}
static void
-channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_x11_open(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
- int ret = x11_open_helper(&c->output);
+ int ret = x11_open_helper(ssh, c->output);
/* c->force_drain = 1; */
if (ret == 1) {
c->type = SSH_CHANNEL_OPEN;
- channel_pre_open(c, readset, writeset);
+ channel_pre_open(ssh, c, readset, writeset);
} else if (ret == -1) {
logit("X11 connection rejected because of wrong authentication.");
- debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
- chan_read_failed(c);
- buffer_clear(&c->input);
- chan_ibuf_empty(c);
- buffer_clear(&c->output);
- chan_write_failed(c);
+ debug2("X11 rejected %d i%d/o%d",
+ c->self, c->istate, c->ostate);
+ chan_read_failed(ssh, c);
+ sshbuf_reset(c->input);
+ chan_ibuf_empty(ssh, c);
+ sshbuf_reset(c->output);
+ chan_write_failed(ssh, c);
debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
}
}
static void
-channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_mux_client(struct ssh *ssh,
+ Channel *c, fd_set *readset, fd_set *writeset)
{
if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
- buffer_check_alloc(&c->input, CHAN_RBUF))
+ sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
FD_SET(c->rfd, readset);
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
/* clear buffer immediately (discard any partial packet) */
- buffer_clear(&c->input);
- chan_ibuf_empty(c);
+ sshbuf_reset(c->input);
+ chan_ibuf_empty(ssh, c);
/* Start output drain. XXX just kill chan? */
- chan_rcvd_oclose(c);
+ chan_rcvd_oclose(ssh, c);
}
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- if (buffer_len(&c->output) > 0)
+ if (sshbuf_len(c->output) > 0)
FD_SET(c->wfd, writeset);
else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
- chan_obuf_empty(c);
+ chan_obuf_empty(ssh, c);
}
}
/* try to decode a socks4 header */
-/* ARGSUSED */
static int
-channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
+channel_decode_socks4(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
- char *p, *host;
+ const u_char *p;
+ char *host;
u_int len, have, i, found, need;
char username[256];
struct {
@@ -1035,14 +1131,15 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
u_int16_t dest_port;
struct in_addr dest_addr;
} s4_req, s4_rsp;
+ int r;
debug2("channel %d: decode socks4", c->self);
- have = buffer_len(&c->input);
+ have = sshbuf_len(c->input);
len = sizeof(s4_req);
if (have < len)
return 0;
- p = (char *)buffer_ptr(&c->input);
+ p = sshbuf_ptr(c->input);
need = 1;
/* SOCKS4A uses an invalid IP address 0.0.0.x */
@@ -1067,12 +1164,15 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
}
if (found < need)
return 0;
- buffer_get(&c->input, (char *)&s4_req.version, 1);
- buffer_get(&c->input, (char *)&s4_req.command, 1);
- buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
- buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
- have = buffer_len(&c->input);
- p = (char *)buffer_ptr(&c->input);
+ if ((r = sshbuf_get(c->input, &s4_req.version, 1)) != 0 ||
+ (r = sshbuf_get(c->input, &s4_req.command, 1)) != 0 ||
+ (r = sshbuf_get(c->input, &s4_req.dest_port, 2)) != 0 ||
+ (r = sshbuf_get(c->input, &s4_req.dest_addr, 4)) != 0) {
+ debug("channels %d: decode socks4: %s", c->self, ssh_err(r));
+ return -1;
+ }
+ have = sshbuf_len(c->input);
+ p = sshbuf_ptr(c->input);
if (memchr(p, '\0', have) == NULL) {
error("channel %d: decode socks4: user not nul terminated",
c->self);
@@ -1080,21 +1180,20 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
}
len = strlen(p);
debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
- len++; /* trailing '\0' */
- if (len > have)
- fatal("channel %d: decode socks4: len %d > have %d",
- c->self, len, have);
+ len++; /* trailing '\0' */
strlcpy(username, p, sizeof(username));
- buffer_consume(&c->input, len);
-
+ if ((r = sshbuf_consume(c->input, len)) != 0) {
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+ }
free(c->path);
c->path = NULL;
if (need == 1) { /* SOCKS4: one string */
host = inet_ntoa(s4_req.dest_addr);
c->path = xstrdup(host);
} else { /* SOCKS4A: two strings */
- have = buffer_len(&c->input);
- p = (char *)buffer_ptr(&c->input);
+ have = sshbuf_len(c->input);
+ p = sshbuf_ptr(c->input);
if (memchr(p, '\0', have) == NULL) {
error("channel %d: decode socks4a: host not nul "
"terminated", c->self);
@@ -1110,7 +1209,10 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
return -1;
}
c->path = xstrdup(p);
- buffer_consume(&c->input, len);
+ if ((r = sshbuf_consume(c->input, len)) != 0) {
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+ }
}
c->host_port = ntohs(s4_req.dest_port);
@@ -1126,7 +1228,10 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
s4_rsp.command = 90; /* cd: req granted */
s4_rsp.dest_port = 0; /* ignored */
s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */
- buffer_append(&c->output, &s4_rsp, sizeof(s4_rsp));
+ if ((r = sshbuf_put(c->output, &s4_rsp, sizeof(s4_rsp))) != 0) {
+ fatal("%s: channel %d: append reply: %s", __func__,
+ c->self, ssh_err(r));
+ }
return 1;
}
@@ -1139,10 +1244,11 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
#define SSH_SOCKS5_CONNECT 0x01
#define SSH_SOCKS5_SUCCESS 0x00
-/* ARGSUSED */
static int
-channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
+channel_decode_socks5(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
+ /* XXX use get/put_u8 instead of trusting struct padding */
struct {
u_int8_t version;
u_int8_t command;
@@ -1151,14 +1257,15 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
} s5_req, s5_rsp;
u_int16_t dest_port;
char dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
- u_char *p;
+ const u_char *p;
u_int have, need, i, found, nmethods, addrlen, af;
+ int r;
debug2("channel %d: decode socks5", c->self);
- p = buffer_ptr(&c->input);
+ p = sshbuf_ptr(c->input);
if (p[0] != 0x05)
return -1;
- have = buffer_len(&c->input);
+ have = sshbuf_len(c->input);
if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
/* format: ver | nmethods | methods */
if (have < 2)
@@ -1178,9 +1285,16 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
c->self);
return -1;
}
- buffer_consume(&c->input, nmethods + 2);
- buffer_put_char(&c->output, 0x05); /* version */
- buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */
+ if ((r = sshbuf_consume(c->input, nmethods + 2)) != 0) {
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ /* version, method */
+ if ((r = sshbuf_put_u8(c->output, 0x05)) != 0 ||
+ (r = sshbuf_put_u8(c->output, SSH_SOCKS5_NOAUTH)) != 0) {
+ fatal("%s: channel %d: append reply: %s", __func__,
+ c->self, ssh_err(r));
+ }
FD_SET(c->sock, writeset);
c->flags |= SSH_SOCKS5_AUTHDONE;
debug2("channel %d: socks5 auth done", c->self);
@@ -1218,11 +1332,22 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
need++;
if (have < need)
return 0;
- buffer_consume(&c->input, sizeof(s5_req));
- if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
- buffer_consume(&c->input, 1); /* host string length */
- buffer_get(&c->input, &dest_addr, addrlen);
- buffer_get(&c->input, (char *)&dest_port, 2);
+ if ((r = sshbuf_consume(c->input, sizeof(s5_req))) != 0) {
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
+ /* host string length */
+ if ((r = sshbuf_consume(c->input, 1)) != 0) {
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ }
+ if ((r = sshbuf_get(c->input, &dest_addr, addrlen)) != 0 ||
+ (r = sshbuf_get(c->input, &dest_port, 2)) != 0) {
+ debug("channel %d: parse addr/port: %s", c->self, ssh_err(r));
+ return -1;
+ }
dest_addr[addrlen] = '\0';
free(c->path);
c->path = NULL;
@@ -1249,22 +1374,23 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
s5_rsp.atyp = SSH_SOCKS5_IPV4;
dest_port = 0; /* ignored */
- buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
- buffer_put_int(&c->output, ntohl(INADDR_ANY)); /* bind address */
- buffer_append(&c->output, &dest_port, sizeof(dest_port));
+ if ((r = sshbuf_put(c->output, &s5_rsp, sizeof(s5_rsp))) != 0 ||
+ (r = sshbuf_put_u32(c->output, ntohl(INADDR_ANY))) != 0 ||
+ (r = sshbuf_put(c->output, &dest_port, sizeof(dest_port))) != 0)
+ fatal("%s: channel %d: append reply: %s", __func__,
+ c->self, ssh_err(r));
return 1;
}
Channel *
-channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
- int in, int out)
+channel_connect_stdio_fwd(struct ssh *ssh,
+ const char *host_to_connect, u_short port_to_connect, int in, int out)
{
Channel *c;
- debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
- port_to_connect);
+ debug("%s %s:%d", __func__, host_to_connect, port_to_connect);
- c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
+ c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out,
-1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "stdio-forward", /*nonblock*/0);
@@ -1273,23 +1399,24 @@ channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
c->listening_port = 0;
c->force_drain = 1;
- channel_register_fds(c, in, out, -1, 0, 1, 0);
- port_open_helper(c, "direct-tcpip");
+ channel_register_fds(ssh, c, in, out, -1, 0, 1, 0);
+ port_open_helper(ssh, c, "direct-tcpip");
return c;
}
/* dynamic port forwarding */
static void
-channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_dynamic(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
- u_char *p;
+ const u_char *p;
u_int have;
int ret;
- have = buffer_len(&c->input);
+ have = sshbuf_len(c->input);
debug2("channel %d: pre_dynamic: have %d", c->self, have);
- /* buffer_dump(&c->input); */
+ /* sshbuf_dump(c->input, stderr); */
/* check if the fixed size part of the packet is in buffer. */
if (have < 3) {
/* need more */
@@ -1297,20 +1424,21 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
return;
}
/* try to guess the protocol */
- p = buffer_ptr(&c->input);
+ p = sshbuf_ptr(c->input);
+ /* XXX sshbuf_peek_u8? */
switch (p[0]) {
case 0x04:
- ret = channel_decode_socks4(c, readset, writeset);
+ ret = channel_decode_socks4(ssh, c, readset, writeset);
break;
case 0x05:
- ret = channel_decode_socks5(c, readset, writeset);
+ ret = channel_decode_socks5(ssh, c, readset, writeset);
break;
default:
ret = -1;
break;
}
if (ret < 0) {
- chan_mark_dead(c);
+ chan_mark_dead(ssh, c);
} else if (ret == 0) {
debug2("channel %d: pre_dynamic: need more", c->self);
/* need more */
@@ -1318,75 +1446,75 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
} else {
/* switch to the next state */
c->type = SSH_CHANNEL_OPENING;
- port_open_helper(c, "direct-tcpip");
+ port_open_helper(ssh, c, "direct-tcpip");
}
}
/* This is our fake X11 server socket. */
-/* ARGSUSED */
static void
-channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_x11_listener(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
- int newsock, oerrno;
+ int r, newsock, oerrno, remote_port;
socklen_t addrlen;
char buf[16384], *remote_ipaddr;
- int remote_port;
-
- if (FD_ISSET(c->sock, readset)) {
- debug("X11 connection requested.");
- addrlen = sizeof(addr);
- newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
- if (c->single_connection) {
- oerrno = errno;
- debug2("single_connection: closing X11 listener.");
- channel_close_fd(&c->sock);
- chan_mark_dead(c);
- errno = oerrno;
- }
- if (newsock < 0) {
- if (errno != EINTR && errno != EWOULDBLOCK &&
- errno != ECONNABORTED)
- error("accept: %.100s", strerror(errno));
- if (errno == EMFILE || errno == ENFILE)
- c->notbefore = monotime() + 1;
- return;
- }
- set_nodelay(newsock);
- remote_ipaddr = get_peer_ipaddr(newsock);
- remote_port = get_peer_port(newsock);
- snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
- remote_ipaddr, remote_port);
-
- nc = channel_new("accepted x11 socket",
- SSH_CHANNEL_OPENING, newsock, newsock, -1,
- c->local_window_max, c->local_maxpacket, 0, buf, 1);
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring("x11");
- packet_put_int(nc->self);
- packet_put_int(nc->local_window_max);
- packet_put_int(nc->local_maxpacket);
- /* originator ipaddr and port */
- packet_put_cstring(remote_ipaddr);
- if (datafellows & SSH_BUG_X11FWD) {
- debug2("ssh2 x11 bug compat mode");
- } else {
- packet_put_int(remote_port);
- }
- packet_send();
- free(remote_ipaddr);
+
+ if (!FD_ISSET(c->sock, readset))
+ return;
+
+ debug("X11 connection requested.");
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
+ if (c->single_connection) {
+ oerrno = errno;
+ debug2("single_connection: closing X11 listener.");
+ channel_close_fd(ssh, &c->sock);
+ chan_mark_dead(ssh, c);
+ errno = oerrno;
+ }
+ if (newsock < 0) {
+ if (errno != EINTR && errno != EWOULDBLOCK &&
+ errno != ECONNABORTED)
+ error("accept: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = monotime() + 1;
+ return;
}
+ set_nodelay(newsock);
+ remote_ipaddr = get_peer_ipaddr(newsock);
+ remote_port = get_peer_port(newsock);
+ snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
+ remote_ipaddr, remote_port);
+
+ nc = channel_new(ssh, "accepted x11 socket",
+ SSH_CHANNEL_OPENING, newsock, newsock, -1,
+ c->local_window_max, c->local_maxpacket, 0, buf, 1);
+ open_preamble(ssh, __func__, nc, "x11");
+ if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if ((datafellows & SSH_BUG_X11FWD) != 0)
+ debug2("channel %d: ssh2 x11 bug compat mode", nc->self);
+ else if ((r = sshpkt_put_u32(ssh, remote_port)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if ((r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r));
+ free(remote_ipaddr);
}
static void
-port_open_helper(Channel *c, char *rtype)
+port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
{
- char buf[1024];
char *local_ipaddr = get_local_ipaddr(c->sock);
int local_port = c->sock == -1 ? 65536 : get_local_port(c->sock);
char *remote_ipaddr = get_peer_ipaddr(c->sock);
int remote_port = get_peer_port(c->sock);
+ int r;
if (remote_port == -1) {
/* Fake addr/port to appease peers that validate it (Tectia) */
@@ -1395,44 +1523,57 @@ port_open_helper(Channel *c, char *rtype)
remote_port = 65535;
}
- snprintf(buf, sizeof buf,
+ free(c->remote_name);
+ xasprintf(&c->remote_name,
"%s: listening port %d for %.100s port %d, "
"connect from %.200s port %d to %.100s port %d",
rtype, c->listening_port, c->path, c->host_port,
remote_ipaddr, remote_port, local_ipaddr, local_port);
- free(c->remote_name);
- c->remote_name = xstrdup(buf);
-
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring(rtype);
- packet_put_int(c->self);
- packet_put_int(c->local_window_max);
- packet_put_int(c->local_maxpacket);
+ open_preamble(ssh, __func__, c, rtype);
if (strcmp(rtype, "direct-tcpip") == 0) {
/* target host, port */
- packet_put_cstring(c->path);
- packet_put_int(c->host_port);
+ if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->host_port)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
/* target path */
- packet_put_cstring(c->path);
+ if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
/* listen path */
- packet_put_cstring(c->path);
+ if ((r = sshpkt_put_cstring(ssh, c->path)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
} else {
/* listen address, port */
- packet_put_cstring(c->path);
- packet_put_int(local_port);
+ if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 ||
+ (r = sshpkt_put_u32(ssh, local_port)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
}
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
/* reserved for future owner/mode info */
- packet_put_cstring("");
+ if ((r = sshpkt_put_cstring(ssh, "")) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
} else {
/* originator host and port */
- packet_put_cstring(remote_ipaddr);
- packet_put_int((u_int)remote_port);
+ if ((r = sshpkt_put_cstring(ssh, remote_ipaddr)) != 0 ||
+ (r = sshpkt_put_u32(ssh, (u_int)remote_port)) != 0) {
+ fatal("%s: channel %i: reply %s", __func__,
+ c->self, ssh_err(r));
+ }
}
- packet_send();
+ if ((r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r));
free(remote_ipaddr);
free(local_ipaddr);
}
@@ -1451,17 +1592,17 @@ channel_set_reuseaddr(int fd)
}
void
-channel_set_x11_refuse_time(u_int refuse_time)
+channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time)
{
- x11_refuse_time = refuse_time;
+ ssh->chanctxt->x11_refuse_time = refuse_time;
}
/*
* This socket is listening for connections to a forwarded TCP/IP port.
*/
-/* ARGSUSED */
static void
-channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_port_listener(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
@@ -1469,336 +1610,387 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
socklen_t addrlen;
char *rtype;
- if (FD_ISSET(c->sock, readset)) {
- debug("Connection to port %d forwarding "
- "to %.100s port %d requested.",
- c->listening_port, c->path, c->host_port);
-
- if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
- nextstate = SSH_CHANNEL_OPENING;
- rtype = "forwarded-tcpip";
- } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
- nextstate = SSH_CHANNEL_OPENING;
- rtype = "forwarded-streamlocal@openssh.com";
- } else if (c->host_port == PORT_STREAMLOCAL) {
- nextstate = SSH_CHANNEL_OPENING;
- rtype = "direct-streamlocal@openssh.com";
- } else if (c->host_port == 0) {
- nextstate = SSH_CHANNEL_DYNAMIC;
- rtype = "dynamic-tcpip";
- } else {
- nextstate = SSH_CHANNEL_OPENING;
- rtype = "direct-tcpip";
- }
+ if (!FD_ISSET(c->sock, readset))
+ return;
- addrlen = sizeof(addr);
- newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
- if (newsock < 0) {
- if (errno != EINTR && errno != EWOULDBLOCK &&
- errno != ECONNABORTED)
- error("accept: %.100s", strerror(errno));
- if (errno == EMFILE || errno == ENFILE)
- c->notbefore = monotime() + 1;
- return;
- }
- if (c->host_port != PORT_STREAMLOCAL)
- set_nodelay(newsock);
- nc = channel_new(rtype, nextstate, newsock, newsock, -1,
- c->local_window_max, c->local_maxpacket, 0, rtype, 1);
- nc->listening_port = c->listening_port;
- nc->host_port = c->host_port;
- if (c->path != NULL)
- nc->path = xstrdup(c->path);
-
- if (nextstate != SSH_CHANNEL_DYNAMIC)
- port_open_helper(nc, rtype);
+ debug("Connection to port %d forwarding to %.100s port %d requested.",
+ c->listening_port, c->path, c->host_port);
+
+ if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "forwarded-tcpip";
+ } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "forwarded-streamlocal@openssh.com";
+ } else if (c->host_port == PORT_STREAMLOCAL) {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "direct-streamlocal@openssh.com";
+ } else if (c->host_port == 0) {
+ nextstate = SSH_CHANNEL_DYNAMIC;
+ rtype = "dynamic-tcpip";
+ } else {
+ nextstate = SSH_CHANNEL_OPENING;
+ rtype = "direct-tcpip";
+ }
+
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
+ if (newsock < 0) {
+ if (errno != EINTR && errno != EWOULDBLOCK &&
+ errno != ECONNABORTED)
+ error("accept: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = monotime() + 1;
+ return;
}
+ if (c->host_port != PORT_STREAMLOCAL)
+ set_nodelay(newsock);
+ nc = channel_new(ssh, rtype, nextstate, newsock, newsock, -1,
+ c->local_window_max, c->local_maxpacket, 0, rtype, 1);
+ nc->listening_port = c->listening_port;
+ nc->host_port = c->host_port;
+ if (c->path != NULL)
+ nc->path = xstrdup(c->path);
+
+ if (nextstate != SSH_CHANNEL_DYNAMIC)
+ port_open_helper(ssh, nc, rtype);
}
/*
* This is the authentication agent socket listening for connections from
* clients.
*/
-/* ARGSUSED */
static void
-channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_auth_listener(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
Channel *nc;
- int newsock;
+ int r, newsock;
struct sockaddr_storage addr;
socklen_t addrlen;
- if (FD_ISSET(c->sock, readset)) {
- addrlen = sizeof(addr);
- newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
- if (newsock < 0) {
- error("accept from auth socket: %.100s",
- strerror(errno));
- if (errno == EMFILE || errno == ENFILE)
- c->notbefore = monotime() + 1;
- return;
- }
- nc = channel_new("accepted auth socket",
- SSH_CHANNEL_OPENING, newsock, newsock, -1,
- c->local_window_max, c->local_maxpacket,
- 0, "accepted auth socket", 1);
- packet_start(SSH2_MSG_CHANNEL_OPEN);
- packet_put_cstring("auth-agent@openssh.com");
- packet_put_int(nc->self);
- packet_put_int(c->local_window_max);
- packet_put_int(c->local_maxpacket);
- packet_send();
+ if (!FD_ISSET(c->sock, readset))
+ return;
+
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
+ if (newsock < 0) {
+ error("accept from auth socket: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = monotime() + 1;
+ return;
}
+ nc = channel_new(ssh, "accepted auth socket",
+ SSH_CHANNEL_OPENING, newsock, newsock, -1,
+ c->local_window_max, c->local_maxpacket,
+ 0, "accepted auth socket", 1);
+ open_preamble(ssh, __func__, nc, "auth-agent@openssh.com");
+ if ((r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
}
-/* ARGSUSED */
static void
-channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_connecting(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
- int err = 0, sock;
+ int err = 0, sock, r;
socklen_t sz = sizeof(err);
- if (FD_ISSET(c->sock, writeset)) {
- if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
- err = errno;
- error("getsockopt SO_ERROR failed");
+ if (!FD_ISSET(c->sock, writeset))
+ return;
+
+ if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
+ err = errno;
+ error("getsockopt SO_ERROR failed");
+ }
+ if (err == 0) {
+ debug("channel %d: connected to %s port %d",
+ c->self, c->connect_ctx.host, c->connect_ctx.port);
+ channel_connect_ctx_free(&c->connect_ctx);
+ c->type = SSH_CHANNEL_OPEN;
+ if ((r = sshpkt_start(ssh,
+ SSH2_MSG_CHANNEL_OPEN_CONFIRMATION)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
+ fatal("%s: channel %i: confirm: %s", __func__,
+ c->self, ssh_err(r));
}
- if (err == 0) {
- debug("channel %d: connected to %s port %d",
- c->self, c->connect_ctx.host, c->connect_ctx.port);
- channel_connect_ctx_free(&c->connect_ctx);
- c->type = SSH_CHANNEL_OPEN;
- packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(c->remote_id);
- packet_put_int(c->self);
- packet_put_int(c->local_window);
- packet_put_int(c->local_maxpacket);
- } else {
- debug("channel %d: connection failed: %s",
- c->self, strerror(err));
- /* Try next address, if any */
- if ((sock = connect_next(&c->connect_ctx)) > 0) {
- close(c->sock);
- c->sock = c->rfd = c->wfd = sock;
- channel_max_fd = channel_find_maxfd();
- return;
- }
- /* Exhausted all addresses */
- error("connect_to %.100s port %d: failed.",
- c->connect_ctx.host, c->connect_ctx.port);
- channel_connect_ctx_free(&c->connect_ctx);
- packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(c->remote_id);
- packet_put_int(SSH2_OPEN_CONNECT_FAILED);
- if (!(datafellows & SSH_BUG_OPENFAILURE)) {
- packet_put_cstring(strerror(err));
- packet_put_cstring("");
- }
- chan_mark_dead(c);
+ } else {
+ debug("channel %d: connection failed: %s",
+ c->self, strerror(err));
+ /* Try next address, if any */
+ if ((sock = connect_next(&c->connect_ctx)) > 0) {
+ close(c->sock);
+ c->sock = c->rfd = c->wfd = sock;
+ channel_find_maxfd(ssh->chanctxt);
+ return;
+ }
+ /* Exhausted all addresses */
+ error("connect_to %.100s port %d: failed.",
+ c->connect_ctx.host, c->connect_ctx.port);
+ channel_connect_ctx_free(&c->connect_ctx);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_u32(ssh, SSH2_OPEN_CONNECT_FAILED)) != 0) {
+ fatal("%s: channel %i: failure: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if ((datafellows & SSH_BUG_OPENFAILURE) == 0 &&
+ ((r = sshpkt_put_cstring(ssh, strerror(err))) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "")) != 0)) {
+ fatal("%s: channel %i: failure: %s", __func__,
+ c->self, ssh_err(r));
}
- packet_send();
+ chan_mark_dead(ssh, c);
}
+ if ((r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
}
-/* ARGSUSED */
static int
-channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
+channel_handle_rfd(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
char buf[CHAN_RBUF];
- int len, force;
+ ssize_t len;
+ int r, force;
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
- if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
- errno = 0;
- len = read(c->rfd, buf, sizeof(buf));
- if (len < 0 && (errno == EINTR ||
- ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
- return 1;
+
+ if (c->rfd == -1 || (!force && !FD_ISSET(c->rfd, readset)))
+ return 1;
+
+ errno = 0;
+ len = read(c->rfd, buf, sizeof(buf));
+ if (len < 0 && (errno == EINTR ||
+ ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
+ return 1;
#ifndef PTY_ZEROREAD
- if (len <= 0) {
+ if (len <= 0) {
#else
- if ((!c->isatty && len <= 0) ||
- (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
+ if ((!c->isatty && len <= 0) ||
+ (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
#endif
- debug2("channel %d: read<=0 rfd %d len %d",
- c->self, c->rfd, len);
- if (c->type != SSH_CHANNEL_OPEN) {
- debug2("channel %d: not open", c->self);
- chan_mark_dead(c);
- return -1;
- } else {
- chan_read_failed(c);
- }
+ debug2("channel %d: read<=0 rfd %d len %zd",
+ c->self, c->rfd, len);
+ if (c->type != SSH_CHANNEL_OPEN) {
+ debug2("channel %d: not open", c->self);
+ chan_mark_dead(ssh, c);
return -1;
- }
- if (c->input_filter != NULL) {
- if (c->input_filter(c, buf, len) == -1) {
- debug2("channel %d: filter stops", c->self);
- chan_read_failed(c);
- }
- } else if (c->datagram) {
- buffer_put_string(&c->input, buf, len);
} else {
- buffer_append(&c->input, buf, len);
+ chan_read_failed(ssh, c);
}
+ return -1;
+ }
+ if (c->input_filter != NULL) {
+ if (c->input_filter(ssh, c, buf, len) == -1) {
+ debug2("channel %d: filter stops", c->self);
+ chan_read_failed(ssh, c);
+ }
+ } else if (c->datagram) {
+ if ((r = sshbuf_put_string(c->input, buf, len)) != 0)
+ fatal("%s: channel %d: put datagram: %s", __func__,
+ c->self, ssh_err(r));
+ } else if ((r = sshbuf_put(c->input, buf, len)) != 0) {
+ fatal("%s: channel %d: put data: %s", __func__,
+ c->self, ssh_err(r));
}
return 1;
}
-/* ARGSUSED */
static int
-channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
+channel_handle_wfd(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
struct termios tio;
- u_char *data = NULL, *buf;
- u_int dlen, olen = 0;
- int len;
+ u_char *data = NULL, *buf; /* XXX const; need filter API change */
+ size_t dlen, olen = 0;
+ int r, len;
+
+ if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||
+ sshbuf_len(c->output) == 0)
+ return 1;
/* Send buffered output data to the socket. */
- if (c->wfd != -1 &&
- FD_ISSET(c->wfd, writeset) &&
- buffer_len(&c->output) > 0) {
- olen = buffer_len(&c->output);
- if (c->output_filter != NULL) {
- if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
- debug2("channel %d: filter stops", c->self);
- if (c->type != SSH_CHANNEL_OPEN)
- chan_mark_dead(c);
- else
- chan_write_failed(c);
- return -1;
- }
- } else if (c->datagram) {
- buf = data = buffer_get_string(&c->output, &dlen);
- } else {
- buf = data = buffer_ptr(&c->output);
- dlen = buffer_len(&c->output);
+ olen = sshbuf_len(c->output);
+ if (c->output_filter != NULL) {
+ if ((buf = c->output_filter(ssh, c, &data, &dlen)) == NULL) {
+ debug2("channel %d: filter stops", c->self);
+ if (c->type != SSH_CHANNEL_OPEN)
+ chan_mark_dead(ssh, c);
+ else
+ chan_write_failed(ssh, c);
+ return -1;
}
+ } else if (c->datagram) {
+ if ((r = sshbuf_get_string(c->output, &data, &dlen)) != 0)
+ fatal("%s: channel %d: get datagram: %s", __func__,
+ c->self, ssh_err(r));
+ } else {
+ buf = data = sshbuf_mutable_ptr(c->output);
+ dlen = sshbuf_len(c->output);
+ }
+
+ if (c->datagram) {
+ /* ignore truncated writes, datagrams might get lost */
+ len = write(c->wfd, data, dlen);
+ free(data);
+ if (len < 0 && (errno == EINTR || errno == EAGAIN ||
+ errno == EWOULDBLOCK))
+ return 1;
+ if (len <= 0)
+ goto write_fail;
+ goto out;
+ }
- if (c->datagram) {
- /* ignore truncated writes, datagrams might get lost */
- len = write(c->wfd, buf, dlen);
- free(data);
- if (len < 0 && (errno == EINTR || errno == EAGAIN ||
- errno == EWOULDBLOCK))
- return 1;
- if (len <= 0) {
- if (c->type != SSH_CHANNEL_OPEN)
- chan_mark_dead(c);
- else
- chan_write_failed(c);
- return -1;
- }
- goto out;
- }
#ifdef _AIX
- /* XXX: Later AIX versions can't push as much data to tty */
- if (c->wfd_isatty)
- dlen = MIN(dlen, 8*1024);
+ /* XXX: Later AIX versions can't push as much data to tty */
+ if (c->wfd_isatty)
+ dlen = MIN(dlen, 8*1024);
#endif
- len = write(c->wfd, buf, dlen);
- if (len < 0 &&
- (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
- return 1;
- if (len <= 0) {
- if (c->type != SSH_CHANNEL_OPEN) {
- debug2("channel %d: not open", c->self);
- chan_mark_dead(c);
- return -1;
- } else {
- chan_write_failed(c);
- }
+ len = write(c->wfd, buf, dlen);
+ if (len < 0 &&
+ (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
+ return 1;
+ if (len <= 0) {
+ write_fail:
+ if (c->type != SSH_CHANNEL_OPEN) {
+ debug2("channel %d: not open", c->self);
+ chan_mark_dead(ssh, c);
return -1;
+ } else {
+ chan_write_failed(ssh, c);
}
+ return -1;
+ }
#ifndef BROKEN_TCGETATTR_ICANON
- if (c->isatty && dlen >= 1 && buf[0] != '\r') {
- if (tcgetattr(c->wfd, &tio) == 0 &&
- !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
- /*
- * Simulate echo to reduce the impact of
- * traffic analysis. We need to match the
- * size of a SSH2_MSG_CHANNEL_DATA message
- * (4 byte channel id + buf)
- */
- packet_send_ignore(4 + len);
- packet_send();
- }
+ if (c->isatty && dlen >= 1 && buf[0] != '\r') {
+ if (tcgetattr(c->wfd, &tio) == 0 &&
+ !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
+ /*
+ * Simulate echo to reduce the impact of
+ * traffic analysis. We need to match the
+ * size of a SSH2_MSG_CHANNEL_DATA message
+ * (4 byte channel id + buf)
+ */
+ if ((r = sshpkt_msg_ignore(ssh, 4+len)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %d: ignore: %s",
+ __func__, c->self, ssh_err(r));
}
-#endif
- buffer_consume(&c->output, len);
+ }
+#endif /* BROKEN_TCGETATTR_ICANON */
+ if ((r = sshbuf_consume(c->output, len)) != 0) {
+ fatal("%s: channel %d: consume: %s",
+ __func__, c->self, ssh_err(r));
}
out:
- if (olen > 0)
- c->local_consumed += olen - buffer_len(&c->output);
+ c->local_consumed += olen - sshbuf_len(c->output);
+
+ return 1;
+}
+
+static int
+channel_handle_efd_write(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
+{
+ int r;
+ ssize_t len;
+
+ if (!FD_ISSET(c->efd, writeset) || sshbuf_len(c->extended) == 0)
+ return 1;
+
+ len = write(c->efd, sshbuf_ptr(c->extended),
+ sshbuf_len(c->extended));
+ debug2("channel %d: written %zd to efd %d", c->self, len, c->efd);
+ if (len < 0 && (errno == EINTR || errno == EAGAIN ||
+ errno == EWOULDBLOCK))
+ return 1;
+ if (len <= 0) {
+ debug2("channel %d: closing write-efd %d", c->self, c->efd);
+ channel_close_fd(ssh, &c->efd);
+ } else {
+ if ((r = sshbuf_consume(c->extended, len)) != 0) {
+ fatal("%s: channel %d: consume: %s",
+ __func__, c->self, ssh_err(r));
+ }
+ c->local_consumed += len;
+ }
return 1;
}
static int
-channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
+channel_handle_efd_read(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
char buf[CHAN_RBUF];
- int len;
+ int r;
+ ssize_t len;
-/** XXX handle drain efd, too */
- if (c->efd != -1) {
- if (c->extended_usage == CHAN_EXTENDED_WRITE &&
- FD_ISSET(c->efd, writeset) &&
- buffer_len(&c->extended) > 0) {
- len = write(c->efd, buffer_ptr(&c->extended),
- buffer_len(&c->extended));
- debug2("channel %d: written %d to efd %d",
- c->self, len, c->efd);
- if (len < 0 && (errno == EINTR || errno == EAGAIN ||
- errno == EWOULDBLOCK))
- return 1;
- if (len <= 0) {
- debug2("channel %d: closing write-efd %d",
- c->self, c->efd);
- channel_close_fd(&c->efd);
- } else {
- buffer_consume(&c->extended, len);
- c->local_consumed += len;
- }
- } else if (c->efd != -1 &&
- (c->extended_usage == CHAN_EXTENDED_READ ||
- c->extended_usage == CHAN_EXTENDED_IGNORE) &&
- (c->detach_close || FD_ISSET(c->efd, readset))) {
- len = read(c->efd, buf, sizeof(buf));
- debug2("channel %d: read %d from efd %d",
- c->self, len, c->efd);
- if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
- errno == EWOULDBLOCK) && !c->detach_close)))
- return 1;
- if (len <= 0) {
- debug2("channel %d: closing read-efd %d",
- c->self, c->efd);
- channel_close_fd(&c->efd);
- } else {
- if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
- debug3("channel %d: discard efd",
- c->self);
- } else
- buffer_append(&c->extended, buf, len);
- }
+ if (!c->detach_close && !FD_ISSET(c->efd, readset))
+ return 1;
+
+ len = read(c->efd, buf, sizeof(buf));
+ debug2("channel %d: read %zd from efd %d", c->self, len, c->efd);
+ if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+ errno == EWOULDBLOCK) && !c->detach_close)))
+ return 1;
+ if (len <= 0) {
+ debug2("channel %d: closing read-efd %d",
+ c->self, c->efd);
+ channel_close_fd(ssh, &c->efd);
+ } else {
+ if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
+ debug3("channel %d: discard efd",
+ c->self);
+ } else if ((r = sshbuf_put(c->extended, buf, len)) != 0) {
+ fatal("%s: channel %d: append: %s",
+ __func__, c->self, ssh_err(r));
}
}
return 1;
}
static int
-channel_check_window(Channel *c)
+channel_handle_efd(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
+{
+ if (c->efd == -1)
+ return 1;
+
+ /** XXX handle drain efd, too */
+
+ if (c->extended_usage == CHAN_EXTENDED_WRITE)
+ return channel_handle_efd_write(ssh, c, readset, writeset);
+ else if (c->extended_usage == CHAN_EXTENDED_READ ||
+ c->extended_usage == CHAN_EXTENDED_IGNORE)
+ return channel_handle_efd_read(ssh, c, readset, writeset);
+
+ return 1;
+}
+
+static int
+channel_check_window(struct ssh *ssh, Channel *c)
{
+ int r;
+
if (c->type == SSH_CHANNEL_OPEN &&
!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
((c->local_window_max - c->local_window >
c->local_maxpacket*3) ||
c->local_window < c->local_window_max/2) &&
c->local_consumed > 0) {
- packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
- packet_put_int(c->remote_id);
- packet_put_int(c->local_consumed);
- packet_send();
+ if ((r = sshpkt_start(ssh,
+ SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ fatal("%s: channel %i: %s", __func__,
+ c->self, ssh_err(r));
+ }
debug2("channel %d: window %d sent adjust %d",
c->self, c->local_window,
c->local_consumed);
@@ -1809,85 +2001,112 @@ channel_check_window(Channel *c)
}
static void
-channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_open(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
- channel_handle_rfd(c, readset, writeset);
- channel_handle_wfd(c, readset, writeset);
- channel_handle_efd(c, readset, writeset);
- channel_check_window(c);
+ channel_handle_rfd(ssh, c, readset, writeset);
+ channel_handle_wfd(ssh, c, readset, writeset);
+ channel_handle_efd(ssh, c, readset, writeset);
+ channel_check_window(ssh, c);
}
static u_int
-read_mux(Channel *c, u_int need)
+read_mux(struct ssh *ssh, Channel *c, u_int need)
{
char buf[CHAN_RBUF];
- int len;
+ ssize_t len;
u_int rlen;
+ int r;
- if (buffer_len(&c->input) < need) {
- rlen = need - buffer_len(&c->input);
+ if (sshbuf_len(c->input) < need) {
+ rlen = need - sshbuf_len(c->input);
len = read(c->rfd, buf, MINIMUM(rlen, CHAN_RBUF));
if (len < 0 && (errno == EINTR || errno == EAGAIN))
- return buffer_len(&c->input);
+ return sshbuf_len(c->input);
if (len <= 0) {
- debug2("channel %d: ctl read<=0 rfd %d len %d",
+ debug2("channel %d: ctl read<=0 rfd %d len %zd",
c->self, c->rfd, len);
- chan_read_failed(c);
+ chan_read_failed(ssh, c);
return 0;
- } else
- buffer_append(&c->input, buf, len);
+ } else if ((r = sshbuf_put(c->input, buf, len)) != 0) {
+ fatal("%s: channel %d: append: %s",
+ __func__, c->self, ssh_err(r));
+ }
}
- return buffer_len(&c->input);
+ return sshbuf_len(c->input);
}
static void
-channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_mux_client_read(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
u_int need;
- ssize_t len;
- if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
- (c->istate == CHAN_INPUT_OPEN ||
- c->istate == CHAN_INPUT_WAIT_DRAIN)) {
- /*
- * Don't not read past the precise end of packets to
- * avoid disrupting fd passing.
- */
- if (read_mux(c, 4) < 4) /* read header */
- return;
- need = get_u32(buffer_ptr(&c->input));
+ if (c->rfd == -1 || !FD_ISSET(c->rfd, readset))
+ return;
+ if (c->istate != CHAN_INPUT_OPEN && c->istate != CHAN_INPUT_WAIT_DRAIN)
+ return;
+ if (c->mux_pause)
+ return;
+
+ /*
+ * Don't not read past the precise end of packets to
+ * avoid disrupting fd passing.
+ */
+ if (read_mux(ssh, c, 4) < 4) /* read header */
+ return;
+ /* XXX sshbuf_peek_u32 */
+ need = PEEK_U32(sshbuf_ptr(c->input));
#define CHANNEL_MUX_MAX_PACKET (256 * 1024)
- if (need > CHANNEL_MUX_MAX_PACKET) {
- debug2("channel %d: packet too big %u > %u",
- c->self, CHANNEL_MUX_MAX_PACKET, need);
- chan_rcvd_oclose(c);
- return;
- }
- if (read_mux(c, need + 4) < need + 4) /* read body */
- return;
- if (c->mux_rcb(c) != 0) {
- debug("channel %d: mux_rcb failed", c->self);
- chan_mark_dead(c);
- return;
- }
+ if (need > CHANNEL_MUX_MAX_PACKET) {
+ debug2("channel %d: packet too big %u > %u",
+ c->self, CHANNEL_MUX_MAX_PACKET, need);
+ chan_rcvd_oclose(ssh, c);
+ return;
}
+ if (read_mux(ssh, c, need + 4) < need + 4) /* read body */
+ return;
+ if (c->mux_rcb(ssh, c) != 0) {
+ debug("channel %d: mux_rcb failed", c->self);
+ chan_mark_dead(ssh, c);
+ return;
+ }
+}
- if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
- buffer_len(&c->output) > 0) {
- len = write(c->wfd, buffer_ptr(&c->output),
- buffer_len(&c->output));
- if (len < 0 && (errno == EINTR || errno == EAGAIN))
- return;
- if (len <= 0) {
- chan_mark_dead(c);
- return;
- }
- buffer_consume(&c->output, len);
+static void
+channel_post_mux_client_write(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
+{
+ ssize_t len;
+ int r;
+
+ if (c->wfd == -1 || !FD_ISSET(c->wfd, writeset) ||
+ sshbuf_len(c->output) == 0)
+ return;
+
+ len = write(c->wfd, sshbuf_ptr(c->output), sshbuf_len(c->output));
+ if (len < 0 && (errno == EINTR || errno == EAGAIN))
+ return;
+ if (len <= 0) {
+ chan_mark_dead(ssh, c);
+ return;
}
+ if ((r = sshbuf_consume(c->output, len)) != 0)
+ fatal("%s: channel %d: consume: %s", __func__,
+ c->self, ssh_err(r));
+}
+
+static void
+channel_post_mux_client(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
+{
+ channel_post_mux_client_read(ssh, c, readset, writeset);
+ channel_post_mux_client_write(ssh, c, readset, writeset);
}
static void
-channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_post_mux_listener(struct ssh *ssh, Channel *c,
+ fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
@@ -1926,97 +2145,98 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
close(newsock);
return;
}
- nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
+ nc = channel_new(ssh, "multiplex client", SSH_CHANNEL_MUX_CLIENT,
newsock, newsock, -1, c->local_window_max,
c->local_maxpacket, 0, "mux-control", 1);
nc->mux_rcb = c->mux_rcb;
- debug3("%s: new mux channel %d fd %d", __func__,
- nc->self, nc->sock);
+ debug3("%s: new mux channel %d fd %d", __func__, nc->self, nc->sock);
/* establish state */
- nc->mux_rcb(nc);
+ nc->mux_rcb(ssh, nc);
/* mux state transitions must not elicit protocol messages */
nc->flags |= CHAN_LOCAL;
}
static void
-channel_handler_init(void)
+channel_handler_init(struct ssh_channels *sc)
{
- int i;
-
- for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
- channel_pre[i] = NULL;
- channel_post[i] = NULL;
- }
- channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
- channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
- channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
- channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
- channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener;
- channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client;
-
- channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
- channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
- channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
- channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
- channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
- channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
- channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
- channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
- channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener;
- channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
+ chan_fn **pre, **post;
+
+ if ((pre = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*pre))) == NULL ||
+ (post = calloc(SSH_CHANNEL_MAX_TYPE, sizeof(*post))) == NULL)
+ fatal("%s: allocation failed", __func__);
+
+ pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
+ pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
+ pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
+ pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
+ pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
+ pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener;
+ pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client;
+
+ post[SSH_CHANNEL_OPEN] = &channel_post_open;
+ post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
+ post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
+ post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
+ post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
+ post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
+ post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
+ post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
+ post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
+ post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener;
+ post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
+
+ sc->channel_pre = pre;
+ sc->channel_post = post;
}
/* gc dead channels */
static void
-channel_garbage_collect(Channel *c)
+channel_garbage_collect(struct ssh *ssh, Channel *c)
{
if (c == NULL)
return;
if (c->detach_user != NULL) {
- if (!chan_is_dead(c, c->detach_close))
+ if (!chan_is_dead(ssh, c, c->detach_close))
return;
debug2("channel %d: gc: notify user", c->self);
- c->detach_user(c->self, NULL);
+ c->detach_user(ssh, c->self, NULL);
/* if we still have a callback */
if (c->detach_user != NULL)
return;
debug2("channel %d: gc: user detached", c->self);
}
- if (!chan_is_dead(c, 1))
+ if (!chan_is_dead(ssh, c, 1))
return;
debug2("channel %d: garbage collecting", c->self);
- channel_free(c);
+ channel_free(ssh, c);
}
+enum channel_table { CHAN_PRE, CHAN_POST };
+
static void
-channel_handler(struct ssh *ssh, chan_fn *ftab[],
+channel_handler(struct ssh *ssh, int table,
fd_set *readset, fd_set *writeset, time_t *unpause_secs)
{
- static int did_init = 0;
+ struct ssh_channels *sc = ssh->chanctxt;
+ chan_fn **ftab = table == CHAN_PRE ? sc->channel_pre : sc->channel_post;
u_int i, oalloc;
Channel *c;
time_t now;
- if (!did_init) {
- channel_handler_init();
- did_init = 1;
- }
now = monotime();
if (unpause_secs != NULL)
*unpause_secs = 0;
- for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
- c = channels[i];
+ for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) {
+ c = sc->channels[i];
if (c == NULL)
continue;
if (c->delayed) {
- if (ftab == channel_pre)
+ if (table == CHAN_PRE)
c->delayed = 0;
else
continue;
@@ -2026,7 +2246,7 @@ channel_handler(struct ssh *ssh, chan_fn *ftab[],
* Run handlers that are not paused.
*/
if (c->notbefore <= now)
- (*ftab[c->type])(c, readset, writeset);
+ (*ftab[c->type])(ssh, c, readset, writeset);
else if (unpause_secs != NULL) {
/*
* Collect the time that the earliest
@@ -2040,7 +2260,7 @@ channel_handler(struct ssh *ssh, chan_fn *ftab[],
*unpause_secs = c->notbefore - now;
}
}
- channel_garbage_collect(c);
+ channel_garbage_collect(ssh, c);
}
if (unpause_secs != NULL && *unpause_secs != 0)
debug3("%s: first channel unpauses in %d seconds",
@@ -2057,7 +2277,7 @@ channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp,
{
u_int n, sz, nfdset;
- n = MAXIMUM(*maxfdp, channel_max_fd);
+ n = MAXIMUM(*maxfdp, ssh->chanctxt->channel_max_fd);
nfdset = howmany(n+1, NFDBITS);
/* Explicitly test here, because xrealloc isn't always called */
@@ -2076,7 +2296,7 @@ channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp,
memset(*writesetp, 0, sz);
if (!ssh_packet_is_rekeying(ssh))
- channel_handler(ssh, channel_pre, *readsetp, *writesetp,
+ channel_handler(ssh, CHAN_PRE, *readsetp, *writesetp,
minwait_secs);
}
@@ -2087,19 +2307,128 @@ channel_prepare_select(struct ssh *ssh, fd_set **readsetp, fd_set **writesetp,
void
channel_after_select(struct ssh *ssh, fd_set *readset, fd_set *writeset)
{
- channel_handler(ssh, channel_post, readset, writeset, NULL);
+ channel_handler(ssh, CHAN_POST, readset, writeset, NULL);
+}
+
+/*
+ * Enqueue data for channels with open or draining c->input.
+ */
+static void
+channel_output_poll_input_open(struct ssh *ssh, Channel *c)
+{
+ size_t len, dlen;
+ int r;
+
+ if ((len = sshbuf_len(c->input)) == 0) {
+ if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
+ /*
+ * input-buffer is empty and read-socket shutdown:
+ * tell peer, that we will not send more data:
+ * send IEOF.
+ * hack for extended data: delay EOF if EFD still
+ * in use.
+ */
+ if (CHANNEL_EFD_INPUT_ACTIVE(c))
+ debug2("channel %d: "
+ "ibuf_empty delayed efd %d/(%zu)",
+ c->self, c->efd, sshbuf_len(c->extended));
+ else
+ chan_ibuf_empty(ssh, c);
+ }
+ return;
+ }
+
+ if (c->datagram) {
+ /* Check datagram will fit; drop if not */
+ if ((r = sshbuf_peek_string_direct(c->input, NULL, &dlen)) != 0)
+ fatal("%s: channel %d: peek datagram: %s", __func__,
+ c->self, ssh_err(r));
+ /*
+ * XXX this does tail-drop on the datagram queue which is
+ * usually suboptimal compared to head-drop. Better to have
+ * backpressure at read time? (i.e. read + discard)
+ */
+ if (dlen > c->remote_window || dlen > c->remote_maxpacket) {
+ debug("channel %d: datagram too big", c->self);
+ return;
+ }
+ /* Enqueue it */
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_stringb(ssh, c->input)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ fatal("%s: channel %i: datagram: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ c->remote_window -= dlen;
+ return;
+ }
+
+ /* Enqueue packet for buffered data. */
+ if (len > c->remote_window)
+ len = c->remote_window;
+ if (len > c->remote_maxpacket)
+ len = c->remote_maxpacket;
+ if (len == 0)
+ return;
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ fatal("%s: channel %i: data: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if ((r = sshbuf_consume(c->input, len)) != 0)
+ fatal("%s: channel %i: consume: %s", __func__,
+ c->self, ssh_err(r));
+ c->remote_window -= len;
}
+/*
+ * Enqueue data for channels with open c->extended in read mode.
+ */
+static void
+channel_output_poll_extended_read(struct ssh *ssh, Channel *c)
+{
+ size_t len;
+ int r;
+
+ if ((len = sshbuf_len(c->extended)) == 0)
+ return;
+
+ debug2("channel %d: rwin %u elen %zu euse %d", c->self,
+ c->remote_window, sshbuf_len(c->extended), c->extended_usage);
+ if (len > c->remote_window)
+ len = c->remote_window;
+ if (len > c->remote_maxpacket)
+ len = c->remote_maxpacket;
+ if (len == 0)
+ return;
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_u32(ssh, SSH2_EXTENDED_DATA_STDERR)) != 0 ||
+ (r = sshpkt_put_string(ssh, sshbuf_ptr(c->extended), len)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0) {
+ fatal("%s: channel %i: data: %s", __func__,
+ c->self, ssh_err(r));
+ }
+ if ((r = sshbuf_consume(c->extended, len)) != 0)
+ fatal("%s: channel %i: consume: %s", __func__,
+ c->self, ssh_err(r));
+ c->remote_window -= len;
+ debug2("channel %d: sent ext data %zu", c->self, len);
+}
/* If there is data to send to the connection, enqueue some of it now. */
void
-channel_output_poll(void)
+channel_output_poll(struct ssh *ssh)
{
+ struct ssh_channels *sc = ssh->chanctxt;
Channel *c;
- u_int i, len;
+ u_int i;
- 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)
continue;
@@ -2111,87 +2440,19 @@ channel_output_poll(void)
continue;
if ((c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
/* XXX is this true? */
- debug3("channel %d: will not send data after close", c->self);
+ debug3("channel %d: will not send data after close",
+ c->self);
continue;
}
/* Get the amount of buffered data for this channel. */
- if ((c->istate == CHAN_INPUT_OPEN ||
- c->istate == CHAN_INPUT_WAIT_DRAIN) &&
- (len = buffer_len(&c->input)) > 0) {
- if (c->datagram) {
- if (len > 0) {
- u_char *data;
- u_int dlen;
-
- data = buffer_get_string(&c->input,
- &dlen);
- if (dlen > c->remote_window ||
- dlen > c->remote_maxpacket) {
- debug("channel %d: datagram "
- "too big for channel",
- c->self);
- free(data);
- continue;
- }
- packet_start(SSH2_MSG_CHANNEL_DATA);
- packet_put_int(c->remote_id);
- packet_put_string(data, dlen);
- packet_send();
- c->remote_window -= dlen;
- free(data);
- }
- continue;
- }
- /*
- * Send some data for the other side over the secure
- * connection.
- */
- if (len > c->remote_window)
- len = c->remote_window;
- if (len > c->remote_maxpacket)
- len = c->remote_maxpacket;
- if (len > 0) {
- packet_start(SSH2_MSG_CHANNEL_DATA);
- packet_put_int(c->remote_id);
- packet_put_string(buffer_ptr(&c->input), len);
- packet_send();
- buffer_consume(&c->input, len);
- c->remote_window -= len;
- }
- } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
- /*
- * input-buffer is empty and read-socket shutdown:
- * tell peer, that we will not send more data: send IEOF.
- * hack for extended data: delay EOF if EFD still in use.
- */
- if (CHANNEL_EFD_INPUT_ACTIVE(c))
- debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
- c->self, c->efd, buffer_len(&c->extended));
- else
- chan_ibuf_empty(c);
- }
+ if (c->istate == CHAN_INPUT_OPEN ||
+ c->istate == CHAN_INPUT_WAIT_DRAIN)
+ channel_output_poll_input_open(ssh, c);
/* Send extended data, i.e. stderr */
if (!(c->flags & CHAN_EOF_SENT) &&
- c->remote_window > 0 &&
- (len = buffer_len(&c->extended)) > 0 &&
- c->extended_usage == CHAN_EXTENDED_READ) {
- debug2("channel %d: rwin %u elen %u euse %d",
- c->self, c->remote_window, buffer_len(&c->extended),
- c->extended_usage);
- if (len > c->remote_window)
- len = c->remote_window;
- if (len > c->remote_maxpacket)
- len = c->remote_maxpacket;
- packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
- packet_put_int(c->remote_id);
- packet_put_int(SSH2_EXTENDED_DATA_STDERR);
- packet_put_string(buffer_ptr(&c->extended), len);
- packet_send();
- buffer_consume(&c->extended, len);
- c->remote_window -= len;
- debug2("channel %d: sent ext data %d", c->self, len);
- }
+ c->extended_usage == CHAN_EXTENDED_READ)
+ channel_output_poll_extended_read(ssh, c);
}
}
@@ -2236,10 +2497,9 @@ channel_output_poll(void)
* on channel creation.
*/
int
-channel_proxy_downstream(Channel *downstream)
+channel_proxy_downstream(struct ssh *ssh, Channel *downstream)
{
Channel *c = NULL;
- struct ssh *ssh = active_state;
struct sshbuf *original = NULL, *modified = NULL;
const u_char *cp;
char *ctype = NULL, *listen_host = NULL;
@@ -2248,8 +2508,8 @@ channel_proxy_downstream(Channel *downstream)
int ret = -1, r, idx;
u_int id, remote_id, listen_port;
- /* sshbuf_dump(&downstream->input, stderr); */
- if ((r = sshbuf_get_string_direct(&downstream->input, &cp, &have))
+ /* sshbuf_dump(downstream->input, stderr); */
+ if ((r = sshbuf_get_string_direct(downstream->input, &cp, &have))
!= 0) {
error("%s: malformed message: %s", __func__, ssh_err(r));
return -1;
@@ -2278,7 +2538,7 @@ channel_proxy_downstream(Channel *downstream)
error("%s: parse error %s", __func__, ssh_err(r));
goto out;
}
- c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
+ c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY,
-1, -1, -1, 0, 0, 0, ctype, 1);
c->mux_ctx = downstream; /* point to mux client */
c->mux_downstream_id = id; /* original downstream id */
@@ -2286,7 +2546,7 @@ channel_proxy_downstream(Channel *downstream)
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
(r = sshbuf_putb(modified, original)) != 0) {
error("%s: compose error %s", __func__, ssh_err(r));
- channel_free(c);
+ channel_free(ssh, c);
goto out;
}
break;
@@ -2305,7 +2565,7 @@ channel_proxy_downstream(Channel *downstream)
error("%s: parse error %s", __func__, ssh_err(r));
goto out;
}
- c = channel_new("mux proxy", SSH_CHANNEL_MUX_PROXY,
+ c = channel_new(ssh, "mux proxy", SSH_CHANNEL_MUX_PROXY,
-1, -1, -1, 0, 0, 0, "mux-down-connect", 1);
c->mux_ctx = downstream; /* point to mux client */
c->mux_downstream_id = id;
@@ -2314,7 +2574,7 @@ channel_proxy_downstream(Channel *downstream)
(r = sshbuf_put_u32(modified, c->self)) != 0 ||
(r = sshbuf_putb(modified, original)) != 0) {
error("%s: compose error %s", __func__, ssh_err(r));
- channel_free(c);
+ channel_free(ssh, c);
goto out;
}
break;
@@ -2343,23 +2603,17 @@ channel_proxy_downstream(Channel *downstream)
goto out;
}
/* Record that connection to this host/port is permitted. */
- permitted_opens = xreallocarray(permitted_opens,
- num_permitted_opens + 1, sizeof(*permitted_opens));
- idx = num_permitted_opens++;
- permitted_opens[idx].host_to_connect = xstrdup("<mux>");
- permitted_opens[idx].port_to_connect = -1;
- permitted_opens[idx].listen_host = listen_host;
- permitted_opens[idx].listen_port = (int)listen_port;
- permitted_opens[idx].downstream = downstream;
+ idx = fwd_perm_list_add(ssh, FWDPERM_USER, "<mux>", -1,
+ listen_host, NULL, (int)listen_port, downstream);
listen_host = NULL;
break;
case SSH2_MSG_CHANNEL_CLOSE:
if (have < 4)
break;
remote_id = PEEK_U32(cp);
- if ((c = channel_by_remote_id(remote_id)) != NULL) {
+ if ((c = channel_by_remote_id(ssh, remote_id)) != NULL) {
if (c->flags & CHAN_CLOSE_RCVD)
- channel_free(c);
+ channel_free(ssh, c);
else
c->flags |= CHAN_CLOSE_SENT;
}
@@ -2446,7 +2700,7 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, struct ssh *ssh)
(r = sshbuf_put_u8(b, type)) != 0 ||
(r = sshbuf_put_u32(b, c->mux_downstream_id)) != 0 ||
(r = sshbuf_put(b, cp, len)) != 0 ||
- (r = sshbuf_put_stringb(&downstream->output, b)) != 0) {
+ (r = sshbuf_put_stringb(downstream->output, b)) != 0) {
error("%s: compose for muxclient %s", __func__, ssh_err(r));
goto out;
}
@@ -2464,7 +2718,7 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, struct ssh *ssh)
break;
case SSH2_MSG_CHANNEL_CLOSE:
if (c->flags & CHAN_CLOSE_SENT)
- channel_free(c);
+ channel_free(ssh, c);
else
c->flags |= CHAN_CLOSE_RCVD;
break;
@@ -2475,20 +2729,46 @@ channel_proxy_upstream(Channel *c, int type, u_int32_t seq, struct ssh *ssh)
/* -- protocol input */
-/* ARGSUSED */
+/* Parse a channel ID from the current packet */
+static int
+channel_parse_id(struct ssh *ssh, const char *where, const char *what)
+{
+ u_int32_t id;
+ int r;
+
+ if ((r = sshpkt_get_u32(ssh, &id)) != 0) {
+ error("%s: parse id: %s", where, ssh_err(r));
+ ssh_packet_disconnect(ssh, "Invalid %s message", what);
+ }
+ if (id > INT_MAX) {
+ error("%s: bad channel id %u: %s", where, id, ssh_err(r));
+ ssh_packet_disconnect(ssh, "Invalid %s channel id", what);
+ }
+ return (int)id;
+}
+
+/* Lookup a channel from an ID in the current packet */
+static Channel *
+channel_from_packet_id(struct ssh *ssh, const char *where, const char *what)
+{
+ int id = channel_parse_id(ssh, where, what);
+ Channel *c;
+
+ if ((c = channel_lookup(ssh, id)) == NULL) {
+ ssh_packet_disconnect(ssh,
+ "%s packet referred to nonexistent channel %d", what, id);
+ }
+ return c;
+}
+
int
channel_input_data(int type, u_int32_t seq, struct ssh *ssh)
{
- int id;
const u_char *data;
- u_int data_len, win_len;
- Channel *c;
+ size_t data_len, win_len;
+ Channel *c = channel_from_packet_id(ssh, __func__, "data");
+ int r;
- /* Get the channel number and verify it. */
- id = packet_get_int();
- c = channel_lookup(id);
- if (c == NULL)
- packet_disconnect("Received data for nonexistent channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
@@ -2498,17 +2778,19 @@ channel_input_data(int type, u_int32_t seq, struct ssh *ssh)
return 0;
/* Get the data. */
- data = packet_get_string_ptr(&data_len);
+ if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0)
+ fatal("%s: channel %d: get data: %s", __func__,
+ c->self, ssh_err(r));
+ ssh_packet_check_eom(ssh);
+
win_len = data_len;
if (c->datagram)
win_len += 4; /* string length header */
/*
- * Ignore data for protocol > 1.3 if output end is no longer open.
- * For protocol 2 the sending side is reducing its window as it sends
- * data, so we must 'fake' consumption of the data in order to ensure
- * that window updates are sent back. Otherwise the connection might
- * deadlock.
+ * The sending side reduces its window as it sends data, so we
+ * must 'fake' consumption of the data in order to ensure that window
+ * updates are sent back. Otherwise the connection might deadlock.
*/
if (c->ostate != CHAN_OUTPUT_OPEN) {
c->local_window -= win_len;
@@ -2517,149 +2799,148 @@ channel_input_data(int type, u_int32_t seq, struct ssh *ssh)
}
if (win_len > c->local_maxpacket) {
- logit("channel %d: rcvd big packet %d, maxpack %d",
+ logit("channel %d: rcvd big packet %zu, maxpack %u",
c->self, win_len, c->local_maxpacket);
+ return 0;
}
if (win_len > c->local_window) {
- logit("channel %d: rcvd too much data %d, win %d",
+ logit("channel %d: rcvd too much data %zu, win %u",
c->self, win_len, c->local_window);
return 0;
}
c->local_window -= win_len;
- if (c->datagram)
- buffer_put_string(&c->output, data, data_len);
- else
- buffer_append(&c->output, data, data_len);
- packet_check_eom();
+ if (c->datagram) {
+ if ((r = sshbuf_put_string(c->output, data, data_len)) != 0)
+ fatal("%s: channel %d: append datagram: %s",
+ __func__, c->self, ssh_err(r));
+ } else if ((r = sshbuf_put(c->output, data, data_len)) != 0)
+ fatal("%s: channel %d: append data: %s",
+ __func__, c->self, ssh_err(r));
+
return 0;
}
-/* ARGSUSED */
int
channel_input_extended_data(int type, u_int32_t seq, struct ssh *ssh)
{
- int id;
- char *data;
- u_int data_len, tcode;
- Channel *c;
-
- /* Get the channel number and verify it. */
- id = packet_get_int();
- c = channel_lookup(id);
+ const u_char *data;
+ size_t data_len;
+ u_int32_t tcode;
+ Channel *c = channel_from_packet_id(ssh, __func__, "extended data");
+ int r;
- if (c == NULL)
- packet_disconnect("Received extended_data for bad channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPEN) {
- logit("channel %d: ext data for non open", id);
+ logit("channel %d: ext data for non open", c->self);
return 0;
}
if (c->flags & CHAN_EOF_RCVD) {
if (datafellows & SSH_BUG_EXTEOF)
- debug("channel %d: accepting ext data after eof", id);
+ debug("channel %d: accepting ext data after eof",
+ c->self);
else
- packet_disconnect("Received extended_data after EOF "
- "on channel %d.", id);
+ ssh_packet_disconnect(ssh, "Received extended_data "
+ "after EOF on channel %d.", c->self);
+ }
+
+ if ((r = sshpkt_get_u32(ssh, &tcode)) != 0) {
+ error("%s: parse tcode: %s", __func__, ssh_err(r));
+ ssh_packet_disconnect(ssh, "Invalid extended_data message");
}
- tcode = packet_get_int();
if (c->efd == -1 ||
c->extended_usage != CHAN_EXTENDED_WRITE ||
tcode != SSH2_EXTENDED_DATA_STDERR) {
logit("channel %d: bad ext data", c->self);
return 0;
}
- data = packet_get_string(&data_len);
- packet_check_eom();
+ if ((r = sshpkt_get_string_direct(ssh, &data, &data_len)) != 0) {
+ error("%s: parse data: %s", __func__, ssh_err(r));
+ ssh_packet_disconnect(ssh, "Invalid extended_data message");
+ }
+ ssh_packet_check_eom(ssh);
+
if (data_len > c->local_window) {
- logit("channel %d: rcvd too much extended_data %d, win %d",
+ logit("channel %d: rcvd too much extended_data %zu, win %u",
c->self, data_len, c->local_window);
- free(data);
return 0;
}
- debug2("channel %d: rcvd ext data %d", c->self, data_len);
+ debug2("channel %d: rcvd ext data %zu", c->self, data_len);
+ /* XXX sshpkt_getb? */
+ if ((r = sshbuf_put(c->extended, data, data_len)) != 0)
+ error("%s: append: %s", __func__, ssh_err(r));
c->local_window -= data_len;
- buffer_append(&c->extended, data, data_len);
- free(data);
return 0;
}
-/* ARGSUSED */
int
channel_input_ieof(int type, u_int32_t seq, struct ssh *ssh)
{
- int id;
- Channel *c;
+ Channel *c = channel_from_packet_id(ssh, __func__, "ieof");
+
+ ssh_packet_check_eom(ssh);
- id = packet_get_int();
- packet_check_eom();
- c = channel_lookup(id);
- if (c == NULL)
- packet_disconnect("Received ieof for nonexistent channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
- chan_rcvd_ieof(c);
+ chan_rcvd_ieof(ssh, c);
/* XXX force input close */
if (c->force_drain && c->istate == CHAN_INPUT_OPEN) {
debug("channel %d: FORCE input drain", c->self);
c->istate = CHAN_INPUT_WAIT_DRAIN;
- if (buffer_len(&c->input) == 0)
- chan_ibuf_empty(c);
+ if (sshbuf_len(c->input) == 0)
+ chan_ibuf_empty(ssh, c);
}
return 0;
}
-/* ARGSUSED */
int
channel_input_oclose(int type, u_int32_t seq, struct ssh *ssh)
{
- int id = packet_get_int();
- Channel *c = channel_lookup(id);
+ Channel *c = channel_from_packet_id(ssh, __func__, "oclose");
- if (c == NULL)
- packet_disconnect("Received oclose for nonexistent channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
- packet_check_eom();
- chan_rcvd_oclose(c);
+ ssh_packet_check_eom(ssh);
+ chan_rcvd_oclose(ssh, c);
return 0;
}
-/* ARGSUSED */
int
channel_input_open_confirmation(int type, u_int32_t seq, struct ssh *ssh)
{
- int id, remote_id;
- Channel *c;
-
- id = packet_get_int();
- c = channel_lookup(id);
+ Channel *c = channel_from_packet_id(ssh, __func__, "open confirmation");
+ u_int32_t remote_window, remote_maxpacket;
+ int r;
- if (c==NULL)
- packet_disconnect("Received open confirmation for "
- "unknown channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPENING)
packet_disconnect("Received open confirmation for "
- "non-opening channel %d.", id);
- remote_id = packet_get_int();
- /* Record the remote channel number and mark that the channel is now open. */
- c->remote_id = remote_id;
- c->type = SSH_CHANNEL_OPEN;
+ "non-opening channel %d.", c->self);
+ /*
+ * Record the remote channel number and mark that the channel
+ * is now open.
+ */
+ c->remote_id = channel_parse_id(ssh, __func__, "open confirmation");
+ if ((r = sshpkt_get_u32(ssh, &remote_window)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &remote_maxpacket)) != 0) {
+ error("%s: window/maxpacket: %s", __func__, ssh_err(r));
+ packet_disconnect("Invalid open confirmation message");
+ }
+ ssh_packet_check_eom(ssh);
- c->remote_window = packet_get_int();
- c->remote_maxpacket = packet_get_int();
+ c->remote_window = remote_window;
+ c->remote_maxpacket = remote_maxpacket;
+ c->type = SSH_CHANNEL_OPEN;
if (c->open_confirm) {
- debug2("callback start");
- c->open_confirm(c->self, 1, c->open_confirm_ctx);
- debug2("callback done");
+ debug2("%s: channel %d: callback start", __func__, c->self);
+ c->open_confirm(ssh, c->self, 1, c->open_confirm_ctx);
+ debug2("%s: channel %d: callback done", __func__, c->self);
}
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
c->remote_window, c->remote_maxpacket);
- packet_check_eom();
return 0;
}
@@ -2679,97 +2960,97 @@ reason2txt(int reason)
return "unknown reason";
}
-/* ARGSUSED */
int
channel_input_open_failure(int type, u_int32_t seq, struct ssh *ssh)
{
- int id, reason;
- char *msg = NULL, *lang = NULL;
- Channel *c;
-
- id = packet_get_int();
- c = channel_lookup(id);
+ Channel *c = channel_from_packet_id(ssh, __func__, "open failure");
+ u_int32_t reason;
+ char *msg = NULL;
+ int r;
- if (c==NULL)
- packet_disconnect("Received open failure for "
- "unknown channel %d.", id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
if (c->type != SSH_CHANNEL_OPENING)
packet_disconnect("Received open failure for "
- "non-opening channel %d.", id);
- reason = packet_get_int();
- if (!(datafellows & SSH_BUG_OPENFAILURE)) {
- msg = packet_get_string(NULL);
- lang = packet_get_string(NULL);
+ "non-opening channel %d.", c->self);
+ if ((r = sshpkt_get_u32(ssh, &reason)) != 0) {
+ error("%s: reason: %s", __func__, ssh_err(r));
+ packet_disconnect("Invalid open failure message");
+ }
+ if ((datafellows & SSH_BUG_OPENFAILURE) == 0) {
+ /* skip language */
+ if ((r = sshpkt_get_cstring(ssh, &msg, NULL)) != 0 ||
+ (r = sshpkt_get_string_direct(ssh, NULL, NULL)) == 0) {
+ error("%s: message/lang: %s", __func__, ssh_err(r));
+ packet_disconnect("Invalid open failure message");
+ }
}
- logit("channel %d: open failed: %s%s%s", id,
+ ssh_packet_check_eom(ssh);
+ logit("channel %d: open failed: %s%s%s", c->self,
reason2txt(reason), msg ? ": ": "", msg ? msg : "");
free(msg);
- free(lang);
if (c->open_confirm) {
- debug2("callback start");
- c->open_confirm(c->self, 0, c->open_confirm_ctx);
- debug2("callback done");
+ debug2("%s: channel %d: callback start", __func__, c->self);
+ c->open_confirm(ssh, c->self, 0, c->open_confirm_ctx);
+ debug2("%s: channel %d: callback done", __func__, c->self);
}
- packet_check_eom();
/* Schedule the channel for cleanup/deletion. */
- chan_mark_dead(c);
+ chan_mark_dead(ssh, c);
return 0;
}
-/* ARGSUSED */
int
channel_input_window_adjust(int type, u_int32_t seq, struct ssh *ssh)
{
+ int id = channel_parse_id(ssh, __func__, "window adjust");
Channel *c;
- int id;
- u_int adjust, tmp;
-
- /* Get the channel number and verify it. */
- id = packet_get_int();
- c = channel_lookup(id);
+ u_int32_t adjust;
+ u_int new_rwin;
+ int r;
- if (c == NULL) {
+ if ((c = channel_lookup(ssh, id)) == NULL) {
logit("Received window adjust for non-open channel %d.", id);
return 0;
- }
+ }
+
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
- adjust = packet_get_int();
- packet_check_eom();
- debug2("channel %d: rcvd adjust %u", id, adjust);
- if ((tmp = c->remote_window + adjust) < c->remote_window)
+ if ((r = sshpkt_get_u32(ssh, &adjust)) != 0) {
+ error("%s: adjust: %s", __func__, ssh_err(r));
+ packet_disconnect("Invalid window adjust message");
+ }
+ ssh_packet_check_eom(ssh);
+ debug2("channel %d: rcvd adjust %u", c->self, adjust);
+ if ((new_rwin = c->remote_window + adjust) < c->remote_window) {
fatal("channel %d: adjust %u overflows remote window %u",
- id, adjust, c->remote_window);
- c->remote_window = tmp;
+ c->self, adjust, c->remote_window);
+ }
+ c->remote_window = new_rwin;
return 0;
}
-/* ARGSUSED */
int
channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh)
{
+ int id = channel_parse_id(ssh, __func__, "status confirm");
Channel *c;
struct channel_confirm *cc;
- int id;
/* Reset keepalive timeout */
packet_set_alive_timeouts(0);
- id = packet_get_int();
- debug2("channel_input_status_confirm: type %d id %d", type, id);
+ debug2("%s: type %d id %d", __func__, type, id);
- if ((c = channel_lookup(id)) == NULL) {
- logit("channel_input_status_confirm: %d: unknown", id);
+ if ((c = channel_lookup(ssh, id)) == NULL) {
+ logit("%s: %d: unknown", __func__, id);
return 0;
- }
+ }
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
- packet_check_eom();
+ ssh_packet_check_eom(ssh);
if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
return 0;
- cc->cb(type, c, cc->ctx);
+ cc->cb(ssh, type, c, cc->ctx);
TAILQ_REMOVE(&c->status_confirms, cc, entry);
explicit_bzero(cc, sizeof(*cc));
free(cc);
@@ -2779,9 +3060,9 @@ channel_input_status_confirm(int type, u_int32_t seq, struct ssh *ssh)
/* -- tcp forwarding */
void
-channel_set_af(int af)
+channel_set_af(struct ssh *ssh, int af)
{
- IPv4or6 = af;
+ ssh->chanctxt->IPv4or6 = af;
}
@@ -2849,8 +3130,9 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
}
static int
-channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
- int *allocated_listen_port, struct ForwardOptions *fwd_opts)
+channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type,
+ struct Forward *fwd, int *allocated_listen_port,
+ struct ForwardOptions *fwd_opts)
{
Channel *c;
int sock, r, success = 0, wildcard = 0, is_client;
@@ -2887,7 +3169,7 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
* set to NULL and hints.ai_flags is not AI_PASSIVE
*/
memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
+ hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_flags = wildcard ? AI_PASSIVE : 0;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", fwd->listen_port);
@@ -2921,12 +3203,14 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
* If allocating a port for -R forwards, then use the
* same port for all address families.
*/
- if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
- allocated_listen_port != NULL && *allocated_listen_port > 0)
+ if (type == SSH_CHANNEL_RPORT_LISTENER &&
+ fwd->listen_port == 0 && allocated_listen_port != NULL &&
+ *allocated_listen_port > 0)
*lport_p = htons(*allocated_listen_port);
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
- strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+ strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
error("%s: getnameinfo failed", __func__);
continue;
}
@@ -2947,7 +3231,10 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
/* Bind the socket to the address. */
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- /* address can be in use ipv6 address is already bound */
+ /*
+ * address can be in if use ipv6 address is
+ * already bound
+ */
if (!ai->ai_next)
error("bind: %.100s", strerror(errno));
else
@@ -2967,7 +3254,8 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
* fwd->listen_port == 0 requests a dynamically allocated port -
* record what we got.
*/
- if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
+ if (type == SSH_CHANNEL_RPORT_LISTENER &&
+ fwd->listen_port == 0 &&
allocated_listen_port != NULL &&
*allocated_listen_port == 0) {
*allocated_listen_port = get_local_port(sock);
@@ -2976,7 +3264,7 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
}
/* Allocate a channel number for the socket. */
- c = channel_new("port listener", type, sock, sock, -1,
+ c = channel_new(ssh, "port listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "port listener", 1);
c->path = xstrdup(host);
@@ -2997,8 +3285,8 @@ channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
}
static int
-channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
- struct ForwardOptions *fwd_opts)
+channel_setup_fwd_listener_streamlocal(struct ssh *ssh, int type,
+ struct Forward *fwd, struct ForwardOptions *fwd_opts)
{
struct sockaddr_un sunaddr;
const char *path;
@@ -3060,7 +3348,7 @@ channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
debug("Local forwarding listening on path %s.", fwd->listen_path);
/* Allocate a channel number for the socket. */
- c = channel_new("unix listener", type, sock, sock, -1,
+ c = channel_new(ssh, "unix listener", type, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "unix listener", 1);
c->path = xstrdup(path);
@@ -3071,66 +3359,71 @@ channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
}
static int
-channel_cancel_rport_listener_tcpip(const char *host, u_short port)
+channel_cancel_rport_listener_tcpip(struct ssh *ssh,
+ const char *host, u_short port)
{
u_int i;
int found = 0;
- for (i = 0; i < channels_alloc; i++) {
- Channel *c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
continue;
if (strcmp(c->path, host) == 0 && c->listening_port == port) {
debug2("%s: close channel %d", __func__, i);
- channel_free(c);
+ channel_free(ssh, c);
found = 1;
}
}
- return (found);
+ return found;
}
static int
-channel_cancel_rport_listener_streamlocal(const char *path)
+channel_cancel_rport_listener_streamlocal(struct ssh *ssh, const char *path)
{
u_int i;
int found = 0;
- for (i = 0; i < channels_alloc; i++) {
- Channel *c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
continue;
if (c->path == NULL)
continue;
if (strcmp(c->path, path) == 0) {
debug2("%s: close channel %d", __func__, i);
- channel_free(c);
+ channel_free(ssh, c);
found = 1;
}
}
- return (found);
+ return found;
}
int
-channel_cancel_rport_listener(struct Forward *fwd)
+channel_cancel_rport_listener(struct ssh *ssh, struct Forward *fwd)
{
- if (fwd->listen_path != NULL)
- return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
- else
- return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
+ if (fwd->listen_path != NULL) {
+ return channel_cancel_rport_listener_streamlocal(ssh,
+ fwd->listen_path);
+ } else {
+ return channel_cancel_rport_listener_tcpip(ssh,
+ fwd->listen_host, fwd->listen_port);
+ }
}
static int
-channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
- int cport, struct ForwardOptions *fwd_opts)
+channel_cancel_lport_listener_tcpip(struct ssh *ssh,
+ const char *lhost, u_short lport, int cport,
+ struct ForwardOptions *fwd_opts)
{
u_int i;
int found = 0;
const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
- for (i = 0; i < channels_alloc; i++) {
- Channel *c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
continue;
if (c->listening_port != lport)
@@ -3148,16 +3441,16 @@ channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
continue;
if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
debug2("%s: close channel %d", __func__, i);
- channel_free(c);
+ channel_free(ssh, c);
found = 1;
}
}
- return (found);
+ return found;
}
static int
-channel_cancel_lport_listener_streamlocal(const char *path)
+channel_cancel_lport_listener_streamlocal(struct ssh *ssh, const char *path)
{
u_int i;
int found = 0;
@@ -3167,54 +3460,59 @@ channel_cancel_lport_listener_streamlocal(const char *path)
return 0;
}
- for (i = 0; i < channels_alloc; i++) {
- Channel *c = channels[i];
+ for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+ Channel *c = ssh->chanctxt->channels[i];
if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
continue;
if (c->listening_addr == NULL)
continue;
if (strcmp(c->listening_addr, path) == 0) {
debug2("%s: close channel %d", __func__, i);
- channel_free(c);
+ channel_free(ssh, c);
found = 1;
}
}
- return (found);
+ return found;
}
int
-channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
+channel_cancel_lport_listener(struct ssh *ssh,
+ struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
{
- if (fwd->listen_path != NULL)
- return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
- else
- return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
+ if (fwd->listen_path != NULL) {
+ return channel_cancel_lport_listener_streamlocal(ssh,
+ fwd->listen_path);
+ } else {
+ return channel_cancel_lport_listener_tcpip(ssh,
+ fwd->listen_host, fwd->listen_port, cport, fwd_opts);
+ }
}
/* protocol local port fwd, used by ssh */
int
-channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts)
+channel_setup_local_fwd_listener(struct ssh *ssh,
+ struct Forward *fwd, struct ForwardOptions *fwd_opts)
{
if (fwd->listen_path != NULL) {
- return channel_setup_fwd_listener_streamlocal(
+ return channel_setup_fwd_listener_streamlocal(ssh,
SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
} else {
- return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
- fwd, NULL, fwd_opts);
+ return channel_setup_fwd_listener_tcpip(ssh,
+ SSH_CHANNEL_PORT_LISTENER, fwd, NULL, fwd_opts);
}
}
/* protocol v2 remote port fwd, used by sshd */
int
-channel_setup_remote_fwd_listener(struct Forward *fwd,
+channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd,
int *allocated_listen_port, struct ForwardOptions *fwd_opts)
{
if (fwd->listen_path != NULL) {
- return channel_setup_fwd_listener_streamlocal(
+ return channel_setup_fwd_listener_streamlocal(ssh,
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
} else {
- return channel_setup_fwd_listener_tcpip(
+ return channel_setup_fwd_listener_tcpip(ssh,
SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
fwd_opts);
}
@@ -3248,56 +3546,61 @@ channel_rfwd_bind_host(const char *listen_host)
* channel_update_permitted_opens().
*/
int
-channel_request_remote_forwarding(struct Forward *fwd)
+channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd)
{
- int success = 0, idx = -1;
+ int r, success = 0, idx = -1;
+ char *host_to_connect, *listen_host, *listen_path;
+ int port_to_connect, listen_port;
/* Send the forward request to the remote side. */
- packet_start(SSH2_MSG_GLOBAL_REQUEST);
if (fwd->listen_path != NULL) {
- packet_put_cstring("streamlocal-forward@openssh.com");
- packet_put_char(1); /* boolean: want reply */
- packet_put_cstring(fwd->listen_path);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+ (r = sshpkt_put_cstring(ssh,
+ "streamlocal-forward@openssh.com")) != 0 ||
+ (r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */
+ (r = sshpkt_put_cstring(ssh, fwd->listen_path)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0 ||
+ (r = ssh_packet_write_wait(ssh)) != 0)
+ fatal("%s: request streamlocal: %s",
+ __func__, ssh_err(r));
} else {
- packet_put_cstring("tcpip-forward");
- packet_put_char(1); /* boolean: want reply */
- packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
- packet_put_int(fwd->listen_port);
+ if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 ||
+ (r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */
+ (r = sshpkt_put_cstring(ssh,
+ channel_rfwd_bind_host(fwd->listen_host))) != 0 ||
+ (r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0 ||
+ (r = ssh_packet_write_wait(ssh)) != 0)
+ fatal("%s: request tcpip-forward: %s",
+ __func__, ssh_err(r));
}
- packet_send();
- packet_write_wait();
/* Assume that server accepts the request */
success = 1;
if (success) {
/* Record that connection to this host/port is permitted. */
- permitted_opens = xreallocarray(permitted_opens,
- num_permitted_opens + 1, sizeof(*permitted_opens));
- idx = num_permitted_opens++;
+ host_to_connect = listen_host = listen_path = NULL;
+ port_to_connect = listen_port = 0;
if (fwd->connect_path != NULL) {
- permitted_opens[idx].host_to_connect =
- xstrdup(fwd->connect_path);
- permitted_opens[idx].port_to_connect =
- PORT_STREAMLOCAL;
+ host_to_connect = xstrdup(fwd->connect_path);
+ port_to_connect = PORT_STREAMLOCAL;
} else {
- permitted_opens[idx].host_to_connect =
- xstrdup(fwd->connect_host);
- permitted_opens[idx].port_to_connect =
- fwd->connect_port;
+ host_to_connect = xstrdup(fwd->connect_host);
+ port_to_connect = fwd->connect_port;
}
if (fwd->listen_path != NULL) {
- permitted_opens[idx].listen_host = NULL;
- permitted_opens[idx].listen_path =
- xstrdup(fwd->listen_path);
- permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
+ listen_path = xstrdup(fwd->listen_path);
+ listen_port = PORT_STREAMLOCAL;
} else {
- permitted_opens[idx].listen_host =
- fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
- permitted_opens[idx].listen_path = NULL;
- permitted_opens[idx].listen_port = fwd->listen_port;
+ if (fwd->listen_host != NULL)
+ listen_host = xstrdup(fwd->listen_host);
+ listen_port = fwd->listen_port;
}
- permitted_opens[idx].downstream = NULL;
+ idx = fwd_perm_list_add(ssh, FWDPERM_USER,
+ host_to_connect, port_to_connect,
+ listen_host, listen_path, listen_port, NULL);
}
- return (idx);
+ return idx;
}
static int
@@ -3362,33 +3665,33 @@ open_listen_match_streamlocal(ForwardPermission *allowed_open,
* local side.
*/
static int
-channel_request_rforward_cancel_tcpip(const char *host, u_short port)
+channel_request_rforward_cancel_tcpip(struct ssh *ssh,
+ const char *host, u_short port)
{
- int i;
+ struct ssh_channels *sc = ssh->chanctxt;
+ int r;
+ u_int i;
+ ForwardPermission *fp;
- for (i = 0; i < num_permitted_opens; i++) {
- if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_listen_match_tcpip(fp, host, port, 0))
break;
+ fp = NULL;
}
- if (i >= num_permitted_opens) {
+ if (fp == NULL) {
debug("%s: requested forward not found", __func__);
return -1;
}
- packet_start(SSH2_MSG_GLOBAL_REQUEST);
- packet_put_cstring("cancel-tcpip-forward");
- packet_put_char(0);
- packet_put_cstring(channel_rfwd_bind_host(host));
- packet_put_int(port);
- packet_send();
-
- 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 ((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 || /* want reply */
+ (r = sshpkt_put_cstring(ssh, channel_rfwd_bind_host(host))) != 0 ||
+ (r = sshpkt_put_u32(ssh, port)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: send cancel: %s", __func__, ssh_err(r));
+
+ fwd_perm_clear(fp); /* unregister */
return 0;
}
@@ -3398,32 +3701,32 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port)
* path from local side.
*/
static int
-channel_request_rforward_cancel_streamlocal(const char *path)
+channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path)
{
- int i;
+ struct ssh_channels *sc = ssh->chanctxt;
+ int r;
+ u_int i;
+ ForwardPermission *fp;
- for (i = 0; i < num_permitted_opens; i++) {
- if (open_listen_match_streamlocal(&permitted_opens[i], path))
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_listen_match_streamlocal(fp, path))
break;
+ fp = NULL;
}
- if (i >= num_permitted_opens) {
+ if (fp == NULL) {
debug("%s: requested forward not found", __func__);
return -1;
}
- packet_start(SSH2_MSG_GLOBAL_REQUEST);
- packet_put_cstring("cancel-streamlocal-forward@openssh.com");
- packet_put_char(0);
- packet_put_cstring(path);
- packet_send();
-
- 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;
- permitted_opens[i].listen_host = NULL;
- free(permitted_opens[i].listen_path);
- permitted_opens[i].listen_path = NULL;
- permitted_opens[i].downstream = NULL;
+ if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+ (r = sshpkt_put_cstring(ssh,
+ "cancel-streamlocal-forward@openssh.com")) != 0 ||
+ (r = sshpkt_put_u8(ssh, 0)) != 0 || /* want reply */
+ (r = sshpkt_put_cstring(ssh, path)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: send cancel: %s", __func__, ssh_err(r));
+
+ fwd_perm_clear(fp); /* unregister */
return 0;
}
@@ -3432,14 +3735,15 @@ channel_request_rforward_cancel_streamlocal(const char *path)
* Request cancellation of remote forwarding of a connection from local side.
*/
int
-channel_request_rforward_cancel(struct Forward *fwd)
+channel_request_rforward_cancel(struct ssh *ssh, struct Forward *fwd)
{
if (fwd->listen_path != NULL) {
- return (channel_request_rforward_cancel_streamlocal(
- fwd->listen_path));
+ return channel_request_rforward_cancel_streamlocal(ssh,
+ fwd->listen_path);
} else {
- return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
- fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
+ return channel_request_rforward_cancel_tcpip(ssh,
+ fwd->listen_host,
+ fwd->listen_port ? fwd->listen_port : fwd->allocated_port);
}
}
@@ -3449,28 +3753,20 @@ channel_request_rforward_cancel(struct Forward *fwd)
* anyway, and the server has no way to know but to trust the client anyway.
*/
void
-channel_permit_all_opens(void)
+channel_permit_all_opens(struct ssh *ssh)
{
- if (num_permitted_opens == 0)
- all_opens_permitted = 1;
+ if (ssh->chanctxt->num_permitted_opens == 0)
+ ssh->chanctxt->all_opens_permitted = 1;
}
void
-channel_add_permitted_opens(char *host, int port)
+channel_add_permitted_opens(struct ssh *ssh, char *host, int port)
{
- debug("allow port forwarding to host %s port %d", host, port);
+ struct ssh_channels *sc = ssh->chanctxt;
- permitted_opens = xreallocarray(permitted_opens,
- num_permitted_opens + 1, sizeof(*permitted_opens));
- permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
- permitted_opens[num_permitted_opens].port_to_connect = port;
- permitted_opens[num_permitted_opens].listen_host = NULL;
- permitted_opens[num_permitted_opens].listen_path = NULL;
- permitted_opens[num_permitted_opens].listen_port = 0;
- permitted_opens[num_permitted_opens].downstream = NULL;
- num_permitted_opens++;
-
- all_opens_permitted = 0;
+ debug("allow port forwarding to host %s port %d", host, port);
+ fwd_perm_list_add(ssh, FWDPERM_USER, host, port, NULL, NULL, 0, NULL);
+ sc->all_opens_permitted = 0;
}
/*
@@ -3479,105 +3775,61 @@ channel_add_permitted_opens(char *host, int port)
* passed then they entry will be invalidated.
*/
void
-channel_update_permitted_opens(int idx, int newport)
+channel_update_permitted_opens(struct ssh *ssh, int idx, int newport)
{
- if (idx < 0 || idx >= num_permitted_opens) {
- debug("channel_update_permitted_opens: index out of range:"
- " %d num_permitted_opens %d", idx, num_permitted_opens);
+ struct ssh_channels *sc = ssh->chanctxt;
+
+ if (idx < 0 || (u_int)idx >= sc->num_permitted_opens) {
+ debug("%s: index out of range: %d num_permitted_opens %d",
+ __func__, idx, sc->num_permitted_opens);
return;
}
debug("%s allowed port %d for forwarding to host %s port %d",
newport > 0 ? "Updating" : "Removing",
newport,
- permitted_opens[idx].host_to_connect,
- permitted_opens[idx].port_to_connect);
- if (newport >= 0) {
- permitted_opens[idx].listen_port =
+ sc->permitted_opens[idx].host_to_connect,
+ sc->permitted_opens[idx].port_to_connect);
+ if (newport <= 0)
+ fwd_perm_clear(&sc->permitted_opens[idx]);
+ else {
+ sc->permitted_opens[idx].listen_port =
(datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport;
- } else {
- permitted_opens[idx].listen_port = 0;
- permitted_opens[idx].port_to_connect = 0;
- free(permitted_opens[idx].host_to_connect);
- permitted_opens[idx].host_to_connect = NULL;
- free(permitted_opens[idx].listen_host);
- permitted_opens[idx].listen_host = NULL;
- free(permitted_opens[idx].listen_path);
- permitted_opens[idx].listen_path = NULL;
}
}
int
-channel_add_adm_permitted_opens(char *host, int port)
+channel_add_adm_permitted_opens(struct ssh *ssh, char *host, int port)
{
debug("config allows port forwarding to host %s port %d", host, port);
-
- permitted_adm_opens = xreallocarray(permitted_adm_opens,
- num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
- permitted_adm_opens[num_adm_permitted_opens].host_to_connect
- = xstrdup(host);
- permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
- permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
- permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
- permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
- return ++num_adm_permitted_opens;
-}
-
-void
-channel_disable_adm_local_opens(void)
-{
- channel_clear_adm_permitted_opens();
- permitted_adm_opens = xcalloc(sizeof(*permitted_adm_opens), 1);
- permitted_adm_opens[num_adm_permitted_opens].host_to_connect = NULL;
- num_adm_permitted_opens = 1;
+ return fwd_perm_list_add(ssh, FWDPERM_ADMIN, host, port,
+ NULL, NULL, 0, NULL);
}
void
-channel_clear_permitted_opens(void)
+channel_disable_adm_local_opens(struct ssh *ssh)
{
- int i;
-
- for (i = 0; i < num_permitted_opens; i++) {
- free(permitted_opens[i].host_to_connect);
- free(permitted_opens[i].listen_host);
- free(permitted_opens[i].listen_path);
- }
- free(permitted_opens);
- permitted_opens = NULL;
- num_permitted_opens = 0;
+ channel_clear_adm_permitted_opens(ssh);
+ fwd_perm_list_add(ssh, FWDPERM_ADMIN, NULL, 0, NULL, NULL, 0, NULL);
}
void
-channel_clear_adm_permitted_opens(void)
+channel_clear_permitted_opens(struct ssh *ssh)
{
- int i;
+ struct ssh_channels *sc = ssh->chanctxt;
- for (i = 0; i < num_adm_permitted_opens; i++) {
- free(permitted_adm_opens[i].host_to_connect);
- free(permitted_adm_opens[i].listen_host);
- free(permitted_adm_opens[i].listen_path);
- }
- free(permitted_adm_opens);
- permitted_adm_opens = NULL;
- num_adm_permitted_opens = 0;
+ sc->permitted_opens = xrecallocarray(sc->permitted_opens,
+ sc->num_permitted_opens, 0, sizeof(*sc->permitted_opens));
+ sc->num_permitted_opens = 0;
}
void
-channel_print_adm_permitted_opens(void)
+channel_clear_adm_permitted_opens(struct ssh *ssh)
{
- int i;
+ struct ssh_channels *sc = ssh->chanctxt;
- printf("permitopen");
- if (num_adm_permitted_opens == 0) {
- printf(" any\n");
- return;
- }
- for (i = 0; i < num_adm_permitted_opens; i++)
- if (permitted_adm_opens[i].host_to_connect == NULL)
- printf(" none");
- else
- printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
- permitted_adm_opens[i].port_to_connect);
- printf("\n");
+ sc->permitted_adm_opens = xrecallocarray(sc->permitted_adm_opens,
+ sc->num_adm_permitted_opens, 0, sizeof(*sc->permitted_adm_opens));
+ sc->num_adm_permitted_opens = 0;
}
/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
@@ -3599,7 +3851,8 @@ connect_next(struct channel_connect *cctx)
{
int sock, saved_errno;
struct sockaddr_un *sunaddr;
- char ntop[NI_MAXHOST], strport[MAXIMUM(NI_MAXSERV,sizeof(sunaddr->sun_path))];
+ char ntop[NI_MAXHOST];
+ char strport[MAXIMUM(NI_MAXSERV, sizeof(sunaddr->sun_path))];
for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
switch (cctx->ai->ai_family) {
@@ -3669,8 +3922,8 @@ channel_connect_ctx_free(struct channel_connect *cctx)
* passing back the failure reason if appropriate.
*/
static Channel *
-connect_to_reason(const char *name, int port, char *ctype, char *rname,
- int *reason, const char **errmsg)
+connect_to_reason(struct ssh *ssh, const char *name, int port,
+ char *ctype, char *rname, int *reason, const char **errmsg)
{
struct addrinfo hints;
int gaierr;
@@ -3708,7 +3961,7 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname,
cctx.aitop = ai;
} else {
memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
+ hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop))
@@ -3733,7 +3986,7 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname,
channel_connect_ctx_free(&cctx);
return NULL;
}
- c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
+ c = channel_new(ssh, ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
c->connect_ctx = cctx;
return c;
@@ -3741,9 +3994,10 @@ connect_to_reason(const char *name, int port, char *ctype, char *rname,
/* Return CONNECTING channel to remote host:port or local socket path */
static Channel *
-connect_to(const char *name, int port, char *ctype, char *rname)
+connect_to(struct ssh *ssh, const char *name, int port,
+ char *ctype, char *rname)
{
- return connect_to_reason(name, port, ctype, rname, NULL, NULL);
+ return connect_to_reason(ssh, name, port, ctype, rname, NULL, NULL);
}
/*
@@ -3751,19 +4005,21 @@ connect_to(const char *name, int port, char *ctype, char *rname)
* that needs to deal with this connection.
*/
Channel *
-channel_connect_by_listen_address(const char *listen_host,
+channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host,
u_short listen_port, char *ctype, char *rname)
{
- int i;
-
- for (i = 0; i < num_permitted_opens; i++) {
- if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
- listen_port, 1)) {
- if (permitted_opens[i].downstream)
- return permitted_opens[i].downstream;
- return connect_to(
- permitted_opens[i].host_to_connect,
- permitted_opens[i].port_to_connect, ctype, rname);
+ struct ssh_channels *sc = ssh->chanctxt;
+ u_int i;
+ ForwardPermission *fp;
+
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) {
+ if (fp->downstream)
+ return fp->downstream;
+ return connect_to(ssh,
+ fp->host_to_connect, fp->port_to_connect,
+ ctype, rname);
}
}
error("WARNING: Server requests forwarding for unknown listen_port %d",
@@ -3772,15 +4028,19 @@ channel_connect_by_listen_address(const char *listen_host,
}
Channel *
-channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
+channel_connect_by_listen_path(struct ssh *ssh, const char *path,
+ char *ctype, char *rname)
{
- int i;
-
- for (i = 0; i < num_permitted_opens; i++) {
- if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
- return connect_to(
- permitted_opens[i].host_to_connect,
- permitted_opens[i].port_to_connect, ctype, rname);
+ struct ssh_channels *sc = ssh->chanctxt;
+ u_int i;
+ ForwardPermission *fp;
+
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_listen_match_streamlocal(fp, path)) {
+ return connect_to(ssh,
+ fp->host_to_connect, fp->port_to_connect,
+ ctype, rname);
}
}
error("WARNING: Server requests forwarding for unknown path %.100s",
@@ -3790,27 +4050,33 @@ channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
/* Check if connecting to that port is permitted and connect. */
Channel *
-channel_connect_to_port(const char *host, u_short port, char *ctype,
- char *rname, int *reason, const char **errmsg)
+channel_connect_to_port(struct ssh *ssh, const char *host, u_short port,
+ char *ctype, char *rname, int *reason, const char **errmsg)
{
- int i, permit, permit_adm = 1;
+ struct ssh_channels *sc = ssh->chanctxt;
+ u_int i, permit, permit_adm = 1;
+ ForwardPermission *fp;
- permit = all_opens_permitted;
+ permit = sc->all_opens_permitted;
if (!permit) {
- for (i = 0; i < num_permitted_opens; i++)
- if (open_match(&permitted_opens[i], host, port)) {
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_match(fp, host, port)) {
permit = 1;
break;
}
+ }
}
- if (num_adm_permitted_opens > 0) {
+ if (sc->num_adm_permitted_opens > 0) {
permit_adm = 0;
- for (i = 0; i < num_adm_permitted_opens; i++)
- if (open_match(&permitted_adm_opens[i], host, port)) {
+ for (i = 0; i < sc->num_adm_permitted_opens; i++) {
+ fp = &sc->permitted_adm_opens[i];
+ if (open_match(fp, host, port)) {
permit_adm = 1;
break;
}
+ }
}
if (!permit || !permit_adm) {
@@ -3820,31 +4086,38 @@ channel_connect_to_port(const char *host, u_short port, char *ctype,
*reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED;
return NULL;
}
- return connect_to_reason(host, port, ctype, rname, reason, errmsg);
+ return connect_to_reason(ssh, host, port, ctype, rname, reason, errmsg);
}
/* Check if connecting to that path is permitted and connect. */
Channel *
-channel_connect_to_path(const char *path, char *ctype, char *rname)
+channel_connect_to_path(struct ssh *ssh, const char *path,
+ char *ctype, char *rname)
{
- int i, permit, permit_adm = 1;
+ struct ssh_channels *sc = ssh->chanctxt;
+ u_int i, permit, permit_adm = 1;
+ ForwardPermission *fp;
- permit = all_opens_permitted;
+ permit = sc->all_opens_permitted;
if (!permit) {
- for (i = 0; i < num_permitted_opens; i++)
- if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
+ for (i = 0; i < sc->num_permitted_opens; i++) {
+ fp = &sc->permitted_opens[i];
+ if (open_match(fp, path, PORT_STREAMLOCAL)) {
permit = 1;
break;
}
+ }
}
- if (num_adm_permitted_opens > 0) {
+ if (sc->num_adm_permitted_opens > 0) {
permit_adm = 0;
- for (i = 0; i < num_adm_permitted_opens; i++)
- if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
+ for (i = 0; i < sc->num_adm_permitted_opens; i++) {
+ fp = &sc->permitted_adm_opens[i];
+ if (open_match(fp, path, PORT_STREAMLOCAL)) {
permit_adm = 1;
break;
}
+ }
}
if (!permit || !permit_adm) {
@@ -3852,27 +4125,31 @@ channel_connect_to_path(const char *path, char *ctype, char *rname)
"but the request was denied.", path);
return NULL;
}
- return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
+ return connect_to(ssh, path, PORT_STREAMLOCAL, ctype, rname);
}
void
-channel_send_window_changes(void)
+channel_send_window_changes(struct ssh *ssh)
{
- u_int i;
+ struct ssh_channels *sc = ssh->chanctxt;
struct winsize ws;
+ int r;
+ u_int i;
- for (i = 0; i < channels_alloc; i++) {
- if (channels[i] == NULL || !channels[i]->client_tty ||
- channels[i]->type != SSH_CHANNEL_OPEN)
+ for (i = 0; i < sc->channels_alloc; i++) {
+ if (sc->channels[i] == NULL || !sc->channels[i]->client_tty ||
+ sc->channels[i]->type != SSH_CHANNEL_OPEN)
continue;
- if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
+ if (ioctl(sc->channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
continue;
- channel_request_start(i, "window-change", 0);
- packet_put_int((u_int)ws.ws_col);
- packet_put_int((u_int)ws.ws_row);
- packet_put_int((u_int)ws.ws_xpixel);
- packet_put_int((u_int)ws.ws_ypixel);
- packet_send();
+ channel_request_start(ssh, i, "window-change", 0);
+ if ((r = sshpkt_put_u32(ssh, (u_int)ws.ws_col)) != 0 ||
+ (r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 ||
+ (r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 ||
+ (r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: channel %u: send window-change: %s",
+ __func__, i, ssh_err(r));
}
}
@@ -3884,8 +4161,9 @@ channel_send_window_changes(void)
* stored in display_numberp , or -1 if an error occurs.
*/
int
-x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
- int single_connection, u_int *display_numberp, int **chanids)
+x11_create_display_inet(struct ssh *ssh, int x11_display_offset,
+ int x11_use_localhost, int single_connection,
+ u_int *display_numberp, int **chanids)
{
Channel *nc = NULL;
int display_number, sock;
@@ -3902,16 +4180,18 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
display_number++) {
port = 6000 + display_number;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
+ hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", port);
- if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
+ if ((gaierr = getaddrinfo(NULL, strport,
+ &hints, &aitop)) != 0) {
error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ if (ai->ai_family != AF_INET &&
+ ai->ai_family != AF_INET6)
continue;
sock = socket(ai->ai_family, ai->ai_socktype,
ai->ai_protocol);
@@ -3935,12 +4215,11 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
if (x11_use_localhost)
channel_set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- debug2("bind port %d: %.100s", port, strerror(errno));
+ debug2("%s: bind port %d: %.100s", __func__,
+ port, strerror(errno));
close(sock);
-
- for (n = 0; n < num_socks; n++) {
+ for (n = 0; n < num_socks; n++)
close(socks[n]);
- }
num_socks = 0;
break;
}
@@ -3970,7 +4249,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
*chanids = xcalloc(num_socks + 1, sizeof(**chanids));
for (n = 0; n < num_socks; n++) {
sock = socks[n];
- nc = channel_new("x11 listener",
+ nc = channel_new(ssh, "x11 listener",
SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "X11 inet listener", 1);
@@ -3981,7 +4260,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
/* Return the display number for the DISPLAY environment variable. */
*display_numberp = display_number;
- return (0);
+ return 0;
}
static int
@@ -4039,7 +4318,7 @@ is_path_to_xsocket(const char *display, char *path, size_t pathlen)
#endif
int
-x11_connect_display(void)
+x11_connect_display(struct ssh *ssh)
{
u_int display_number;
const char *display;
@@ -4084,9 +4363,10 @@ x11_connect_display(void)
if (strncmp(display, "unix:", 5) == 0 ||
display[0] == ':') {
/* Connect to the unix domain socket. */
- if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
- error("Could not parse display number from DISPLAY: %.100s",
- display);
+ if (sscanf(strrchr(display, ':') + 1, "%u",
+ &display_number) != 1) {
+ error("Could not parse display number from DISPLAY: "
+ "%.100s", display);
return -1;
}
/* Create a socket. */
@@ -4108,7 +4388,10 @@ x11_connect_display(void)
return -1;
}
*cp = 0;
- /* buf now contains the host name. But first we parse the display number. */
+ /*
+ * buf now contains the host name. But first we parse the
+ * display number.
+ */
if (sscanf(cp + 1, "%u", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
display);
@@ -4117,7 +4400,7 @@ x11_connect_display(void)
/* Look up the host address */
memset(&hints, 0, sizeof(hints));
- hints.ai_family = IPv4or6;
+ hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%u", 6000 + display_number);
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
@@ -4144,8 +4427,8 @@ x11_connect_display(void)
}
freeaddrinfo(aitop);
if (!ai) {
- error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
- strerror(errno));
+ error("connect %.100s port %u: %.100s", buf,
+ 6000 + display_number, strerror(errno));
return -1;
}
set_nodelay(sock);
@@ -4158,18 +4441,19 @@ x11_connect_display(void)
* This should be called in the client only.
*/
void
-x11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
- const char *proto, const char *data, int want_reply)
+x11_request_forwarding_with_spoofing(struct ssh *ssh, int client_session_id,
+ const char *disp, const char *proto, const char *data, int want_reply)
{
+ struct ssh_channels *sc = ssh->chanctxt;
u_int data_len = (u_int) strlen(data) / 2;
u_int i, value;
- char *new_data;
- int screen_number;
const char *cp;
+ char *new_data;
+ int r, screen_number;
- if (x11_saved_display == NULL)
- x11_saved_display = xstrdup(disp);
- else if (strcmp(disp, x11_saved_display) != 0) {
+ if (sc->x11_saved_display == NULL)
+ sc->x11_saved_display = xstrdup(disp);
+ else if (strcmp(disp, sc->x11_saved_display) != 0) {
error("x11_request_forwarding_with_spoofing: different "
"$DISPLAY already forwarded");
return;
@@ -4183,36 +4467,37 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
else
screen_number = 0;
- if (x11_saved_proto == NULL) {
+ if (sc->x11_saved_proto == NULL) {
/* Save protocol name. */
- x11_saved_proto = xstrdup(proto);
+ sc->x11_saved_proto = xstrdup(proto);
/* Extract real authentication data. */
- x11_saved_data = xmalloc(data_len);
+ sc->x11_saved_data = xmalloc(data_len);
for (i = 0; i < data_len; i++) {
if (sscanf(data + 2 * i, "%2x", &value) != 1)
fatal("x11_request_forwarding: bad "
"authentication data: %.100s", data);
- x11_saved_data[i] = value;
+ sc->x11_saved_data[i] = value;
}
- x11_saved_data_len = data_len;
+ sc->x11_saved_data_len = data_len;
/* Generate fake data of the same length. */
- x11_fake_data = xmalloc(data_len);
- arc4random_buf(x11_fake_data, data_len);
- x11_fake_data_len = data_len;
+ sc->x11_fake_data = xmalloc(data_len);
+ arc4random_buf(sc->x11_fake_data, data_len);
+ sc->x11_fake_data_len = data_len;
}
/* Convert the fake data into hex. */
- new_data = tohex(x11_fake_data, data_len);
+ new_data = tohex(sc->x11_fake_data, data_len);
/* Send the request packet. */
- channel_request_start(client_session_id, "x11-req", want_reply);
- packet_put_char(0); /* XXX bool single connection */
- packet_put_cstring(proto);
- packet_put_cstring(new_data);
- packet_put_int(screen_number);
- packet_send();
- packet_write_wait();
+ channel_request_start(ssh, client_session_id, "x11-req", want_reply);
+ if ((r = sshpkt_put_u8(ssh, 0)) != 0 || /* bool: single connection */
+ (r = sshpkt_put_cstring(ssh, proto)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, new_data)) != 0 ||
+ (r = sshpkt_put_u32(ssh, screen_number)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0 ||
+ (r = ssh_packet_write_wait(ssh)) != 0)
+ fatal("%s: send x11-req: %s", __func__, ssh_err(r));
free(new_data);
}
diff --git a/channels.h b/channels.h
index 5ecb4d7c..f04c43af 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.127 2017/08/30 03:59:08 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.128 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -64,16 +64,18 @@
struct ssh;
struct Channel;
typedef struct Channel Channel;
+struct fwd_perm_list;
-typedef void channel_open_fn(int, int, void *);
-typedef void channel_callback_fn(int, void *);
-typedef int channel_infilter_fn(struct Channel *, char *, int);
-typedef void channel_filter_cleanup_fn(int, void *);
-typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
+typedef void channel_open_fn(struct ssh *, int, int, void *);
+typedef void channel_callback_fn(struct ssh *, int, void *);
+typedef int channel_infilter_fn(struct ssh *, struct Channel *, char *, int);
+typedef void channel_filter_cleanup_fn(struct ssh *, int, void *);
+typedef u_char *channel_outfilter_fn(struct ssh *, struct Channel *,
+ u_char **, size_t *);
/* Channel success/failure callbacks */
-typedef void channel_confirm_cb(int, struct Channel *, void *);
-typedef void channel_confirm_abandon_cb(struct Channel *, void *);
+typedef void channel_confirm_cb(struct ssh *, int, struct Channel *, void *);
+typedef void channel_confirm_abandon_cb(struct ssh *, struct Channel *, void *);
struct channel_confirm {
TAILQ_ENTRY(channel_confirm) entry;
channel_confirm_cb *cb;
@@ -90,12 +92,13 @@ struct channel_connect {
};
/* Callbacks for mux channels back into client-specific code */
-typedef int mux_callback_fn(struct Channel *);
+typedef int mux_callback_fn(struct ssh *, struct Channel *);
struct Channel {
int type; /* channel type/state */
int self; /* my own channel identifier */
int remote_id; /* channel identifier for remote peer */
+ /* XXX should be uint32_t */
u_int istate; /* input from channel (state of receive half) */
u_int ostate; /* output to channel (state of transmit half) */
int flags; /* close sent/rcvd */
@@ -116,11 +119,12 @@ struct Channel {
* to a matching pre-select handler.
* this way post-select handlers are not
* accidentally called if a FD gets reused */
- Buffer input; /* data read from socket, to be sent over
+ struct sshbuf *input; /* data read from socket, to be sent over
* encrypted connection */
- Buffer output; /* data received over encrypted connection for
+ struct sshbuf *output; /* data received over encrypted connection for
* send on socket */
- Buffer extended;
+ struct sshbuf *extended;
+
char *path;
/* path for unix domain sockets, or host name for forwards */
int listening_port; /* port being listened for forwards */
@@ -156,6 +160,7 @@ struct Channel {
int datagram;
/* non-blocking connect */
+ /* XXX make this a pointer so the structure can be opaque */
struct channel_connect connect_ctx;
/* multiplexing protocol hook, called for each packet received */
@@ -195,44 +200,55 @@ struct Channel {
#define CHAN_EOF_RCVD 0x08
#define CHAN_LOCAL 0x10
-#define CHAN_RBUF 16*1024
+/* Read buffer size */
+#define CHAN_RBUF (16*1024)
+
+/* Hard limit on number of channels */
+#define CHANNELS_MAX_CHANNELS (16*1024)
/* check whether 'efd' is still in use */
#define CHANNEL_EFD_INPUT_ACTIVE(c) \
(c->extended_usage == CHAN_EXTENDED_READ && \
(c->efd != -1 || \
- buffer_len(&c->extended) > 0))
+ sshbuf_len(c->extended) > 0))
#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
(c->extended_usage == CHAN_EXTENDED_WRITE && \
c->efd != -1 && (!(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD)) || \
- buffer_len(&c->extended) > 0))
+ sshbuf_len(c->extended) > 0))
+
+/* Add channel management structures to SSH transport instance */
+void channel_init_channels(struct ssh *ssh);
/* channel management */
-Channel *channel_by_id(int);
-Channel *channel_by_remote_id(int);
-Channel *channel_lookup(int);
-Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
-void channel_set_fds(int, int, int, int, int, int, int, u_int);
-void channel_free(Channel *);
-void channel_free_all(void);
-void channel_stop_listening(void);
-
-void channel_send_open(int);
-void channel_request_start(int, char *, int);
-void channel_register_cleanup(int, channel_callback_fn *, int);
-void channel_register_open_confirm(int, channel_open_fn *, void *);
-void channel_register_filter(int, channel_infilter_fn *,
- channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
-void channel_register_status_confirm(int, channel_confirm_cb *,
- channel_confirm_abandon_cb *, void *);
-void channel_cancel_cleanup(int);
-int channel_close_fd(int *);
-void channel_send_window_changes(void);
+Channel *channel_by_id(struct ssh *, int);
+Channel *channel_by_remote_id(struct ssh *, int);
+Channel *channel_lookup(struct ssh *, int);
+Channel *channel_new(struct ssh *, char *, int, int, int, int,
+ u_int, u_int, int, char *, int);
+void channel_set_fds(struct ssh *, int, int, int, int, int,
+ int, int, u_int);
+void channel_free(struct ssh *, Channel *);
+void channel_free_all(struct ssh *);
+void channel_stop_listening(struct ssh *);
+
+void channel_send_open(struct ssh *, int);
+void channel_request_start(struct ssh *, int, char *, int);
+void channel_register_cleanup(struct ssh *, int,
+ channel_callback_fn *, int);
+void channel_register_open_confirm(struct ssh *, int,
+ channel_open_fn *, void *);
+void channel_register_filter(struct ssh *, int, channel_infilter_fn *,
+ channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
+void channel_register_status_confirm(struct ssh *, int,
+ channel_confirm_cb *, channel_confirm_abandon_cb *, void *);
+void channel_cancel_cleanup(struct ssh *, int);
+int channel_close_fd(struct ssh *, int *);
+void channel_send_window_changes(struct ssh *);
/* mux proxy support */
-int channel_proxy_downstream(Channel *mc);
+int channel_proxy_downstream(struct ssh *, Channel *mc);
int channel_proxy_upstream(Channel *, int, u_int32_t, struct ssh *);
/* protocol handler */
@@ -252,63 +268,69 @@ int channel_input_status_confirm(int, u_int32_t, struct ssh *);
void channel_prepare_select(struct ssh *, fd_set **, fd_set **, int *,
u_int*, time_t*);
void channel_after_select(struct ssh *, fd_set *, fd_set *);
-void channel_output_poll(void);
+void channel_output_poll(struct ssh *);
-int channel_not_very_much_buffered_data(void);
-void channel_close_all(void);
-int channel_still_open(void);
-char *channel_open_message(void);
-int channel_find_open(void);
+int channel_not_very_much_buffered_data(struct ssh *);
+void channel_close_all(struct ssh *);
+int channel_still_open(struct ssh *);
+char *channel_open_message(struct ssh *);
+int channel_find_open(struct ssh *);
/* tcp forwarding */
struct Forward;
struct ForwardOptions;
-void channel_set_af(int af);
-void channel_permit_all_opens(void);
-void channel_add_permitted_opens(char *, int);
-int channel_add_adm_permitted_opens(char *, int);
-void channel_disable_adm_local_opens(void);
-void channel_update_permitted_opens(int, int);
-void channel_clear_permitted_opens(void);
-void channel_clear_adm_permitted_opens(void);
-void channel_print_adm_permitted_opens(void);
-Channel *channel_connect_to_port(const char *, u_short, char *, char *, int *,
- const char **);
-Channel *channel_connect_to_path(const char *, char *, char *);
-Channel *channel_connect_stdio_fwd(const char*, u_short, int, int);
-Channel *channel_connect_by_listen_address(const char *, u_short,
- char *, char *);
-Channel *channel_connect_by_listen_path(const char *, char *, char *);
-int channel_request_remote_forwarding(struct Forward *);
-int channel_setup_local_fwd_listener(struct Forward *, struct ForwardOptions *);
-int channel_request_rforward_cancel(struct Forward *);
-int channel_setup_remote_fwd_listener(struct Forward *, int *, struct ForwardOptions *);
-int channel_cancel_rport_listener(struct Forward *);
-int channel_cancel_lport_listener(struct Forward *, int, struct ForwardOptions *);
+void channel_set_af(struct ssh *, int af);
+void channel_permit_all_opens(struct ssh *);
+void channel_add_permitted_opens(struct ssh *, char *, int);
+int channel_add_adm_permitted_opens(struct ssh *, char *, int);
+void channel_copy_adm_permitted_opens(struct ssh *,
+ const struct fwd_perm_list *);
+void channel_disable_adm_local_opens(struct ssh *);
+void channel_update_permitted_opens(struct ssh *, int, int);
+void channel_clear_permitted_opens(struct ssh *);
+void channel_clear_adm_permitted_opens(struct ssh *);
+void channel_print_adm_permitted_opens(struct ssh *);
+Channel *channel_connect_to_port(struct ssh *, const char *, u_short,
+ char *, char *, int *, const char **);
+Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *);
+Channel *channel_connect_stdio_fwd(struct ssh *, const char*,
+ u_short, int, int);
+Channel *channel_connect_by_listen_address(struct ssh *, const char *,
+ u_short, char *, char *);
+Channel *channel_connect_by_listen_path(struct ssh *, const char *,
+ char *, char *);
+int channel_request_remote_forwarding(struct ssh *, struct Forward *);
+int channel_setup_local_fwd_listener(struct ssh *, struct Forward *,
+ struct ForwardOptions *);
+int channel_request_rforward_cancel(struct ssh *, struct Forward *);
+int channel_setup_remote_fwd_listener(struct ssh *, struct Forward *,
+ int *, struct ForwardOptions *);
+int channel_cancel_rport_listener(struct ssh *, struct Forward *);
+int channel_cancel_lport_listener(struct ssh *, struct Forward *,
+ int, struct ForwardOptions *);
int permitopen_port(const char *);
/* x11 forwarding */
-void channel_set_x11_refuse_time(u_int);
-int x11_connect_display(void);
-int x11_create_display_inet(int, int, int, u_int *, int **);
-void x11_request_forwarding_with_spoofing(int, const char *, const char *,
- const char *, int);
+void channel_set_x11_refuse_time(struct ssh *, u_int);
+int x11_connect_display(struct ssh *);
+int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **);
+void x11_request_forwarding_with_spoofing(struct ssh *, int,
+ const char *, const char *, const char *, int);
/* channel close */
-int chan_is_dead(Channel *, int);
-void chan_mark_dead(Channel *);
+int chan_is_dead(struct ssh *, Channel *, int);
+void chan_mark_dead(struct ssh *, Channel *);
/* channel events */
-void chan_rcvd_oclose(Channel *);
-void chan_rcvd_eow(Channel *); /* SSH2-only */
-void chan_read_failed(Channel *);
-void chan_ibuf_empty(Channel *);
-
-void chan_rcvd_ieof(Channel *);
-void chan_write_failed(Channel *);
-void chan_obuf_empty(Channel *);
+void chan_rcvd_oclose(struct ssh *, Channel *);
+void chan_rcvd_eow(struct ssh *, Channel *);
+void chan_read_failed(struct ssh *, Channel *);
+void chan_ibuf_empty(struct ssh *, Channel *);
+void chan_rcvd_ieof(struct ssh *, Channel *);
+void chan_write_failed(struct ssh *, Channel *);
+void chan_obuf_empty(struct ssh *, Channel *);
#endif
diff --git a/clientloop.c b/clientloop.c
index 2934c476..1218b3b7 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.302 2017/08/30 03:59:08 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.303 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
@@ -177,6 +177,7 @@ struct channel_reply_ctx {
};
/* Global request success/failure callbacks */
+/* XXX move to struct ssh? */
struct global_confirm {
TAILQ_ENTRY(global_confirm) entry;
global_confirm_cb *cb;
@@ -244,13 +245,13 @@ get_current_time(void)
* control master process, or if there is no ControlPersist timeout.
*/
static void
-set_control_persist_exit_time(void)
+set_control_persist_exit_time(struct ssh *ssh)
{
if (muxserver_sock == -1 || !options.control_persist
|| options.control_persist_timeout == 0) {
/* not using a ControlPersist timeout */
control_persist_exit_time = 0;
- } else if (channel_still_open()) {
+ } else if (channel_still_open(ssh)) {
/* some client connections are still open */
if (control_persist_exit_time > 0)
debug2("%s: cancel scheduled exit", __func__);
@@ -288,8 +289,9 @@ client_x11_display_valid(const char *display)
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
#define X11_TIMEOUT_SLACK 60
int
-client_x11_get_proto(const char *display, const char *xauth_path,
- u_int trusted, u_int timeout, char **_proto, char **_data)
+client_x11_get_proto(struct ssh *ssh, const char *display,
+ const char *xauth_path, u_int trusted, u_int timeout,
+ char **_proto, char **_data)
{
char cmd[1024], line[512], xdisplay[512];
char xauthfile[PATH_MAX], xauthdir[PATH_MAX];
@@ -373,7 +375,8 @@ client_x11_get_proto(const char *display, const char *xauth_path,
x11_refuse_time = UINT_MAX;
else
x11_refuse_time = now + timeout;
- channel_set_x11_refuse_time(x11_refuse_time);
+ channel_set_x11_refuse_time(ssh,
+ x11_refuse_time);
}
if (system(cmd) == 0)
generated = 1;
@@ -446,7 +449,7 @@ client_x11_get_proto(const char *display, const char *xauth_path,
*/
static void
-client_check_window_change(void)
+client_check_window_change(struct ssh *ssh)
{
if (!received_window_change_signal)
return;
@@ -455,7 +458,7 @@ client_check_window_change(void)
debug2("%s: changed", __func__);
- channel_send_window_changes();
+ channel_send_window_changes(ssh);
}
static int
@@ -466,7 +469,7 @@ client_global_request_reply(int type, u_int32_t seq, struct ssh *ssh)
if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
return 0;
if (gc->cb != NULL)
- gc->cb(type, seq, gc->ctx);
+ gc->cb(ssh, type, seq, gc->ctx);
if (--gc->ref_count <= 0) {
TAILQ_REMOVE(&global_confirms, gc, entry);
explicit_bzero(gc, sizeof(*gc));
@@ -497,7 +500,8 @@ server_alive_check(void)
* one of the file descriptors).
*/
static void
-client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
+client_wait_until_can_do_something(struct ssh *ssh,
+ fd_set **readsetp, fd_set **writesetp,
int *maxfdp, u_int *nallocp, int rekeying)
{
struct timeval tv, *tvp;
@@ -510,7 +514,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
nallocp, &minwait_secs);
/* channel_prepare_select could have closed the last channel */
- if (session_closed && !channel_still_open() &&
+ if (session_closed && !channel_still_open(ssh) &&
!packet_have_data_to_write()) {
/* clear mask since we did not call select() */
memset(*readsetp, 0, *nallocp);
@@ -537,7 +541,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
}
if (options.rekey_interval > 0 && !rekeying)
timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout());
- set_control_persist_exit_time();
+ set_control_persist_exit_time(ssh);
if (control_persist_exit_time > 0) {
timeout_secs = MINIMUM(timeout_secs,
control_persist_exit_time - now);
@@ -668,7 +672,7 @@ client_process_net_input(fd_set *readset)
}
static void
-client_status_confirm(int type, Channel *c, void *ctx)
+client_status_confirm(struct ssh *ssh, int type, Channel *c, void *ctx)
{
struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
char errmsg[256];
@@ -707,8 +711,7 @@ client_status_confirm(int type, Channel *c, void *ctx)
* their stderr.
*/
if (tochan) {
- buffer_append(&c->extended, errmsg,
- strlen(errmsg));
+ buffer_append(c->extended, errmsg, strlen(errmsg));
} else
error("%s", errmsg);
if (cr->action == CONFIRM_TTY) {
@@ -719,23 +722,23 @@ client_status_confirm(int type, Channel *c, void *ctx)
if (c->self == session_ident)
leave_raw_mode(0);
else
- mux_tty_alloc_failed(c);
+ mux_tty_alloc_failed(ssh, c);
} else if (cr->action == CONFIRM_CLOSE) {
- chan_read_failed(c);
- chan_write_failed(c);
+ chan_read_failed(ssh, c);
+ chan_write_failed(ssh, c);
}
}
free(cr);
}
static void
-client_abandon_status_confirm(Channel *c, void *ctx)
+client_abandon_status_confirm(struct ssh *ssh, Channel *c, void *ctx)
{
free(ctx);
}
void
-client_expect_confirm(int id, const char *request,
+client_expect_confirm(struct ssh *ssh, int id, const char *request,
enum confirm_action action)
{
struct channel_reply_ctx *cr = xcalloc(1, sizeof(*cr));
@@ -743,7 +746,7 @@ client_expect_confirm(int id, const char *request,
cr->request_type = request;
cr->action = action;
- channel_register_status_confirm(id, client_status_confirm,
+ channel_register_status_confirm(ssh, id, client_status_confirm,
client_abandon_status_confirm, cr);
}
@@ -769,7 +772,7 @@ client_register_global_confirm(global_confirm_cb *cb, void *ctx)
}
static void
-process_cmdline(void)
+process_cmdline(struct ssh *ssh)
{
void (*handler)(int);
char *s, *cmd;
@@ -843,12 +846,12 @@ process_cmdline(void)
goto out;
}
if (remote)
- ok = channel_request_rforward_cancel(&fwd) == 0;
+ ok = channel_request_rforward_cancel(ssh, &fwd) == 0;
else if (dynamic)
- ok = channel_cancel_lport_listener(&fwd,
+ ok = channel_cancel_lport_listener(ssh, &fwd,
0, &options.fwd_opts) > 0;
else
- ok = channel_cancel_lport_listener(&fwd,
+ ok = channel_cancel_lport_listener(ssh, &fwd,
CHANNEL_CANCEL_PORT_STATIC,
&options.fwd_opts) > 0;
if (!ok) {
@@ -862,13 +865,13 @@ process_cmdline(void)
goto out;
}
if (local || dynamic) {
- if (!channel_setup_local_fwd_listener(&fwd,
+ if (!channel_setup_local_fwd_listener(ssh, &fwd,
&options.fwd_opts)) {
logit("Port forwarding failed.");
goto out;
}
} else {
- if (channel_request_remote_forwarding(&fwd) < 0) {
+ if (channel_request_remote_forwarding(ssh, &fwd) < 0) {
logit("Port forwarding failed.");
goto out;
}
@@ -945,7 +948,8 @@ print_escape_help(Buffer *b, int escape_char, int mux_client, int using_stderr)
* Process the characters one by one.
*/
static int
-process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
+process_escapes(struct ssh *ssh, Channel *c,
+ Buffer *bin, Buffer *bout, Buffer *berr,
char *buf, int len)
{
char string[1024];
@@ -981,13 +985,15 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
buffer_append(berr, string, strlen(string));
if (c && c->ctl_chan != -1) {
- chan_read_failed(c);
- chan_write_failed(c);
- if (c->detach_user)
- c->detach_user(c->self, NULL);
+ chan_read_failed(ssh, c);
+ chan_write_failed(ssh, c);
+ if (c->detach_user) {
+ c->detach_user(ssh,
+ c->self, NULL);
+ }
c->type = SSH_CHANNEL_ABANDONED;
- buffer_clear(&c->input);
- chan_ibuf_empty(c);
+ buffer_clear(c->input);
+ chan_ibuf_empty(ssh, c);
return 0;
} else
quit_pending = 1;
@@ -1025,7 +1031,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
snprintf(string, sizeof string,
"%cB\r\n", efc->escape_char);
buffer_append(berr, string, strlen(string));
- channel_request_start(c->self, "break", 0);
+ channel_request_start(ssh, c->self, "break", 0);
packet_put_int(1000);
packet_send();
continue;
@@ -1077,7 +1083,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
options.request_tty == REQUEST_TTY_FORCE);
/* Stop listening for new connections. */
- channel_stop_listening();
+ channel_stop_listening(ssh);
snprintf(string, sizeof string,
"%c& [backgrounded]\n", efc->escape_char);
@@ -1107,7 +1113,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
snprintf(string, sizeof string, "%c#\r\n",
efc->escape_char);
buffer_append(berr, string, strlen(string));
- s = channel_open_message();
+ s = channel_open_message(ssh);
buffer_append(berr, s, strlen(s));
free(s);
continue;
@@ -1115,7 +1121,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
case 'C':
if (c && c->ctl_chan != -1)
goto noescape;
- process_cmdline();
+ process_cmdline(ssh);
continue;
default:
@@ -1186,25 +1192,25 @@ client_new_escape_filter_ctx(int escape_char)
/* Free the escape filter context on channel free */
void
-client_filter_cleanup(int cid, void *ctx)
+client_filter_cleanup(struct ssh *ssh, int cid, void *ctx)
{
free(ctx);
}
int
-client_simple_escape_filter(Channel *c, char *buf, int len)
+client_simple_escape_filter(struct ssh *ssh, Channel *c, char *buf, int len)
{
if (c->extended_usage != CHAN_EXTENDED_WRITE)
return 0;
- return process_escapes(c, &c->input, &c->output, &c->extended,
+ return process_escapes(ssh, c, c->input, c->output, c->extended,
buf, len);
}
static void
-client_channel_closed(int id, void *arg)
+client_channel_closed(struct ssh *ssh, int id, void *arg)
{
- channel_cancel_cleanup(id);
+ channel_cancel_cleanup(ssh, id);
session_closed = 1;
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
}
@@ -1215,9 +1221,9 @@ client_channel_closed(int id, void *arg)
* remote host. If escape_char != SSH_ESCAPECHAR_NONE, it is the character
* used as an escape character for terminating or suspending the session.
*/
-
int
-client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
+client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
+ int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
@@ -1295,13 +1301,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
session_ident = ssh2_chan_id;
if (session_ident != -1) {
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
- channel_register_filter(session_ident,
+ channel_register_filter(ssh, session_ident,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx(
escape_char_arg));
}
- channel_register_cleanup(session_ident,
+ channel_register_cleanup(ssh, session_ident,
client_channel_closed, 0);
}
@@ -1311,15 +1317,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
- if (session_closed && !channel_still_open())
+ if (session_closed && !channel_still_open(ssh))
break;
- if (ssh_packet_is_rekeying(active_state)) {
+ if (ssh_packet_is_rekeying(ssh)) {
debug("rekeying in progress");
} else if (need_rekeying) {
/* manual rekey request */
debug("need rekeying");
- if ((r = kex_start_rekex(active_state)) != 0)
+ if ((r = kex_start_rekex(ssh)) != 0)
fatal("%s: kex_start_rekex: %s", __func__,
ssh_err(r));
need_rekeying = 0;
@@ -1329,13 +1335,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
* enqueue them for sending to the server.
*/
if (packet_not_very_much_data_to_write())
- channel_output_poll();
+ channel_output_poll(ssh);
/*
* Check if the window size has changed, and buffer a
* message about it to the server if so.
*/
- client_check_window_change();
+ client_check_window_change(ssh);
if (quit_pending)
break;
@@ -1345,15 +1351,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
* available on one of the descriptors).
*/
max_fd2 = max_fd;
- client_wait_until_can_do_something(&readset, &writeset,
- &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state));
+ client_wait_until_can_do_something(ssh, &readset, &writeset,
+ &max_fd2, &nalloc, ssh_packet_is_rekeying(ssh));
if (quit_pending)
break;
/* Do channel operations unless rekeying in progress. */
- if (!ssh_packet_is_rekeying(active_state))
- channel_after_select(active_state, readset, writeset);
+ if (!ssh_packet_is_rekeying(ssh))
+ channel_after_select(ssh, readset, writeset);
/* Buffer input from the connection. */
client_process_net_input(readset);
@@ -1395,7 +1401,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
packet_send();
packet_write_wait();
- channel_free_all();
+ channel_free_all(ssh);
if (have_pty)
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
@@ -1463,8 +1469,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/*********/
static Channel *
-client_request_forwarded_tcpip(const char *request_type, int rchan,
- u_int rwindow, u_int rmaxpack)
+client_request_forwarded_tcpip(struct ssh *ssh, const char *request_type,
+ int rchan, u_int rwindow, u_int rmaxpack)
{
Channel *c = NULL;
struct sshbuf *b = NULL;
@@ -1482,7 +1488,7 @@ client_request_forwarded_tcpip(const char *request_type, int rchan,
debug("%s: listen %s port %d, originator %s port %d", __func__,
listen_address, listen_port, originator_address, originator_port);
- c = channel_connect_by_listen_address(listen_address, listen_port,
+ c = channel_connect_by_listen_address(ssh, listen_address, listen_port,
"forwarded-tcpip", originator_address);
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
@@ -1501,7 +1507,7 @@ client_request_forwarded_tcpip(const char *request_type, int rchan,
(r = sshbuf_put_u32(b, listen_port)) != 0 ||
(r = sshbuf_put_cstring(b, originator_address)) != 0 ||
(r = sshbuf_put_u32(b, originator_port)) != 0 ||
- (r = sshbuf_put_stringb(&c->output, b)) != 0) {
+ (r = sshbuf_put_stringb(c->output, b)) != 0) {
error("%s: compose for muxclient %s", __func__,
ssh_err(r));
goto out;
@@ -1516,7 +1522,8 @@ client_request_forwarded_tcpip(const char *request_type, int rchan,
}
static Channel *
-client_request_forwarded_streamlocal(const char *request_type, int rchan)
+client_request_forwarded_streamlocal(struct ssh *ssh,
+ const char *request_type, int rchan)
{
Channel *c = NULL;
char *listen_path;
@@ -1530,14 +1537,14 @@ client_request_forwarded_streamlocal(const char *request_type, int rchan)
debug("%s: %s", __func__, listen_path);
- c = channel_connect_by_listen_path(listen_path,
+ c = channel_connect_by_listen_path(ssh, listen_path,
"forwarded-streamlocal@openssh.com", "forwarded-streamlocal");
free(listen_path);
return c;
}
static Channel *
-client_request_x11(const char *request_type, int rchan)
+client_request_x11(struct ssh *ssh, const char *request_type, int rchan)
{
Channel *c = NULL;
char *originator;
@@ -1567,10 +1574,10 @@ client_request_x11(const char *request_type, int rchan)
debug("client_request_x11: request from %s %d", originator,
originator_port);
free(originator);
- sock = x11_connect_display();
+ sock = x11_connect_display(ssh);
if (sock < 0)
return NULL;
- c = channel_new("x11",
+ c = channel_new(ssh, "x11",
SSH_CHANNEL_X11_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1);
c->force_drain = 1;
@@ -1578,7 +1585,7 @@ client_request_x11(const char *request_type, int rchan)
}
static Channel *
-client_request_agent(const char *request_type, int rchan)
+client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
{
Channel *c = NULL;
int r, sock;
@@ -1595,7 +1602,7 @@ client_request_agent(const char *request_type, int rchan)
__func__, ssh_err(r));
return NULL;
}
- c = channel_new("authentication agent connection",
+ c = channel_new(ssh, "authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
"authentication agent connection", 1);
@@ -1604,7 +1611,8 @@ client_request_agent(const char *request_type, int rchan)
}
int
-client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
+client_request_tun_fwd(struct ssh *ssh, int tun_mode,
+ int local_tun, int remote_tun)
{
Channel *c;
int fd;
@@ -1620,7 +1628,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
return -1;
}
- c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
+ c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;
@@ -1660,14 +1668,14 @@ client_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "forwarded-tcpip") == 0) {
- c = client_request_forwarded_tcpip(ctype, rchan, rwindow,
+ c = client_request_forwarded_tcpip(ssh, ctype, rchan, rwindow,
rmaxpack);
} else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
- c = client_request_forwarded_streamlocal(ctype, rchan);
+ c = client_request_forwarded_streamlocal(ssh, ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
- c = client_request_x11(ctype, rchan);
+ c = client_request_x11(ssh, ctype, rchan);
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
- c = client_request_agent(ctype, rchan);
+ c = client_request_agent(ssh, ctype, rchan);
}
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
debug3("proxied to downstream: %s", ctype);
@@ -1707,7 +1715,7 @@ client_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
char *rtype;
id = packet_get_int();
- c = channel_lookup(id);
+ c = channel_lookup(ssh, id);
if (channel_proxy_upstream(c, type, seq, ssh))
return 0;
rtype = packet_get_string(NULL);
@@ -1723,11 +1731,11 @@ client_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
"unknown channel", id);
} else if (strcmp(rtype, "eow@openssh.com") == 0) {
packet_check_eom();
- chan_rcvd_eow(c);
+ chan_rcvd_eow(ssh, c);
} else if (strcmp(rtype, "exit-status") == 0) {
exitval = packet_get_int();
if (c->ctl_chan != -1) {
- mux_exit_message(c, exitval);
+ mux_exit_message(ssh, c, exitval);
success = 1;
} else if (id == session_ident) {
/* Record exit value of local session */
@@ -1895,9 +1903,9 @@ update_known_hosts(struct hostkeys_update_ctx *ctx)
}
static void
-client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx)
+client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
+ u_int32_t seq, void *_ctx)
{
- struct ssh *ssh = active_state; /* XXX */
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i, ndone;
struct sshbuf *signdata;
@@ -2161,7 +2169,7 @@ client_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
}
void
-client_session2_setup(int id, int want_tty, int want_subsystem,
+client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem,
const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env)
{
int len;
@@ -2169,8 +2177,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
debug2("%s: id %d", __func__, id);
- if ((c = channel_lookup(id)) == NULL)
- fatal("client_session2_setup: channel %d: unknown channel", id);
+ if ((c = channel_lookup(ssh, id)) == NULL)
+ fatal("%s: channel %d: unknown channel", __func__, id);
packet_set_interactive(want_tty,
options.ip_qos_interactive, options.ip_qos_bulk);
@@ -2182,8 +2190,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
memset(&ws, 0, sizeof(ws));
- channel_request_start(id, "pty-req", 1);
- client_expect_confirm(id, "PTY allocation", CONFIRM_TTY);
+ channel_request_start(ssh, id, "pty-req", 1);
+ client_expect_confirm(ssh, id, "PTY allocation", CONFIRM_TTY);
packet_put_cstring(term != NULL ? term : "");
packet_put_int((u_int)ws.ws_col);
packet_put_int((u_int)ws.ws_row);
@@ -2226,7 +2234,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
}
debug("Sending env %s = %s", name, val);
- channel_request_start(id, "env", 0);
+ channel_request_start(ssh, id, "env", 0);
packet_put_cstring(name);
packet_put_cstring(val);
packet_send();
@@ -2241,19 +2249,20 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
if (want_subsystem) {
debug("Sending subsystem: %.*s",
len, (u_char*)buffer_ptr(cmd));
- channel_request_start(id, "subsystem", 1);
- client_expect_confirm(id, "subsystem", CONFIRM_CLOSE);
+ channel_request_start(ssh, id, "subsystem", 1);
+ client_expect_confirm(ssh, id, "subsystem",
+ CONFIRM_CLOSE);
} else {
debug("Sending command: %.*s",
len, (u_char*)buffer_ptr(cmd));
- channel_request_start(id, "exec", 1);
- client_expect_confirm(id, "exec", CONFIRM_CLOSE);
+ channel_request_start(ssh, id, "exec", 1);
+ client_expect_confirm(ssh, id, "exec", CONFIRM_CLOSE);
}
packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
packet_send();
} else {
- channel_request_start(id, "shell", 1);
- client_expect_confirm(id, "shell", CONFIRM_CLOSE);
+ channel_request_start(ssh, id, "shell", 1);
+ client_expect_confirm(ssh, id, "shell", CONFIRM_CLOSE);
packet_send();
}
}
diff --git a/clientloop.h b/clientloop.h
index ae83aa8c..a1975ccc 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.h,v 1.33 2016/09/30 09:19:13 markus Exp $ */
+/* $OpenBSD: clientloop.h,v 1.34 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -37,28 +37,31 @@
#include <termios.h>
+struct ssh;
+
/* Client side main loop for the interactive session. */
-int client_loop(int, int, int);
-int client_x11_get_proto(const char *, const char *, u_int, u_int,
- char **, char **);
+int client_loop(struct ssh *, int, int, int);
+int client_x11_get_proto(struct ssh *, const char *, const char *,
+ u_int, u_int, char **, char **);
void client_global_request_reply_fwd(int, u_int32_t, void *);
-void client_session2_setup(int, int, int, const char *, struct termios *,
- int, Buffer *, char **);
-int client_request_tun_fwd(int, int, int);
+void client_session2_setup(struct ssh *, int, int, int,
+ const char *, struct termios *, int, Buffer *, char **);
+int client_request_tun_fwd(struct ssh *, int, int, int);
void client_stop_mux(void);
/* Escape filter for protocol 2 sessions */
void *client_new_escape_filter_ctx(int);
-void client_filter_cleanup(int, void *);
-int client_simple_escape_filter(Channel *, char *, int);
+void client_filter_cleanup(struct ssh *, int, void *);
+int client_simple_escape_filter(struct ssh *, Channel *, char *, int);
/* Global request confirmation callbacks */
-typedef void global_confirm_cb(int, u_int32_t seq, void *);
+typedef void global_confirm_cb(struct ssh *, int, u_int32_t, void *);
void client_register_global_confirm(global_confirm_cb *, void *);
/* Channel request confirmation callbacks */
enum confirm_action { CONFIRM_WARN = 0, CONFIRM_CLOSE, CONFIRM_TTY };
-void client_expect_confirm(int, const char *, enum confirm_action);
+void client_expect_confirm(struct ssh *, int, const char *,
+ enum confirm_action);
/* Multiplexing protocol version */
#define SSHMUX_VER 4
@@ -73,8 +76,8 @@ void client_expect_confirm(int, const char *, enum confirm_action);
#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */
#define SSHMUX_COMMAND_PROXY 8 /* Open new connection */
-void muxserver_listen(void);
+void muxserver_listen(struct ssh *);
int muxclient(const char *);
-void mux_exit_message(Channel *, int);
-void mux_tty_alloc_failed(Channel *);
+void mux_exit_message(struct ssh *, Channel *, int);
+void mux_tty_alloc_failed(struct ssh *ssh, Channel *);
diff --git a/monitor.c b/monitor.c
index 8a7897bd..bdb4e855 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.172 2017/06/24 06:34:38 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.173 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -1519,13 +1519,14 @@ mm_answer_pty_cleanup(int sock, Buffer *m)
int
mm_answer_term(int sock, Buffer *req)
{
+ struct ssh *ssh = active_state; /* XXX */
extern struct monitor *pmonitor;
int res, status;
debug3("%s: tearing down sessions", __func__);
/* The child is terminating */
- session_destroy_all(&mm_session_close);
+ session_destroy_all(ssh, &mm_session_close);
#ifdef USE_PAM
if (options.use_pam)
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 25f3e967..287af066 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.92 2017/05/30 14:10:53 markus Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.93 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -242,6 +242,7 @@ mm_key_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
struct passwd *
mm_getpwnamallow(const char *username)
{
+ struct ssh *ssh = active_state; /* XXX */
Buffer m;
struct passwd *pw;
u_int len, i;
@@ -296,6 +297,7 @@ out:
copy_set_server_options(&options, newopts, 1);
log_change_level(options.log_level);
+ process_permitopen(ssh, &options);
free(newopts);
buffer_free(&m);
diff --git a/mux.c b/mux.c
index 3dde4da4..9eee287b 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.65 2017/06/09 06:47:13 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.66 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@@ -161,22 +161,32 @@ struct mux_master_state {
#define MUX_FWD_REMOTE 2
#define MUX_FWD_DYNAMIC 3
-static void mux_session_confirm(int, int, void *);
-static void mux_stdio_confirm(int, int, void *);
-
-static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
-static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *);
+static void mux_session_confirm(struct ssh *, int, int, void *);
+static void mux_stdio_confirm(struct ssh *, int, int, void *);
+
+static int process_mux_master_hello(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_new_session(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_alive_check(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_terminate(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_open_fwd(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_close_fwd(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_stdio_fwd(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_stop_listening(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
+static int process_mux_proxy(struct ssh *, u_int,
+ Channel *, struct sshbuf *, struct sshbuf *);
static const struct {
u_int type;
- int (*handler)(u_int, Channel *, Buffer *, Buffer *);
+ int (*handler)(struct ssh *, u_int, Channel *,
+ struct sshbuf *, struct sshbuf *);
} mux_master_handlers[] = {
{ MUX_MSG_HELLO, process_mux_master_hello },
{ MUX_C_NEW_SESSION, process_mux_new_session },
@@ -193,36 +203,36 @@ static const struct {
/* Cleanup callback fired on closure of mux slave _session_ channel */
/* ARGSUSED */
static void
-mux_master_session_cleanup_cb(int cid, void *unused)
+mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
{
- Channel *cc, *c = channel_by_id(cid);
+ Channel *cc, *c = channel_by_id(ssh, cid);
debug3("%s: entering for channel %d", __func__, cid);
if (c == NULL)
fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
if (c->ctl_chan != -1) {
- if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+ if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal("%s: channel %d missing control channel %d",
__func__, c->self, c->ctl_chan);
c->ctl_chan = -1;
cc->remote_id = -1;
- chan_rcvd_oclose(cc);
+ chan_rcvd_oclose(ssh, cc);
}
- channel_cancel_cleanup(c->self);
+ channel_cancel_cleanup(ssh, c->self);
}
/* Cleanup callback fired on closure of mux slave _control_ channel */
/* ARGSUSED */
static void
-mux_master_control_cleanup_cb(int cid, void *unused)
+mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
{
- Channel *sc, *c = channel_by_id(cid);
+ Channel *sc, *c = channel_by_id(ssh, cid);
debug3("%s: entering for channel %d", __func__, cid);
if (c == NULL)
fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
if (c->remote_id != -1) {
- if ((sc = channel_by_id(c->remote_id)) == NULL)
+ if ((sc = channel_by_id(ssh, c->remote_id)) == NULL)
fatal("%s: channel %d missing session channel %d",
__func__, c->self, c->remote_id);
c->remote_id = -1;
@@ -230,15 +240,15 @@ mux_master_control_cleanup_cb(int cid, void *unused)
if (sc->type != SSH_CHANNEL_OPEN &&
sc->type != SSH_CHANNEL_OPENING) {
debug2("%s: channel %d: not open", __func__, sc->self);
- chan_mark_dead(sc);
+ chan_mark_dead(ssh, sc);
} else {
if (sc->istate == CHAN_INPUT_OPEN)
- chan_read_failed(sc);
+ chan_read_failed(ssh, sc);
if (sc->ostate == CHAN_OUTPUT_OPEN)
- chan_write_failed(sc);
+ chan_write_failed(ssh, sc);
}
}
- channel_cancel_cleanup(c->self);
+ channel_cancel_cleanup(ssh, c->self);
}
/* Check mux client environment variables before passing them to mux master. */
@@ -266,7 +276,8 @@ env_permitted(char *env)
/* Mux master protocol message handlers */
static int
-process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_master_hello(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
u_int ver;
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
@@ -308,7 +319,8 @@ process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static int
-process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_new_session(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
Channel *nc;
struct mux_session_confirm_ctx *cctx;
@@ -453,7 +465,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
packetmax >>= 1;
}
- nc = channel_new("session", SSH_CHANNEL_OPENING,
+ nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING,
new_fd[0], new_fd[1], new_fd[2], window, packetmax,
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
@@ -461,7 +473,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
c->remote_id = nc->self; /* link control -> session channel */
if (cctx->want_tty && escape_char != 0xffffffff) {
- channel_register_filter(nc->self,
+ channel_register_filter(ssh, nc->self,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx((int)escape_char));
@@ -470,17 +482,19 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
debug2("%s: channel_new: %d linked to control channel %d",
__func__, nc->self, nc->ctl_chan);
- channel_send_open(nc->self);
- channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
+ channel_send_open(ssh, nc->self);
+ channel_register_open_confirm(ssh, nc->self, mux_session_confirm, cctx);
c->mux_pause = 1; /* stop handling messages until open_confirm done */
- channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
+ channel_register_cleanup(ssh, nc->self,
+ mux_master_session_cleanup_cb, 1);
/* reply is deferred, sent by mux_session_confirm */
return 0;
}
static int
-process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_alive_check(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
debug2("%s: channel %d: alive check", __func__, c->self);
@@ -493,7 +507,8 @@ process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static int
-process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_terminate(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
debug2("%s: channel %d: terminate request", __func__, c->self);
@@ -582,7 +597,7 @@ compare_forward(struct Forward *a, struct Forward *b)
}
static void
-mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+mux_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
@@ -590,7 +605,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
Channel *c;
Buffer out;
- if ((c = channel_by_id(fctx->cid)) == NULL) {
+ if ((c = channel_by_id(ssh, fctx->cid)) == NULL) {
/* no channel for reply */
error("%s: unknown channel", __func__);
return;
@@ -616,7 +631,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
buffer_put_int(&out, MUX_S_REMOTE_PORT);
buffer_put_int(&out, fctx->rid);
buffer_put_int(&out, rfwd->allocated_port);
- channel_update_permitted_opens(rfwd->handle,
+ channel_update_permitted_opens(ssh, rfwd->handle,
rfwd->allocated_port);
} else {
buffer_put_int(&out, MUX_S_OK);
@@ -625,7 +640,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
goto out;
} else {
if (rfwd->listen_port == 0)
- channel_update_permitted_opens(rfwd->handle, -1);
+ channel_update_permitted_opens(ssh, rfwd->handle, -1);
if (rfwd->listen_path != NULL)
xasprintf(&failmsg, "remote port forwarding failed for "
"listen path %s", rfwd->listen_path);
@@ -651,7 +666,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
buffer_put_cstring(&out, failmsg);
free(failmsg);
out:
- buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
+ buffer_put_string(c->output, buffer_ptr(&out), buffer_len(&out));
buffer_free(&out);
if (c->mux_pause <= 0)
fatal("%s: mux_pause %d", __func__, c->mux_pause);
@@ -659,7 +674,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
}
static int
-process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_open_fwd(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
struct Forward fwd;
char *fwd_desc = NULL;
@@ -727,13 +743,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
fwd.listen_port);
goto invalid;
}
- if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536)
- || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
+ if ((fwd.connect_port != PORT_STREAMLOCAL &&
+ fwd.connect_port >= 65536) ||
+ (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE &&
+ fwd.connect_port == 0)) {
logit("%s: invalid connect port %u", __func__,
fwd.connect_port);
goto invalid;
}
- if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) {
+ if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL &&
+ fwd.connect_path == NULL) {
logit("%s: missing connect host", __func__);
goto invalid;
}
@@ -784,7 +803,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
- if (!channel_setup_local_fwd_listener(&fwd,
+ if (!channel_setup_local_fwd_listener(ssh, &fwd,
&options.fwd_opts)) {
fail:
logit("slave-requested %s failed", fwd_desc);
@@ -798,7 +817,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
} else {
struct mux_channel_confirm_ctx *fctx;
- fwd.handle = channel_request_remote_forwarding(&fwd);
+ fwd.handle = channel_request_remote_forwarding(ssh, &fwd);
if (fwd.handle < 0)
goto fail;
add_remote_forward(&options, &fwd);
@@ -827,7 +846,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static int
-process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_close_fwd(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
struct Forward fwd, *found_fwd;
char *fwd_desc = NULL;
@@ -908,11 +928,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
* However, for dynamic allocated listen ports we need
* to use the actual listen port.
*/
- if (channel_request_rforward_cancel(found_fwd) == -1)
+ if (channel_request_rforward_cancel(ssh, found_fwd) == -1)
error_reason = "port not in permitted opens";
} else { /* local and dynamic forwards */
/* Ditto */
- if (channel_cancel_lport_listener(&fwd, fwd.connect_port,
+ if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port,
&options.fwd_opts) == -1)
error_reason = "port not found";
}
@@ -942,7 +962,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static int
-process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_stdio_fwd(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
Channel *nc;
char *reserved, *chost;
@@ -1018,7 +1039,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
if (!isatty(new_fd[1]))
set_nonblock(new_fd[1]);
- nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
+ nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]);
nc->ctl_chan = c->self; /* link session -> control channel */
c->remote_id = nc->self; /* link control -> session channel */
@@ -1026,11 +1047,12 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
debug2("%s: channel_new: %d linked to control channel %d",
__func__, nc->self, nc->ctl_chan);
- channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
+ channel_register_cleanup(ssh, nc->self,
+ mux_master_session_cleanup_cb, 1);
cctx = xcalloc(1, sizeof(*cctx));
cctx->rid = rid;
- channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx);
+ channel_register_open_confirm(ssh, nc->self, mux_stdio_confirm, cctx);
c->mux_pause = 1; /* stop handling messages until open_confirm done */
/* reply is deferred, sent by mux_session_confirm */
@@ -1039,7 +1061,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
/* Callback on open confirmation in mux master for a mux stdio fwd session. */
static void
-mux_stdio_confirm(int id, int success, void *arg)
+mux_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
{
struct mux_stdio_confirm_ctx *cctx = arg;
Channel *c, *cc;
@@ -1047,9 +1069,9 @@ mux_stdio_confirm(int id, int success, void *arg)
if (cctx == NULL)
fatal("%s: cctx == NULL", __func__);
- if ((c = channel_by_id(id)) == NULL)
+ if ((c = channel_by_id(ssh, id)) == NULL)
fatal("%s: no channel for id %d", __func__, id);
- if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+ if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal("%s: channel %d lacks control channel %d", __func__,
id, c->ctl_chan);
@@ -1072,7 +1094,7 @@ mux_stdio_confirm(int id, int success, void *arg)
done:
/* Send reply */
- buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
+ buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply));
buffer_free(&reply);
if (cc->mux_pause <= 0)
@@ -1083,7 +1105,8 @@ mux_stdio_confirm(int id, int success, void *arg)
}
static int
-process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_stop_listening(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
debug("%s: channel %d: stop listening", __func__, c->self);
@@ -1100,7 +1123,7 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
if (mux_listener_channel != NULL) {
- channel_free(mux_listener_channel);
+ channel_free(ssh, mux_listener_channel);
client_stop_mux();
free(options.control_path);
options.control_path = NULL;
@@ -1116,7 +1139,8 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
static int
-process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
+process_mux_proxy(struct ssh *ssh, u_int rid,
+ Channel *c, Buffer *m, Buffer *r)
{
debug("%s: channel %d: proxy request", __func__, c->self);
@@ -1129,7 +1153,7 @@ process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
/* Channel callbacks fired on read/write from mux slave fd */
static int
-mux_master_read_cb(Channel *c)
+mux_master_read_cb(struct ssh *ssh, Channel *c)
{
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
Buffer in, out;
@@ -1141,7 +1165,7 @@ mux_master_read_cb(Channel *c)
if (c->mux_ctx == NULL) {
state = xcalloc(1, sizeof(*state));
c->mux_ctx = state;
- channel_register_cleanup(c->self,
+ channel_register_cleanup(ssh, c->self,
mux_master_control_cleanup_cb, 0);
/* Send hello */
@@ -1149,7 +1173,7 @@ mux_master_read_cb(Channel *c)
buffer_put_int(&out, MUX_MSG_HELLO);
buffer_put_int(&out, SSHMUX_VER);
/* no extensions */
- buffer_put_string(&c->output, buffer_ptr(&out),
+ buffer_put_string(c->output, buffer_ptr(&out),
buffer_len(&out));
buffer_free(&out);
debug3("%s: channel %d: hello sent", __func__, c->self);
@@ -1160,7 +1184,7 @@ mux_master_read_cb(Channel *c)
buffer_init(&out);
/* Channel code ensures that we receive whole packets */
- if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
+ if ((ptr = buffer_get_string_ptr_ret(c->input, &have)) == NULL) {
malf:
error("%s: malformed message", __func__);
goto out;
@@ -1186,7 +1210,8 @@ mux_master_read_cb(Channel *c)
for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
if (type == mux_master_handlers[i].type) {
- ret = mux_master_handlers[i].handler(rid, c, &in, &out);
+ ret = mux_master_handlers[i].handler(ssh, rid,
+ c, &in, &out);
break;
}
}
@@ -1199,7 +1224,7 @@ mux_master_read_cb(Channel *c)
}
/* Enqueue reply packet */
if (buffer_len(&out) != 0) {
- buffer_put_string(&c->output, buffer_ptr(&out),
+ buffer_put_string(c->output, buffer_ptr(&out),
buffer_len(&out));
}
out:
@@ -1209,7 +1234,7 @@ mux_master_read_cb(Channel *c)
}
void
-mux_exit_message(Channel *c, int exitval)
+mux_exit_message(struct ssh *ssh, Channel *c, int exitval)
{
Buffer m;
Channel *mux_chan;
@@ -1217,7 +1242,7 @@ mux_exit_message(Channel *c, int exitval)
debug3("%s: channel %d: exit message, exitval %d", __func__, c->self,
exitval);
- if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
+ if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal("%s: channel %d missing mux channel %d",
__func__, c->self, c->ctl_chan);
@@ -1227,19 +1252,19 @@ mux_exit_message(Channel *c, int exitval)
buffer_put_int(&m, c->self);
buffer_put_int(&m, exitval);
- buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
+ buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m));
buffer_free(&m);
}
void
-mux_tty_alloc_failed(Channel *c)
+mux_tty_alloc_failed(struct ssh *ssh, Channel *c)
{
Buffer m;
Channel *mux_chan;
debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
- if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
+ if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal("%s: channel %d missing mux channel %d",
__func__, c->self, c->ctl_chan);
@@ -1248,13 +1273,13 @@ mux_tty_alloc_failed(Channel *c)
buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
buffer_put_int(&m, c->self);
- buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
+ buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m));
buffer_free(&m);
}
/* Prepare a mux master to listen on a Unix domain socket. */
void
-muxserver_listen(void)
+muxserver_listen(struct ssh *ssh)
{
mode_t old_umask;
char *orig_control_path = options.control_path;
@@ -1327,7 +1352,7 @@ muxserver_listen(void)
set_nonblock(muxserver_sock);
- mux_listener_channel = channel_new("mux listener",
+ mux_listener_channel = channel_new(ssh, "mux listener",
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, options.control_path, 1);
@@ -1338,7 +1363,7 @@ muxserver_listen(void)
/* Callback on open confirmation in mux master for a mux client session. */
static void
-mux_session_confirm(int id, int success, void *arg)
+mux_session_confirm(struct ssh *ssh, int id, int success, void *arg)
{
struct mux_session_confirm_ctx *cctx = arg;
const char *display;
@@ -1348,9 +1373,9 @@ mux_session_confirm(int id, int success, void *arg)
if (cctx == NULL)
fatal("%s: cctx == NULL", __func__);
- if ((c = channel_by_id(id)) == NULL)
+ if ((c = channel_by_id(ssh, id)) == NULL)
fatal("%s: no channel for id %d", __func__, id);
- if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+ if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
fatal("%s: channel %d lacks control channel %d", __func__,
id, c->ctl_chan);
@@ -1369,27 +1394,27 @@ mux_session_confirm(int id, int success, void *arg)
char *proto, *data;
/* Get reasonable local authentication information. */
- if (client_x11_get_proto(display, options.xauth_location,
+ if (client_x11_get_proto(ssh, display, options.xauth_location,
options.forward_x11_trusted, options.forward_x11_timeout,
&proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
- x11_request_forwarding_with_spoofing(id, display, proto,
- data, 1);
+ x11_request_forwarding_with_spoofing(ssh, id,
+ display, proto, data, 1);
/* XXX exit_on_forward_failure */
- client_expect_confirm(id, "X11 forwarding",
+ client_expect_confirm(ssh, id, "X11 forwarding",
CONFIRM_WARN);
}
}
if (cctx->want_agent_fwd && options.forward_agent) {
debug("Requesting authentication agent forwarding.");
- channel_request_start(id, "auth-agent-req@openssh.com", 0);
+ channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
packet_send();
}
- client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
+ client_session2_setup(ssh, id, cctx->want_tty, cctx->want_subsys,
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
debug3("%s: sending success reply", __func__);
@@ -1401,7 +1426,7 @@ mux_session_confirm(int id, int success, void *arg)
done:
/* Send reply */
- buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
+ buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply));
buffer_free(&reply);
if (cc->mux_pause <= 0)
diff --git a/nchan.c b/nchan.c
index 36da8904..74c855c9 100644
--- a/nchan.c
+++ b/nchan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nchan.c,v 1.65 2017/04/30 23:28:42 djm Exp $ */
+/* $OpenBSD: nchan.c,v 1.66 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
@@ -34,7 +34,8 @@
#include "openbsd-compat/sys-queue.h"
#include "ssh2.h"
-#include "buffer.h"
+#include "sshbuf.h"
+#include "ssherr.h"
#include "packet.h"
#include "channels.h"
#include "compat.h"
@@ -73,15 +74,15 @@
/*
* ACTIONS: should never update the channel states
*/
-static void chan_send_eof2(Channel *);
-static void chan_send_eow2(Channel *);
+static void chan_send_eof2(struct ssh *, Channel *);
+static void chan_send_eow2(struct ssh *, Channel *);
/* helper */
-static void chan_shutdown_write(Channel *);
-static void chan_shutdown_read(Channel *);
+static void chan_shutdown_write(struct ssh *, Channel *);
+static void chan_shutdown_read(struct ssh *, Channel *);
-static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
-static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
+static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
+static const char *istates[] = { "open", "drain", "wait_oclose", "closed" };
static void
chan_set_istate(Channel *c, u_int next)
@@ -104,12 +105,12 @@ chan_set_ostate(Channel *c, u_int next)
}
void
-chan_read_failed(Channel *c)
+chan_read_failed(struct ssh *ssh, Channel *c)
{
debug2("channel %d: read failed", c->self);
switch (c->istate) {
case CHAN_INPUT_OPEN:
- chan_shutdown_read(c);
+ chan_shutdown_read(ssh, c);
chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
break;
default:
@@ -120,10 +121,10 @@ chan_read_failed(Channel *c)
}
void
-chan_ibuf_empty(Channel *c)
+chan_ibuf_empty(struct ssh *ssh, Channel *c)
{
debug2("channel %d: ibuf empty", c->self);
- if (buffer_len(&c->input)) {
+ if (sshbuf_len(c->input)) {
error("channel %d: chan_ibuf_empty for non empty buffer",
c->self);
return;
@@ -131,7 +132,7 @@ chan_ibuf_empty(Channel *c)
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
- chan_send_eof2(c);
+ chan_send_eof2(ssh, c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
default:
@@ -142,17 +143,17 @@ chan_ibuf_empty(Channel *c)
}
void
-chan_obuf_empty(Channel *c)
+chan_obuf_empty(struct ssh *ssh, Channel *c)
{
debug2("channel %d: obuf empty", c->self);
- if (buffer_len(&c->output)) {
+ if (sshbuf_len(c->output)) {
error("channel %d: chan_obuf_empty for non empty buffer",
c->self);
return;
}
switch (c->ostate) {
case CHAN_OUTPUT_WAIT_DRAIN:
- chan_shutdown_write(c);
+ chan_shutdown_write(ssh, c);
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
@@ -163,26 +164,29 @@ chan_obuf_empty(Channel *c)
}
void
-chan_rcvd_eow(Channel *c)
+chan_rcvd_eow(struct ssh *ssh, Channel *c)
{
debug2("channel %d: rcvd eow", c->self);
switch (c->istate) {
case CHAN_INPUT_OPEN:
- chan_shutdown_read(c);
+ chan_shutdown_read(ssh, c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
}
}
static void
-chan_send_eof2(Channel *c)
+chan_send_eof2(struct ssh *ssh, Channel *c)
{
+ int r;
+
debug2("channel %d: send eof", c->self);
switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN:
- packet_start(SSH2_MSG_CHANNEL_EOF);
- packet_put_int(c->remote_id);
- packet_send();
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
c->flags |= CHAN_EOF_SENT;
break;
default:
@@ -193,8 +197,10 @@ chan_send_eof2(Channel *c)
}
static void
-chan_send_close2(Channel *c)
+chan_send_close2(struct ssh *ssh, Channel *c)
{
+ int r;
+
debug2("channel %d: send close", c->self);
if (c->ostate != CHAN_OUTPUT_CLOSED ||
c->istate != CHAN_INPUT_CLOSED) {
@@ -203,16 +209,19 @@ chan_send_close2(Channel *c)
} else if (c->flags & CHAN_CLOSE_SENT) {
error("channel %d: already sent close", c->self);
} else {
- packet_start(SSH2_MSG_CHANNEL_CLOSE);
- packet_put_int(c->remote_id);
- packet_send();
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
c->flags |= CHAN_CLOSE_SENT;
}
}
static void
-chan_send_eow2(Channel *c)
+chan_send_eow2(struct ssh *ssh, Channel *c)
{
+ int r;
+
debug2("channel %d: send eow", c->self);
if (c->ostate == CHAN_OUTPUT_CLOSED) {
error("channel %d: must not sent eow on closed output",
@@ -221,30 +230,31 @@ chan_send_eow2(Channel *c)
}
if (!(datafellows & SSH_NEW_OPENSSH))
return;
- packet_start(SSH2_MSG_CHANNEL_REQUEST);
- packet_put_int(c->remote_id);
- packet_put_cstring("eow@openssh.com");
- packet_put_char(0);
- packet_send();
+ if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
+ (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 ||
+ (r = sshpkt_put_u8(ssh, 0)) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
}
/* shared */
void
-chan_rcvd_ieof(Channel *c)
+chan_rcvd_ieof(struct ssh *ssh, Channel *c)
{
debug2("channel %d: rcvd eof", c->self);
c->flags |= CHAN_EOF_RCVD;
if (c->ostate == CHAN_OUTPUT_OPEN)
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
- buffer_len(&c->output) == 0 &&
+ sshbuf_len(c->output) == 0 &&
!CHANNEL_EFD_OUTPUT_ACTIVE(c))
- chan_obuf_empty(c);
+ chan_obuf_empty(ssh, c);
}
void
-chan_rcvd_oclose(Channel *c)
+chan_rcvd_oclose(struct ssh *ssh, Channel *c)
{
debug2("channel %d: rcvd close", c->self);
if (!(c->flags & CHAN_LOCAL)) {
@@ -270,27 +280,27 @@ chan_rcvd_oclose(Channel *c)
}
switch (c->istate) {
case CHAN_INPUT_OPEN:
- chan_shutdown_read(c);
+ chan_shutdown_read(ssh, c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
case CHAN_INPUT_WAIT_DRAIN:
if (!(c->flags & CHAN_LOCAL))
- chan_send_eof2(c);
+ chan_send_eof2(ssh, c);
chan_set_istate(c, CHAN_INPUT_CLOSED);
break;
}
}
void
-chan_write_failed(Channel *c)
+chan_write_failed(struct ssh *ssh, Channel *c)
{
debug2("channel %d: write failed", c->self);
switch (c->ostate) {
case CHAN_OUTPUT_OPEN:
case CHAN_OUTPUT_WAIT_DRAIN:
- chan_shutdown_write(c);
+ chan_shutdown_write(ssh, c);
if (strcmp(c->ctype, "session") == 0)
- chan_send_eow2(c);
+ chan_send_eow2(ssh, c);
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
break;
default:
@@ -301,13 +311,13 @@ chan_write_failed(Channel *c)
}
void
-chan_mark_dead(Channel *c)
+chan_mark_dead(struct ssh *ssh, Channel *c)
{
c->type = SSH_CHANNEL_ZOMBIE;
}
int
-chan_is_dead(Channel *c, int do_send)
+chan_is_dead(struct ssh *ssh, Channel *c, int do_send)
{
if (c->type == SSH_CHANNEL_ZOMBIE) {
debug2("channel %d: zombie", c->self);
@@ -318,9 +328,9 @@ chan_is_dead(Channel *c, int do_send)
if ((datafellows & SSH_BUG_EXTEOF) &&
c->extended_usage == CHAN_EXTENDED_WRITE &&
c->efd != -1 &&
- buffer_len(&c->extended) > 0) {
- debug2("channel %d: active efd: %d len %d",
- c->self, c->efd, buffer_len(&c->extended));
+ sshbuf_len(c->extended) > 0) {
+ debug2("channel %d: active efd: %d len %zu",
+ c->self, c->efd, sshbuf_len(c->extended));
return 0;
}
if (c->flags & CHAN_LOCAL) {
@@ -329,7 +339,7 @@ chan_is_dead(Channel *c, int do_send)
}
if (!(c->flags & CHAN_CLOSE_SENT)) {
if (do_send) {
- chan_send_close2(c);
+ chan_send_close2(ssh, c);
} else {
/* channel would be dead if we sent a close */
if (c->flags & CHAN_CLOSE_RCVD) {
@@ -349,9 +359,9 @@ chan_is_dead(Channel *c, int do_send)
/* helper */
static void
-chan_shutdown_write(Channel *c)
+chan_shutdown_write(struct ssh *ssh, Channel *c)
{
- buffer_clear(&c->output);
+ sshbuf_reset(c->output);
if (c->type == SSH_CHANNEL_LARVAL)
return;
/* shutdown failure is allowed if write failed already */
@@ -362,7 +372,7 @@ chan_shutdown_write(Channel *c)
"shutdown() failed for fd %d: %.100s",
c->self, c->sock, strerror(errno));
} else {
- if (channel_close_fd(&c->wfd) < 0)
+ if (channel_close_fd(ssh, &c->wfd) < 0)
logit("channel %d: chan_shutdown_write: "
"close() failed for fd %d: %.100s",
c->self, c->wfd, strerror(errno));
@@ -370,7 +380,7 @@ chan_shutdown_write(Channel *c)
}
static void
-chan_shutdown_read(Channel *c)
+chan_shutdown_read(struct ssh *ssh, Channel *c)
{
if (c->type == SSH_CHANNEL_LARVAL)
return;
@@ -388,7 +398,7 @@ chan_shutdown_read(Channel *c)
c->self, c->sock, c->istate, c->ostate,
strerror(errno));
} else {
- if (channel_close_fd(&c->rfd) < 0)
+ if (channel_close_fd(ssh, &c->rfd) < 0)
logit("channel %d: chan_shutdown_read: "
"close() failed for fd %d: %.100s",
c->self, c->rfd, strerror(errno));
diff --git a/packet.c b/packet.c
index ff69b660..f114ea52 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.263 2017/07/23 23:37:02 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.264 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
@@ -2090,35 +2090,6 @@ ssh_packet_get_maxsize(struct ssh *ssh)
return ssh->state->max_packet_size;
}
-/*
- * 9.2. Ignored Data Message
- *
- * byte SSH_MSG_IGNORE
- * string data
- *
- * All implementations MUST understand (and ignore) this message at any
- * time (after receiving the protocol version). No implementation is
- * required to send them. This message can be used as an additional
- * protection measure against advanced traffic analysis techniques.
- */
-void
-ssh_packet_send_ignore(struct ssh *ssh, int nbytes)
-{
- u_int32_t rnd = 0;
- int r, i;
-
- if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
- (r = sshpkt_put_u32(ssh, nbytes)) != 0)
- fatal("%s: %s", __func__, ssh_err(r));
- for (i = 0; i < nbytes; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
- if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0)
- fatal("%s: %s", __func__, ssh_err(r));
- rnd >>= 8;
- }
-}
-
void
ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds)
{
@@ -2539,6 +2510,12 @@ sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
}
int
+sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp)
+{
+ return sshbuf_peek_string_direct(ssh->state->incoming_packet, valp, lenp);
+}
+
+int
sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp)
{
return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp);
@@ -2621,6 +2598,37 @@ ssh_packet_send_mux(struct ssh *ssh)
return 0;
}
+/*
+ * 9.2. Ignored Data Message
+ *
+ * byte SSH_MSG_IGNORE
+ * string data
+ *
+ * All implementations MUST understand (and ignore) this message at any
+ * time (after receiving the protocol version). No implementation is
+ * required to send them. This message can be used as an additional
+ * protection measure against advanced traffic analysis techniques.
+ */
+int
+sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes)
+{
+ u_int32_t rnd = 0;
+ int r;
+ u_int i;
+
+ if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
+ (r = sshpkt_put_u32(ssh, nbytes)) != 0)
+ return r;
+ for (i = 0; i < nbytes; i++) {
+ if (i % 4 == 0)
+ rnd = arc4random();
+ if ((r = sshpkt_put_u8(ssh, (u_char)rnd & 0xff)) != 0)
+ return r;
+ rnd >>= 8;
+ }
+ return 0;
+}
+
/* send it */
int
diff --git a/packet.h b/packet.h
index 6ce6dd56..40837e9d 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.h,v 1.81 2017/05/31 08:09:45 markus Exp $ */
+/* $OpenBSD: packet.h,v 1.82 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -80,6 +80,9 @@ struct ssh {
/* Client/Server authentication context */
void *authctxt;
+ /* Channels context */
+ struct ssh_channels *chanctxt;
+
/* APP data */
void *app_data;
};
@@ -143,7 +146,6 @@ int ssh_packet_not_very_much_data_to_write(struct ssh *);
int ssh_packet_connection_is_on_socket(struct ssh *);
int ssh_packet_remaining(struct ssh *);
-void ssh_packet_send_ignore(struct ssh *, int);
void tty_make_modes(int, struct termios *);
void tty_parse_modes(int, int *);
@@ -174,6 +176,7 @@ int sshpkt_disconnect(struct ssh *, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
int sshpkt_add_padding(struct ssh *, u_char);
void sshpkt_fatal(struct ssh *ssh, const char *tag, int r);
+int sshpkt_msg_ignore(struct ssh *, u_int);
int sshpkt_put(struct ssh *ssh, const void *v, size_t len);
int sshpkt_putb(struct ssh *ssh, const struct sshbuf *b);
@@ -192,6 +195,7 @@ int sshpkt_get_u32(struct ssh *ssh, u_int32_t *valp);
int sshpkt_get_u64(struct ssh *ssh, u_int64_t *valp);
int sshpkt_get_string(struct ssh *ssh, u_char **valp, size_t *lenp);
int sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp);
+int sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp);
int sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp);
int sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g);
int sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v);
diff --git a/servconf.c b/servconf.c
index ed1fc71c..e0e43c3d 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: servconf.c,v 1.309 2017/06/24 06:34:38 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.310 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -149,7 +149,7 @@ initialize_server_options(ServerOptions *options)
options->num_authkeys_files = 0;
options->num_accept_env = 0;
options->permit_tun = -1;
- options->num_permitted_opens = -1;
+ options->permitted_opens = NULL;
options->adm_forced_command = NULL;
options->chroot_directory = NULL;
options->authorized_keys_command = NULL;
@@ -697,6 +697,44 @@ process_queued_listen_addrs(ServerOptions *options)
options->num_queued_listens = 0;
}
+/*
+ * Inform channels layer of permitopen options from configuration.
+ */
+void
+process_permitopen(struct ssh *ssh, ServerOptions *options)
+{
+ u_int i;
+ int port;
+ char *host, *arg, *oarg;
+
+ channel_clear_adm_permitted_opens(ssh);
+ if (options->num_permitted_opens == 0)
+ return; /* permit any */
+
+ /* handle keywords: "any" / "none" */
+ if (options->num_permitted_opens == 1 &&
+ strcmp(options->permitted_opens[0], "any") == 0)
+ return;
+ if (options->num_permitted_opens == 1 &&
+ strcmp(options->permitted_opens[0], "none") == 0) {
+ channel_disable_adm_local_opens(ssh);
+ return;
+ }
+ /* Otherwise treat it as a list of permitted host:port */
+ for (i = 0; i < options->num_permitted_opens; i++) {
+ oarg = arg = xstrdup(options->permitted_opens[i]);
+ host = hpdelim(&arg);
+ if (host == NULL)
+ fatal("%s: missing host in PermitOpen", __func__);
+ host = cleanhostname(host);
+ if (arg == NULL || ((port = permitopen_port(arg)) < 0))
+ fatal("%s: bad port number in PermitOpen", __func__);
+ /* Send it to channels layer */
+ channel_add_adm_permitted_opens(ssh, host, port);
+ free(oarg);
+ }
+}
+
struct connection_info *
get_connection_info(int populate, int use_dns)
{
@@ -954,7 +992,7 @@ process_server_config_line(ServerOptions *options, char *line,
const char *filename, int linenum, int *activep,
struct connection_info *connectinfo)
{
- char *cp, **charptr, *arg, *p;
+ char *cp, **charptr, *arg, *arg2, *p;
int cmdline = 0, *intptr, value, value2, n, port;
SyslogFacility *log_facility_ptr;
LogLevel *log_level_ptr;
@@ -1625,24 +1663,17 @@ process_server_config_line(ServerOptions *options, char *line,
if (!arg || *arg == '\0')
fatal("%s line %d: missing PermitOpen specification",
filename, linenum);
- n = options->num_permitted_opens; /* modified later */
- if (strcmp(arg, "any") == 0) {
- if (*activep && n == -1) {
- channel_clear_adm_permitted_opens();
- options->num_permitted_opens = 0;
- }
- break;
- }
- if (strcmp(arg, "none") == 0) {
- if (*activep && n == -1) {
+ i = options->num_permitted_opens; /* modified later */
+ if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
+ if (*activep && i == 0)
options->num_permitted_opens = 1;
- channel_disable_adm_local_opens();
- }
+ options->permitted_opens = xcalloc(1,
+ sizeof(*options->permitted_opens));
+ options->permitted_opens[0] = xstrdup(arg);
break;
}
- if (*activep && n == -1)
- channel_clear_adm_permitted_opens();
for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
+ arg2 = xstrdup(arg);
p = hpdelim(&arg);
if (p == NULL)
fatal("%s line %d: missing host in PermitOpen",
@@ -1651,9 +1682,16 @@ process_server_config_line(ServerOptions *options, char *line,
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
fatal("%s line %d: bad port number in "
"PermitOpen", filename, linenum);
- if (*activep && n == -1)
- options->num_permitted_opens =
- channel_add_adm_permitted_opens(p, port);
+ if (*activep && i == 0) {
+ options->permitted_opens = xrecallocarray(
+ options->permitted_opens,
+ options->num_permitted_opens,
+ options->num_permitted_opens + 1,
+ sizeof(*options->permitted_opens));
+ i = options->num_permitted_opens++;
+ options->permitted_opens[i] = arg2;
+ } else
+ free(arg2);
}
break;
@@ -2352,5 +2390,12 @@ dump_config(ServerOptions *o)
printf("rekeylimit %llu %d\n", (unsigned long long)o->rekey_limit,
o->rekey_interval);
- channel_print_adm_permitted_opens();
+ printf("permitopen");
+ if (o->num_permitted_opens == 0)
+ printf(" any");
+ else {
+ for (i = 0; i < o->num_permitted_opens; i++)
+ printf(" %s", o->permitted_opens[i]);
+ }
+ printf("\n");
}
diff --git a/servconf.h b/servconf.h
index c2848a76..ffcbc331 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.124 2017/06/24 06:34:38 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.125 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -48,12 +48,19 @@
#define FORWARD_LOCAL (1<<1)
#define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL)
+/* PermitOpen */
+#define PERMITOPEN_ANY 0
+#define PERMITOPEN_NONE -2
+
#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */
/* Magic name for internal sftp-server */
#define INTERNAL_SFTP_NAME "internal-sftp"
+struct ssh;
+struct fwd_perm_list;
+
typedef struct {
u_int num_ports;
u_int ports_from_cmdline;
@@ -169,7 +176,8 @@ typedef struct {
int permit_tun;
- int num_permitted_opens;
+ char **permitted_opens;
+ u_int num_permitted_opens; /* May also be one of PERMITOPEN_* */
char *chroot_directory;
char *revoked_keys_file;
@@ -229,6 +237,7 @@ struct connection_info {
M_CP_STRARRAYOPT(deny_groups, num_deny_groups); \
M_CP_STRARRAYOPT(accept_env, num_accept_env); \
M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \
+ M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \
} while (0)
struct connection_info *get_connection_info(int, int);
@@ -236,6 +245,7 @@ void initialize_server_options(ServerOptions *);
void fill_default_server_options(ServerOptions *);
int process_server_config_line(ServerOptions *, char *, const char *, int,
int *, struct connection_info *);
+void process_permitopen(struct ssh *ssh, ServerOptions *options);
void load_server_config(const char *, Buffer *);
void parse_server_config(ServerOptions *, const char *, Buffer *,
struct connection_info *);
diff --git a/serverloop.c b/serverloop.c
index bc56709b..56715941 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.196 2017/08/30 03:59:08 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.197 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
@@ -165,7 +165,7 @@ sigterm_handler(int sig)
}
static void
-client_alive_check(void)
+client_alive_check(struct ssh *ssh)
{
int channel_id;
@@ -179,12 +179,13 @@ client_alive_check(void)
* send a bogus global/channel request with "wantreply",
* we should get back a failure
*/
- if ((channel_id = channel_find_open()) == -1) {
+ if ((channel_id = channel_find_open(ssh)) == -1) {
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("keepalive@openssh.com");
packet_put_char(1); /* boolean: want reply */
} else {
- channel_request_start(channel_id, "keepalive@openssh.com", 1);
+ channel_request_start(ssh, channel_id,
+ "keepalive@openssh.com", 1);
}
packet_send();
}
@@ -196,7 +197,8 @@ client_alive_check(void)
* for the duration of the wait (0 = infinite).
*/
static void
-wait_until_can_do_something(int connection_in, int connection_out,
+wait_until_can_do_something(struct ssh *ssh,
+ int connection_in, int connection_out,
fd_set **readsetp, fd_set **writesetp, int *maxfdp,
u_int *nallocp, u_int64_t max_time_ms)
{
@@ -207,7 +209,7 @@ wait_until_can_do_something(int connection_in, int connection_out,
static time_t last_client_time;
/* Allocate and update select() masks for channel descriptors. */
- channel_prepare_select(active_state, readsetp, writesetp, maxfdp,
+ channel_prepare_select(ssh, readsetp, writesetp, maxfdp,
nallocp, &minwait_secs);
/* XXX need proper deadline system for rekey/client alive */
@@ -273,12 +275,12 @@ wait_until_can_do_something(int connection_in, int connection_out,
time_t now = monotime();
if (ret == 0) { /* timeout */
- client_alive_check();
+ client_alive_check(ssh);
} else if (FD_ISSET(connection_in, *readsetp)) {
last_client_time = now;
} else if (last_client_time != 0 && last_client_time +
options.client_alive_interval <= now) {
- client_alive_check();
+ client_alive_check(ssh);
last_client_time = now;
}
}
@@ -291,9 +293,8 @@ wait_until_can_do_something(int connection_in, int connection_out,
* in buffers and processed later.
*/
static int
-process_input(fd_set *readset, int connection_in)
+process_input(struct ssh *ssh, fd_set *readset, int connection_in)
{
- struct ssh *ssh = active_state; /* XXX */
int len;
char buf[16384];
@@ -333,13 +334,13 @@ process_output(fd_set *writeset, int connection_out)
}
static void
-process_buffered_input_packets(void)
+process_buffered_input_packets(struct ssh *ssh)
{
- ssh_dispatch_run_fatal(active_state, DISPATCH_NONBLOCK, NULL);
+ ssh_dispatch_run_fatal(ssh, DISPATCH_NONBLOCK, NULL);
}
static void
-collect_children(void)
+collect_children(struct ssh *ssh)
{
pid_t pid;
sigset_t oset, nset;
@@ -354,14 +355,14 @@ collect_children(void)
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
if (pid > 0)
- session_close_by_pid(pid, status);
+ session_close_by_pid(ssh, pid, status);
child_terminated = 0;
}
sigprocmask(SIG_SETMASK, &oset, NULL);
}
void
-server_loop2(Authctxt *authctxt)
+server_loop2(struct ssh *ssh, Authctxt *authctxt)
{
fd_set *readset = NULL, *writeset = NULL;
int max_fd;
@@ -389,18 +390,17 @@ server_loop2(Authctxt *authctxt)
server_init_dispatch();
for (;;) {
- process_buffered_input_packets();
+ process_buffered_input_packets(ssh);
- if (!ssh_packet_is_rekeying(active_state) &&
+ if (!ssh_packet_is_rekeying(ssh) &&
packet_not_very_much_data_to_write())
- channel_output_poll();
- if (options.rekey_interval > 0 &&
- !ssh_packet_is_rekeying(active_state))
+ channel_output_poll(ssh);
+ if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh))
rekey_timeout_ms = packet_get_rekey_timeout() * 1000;
else
rekey_timeout_ms = 0;
- wait_until_can_do_something(connection_in, connection_out,
+ wait_until_can_do_something(ssh, connection_in, connection_out,
&readset, &writeset, &max_fd, &nalloc, rekey_timeout_ms);
if (received_sigterm) {
@@ -409,23 +409,23 @@ server_loop2(Authctxt *authctxt)
cleanup_exit(255);
}
- collect_children();
- if (!ssh_packet_is_rekeying(active_state))
- channel_after_select(active_state, readset, writeset);
- if (process_input(readset, connection_in) < 0)
+ collect_children(ssh);
+ if (!ssh_packet_is_rekeying(ssh))
+ channel_after_select(ssh, readset, writeset);
+ if (process_input(ssh, readset, connection_in) < 0)
break;
process_output(writeset, connection_out);
}
- collect_children();
+ collect_children(ssh);
free(readset);
free(writeset);
/* free all channels, no more reads and writes */
- channel_free_all();
+ channel_free_all(ssh);
/* free remaining sessions, e.g. remove wtmp entries */
- session_destroy_all(NULL);
+ session_destroy_all(ssh, NULL);
}
static int
@@ -442,7 +442,7 @@ server_input_keep_alive(int type, u_int32_t seq, struct ssh *ssh)
}
static Channel *
-server_request_direct_tcpip(int *reason, const char **errmsg)
+server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
{
Channel *c = NULL;
char *target, *originator;
@@ -460,7 +460,7 @@ server_request_direct_tcpip(int *reason, const char **errmsg)
/* XXX fine grained permissions */
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
!no_port_forwarding_flag && !options.disable_forwarding) {
- c = channel_connect_to_port(target, target_port,
+ c = channel_connect_to_port(ssh, target, target_port,
"direct-tcpip", "direct-tcpip", reason, errmsg);
} else {
logit("refused local port forward: "
@@ -477,7 +477,7 @@ server_request_direct_tcpip(int *reason, const char **errmsg)
}
static Channel *
-server_request_direct_streamlocal(void)
+server_request_direct_streamlocal(struct ssh *ssh)
{
Channel *c = NULL;
char *target, *originator;
@@ -499,7 +499,7 @@ server_request_direct_streamlocal(void)
if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
!no_port_forwarding_flag && !options.disable_forwarding &&
(pw->pw_uid == 0 || use_privsep)) {
- c = channel_connect_to_path(target,
+ c = channel_connect_to_path(ssh, target,
"direct-streamlocal@openssh.com", "direct-streamlocal");
} else {
logit("refused streamlocal port forward: "
@@ -514,7 +514,7 @@ server_request_direct_streamlocal(void)
}
static Channel *
-server_request_tun(void)
+server_request_tun(struct ssh *ssh)
{
Channel *c = NULL;
int mode, tun;
@@ -544,7 +544,7 @@ server_request_tun(void)
sock = tun_open(tun, mode);
if (sock < 0)
goto done;
- c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
+ c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;
#if defined(SSH_TUN_FILTER)
@@ -560,7 +560,7 @@ server_request_tun(void)
}
static Channel *
-server_request_session(void)
+server_request_session(struct ssh *ssh)
{
Channel *c;
@@ -578,15 +578,15 @@ server_request_session(void)
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
- c = channel_new("session", SSH_CHANNEL_LARVAL,
+ c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL,
-1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
0, "server-session", 1);
if (session_open(the_authctxt, c->self) != 1) {
debug("session open failed, free channel %d", c->self);
- channel_free(c);
+ channel_free(ssh, c);
return NULL;
}
- channel_register_cleanup(c->self, session_close_by_channel, 0);
+ channel_register_cleanup(ssh, c->self, session_close_by_channel, 0);
return c;
}
@@ -608,13 +608,13 @@ server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) {
- c = server_request_session();
+ c = server_request_session(ssh);
} else if (strcmp(ctype, "direct-tcpip") == 0) {
- c = server_request_direct_tcpip(&reason, &errmsg);
+ c = server_request_direct_tcpip(ssh, &reason, &errmsg);
} else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
- c = server_request_direct_streamlocal();
+ c = server_request_direct_streamlocal(ssh);
} else if (strcmp(ctype, "tun@openssh.com") == 0) {
- c = server_request_tun();
+ c = server_request_tun(ssh);
}
if (c != NULL) {
debug("server_input_channel_open: confirm %s", ctype);
@@ -645,9 +645,8 @@ server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
}
static int
-server_input_hostkeys_prove(struct sshbuf **respp)
+server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
{
- struct ssh *ssh = active_state; /* XXX */
struct sshbuf *resp = NULL;
struct sshbuf *sigbuf = NULL;
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
@@ -750,7 +749,7 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
- success = channel_setup_remote_fwd_listener(&fwd,
+ success = channel_setup_remote_fwd_listener(ssh, &fwd,
&allocated_listen_port, &options.fwd_opts);
}
free(fwd.listen_host);
@@ -768,7 +767,7 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
fwd.listen_host, fwd.listen_port);
- success = channel_cancel_rport_listener(&fwd);
+ success = channel_cancel_rport_listener(ssh, &fwd);
free(fwd.listen_host);
} else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
struct Forward fwd;
@@ -787,7 +786,7 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
"streamlocal forwarding.");
} else {
/* Start listening on the socket */
- success = channel_setup_remote_fwd_listener(
+ success = channel_setup_remote_fwd_listener(ssh,
&fwd, NULL, &options.fwd_opts);
}
free(fwd.listen_path);
@@ -799,19 +798,19 @@ server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
debug("%s: cancel-streamlocal-forward path %s", __func__,
fwd.listen_path);
- success = channel_cancel_rport_listener(&fwd);
+ success = channel_cancel_rport_listener(ssh, &fwd);
free(fwd.listen_path);
} else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
no_more_sessions = 1;
success = 1;
} else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) {
- success = server_input_hostkeys_prove(&resp);
+ success = server_input_hostkeys_prove(ssh, &resp);
}
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
if (success && resp != NULL)
- ssh_packet_put_raw(active_state, sshbuf_ptr(resp),
+ ssh_packet_put_raw(ssh, sshbuf_ptr(resp),
sshbuf_len(resp));
packet_send();
packet_write_wait();
@@ -835,15 +834,15 @@ server_input_channel_req(int type, u_int32_t seq, struct ssh *ssh)
debug("server_input_channel_req: channel %d request %s reply %d",
id, rtype, reply);
- if ((c = channel_lookup(id)) == NULL)
+ if ((c = channel_lookup(ssh, id)) == NULL)
packet_disconnect("server_input_channel_req: "
"unknown channel %d", id);
if (!strcmp(rtype, "eow@openssh.com")) {
packet_check_eom();
- chan_rcvd_eow(c);
+ chan_rcvd_eow(ssh, c);
} else if ((c->type == SSH_CHANNEL_LARVAL ||
c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
- success = session_input_channel_req(c, rtype);
+ success = session_input_channel_req(ssh, c, rtype);
if (reply && !(c->flags & CHAN_CLOSE_SENT)) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
diff --git a/serverloop.h b/serverloop.h
index d5fbda16..fd2cf63f 100644
--- a/serverloop.h
+++ b/serverloop.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.h,v 1.7 2016/08/13 17:47:41 markus Exp $ */
+/* $OpenBSD: serverloop.h,v 1.8 2017/09/12 06:32:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -21,6 +21,8 @@
#ifndef SERVERLOOP_H
#define SERVERLOOP_H
-void server_loop2(Authctxt *);
+struct ssh;
+
+void server_loop2(struct ssh *, Authctxt *);
#endif
diff --git a/session.c b/session.c
index cd03fd42..4bccb62d 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.291 2017/08/18 05:36:45 djm Exp $ */
+/* $OpenBSD: session.c,v 1.292 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -113,24 +113,24 @@
/* func */
Session *session_new(void);
-void session_set_fds(Session *, int, int, int, int, int);
+void session_set_fds(struct ssh *, Session *, int, int, int, int, int);
void session_pty_cleanup(Session *);
void session_proctitle(Session *);
-int session_setup_x11fwd(Session *);
-int do_exec_pty(Session *, const char *);
-int do_exec_no_pty(Session *, const char *);
-int do_exec(Session *, const char *);
-void do_login(Session *, const char *);
+int session_setup_x11fwd(struct ssh *, Session *);
+int do_exec_pty(struct ssh *, Session *, const char *);
+int do_exec_no_pty(struct ssh *, Session *, const char *);
+int do_exec(struct ssh *, Session *, const char *);
+void do_login(struct ssh *, Session *, const char *);
+void do_child(struct ssh *, Session *, const char *);
#ifdef LOGIN_NEEDS_UTMPX
static void do_pre_login(Session *s);
#endif
-void do_child(Session *, const char *);
void do_motd(void);
int check_quietlogin(Session *, const char *);
-static void do_authenticated2(Authctxt *);
+static void do_authenticated2(struct ssh *, Authctxt *);
-static int session_pty_req(Session *);
+static int session_pty_req(struct ssh *, Session *);
/* import */
extern ServerOptions options;
@@ -183,7 +183,7 @@ auth_sock_cleanup_proc(struct passwd *pw)
}
static int
-auth_input_request_forwarding(struct passwd * pw)
+auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
{
Channel *nc;
int sock = -1;
@@ -223,7 +223,7 @@ auth_input_request_forwarding(struct passwd * pw)
goto authsock_err;
/* Allocate a channel for the authentication agent socket. */
- nc = channel_new("auth socket",
+ nc = channel_new(ssh, "auth socket",
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "auth socket", 1);
@@ -288,7 +288,7 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
}
void
-do_authenticated(Authctxt *authctxt)
+do_authenticated(struct ssh *ssh, Authctxt *authctxt)
{
setproctitle("%s", authctxt->pw->pw_name);
@@ -296,17 +296,17 @@ do_authenticated(Authctxt *authctxt)
/* XXX - streamlocal? */
if (no_port_forwarding_flag || options.disable_forwarding ||
(options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
- channel_disable_adm_local_opens();
+ channel_disable_adm_local_opens(ssh);
else
- channel_permit_all_opens();
+ channel_permit_all_opens(ssh);
auth_debug_send();
prepare_auth_info_file(authctxt->pw, authctxt->session_info);
- do_authenticated2(authctxt);
+ do_authenticated2(ssh, authctxt);
- do_cleanup(authctxt);
+ do_cleanup(ssh, authctxt);
}
/* Check untrusted xauth strings for metacharacters */
@@ -331,7 +331,7 @@ xauth_valid_string(const char *s)
* setting up file descriptors and such.
*/
int
-do_exec_no_pty(Session *s, const char *command)
+do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
{
pid_t pid;
@@ -456,7 +456,7 @@ do_exec_no_pty(Session *s, const char *command)
#endif
/* Do processing for the child (exec command etc). */
- do_child(s, command);
+ do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
@@ -487,7 +487,7 @@ do_exec_no_pty(Session *s, const char *command)
close(pout[1]);
close(perr[1]);
- session_set_fds(s, pin[1], pout[0], perr[0],
+ session_set_fds(ssh, s, pin[1], pout[0], perr[0],
s->is_subsystem, 0);
#else
/* We are the parent. Close the child sides of the socket pairs. */
@@ -511,7 +511,7 @@ do_exec_no_pty(Session *s, const char *command)
* lastlog, and other such operations.
*/
int
-do_exec_pty(Session *s, const char *command)
+do_exec_pty(struct ssh *ssh, Session *s, const char *command)
{
int fdout, ptyfd, ttyfd, ptymaster;
pid_t pid;
@@ -580,13 +580,13 @@ do_exec_pty(Session *s, const char *command)
cray_init_job(s->pw); /* set up cray jid and tmpdir */
#endif /* _UNICOS */
#ifndef HAVE_OSF_SIA
- do_login(s, command);
+ do_login(ssh, s, command);
#endif
/*
* Do common processing for the child, such as execing
* the command.
*/
- do_child(s, command);
+ do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
@@ -608,7 +608,7 @@ do_exec_pty(Session *s, const char *command)
s->ptymaster = ptymaster;
packet_set_interactive(1,
options.ip_qos_interactive, options.ip_qos_bulk);
- session_set_fds(s, ptyfd, fdout, -1, 1, 1);
+ session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
return 0;
}
@@ -646,9 +646,8 @@ do_pre_login(Session *s)
* to be forced, execute that instead.
*/
int
-do_exec(Session *s, const char *command)
+do_exec(struct ssh *ssh, Session *s, const char *command)
{
- struct ssh *ssh = active_state; /* XXX */
int ret;
const char *forced = NULL, *tty = NULL;
char session_type[1024];
@@ -707,9 +706,9 @@ do_exec(Session *s, const char *command)
}
#endif
if (s->ttyfd != -1)
- ret = do_exec_pty(s, command);
+ ret = do_exec_pty(ssh, s, command);
else
- ret = do_exec_no_pty(s, command);
+ ret = do_exec_no_pty(ssh, s, command);
original_command = NULL;
@@ -725,9 +724,8 @@ do_exec(Session *s, const char *command)
/* administrative, login(1)-like work */
void
-do_login(Session *s, const char *command)
+do_login(struct ssh *ssh, Session *s, const char *command)
{
- struct ssh *ssh = active_state; /* XXX */
socklen_t fromlen;
struct sockaddr_storage from;
struct passwd * pw = s->pw;
@@ -960,9 +958,8 @@ copy_environment(char **source, char ***env, u_int *envsize)
}
static char **
-do_setup_env(Session *s, const char *shell)
+do_setup_env(struct ssh *ssh, Session *s, const char *shell)
{
- struct ssh *ssh = active_state; /* XXX */
char buf[256];
u_int i, envsize;
char **env, *laddr;
@@ -1421,7 +1418,7 @@ do_pwchange(Session *s)
}
static void
-child_close_fds(void)
+child_close_fds(struct ssh *ssh)
{
extern int auth_sock;
@@ -1441,7 +1438,7 @@ child_close_fds(void)
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
- channel_close_all();
+ channel_close_all(ssh);
/*
* Close any extra file descriptors. Note that there may still be
@@ -1465,7 +1462,7 @@ child_close_fds(void)
*/
#define ARGV_MAX 10
void
-do_child(Session *s, const char *command)
+do_child(struct ssh *ssh, Session *s, const char *command)
{
extern char **environ;
char **env;
@@ -1481,7 +1478,7 @@ do_child(Session *s, const char *command)
/* Force a password change */
if (s->authctxt->force_pwchange) {
do_setusercontext(pw);
- child_close_fds();
+ child_close_fds(ssh);
do_pwchange(s);
exit(1);
}
@@ -1530,7 +1527,7 @@ do_child(Session *s, const char *command)
* Make sure $SHELL points to the shell from the password file,
* even if shell is overridden from login.conf
*/
- env = do_setup_env(s, shell);
+ env = do_setup_env(ssh, s, shell);
#ifdef HAVE_LOGIN_CAP
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
@@ -1543,7 +1540,7 @@ do_child(Session *s, const char *command)
* closed before building the environment, as we call
* ssh_remote_ipaddr there.
*/
- child_close_fds();
+ child_close_fds(ssh);
/*
* Must take new environment into use so that .ssh/rc,
@@ -1840,7 +1837,7 @@ session_by_pid(pid_t pid)
}
static int
-session_window_change_req(Session *s)
+session_window_change_req(struct ssh *ssh, Session *s)
{
s->col = packet_get_int();
s->row = packet_get_int();
@@ -1852,7 +1849,7 @@ session_window_change_req(Session *s)
}
static int
-session_pty_req(Session *s)
+session_pty_req(struct ssh *ssh, Session *s)
{
u_int len;
int n_bytes;
@@ -1905,7 +1902,7 @@ session_pty_req(Session *s)
}
static int
-session_subsystem_req(Session *s)
+session_subsystem_req(struct ssh *ssh, Session *s)
{
struct stat st;
u_int len;
@@ -1932,7 +1929,7 @@ session_subsystem_req(Session *s)
s->is_subsystem = SUBSYSTEM_EXT;
debug("subsystem: exec() %s", cmd);
}
- success = do_exec(s, cmd) == 0;
+ success = do_exec(ssh, s, cmd) == 0;
break;
}
}
@@ -1945,7 +1942,7 @@ session_subsystem_req(Session *s)
}
static int
-session_x11_req(Session *s)
+session_x11_req(struct ssh *ssh, Session *s)
{
int success;
@@ -1962,7 +1959,7 @@ session_x11_req(Session *s)
if (xauth_valid_string(s->auth_proto) &&
xauth_valid_string(s->auth_data))
- success = session_setup_x11fwd(s);
+ success = session_setup_x11fwd(ssh, s);
else {
success = 0;
error("Invalid X11 forwarding data");
@@ -1977,26 +1974,26 @@ session_x11_req(Session *s)
}
static int
-session_shell_req(Session *s)
+session_shell_req(struct ssh *ssh, Session *s)
{
packet_check_eom();
- return do_exec(s, NULL) == 0;
+ return do_exec(ssh, s, NULL) == 0;
}
static int
-session_exec_req(Session *s)
+session_exec_req(struct ssh *ssh, Session *s)
{
u_int len, success;
char *command = packet_get_string(&len);
packet_check_eom();
- success = do_exec(s, command) == 0;
+ success = do_exec(ssh, s, command) == 0;
free(command);
return success;
}
static int
-session_break_req(Session *s)
+session_break_req(struct ssh *ssh, Session *s)
{
packet_get_int(); /* ignored */
@@ -2008,7 +2005,7 @@ session_break_req(Session *s)
}
static int
-session_env_req(Session *s)
+session_env_req(struct ssh *ssh, Session *s)
{
char *name, *val;
u_int name_len, val_len, i;
@@ -2043,7 +2040,7 @@ session_env_req(Session *s)
}
static int
-session_auth_agent_req(Session *s)
+session_auth_agent_req(struct ssh *ssh, Session *s)
{
static int called = 0;
packet_check_eom();
@@ -2055,22 +2052,21 @@ session_auth_agent_req(Session *s)
return 0;
} else {
called = 1;
- return auth_input_request_forwarding(s->pw);
+ return auth_input_request_forwarding(ssh, s->pw);
}
}
int
-session_input_channel_req(Channel *c, const char *rtype)
+session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
{
int success = 0;
Session *s;
if ((s = session_by_channel(c->self)) == NULL) {
- logit("session_input_channel_req: no session %d req %.100s",
- c->self, rtype);
+ logit("%s: no session %d req %.100s", __func__, c->self, rtype);
return 0;
}
- debug("session_input_channel_req: session %d req %s", s->self, rtype);
+ debug("%s: session %d req %s", __func__, s->self, rtype);
/*
* a session is in LARVAL state until a shell, a command
@@ -2078,33 +2074,33 @@ session_input_channel_req(Channel *c, const char *rtype)
*/
if (c->type == SSH_CHANNEL_LARVAL) {
if (strcmp(rtype, "shell") == 0) {
- success = session_shell_req(s);
+ success = session_shell_req(ssh, s);
} else if (strcmp(rtype, "exec") == 0) {
- success = session_exec_req(s);
+ success = session_exec_req(ssh, s);
} else if (strcmp(rtype, "pty-req") == 0) {
- success = session_pty_req(s);
+ success = session_pty_req(ssh, s);
} else if (strcmp(rtype, "x11-req") == 0) {
- success = session_x11_req(s);
+ success = session_x11_req(ssh, s);
} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
- success = session_auth_agent_req(s);
+ success = session_auth_agent_req(ssh, s);
} else if (strcmp(rtype, "subsystem") == 0) {
- success = session_subsystem_req(s);
+ success = session_subsystem_req(ssh, s);
} else if (strcmp(rtype, "env") == 0) {
- success = session_env_req(s);
+ success = session_env_req(ssh, s);
}
}
if (strcmp(rtype, "window-change") == 0) {
- success = session_window_change_req(s);
+ success = session_window_change_req(ssh, s);
} else if (strcmp(rtype, "break") == 0) {
- success = session_break_req(s);
+ success = session_break_req(ssh, s);
}
return success;
}
void
-session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
- int is_tty)
+session_set_fds(struct ssh *ssh, Session *s,
+ int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
{
/*
* now that have a child and a pipe to the child,
@@ -2112,7 +2108,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
*/
if (s->chanid == -1)
fatal("no channel for session %d", s->self);
- channel_set_fds(s->chanid,
+ channel_set_fds(ssh, s->chanid,
fdout, fdin, fderr,
ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
1, is_tty, CHAN_SES_WINDOW_DEFAULT);
@@ -2183,40 +2179,40 @@ sig2name(int sig)
}
static void
-session_close_x11(int id)
+session_close_x11(struct ssh *ssh, int id)
{
Channel *c;
- if ((c = channel_by_id(id)) == NULL) {
- debug("session_close_x11: x11 channel %d missing", id);
+ if ((c = channel_by_id(ssh, id)) == NULL) {
+ debug("%s: x11 channel %d missing", __func__, id);
} else {
/* Detach X11 listener */
- debug("session_close_x11: detach x11 channel %d", id);
- channel_cancel_cleanup(id);
+ debug("%s: detach x11 channel %d", __func__, id);
+ channel_cancel_cleanup(ssh, id);
if (c->ostate != CHAN_OUTPUT_CLOSED)
- chan_mark_dead(c);
+ chan_mark_dead(ssh, c);
}
}
static void
-session_close_single_x11(int id, void *arg)
+session_close_single_x11(struct ssh *ssh, int id, void *arg)
{
Session *s;
u_int i;
- debug3("session_close_single_x11: channel %d", id);
- channel_cancel_cleanup(id);
+ debug3("%s: channel %d", __func__, id);
+ channel_cancel_cleanup(ssh, id);
if ((s = session_by_x11_channel(id)) == NULL)
- fatal("session_close_single_x11: no x11 channel %d", id);
+ fatal("%s: no x11 channel %d", __func__, id);
for (i = 0; s->x11_chanids[i] != -1; i++) {
- debug("session_close_single_x11: session %d: "
- "closing channel %d", s->self, s->x11_chanids[i]);
+ debug("%s: session %d: closing channel %d",
+ __func__, s->self, s->x11_chanids[i]);
/*
* The channel "id" is already closing, but make sure we
* close all of its siblings.
*/
if (s->x11_chanids[i] != id)
- session_close_x11(s->x11_chanids[i]);
+ session_close_x11(ssh, s->x11_chanids[i]);
}
free(s->x11_chanids);
s->x11_chanids = NULL;
@@ -2231,22 +2227,22 @@ session_close_single_x11(int id, void *arg)
}
static void
-session_exit_message(Session *s, int status)
+session_exit_message(struct ssh *ssh, Session *s, int status)
{
Channel *c;
- if ((c = channel_lookup(s->chanid)) == NULL)
- fatal("session_exit_message: session %d: no channel %d",
- s->self, s->chanid);
- debug("session_exit_message: session %d channel %d pid %ld",
- s->self, s->chanid, (long)s->pid);
+ if ((c = channel_lookup(ssh, s->chanid)) == NULL)
+ fatal("%s: session %d: no channel %d",
+ __func__, s->self, s->chanid);
+ debug("%s: session %d channel %d pid %ld",
+ __func__, s->self, s->chanid, (long)s->pid);
if (WIFEXITED(status)) {
- channel_request_start(s->chanid, "exit-status", 0);
+ channel_request_start(ssh, s->chanid, "exit-status", 0);
packet_put_int(WEXITSTATUS(status));
packet_send();
} else if (WIFSIGNALED(status)) {
- channel_request_start(s->chanid, "exit-signal", 0);
+ channel_request_start(ssh, s->chanid, "exit-signal", 0);
packet_put_cstring(sig2name(WTERMSIG(status)));
#ifdef WCOREDUMP
packet_put_char(WCOREDUMP(status)? 1 : 0);
@@ -2262,14 +2258,14 @@ session_exit_message(Session *s, int status)
}
/* disconnect channel */
- debug("session_exit_message: release channel %d", s->chanid);
+ debug("%s: release channel %d", __func__, s->chanid);
/*
* Adjust cleanup callback attachment to send close messages when
* the channel gets EOF. The session will be then be closed
* by session_close_by_channel when the childs close their fds.
*/
- channel_register_cleanup(c->self, session_close_by_channel, 1);
+ channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
/*
* emulate a write failure with 'chan_write_failed', nobody will be
@@ -2278,13 +2274,12 @@ session_exit_message(Session *s, int status)
* be some more data waiting in the pipe.
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
- chan_write_failed(c);
+ chan_write_failed(ssh, c);
}
void
-session_close(Session *s)
+session_close(struct ssh *ssh, Session *s)
{
- struct ssh *ssh = active_state; /* XXX */
u_int i;
verbose("Close session: user %s from %.200s port %d id %d",
@@ -2314,16 +2309,15 @@ session_close(Session *s)
}
void
-session_close_by_pid(pid_t pid, int status)
+session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
{
Session *s = session_by_pid(pid);
if (s == NULL) {
- debug("session_close_by_pid: no session for pid %ld",
- (long)pid);
+ debug("%s: no session for pid %ld", __func__, (long)pid);
return;
}
if (s->chanid != -1)
- session_exit_message(s, status);
+ session_exit_message(ssh, s, status);
if (s->ttyfd != -1)
session_pty_cleanup(s);
s->pid = 0;
@@ -2334,19 +2328,18 @@ session_close_by_pid(pid_t pid, int status)
* the session 'child' itself dies
*/
void
-session_close_by_channel(int id, void *arg)
+session_close_by_channel(struct ssh *ssh, int id, void *arg)
{
Session *s = session_by_channel(id);
u_int i;
if (s == NULL) {
- debug("session_close_by_channel: no session for id %d", id);
+ debug("%s: no session for id %d", __func__, id);
return;
}
- debug("session_close_by_channel: channel %d child %ld",
- id, (long)s->pid);
+ debug("%s: channel %d child %ld", __func__, id, (long)s->pid);
if (s->pid != 0) {
- debug("session_close_by_channel: channel %d: has child", id);
+ debug("%s: channel %d: has child", __func__, id);
/*
* delay detach of session, but release pty, since
* the fd's to the child are already closed
@@ -2356,22 +2349,22 @@ session_close_by_channel(int id, void *arg)
return;
}
/* detach by removing callback */
- channel_cancel_cleanup(s->chanid);
+ channel_cancel_cleanup(ssh, s->chanid);
/* Close any X11 listeners associated with this session */
if (s->x11_chanids != NULL) {
for (i = 0; s->x11_chanids[i] != -1; i++) {
- session_close_x11(s->x11_chanids[i]);
+ session_close_x11(ssh, s->x11_chanids[i]);
s->x11_chanids[i] = -1;
}
}
s->chanid = -1;
- session_close(s);
+ session_close(ssh, s);
}
void
-session_destroy_all(void (*closefunc)(Session *))
+session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
@@ -2380,7 +2373,7 @@ session_destroy_all(void (*closefunc)(Session *))
if (closefunc != NULL)
closefunc(s);
else
- session_close(s);
+ session_close(ssh, s);
}
}
}
@@ -2423,7 +2416,7 @@ session_proctitle(Session *s)
}
int
-session_setup_x11fwd(Session *s)
+session_setup_x11fwd(struct ssh *ssh, Session *s)
{
struct stat st;
char display[512], auth_display[512];
@@ -2447,14 +2440,14 @@ session_setup_x11fwd(Session *s)
debug("X11 display already set.");
return 0;
}
- if (x11_create_display_inet(options.x11_display_offset,
+ if (x11_create_display_inet(ssh, options.x11_display_offset,
options.x11_use_localhost, s->single_connection,
&s->display_number, &s->x11_chanids) == -1) {
debug("x11_create_display_inet failed.");
return 0;
}
for (i = 0; s->x11_chanids[i] != -1; i++) {
- channel_register_cleanup(s->x11_chanids[i],
+ channel_register_cleanup(ssh, s->x11_chanids[i],
session_close_single_x11, 0);
}
@@ -2499,13 +2492,13 @@ session_setup_x11fwd(Session *s)
}
static void
-do_authenticated2(Authctxt *authctxt)
+do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
{
- server_loop2(authctxt);
+ server_loop2(ssh, authctxt);
}
void
-do_cleanup(Authctxt *authctxt)
+do_cleanup(struct ssh *ssh, Authctxt *authctxt)
{
static int called = 0;
@@ -2561,7 +2554,7 @@ do_cleanup(Authctxt *authctxt)
* or if running in monitor.
*/
if (!use_privsep || mm_is_monitor())
- session_destroy_all(session_pty_cleanup2);
+ session_destroy_all(ssh, session_pty_cleanup2);
}
/* Return a name for the remote host that fits inside utmp_size */
diff --git a/session.h b/session.h
index 74c557db..54dd1f0c 100644
--- a/session.h
+++ b/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.34 2017/08/18 05:36:45 djm Exp $ */
+/* $OpenBSD: session.h,v 1.35 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -62,20 +62,20 @@ struct Session {
} *env;
};
-void do_authenticated(Authctxt *);
-void do_cleanup(Authctxt *);
+void do_authenticated(struct ssh *, Authctxt *);
+void do_cleanup(struct ssh *, Authctxt *);
int session_open(Authctxt *, int);
void session_unused(int);
-int session_input_channel_req(Channel *, const char *);
-void session_close_by_pid(pid_t, int);
-void session_close_by_channel(int, void *);
-void session_destroy_all(void (*)(Session *));
+int session_input_channel_req(struct ssh *, Channel *, const char *);
+void session_close_by_pid(struct ssh *ssh, pid_t, int);
+void session_close_by_channel(struct ssh *, int, void *);
+void session_destroy_all(struct ssh *, void (*)(Session *));
void session_pty_cleanup2(Session *);
Session *session_new(void);
Session *session_by_tty(char *);
-void session_close(Session *);
+void session_close(struct ssh *, Session *);
void do_setusercontext(struct passwd *);
const char *session_get_remote_name_or_ip(struct ssh *, u_int, int);
diff --git a/ssh.c b/ssh.c
index 019d1d31..ecc50f37 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.462 2017/08/12 06:46:01 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.463 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
@@ -208,7 +208,7 @@ usage(void)
exit(255);
}
-static int ssh_session2(void);
+static int ssh_session2(struct ssh *);
static void load_public_identity_files(void);
static void main_sigchld_handler(int);
@@ -596,6 +596,14 @@ main(int ac, char **av)
*/
initialize_options(&options);
+ /*
+ * Prepare main ssh transport/connection structures
+ */
+ if ((ssh = ssh_alloc_session_state()) == NULL)
+ fatal("Couldn't allocate session state");
+ channel_init_channels(ssh);
+ active_state = ssh; /* XXX legacy API compat */
+
/* Parse command-line arguments. */
host = NULL;
use_syslog = 0;
@@ -1108,7 +1116,7 @@ main(int ac, char **av)
if (options.port == 0)
options.port = default_ssh_port();
- channel_set_af(options.address_family);
+ channel_set_af(ssh, options.address_family);
/* Tidy and check options */
if (options.host_key_alias != NULL)
@@ -1253,8 +1261,7 @@ main(int ac, char **av)
if (options.control_path != NULL) {
int sock;
if ((sock = muxclient(options.control_path)) >= 0) {
- packet_set_connection(sock, sock);
- ssh = active_state; /* XXX */
+ ssh_packet_set_connection(ssh, sock, sock);
packet_set_mux();
goto skip_connect;
}
@@ -1274,7 +1281,7 @@ main(int ac, char **av)
timeout_ms = options.connection_timeout * 1000;
/* Open a connection to the remote host. */
- if (ssh_connect(host, addrs, &hostaddr, options.port,
+ if (ssh_connect(ssh, host, addrs, &hostaddr, options.port,
options.address_family, options.connection_attempts,
&timeout_ms, options.tcp_keep_alive,
options.use_privileged_port) != 0)
@@ -1457,7 +1464,7 @@ main(int ac, char **av)
}
skip_connect:
- exit_status = ssh_session2();
+ exit_status = ssh_session2(ssh);
packet_close();
if (options.control_path != NULL && muxserver_sock != -1)
@@ -1530,7 +1537,7 @@ fork_postauth(void)
/* Callback for remote forward global requests */
static void
-ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
{
struct Forward *rfwd = (struct Forward *)ctxt;
@@ -1548,10 +1555,10 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
logit("Allocated port %u for remote forward to %s:%d",
rfwd->allocated_port,
rfwd->connect_host, rfwd->connect_port);
- channel_update_permitted_opens(rfwd->handle,
- rfwd->allocated_port);
+ channel_update_permitted_opens(ssh,
+ rfwd->handle, rfwd->allocated_port);
} else {
- channel_update_permitted_opens(rfwd->handle, -1);
+ channel_update_permitted_opens(ssh, rfwd->handle, -1);
}
}
@@ -1580,21 +1587,21 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
}
static void
-client_cleanup_stdio_fwd(int id, void *arg)
+client_cleanup_stdio_fwd(struct ssh *ssh, int id, void *arg)
{
debug("stdio forwarding: done");
cleanup_exit(0);
}
static void
-ssh_stdio_confirm(int id, int success, void *arg)
+ssh_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
{
if (!success)
fatal("stdio forwarding failed");
}
static void
-ssh_init_stdio_forwarding(void)
+ssh_init_stdio_forwarding(struct ssh *ssh)
{
Channel *c;
int in, out;
@@ -1608,15 +1615,15 @@ ssh_init_stdio_forwarding(void)
if ((in = dup(STDIN_FILENO)) < 0 ||
(out = dup(STDOUT_FILENO)) < 0)
fatal("channel_connect_stdio_fwd: dup() in/out failed");
- if ((c = channel_connect_stdio_fwd(options.stdio_forward_host,
+ if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host,
options.stdio_forward_port, in, out)) == NULL)
fatal("%s: channel_connect_stdio_fwd failed", __func__);
- channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
- channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL);
+ channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0);
+ channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL);
}
static void
-ssh_init_forwarding(void)
+ssh_init_forwarding(struct ssh *ssh)
{
int success = 0;
int i;
@@ -1635,7 +1642,7 @@ ssh_init_forwarding(void)
options.local_forwards[i].connect_path :
options.local_forwards[i].connect_host,
options.local_forwards[i].connect_port);
- success += channel_setup_local_fwd_listener(
+ success += channel_setup_local_fwd_listener(ssh,
&options.local_forwards[i], &options.fwd_opts);
}
if (i > 0 && success != i && options.exit_on_forward_failure)
@@ -1657,7 +1664,7 @@ ssh_init_forwarding(void)
options.remote_forwards[i].connect_host,
options.remote_forwards[i].connect_port);
options.remote_forwards[i].handle =
- channel_request_remote_forwarding(
+ channel_request_remote_forwarding(ssh,
&options.remote_forwards[i]);
if (options.remote_forwards[i].handle < 0) {
if (options.exit_on_forward_failure)
@@ -1666,14 +1673,15 @@ ssh_init_forwarding(void)
logit("Warning: Could not request remote "
"forwarding.");
} else {
- client_register_global_confirm(ssh_confirm_remote_forward,
+ client_register_global_confirm(
+ ssh_confirm_remote_forward,
&options.remote_forwards[i]);
}
}
/* Initiate tunnel forwarding. */
if (options.tun_open != SSH_TUNMODE_NO) {
- if (client_request_tun_fwd(options.tun_open,
+ if (client_request_tun_fwd(ssh, options.tun_open,
options.tun_local, options.tun_remote) == -1) {
if (options.exit_on_forward_failure)
fatal("Could not request tunnel forwarding.");
@@ -1700,7 +1708,7 @@ check_agent_present(void)
}
static void
-ssh_session2_setup(int id, int success, void *arg)
+ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg)
{
extern char **environ;
const char *display;
@@ -1713,15 +1721,15 @@ ssh_session2_setup(int id, int success, void *arg)
display = getenv("DISPLAY");
if (display == NULL && options.forward_x11)
debug("X11 forwarding requested but DISPLAY not set");
- if (options.forward_x11 && client_x11_get_proto(display,
+ if (options.forward_x11 && client_x11_get_proto(ssh, display,
options.xauth_location, options.forward_x11_trusted,
options.forward_x11_timeout, &proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
- x11_request_forwarding_with_spoofing(id, display, proto,
+ x11_request_forwarding_with_spoofing(ssh, id, display, proto,
data, 1);
- client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN);
+ client_expect_confirm(ssh, id, "X11 forwarding", CONFIRM_WARN);
/* XXX exit_on_forward_failure */
interactive = 1;
}
@@ -1729,7 +1737,7 @@ ssh_session2_setup(int id, int success, void *arg)
check_agent_present();
if (options.forward_agent) {
debug("Requesting authentication agent forwarding.");
- channel_request_start(id, "auth-agent-req@openssh.com", 0);
+ channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
packet_send();
}
@@ -1737,13 +1745,13 @@ ssh_session2_setup(int id, int success, void *arg)
packet_set_interactive(interactive,
options.ip_qos_interactive, options.ip_qos_bulk);
- client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
+ client_session2_setup(ssh, id, tty_flag, subsystem_flag, getenv("TERM"),
NULL, fileno(stdin), &command, environ);
}
/* open new channel for a session */
static int
-ssh_session2_open(void)
+ssh_session2_open(struct ssh *ssh)
{
Channel *c;
int window, packetmax, in, out, err;
@@ -1773,34 +1781,34 @@ ssh_session2_open(void)
window >>= 1;
packetmax >>= 1;
}
- c = channel_new(
+ c = channel_new(ssh,
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
"client-session", /*nonblock*/0);
- debug3("ssh_session2_open: channel_new: %d", c->self);
+ debug3("%s: channel_new: %d", __func__, c->self);
- channel_send_open(c->self);
+ channel_send_open(ssh, c->self);
if (!no_shell_flag)
- channel_register_open_confirm(c->self,
+ channel_register_open_confirm(ssh, c->self,
ssh_session2_setup, NULL);
return c->self;
}
static int
-ssh_session2(void)
+ssh_session2(struct ssh *ssh)
{
int id = -1;
/* XXX should be pre-session */
if (!options.control_persist)
- ssh_init_stdio_forwarding();
- ssh_init_forwarding();
+ ssh_init_stdio_forwarding(ssh);
+ ssh_init_forwarding(ssh);
/* Start listening for multiplex clients */
if (!packet_get_mux())
- muxserver_listen();
+ muxserver_listen(ssh);
/*
* If we are in control persist mode and have a working mux listen
@@ -1828,10 +1836,10 @@ ssh_session2(void)
* stdio forward setup that we skipped earlier.
*/
if (options.control_persist && muxserver_sock == -1)
- ssh_init_stdio_forwarding();
+ ssh_init_stdio_forwarding(ssh);
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
- id = ssh_session2_open();
+ id = ssh_session2_open(ssh);
else {
packet_set_interactive(
options.control_master == SSHCTL_MASTER_NO,
@@ -1866,7 +1874,7 @@ ssh_session2(void)
fork_postauth();
}
- return client_loop(tty_flag, tty_flag ?
+ return client_loop(ssh, tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}
diff --git a/sshbuf.h b/sshbuf.h
index 1ac4b8c0..77f1e9e6 100644
--- a/sshbuf.h
+++ b/sshbuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshbuf.h,v 1.8 2016/11/25 23:22:04 djm Exp $ */
+/* $OpenBSD: sshbuf.h,v 1.9 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
@@ -211,6 +211,7 @@ int sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp,
/* Another variant: "peeks" into the buffer without modifying it */
int sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
size_t *lenp);
+/* XXX peek_u8 / peek_u32 */
/*
* Functions to extract or store SSH wire encoded bignums and elliptic
diff --git a/sshconnect.c b/sshconnect.c
index 2842d9e5..60856620 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.285 2017/09/03 23:33:13 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.286 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
@@ -105,7 +105,7 @@ expand_proxy_command(const char *proxy_command, const char *user,
* a connected fd back to us.
*/
static int
-ssh_proxy_fdpass_connect(const char *host, u_short port,
+ssh_proxy_fdpass_connect(struct ssh *ssh, const char *host, u_short port,
const char *proxy_command)
{
char *command_string;
@@ -176,7 +176,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
fatal("Couldn't wait for child: %s", strerror(errno));
/* Set the connection file descriptors. */
- packet_set_connection(sock, sock);
+ if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
+ return -1; /* ssh_packet_set_connection logs error */
return 0;
}
@@ -185,7 +186,8 @@ ssh_proxy_fdpass_connect(const char *host, u_short port,
* Connect to the given ssh server using a proxy command.
*/
static int
-ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
+ssh_proxy_connect(struct ssh *ssh, const char *host, u_short port,
+ const char *proxy_command)
{
char *command_string;
int pin[2], pout[2];
@@ -252,9 +254,9 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
free(command_string);
/* Set the connection file descriptors. */
- packet_set_connection(pout[0], pin[1]);
+ if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL)
+ return -1; /* ssh_packet_set_connection logs error */
- /* Indicate OK return */
return 0;
}
@@ -410,7 +412,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
* the daemon.
*/
static int
-ssh_connect_direct(const char *host, struct addrinfo *aitop,
+ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
struct sockaddr_storage *hostaddr, u_short port, int family,
int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
{
@@ -484,27 +486,31 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop,
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
/* Set the connection. */
- packet_set_connection(sock, sock);
+ if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
+ return -1; /* ssh_packet_set_connection logs error */
- return 0;
+ return 0;
}
int
-ssh_connect(const char *host, struct addrinfo *addrs,
+ssh_connect(struct ssh *ssh, const char *host, struct addrinfo *addrs,
struct sockaddr_storage *hostaddr, u_short port, int family,
int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
{
if (options.proxy_command == NULL) {
- return ssh_connect_direct(host, addrs, hostaddr, port, family,
- connection_attempts, timeout_ms, want_keepalive, needpriv);
+ return ssh_connect_direct(ssh, host, addrs, hostaddr, port,
+ family, connection_attempts, timeout_ms, want_keepalive,
+ needpriv);
} else if (strcmp(options.proxy_command, "-") == 0) {
- packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
- return 0; /* Always succeeds */
+ if ((ssh_packet_set_connection(ssh,
+ STDIN_FILENO, STDOUT_FILENO)) == NULL)
+ return -1; /* ssh_packet_set_connection logs error */
+ return 0;
} else if (options.proxy_use_fdpass) {
- return ssh_proxy_fdpass_connect(host, port,
+ return ssh_proxy_fdpass_connect(ssh, host, port,
options.proxy_command);
}
- return ssh_proxy_connect(host, port, options.proxy_command);
+ return ssh_proxy_connect(ssh, host, port, options.proxy_command);
}
static void
diff --git a/sshconnect.h b/sshconnect.h
index f4e73f7b..b5029e23 100644
--- a/sshconnect.h
+++ b/sshconnect.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.h,v 1.30 2017/05/30 08:52:19 markus Exp $ */
+/* $OpenBSD: sshconnect.h,v 1.31 2017/09/12 06:32:07 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -32,8 +32,10 @@ struct Sensitive {
};
struct addrinfo;
-int ssh_connect(const char *, struct addrinfo *, struct sockaddr_storage *,
- u_short, int, int, int *, int, int);
+struct ssh;
+
+int ssh_connect(struct ssh *, const char *, struct addrinfo *,
+ struct sockaddr_storage *, u_short, int, int, int *, int, int);
void ssh_kill_proxy_command(void);
void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short,
diff --git a/sshd.c b/sshd.c
index 1d19ce67..51a1aaf6 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.491 2017/07/01 13:50:45 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.492 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
@@ -1621,9 +1621,6 @@ main(int ac, char **av)
"enabled authentication methods");
}
- /* set default channel AF */
- channel_set_af(options.address_family);
-
/* Check that there are no remaining arguments. */
if (optind < ac) {
fprintf(stderr, "Extra argument %s.\n", av[optind]);
@@ -1955,8 +1952,14 @@ main(int ac, char **av)
packet_set_connection(sock_in, sock_out);
packet_set_server();
ssh = active_state; /* XXX */
+
check_ip_options(ssh);
+ /* Prepare the channels layer */
+ channel_init_channels(ssh);
+ channel_set_af(ssh, options.address_family);
+ process_permitopen(ssh, &options);
+
/* Set SO_KEEPALIVE if requested. */
if (options.tcp_keep_alive && packet_connection_is_on_socket() &&
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
@@ -2080,10 +2083,10 @@ main(int ac, char **av)
options.client_alive_count_max);
/* Try to send all our hostkeys to the client */
- notify_hostkeys(active_state);
+ notify_hostkeys(ssh);
/* Start session. */
- do_authenticated(authctxt);
+ do_authenticated(ssh, authctxt);
/* The connection has been terminated. */
packet_get_bytes(&ibytes, &obytes);
@@ -2211,8 +2214,10 @@ do_ssh2_kex(void)
void
cleanup_exit(int i)
{
+ struct ssh *ssh = active_state; /* XXX */
+
if (the_authctxt) {
- do_cleanup(the_authctxt);
+ do_cleanup(ssh, the_authctxt);
if (use_privsep && privsep_is_preauth &&
pmonitor != NULL && pmonitor->m_pid > 1) {
debug("Killing privsep child %d", pmonitor->m_pid);
diff --git a/ssherr.c b/ssherr.c
index 4bd5f59c..3c0009d6 100644
--- a/ssherr.c
+++ b/ssherr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssherr.c,v 1.6 2017/05/07 23:15:59 djm Exp $ */
+/* $OpenBSD: ssherr.c,v 1.7 2017/09/12 06:32:08 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
@@ -137,6 +137,8 @@ ssh_err(int n)
return "Protocol error";
case SSH_ERR_KEY_LENGTH:
return "Invalid key length";
+ case SSH_ERR_NUMBER_TOO_LARGE:
+ return "number is too large";
default:
return "unknown error";
}
diff --git a/ssherr.h b/ssherr.h
index a3078162..c0b59211 100644
--- a/ssherr.h
+++ b/ssherr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssherr.h,v 1.4 2017/05/07 23:15:59 djm Exp $ */
+/* $OpenBSD: ssherr.h,v 1.5 2017/09/12 06:32:08 djm Exp $ */
/*
* Copyright (c) 2011 Damien Miller
*
@@ -78,6 +78,7 @@
#define SSH_ERR_CONN_CORRUPT -54
#define SSH_ERR_PROTOCOL_ERROR -55
#define SSH_ERR_KEY_LENGTH -56
+#define SSH_ERR_NUMBER_TOO_LARGE -57
/* Translate a numeric error code to a human-readable error string */
const char *ssh_err(int n);