summaryrefslogtreecommitdiffstats
path: root/mux.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
committerDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
commit7acefbbcbeab725420ea07397ae35992f505f702 (patch)
treebfb07917715d425438dab987a47ccd7a8d7f118b /mux.c
parent6262d760e00714523633bd989d62e273a3dca99a (diff)
- millert@cvs.openbsd.org 2014/07/15 15:54:14
[PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c] [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h] [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c] [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c] [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c] [sshd_config.5 sshlogin.c] Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket. This is a reimplementation of the streamlocal patches by William Ahern from: http://www.25thandclement.com/~william/projects/streamlocal.html OK djm@ markus@
Diffstat (limited to 'mux.c')
-rw-r--r--mux.c203
1 files changed, 117 insertions, 86 deletions
diff --git a/mux.c b/mux.c
index 784e942b..5278ce4b 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.45 2014/04/28 03:09:18 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.46 2014/07/15 15:54:14 millert Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@@ -509,29 +509,33 @@ process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
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:
@@ -551,14 +555,18 @@ compare_host(const char *a, const char *b)
}
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;
@@ -570,7 +578,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
- Forward *rfwd;
+ struct Forward *rfwd;
Channel *c;
Buffer out;
@@ -587,7 +595,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
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();
@@ -607,8 +616,12 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
} else {
if (rfwd->listen_port == 0)
channel_update_permitted_opens(rfwd->handle, -1);
- xasprintf(&failmsg, "remote port forwarding failed for "
- "listen port %d", rfwd->listen_port);
+ 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);
@@ -627,34 +640,46 @@ 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)
{
- 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 ||
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&lport, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cport, m) != 0 ||
- lport > 65535 || cport > 65535) {
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
- fwd.listen_port = lport;
- fwd.connect_port = cport;
- if (*fwd.listen_host == '\0') {
- free(fwd.listen_host);
- fwd.listen_host = NULL;
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
}
- if (*fwd.connect_host == '\0') {
- free(fwd.connect_host);
- fwd.connect_host = NULL;
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = 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)));
@@ -662,25 +687,30 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
ftype != MUX_FWD_DYNAMIC) {
logit("%s: invalid forwarding type %u", __func__, ftype);
invalid:
- free(fwd.listen_host);
- free(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;
}
@@ -731,9 +761,8 @@ 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.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port,
- options.gateway_ports)) {
+ 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);
@@ -746,8 +775,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.listen_host,
- fwd.listen_port, fwd.connect_host, fwd.connect_port);
+ fwd.handle = channel_request_remote_forwarding(&fwd);
if (fwd.handle < 0)
goto fail;
add_remote_forward(&options, &fwd);
@@ -768,7 +796,9 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
free(fwd_desc);
if (freefwd) {
free(fwd.listen_host);
+ free(fwd.listen_path);
free(fwd.connect_host);
+ free(fwd.connect_path);
}
return ret;
}
@@ -776,36 +806,47 @@ 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)
{
- Forward fwd, *found_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 i, listen_port, 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 ||
+ (listen_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&lport, m) != 0 ||
- (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+ (connect_addr = buffer_get_string_ret(m, NULL)) == NULL ||
buffer_get_int_ret(&cport, m) != 0 ||
- lport > 65535 || cport > 65535) {
+ (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) ||
+ (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) {
error("%s: malformed message", __func__);
ret = -1;
goto out;
}
- fwd.listen_port = lport;
- fwd.connect_port = cport;
- if (*fwd.listen_host == '\0') {
- free(fwd.listen_host);
- fwd.listen_host = NULL;
+ if (*listen_addr == '\0') {
+ free(listen_addr);
+ listen_addr = NULL;
}
- if (*fwd.connect_host == '\0') {
- free(fwd.connect_host);
- fwd.connect_host = NULL;
+ if (*connect_addr == '\0') {
+ free(connect_addr);
+ connect_addr = 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 cancel %s", __func__, c->self,
(fwd_desc = format_forward(ftype, &fwd)));
@@ -840,18 +881,14 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
* 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 lookup the actual listen port.
+ * to use the actual listen port.
*/
- listen_port = (fwd.listen_port == 0) ?
- found_fwd->allocated_port : fwd.listen_port;
- if (channel_request_rforward_cancel(fwd.listen_host,
- listen_port) == -1)
+ 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.listen_host,
- fwd.listen_port, fwd.connect_port,
- options.gateway_ports) == -1)
+ if (channel_cancel_lport_listener(&fwd, fwd.connect_port,
+ &options.fwd_opts) == -1)
error_reason = "port not found";
}
@@ -860,8 +897,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
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);
@@ -870,8 +910,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
}
out:
free(fwd_desc);
- free(fwd.listen_host);
- free(fwd.connect_host);
+ free(listen_addr);
+ free(connect_addr);
return ret;
}
@@ -1133,8 +1173,6 @@ mux_tty_alloc_failed(Channel *c)
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];
@@ -1163,23 +1201,10 @@ muxserver_listen(void)
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) {
+ muxserver_sock = unix_listener(options.control_path, 64, 0);
+ umask(old_umask);
+ if (muxserver_sock < 0) {
if (errno == EINVAL || errno == EADDRINUSE) {
error("ControlSocket %s already exists, "
"disabling multiplexing", options.control_path);
@@ -1193,13 +1218,11 @@ muxserver_listen(void)
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) {
@@ -1593,7 +1616,7 @@ mux_client_request_terminate(int fd)
}
static int
-mux_client_forward(int fd, int cancel_flag, 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;
@@ -1608,11 +1631,19 @@ mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *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);
+ }
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)