diff -Naur openssh-4.7p1.orig/canohost.c openssh-4.7p1-streamlocal/canohost.c
--- openssh-4.7p1.orig/canohost.c	2006-09-22 12:22:18.000000000 +0300
+++ openssh-4.7p1-streamlocal/canohost.c	2009-08-29 18:28:30.000000000 +0300
@@ -261,6 +261,15 @@
 			return NULL;
 	}
 
+	/*
+	 * Do not pass anything we cannot expect getnameinfo() to parse,
+	 * e.g. AF_UNIX. We cannot be explicit about the AF_UNIX case
+	 * because getpeername() is not guaranteed to give us detailed
+	 * information on a remote socket (e.g. for the AF_UNIX case).
+	 */
+	if (addrlen == 0 || (addr.ss_family != AF_INET && addr.ss_family != AF_INET6))
+		return NULL;
+
 	/* Work around Linux IPv6 weirdness */
 	if (addr.ss_family == AF_INET6)
 		addrlen = sizeof(struct sockaddr_in6);
@@ -364,6 +373,15 @@
 		}
 	}
 
+	/*
+	 * Do not pass anything we cannot expect getnameinfo() to parse,
+	 * e.g. AF_UNIX. We cannot be explicit about the AF_UNIX case
+	 * because getpeername() is not guaranteed to give us detailed
+	 * information on a remote socket (e.g. for the AF_UNIX case).
+	 */
+	if (fromlen == 0 || (from.ss_family != AF_INET && from.ss_family != AF_INET6))
+		return 0;
+
 	/* Work around Linux IPv6 weirdness */
 	if (from.ss_family == AF_INET6)
 		fromlen = sizeof(struct sockaddr_in6);
diff -Naur openssh-4.7p1.orig/channels.c openssh-4.7p1-streamlocal/channels.c
--- openssh-4.7p1.orig/channels.c	2007-06-25 12:04:47.000000000 +0300
+++ openssh-4.7p1-streamlocal/channels.c	2009-08-29 18:33:19.000000000 +0300
@@ -75,6 +75,10 @@
 #include "key.h"
 #include "authfd.h"
 #include "pathnames.h"
+#include "readconf.h"
+#include "servconf.h"
+
+#define FORWARD_PERMISSIONS_FIXED 1
 
 /* -- channel core */
 
@@ -96,6 +100,21 @@
  */
 static int channel_max_fd = 0;
 
+/* -- socket naming */
+
+const SocketName socketname_initializer = {
+	NULL,	/* .host */
+	0,	/* .port */
+	NULL,	/* .path */
+};
+
+/* -- forward options */
+
+static const ForwardOptions forward_options_initializer = {
+	0,	/* .tcpip_gateway_ports */
+	0177,	/* .streamlocal_bind_mask */
+	0,	/* .streamlocal_bind_unlink */
+};
 
 /* -- tcp forwarding */
 
@@ -106,9 +125,14 @@
  * network (which might be behind a firewall).
  */
 typedef struct {
+#if FORWARD_PERMISSIONS_FIXED
+	SocketName connect_addr;
+	SocketName listen_addr;
+#else
 	char *host_to_connect;		/* Connect to 'host'. */
 	u_short port_to_connect;	/* Connect to 'port'. */
 	u_short listen_port;		/* Remote side should listen port number. */
+#endif
 } ForwardPermission;
 
 /* List of all permitted host/port pairs to connect by the user. */
@@ -164,6 +188,76 @@
 /* helper */
 static void port_open_helper(Channel *c, char *rtype);
 
+/* -- socket naming */
+
+const char *
+socketname_tostring(const SocketName *n)
+{
+	static char bufs[3][32 + SSH_CHANNEL_PATH_LEN];
+	static const int nbufs = sizeof(bufs) / sizeof(bufs[0]);
+	static struct { char *next, *this; } buf;
+	static const size_t bufsz = sizeof bufs[0];
+
+	/*
+	 * Implement a simple ring buffer. Definitely not async-safe, but
+	 * useful when converting multiple socketnames for a printf without
+	 * having to bother with dynamic allocation.
+	 */ 
+	if (buf.next == NULL || buf.next > &bufs[nbufs - 1][0])
+		buf.next = &bufs[0][0];
+	buf.this = buf.next;
+	buf.next += bufsz;
+
+	if (SOCKETNAME_IS_STREAMLOCAL(n)) {
+		snprintf(buf.this, bufsz, "unix:%s", n->path);
+	} else {
+		snprintf(buf.this, bufsz, "tcpip:[%s]:%d",
+		    (n->host)? n->host : "LOCALHOST", n->port);
+	}
+
+	return buf.this;
+}
+
+int
+socketname_eq(const SocketName *n1, const SocketName *n2)
+{
+	if (n1->port != n2->port) {
+		return 0;
+	} else if (n1->path != NULL || n2->path != NULL) {
+		return (n1->path != NULL && n2->path != NULL &&
+		    0 == strcmp(n1->path, n2->path));
+	} else if (n1->host != NULL && n2->host != NULL) {
+		/*
+		 * XXX: Do we need to get more sophisticated, checking for
+		 * wildcards and such?
+		 */
+		return (0 == strcmp(n1->host, n2->host));
+	} else
+		return 1; /* If only one empty then they match. */
+}
+
+/* -- forward options */
+
+void
+forward_options_init_from_client(ForwardOptions *fwd_opts, struct Options *opts)
+{
+	*fwd_opts = forward_options_initializer;
+
+	fwd_opts->tcpip_gateway_ports = opts->gateway_ports;
+	fwd_opts->streamlocal_bind_mask = opts->streamlocal_bind_mask;
+	fwd_opts->streamlocal_bind_unlink = opts->streamlocal_bind_unlink;
+}
+
+void
+forward_options_init_from_server(ForwardOptions *fwd_opts, struct ServerOptions *opts)
+{
+	*fwd_opts = forward_options_initializer;
+
+	fwd_opts->tcpip_gateway_ports = opts->gateway_ports;
+	fwd_opts->streamlocal_bind_mask = opts->streamlocal_bind_mask;
+	fwd_opts->streamlocal_bind_unlink = opts->streamlocal_bind_unlink;
+}
+
 /* -- channel core */
 
 Channel *
@@ -443,6 +537,8 @@
 		c = channels[i];
 		if (c != NULL) {
 			switch (c->type) {
+			case SSH_CHANNEL_UNIX_LISTENER:
+			case SSH_CHANNEL_RUNIX_LISTENER:
 			case SSH_CHANNEL_AUTH_SOCKET:
 			case SSH_CHANNEL_PORT_LISTENER:
 			case SSH_CHANNEL_RPORT_LISTENER:
@@ -502,6 +598,8 @@
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
+		case SSH_CHANNEL_UNIX_LISTENER:
+		case SSH_CHANNEL_RUNIX_LISTENER:
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_AUTH_SOCKET:
 		case SSH_CHANNEL_DYNAMIC:
@@ -546,6 +644,8 @@
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
+		case SSH_CHANNEL_UNIX_LISTENER:
+		case SSH_CHANNEL_RUNIX_LISTENER:
 		case SSH_CHANNEL_OPENING:
 		case SSH_CHANNEL_CONNECTING:
 		case SSH_CHANNEL_ZOMBIE:
@@ -593,6 +693,8 @@
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
 		case SSH_CHANNEL_RPORT_LISTENER:
+		case SSH_CHANNEL_UNIX_LISTENER:
+		case SSH_CHANNEL_RUNIX_LISTENER:
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_AUTH_SOCKET:
 		case SSH_CHANNEL_ZOMBIE:
@@ -1238,13 +1340,10 @@
 static void
 port_open_helper(Channel *c, char *rtype)
 {
-	int direct;
 	char buf[1024];
 	char *remote_ipaddr = get_peer_ipaddr(c->sock);
 	int remote_port = get_peer_port(c->sock);
 
-	direct = (strcmp(rtype, "direct-tcpip") == 0);
-
 	snprintf(buf, sizeof buf,
 	    "%s: listening port %d for %.100s port %d, "
 	    "connect from %.200s port %d",
@@ -1260,19 +1359,46 @@
 		packet_put_int(c->self);
 		packet_put_int(c->local_window_max);
 		packet_put_int(c->local_maxpacket);
-		if (direct) {
+		if (strcmp(rtype, "direct-tcpip") == 0) {
 			/* target host, port */
 			packet_put_cstring(c->path);
 			packet_put_int(c->host_port);
+		} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
+			/* target path */
+			packet_put_cstring(c->path);
+		} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
+			/* listen path */
+			packet_put_cstring(c->path);
 		} else {
 			/* listen address, port */
 			packet_put_cstring(c->path);
 			packet_put_int(c->listening_port);
 		}
-		/* originator host and port */
-		packet_put_cstring(remote_ipaddr);
-		packet_put_int((u_int)remote_port);
-		packet_send();
+
+		/*
+		 * XXX: Maybe we want to simplify this, since it is a little
+		 * inconsistent with direct forwardings (unless
+		 * FakeStreamLocalForwards is used to switch between
+		 * enhanced direct forwarding modes) originating from the
+		 * unix domain, but this seemed liked a good opportunity to
+		 * keep open the door to remote domain socket forwarding
+		 * being capable of other interesting things.
+		 */
+		if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
+			/*
+			 * here we could send interestings tidbits, like
+			 * uid=1234 and group=wheel, so something like
+			 * getpeername() could be emulated on the other
+			 * side.
+			 */
+			packet_put_cstring(""); /* terminate the list */
+			packet_send();
+		} else {
+			/* originator host and port */
+			packet_put_cstring(remote_ipaddr);
+			packet_put_int((u_int)remote_port);
+			packet_send();
+		}
 	} else {
 		packet_start(SSH_MSG_PORT_OPEN);
 		packet_put_int(c->self);
@@ -1320,8 +1446,14 @@
 		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 == 0) {
+			if (c->host_port == -1) {
+				nextstate = SSH_CHANNEL_OPENING;
+				rtype = "direct-streamlocal@openssh.com";
+			} else if (c->host_port == 0) {
 				nextstate = SSH_CHANNEL_DYNAMIC;
 				rtype = "dynamic-tcpip";
 			} else {
@@ -1712,6 +1844,8 @@
 	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;
@@ -1720,6 +1854,8 @@
 	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;
@@ -2304,6 +2440,7 @@
 	u_short host_port;
 	char *host, *originator_string;
 	int remote_id, sock = -1;
+	SocketName name;
 
 	remote_id = packet_get_int();
 	host = packet_get_string(NULL);
@@ -2315,7 +2452,8 @@
 		originator_string = xstrdup("unknown (remote did not supply name)");
 	}
 	packet_check_eom();
-	sock = channel_connect_to(host, host_port);
+	SOCKETNAME_INIT_TCPIP(&name, host, host_port);
+	sock = channel_connect_to(&name);
 	if (sock != -1) {
 		c = channel_new("connected socket",
 		    SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
@@ -2341,8 +2479,8 @@
 }
 
 static int
-channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port,
-    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+channel_setup_tcpip_fwd_listener(int type, const char *listen_addr, u_short listen_port,
+    const char *host_to_connect, int port_to_connect, ForwardOptions *opts)
 {
 	Channel *c;
 	int sock, r, success = 0, wildcard = 0, is_client;
@@ -2381,19 +2519,19 @@
 	addr = NULL;
 	if (listen_addr == NULL) {
 		/* No address specified: default to gateway_ports setting */
-		if (gateway_ports)
+		if (opts->tcpip_gateway_ports)
 			wildcard = 1;
-	} else if (gateway_ports || is_client) {
+	} else if (opts->tcpip_gateway_ports || is_client) {
 		if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
 		    strcmp(listen_addr, "0.0.0.0") == 0) ||
 		    *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
-		    (!is_client && gateway_ports == 1))
+		    (!is_client && opts->tcpip_gateway_ports == 1))
 			wildcard = 1;
 		else if (strcmp(listen_addr, "localhost") != 0)
 			addr = listen_addr;
 	}
 
-	debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
+	debug3("channel_setup_tcpip_fwd_listener: type %d wildcard %d addr %s",
 	    type, wildcard, (addr == NULL) ? "NULL" : addr);
 
 	/*
@@ -2411,7 +2549,7 @@
 			packet_disconnect("getaddrinfo: fatal error: %s",
 			    gai_strerror(r));
 		} else {
-			error("channel_setup_fwd_listener: "
+			error("channel_setup_tcpip_fwd_listener: "
 			    "getaddrinfo(%.64s): %s", addr, gai_strerror(r));
 		}
 		return 0;
@@ -2422,7 +2560,7 @@
 			continue;
 		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
 		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-			error("channel_setup_fwd_listener: getnameinfo failed");
+			error("channel_setup_tcpip_fwd_listener: getnameinfo failed");
 			continue;
 		}
 		/* Create a port to listen for the host. */
@@ -2464,24 +2602,143 @@
 		success = 1;
 	}
 	if (success == 0)
-		error("channel_setup_fwd_listener: cannot listen to port: %d",
+		error("channel_setup_tcpip_fwd_listener: cannot listen to port: %d",
 		    listen_port);
 	freeaddrinfo(aitop);
 	return success;
 }
 
+static int
+channel_setup_streamlocal_fwd_listener(int type, const char *listen_path,
+    const char *host_to_connect, int port_to_connect, ForwardOptions *opts)
+{
+	Channel *c;
+	struct sockaddr_un sun;
+	int sock;
+	const char *host_or_path;
+	mode_t omask;
+
+	host_or_path = (type == SSH_CHANNEL_RUNIX_LISTENER) ?
+	    listen_path : host_to_connect;
+
+	if (host_or_path == NULL) {
+		error("No forward host or path name.");
+		return 0;
+	}
+	if (strlen(host_or_path) > SSH_CHANNEL_PATH_LEN - 1) {
+		error("Forward host or path name too long.");
+		return 0;
+	}
+
+	debug3("channel_setup_streamlocal_fwd_listener: type %d path %s",
+	    type, listen_path);
+
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_LOCAL;
+	/* strncpy was made for this usage */
+	strncpy(sun.sun_path, listen_path, sizeof(sun.sun_path));
+	sock = socket(sun.sun_family, SOCK_STREAM, 0);
+	if (sock < 0) {
+		verbose("socket: %.100s", strerror(errno));
+		return 0;
+	}
+
+	channel_set_reuseaddr(sock);
+
+	debug("Local forwarding listening on path %s.", listen_path);
+
+	if (opts->streamlocal_bind_unlink == 1 &&
+	    0 != unlink(listen_path) && errno != ENOENT)
+		error("unlink(%s): %.100s", listen_path, strerror(errno));
+
+	omask = umask(opts->streamlocal_bind_mask);
+
+	if (bind(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+		error("bind: %.100s", strerror(errno));
+		umask(omask);
+		close(sock);
+		error("channel_setup_streamlocal_fwd_listener: cannot listen to path: %s",
+		    listen_path);
+		return 0;
+	}
+
+	umask(omask);
+
+	if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
+		error("listen: %.100s", strerror(errno));
+		close(sock);
+		error("channel_setup_streamlocal_fwd_listener: cannot listen to path: %s",
+		    listen_path);
+		return 0;
+	}
+	c = channel_new("unix listener", type, sock, sock, -1,
+	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+	    0, "unix listener", 1);
+	strlcpy(c->path, host_or_path, sizeof(c->path));
+	c->host_port = port_to_connect;
+	c->listening_port = 0;
+	return 1;
+}
+
+static int
+channel_setup_fwd_listener(int type, const SocketName *listen_addr,
+    const SocketName *host_to_connect, ForwardOptions *opts)
+{
+	char *host_or_path = NULL;
+	int port_to_connect = 0;
+
+	/*
+	 * Passing port_to_connect as -1 when the destination is a domain
+	 * socket is quite the hack! This special value is then used by
+	 * channel_post_port_listener(), similar to the SOCKS4/SOCKS5 check,
+	 * to determine the type of request message to send.
+	 */
+	if (host_to_connect != NULL) {
+		if (SOCKETNAME_IS_STREAMLOCAL(host_to_connect)) {
+			host_or_path = host_to_connect->path;
+			port_to_connect = -1;
+		} else {
+			host_or_path = host_to_connect->host;
+			port_to_connect = host_to_connect->port;
+		}
+	}
+
+	if (type == SSH_CHANNEL_UNIX_LISTENER || type == SSH_CHANNEL_RUNIX_LISTENER) {
+		return channel_setup_streamlocal_fwd_listener(type,
+		    listen_addr->path, host_or_path, port_to_connect, opts);
+	} else {
+		return channel_setup_tcpip_fwd_listener(type,
+		    listen_addr->host, listen_addr->port, host_or_path,
+		    port_to_connect, opts);
+	}
+}
+
 int
-channel_cancel_rport_listener(const char *host, u_short port)
+channel_cancel_rport_listener(const SocketName *name)
 {
 	u_int i;
 	int found = 0;
+	const char *host_or_path;
+	u_short port;
+
+	host_or_path = (name->path)? name->path : name->host;
+	port = name->port;
 
 	for (i = 0; i < channels_alloc; i++) {
 		Channel *c = channels[i];
 
-		if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER &&
-		    strncmp(c->path, host, sizeof(c->path)) == 0 &&
-		    c->listening_port == port) {
+		/*
+		 * XXX: Looks like string truncation bug here. Need
+		 * something like a strlcmp(), which can take a limit to
+		 * prevent walking past the end of a non-NUL terminated
+		 * buffer but also handle NUL termination detection and
+		 * comparison appropriately.
+		 */
+		if (c != NULL
+		&&  (c->type == SSH_CHANNEL_RPORT_LISTENER
+		 ||  c->type == SSH_CHANNEL_RUNIX_LISTENER)
+		&&  strncmp(c->path, host_or_path, sizeof(c->path)) == 0
+		&&  c->listening_port == port) {
 			debug2("%s: close channel %d", __func__, i);
 			channel_free(c);
 			found = 1;
@@ -2493,31 +2750,39 @@
 
 /* protocol local port fwd, used by ssh (and sshd in v1) */
 int
-channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
-    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+channel_setup_local_fwd_listener(const SocketName *listen_addr,
+    const SocketName *connect_addr, ForwardOptions *opts)
 {
-	return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
-	    listen_host, listen_port, host_to_connect, port_to_connect,
-	    gateway_ports);
+	if (SOCKETNAME_IS_STREAMLOCAL(listen_addr)) {
+		return channel_setup_fwd_listener(SSH_CHANNEL_UNIX_LISTENER,
+		    listen_addr, connect_addr, opts);
+	} else {
+		return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
+		    listen_addr, connect_addr, opts);
+	}
 }
 
 /* protocol v2 remote port fwd, used by sshd */
 int
-channel_setup_remote_fwd_listener(const char *listen_address,
-    u_short listen_port, int gateway_ports)
+channel_setup_remote_fwd_listener(const SocketName *listen_addr,
+    ForwardOptions *opts)
 {
-	return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
-	    listen_address, listen_port, NULL, 0, gateway_ports);
+	if (SOCKETNAME_IS_STREAMLOCAL(listen_addr)) {
+		return channel_setup_fwd_listener(SSH_CHANNEL_RUNIX_LISTENER,
+		    listen_addr, NULL, opts);
+	} else {
+		return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
+		    listen_addr, NULL, opts);
+	}
 }
 
 /*
  * Initiate forwarding of connections to port "port" on remote host through
  * the secure channel to host:port from local side.
  */
-
 int
-channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
-    const char *host_to_connect, u_short port_to_connect)
+channel_request_remote_forwarding(const SocketName *listen_name,
+    const SocketName *connect_name)
 {
 	int type, success = 0;
 
@@ -2527,35 +2792,47 @@
 
 	/* Send the forward request to the remote side. */
 	if (compat20) {
-		const char *address_to_bind;
-		if (listen_host == NULL) {
-			if (datafellows & SSH_BUG_RFWD_ADDR)
-				address_to_bind = "127.0.0.1";
-			else
-				address_to_bind = "localhost";
-		} else if (*listen_host == '\0' ||
-			   strcmp(listen_host, "*") == 0) {
-			if (datafellows & SSH_BUG_RFWD_ADDR)
-				address_to_bind = "0.0.0.0";
-			else
-				address_to_bind = "";
-		} else
-			address_to_bind = listen_host;
-
-		packet_start(SSH2_MSG_GLOBAL_REQUEST);
-		packet_put_cstring("tcpip-forward");
-		packet_put_char(1);			/* boolean: want reply */
-		packet_put_cstring(address_to_bind);
-		packet_put_int(listen_port);
-		packet_send();
-		packet_write_wait();
-		/* Assume that server accepts the request */
-		success = 1;
-	} else {
+		if (SOCKETNAME_IS_TCPIP(listen_name)) {
+			const char *address_to_bind;
+			if (listen_name->host == NULL) {
+				if (datafellows & SSH_BUG_RFWD_ADDR)
+					address_to_bind = "127.0.0.1";
+				else
+					address_to_bind = "localhost";
+			} else if (*listen_name->host == '\0' ||
+				strcmp(listen_name->host, "*") == 0) {
+				if (datafellows & SSH_BUG_RFWD_ADDR)
+					address_to_bind = "0.0.0.0";
+				else
+					address_to_bind = "";
+			} else
+				address_to_bind = listen_name->host;
+	
+			packet_start(SSH2_MSG_GLOBAL_REQUEST);
+			packet_put_cstring("tcpip-forward");
+			packet_put_char(1);			/* boolean: want reply */
+			packet_put_cstring(address_to_bind);
+			packet_put_int(listen_name->port);
+			packet_send();
+			packet_write_wait();
+			/* Assume that server accepts the request */
+			success = 1;
+		} else {
+ 			packet_start(SSH2_MSG_GLOBAL_REQUEST);
+ 			packet_put_cstring("streamlocal-forward@openssh.com");
+ 			packet_put_char(1);			/* boolean: want reply */
+ 			packet_put_cstring(listen_name->path);
+ 			/* XXX what else do we want to send? */
+ 			packet_send();
+ 			packet_write_wait();
+ 			/* Assume that server accepts the request */
+ 			success = 1;			
+		}
+	} else if (SOCKETNAME_IS_TCPIP(listen_name)) {
 		packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
-		packet_put_int(listen_port);
-		packet_put_cstring(host_to_connect);
-		packet_put_int(port_to_connect);
+		packet_put_int(listen_name->port);
+		packet_put_cstring(connect_name->host);
+		packet_put_int(connect_name->port);
 		packet_send();
 		packet_write_wait();
 
@@ -2572,12 +2849,24 @@
 			packet_disconnect("Protocol error for port forward request:"
 			    "received packet type %d.", type);
 		}
+	} else {
+		logit("Warning: Server does not support remote stream local forwarding.");
 	}
 	if (success) {
+#if FORWARD_PERMISSIONS_FIXED
+		SOCKETNAME_COPY(
+		    &permitted_opens[num_permitted_opens].connect_addr,
+		    connect_name);
+		SOCKETNAME_COPY(
+		    &permitted_opens[num_permitted_opens].listen_addr,
+		    listen_name);
+		num_permitted_opens++;
+#elif 0
 		permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
 		permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
 		permitted_opens[num_permitted_opens].listen_port = listen_port;
 		num_permitted_opens++;
+#endif
 	}
 	return (success ? 0 : -1);
 }
@@ -2587,13 +2876,30 @@
  * local side.
  */
 void
-channel_request_rforward_cancel(const char *host, u_short port)
+channel_request_rforward_cancel(const SocketName *host)
 {
+	const char *host_or_path;
+#if FORWARD_PERMISSIONS_FIXED
 	int i;
+#endif
+
+	host_or_path = (host->path)? host->path : host->host;
 
 	if (!compat20)
 		return;
 
+#if FORWARD_PERMISSIONS_FIXED
+	for (i = 0; i < num_permitted_opens; i++) {
+		if ((permitted_opens[i].connect_addr.host != NULL
+		||   permitted_opens[i].connect_addr.path != NULL)
+		&&  SOCKETNAME_EQ(&permitted_opens[i].listen_addr, host))
+			break;
+	}
+	if (i >= num_permitted_opens) {
+		debug("%s: requested forward not found", __func__);
+		return;
+	}
+#elif 0
 	for (i = 0; i < num_permitted_opens; i++) {
 		if (permitted_opens[i].host_to_connect != NULL &&
 		    permitted_opens[i].listen_port == port)
@@ -2603,17 +2909,32 @@
 		debug("%s: requested forward not found", __func__);
 		return;
 	}
-	packet_start(SSH2_MSG_GLOBAL_REQUEST);
-	packet_put_cstring("cancel-tcpip-forward");
-	packet_put_char(0);
-	packet_put_cstring(host == NULL ? "" : host);
-	packet_put_int(port);
-	packet_send();
+#endif
+	if (SOCKETNAME_IS_STREAMLOCAL(host)) {
+		packet_start(SSH2_MSG_GLOBAL_REQUEST);
+		packet_put_cstring("cancel-streamlocal-forward@openssh.com");
+		packet_put_char(0);
+		packet_put_cstring(host_or_path);
+		packet_send();
+	} else {
+		packet_start(SSH2_MSG_GLOBAL_REQUEST);
+		packet_put_cstring("cancel-tcpip-forward");
+		packet_put_char(0);
+		packet_put_cstring(host_or_path == NULL ? "" : host_or_path);
+		packet_put_int(host->port);
+		packet_send();
+	}
+	
 
+#if FORWARD_PERMISSIONS_FIXED
+	SOCKETNAME_FREE_MEMBERS(&permitted_opens[i].connect_addr);
+	SOCKETNAME_FREE_MEMBERS(&permitted_opens[i].listen_addr);
+#elif 0
 	permitted_opens[i].listen_port = 0;
 	permitted_opens[i].port_to_connect = 0;
 	xfree(permitted_opens[i].host_to_connect);
 	permitted_opens[i].host_to_connect = NULL;
+#endif
 }
 
 /*
@@ -2622,11 +2943,12 @@
  * message if there was an error).
  */
 int
-channel_input_port_forward_request(int is_root, int gateway_ports)
+channel_input_port_forward_request(int is_root, ForwardOptions *opts)
 {
 	u_short port, host_port;
 	int success = 0;
 	char *hostname;
+	SocketName listen_addr, connect_addr;
 
 	/* Get arguments from the packet. */
 	port = packet_get_int();
@@ -2647,8 +2969,10 @@
 #endif
 
 	/* Initiate forwarding */
-	success = channel_setup_local_fwd_listener(NULL, port, hostname,
-	    host_port, gateway_ports);
+	SOCKETNAME_INIT_TCPIP(&listen_addr, NULL, port);
+	SOCKETNAME_INIT_TCPIP(&connect_addr, hostname, host_port);
+	success = channel_setup_local_fwd_listener(&listen_addr, &connect_addr,
+	    opts);
 
 	/* Free the argument string. */
 	xfree(hostname);
@@ -2675,9 +2999,15 @@
 		fatal("channel_add_permitted_opens: too many forwards");
 	debug("allow port forwarding to host %s port %d", host, port);
 
+#if FORWARD_PERMISSIONS_FIXED
+	SOCKETNAME_SET_TCPIP(&permitted_opens[num_permitted_opens].connect_addr, host, port);
+	SOCKETNAME_INIT(&permitted_opens[num_permitted_opens].listen_addr);
+	num_permitted_opens++;
+#elif 0
 	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
 	permitted_opens[num_permitted_opens].port_to_connect = port;
 	num_permitted_opens++;
+#endif
 
 	all_opens_permitted = 0;
 }
@@ -2689,10 +3019,18 @@
 		fatal("channel_add_adm_permitted_opens: too many forwards");
 	debug("config allows port forwarding to host %s port %d", host, port);
 
+#if FORWARD_PERMISSIONS_FIXED
+	SOCKETNAME_SET_TCPIP(&permitted_adm_opens[num_adm_permitted_opens].connect_addr, host, port);
+	SOCKETNAME_INIT(&permitted_adm_opens[num_adm_permitted_opens].listen_addr);
+	return ++num_adm_permitted_opens;
+#elif 0
 	permitted_adm_opens[num_adm_permitted_opens].host_to_connect
 	     = xstrdup(host);
 	permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
 	return ++num_adm_permitted_opens;
+#else
+	return 0;
+#endif
 }
 
 void
@@ -2700,10 +3038,18 @@
 {
 	int i;
 
+#if FORWARD_PERMISSIONS_FIXED
+	for (i = 0; i < num_permitted_opens; i++) {
+		SOCKETNAME_FREE_MEMBERS(&permitted_opens[i].connect_addr);
+		SOCKETNAME_FREE_MEMBERS(&permitted_opens[i].listen_addr);
+	}
+	num_permitted_opens = 0;
+#elif 0
 	for (i = 0; i < num_permitted_opens; i++)
 		if (permitted_opens[i].host_to_connect != NULL)
 			xfree(permitted_opens[i].host_to_connect);
 	num_permitted_opens = 0;
+#endif
 }
 
 void
@@ -2711,62 +3057,93 @@
 {
 	int i;
 
+#if FORWARD_PERMISSIONS_FIXED
+	for (i = 0; i < num_adm_permitted_opens; i++) {
+		SOCKETNAME_FREE_MEMBERS(&permitted_adm_opens[i].connect_addr);
+		SOCKETNAME_FREE_MEMBERS(&permitted_adm_opens[i].listen_addr);
+	}
+	num_adm_permitted_opens = 0;
+#elif 0
 	for (i = 0; i < num_adm_permitted_opens; i++)
 		if (permitted_adm_opens[i].host_to_connect != NULL)
 			xfree(permitted_adm_opens[i].host_to_connect);
 	num_adm_permitted_opens = 0;
+#endif
 }
 
 /* return socket to remote host, port */
 static int
-connect_to(const char *host, u_short port)
+connect_to(const SocketName *name)
 {
 	struct addrinfo hints, *ai, *aitop;
 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
 	int gaierr;
+	struct sockaddr_un sun;
 	int sock = -1;
 
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = IPv4or6;
-	hints.ai_socktype = SOCK_STREAM;
-	snprintf(strport, sizeof strport, "%d", port);
-	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
-		error("connect_to %.100s: unknown host (%s)", host,
-		    gai_strerror(gaierr));
-		return -1;
-	}
-	for (ai = aitop; ai; ai = ai->ai_next) {
-		if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
-			continue;
-		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
-		    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-			error("connect_to: getnameinfo failed");
-			continue;
-		}
-		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+	if (SOCKETNAME_IS_STREAMLOCAL(name)) {
+		memset(&sun, 0, sizeof(sun));
+		sun.sun_family = AF_LOCAL;
+		/* strncpy was made for this usage */
+		strncpy(sun.sun_path, name->path, sizeof(sun.sun_path));
+		sock = socket(sun.sun_family, SOCK_STREAM, 0);
 		if (sock < 0) {
-			if (ai->ai_next == NULL)
-				error("socket: %.100s", strerror(errno));
-			else
-				verbose("socket: %.100s", strerror(errno));
-			continue;
+			error("socket: %.100s", strerror(errno));
+			return -1;
 		}
 		if (set_nonblock(sock) == -1)
 			fatal("%s: set_nonblock(%d)", __func__, sock);
-		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
+		/* TODO: attempt to unlink socket path if requested */
+		if (connect(sock, (struct sockaddr *)&sun, sizeof sun) < 0 &&
 		    errno != EINPROGRESS) {
-			error("connect_to %.100s port %s: %.100s", ntop, strport,
+			error("connect_to path %s: %.100s", name->path,
 			    strerror(errno));
 			close(sock);
-			continue;	/* fail -- try next */
+			return -1;
+		}
+	} else {
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = IPv4or6;
+		hints.ai_socktype = SOCK_STREAM;
+		snprintf(strport, sizeof strport, "%d", name->port);
+		if ((gaierr = getaddrinfo(name->host, strport, &hints, &aitop)) != 0) {
+			error("connect_to %.100s: unknown host (%s)", name->host,
+			    gai_strerror(gaierr));
+			return -1;
+		}
+		for (ai = aitop; ai; ai = ai->ai_next) {
+			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+				continue;
+			if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
+			    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+				error("connect_to: getnameinfo failed");
+				continue;
+			}
+			sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+			if (sock < 0) {
+				if (ai->ai_next == NULL)
+					error("socket: %.100s", strerror(errno));
+				else
+					verbose("socket: %.100s", strerror(errno));
+				continue;
+			}
+			if (set_nonblock(sock) == -1)
+				fatal("%s: set_nonblock(%d)", __func__, sock);
+			if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
+			    errno != EINPROGRESS) {
+				error("connect_to %.100s port %s: %.100s", ntop, strport,
+				    strerror(errno));
+				close(sock);
+				continue;	/* fail -- try next */
+			}
+			break; /* success */
+	
+		}
+		freeaddrinfo(aitop);
+		if (!ai) {
+			error("connect_to %.100s port %d: failed.", name->host, name->port);
+			return -1;
 		}
-		break; /* success */
-
-	}
-	freeaddrinfo(aitop);
-	if (!ai) {
-		error("connect_to %.100s port %d: failed.", host, port);
-		return -1;
 	}
 	/* success */
 	set_nodelay(sock);
@@ -2774,8 +3151,18 @@
 }
 
 int
-channel_connect_by_listen_address(u_short listen_port)
+channel_connect_by_listen_address(const SocketName *name)
 {
+#if FORWARD_PERMISSIONS_FIXED
+	int i;
+
+	for (i = 0; i < num_permitted_opens; i++)
+		if (SOCKETNAME_ISSET(&permitted_opens[i].connect_addr)
+		&&  SOCKETNAME_EQ(&permitted_opens[i].listen_addr, name))
+			return connect_to(&permitted_opens[i].connect_addr);
+	error("WARNING: Server requests forwarding for unknown address %s",
+	    SOCKETNAME_TOSTRING(name));
+#elif 0
 	int i;
 
 	for (i = 0; i < num_permitted_opens; i++)
@@ -2786,22 +3173,38 @@
 			    permitted_opens[i].port_to_connect);
 	error("WARNING: Server requests forwarding for unknown listen_port %d",
 	    listen_port);
+#endif
 	return -1;
 }
 
 /* Check if connecting to that port is permitted and connect. */
 int
-channel_connect_to(const char *host, u_short port)
+channel_connect_to(const SocketName *name)
 {
 	int i, permit, permit_adm = 1;
 
 	permit = all_opens_permitted;
+#if FORWARD_PERMISSIONS_FIXED
+	if (!permit) {
+		for (i = 0; i < num_permitted_opens; i++)
+			if (SOCKETNAME_EQ(&permitted_opens[i].connect_addr, name))
+				permit = 1;
+	}
+
+	if (num_adm_permitted_opens > 0) {
+		permit_adm = 0;
+		for (i = 0; i < num_adm_permitted_opens; i++)
+			if (SOCKETNAME_EQ(&permitted_adm_opens[i].connect_addr, name))
+				permit_adm = 1;
+	}
+#elif 0
 	if (!permit) {
 		for (i = 0; i < num_permitted_opens; i++)
 			if (permitted_opens[i].host_to_connect != NULL &&
 			    permitted_opens[i].port_to_connect == port &&
 			    strcmp(permitted_opens[i].host_to_connect, host) == 0)
 				permit = 1;
+
 	}
 
 	if (num_adm_permitted_opens > 0) {
@@ -2813,13 +3216,18 @@
 			    == 0)
 				permit_adm = 1;
 	}
-
+#endif
 	if (!permit || !permit_adm) {
-		logit("Received request to connect to host %.100s port %d, "
-		    "but the request was denied.", host, port);
+		if (name->path != NULL)
+			logit("Received request to connect to socket %.100s, "
+			    "but the request was denied.", name->path);
+		else
+			logit("Received request to connect to host %.100s port %d, "
+			    "but the request was denied.", name->host, name->port);
+		
 		return -1;
 	}
-	return connect_to(host, port);
+	return connect_to(name);
 }
 
 void
diff -Naur openssh-4.7p1.orig/channels.h openssh-4.7p1-streamlocal/channels.h
--- openssh-4.7p1.orig/channels.h	2007-06-12 16:38:54.000000000 +0300
+++ openssh-4.7p1-streamlocal/channels.h	2009-08-29 18:33:41.000000000 +0300
@@ -38,6 +38,91 @@
 #ifndef CHANNEL_H
 #define CHANNEL_H
 
+/* Definitions and data structures to describe a socket address. */
+#define SOCKETNAME_INITIALIZER	(socketname_initializer)
+
+#define SOCKETNAME_INIT(n)		do {				\
+	*(n) = SOCKETNAME_INITIALIZER;					\
+} while(0)
+
+#define SOCKETNAME_INIT_TCPIP(n, h, p)	do {				\
+	SOCKETNAME_INIT((n));						\
+	(n)->host = (h);						\
+	(n)->port = (p);						\
+} while(0)
+
+#define SOCKETNAME_INIT_STREAMLOCAL(n, p)	do {			\
+	SOCKETNAME_INIT((n));						\
+	(n)->path = (p);						\
+} while(0)
+
+#define SOCKETNAME_COPY(dst, src)	do {				\
+	*(dst) = SOCKETNAME_INITIALIZER;				\
+	if ((src)->host)						\
+		(dst)->host = xstrdup((src)->host);			\
+	(dst)->port = (src)->port;					\
+	if ((src)->path)						\
+		(dst)->path = xstrdup((src)->path);			\
+} while(0)
+
+#define SOCKETNAME_FREE_MEMBERS(n)	do {				\
+	if ((n)->host)							\
+		xfree((n)->host);					\
+	if ((n)->path)							\
+		xfree((n)->path);					\
+	SOCKETNAME_INIT(n);						\
+} while(0)
+
+#define SOCKETNAME_SET_TCPIP(n, h, p)	do {				\
+	SOCKETNAME_INIT(n);						\
+	if ((h) != NULL)						\
+		(n)->host = xstrdup((h));				\
+	(n)->port = (p);						\
+} while(0)
+
+#define SOCKETNAME_SET_STREAMLOCAL(n, p)	do {			\
+	SOCKETNAME_INIT(n);						\
+	(n)->path = xstrdup((p));					\
+} while(0)
+
+#define SOCKETNAME_TOSTRING(n)	socketname_tostring((n))
+
+#define SOCKETNAME_ISSET(n)		((n)->host != NULL ||		\
+					 (n)->path != NULL ||		\
+					 (n)->port > 0)
+#define SOCKETNAME_IS_TCPIP(n)		((n)->path == NULL)
+#define SOCKETNAME_IS_STREAMLOCAL(n)	((n)->path != NULL)
+
+#define SOCKETNAME_EQ(n1, n2)	socketname_eq((n1), (n2))
+
+struct SocketName;
+typedef struct SocketName SocketName;
+
+struct SocketName {
+	char	 *host;		/* Inet address. */
+	u_short	  port;		/* Inet port. */
+	char	 *path;		/* Local (Unix domain) path. */
+};
+
+const char *socketname_tostring(const SocketName *);
+
+int socketname_eq(const SocketName *, const SocketName *);
+
+extern const SocketName socketname_initializer;
+
+/* Port forwarding options. */
+struct Options;
+struct ServerOptions;
+
+typedef struct {
+	int tcpip_gateway_ports;
+	mode_t streamlocal_bind_mask;
+	int streamlocal_bind_unlink;
+} ForwardOptions;
+
+void forward_options_init_from_client(ForwardOptions *, struct Options *);
+void forward_options_init_from_server(ForwardOptions *, struct ServerOptions *);
+
 /* Definitions for channel types. */
 #define SSH_CHANNEL_X11_LISTENER	1	/* Listening for inet X11 conn. */
 #define SSH_CHANNEL_PORT_LISTENER	2	/* Listening on a port. */
@@ -53,7 +138,9 @@
 #define SSH_CHANNEL_CONNECTING		12
 #define SSH_CHANNEL_DYNAMIC		13
 #define SSH_CHANNEL_ZOMBIE		14	/* Almost dead. */
-#define SSH_CHANNEL_MAX_TYPE		15
+#define SSH_CHANNEL_UNIX_LISTENER	15	/* Listening on a domain socket. */
+#define SSH_CHANNEL_RUNIX_LISTENER	16	/* Listening to a R-style domain socket */
+#define SSH_CHANNEL_MAX_TYPE		17
 
 #define SSH_CHANNEL_PATH_LEN		256
 
@@ -208,16 +295,16 @@
 int	 channel_add_adm_permitted_opens(char *, int);
 void	 channel_clear_permitted_opens(void);
 void	 channel_clear_adm_permitted_opens(void);
-int      channel_input_port_forward_request(int, int);
-int	 channel_connect_to(const char *, u_short);
-int	 channel_connect_by_listen_address(u_short);
-int	 channel_request_remote_forwarding(const char *, u_short,
-	     const char *, u_short);
-int	 channel_setup_local_fwd_listener(const char *, u_short,
-	     const char *, u_short, int);
-void	 channel_request_rforward_cancel(const char *host, u_short port);
-int	 channel_setup_remote_fwd_listener(const char *, u_short, int);
-int	 channel_cancel_rport_listener(const char *, u_short);
+int	 channel_input_port_forward_request(int, ForwardOptions *);
+int	 channel_connect_to(const SocketName *);
+int	 channel_connect_by_listen_address(const SocketName *);
+int	 channel_request_remote_forwarding(const SocketName *,
+	     const SocketName *);
+int	 channel_setup_local_fwd_listener(const SocketName *,
+	     const SocketName *, ForwardOptions *);
+void	 channel_request_rforward_cancel(const SocketName *);
+int	 channel_setup_remote_fwd_listener(const SocketName *, ForwardOptions *);
+int	 channel_cancel_rport_listener(const SocketName *);
 
 /* x11 forwarding */
 
diff -Naur openssh-4.7p1.orig/clientloop.c openssh-4.7p1-streamlocal/clientloop.c
--- openssh-4.7p1.orig/clientloop.c	2007-08-15 12:13:42.000000000 +0300
+++ openssh-4.7p1-streamlocal/clientloop.c	2009-08-29 18:28:30.000000000 +0300
@@ -84,6 +84,7 @@
 #include <string.h>
 #include <termios.h>
 #include <pwd.h>
+#include <grp.h>
 #include <unistd.h>
 
 #include "xmalloc.h"
@@ -712,6 +713,84 @@
 	xfree(cctx);
 }
 
+
+static int
+client_control_grant(int client_fd)
+{
+	struct passwd *epw	= 0;
+	struct group *egr	= 0;
+	char euidstr[48];	/* Sufficient for 2^128 in decimal ascii */
+	char egidstr[48];	/* Sufficient for 2^128 in decimal ascii */
+	uid_t euid;
+	gid_t egid;
+	u_int i;
+
+	if (getpeereid(client_fd, &euid, &egid) < 0) {
+		error("%s getpeereid failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	if ((euid == 0) || (getuid() == euid))
+		return 1; /* Short circuit. */
+
+	if ((int)sizeof euidstr <= snprintf(euidstr, sizeof euidstr, "%lu", (u_long)euid)) {
+		error("%s uid too high", __func__);
+		return -1;
+	}
+
+	if ((int)sizeof egidstr <= snprintf(egidstr, sizeof egidstr, "%lu", (u_long)egid)) {
+		error("%s gid too high", __func__);
+		return -1;
+	}
+
+	if ((options.num_control_allow_users || options.num_control_deny_users)
+	&&  !(epw = getpwuid(euid))) {
+		error("%s getpwuid failed: %s", __func__, strerror(errno));
+		return -1;	/* Fail, otherwise we might miss a deny pattern. */
+	}
+
+	if ((options.num_control_allow_groups || options.num_control_deny_groups)
+	&&  !(egr = getgrgid(euid))) {
+		error("%s getgrgid failed: %s", __func__, strerror(errno));
+		return -1;	/* Fail, otherwise we might miss a deny pattern. */
+	}
+
+	for (i = 0; i < options.num_control_deny_users; i++) {
+		if (match_pattern(euidstr,options.control_deny_users[i])
+		||  (epw && match_pattern(epw->pw_name,options.control_deny_users[i]))) {
+			error("%s control mode uid denied: %s", __func__, options.control_deny_users[i]);
+			return 0;
+		}
+	}
+
+	for (i = 0; i < options.num_control_deny_groups; i++) {
+		if (match_pattern(egidstr,options.control_deny_groups[i])
+		||  (egr && match_pattern(egr->gr_name,options.control_deny_groups[i]))) {
+			error("%s control mode gid denied: %s", __func__, options.control_deny_groups[i]);
+			return 0;
+		}
+	}
+
+	for (i = 0; i < options.num_control_allow_users; i++) {
+		if (match_pattern(euidstr,options.control_allow_users[i])
+		||  (epw && match_pattern(epw->pw_name,options.control_allow_users[i]))) {
+			return 1;
+		}
+	}
+
+	for (i = 0; i < options.num_control_allow_groups; i++) {
+		if (match_pattern(egidstr,options.control_allow_groups[i])
+		||  (egr && match_pattern(egr->gr_name,options.control_allow_groups[i]))) {
+			return 1;
+		}
+	}
+
+	error("%s control mode uid/gid denied: %s/%s", __func__, euidstr, egidstr);
+
+	return 0; /* Deny by default. */
+}
+
+
 static void
 client_process_control(fd_set *readset)
 {
@@ -723,8 +802,6 @@
 	struct confirm_ctx *cctx;
 	char *cmd;
 	u_int i, len, env_len, command, flags;
-	uid_t euid;
-	gid_t egid;
 
 	/*
 	 * Accept connection on control socket
@@ -740,14 +817,19 @@
 		return;
 	}
 
-	if (getpeereid(client_fd, &euid, &egid) < 0) {
-		error("%s getpeereid failed: %s", __func__, strerror(errno));
+	switch(client_control_grant(client_fd)) {
+	case 1: /* ALLOWED */
+		break;
+	case 0: /* DENIED */
+		error("control access denied!");
 		close(client_fd);
 		return;
-	}
-	if ((euid != 0) && (getuid() != euid)) {
-		error("control mode uid mismatch: peer euid %u != uid %u",
-		    (u_int) euid, (u_int) getuid());
+	case -1: /* SYSERR! */
+		error("error granting access");
+		close(client_fd);
+		return;
+	default: /* OOPS! */
+		error("unknown error granting access");
 		close(client_fd);
 		return;
 	}
@@ -939,6 +1021,8 @@
 	int local = 0;
 	u_short cancel_port;
 	Forward fwd;
+	SocketName name, listen_host, connect_host;
+	ForwardOptions fwd_opts;
 
 	leave_raw_mode();
 	handler = signal(SIGINT, SIG_IGN);
@@ -1009,23 +1093,25 @@
 			logit("Bad forwarding close port");
 			goto out;
 		}
-		channel_request_rforward_cancel(cancel_host, cancel_port);
+		SOCKETNAME_INIT_TCPIP(&name, cancel_host, cancel_port);
+		channel_request_rforward_cancel(&name);
 	} else {
 		if (!parse_forward(&fwd, s)) {
 			logit("Bad forwarding specification.");
 			goto out;
 		}
+		SOCKETNAME_INIT_TCPIP(&listen_host, fwd.listen_host, fwd.listen_port);
+		SOCKETNAME_INIT_TCPIP(&connect_host, fwd.connect_host, fwd.connect_port);
 		if (local) {
-			if (channel_setup_local_fwd_listener(fwd.listen_host,
-			    fwd.listen_port, fwd.connect_host,
-			    fwd.connect_port, options.gateway_ports) < 0) {
+			forward_options_init_from_client(&fwd_opts, &options);
+			if (channel_setup_local_fwd_listener(&listen_host,
+			    &connect_host, &fwd_opts) < 0) {
 				logit("Port forwarding failed.");
 				goto out;
 			}
 		} else {
-			if (channel_request_remote_forwarding(fwd.listen_host,
-			    fwd.listen_port, fwd.connect_host,
-			    fwd.connect_port) < 0) {
+			if (channel_request_remote_forwarding(&listen_host,
+			    &connect_host) < 0) {
 				logit("Port forwarding failed.");
 				goto out;
 			}
@@ -1699,6 +1785,7 @@
 	Channel *c = NULL;
 	char *listen_address, *originator_address;
 	int listen_port, originator_port;
+	SocketName name;
 	int sock;
 
 	/* Get rest of the packet */
@@ -1711,7 +1798,8 @@
 	debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d",
 	    listen_address, listen_port, originator_address, originator_port);
 
-	sock = channel_connect_by_listen_address(listen_port);
+	SOCKETNAME_INIT_TCPIP(&name, listen_address, listen_port);
+	sock = channel_connect_by_listen_address(&name);
 	if (sock < 0) {
 		xfree(originator_address);
 		xfree(listen_address);
@@ -1726,6 +1814,63 @@
 	return c;
 }
 
+/*
+ * a connection came in on a listening local (unix domain) socket at the
+ * remote server. If we so desire, attempt to connect the stream to a local
+ * end point.
+ */
+static Channel *
+client_request_forwarded_streamlocal(const char *request_type, int rchan)
+{
+	Channel *c = NULL;
+	char *listen_path, *originator_info;
+	SocketName name;
+	int sock;
+
+	/* Get remote path and name/value pairs */
+	listen_path = packet_get_string(NULL);
+	originator_info = NULL;
+	do {
+		/* just discard for now */
+		if (originator_info != NULL) {
+			debug("client_request_forwarded_streamlocal "
+			    "origin info: %s", originator_info);
+			xfree(originator_info), originator_info = NULL;
+		}
+
+		/*
+		 * If provided, these look like "uid=1234" and/or
+		 * "group=foo". Since unix domain sockets can carry possibly
+		 * useful info (like uid, user names, gid, etc.) leave the
+		 * capability here to utilize this data, even if any
+		 * specific type of data is entirely unportable.
+		 *
+		 * This variable length list of name=value strings is
+		 * terminated by an empty string.
+		 */
+		originator_info = packet_get_string(NULL);
+	} while (originator_info && *originator_info);
+	packet_check_eom();
+	if (originator_info)
+		xfree(originator_info), originator_info = NULL;
+
+	debug("client_request_forwarded_streamlocal: %s",
+	    listen_path);
+
+	SOCKETNAME_INIT_STREAMLOCAL(&name, listen_path);
+	sock = channel_connect_by_listen_address(&name);
+	if (sock < 0) {
+		xfree(listen_path);
+		return NULL;
+	}
+	c = channel_new("forwarded-streamlocal@openssh.com",
+	    SSH_CHANNEL_CONNECTING, sock, sock, -1,
+	    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0,
+	    listen_path, 1);
+	xfree(listen_path);
+	return c;
+}
+
 static Channel *
 client_request_x11(const char *request_type, int rchan)
 {
@@ -1846,6 +1991,8 @@
 
 	if (strcmp(ctype, "forwarded-tcpip") == 0) {
 		c = client_request_forwarded_tcpip(ctype, rchan);
+	} else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
+		c = client_request_forwarded_streamlocal(ctype, rchan);
 	} else if (strcmp(ctype, "x11") == 0) {
 		c = client_request_x11(ctype, rchan);
 	} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
diff -Naur openssh-4.7p1.orig/readconf.c openssh-4.7p1-streamlocal/readconf.c
--- openssh-4.7p1.orig/readconf.c	2007-03-21 11:46:03.000000000 +0200
+++ openssh-4.7p1-streamlocal/readconf.c	2009-08-29 18:28:30.000000000 +0300
@@ -17,6 +17,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 
 #include <netinet/in.h>
 
@@ -124,11 +125,14 @@
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
-	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+	oClearAllForwardings, oFakeStreamLocalForwards,
+	oStreamLocalBindMask, oStreamLocalBindUnlink, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
-	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
+	oSendEnv, oControlBindMask, oControlPath, oControlMaster,
+	oControlAllowUsers, oControlDenyUsers, oControlAllowGroups,
+	oControlDenyGroups, oHashKnownHosts,
 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
 	oDeprecated, oUnsupported
 } OpCodes;
@@ -210,6 +214,9 @@
 	{ "smartcarddevice", oUnsupported },
 #endif
 	{ "clearallforwardings", oClearAllForwardings },
+	{ "fakestreamlocalforwards", oFakeStreamLocalForwards },
+	{ "streamlocalbindmask", oStreamLocalBindMask },
+	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
 	{ "enablesshkeysign", oEnableSSHKeysign },
 	{ "verifyhostkeydns", oVerifyHostKeyDNS },
 	{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
@@ -219,8 +226,13 @@
 	{ "serveraliveinterval", oServerAliveInterval },
 	{ "serveralivecountmax", oServerAliveCountMax },
 	{ "sendenv", oSendEnv },
+	{ "controlbindmask", oControlBindMask },
 	{ "controlpath", oControlPath },
 	{ "controlmaster", oControlMaster },
+	{ "controlallowusers", oControlAllowUsers },
+	{ "controldenyusers", oControlDenyUsers },
+	{ "controlallowgroups", oControlAllowUsers },
+	{ "controldenygroups", oControlDenyGroups },
 	{ "hashknownhosts", oHashKnownHosts },
 	{ "tunnel", oTunnel },
 	{ "tunneldevice", oTunnelDevice },
@@ -240,7 +252,8 @@
 	Forward *fwd;
 #ifndef NO_IPPORT_RESERVED_CONCEPT
 	extern uid_t original_real_uid;
-	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
+	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0
+	&&  newfwd->listen_path == NULL)
 		fatal("Privileged ports can only be forwarded by root.");
 #endif
 	if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
@@ -250,8 +263,13 @@
 	fwd->listen_host = (newfwd->listen_host == NULL) ?
 	    NULL : xstrdup(newfwd->listen_host);
 	fwd->listen_port = newfwd->listen_port;
-	fwd->connect_host = xstrdup(newfwd->connect_host);
+	fwd->listen_path = (newfwd->listen_path == NULL) ?
+	    NULL : xstrdup(newfwd->listen_path);
+	fwd->connect_host = (newfwd->connect_host == NULL) ?
+	    NULL : xstrdup(newfwd->connect_host);
 	fwd->connect_port = newfwd->connect_port;
+	fwd->connect_path = (newfwd->connect_path == NULL) ?
+	    NULL : xstrdup(newfwd->connect_path);
 }
 
 /*
@@ -271,8 +289,13 @@
 	fwd->listen_host = (newfwd->listen_host == NULL) ?
 	    NULL : xstrdup(newfwd->listen_host);
 	fwd->listen_port = newfwd->listen_port;
-	fwd->connect_host = xstrdup(newfwd->connect_host);
+	fwd->listen_path = (newfwd->listen_path == NULL) ?
+	    NULL : xstrdup(newfwd->listen_path);
+	fwd->connect_host = (newfwd->connect_host == NULL) ?
+	    NULL : xstrdup(newfwd->connect_host);
 	fwd->connect_port = newfwd->connect_port;
+	fwd->connect_path = (newfwd->connect_path == NULL) ?
+	    NULL : xstrdup(newfwd->connect_path);
 }
 
 static void
@@ -758,6 +781,25 @@
 		intptr = &options->clear_forwardings;
 		goto parse_flag;
 
+	case oFakeStreamLocalForwards:
+		intptr = &options->fake_streamlocal_forwards;
+		goto parse_flag;
+
+	case oStreamLocalBindMask:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing StreamLocalBindMask argument.",
+			    filename, linenum);
+		value = strtol(arg, &endofnumber, 0);
+		if (*endofnumber != '\0' || value < 0 || value > 0777)
+			fatal("%.200s line %d: Bad mask.", filename, linenum);
+		options->streamlocal_bind_mask = value;
+		break;
+
+	case oStreamLocalBindUnlink:
+		intptr = &options->streamlocal_bind_unlink;
+		goto parse_flag;
+
 	case oHost:
 		*activep = 0;
 		while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@@ -840,6 +882,17 @@
 		}
 		break;
 
+	case oControlBindMask:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing ControlBindMask argument.",
+			    filename, linenum);
+		value = strtol(arg, &endofnumber, 0);
+		if (*endofnumber != '\0' || value < 0 || value > 0777)
+			fatal("%.200s line %d: Bad mask.", filename, linenum);
+		options->control_bind_mask = value;
+		break;
+
 	case oControlPath:
 		charptr = &options->control_path;
 		goto parse_string;
@@ -868,6 +921,46 @@
 			*intptr = value;
 		break;
 
+	case oControlAllowUsers:
+		while ((arg = strdelim(&s)) && *arg != '\0') {
+			if (options->num_control_allow_users >= MAX_CONTROL_ALLOW_USERS)
+				fatal("%s line %d: too many control allow users.",
+				    filename, linenum);
+			options->control_allow_users[options->num_control_allow_users++] =
+			    xstrdup(arg);
+		}
+		break;
+
+	case oControlDenyUsers:
+		while ((arg = strdelim(&s)) && *arg != '\0') {
+			if (options->num_control_deny_users >= MAX_CONTROL_DENY_USERS)
+				fatal("%s line %d: too many control deny users.",
+				    filename, linenum);
+			options->control_deny_users[options->num_control_deny_users++] =
+			    xstrdup(arg);
+		}
+		break;
+
+	case oControlAllowGroups:
+		while ((arg = strdelim(&s)) && *arg != '\0') {
+			if (options->num_control_allow_groups >= MAX_CONTROL_ALLOW_GROUPS)
+				fatal("%s line %d: too many control allow groups.",
+				    filename, linenum);
+			options->control_allow_groups[options->num_control_allow_groups++] =
+			    xstrdup(arg);
+		}
+		break;
+
+	case oControlDenyGroups:
+		while ((arg = strdelim(&s)) && *arg != '\0') {
+			if (options->num_control_deny_groups >= MAX_CONTROL_DENY_GROUPS)
+				fatal("%s line %d: too many control deny groups.",
+				    filename, linenum);
+			options->control_deny_groups[options->num_control_deny_groups++] =
+			    xstrdup(arg);
+		}
+		break;
+
 	case oHashKnownHosts:
 		intptr = &options->hash_known_hosts;
 		goto parse_flag;
@@ -1045,6 +1138,9 @@
 	options->num_local_forwards = 0;
 	options->num_remote_forwards = 0;
 	options->clear_forwardings = -1;
+	options->fake_streamlocal_forwards = -1;
+	options->streamlocal_bind_mask = 0177;
+	options->streamlocal_bind_unlink = -1;
 	options->log_level = SYSLOG_LEVEL_NOT_SET;
 	options->preferred_authentications = NULL;
 	options->bind_address = NULL;
@@ -1057,8 +1153,13 @@
 	options->server_alive_interval = -1;
 	options->server_alive_count_max = -1;
 	options->num_send_env = 0;
+	options->control_bind_mask = 0177;
 	options->control_path = NULL;
 	options->control_master = -1;
+	options->num_control_allow_users = 0;
+	options->num_control_deny_users = 0;
+	options->num_control_allow_groups = 0;
+	options->num_control_deny_groups = 0;
 	options->hash_known_hosts = -1;
 	options->tun_open = -1;
 	options->tun_local = -1;
@@ -1173,6 +1274,10 @@
 		options->log_level = SYSLOG_LEVEL_INFO;
 	if (options->clear_forwardings == 1)
 		clear_forwardings(options);
+	if (options->fake_streamlocal_forwards == -1)
+		options->fake_streamlocal_forwards = 0;
+	if (options->streamlocal_bind_unlink == -1)
+		options->streamlocal_bind_unlink = 0;
 	if (options->no_host_authentication_for_localhost == - 1)
 		options->no_host_authentication_for_localhost = 0;
 	if (options->identities_only == -1)
@@ -1207,6 +1312,112 @@
 	/* options->preferred_authentications will be set in ssh */
 }
 
+
+/*
+ * parse_forward_part
+ *
+ * parses the next part (semi-colon delimited) of a port forwarding
+ * specification.
+ *
+ * This works similar to shell word parsing, except that square brackets are
+ * used for quoting instead of single or double quotes; semi-colons delimit
+ * the parts instead of whitespace; and adjacent delimiters are not merged.
+ * The canonical backslash escaping mechanism works identically, though.
+ *
+ * NOTE: All whitespace is preserved as-is.
+ *
+ * Returns the logical string length of the parsed part. On return `dstbuf'
+ * will contain up to `dstbufsz' - 1 characters of the part, and will always
+ * be zero terminated (if `dstbufsz' > 0). `end' will contain the next
+ * position in `src' to be parsed. If *end is NUL then there is no more
+ * input.
+ */
+size_t
+parse_forward_part(char *dstbuf, size_t dstbufsz, const char *src, char **end, int *special)
+{
+	struct { char *pos, *end; } dst;
+	int quoted;
+	int escaped;
+	int ibuf;
+	char *cbuf;
+
+	dst.pos = dstbuf;
+	dst.end = dstbuf + dstbufsz;
+
+	if (!end)
+		end = &cbuf;
+
+	if (!special)
+		special = &ibuf;
+
+	quoted  = '\0';
+	escaped = 0;
+
+	for (; src && *src != '\0'; src++) {
+		switch (*src) {
+		case ':':
+			if (escaped || quoted)
+				goto copyout;
+
+			src++;	/* Eat it before breaking the loop. */
+
+			goto nomore;
+
+			/* NOT REACHED */
+		case '[':
+			if (escaped) {
+				goto copyout;
+			} else if (quoted) {
+				goto copyout;
+			} else {
+				quoted   = 1;
+				*special = 1;
+			}
+			
+			break;
+		case ']':
+			if (escaped) {
+				goto copyout;
+			} else if (quoted) {
+				quoted = 0;
+			} else {
+				goto copyout;
+			}
+
+			break;
+		case '\\':
+			if (escaped) {
+				goto copyout;
+			} else {
+				escaped  = 1;
+				*special = 1;
+			}
+
+			break;
+copyout:
+		default:
+			escaped = 0;
+
+			if (dst.pos < dst.end)
+				*dst.pos = *src;
+
+			dst.pos++;
+		} /* switch (*src) */
+	} /* for (*src; src++) */
+
+nomore:
+
+	*end = (char *)src;
+
+	if (dst.pos < dst.end)
+		*dst.pos = '\0';
+	else if (dst.end > dstbuf)
+		dst.end[-1] = '\0';
+
+	return dst.pos - dstbuf;
+} /* parse_forward_part */
+
+
 /*
  * parse_forward
  * parses a string containing a port forwarding specification of the form:
@@ -1216,8 +1427,11 @@
 int
 parse_forward(Forward *fwd, const char *fwdspec)
 {
-	int i;
-	char *p, *cp, *fwdarg[4];
+	unsigned int i;
+	char *p, *cp, *fwdarg[4] = { 0 };
+	int fwdesc[4] = { 0 };	/* Tag whether part used escaping or quoting. */
+	char part[MAX(NI_MAXHOST + 1, sizeof ((struct sockaddr_un *)0)->sun_path)];
+	size_t partlen;
 
 	memset(fwd, '\0', sizeof(*fwd));
 
@@ -1227,47 +1441,105 @@
 	while (isspace(*cp))
 		cp++;
 
-	for (i = 0; i < 4; ++i)
-		if ((fwdarg[i] = hpdelim(&cp)) == NULL)
-			break;
+	for (i = 0; i < 4 && *cp != '\0'; ++i) {
+		partlen = parse_forward_part(part, sizeof part, cp, &cp, &fwdesc[i]);
 
-	/* Check for trailing garbage in 4-arg case*/
-	if (cp != NULL)
+		/* Was the part too long to be sane? */
+		if (partlen >= sizeof part)
+			goto fail_free;
+
+		fwdarg[i]	= xstrdup(part);
+	}
+
+	/* Check for trailing garbage in 4-arg case */
+	if (*cp != '\0')
 		i = 0;	/* failure */
 
 	switch (i) {
+	case 2:
+		/* Force escaping of all paths, just to be consistent. */
+		if (!fwdesc[0] || !fwdesc[1]) {
+			i = 0;
+		} else {
+			fwd->listen_host = NULL;
+			fwd->listen_port = 0;
+			fwd->listen_path = xstrdup(fwdarg[0]);
+
+			fwd->connect_host = NULL;
+			fwd->connect_port = 0;
+			fwd->connect_path = xstrdup(fwdarg[1]);
+		}
+		break;
 	case 3:
-		fwd->listen_host = NULL;
-		fwd->listen_port = a2port(fwdarg[0]);
-		fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
-		fwd->connect_port = a2port(fwdarg[2]);
+		if (fwdesc[0]) {
+			fwd->listen_host = NULL;
+			fwd->listen_port = 0;
+			fwd->listen_path = xstrdup(fwdarg[0]);
+			fwd->connect_host = xstrdup(fwdarg[1]);
+			fwd->connect_port = a2port(fwdarg[2]);
+			fwd->connect_path = NULL;
+		} else if (fwdesc[2]) {
+			fwd->listen_host = xstrdup(fwdarg[0]);
+			fwd->listen_port = a2port(fwdarg[1]);
+			fwd->listen_path = NULL;
+			fwd->connect_host = NULL;
+			fwd->connect_port = 0;
+			fwd->connect_path = xstrdup(fwdarg[2]);
+		} else {
+			fwd->listen_host = NULL;
+			fwd->listen_port = a2port(fwdarg[0]);
+			fwd->listen_path = NULL;
+			fwd->connect_host = xstrdup(fwdarg[1]);
+			fwd->connect_port = a2port(fwdarg[2]);
+			fwd->connect_path = NULL;
+		}
 		break;
-
 	case 4:
 		fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
 		fwd->listen_port = a2port(fwdarg[1]);
+		fwd->listen_path = NULL;
 		fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
 		fwd->connect_port = a2port(fwdarg[3]);
+		fwd->connect_path = NULL;
 		break;
 	default:
 		i = 0; /* failure */
 	}
 
-	xfree(p);
+	xfree(p), p = 0;
 
-	if (fwd->listen_port == 0 && fwd->connect_port == 0)
+	if (fwd->listen_port == 0 && fwd->listen_path == NULL
+	&&  fwd->connect_port == 0 && fwd->connect_path == NULL)
 		goto fail_free;
 
 	if (fwd->connect_host != NULL &&
 	    strlen(fwd->connect_host) >= NI_MAXHOST)
 		goto fail_free;
 
+	for (i = 0; i < sizeof fwdarg / sizeof *fwdarg; i++) {
+		if (fwdarg[i] != NULL)
+			xfree(fwdarg[i]), fwdarg[i] = NULL;
+	}
+
 	return (i);
 
  fail_free:
 	if (fwd->connect_host != NULL)
-		xfree(fwd->connect_host);
+		xfree(fwd->connect_host), fwd->connect_host = NULL;
+	if (fwd->connect_path != NULL)
+		xfree(fwd->connect_path), fwd->connect_path = NULL;
 	if (fwd->listen_host != NULL)
-		xfree(fwd->listen_host);
+		xfree(fwd->listen_host), fwd->listen_host = NULL;
+	if (fwd->listen_path != NULL)
+		xfree(fwd->listen_path), fwd->listen_path = NULL;
+
+	if (p)
+		xfree(p), p = NULL;
+
+	for (i = 0; i < sizeof fwdarg / sizeof *fwdarg; i++) {
+		if (fwdarg[i] != NULL)
+			xfree(fwdarg[i]), fwdarg[i] = NULL;
+	}
+
 	return (0);
 }
diff -Naur openssh-4.7p1.orig/readconf.h openssh-4.7p1-streamlocal/readconf.h
--- openssh-4.7p1.orig/readconf.h	2006-08-05 05:39:40.000000000 +0300
+++ openssh-4.7p1-streamlocal/readconf.h	2009-08-29 18:28:30.000000000 +0300
@@ -21,14 +21,21 @@
 typedef struct {
 	char	 *listen_host;		/* Host (address) to listen on. */
 	u_short	  listen_port;		/* Port to forward. */
+	char	 *listen_path;		/* Path to bind domain socket. */
 	char	 *connect_host;		/* Host to connect. */
 	u_short	  connect_port;		/* Port to connect on connect_host. */
+	char	 *connect_path;		/* Path to connect domain socket. */
 }       Forward;
 /* Data structure for representing option data. */
 
-#define MAX_SEND_ENV	256
+#define MAX_SEND_ENV			256
 
-typedef struct {
+#define MAX_CONTROL_ALLOW_USERS		256
+#define MAX_CONTROL_DENY_USERS		256
+#define MAX_CONTROL_ALLOW_GROUPS	256
+#define MAX_CONTROL_DENY_GROUPS		256
+
+typedef struct Options {
 	int     forward_agent;	/* Forward authentication agent. */
 	int     forward_x11;	/* Forward X11 display. */
 	int     forward_x11_trusted;	/* Trust Forward X11 display. */
@@ -98,6 +105,10 @@
 	int     num_remote_forwards;
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
 	int	clear_forwardings;
+	int	fake_streamlocal_forwards;
+	mode_t	streamlocal_bind_mask;
+	int	streamlocal_bind_unlink;
+	
 
 	int	enable_ssh_keysign;
 	int	rekey_limit;
@@ -109,8 +120,17 @@
 	int     num_send_env;
 	char   *send_env[MAX_SEND_ENV];
 
+	mode_t	control_bind_mask;
 	char	*control_path;
 	int	control_master;
+	u_int	num_control_allow_users;
+	char	*control_allow_users[MAX_CONTROL_ALLOW_USERS];
+	u_int	num_control_deny_users;
+	char	*control_deny_users[MAX_CONTROL_DENY_USERS];
+	u_int	num_control_allow_groups;
+	char	*control_allow_groups[MAX_CONTROL_ALLOW_GROUPS];
+	u_int	num_control_deny_groups;
+	char	*control_deny_groups[MAX_CONTROL_ALLOW_USERS];
 
 	int	hash_known_hosts;
 
diff -Naur openssh-4.7p1.orig/regress/forwarding.sh openssh-4.7p1-streamlocal/regress/forwarding.sh
--- openssh-4.7p1.orig/regress/forwarding.sh	2006-07-24 08:31:42.000000000 +0300
+++ openssh-4.7p1-streamlocal/regress/forwarding.sh	2009-08-29 18:28:30.000000000 +0300
@@ -93,3 +93,18 @@
 	fi
 	sleep 10
 done
+
+trace "transfer over chained unix domain socket forwards and check result"
+rm -f $OBJ/unix-1.fwd
+rm -f $OBJ/unix-2.fwd
+rm -f $OBJ/unix-3.fwd
+${SSH} -F $OBJ/ssh_config -f -R127.0.0.1:${base}01:[$OBJ/unix-1.fwd] somehost sleep 10
+${SSH} -F $OBJ/ssh_config -f -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10
+${SSH} -F $OBJ/ssh_config -f -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10
+${SSH} -F $OBJ/ssh_config -f -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost sleep 10
+${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=4' \
+	somehost cat $DATA > $OBJ/ls.copy
+test -f $OBJ/ls.copy			|| fail "failed copy $DATA"
+cmp $DATA $OBJ/ls.copy			|| fail "corrupted copy of $DATA"
+
+sleep 10
diff -Naur openssh-4.7p1.orig/scp.0 openssh-4.7p1-streamlocal/scp.0
--- openssh-4.7p1.orig/scp.0	2007-09-04 09:50:09.000000000 +0300
+++ openssh-4.7p1-streamlocal/scp.0	2009-08-29 18:28:30.000000000 +0300
@@ -70,6 +70,11 @@
                    ConnectTimeout
                    ControlMaster
                    ControlPath
+                   ControlBindMask
+                   ControlAllowUsers
+                   ControlAllowGroups
+                   ControlDenyUsers
+                   ControlDenyGroups
                    GlobalKnownHostsFile
                    GSSAPIAuthentication
                    GSSAPIDelegateCredentials
diff -Naur openssh-4.7p1.orig/scp.1 openssh-4.7p1-streamlocal/scp.1
--- openssh-4.7p1.orig/scp.1	2007-08-08 07:29:58.000000000 +0300
+++ openssh-4.7p1-streamlocal/scp.1	2009-08-29 18:28:30.000000000 +0300
@@ -130,6 +130,11 @@
 .It ConnectTimeout
 .It ControlMaster
 .It ControlPath
+.It ControlBindMask
+.It ControlAllowUsers
+.It ControlAllowGroups
+.It ControlDenyUsers
+.It ControlDenyGroups
 .It GlobalKnownHostsFile
 .It GSSAPIAuthentication
 .It GSSAPIDelegateCredentials
diff -Naur openssh-4.7p1.orig/servconf.c openssh-4.7p1-streamlocal/servconf.c
--- openssh-4.7p1.orig/servconf.c	2007-05-20 08:03:16.000000000 +0300
+++ openssh-4.7p1-streamlocal/servconf.c	2009-08-29 18:28:30.000000000 +0300
@@ -122,6 +122,9 @@
 	options->permit_tun = -1;
 	options->num_permitted_opens = -1;
 	options->adm_forced_command = NULL;
+	options->streamlocal_bind_mask = 0177;
+	options->streamlocal_bind_unlink = -1;
+	options->protocol_banner = NULL;
 }
 
 void
@@ -249,6 +252,8 @@
 		options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
 	if (options->permit_tun == -1)
 		options->permit_tun = SSH_TUNMODE_NO;
+	if (options->streamlocal_bind_unlink == -1)
+		options->streamlocal_bind_unlink = 0;
 
 	/* Turn privilege separation on by default */
 	if (use_privsep == -1)
@@ -291,6 +296,8 @@
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
+	sStreamLocalBindMask, sStreamLocalBindUnlink,
+	sProtocolBanner,
 	sMatch, sPermitOpen, sForceCommand,
 	sUsePrivilegeSeparation,
 	sDeprecated, sUnsupported
@@ -316,7 +323,7 @@
 	/* Standard Options */
 	{ "port", sPort, SSHCFG_GLOBAL },
 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
-	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
+	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },					/* alias */
 	{ "pidfile", sPidFile, SSHCFG_GLOBAL },
 	{ "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
 	{ "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
@@ -366,7 +373,7 @@
 	{ "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
 	{ "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
 	{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
-	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
+	{ "x11forwarding", sX11Forwarding, SSHCFG_ALL, },
 	{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
 	{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
 	{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
@@ -377,7 +384,7 @@
 	{ "compression", sCompression, SSHCFG_GLOBAL },
 	{ "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
 	{ "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },	/* obsolete alias */
-	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
+	{ "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_GLOBAL },
 	{ "allowusers", sAllowUsers, SSHCFG_GLOBAL },
 	{ "denyusers", sDenyUsers, SSHCFG_GLOBAL },
 	{ "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
@@ -403,6 +410,9 @@
  	{ "match", sMatch, SSHCFG_ALL },
 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
+	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_GLOBAL },
+	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_GLOBAL },
+	{ "protocolbanner", sProtocolBanner, SSHCFG_GLOBAL },
 	{ NULL, sBadOption, 0 }
 };
 
@@ -619,7 +629,7 @@
     const char *filename, int linenum, int *activep, const char *user,
     const char *host, const char *address)
 {
-	char *cp, **charptr, *arg, *p;
+	char *cp, **charptr, *endofnumber, *arg, *p;
 	int cmdline = 0, *intptr, value, n;
 	ServerOpCodes opcode;
 	u_short port;
@@ -1203,6 +1213,25 @@
 			*intptr = value;
 		break;
 
+	case sStreamLocalBindMask:
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing StreamLocalBindMask argument.",
+			    filename, linenum);
+		value = strtol(arg, &endofnumber, 0);
+		if (*endofnumber != '\0' || value < 0 || value > 0777)
+			fatal("%.200s line %d: Bad mask.", filename, linenum);
+		options->streamlocal_bind_mask = value;
+		break;
+
+	case sStreamLocalBindUnlink:
+		intptr = &options->streamlocal_bind_unlink;
+		goto parse_flag;
+
+	case sProtocolBanner:
+		charptr = &options->protocol_banner;
+		goto parse_filename;
+
 	case sMatch:
 		if (cmdline)
 			fatal("Match directive not supported as a command-line "
diff -Naur openssh-4.7p1.orig/servconf.h openssh-4.7p1-streamlocal/servconf.h
--- openssh-4.7p1.orig/servconf.h	2007-02-19 13:25:38.000000000 +0200
+++ openssh-4.7p1-streamlocal/servconf.h	2009-08-29 18:28:30.000000000 +0300
@@ -36,7 +36,7 @@
 
 #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
 
-typedef struct {
+typedef struct ServerOptions {
 	u_int num_ports;
 	u_int ports_from_cmdline;
 	u_short ports[MAX_PORTS];	/* Port number to listen on. */
@@ -141,6 +141,14 @@
 	int	permit_tun;
 
 	int	num_permitted_opens;
+
+	mode_t	streamlocal_bind_mask;	/*
+					 * Mask to use when binding forwarded
+					 * domain sockets.
+					 */
+	int	streamlocal_bind_unlink;/* Attempt unlink before binding? */
+
+	char	*protocol_banner;
 }       ServerOptions;
 
 void	 initialize_server_options(ServerOptions *);
diff -Naur openssh-4.7p1.orig/serverloop.c openssh-4.7p1-streamlocal/serverloop.c
--- openssh-4.7p1.orig/serverloop.c	2007-01-29 01:16:28.000000000 +0200
+++ openssh-4.7p1-streamlocal/serverloop.c	2009-08-29 18:28:30.000000000 +0300
@@ -941,6 +941,7 @@
 	int sock;
 	char *target, *originator;
 	int target_port, originator_port;
+	SocketName name;
 
 	target = packet_get_string(NULL);
 	target_port = packet_get_int();
@@ -952,7 +953,8 @@
 	    originator, originator_port, target, target_port);
 
 	/* XXX check permission */
-	sock = channel_connect_to(target, target_port);
+	SOCKETNAME_INIT_TCPIP(&name, target, target_port);
+	sock = channel_connect_to(&name);
 	xfree(target);
 	xfree(originator);
 	if (sock < 0)
@@ -964,6 +966,36 @@
 }
 
 static Channel *
+server_request_direct_streamlocal(void)
+{
+	Channel *c;
+	int sock;
+	char *target, *originator;
+	int originator_port;
+	SocketName name;
+
+	target = packet_get_string(NULL);
+	originator = packet_get_string(NULL);
+	originator_port = packet_get_int();
+	packet_check_eom();
+
+	debug("server_request_direct_streamlocal: originator %s port %d, target %s",
+	    originator, originator_port, target);
+
+	/* XXX check permission */
+	SOCKETNAME_INIT_STREAMLOCAL(&name, target);
+	sock = channel_connect_to(&name);
+	xfree(target);
+	xfree(originator);
+	if (sock < 0)
+		return NULL;
+	c = channel_new("direct-streamlocal@openssh.com", SSH_CHANNEL_CONNECTING,
+	    sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
+	    CHAN_TCP_PACKET_DEFAULT, 0, "direct-streamlocal", 1);
+	return c;
+}
+
+static Channel *
 server_request_tun(void)
 {
 	Channel *c = NULL;
@@ -1054,6 +1086,8 @@
 		c = server_request_session();
 	} else if (strcmp(ctype, "direct-tcpip") == 0) {
 		c = server_request_direct_tcpip();
+	} else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
+		c = server_request_direct_streamlocal();
 	} else if (strcmp(ctype, "tun@openssh.com") == 0) {
 		c = server_request_tun();
 	}
@@ -1090,6 +1124,8 @@
 	char *rtype;
 	int want_reply;
 	int success = 0;
+	SocketName name;
+	ForwardOptions fwd_opts;
 
 	rtype = packet_get_string(NULL);
 	want_reply = packet_get_char();
@@ -1120,8 +1156,10 @@
 			packet_send_debug("Server has disabled port forwarding.");
 		} else {
 			/* Start listening on the port */
+			SOCKETNAME_INIT_TCPIP(&name, listen_address, listen_port);
+			forward_options_init_from_server(&fwd_opts, &options);
 			success = channel_setup_remote_fwd_listener(
-			    listen_address, listen_port, options.gateway_ports);
+			    &name, &fwd_opts);
 		}
 		xfree(listen_address);
 	} else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
@@ -1133,9 +1171,39 @@
 		debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
 		    cancel_address, cancel_port);
 
-		success = channel_cancel_rport_listener(cancel_address,
-		    cancel_port);
+		SOCKETNAME_INIT_TCPIP(&name, cancel_address, cancel_port);
+		success = channel_cancel_rport_listener(&name);
 		xfree(cancel_address);
+	} else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
+		char *listen_path;
+
+		listen_path = packet_get_string(NULL);
+		debug("server_input_global_request: streamlocal-forward listen path %s",
+		    listen_path);
+
+		/* check permissions */
+		if (!options.allow_tcp_forwarding ||
+		    no_port_forwarding_flag
+		    ) {
+			success = 0;
+			packet_send_debug("Server has disabled port forwarding.");
+		} else {
+			/* Start listening on the port */
+			SOCKETNAME_INIT_STREAMLOCAL(&name, listen_path);
+			forward_options_init_from_server(&fwd_opts, &options);
+			success = channel_setup_remote_fwd_listener(
+			    &name, &fwd_opts);
+		}
+		xfree(listen_path);
+	} else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
+		char *cancel_path;
+
+		cancel_path = packet_get_string(NULL);
+		debug("%s: cancel-streamlocal-forward path %s", __func__,
+		    cancel_path);
+
+		SOCKETNAME_INIT_STREAMLOCAL(&name, cancel_path);
+		success = channel_cancel_rport_listener(&name);
 	}
 	if (want_reply) {
 		packet_start(success ?
diff -Naur openssh-4.7p1.orig/session.c openssh-4.7p1-streamlocal/session.c
--- openssh-4.7p1.orig/session.c	2007-08-16 16:28:04.000000000 +0300
+++ openssh-4.7p1-streamlocal/session.c	2009-08-29 18:28:30.000000000 +0300
@@ -260,6 +260,7 @@
 	int success, type, screen_flag;
 	int enable_compression_after_reply = 0;
 	u_int proto_len, data_len, dlen, compression_level = 0;
+	ForwardOptions fwd_opts;
 
 	s = session_new();
 	if (s == NULL) {
@@ -347,8 +348,9 @@
 				break;
 			}
 			debug("Received TCP/IP port forwarding request.");
+			forward_options_init_from_server(&fwd_opts, &options);
 			if (channel_input_port_forward_request(s->pw->pw_uid == 0,
-			    options.gateway_ports) < 0) {
+			    &fwd_opts) < 0) {
 				debug("Port forwarding failed.");
 				break;
 			}
diff -Naur openssh-4.7p1.orig/sftp.0 openssh-4.7p1-streamlocal/sftp.0
--- openssh-4.7p1.orig/sftp.0	2007-09-04 09:50:11.000000000 +0300
+++ openssh-4.7p1-streamlocal/sftp.0	2009-08-29 18:28:30.000000000 +0300
@@ -74,6 +74,11 @@
                    ConnectTimeout
                    ControlMaster
                    ControlPath
+                   ControlBindMask
+                   ControlAllowUsers
+                   ControlAllowGroups
+                   ControlDenyUsers
+                   ControlDenyGroups
                    GlobalKnownHostsFile
                    GSSAPIAuthentication
                    GSSAPIDelegateCredentials
diff -Naur openssh-4.7p1.orig/sftp.1 openssh-4.7p1-streamlocal/sftp.1
--- openssh-4.7p1.orig/sftp.1	2007-06-05 11:27:13.000000000 +0300
+++ openssh-4.7p1-streamlocal/sftp.1	2009-08-29 18:28:30.000000000 +0300
@@ -158,6 +158,11 @@
 .It ConnectTimeout
 .It ControlMaster
 .It ControlPath
+.It ControlBindMask
+.It ControlAllowUsers
+.It ControlAllowGroups
+.It ControlDenyUsers
+.It ControlDenyGroups
 .It GlobalKnownHostsFile
 .It GSSAPIAuthentication
 .It GSSAPIDelegateCredentials
diff -Naur openssh-4.7p1.orig/ssh.0 openssh-4.7p1-streamlocal/ssh.0
--- openssh-4.7p1.orig/ssh.0	2007-09-04 09:50:10.000000000 +0300
+++ openssh-4.7p1-streamlocal/ssh.0	2009-08-29 18:28:30.000000000 +0300
@@ -226,6 +226,11 @@
                    ConnectTimeout
                    ControlMaster
                    ControlPath
+                   ControlBindMask
+                   ControlAllowUsers
+                   ControlAllowGroups
+                   ControlDenyUsers
+                   ControlDenyGroups
                    DynamicForward
                    EscapeChar
                    ExitOnForwardFailure
diff -Naur openssh-4.7p1.orig/ssh.1 openssh-4.7p1-streamlocal/ssh.1
--- openssh-4.7p1.orig/ssh.1	2007-06-12 17:00:59.000000000 +0300
+++ openssh-4.7p1-streamlocal/ssh.1	2009-08-29 18:28:30.000000000 +0300
@@ -450,6 +450,11 @@
 .It ConnectTimeout
 .It ControlMaster
 .It ControlPath
+.It ControlBindMask
+.It ControlAllowUsers
+.It ControlAllowGroups
+.It ControlDenyUsers
+.It ControlDenyGroups
 .It DynamicForward
 .It EscapeChar
 .It ExitOnForwardFailure
diff -Naur openssh-4.7p1.orig/ssh.c openssh-4.7p1-streamlocal/ssh.c
--- openssh-4.7p1.orig/ssh.c	2007-08-08 07:32:41.000000000 +0300
+++ openssh-4.7p1-streamlocal/ssh.c	2009-08-29 18:28:30.000000000 +0300
@@ -813,23 +813,27 @@
 {
 	int success = 0;
 	int i;
+	SocketName listen_on, connect_to;
+	ForwardOptions fwd_options;
+
+	forward_options_init_from_client(&fwd_options, &options);
 
 	/* Initiate local TCP/IP port forwardings. */
 	for (i = 0; i < options.num_local_forwards; i++) {
-		debug("Local connections to %.200s:%d forwarded to remote "
-		    "address %.200s:%d",
-		    (options.local_forwards[i].listen_host == NULL) ?
-		    (options.gateway_ports ? "*" : "LOCALHOST") :
-		    options.local_forwards[i].listen_host,
-		    options.local_forwards[i].listen_port,
-		    options.local_forwards[i].connect_host,
-		    options.local_forwards[i].connect_port);
+		SOCKETNAME_INIT(&listen_on);
+		listen_on.host = options.local_forwards[i].listen_host;
+		listen_on.port = options.local_forwards[i].listen_port;
+		listen_on.path = options.local_forwards[i].listen_path;
+		SOCKETNAME_INIT(&connect_to);
+		connect_to.host = options.local_forwards[i].connect_host;
+		connect_to.port = options.local_forwards[i].connect_port;
+		connect_to.path = options.local_forwards[i].connect_path;
+		debug("Local connections to %.200s forwarded to remote "
+		    "address %.200s",
+		    SOCKETNAME_TOSTRING(&listen_on),
+		    SOCKETNAME_TOSTRING(&connect_to));
 		success += channel_setup_local_fwd_listener(
-		    options.local_forwards[i].listen_host,
-		    options.local_forwards[i].listen_port,
-		    options.local_forwards[i].connect_host,
-		    options.local_forwards[i].connect_port,
-		    options.gateway_ports);
+		    &listen_on, &connect_to, &fwd_options);
 	}
 	if (i > 0 && success != i && options.exit_on_forward_failure)
 		fatal("Could not request local forwarding.");
@@ -838,18 +842,20 @@
 
 	/* Initiate remote TCP/IP port forwardings. */
 	for (i = 0; i < options.num_remote_forwards; i++) {
-		debug("Remote connections from %.200s:%d forwarded to "
-		    "local address %.200s:%d",
-		    (options.remote_forwards[i].listen_host == NULL) ?
-		    "LOCALHOST" : options.remote_forwards[i].listen_host,
-		    options.remote_forwards[i].listen_port,
-		    options.remote_forwards[i].connect_host,
-		    options.remote_forwards[i].connect_port);
+		SOCKETNAME_INIT(&listen_on);
+		listen_on.host = options.remote_forwards[i].listen_host;
+		listen_on.port = options.remote_forwards[i].listen_port;
+		listen_on.path = options.remote_forwards[i].listen_path;
+		SOCKETNAME_INIT(&connect_to);
+		connect_to.host = options.remote_forwards[i].connect_host;
+		connect_to.port = options.remote_forwards[i].connect_port;
+		connect_to.path = options.remote_forwards[i].connect_path;
+		debug("Remote connections from %.200s forwarded to "
+		    "local address %.200s",
+		    SOCKETNAME_TOSTRING(&listen_on),
+		    SOCKETNAME_TOSTRING(&connect_to));
 		if (channel_request_remote_forwarding(
-		    options.remote_forwards[i].listen_host,
-		    options.remote_forwards[i].listen_port,
-		    options.remote_forwards[i].connect_host,
-		    options.remote_forwards[i].connect_port) < 0) {
+		    &listen_on, &connect_to) < 0) {
 			if (options.exit_on_forward_failure)
 				fatal("Could not request remote forwarding.");
 			else
@@ -1085,7 +1091,7 @@
 	if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
 		fatal("%s socket(): %s", __func__, strerror(errno));
 
-	old_umask = umask(0177);
+	old_umask = umask(options.control_bind_mask);
 	if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) {
 		control_fd = -1;
 		if (errno == EINVAL || errno == EADDRINUSE)
diff -Naur openssh-4.7p1.orig/ssh_config.0 openssh-4.7p1-streamlocal/ssh_config.0
--- openssh-4.7p1.orig/ssh_config.0	2007-09-04 09:50:12.000000000 +0300
+++ openssh-4.7p1-streamlocal/ssh_config.0	2009-08-29 18:28:30.000000000 +0300
@@ -163,6 +163,38 @@
              opportunistic connection sharing include at least %h, %p, and %r.
              This ensures that shared connections are uniquely identified.
 
+     ControlBindMask
+             Specify the umask to use when creating/binding the control
+             socket.
+
+     ControlAllowUsers
+             Specify a list of uid and/or user name patterns, separated by
+             spaces. control socket access is granted for non-process owner
+             users only if the requesting process has an effective uid of 0,
+             or if the effective uid/user name matches here or the effective
+             gid/group name matches ControlAllowGroups.
+
+     ControlAllowGroups
+             Specify a list of gid and/or group name patterns, separated by
+             spaces. control socket access is granted for non-process owner
+             users only if the requesting process has an effective uid of 0,
+             or if the effective gid/group name matches here or the 
+             effective uid/user name matches ControlAllowUsers.
+
+     ControlDenyUsers
+             Unless the requesting process has an effective uid of 0 or an
+             effective uid which matches the uid of the control master,
+             control socket access is denied if the effective uid/user name
+             matches here or the effective gid/group name matches
+             ControlDenyGroups.
+
+     ControlDenyGroups
+             Unless the requesting process has an effective uid of 0 or an
+             effective uid which matches the uid of the control master,
+             control socket access is denied if the effective gid/group name
+             matches here or the effective uid/user name matches
+             ControlDenyUsers.
+
      DynamicForward
              Specifies that a TCP port on the local machine be forwarded over
              the secure channel, and the application protocol is then used to
diff -Naur openssh-4.7p1.orig/ssh_config.5 openssh-4.7p1-streamlocal/ssh_config.5
--- openssh-4.7p1.orig/ssh_config.5	2007-08-15 15:20:22.000000000 +0300
+++ openssh-4.7p1-streamlocal/ssh_config.5	2009-08-29 18:28:30.000000000 +0300
@@ -318,6 +318,36 @@
 used for opportunistic connection sharing include
 at least %h, %p, and %r.
 This ensures that shared connections are uniquely identified.
+.It Cm ControlBindMask
+Specify the umask to use when creating/binding the control socket.
+.It Cm ControlAllowUsers
+Specify a list of uid and/or user name patterns, separated by spaces.
+control socket access is granted for non-process owner users only if the
+requesting process has an effective uid of 0, or if the effective uid/user
+name matches here or the effective gid/group name matches
+.Cm ControlAllowGroups
+.
+.It Cm ControlAllowGroups
+Specify a list of gid and/or group name patterns, separated by spaces.
+control socket access is granted for non-process owner users only if the
+requesting process has an effective uid of 0, or if the effective gid/group
+name matches here or the effective uid/user name matches
+.Cm ControlAllowUsers
+.
+.It Cm ControlDenyUsers
+Unless the requesting process has an effective uid of 0 or an effective uid
+which matches the uid of the control master, control socket access is denied
+if the effective uid/user name matches here or the effective gid/group name
+matches
+.Cm ControlDenyGroups
+.
+.It Cm ControlDenyGroups
+Unless the requesting process has an effective uid of 0 or an effective uid
+which matches the uid of the control master, control socket access is denied
+if the effective gid/group name matches here or the effective uid/user name
+matches
+.Cm ControlDenyUsers
+.
 .It Cm DynamicForward
 Specifies that a TCP port on the local machine be forwarded
 over the secure channel, and the application
diff -Naur openssh-4.7p1.orig/sshd.c openssh-4.7p1-streamlocal/sshd.c
--- openssh-4.7p1.orig/sshd.c	2007-06-05 11:22:32.000000000 +0300
+++ openssh-4.7p1-streamlocal/sshd.c	2009-08-29 18:28:30.000000000 +0300
@@ -419,7 +419,11 @@
 		major = PROTOCOL_MAJOR_1;
 		minor = PROTOCOL_MINOR_1;
 	}
-	snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+	if (options.protocol_banner != NULL) {
+		snprintf(buf, sizeof buf, "%s\n", options.protocol_banner);
+	} else {
+		snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+	}
 	server_version_string = xstrdup(buf);
 
 	/* Send our protocol version identification. */
