external/openssh: update to 6.8p1.
In preparation for some updates to external/openssh to make it work with
BoringSSL, this change updates the code to a recent version. The current
version (5.9p1) is coming up on four years old now.
* Confirmed that f5c67b478bef9992de9e9ec91ce10af4f6205e0d matches
OpenSSH 5.9p1 exactly (save for the removal of the scard
subdirectory).
* Downloaded openssh-6.8p1.tar.gz (SHA256:
3ff64ce73ee124480b5bf767b9830d7d3c03bbcb6abe716b78f0192c37ce160e)
and verified with PGP signature. (I've verified Damien's key in
person previously.)
* Applied changes between f5c67b478bef9992de9e9ec91ce10af4f6205e0d and
OpenSSH 5.9p1 to 6.8p1 and updated the build as best I can. The
ugliest change is probably the duplication of umac.c to umac128.c
because Android conditionally compiles that file twice. See the
comment in those files.
Change-Id: I63cb07a8118afb5a377f116087a0882914cea486
diff --git a/mux.c b/mux.c
index add0e26..f3faaee 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.29 2011/06/22 22:08:42 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.50 2015/01/20 23:14:00 deraadt Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@@ -33,7 +33,6 @@
#include "includes.h"
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -63,10 +62,6 @@
# include <util.h>
#endif
-#ifdef HAVE_LIBUTIL_H
-# include <libutil.h>
-#endif
-
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "log.h"
@@ -109,6 +104,11 @@
u_int rid;
};
+/* Context for stdio fwd open confirmation callback */
+struct mux_stdio_confirm_ctx {
+ u_int rid;
+};
+
/* Context for global channel callback */
struct mux_channel_confirm_ctx {
u_int cid; /* channel id */
@@ -161,6 +161,7 @@
#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 *);
@@ -223,7 +224,8 @@
__func__, c->self, c->remote_id);
c->remote_id = -1;
sc->ctl_chan = -1;
- if (sc->type != SSH_CHANNEL_OPEN) {
+ if (sc->type != SSH_CHANNEL_OPEN &&
+ sc->type != SSH_CHANNEL_OPENING) {
debug2("%s: channel %d: not open", __func__, sc->self);
chan_mark_dead(sc);
} else {
@@ -290,13 +292,13 @@
char *value = buffer_get_string_ret(m, NULL);
if (name == NULL || value == NULL) {
- if (name != NULL)
- xfree(name);
+ free(name);
+ free(value);
goto malf;
}
debug2("Unrecognised slave extension \"%s\"", name);
- xfree(name);
- xfree(value);
+ free(name);
+ free(value);
}
state->hello_rcvd = 1;
return 0;
@@ -316,6 +318,8 @@
cctx->term = NULL;
cctx->rid = rid;
cmd = reserved = NULL;
+ cctx->env = NULL;
+ env_len = 0;
if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 ||
@@ -325,28 +329,25 @@
(cctx->term = buffer_get_string_ret(m, &len)) == NULL ||
(cmd = buffer_get_string_ret(m, &len)) == NULL) {
malf:
- if (cmd != NULL)
- xfree(cmd);
- if (reserved != NULL)
- xfree(reserved);
- if (cctx->term != NULL)
- xfree(cctx->term);
+ free(cmd);
+ free(reserved);
+ for (j = 0; j < env_len; j++)
+ free(cctx->env[j]);
+ free(cctx->env);
+ free(cctx->term);
+ free(cctx);
error("%s: malformed message", __func__);
return -1;
}
- xfree(reserved);
+ free(reserved);
reserved = NULL;
- cctx->env = NULL;
- env_len = 0;
while (buffer_len(m) > 0) {
#define MUX_MAX_ENV_VARS 4096
- if ((cp = buffer_get_string_ret(m, &len)) == NULL) {
- xfree(cmd);
+ if ((cp = buffer_get_string_ret(m, &len)) == NULL)
goto malf;
- }
if (!env_permitted(cp)) {
- xfree(cp);
+ free(cp);
continue;
}
cctx->env = xrealloc(cctx->env, env_len + 2,
@@ -367,7 +368,7 @@
buffer_init(&cctx->cmd);
buffer_append(&cctx->cmd, cmd, strlen(cmd));
- xfree(cmd);
+ free(cmd);
cmd = NULL;
/* Gather fds from client */
@@ -378,12 +379,11 @@
for (j = 0; j < i; j++)
close(new_fd[j]);
for (j = 0; j < env_len; j++)
- xfree(cctx->env[j]);
- if (env_len > 0)
- xfree(cctx->env);
- xfree(cctx->term);
+ free(cctx->env[j]);
+ free(cctx->env);
+ free(cctx->term);
buffer_free(&cctx->cmd);
- xfree(cctx);
+ free(cctx);
/* prepare reply */
buffer_put_int(r, MUX_S_FAILURE);
@@ -408,13 +408,14 @@
close(new_fd[0]);
close(new_fd[1]);
close(new_fd[2]);
- xfree(cctx->term);
+ free(cctx->term);
if (env_len != 0) {
for (i = 0; i < env_len; i++)
- xfree(cctx->env[i]);
- xfree(cctx->env);
+ free(cctx->env[i]);
+ free(cctx->env);
}
buffer_free(&cctx->cmd);
+ free(cctx);
return 0;
}
@@ -513,29 +514,33 @@
}
static char *
-format_forward(u_int ftype, Forward *fwd)
+format_forward(u_int ftype, struct Forward *fwd)
{
char *ret;
switch (ftype) {
case MUX_FWD_LOCAL:
xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
+ (fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
- (options.gateway_ports ? "*" : "LOCALHOST") :
+ (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
fwd->listen_host, fwd->listen_port,
+ (fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
case MUX_FWD_DYNAMIC:
xasprintf(&ret, "dynamic forward %.200s:%d -> *",
(fwd->listen_host == NULL) ?
- (options.gateway_ports ? "*" : "LOCALHOST") :
+ (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
fwd->listen_host, fwd->listen_port);
break;
case MUX_FWD_REMOTE:
xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
+ (fwd->listen_path != NULL) ? fwd->listen_path :
(fwd->listen_host == NULL) ?
"LOCALHOST" : fwd->listen_host,
fwd->listen_port,
+ (fwd->connect_path != NULL) ? fwd->connect_path :
fwd->connect_host, fwd->connect_port);
break;
default:
@@ -555,14 +560,18 @@
}
static int
-compare_forward(Forward *a, Forward *b)
+compare_forward(struct Forward *a, struct Forward *b)
{
if (!compare_host(a->listen_host, b->listen_host))
return 0;
+ if (!compare_host(a->listen_path, b->listen_path))
+ return 0;
if (a->listen_port != b->listen_port)
return 0;
if (!compare_host(a->connect_host, b->connect_host))
return 0;
+ if (!compare_host(a->connect_path, b->connect_path))
+ return 0;
if (a->connect_port != b->connect_port)
return 0;
@@ -574,7 +583,7 @@
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
- Forward *rfwd;
+ struct Forward *rfwd;
Channel *c;
Buffer out;
@@ -591,7 +600,8 @@
rfwd = &options.remote_forwards[fctx->fid];
debug("%s: %s for: listen %d, connect %s:%d", __func__,
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
- rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+ rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
+ rfwd->connect_host, rfwd->connect_port);
if (type == SSH2_MSG_REQUEST_SUCCESS) {
if (rfwd->listen_port == 0) {
rfwd->allocated_port = packet_get_int();
@@ -601,21 +611,29 @@
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,
+ rfwd->allocated_port);
} else {
buffer_put_int(&out, MUX_S_OK);
buffer_put_int(&out, fctx->rid);
}
goto out;
} else {
- xasprintf(&failmsg, "remote port forwarding failed for "
- "listen port %d", rfwd->listen_port);
+ if (rfwd->listen_port == 0)
+ channel_update_permitted_opens(rfwd->handle, -1);
+ if (rfwd->listen_path != NULL)
+ xasprintf(&failmsg, "remote port forwarding failed for "
+ "listen path %s", rfwd->listen_path);
+ else
+ xasprintf(&failmsg, "remote port forwarding failed for "
+ "listen port %d", rfwd->listen_port);
}
fail:
error("%s: %s", __func__, failmsg);
buffer_put_int(&out, MUX_S_FAILURE);
buffer_put_int(&out, fctx->rid);
buffer_put_cstring(&out, failmsg);
- xfree(failmsg);
+ free(failmsg);
out:
buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
buffer_free(&out);
@@ -627,30 +645,45 @@
static int
process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
- Forward fwd;
+ struct Forward fwd;
char *fwd_desc = NULL;
+ char *listen_addr, *connect_addr;
u_int ftype;
+ u_int lport, cport;
int i, ret = 0, freefwd = 1;
- fwd.listen_host = fwd.connect_host = NULL;
+ /* XXX - lport/cport check redundant */
if (buffer_get_int_ret(&ftype, m) != 0 ||
- (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
- buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
- buffer_get_int_ret(&fwd.connect_port, m) != 0) {
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
+ buffer_get_int_ret(&lport, m) != 0 ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
+ buffer_get_int_ret(&cport, m) != 0 ||
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
+ }
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = NULL;
+ }
- if (*fwd.listen_host == '\0') {
- xfree(fwd.listen_host);
- fwd.listen_host = NULL;
- }
- if (*fwd.connect_host == '\0') {
- xfree(fwd.connect_host);
- fwd.connect_host = NULL;
- }
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_port = lport;
+ if (fwd.listen_port == PORT_STREAMLOCAL)
+ fwd.listen_path = listen_addr;
+ else
+ fwd.listen_host = listen_addr;
+ fwd.connect_port = cport;
+ if (fwd.connect_port == PORT_STREAMLOCAL)
+ fwd.connect_path = connect_addr;
+ else
+ fwd.connect_host = connect_addr;
debug2("%s: channel %d: request %s", __func__, c->self,
(fwd_desc = format_forward(ftype, &fwd)));
@@ -659,27 +692,30 @@
ftype != MUX_FWD_DYNAMIC) {
logit("%s: invalid forwarding type %u", __func__, ftype);
invalid:
- if (fwd.listen_host)
- xfree(fwd.listen_host);
- if (fwd.connect_host)
- xfree(fwd.connect_host);
+ free(listen_addr);
+ free(connect_addr);
buffer_put_int(r, MUX_S_FAILURE);
buffer_put_int(r, rid);
buffer_put_cstring(r, "Invalid forwarding request");
return 0;
}
- if (fwd.listen_port >= 65536) {
+ if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) {
+ logit("%s: streamlocal and dynamic forwards "
+ "are mutually exclusive", __func__);
+ goto invalid;
+ }
+ if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) {
logit("%s: invalid listen port %u", __func__,
fwd.listen_port);
goto invalid;
}
- if (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) {
+ if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) {
logit("%s: missing connect host", __func__);
goto invalid;
}
@@ -730,9 +766,8 @@
}
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
- if (channel_setup_local_fwd_listener(fwd.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port,
- options.gateway_ports) < 0) {
+ if (!channel_setup_local_fwd_listener(&fwd,
+ &options.fwd_opts)) {
fail:
logit("slave-requested %s failed", fwd_desc);
buffer_put_int(r, MUX_S_FAILURE);
@@ -745,8 +780,8 @@
} else {
struct mux_channel_confirm_ctx *fctx;
- if (channel_request_remote_forwarding(fwd.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0)
+ fwd.handle = channel_request_remote_forwarding(&fwd);
+ if (fwd.handle < 0)
goto fail;
add_remote_forward(&options, &fwd);
fctx = xcalloc(1, sizeof(*fctx));
@@ -763,13 +798,12 @@
buffer_put_int(r, MUX_S_OK);
buffer_put_int(r, rid);
out:
- if (fwd_desc != NULL)
- xfree(fwd_desc);
+ free(fwd_desc);
if (freefwd) {
- if (fwd.listen_host != NULL)
- xfree(fwd.listen_host);
- if (fwd.connect_host != NULL)
- xfree(fwd.connect_host);
+ free(fwd.listen_host);
+ free(fwd.listen_path);
+ free(fwd.connect_host);
+ free(fwd.connect_path);
}
return ret;
}
@@ -777,46 +811,112 @@
static int
process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
- Forward fwd;
+ struct Forward fwd, *found_fwd;
char *fwd_desc = NULL;
+ const char *error_reason = NULL;
+ char *listen_addr = NULL, *connect_addr = NULL;
u_int ftype;
- int ret = 0;
+ int i, ret = 0;
+ u_int lport, cport;
- fwd.listen_host = fwd.connect_host = NULL;
if (buffer_get_int_ret(&ftype, m) != 0 ||
- (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
- buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
- buffer_get_int_ret(&fwd.connect_port, m) != 0) {
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
+ buffer_get_int_ret(&lport, m) != 0 ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
+ buffer_get_int_ret(&cport, m) != 0 ||
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
- if (*fwd.listen_host == '\0') {
- xfree(fwd.listen_host);
- fwd.listen_host = NULL;
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
}
- if (*fwd.connect_host == '\0') {
- xfree(fwd.connect_host);
- fwd.connect_host = NULL;
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = NULL;
}
- debug2("%s: channel %d: request %s", __func__, c->self,
+ memset(&fwd, 0, sizeof(fwd));
+ fwd.listen_port = lport;
+ if (fwd.listen_port == PORT_STREAMLOCAL)
+ fwd.listen_path = listen_addr;
+ else
+ fwd.listen_host = listen_addr;
+ fwd.connect_port = cport;
+ if (fwd.connect_port == PORT_STREAMLOCAL)
+ fwd.connect_path = connect_addr;
+ else
+ fwd.connect_host = connect_addr;
+
+ debug2("%s: channel %d: request cancel %s", __func__, c->self,
(fwd_desc = format_forward(ftype, &fwd)));
- /* XXX implement this */
- buffer_put_int(r, MUX_S_FAILURE);
- buffer_put_int(r, rid);
- buffer_put_cstring(r, "unimplemented");
+ /* make sure this has been requested */
+ found_fwd = NULL;
+ switch (ftype) {
+ case MUX_FWD_LOCAL:
+ case MUX_FWD_DYNAMIC:
+ for (i = 0; i < options.num_local_forwards; i++) {
+ if (compare_forward(&fwd,
+ options.local_forwards + i)) {
+ found_fwd = options.local_forwards + i;
+ break;
+ }
+ }
+ break;
+ case MUX_FWD_REMOTE:
+ for (i = 0; i < options.num_remote_forwards; i++) {
+ if (compare_forward(&fwd,
+ options.remote_forwards + i)) {
+ found_fwd = options.remote_forwards + i;
+ break;
+ }
+ }
+ break;
+ }
+ if (found_fwd == NULL)
+ error_reason = "port not forwarded";
+ else if (ftype == MUX_FWD_REMOTE) {
+ /*
+ * This shouldn't fail unless we confused the host/port
+ * between options.remote_forwards and permitted_opens.
+ * However, for dynamic allocated listen ports we need
+ * to use the actual listen port.
+ */
+ if (channel_request_rforward_cancel(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,
+ &options.fwd_opts) == -1)
+ error_reason = "port not found";
+ }
+
+ if (error_reason == NULL) {
+ buffer_put_int(r, MUX_S_OK);
+ buffer_put_int(r, rid);
+
+ free(found_fwd->listen_host);
+ free(found_fwd->listen_path);
+ free(found_fwd->connect_host);
+ free(found_fwd->connect_path);
+ found_fwd->listen_host = found_fwd->connect_host = NULL;
+ found_fwd->listen_path = found_fwd->connect_path = NULL;
+ found_fwd->listen_port = found_fwd->connect_port = 0;
+ } else {
+ buffer_put_int(r, MUX_S_FAILURE);
+ buffer_put_int(r, rid);
+ buffer_put_cstring(r, error_reason);
+ }
out:
- if (fwd_desc != NULL)
- xfree(fwd_desc);
- if (fwd.listen_host != NULL)
- xfree(fwd.listen_host);
- if (fwd.connect_host != NULL)
- xfree(fwd.connect_host);
+ free(fwd_desc);
+ free(listen_addr);
+ free(connect_addr);
return ret;
}
@@ -828,19 +928,18 @@
char *reserved, *chost;
u_int cport, i, j;
int new_fd[2];
+ struct mux_stdio_confirm_ctx *cctx;
chost = reserved = NULL;
if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
(chost = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cport, m) != 0) {
- if (reserved != NULL)
- xfree(reserved);
- if (chost != NULL)
- xfree(chost);
+ free(reserved);
+ free(chost);
error("%s: malformed message", __func__);
return -1;
}
- xfree(reserved);
+ free(reserved);
debug2("%s: channel %d: request stdio fwd to %s:%u",
__func__, c->self, chost, cport);
@@ -852,7 +951,7 @@
__func__, i);
for (j = 0; j < i; j++)
close(new_fd[j]);
- xfree(chost);
+ free(chost);
/* prepare reply */
buffer_put_int(r, MUX_S_FAILURE);
@@ -876,7 +975,7 @@
cleanup:
close(new_fd[0]);
close(new_fd[1]);
- xfree(chost);
+ free(chost);
return 0;
}
@@ -909,15 +1008,60 @@
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
- /* prepare reply */
- /* XXX defer until channel confirmed */
- buffer_put_int(r, MUX_S_SESSION_OPENED);
- buffer_put_int(r, rid);
- buffer_put_int(r, nc->self);
+ cctx = xcalloc(1, sizeof(*cctx));
+ cctx->rid = rid;
+ channel_register_open_confirm(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 */
return 0;
}
+/* Callback on open confirmation in mux master for a mux stdio fwd session. */
+static void
+mux_stdio_confirm(int id, int success, void *arg)
+{
+ struct mux_stdio_confirm_ctx *cctx = arg;
+ Channel *c, *cc;
+ Buffer reply;
+
+ if (cctx == NULL)
+ fatal("%s: cctx == NULL", __func__);
+ if ((c = channel_by_id(id)) == NULL)
+ fatal("%s: no channel for id %d", __func__, id);
+ if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+ fatal("%s: channel %d lacks control channel %d", __func__,
+ id, c->ctl_chan);
+
+ if (!success) {
+ debug3("%s: sending failure reply", __func__);
+ /* prepare reply */
+ buffer_init(&reply);
+ buffer_put_int(&reply, MUX_S_FAILURE);
+ buffer_put_int(&reply, cctx->rid);
+ buffer_put_cstring(&reply, "Session open refused by peer");
+ goto done;
+ }
+
+ debug3("%s: sending success reply", __func__);
+ /* prepare reply */
+ buffer_init(&reply);
+ buffer_put_int(&reply, MUX_S_SESSION_OPENED);
+ buffer_put_int(&reply, cctx->rid);
+ buffer_put_int(&reply, c->self);
+
+ done:
+ /* Send reply */
+ buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
+ buffer_free(&reply);
+
+ if (cc->mux_pause <= 0)
+ fatal("%s: mux_pause %d", __func__, cc->mux_pause);
+ cc->mux_pause = 0; /* start processing messages again */
+ c->open_confirm_ctx = NULL;
+ free(cctx);
+}
+
static int
process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
@@ -938,7 +1082,7 @@
if (mux_listener_channel != NULL) {
channel_free(mux_listener_channel);
client_stop_mux();
- xfree(options.control_path);
+ free(options.control_path);
options.control_path = NULL;
mux_listener_channel = NULL;
muxserver_sock = -1;
@@ -957,7 +1101,7 @@
{
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
Buffer in, out;
- void *ptr;
+ const u_char *ptr;
u_int type, rid, have, i;
int ret = -1;
@@ -1038,7 +1182,7 @@
Buffer m;
Channel *mux_chan;
- debug3("%s: channel %d: exit message, evitval %d", __func__, c->self,
+ debug3("%s: channel %d: exit message, exitval %d", __func__, c->self,
exitval);
if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
@@ -1080,12 +1224,11 @@
void
muxserver_listen(void)
{
- struct sockaddr_un addr;
- socklen_t sun_len;
mode_t old_umask;
char *orig_control_path = options.control_path;
char rbuf[16+1];
u_int i, r;
+ int oerrno;
if (options.control_path == NULL ||
options.control_master == SSHCTL_MASTER_NO)
@@ -1110,24 +1253,12 @@
xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
debug3("%s: temporary control path %s", __func__, options.control_path);
- memset(&addr, '\0', sizeof(addr));
- addr.sun_family = AF_UNIX;
- sun_len = offsetof(struct sockaddr_un, sun_path) +
- strlen(options.control_path) + 1;
-
- if (strlcpy(addr.sun_path, options.control_path,
- sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) {
- error("ControlPath \"%s\" too long for Unix domain socket",
- options.control_path);
- goto disable_mux_master;
- }
-
- if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
- fatal("%s socket(): %s", __func__, strerror(errno));
-
old_umask = umask(0177);
- if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
- if (errno == EINVAL || errno == EADDRINUSE) {
+ muxserver_sock = unix_listener(options.control_path, 64, 0);
+ oerrno = errno;
+ umask(old_umask);
+ if (muxserver_sock < 0) {
+ if (oerrno == EINVAL || oerrno == EADDRINUSE) {
error("ControlSocket %s already exists, "
"disabling multiplexing", options.control_path);
disable_mux_master:
@@ -1135,17 +1266,16 @@
close(muxserver_sock);
muxserver_sock = -1;
}
- xfree(options.control_path);
+ free(orig_control_path);
+ free(options.control_path);
options.control_path = NULL;
options.control_master = SSHCTL_MASTER_NO;
return;
- } else
- fatal("%s bind(): %s", __func__, strerror(errno));
+ } else {
+ /* unix_listener() logs the error */
+ cleanup_exit(255);
+ }
}
- umask(old_umask);
-
- if (listen(muxserver_sock, 64) == -1)
- fatal("%s listen(): %s", __func__, strerror(errno));
/* Now atomically "move" the mux socket into position */
if (link(options.control_path, orig_control_path) != 0) {
@@ -1156,12 +1286,11 @@
}
error("ControlSocket %s already exists, disabling multiplexing",
orig_control_path);
- xfree(orig_control_path);
unlink(options.control_path);
goto disable_mux_master;
}
unlink(options.control_path);
- xfree(options.control_path);
+ free(options.control_path);
options.control_path = orig_control_path;
set_nonblock(muxserver_sock);
@@ -1246,13 +1375,13 @@
cc->mux_pause = 0; /* start processing messages again */
c->open_confirm_ctx = NULL;
buffer_free(&cctx->cmd);
- xfree(cctx->term);
+ free(cctx->term);
if (cctx->env != NULL) {
for (i = 0; cctx->env[i] != NULL; i++)
- xfree(cctx->env[i]);
- xfree(cctx->env);
+ free(cctx->env[i]);
+ free(cctx->env);
}
- xfree(cctx);
+ free(cctx);
}
/* ** Multiplexing client support */
@@ -1376,13 +1505,15 @@
{
Buffer queue;
u_int need, have;
- void *ptr;
+ const u_char *ptr;
int oerrno;
buffer_init(&queue);
if (mux_client_read(fd, &queue, 4) != 0) {
if ((oerrno = errno) == EPIPE)
- debug3("%s: read header failed: %s", __func__, strerror(errno));
+ debug3("%s: read header failed: %s", __func__,
+ strerror(errno));
+ buffer_free(&queue);
errno = oerrno;
return -1;
}
@@ -1390,6 +1521,7 @@
if (mux_client_read(fd, &queue, need) != 0) {
oerrno = errno;
debug3("%s: read body failed: %s", __func__, strerror(errno));
+ buffer_free(&queue);
errno = oerrno;
return -1;
}
@@ -1436,8 +1568,8 @@
char *value = buffer_get_string(&m, NULL);
debug2("Unrecognised master extension \"%s\"", name);
- xfree(name);
- xfree(value);
+ free(name);
+ free(value);
}
buffer_free(&m);
return 0;
@@ -1537,25 +1669,35 @@
}
static int
-mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
+mux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd)
{
Buffer m;
char *e, *fwd_desc;
u_int type, rid;
fwd_desc = format_forward(ftype, fwd);
- debug("Requesting %s", fwd_desc);
- xfree(fwd_desc);
+ debug("Requesting %s %s",
+ cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
+ free(fwd_desc);
buffer_init(&m);
- buffer_put_int(&m, MUX_C_OPEN_FWD);
+ buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
buffer_put_int(&m, muxclient_request_id);
buffer_put_int(&m, ftype);
- buffer_put_cstring(&m,
- fwd->listen_host == NULL ? "" : fwd->listen_host);
+ if (fwd->listen_path != NULL) {
+ buffer_put_cstring(&m, fwd->listen_path);
+ } else {
+ buffer_put_cstring(&m,
+ fwd->listen_host == NULL ? "" :
+ (*fwd->listen_host == '\0' ? "*" : fwd->listen_host));
+ }
buffer_put_int(&m, fwd->listen_port);
- buffer_put_cstring(&m,
- fwd->connect_host == NULL ? "" : fwd->connect_host);
+ if (fwd->connect_path != NULL) {
+ buffer_put_cstring(&m, fwd->connect_path);
+ } else {
+ buffer_put_cstring(&m,
+ fwd->connect_host == NULL ? "" : fwd->connect_host);
+ }
buffer_put_int(&m, fwd->connect_port);
if (mux_client_write_packet(fd, &m) != 0)
@@ -1577,6 +1719,8 @@
case MUX_S_OK:
break;
case MUX_S_REMOTE_PORT:
+ if (cancel_flag)
+ fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
fwd->allocated_port = buffer_get_int(&m);
logit("Allocated port %u for remote forward to %s:%d",
fwd->allocated_port,
@@ -1606,27 +1750,28 @@
}
static int
-mux_client_request_forwards(int fd)
+mux_client_forwards(int fd, int cancel_flag)
{
- int i;
+ int i, ret = 0;
- debug3("%s: requesting forwardings: %d local, %d remote", __func__,
+ debug3("%s: %s forwardings: %d local, %d remote", __func__,
+ cancel_flag ? "cancel" : "request",
options.num_local_forwards, options.num_remote_forwards);
/* XXX ExitOnForwardingFailure */
for (i = 0; i < options.num_local_forwards; i++) {
- if (mux_client_request_forward(fd,
+ if (mux_client_forward(fd, cancel_flag,
options.local_forwards[i].connect_port == 0 ?
MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
options.local_forwards + i) != 0)
- return -1;
+ ret = -1;
}
for (i = 0; i < options.num_remote_forwards; i++) {
- if (mux_client_request_forward(fd, MUX_FWD_REMOTE,
+ if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
options.remote_forwards + i) != 0)
- return -1;
+ ret = -1;
}
- return 0;
+ return ret;
}
static int
@@ -1862,7 +2007,7 @@
case MUX_S_FAILURE:
e = buffer_get_string(&m, NULL);
buffer_free(&m);
- fatal("%s: stdio forwarding request failed: %s", __func__, e);
+ fatal("Stdio forwarding request failed: %s", e);
default:
buffer_free(&m);
error("%s: unexpected response from master 0x%08x",
@@ -2014,11 +2159,11 @@
fprintf(stderr, "Exit request sent.\r\n");
exit(0);
case SSHMUX_COMMAND_FORWARD:
- if (mux_client_request_forwards(sock) != 0)
+ if (mux_client_forwards(sock, 0) != 0)
fatal("%s: master forward request failed", __func__);
exit(0);
case SSHMUX_COMMAND_OPEN:
- if (mux_client_request_forwards(sock) != 0) {
+ if (mux_client_forwards(sock, 0) != 0) {
error("%s: master forward request failed", __func__);
return;
}
@@ -2031,6 +2176,11 @@
mux_client_request_stop_listening(sock);
fprintf(stderr, "Stop listening request sent.\r\n");
exit(0);
+ case SSHMUX_COMMAND_CANCEL_FWD:
+ if (mux_client_forwards(sock, 1) != 0)
+ error("%s: master cancel forward request failed",
+ __func__);
+ exit(0);
default:
fatal("unrecognised muxclient_command %d", muxclient_command);
}