Add support for Unix domain socket forwarding. A remote TCP port
authormillert <millert@openbsd.org>
Tue, 15 Jul 2014 15:54:14 +0000 (15:54 +0000)
committermillert <millert@openbsd.org>
Tue, 15 Jul 2014 15:54:14 +0000 (15:54 +0000)
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@

40 files changed:
regress/usr.bin/ssh/forwarding.sh
regress/usr.bin/ssh/multiplex.sh
usr.bin/ssh/PROTOCOL
usr.bin/ssh/auth-options.c
usr.bin/ssh/auth-passwd.c
usr.bin/ssh/auth-rh-rsa.c
usr.bin/ssh/auth-rhosts.c
usr.bin/ssh/auth-rsa.c
usr.bin/ssh/auth.c
usr.bin/ssh/auth1.c
usr.bin/ssh/auth2-hostbased.c
usr.bin/ssh/auth2-kbdint.c
usr.bin/ssh/auth2-none.c
usr.bin/ssh/auth2-passwd.c
usr.bin/ssh/auth2-pubkey.c
usr.bin/ssh/auth2.c
usr.bin/ssh/canohost.c
usr.bin/ssh/channels.c
usr.bin/ssh/channels.h
usr.bin/ssh/clientloop.c
usr.bin/ssh/misc.c
usr.bin/ssh/misc.h
usr.bin/ssh/monitor.c
usr.bin/ssh/mux.c
usr.bin/ssh/packet.c
usr.bin/ssh/readconf.c
usr.bin/ssh/readconf.h
usr.bin/ssh/servconf.c
usr.bin/ssh/servconf.h
usr.bin/ssh/serverloop.c
usr.bin/ssh/session.c
usr.bin/ssh/ssh-agent.c
usr.bin/ssh/ssh.c
usr.bin/ssh/ssh_config.5
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshconnect1.c
usr.bin/ssh/sshconnect2.c
usr.bin/ssh/sshd.c
usr.bin/ssh/sshd_config.5
usr.bin/ssh/sshlogin.c

index f9c261b..12307e5 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: forwarding.sh,v 1.11 2013/06/10 21:56:43 dtucker Exp $
+#      $OpenBSD: forwarding.sh,v 1.12 2014/07/15 15:54:15 millert Exp $
 #      Placed in the Public Domain.
 
 tid="local and remote forwarding"
@@ -26,7 +26,7 @@ for p in 1 2; do
        trace "transfer over forwarded channels and check result"
        ${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \
                somehost cat ${DATA} > ${COPY}
-       test -f ${COPY}         || fail "failed copy of ${DATA}"
+       test -s ${COPY}         || fail "failed copy of ${DATA}"
        cmp ${DATA} ${COPY}     || fail "corrupted copy of ${DATA}"
 
        sleep 10
@@ -112,8 +112,24 @@ for p in 1 2; do
        trace "config file: transfer over forwarded channels and check result"
        ${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=4' \
                somehost cat ${DATA} > ${COPY}
-       test -f ${COPY}         || fail "failed copy of ${DATA}"
+       test -s ${COPY}         || fail "failed copy of ${DATA}"
        cmp ${DATA} ${COPY}     || fail "corrupted copy of ${DATA}"
 
        wait
 done
+
+for p in 2; do
+       trace "transfer over chained unix domain socket forwards and check result"
+       rm -f $OBJ/unix-[123].fwd
+       ${SSH} -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehost sleep 10
+       ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10
+       ${SSH} -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10
+       ${SSH} -f -F $OBJ/ssh_config -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} > ${COPY}
+       test -s ${COPY}                 || fail "failed copy ${DATA}"
+       cmp ${DATA} ${COPY}             || fail "corrupted copy of ${DATA}"
+
+       #wait
+       sleep 10
+done
index 6bceb3f..8e51f50 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: multiplex.sh,v 1.23 2014/07/07 08:15:26 djm Exp $
+#      $OpenBSD: multiplex.sh,v 1.24 2014/07/15 15:54:15 millert Exp $
 #      Placed in the Public Domain.
 
 CTL=$OBJ/ctl-sock
@@ -67,6 +67,25 @@ test -f ${COPY}                      || fail "scp: failed copy ${DATA}"
 cmp ${DATA} ${COPY}            || fail "scp: corrupted copy of ${DATA}"
 
 rm -f ${COPY}
+verbose "test $tid: forward"
+trace "forward over TCP/IP and check result"
+nc -N -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} &
+netcat_pid=$!
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1
+nc 127.0.0.1 $((${PORT} + 2)) > ${COPY}
+cmp ${DATA} ${COPY}            || fail "ssh: corrupted copy of ${DATA}"
+kill $netcat_pid 2>/dev/null
+rm -f ${COPY} $OBJ/unix-[123].fwd
+
+trace "forward over UNIX and check result"
+nc -N -Ul $OBJ/unix-1.fwd < ${DATA} &
+netcat_pid=$!
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1
+nc -U $OBJ/unix-3.fwd > ${COPY}
+cmp ${DATA} ${COPY}            || fail "ssh: corrupted copy of ${DATA}"
+kill $netcat_pid 2>/dev/null
+rm -f ${COPY} $OBJ/unix-[123].fwd
 
 for s in 0 1 4 5 44; do
        trace "exit status $s over multiplexed connection"
@@ -91,7 +110,7 @@ verbose "test $tid: cmd check"
 ${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
     || fail "check command failed" 
 
-verbose "test $tid: cmd forward local"
+verbose "test $tid: cmd forward local (TCP)"
 ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $P:localhost:$PORT otherhost \
      || fail "request local forward failed"
 ${SSH} -F $OBJ/ssh_config -p$P otherhost true \
@@ -101,7 +120,7 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $P:localhost:$PORT otherhost \
 ${SSH} -F $OBJ/ssh_config -p$P otherhost true \
      && fail "local forward port still listening"
 
-verbose "test $tid: cmd forward remote"
+verbose "test $tid: cmd forward remote (TCP)"
 ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $P:localhost:$PORT otherhost \
      || fail "request remote forward failed"
 ${SSH} -F $OBJ/ssh_config -p$P otherhost true \
@@ -111,6 +130,28 @@ ${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $P:localhost:$PORT otherhost \
 ${SSH} -F $OBJ/ssh_config -p$P otherhost true \
      && fail "remote forward port still listening"
 
+verbose "test $tid: cmd forward local (UNIX)"
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+     || fail "request local forward failed"
+echo "" | nc -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
+     || fail "connect to local forward path failed"
+${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -L $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+     || fail "cancel local forward failed"
+N=$(echo "" | nc -U $OBJ/unix-1.fwd 2>&1 | wc -l)
+test ${N} -eq 0 || fail "local forward path still listening"
+rm -f $OBJ/unix-1.fwd
+
+verbose "test $tid: cmd forward remote (UNIX)"
+${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+     || fail "request remote forward failed"
+echo "" | nc -U $OBJ/unix-1.fwd | grep "Protocol mismatch" >/dev/null 2>&1 \
+     || fail "connect to remote forwarded path failed"
+${SSH} -F $OBJ/ssh_config -S $CTL -Ocancel -R $OBJ/unix-1.fwd:localhost:$PORT otherhost \
+     || fail "cancel remote forward failed"
+N=$(echo "" | nc -U $OBJ/unix-1.fwd 2>&1 | wc -l)
+test ${N} -eq 0 || fail "remote forward path still listening"
+rm -f $OBJ/unix-1.fwd
+
 verbose "test $tid: cmd exit"
 ${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost >>$TEST_REGRESS_LOGFILE 2>&1 \
     || fail "send exit command failed" 
index 4a5088f..aa59f58 100644 (file)
@@ -232,6 +232,56 @@ The contents of the "data" field for layer 2 packets is:
 The "frame" field contains an IEEE 802.3 Ethernet frame, including
 header.
 
+2.4. connection: Unix domain socket forwarding
+
+OpenSSH supports local and remote Unix domain socket forwarding
+using the "streamlocal" extension.  Forwarding is initiated as per
+TCP sockets but with a single path instead of a host and port.
+
+Similar to direct-tcpip, direct-streamlocal is sent by the client
+to request that the server make a connection to a Unix domain socket.
+
+       byte            SSH_MSG_CHANNEL_OPEN
+       string          "direct-streamlocal@openssh.com"
+       uint32          sender channel
+       uint32          initial window size
+       uint32          maximum packet size
+       string          socket path
+       string          reserved for future use
+
+Similar to forwarded-tcpip, forwarded-streamlocal is sent by the
+server when the client has previously send the server a streamlocal-forward
+GLOBAL_REQUEST.
+
+       byte            SSH_MSG_CHANNEL_OPEN
+       string          "forwarded-streamlocal@openssh.com"
+       uint32          sender channel
+       uint32          initial window size
+       uint32          maximum packet size
+       string          socket path
+       string          reserved for future use
+
+The reserved field is not currently defined and is ignored on the
+remote end.  It is intended to be used in the future to pass
+information about the socket file, such as ownership and mode.
+The client currently sends the empty string for this field.
+
+Similar to tcpip-forward, streamlocal-forward is sent by the client
+to request remote forwarding of a Unix domain socket.
+
+       byte            SSH2_MSG_GLOBAL_REQUEST
+       string          "streamlocal-forward@openssh.com"
+       boolean         TRUE
+       string          socket path
+
+Similar to cancel-tcpip-forward, cancel-streamlocal-forward is sent
+by the client cancel the forwarding of a Unix domain socket.
+
+       byte            SSH2_MSG_GLOBAL_REQUEST
+       string          "cancel-streamlocal-forward@openssh.com"
+       boolean         FALSE
+       string          socket path
+
 3. SFTP protocol changes
 
 3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
@@ -356,4 +406,4 @@ respond with a SSH_FXP_STATUS message.
 This extension is advertised in the SSH_FXP_VERSION hello with version
 "1".
 
-$OpenBSD: PROTOCOL,v 1.23 2013/12/01 23:19:05 djm Exp $
+$OpenBSD: PROTOCOL,v 1.24 2014/07/15 15:54:14 millert Exp $
index 69abedf..7274e1d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.63 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.64 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -24,9 +24,9 @@
 #include "log.h"
 #include "canohost.h"
 #include "buffer.h"
+#include "misc.h"
 #include "channels.h"
 #include "servconf.h"
-#include "misc.h"
 #include "key.h"
 #include "auth-options.h"
 #include "hostfile.h"
@@ -323,6 +323,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        patterns[i] = '\0';
                        opts++;
                        p = patterns;
+                       /* XXX - add streamlocal support */
                        host = hpdelim(&p);
                        if (host == NULL || strlen(host) >= NI_MAXHOST) {
                                debug("%.100s, line %lu: Bad permitopen "
index bf42a14..1346f8c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-passwd.c,v 1.43 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth-passwd.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -47,6 +47,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "key.h"
 #include "hostfile.h"
index d233e49..ea8f45d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */
+/* $OpenBSD: auth-rh-rsa.c,v 1.44 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -22,6 +22,7 @@
 #include "uidswap.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "key.h"
 #include "hostfile.h"
index 5257e6d..3843aaa 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */
+/* $OpenBSD: auth-rhosts.c,v 1.45 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include "uidswap.h"
 #include "pathnames.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "canohost.h"
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
-#include "misc.h"
 
 /* import */
 extern ServerOptions options;
index 32ffc62..d736d5a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rsa.c,v 1.87 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -32,6 +32,7 @@
 #include "buffer.h"
 #include "pathnames.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "key.h"
 #include "auth-options.h"
@@ -42,7 +43,6 @@
 #endif
 #include "monitor_wrap.h"
 #include "ssh.h"
-#include "misc.h"
 
 #include "digest.h"
 
index afde0c7..161b80b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.105 2014/07/03 11:16:55 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -43,6 +43,7 @@
 #include "groupaccess.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "key.h"
 #include "hostfile.h"
@@ -50,7 +51,6 @@
 #include "auth-options.h"
 #include "canohost.h"
 #include "uidswap.h"
-#include "misc.h"
 #include "packet.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
index 0b36151..4f4a58a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth1.c,v 1.81 2014/07/03 11:16:55 djm Exp $ */
+/* $OpenBSD: auth1.c,v 1.82 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -24,6 +24,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "key.h"
index ae776c1..17d382a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.17 2013/12/30 23:52:27 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -35,6 +35,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "key.h"
index 2a6e4c8..2c3203c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-kbdint.c,v 1.6 2013/05/17 00:13:13 djm Exp $ */
+/* $OpenBSD: auth2-kbdint.c,v 1.7 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -32,6 +32,7 @@
 #include "auth.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 
 /* import */
index 7146a95..5b45185 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-none.c,v 1.17 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: auth2-none.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -34,6 +34,7 @@
 #include "packet.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "ssh2.h"
index ae11d1f..4fa7dfb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-passwd.c,v 1.11 2014/02/02 03:44:31 djm Exp $ */
+/* $OpenBSD: auth2-passwd.c,v 1.12 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -39,6 +39,7 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "misc.h"
 #include "servconf.h"
 
 /* import */
index 124fcd8..c4b05ed 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.40 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -45,6 +45,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "key.h"
@@ -58,7 +59,6 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
-#include "misc.h"
 #include "authfile.h"
 #include "match.h"
 
index 4767e6e..cf6443d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.131 2014/07/03 11:16:55 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.132 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -40,6 +40,7 @@
 #include "packet.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "key.h"
index f3539d8..2f98510 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: canohost.c,v 1.70 2014/01/19 04:17:29 dtucker Exp $ */
+/* $OpenBSD: canohost.c,v 1.71 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -14,6 +14,7 @@
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 
 #include <netinet/in.h>
 
@@ -222,6 +223,12 @@ get_socket_address(int sock, int remote, int flags)
                    < 0)
                        return NULL;
        }
+
+       if (addr.ss_family == AF_UNIX) {
+               /* Get the Unix domain socket path. */
+               return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
+       }
+
        /* Get the address in ascii. */
        if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
            sizeof(ntop), NULL, 0, flags)) != 0) {
@@ -337,6 +344,11 @@ get_sock_port(int sock, int local)
                        return -1;
                }
        }
+
+       /* Unix domain sockets don't have a port number. */
+       if (from.ss_family == AF_UNIX)
+               return 0;
+
        /* Return port number. */
        if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
            strport, sizeof(strport), NI_NUMERICSERV)) != 0)
index 8cd8c15..73c171d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.335 2014/07/05 23:11:48 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.336 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -40,6 +40,7 @@
  */
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/un.h>
 #include <sys/socket.h>
@@ -103,11 +104,15 @@ static int channel_max_fd = 0;
  * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
  * network (which might be behind a firewall).
  */
+/* XXX: streamlocal wants a path instead of host:port */
+/*      Overload host_to_connect; we could just make this match Forward */
+/*     XXX - can we use listen_host instead of listen_path? */
 typedef struct {
        char *host_to_connect;          /* Connect to 'host'. */
-       u_short port_to_connect;        /* Connect to 'port'. */
+       int port_to_connect;            /* Connect to 'port'. */
        char *listen_host;              /* Remote side should listen address. */
-       u_short listen_port;            /* Remote side should listen port. */
+       char *listen_path;              /* Remote side should listen path. */
+       int listen_port;                /* Remote side should listen port. */
 } ForwardPermission;
 
 /* List of all permitted host/port pairs to connect by the user. */
@@ -466,6 +471,8 @@ channel_stop_listening(void)
                        case SSH_CHANNEL_PORT_LISTENER:
                        case SSH_CHANNEL_RPORT_LISTENER:
                        case SSH_CHANNEL_X11_LISTENER:
+                       case SSH_CHANNEL_UNIX_LISTENER:
+                       case SSH_CHANNEL_RUNIX_LISTENER:
                                channel_close_fd(&c->sock);
                                channel_free(c);
                                break;
@@ -528,6 +535,8 @@ channel_still_open(void)
                case SSH_CHANNEL_CONNECTING:
                case SSH_CHANNEL_ZOMBIE:
                case SSH_CHANNEL_ABANDONED:
+               case SSH_CHANNEL_UNIX_LISTENER:
+               case SSH_CHANNEL_RUNIX_LISTENER:
                        continue;
                case SSH_CHANNEL_LARVAL:
                        if (!compat20)
@@ -574,6 +583,8 @@ channel_find_open(void)
                case SSH_CHANNEL_CONNECTING:
                case SSH_CHANNEL_ZOMBIE:
                case SSH_CHANNEL_ABANDONED:
+               case SSH_CHANNEL_UNIX_LISTENER:
+               case SSH_CHANNEL_RUNIX_LISTENER:
                        continue;
                case SSH_CHANNEL_LARVAL:
                case SSH_CHANNEL_AUTH_SOCKET:
@@ -624,6 +635,8 @@ channel_open_message(void)
                case SSH_CHANNEL_ABANDONED:
                case SSH_CHANNEL_MUX_CLIENT:
                case SSH_CHANNEL_MUX_LISTENER:
+               case SSH_CHANNEL_UNIX_LISTENER:
+               case SSH_CHANNEL_RUNIX_LISTENER:
                        continue;
                case SSH_CHANNEL_LARVAL:
                case SSH_CHANNEL_OPENING:
@@ -1379,7 +1392,6 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
 static void
 port_open_helper(Channel *c, char *rtype)
 {
-       int direct;
        char buf[1024];
        char *local_ipaddr = get_local_ipaddr(c->sock);
        int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1);
@@ -1393,8 +1405,6 @@ port_open_helper(Channel *c, char *rtype)
                remote_port = 65535;
        }
 
-       direct = (strcmp(rtype, "direct-tcpip") == 0);
-
        snprintf(buf, sizeof buf,
            "%s: listening port %d for %.100s port %d, "
            "connect from %.200s port %d to %.100s port %d",
@@ -1410,18 +1420,29 @@ port_open_helper(Channel *c, char *rtype)
                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(local_port);
                }
-               /* originator host and port */
-               packet_put_cstring(remote_ipaddr);
-               packet_put_int((u_int)remote_port);
+               if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
+                       /* reserved for future owner/mode info */
+                       packet_put_cstring("");
+               } 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);
@@ -1471,14 +1492,18 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
                if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
                        nextstate = SSH_CHANNEL_OPENING;
                        rtype = "forwarded-tcpip";
+               } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
+                       nextstate = SSH_CHANNEL_OPENING;
+                       rtype = "forwarded-streamlocal@openssh.com";
+               } else if (c->host_port == PORT_STREAMLOCAL) {
+                       nextstate = SSH_CHANNEL_OPENING;
+                       rtype = "direct-streamlocal@openssh.com";
+               } else if (c->host_port == 0) {
+                       nextstate = SSH_CHANNEL_DYNAMIC;
+                       rtype = "dynamic-tcpip";
                } else {
-                       if (c->host_port == 0) {
-                               nextstate = SSH_CHANNEL_DYNAMIC;
-                               rtype = "dynamic-tcpip";
-                       } else {
-                               nextstate = SSH_CHANNEL_OPENING;
-                               rtype = "direct-tcpip";
-                       }
+                       nextstate = SSH_CHANNEL_OPENING;
+                       rtype = "direct-tcpip";
                }
 
                addrlen = sizeof(addr);
@@ -1491,7 +1516,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
                                c->notbefore = monotime() + 1;
                        return;
                }
-               set_nodelay(newsock);
+               if (c->host_port != PORT_STREAMLOCAL)
+                       set_nodelay(newsock);
                nc = channel_new(rtype, nextstate, newsock, newsock, -1,
                    c->local_window_max, c->local_maxpacket, 0, rtype, 1);
                nc->listening_port = c->listening_port;
@@ -1963,6 +1989,8 @@ channel_handler_init_20(void)
        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;
@@ -1973,6 +2001,8 @@ channel_handler_init_20(void)
        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;
@@ -2613,7 +2643,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
                originator_string = xstrdup("unknown (remote did not supply name)");
        }
        packet_check_eom();
-       c = channel_connect_to(host, host_port,
+       c = channel_connect_to_port(host, host_port,
            "connected socket", originator_string);
        free(originator_string);
        free(host);
@@ -2680,20 +2710,20 @@ channel_set_af(int af)
  */
 static const char *
 channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
-    int is_client, int gateway_ports)
+    int is_client, struct ForwardOptions *fwd_opts)
 {
        const char *addr = NULL;
        int wildcard = 0;
 
        if (listen_addr == NULL) {
                /* No address specified: default to gateway_ports setting */
-               if (gateway_ports)
+               if (fwd_opts->gateway_ports)
                        wildcard = 1;
-       } else if (gateway_ports || is_client) {
+       } else if (fwd_opts->gateway_ports || is_client) {
                if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
                    strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
                    *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
-                   (!is_client && gateway_ports == 1)) {
+                   (!is_client && fwd_opts->gateway_ports == 1)) {
                        wildcard = 1;
                        /*
                         * Notify client if they requested a specific listen
@@ -2727,9 +2757,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
 }
 
 static int
-channel_setup_fwd_listener(int type, const char *listen_addr,
-    u_short listen_port, int *allocated_listen_port,
-    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
+    int *allocated_listen_port, struct ForwardOptions *fwd_opts)
 {
        Channel *c;
        int sock, r, success = 0, wildcard = 0, is_client;
@@ -2739,7 +2768,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
        in_port_t *lport_p;
 
        host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
-           listen_addr : host_to_connect;
+           fwd->listen_host : fwd->connect_host;
        is_client = (type == SSH_CHANNEL_PORT_LISTENER);
 
        if (host == NULL) {
@@ -2752,9 +2781,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
        }
 
        /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
-       addr = channel_fwd_bind_addr(listen_addr, &wildcard,
-           is_client, gateway_ports);
-       debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
+       addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard,
+           is_client, fwd_opts);
+       debug3("%s: type %d wildcard %d addr %s", __func__,
            type, wildcard, (addr == NULL) ? "NULL" : addr);
 
        /*
@@ -2765,15 +2794,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
        hints.ai_family = IPv4or6;
        hints.ai_flags = wildcard ? AI_PASSIVE : 0;
        hints.ai_socktype = SOCK_STREAM;
-       snprintf(strport, sizeof strport, "%d", listen_port);
+       snprintf(strport, sizeof strport, "%d", fwd->listen_port);
        if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
                if (addr == NULL) {
                        /* This really shouldn't happen */
                        packet_disconnect("getaddrinfo: fatal error: %s",
                            ssh_gai_strerror(r));
                } else {
-                       error("channel_setup_fwd_listener: "
-                           "getaddrinfo(%.64s): %s", addr,
+                       error("%s: getaddrinfo(%.64s): %s", __func__, addr,
                            ssh_gai_strerror(r));
                }
                return 0;
@@ -2797,13 +2825,13 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
                 * If allocating a port for -R forwards, then use the
                 * same port for all address families.
                 */
-               if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+               if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
                    allocated_listen_port != NULL && *allocated_listen_port > 0)
                        *lport_p = htons(*allocated_listen_port);
 
                if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
                    strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-                       error("channel_setup_fwd_listener: getnameinfo failed");
+                       error("%s: getnameinfo failed", __func__);
                        continue;
                }
                /* Create a port to listen for the host. */
@@ -2834,10 +2862,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
                }
 
                /*
-                * listen_port == 0 requests a dynamically allocated port -
+                * fwd->listen_port == 0 requests a dynamically allocated port -
                 * record what we got.
                 */
-               if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+               if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
                    allocated_listen_port != NULL &&
                    *allocated_listen_port == 0) {
                        *allocated_listen_port = get_sock_port(sock, 1);
@@ -2850,24 +2878,98 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
                    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
                    0, "port listener", 1);
                c->path = xstrdup(host);
-               c->host_port = port_to_connect;
+               c->host_port = fwd->connect_port;
                c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
-               if (listen_port == 0 && allocated_listen_port != NULL &&
+               if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
                    !(datafellows & SSH_BUG_DYNAMIC_RPORT))
                        c->listening_port = *allocated_listen_port;
                else
-                       c->listening_port = listen_port;
+                       c->listening_port = fwd->listen_port;
                success = 1;
        }
        if (success == 0)
-               error("channel_setup_fwd_listener: cannot listen to port: %d",
-                   listen_port);
+               error("%s: cannot listen to port: %d", __func__,
+                   fwd->listen_port);
        freeaddrinfo(aitop);
        return success;
 }
 
-int
-channel_cancel_rport_listener(const char *host, u_short port)
+static int
+channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
+    struct ForwardOptions *fwd_opts)
+{
+       struct sockaddr_un sunaddr;
+       const char *path;
+       Channel *c;
+       int port, sock;
+       mode_t omask;
+
+       switch (type) {
+       case SSH_CHANNEL_UNIX_LISTENER:
+               if (fwd->connect_path != NULL) {
+                       if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
+                               error("Local connecting path too long: %s",
+                                   fwd->connect_path);
+                               return 0;
+                       }
+                       path = fwd->connect_path;
+                       port = PORT_STREAMLOCAL;
+               } else {
+                       if (fwd->connect_host == NULL) {
+                               error("No forward host name.");
+                               return 0;
+                       }
+                       if (strlen(fwd->connect_host) >= NI_MAXHOST) {
+                               error("Forward host name too long.");
+                               return 0;
+                       }
+                       path = fwd->connect_host;
+                       port = fwd->connect_port;
+               }
+               break;
+       case SSH_CHANNEL_RUNIX_LISTENER:
+               path = fwd->listen_path;
+               port = PORT_STREAMLOCAL;
+               break;
+       default:
+               error("%s: unexpected channel type %d", __func__, type);
+               return 0;
+       }
+
+       if (fwd->listen_path == NULL) {
+               error("No forward path name.");
+               return 0;
+       }
+       if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
+               error("Local listening path too long: %s", fwd->listen_path);
+               return 0;
+       }
+
+       debug3("%s: type %d path %s", __func__, type, fwd->listen_path);
+
+       /* Start a Unix domain listener. */
+       omask = umask(fwd_opts->streamlocal_bind_mask);
+       sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
+           fwd_opts->streamlocal_bind_unlink);
+       umask(omask);
+       if (sock < 0)
+               return 0;
+
+       debug("Local forwarding listening on path %s.", fwd->listen_path);
+
+       /* Allocate a channel number for the socket. */
+       c = channel_new("unix listener", type, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+           0, "unix listener", 1);
+       c->path = xstrdup(path);
+       c->host_port = port;
+       c->listening_port = PORT_STREAMLOCAL;
+       c->listening_addr = xstrdup(fwd->listen_path);
+       return 1;
+}
+
+static int
+channel_cancel_rport_listener_tcpip(const char *host, u_short port)
 {
        u_int i;
        int found = 0;
@@ -2886,13 +2988,44 @@ channel_cancel_rport_listener(const char *host, u_short port)
        return (found);
 }
 
+static int
+channel_cancel_rport_listener_streamlocal(const char *path)
+{
+       u_int i;
+       int found = 0;
+
+       for (i = 0; i < channels_alloc; i++) {
+               Channel *c = channels[i];
+               if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
+                       continue;
+               if (c->path == NULL)
+                       continue;
+               if (strcmp(c->path, path) == 0) {
+                       debug2("%s: close channel %d", __func__, i);
+                       channel_free(c);
+                       found = 1;
+               }
+       }
+
+       return (found);
+}
+
 int
-channel_cancel_lport_listener(const char *lhost, u_short lport,
-    int cport, int gateway_ports)
+channel_cancel_rport_listener(struct Forward *fwd)
+{
+       if (fwd->listen_path != NULL)
+               return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
+       else
+               return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
+}
+
+static int
+channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
+    int cport, struct ForwardOptions *fwd_opts)
 {
        u_int i;
        int found = 0;
-       const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
+       const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
 
        for (i = 0; i < channels_alloc; i++) {
                Channel *c = channels[i];
@@ -2921,24 +3054,68 @@ channel_cancel_lport_listener(const char *lhost, u_short lport,
        return (found);
 }
 
+static int
+channel_cancel_lport_listener_streamlocal(const char *path)
+{
+       u_int i;
+       int found = 0;
+
+       if (path == NULL) {
+               error("%s: no path specified.", __func__);
+               return 0;
+       }
+
+       for (i = 0; i < channels_alloc; i++) {
+               Channel *c = channels[i];
+               if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
+                       continue;
+               if (c->listening_addr == NULL)
+                       continue;
+               if (strcmp(c->listening_addr, path) == 0) {
+                       debug2("%s: close channel %d", __func__, i);
+                       channel_free(c);
+                       found = 1;
+               }
+       }
+
+       return (found);
+}
+
+int
+channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
+{
+       if (fwd->listen_path != NULL)
+               return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
+       else
+               return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
+}
+
 /* 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(struct Forward *fwd, struct ForwardOptions *fwd_opts)
 {
-       return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
-           listen_host, listen_port, NULL, host_to_connect, port_to_connect,
-           gateway_ports);
+       if (fwd->listen_path != NULL) {
+               return channel_setup_fwd_listener_streamlocal(
+                   SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
+       } else {
+               return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
+                   fwd, NULL, fwd_opts);
+       }
 }
 
 /* protocol v2 remote port fwd, used by sshd */
 int
-channel_setup_remote_fwd_listener(const char *listen_address,
-    u_short listen_port, int *allocated_listen_port, int gateway_ports)
+channel_setup_remote_fwd_listener(struct Forward *fwd,
+    int *allocated_listen_port, struct ForwardOptions *fwd_opts)
 {
-       return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
-           listen_address, listen_port, allocated_listen_port,
-           NULL, 0, gateway_ports);
+       if (fwd->listen_path != NULL) {
+               return channel_setup_fwd_listener_streamlocal(
+                   SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
+       } else {
+               return channel_setup_fwd_listener_tcpip(
+                   SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
+                   fwd_opts);
+       }
 }
 
 /*
@@ -2969,27 +3146,32 @@ channel_rfwd_bind_host(const char *listen_host)
  * channel_update_permitted_opens().
  */
 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(struct Forward *fwd)
 {
        int type, success = 0, idx = -1;
 
        /* Send the forward request to the remote side. */
        if (compat20) {
                packet_start(SSH2_MSG_GLOBAL_REQUEST);
-               packet_put_cstring("tcpip-forward");
-               packet_put_char(1);             /* boolean: want reply */
-               packet_put_cstring(channel_rfwd_bind_host(listen_host));
-               packet_put_int(listen_port);
+               if (fwd->listen_path != NULL) {
+                   packet_put_cstring("streamlocal-forward@openssh.com");
+                   packet_put_char(1);         /* boolean: want reply */
+                   packet_put_cstring(fwd->listen_path);
+               } else {
+                   packet_put_cstring("tcpip-forward");
+                   packet_put_char(1);         /* boolean: want reply */
+                   packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
+                   packet_put_int(fwd->listen_port);
+               }
                packet_send();
                packet_write_wait();
                /* Assume that server accepts the request */
                success = 1;
-       } else {
+       } else if (fwd->listen_path == NULL) {
                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(fwd->listen_port);
+               packet_put_cstring(fwd->connect_host);
+               packet_put_int(fwd->connect_port);
                packet_send();
                packet_write_wait();
 
@@ -3006,24 +3188,43 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
                        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) {
                /* Record that connection to this host/port is permitted. */
                permitted_opens = xrealloc(permitted_opens,
                    num_permitted_opens + 1, sizeof(*permitted_opens));
                idx = num_permitted_opens++;
-               permitted_opens[idx].host_to_connect = xstrdup(host_to_connect);
-               permitted_opens[idx].port_to_connect = port_to_connect;
-               permitted_opens[idx].listen_host = listen_host ?
-                   xstrdup(listen_host) : NULL;
-               permitted_opens[idx].listen_port = listen_port;
+               if (fwd->connect_path != NULL) {
+                       permitted_opens[idx].host_to_connect =
+                           xstrdup(fwd->connect_path);
+                       permitted_opens[idx].port_to_connect =
+                           PORT_STREAMLOCAL;
+               } else {
+                       permitted_opens[idx].host_to_connect =
+                           xstrdup(fwd->connect_host);
+                       permitted_opens[idx].port_to_connect =
+                           fwd->connect_port;
+               }
+               if (fwd->listen_path != NULL) {
+                       permitted_opens[idx].listen_host = NULL;
+                       permitted_opens[idx].listen_path =
+                           xstrdup(fwd->listen_path);
+                       permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
+               } else {
+                       permitted_opens[idx].listen_host =
+                           fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
+                       permitted_opens[idx].listen_path = NULL;
+                       permitted_opens[idx].listen_port = fwd->listen_port;
+               }
        }
        return (idx);
 }
 
 static int
 open_match(ForwardPermission *allowed_open, const char *requestedhost,
-    u_short requestedport)
+    int requestedport)
 {
        if (allowed_open->host_to_connect == NULL)
                return 0;
@@ -3036,14 +3237,14 @@ open_match(ForwardPermission *allowed_open, const char *requestedhost,
 }
 
 /*
- * Note that in he listen host/port case
+ * Note that in the listen host/port case
  * we don't support FWD_PERMIT_ANY_PORT and
  * need to translate between the configured-host (listen_host)
  * and what we've sent to the remote server (channel_rfwd_bind_host)
  */
 static int
-open_listen_match(ForwardPermission *allowed_open, const char *requestedhost,
-    u_short requestedport, int translate)
+open_listen_match_tcpip(ForwardPermission *allowed_open,
+    const char *requestedhost, u_short requestedport, int translate)
 {
        const char *allowed_host;
 
@@ -3063,12 +3264,26 @@ open_listen_match(ForwardPermission *allowed_open, const char *requestedhost,
        return 1;
 }
 
+static int
+open_listen_match_streamlocal(ForwardPermission *allowed_open,
+    const char *requestedpath)
+{
+       if (allowed_open->host_to_connect == NULL)
+               return 0;
+       if (allowed_open->listen_port != PORT_STREAMLOCAL)
+               return 0;
+       if (allowed_open->listen_path == NULL ||
+           strcmp(allowed_open->listen_path, requestedpath) != 0)
+               return 0;
+       return 1;
+}
+
 /*
  * Request cancellation of remote forwarding of connection host:port from
  * local side.
  */
-int
-channel_request_rforward_cancel(const char *host, u_short port)
+static int
+channel_request_rforward_cancel_tcpip(const char *host, u_short port)
 {
        int i;
 
@@ -3076,7 +3291,7 @@ channel_request_rforward_cancel(const char *host, u_short port)
                return -1;
 
        for (i = 0; i < num_permitted_opens; i++) {
-               if (open_listen_match(&permitted_opens[i], host, port, 0))
+               if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
                        break;
        }
        if (i >= num_permitted_opens) {
@@ -3090,50 +3305,102 @@ channel_request_rforward_cancel(const char *host, u_short port)
        packet_put_int(port);
        packet_send();
 
-       permitted_opens[i].port_to_connect = 0;
        permitted_opens[i].listen_port = 0;
+       permitted_opens[i].port_to_connect = 0;
        free(permitted_opens[i].host_to_connect);
        permitted_opens[i].host_to_connect = NULL;
        free(permitted_opens[i].listen_host);
        permitted_opens[i].listen_host = NULL;
+       permitted_opens[i].listen_path = NULL;
+
+       return 0;
+}
+
+/*
+ * Request cancellation of remote forwarding of Unix domain socket
+ * path from local side.
+ */
+static int
+channel_request_rforward_cancel_streamlocal(const char *path)
+{
+       int i;
+
+       if (!compat20)
+               return -1;
+
+       for (i = 0; i < num_permitted_opens; i++) {
+               if (open_listen_match_streamlocal(&permitted_opens[i], path))
+                       break;
+       }
+       if (i >= num_permitted_opens) {
+               debug("%s: requested forward not found", __func__);
+               return -1;
+       }
+       packet_start(SSH2_MSG_GLOBAL_REQUEST);
+       packet_put_cstring("cancel-streamlocal-forward@openssh.com");
+       packet_put_char(0);
+       packet_put_cstring(path);
+       packet_send();
+
+       permitted_opens[i].listen_port = 0;
+       permitted_opens[i].port_to_connect = 0;
+       free(permitted_opens[i].host_to_connect);
+       permitted_opens[i].host_to_connect = NULL;
+       permitted_opens[i].listen_host = NULL;
+       free(permitted_opens[i].listen_path);
+       permitted_opens[i].listen_path = NULL;
 
        return 0;
 }
 
+/*
+ * Request cancellation of remote forwarding of a connection from local side.
+ */
+int
+channel_request_rforward_cancel(struct Forward *fwd)
+{
+       if (fwd->listen_path != NULL) {
+               return (channel_request_rforward_cancel_streamlocal(
+                   fwd->listen_path));
+       } else {
+               return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
+                   fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
+       }
+}
+
 /*
  * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
  * listening for the port, and sends back a success reply (or disconnect
  * 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, struct ForwardOptions *fwd_opts)
 {
-       u_short port, host_port;
        int success = 0;
-       char *hostname;
+       struct Forward fwd;
 
        /* Get arguments from the packet. */
-       port = packet_get_int();
-       hostname = packet_get_string(NULL);
-       host_port = packet_get_int();
+       memset(&fwd, 0, sizeof(fwd));
+       fwd.listen_port = packet_get_int();
+       fwd.connect_host = packet_get_string(NULL);
+       fwd.connect_port = packet_get_int();
 
        /*
         * Check that an unprivileged user is not trying to forward a
         * privileged port.
         */
-       if (port < IPPORT_RESERVED && !is_root)
+       if (fwd.listen_port < IPPORT_RESERVED && !is_root)
                packet_disconnect(
                    "Requested forwarding of port %d but user is not root.",
-                   port);
-       if (host_port == 0)
+                   fwd.listen_port);
+       if (fwd.connect_port == 0)
                packet_disconnect("Dynamic forwarding denied.");
 
        /* Initiate forwarding */
-       success = channel_setup_local_fwd_listener(NULL, port, hostname,
-           host_port, gateway_ports);
+       success = channel_setup_local_fwd_listener(&fwd, fwd_opts);
 
        /* Free the argument string. */
-       free(hostname);
+       free(fwd.connect_host);
 
        return (success ? 0 : -1);
 }
@@ -3160,6 +3427,7 @@ channel_add_permitted_opens(char *host, int port)
        permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
        permitted_opens[num_permitted_opens].port_to_connect = port;
        permitted_opens[num_permitted_opens].listen_host = NULL;
+       permitted_opens[num_permitted_opens].listen_path = NULL;
        permitted_opens[num_permitted_opens].listen_port = 0;
        num_permitted_opens++;
 
@@ -3194,6 +3462,8 @@ channel_update_permitted_opens(int idx, int newport)
                permitted_opens[idx].host_to_connect = NULL;
                free(permitted_opens[idx].listen_host);
                permitted_opens[idx].listen_host = NULL;
+               free(permitted_opens[idx].listen_path);
+               permitted_opens[idx].listen_path = NULL;
        }
 }
 
@@ -3208,6 +3478,7 @@ channel_add_adm_permitted_opens(char *host, int port)
             = xstrdup(host);
        permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
        permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
+       permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
        permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
        return ++num_adm_permitted_opens;
 }
@@ -3229,6 +3500,7 @@ channel_clear_permitted_opens(void)
        for (i = 0; i < num_permitted_opens; i++) {
                free(permitted_opens[i].host_to_connect);
                free(permitted_opens[i].listen_host);
+               free(permitted_opens[i].listen_path);
        }
        free(permitted_opens);
        permitted_opens = NULL;
@@ -3243,6 +3515,7 @@ channel_clear_adm_permitted_opens(void)
        for (i = 0; i < num_adm_permitted_opens; i++) {
                free(permitted_adm_opens[i].host_to_connect);
                free(permitted_adm_opens[i].listen_host);
+               free(permitted_adm_opens[i].listen_path);
        }
        free(permitted_adm_opens);
        permitted_adm_opens = NULL;
@@ -3286,16 +3559,27 @@ static int
 connect_next(struct channel_connect *cctx)
 {
        int sock, saved_errno;
-       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       struct sockaddr_un *sunaddr;
+       char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))];
 
        for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
-               if (cctx->ai->ai_family != AF_INET &&
-                   cctx->ai->ai_family != AF_INET6)
-                       continue;
-               if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
-                   ntop, sizeof(ntop), strport, sizeof(strport),
-                   NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-                       error("connect_next: getnameinfo failed");
+               switch (cctx->ai->ai_family) {
+               case AF_UNIX:
+                       /* unix:pathname instead of host:port */
+                       sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
+                       strlcpy(ntop, "unix", sizeof(ntop));
+                       strlcpy(strport, sunaddr->sun_path, sizeof(strport));
+                       break;
+               case AF_INET:
+               case AF_INET6:
+                       if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
+                           ntop, sizeof(ntop), strport, sizeof(strport),
+                           NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                               error("connect_next: getnameinfo failed");
+                               continue;
+                       }
+                       break;
+               default:
                        continue;
                }
                if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
@@ -3318,10 +3602,11 @@ connect_next(struct channel_connect *cctx)
                        errno = saved_errno;
                        continue;       /* fail -- try next */
                }
+               if (cctx->ai->ai_family != AF_UNIX)
+                       set_nodelay(sock);
                debug("connect_next: host %.100s ([%.100s]:%s) "
                    "in progress, fd=%d", cctx->host, ntop, strport, sock);
                cctx->ai = cctx->ai->ai_next;
-               set_nodelay(sock);
                return sock;
        }
        return -1;
@@ -3331,14 +3616,18 @@ static void
 channel_connect_ctx_free(struct channel_connect *cctx)
 {
        free(cctx->host);
-       if (cctx->aitop)
-               freeaddrinfo(cctx->aitop);
+       if (cctx->aitop) {
+               if (cctx->aitop->ai_family == AF_UNIX)
+                       free(cctx->aitop);
+               else
+                       freeaddrinfo(cctx->aitop);
+       }
        memset(cctx, 0, sizeof(*cctx));
 }
 
-/* Return CONNECTING channel to remote host, port */
+/* Return CONNECTING channel to remote host:port or local socket path */
 static Channel *
-connect_to(const char *host, u_short port, char *ctype, char *rname)
+connect_to(const char *name, int port, char *ctype, char *rname)
 {
        struct addrinfo hints;
        int gaierr;
@@ -3348,23 +3637,51 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
        Channel *c;
 
        memset(&cctx, 0, sizeof(cctx));
-       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, &cctx.aitop)) != 0) {
-               error("connect_to %.100s: unknown host (%s)", host,
-                   ssh_gai_strerror(gaierr));
-               return NULL;
+
+       if (port == PORT_STREAMLOCAL) {
+               struct sockaddr_un *sunaddr;
+               struct addrinfo *ai;
+
+               if (strlen(name) > sizeof(sunaddr->sun_path)) {
+                       error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
+                       return (NULL);
+               }
+
+               /*
+                * Fake up a struct addrinfo for AF_UNIX connections.
+                * channel_connect_ctx_free() must check ai_family
+                * and use free() not freeaddirinfo() for AF_UNIX.
+                */
+               ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
+               memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
+               ai->ai_addr = (struct sockaddr *)(ai + 1);
+               ai->ai_addrlen = sizeof(*sunaddr);
+               ai->ai_family = AF_UNIX;
+               ai->ai_socktype = SOCK_STREAM;
+               ai->ai_protocol = PF_UNSPEC;
+               sunaddr = (struct sockaddr_un *)ai->ai_addr;
+               sunaddr->sun_family = AF_UNIX;
+               strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
+               cctx.aitop = ai;
+       } else {
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = IPv4or6;
+               hints.ai_socktype = SOCK_STREAM;
+               snprintf(strport, sizeof strport, "%d", port);
+               if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) {
+                       error("connect_to %.100s: unknown host (%s)", name,
+                           ssh_gai_strerror(gaierr));
+                       return NULL;
+               }
        }
 
-       cctx.host = xstrdup(host);
+       cctx.host = xstrdup(name);
        cctx.port = port;
        cctx.ai = cctx.aitop;
 
        if ((sock = connect_next(&cctx)) == -1) {
                error("connect to %.100s port %d failed: %s",
-                   host, port, strerror(errno));
+                   name, port, strerror(errno));
                channel_connect_ctx_free(&cctx);
                return NULL;
        }
@@ -3381,7 +3698,7 @@ channel_connect_by_listen_address(const char *listen_host,
        int i;
 
        for (i = 0; i < num_permitted_opens; i++) {
-               if (open_listen_match(&permitted_opens[i], listen_host,
+               if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
                    listen_port, 1)) {
                        return connect_to(
                            permitted_opens[i].host_to_connect,
@@ -3393,9 +3710,26 @@ channel_connect_by_listen_address(const char *listen_host,
        return NULL;
 }
 
+Channel *
+channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
+{
+       int i;
+
+       for (i = 0; i < num_permitted_opens; i++) {
+               if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
+                       return connect_to(
+                           permitted_opens[i].host_to_connect,
+                           permitted_opens[i].port_to_connect, ctype, rname);
+               }
+       }
+       error("WARNING: Server requests forwarding for unknown path %.100s",
+           path);
+       return NULL;
+}
+
 /* Check if connecting to that port is permitted and connect. */
 Channel *
-channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
+channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname)
 {
        int i, permit, permit_adm = 1;
 
@@ -3425,6 +3759,38 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
        return connect_to(host, port, ctype, rname);
 }
 
+/* Check if connecting to that path is permitted and connect. */
+Channel *
+channel_connect_to_path(const char *path, char *ctype, char *rname)
+{
+       int i, permit, permit_adm = 1;
+
+       permit = all_opens_permitted;
+       if (!permit) {
+               for (i = 0; i < num_permitted_opens; i++)
+                       if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
+                               permit = 1;
+                               break;
+                       }
+       }
+
+       if (num_adm_permitted_opens > 0) {
+               permit_adm = 0;
+               for (i = 0; i < num_adm_permitted_opens; i++)
+                       if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
+                               permit_adm = 1;
+                               break;
+                       }
+       }
+
+       if (!permit || !permit_adm) {
+               logit("Received request to connect to path %.100s, "
+                   "but the request was denied.", path);
+               return NULL;
+       }
+       return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
+}
+
 void
 channel_send_window_changes(void)
 {
index a7537cb..e8662f5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.114 2014/06/27 16:41:56 markus Exp $ */
+/* $OpenBSD: channels.h,v 1.115 2014/07/15 15:54:14 millert Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -56,7 +56,9 @@
 #define SSH_CHANNEL_MUX_LISTENER       15      /* Listener for mux conn. */
 #define SSH_CHANNEL_MUX_CLIENT         16      /* Conn. to mux slave */
 #define SSH_CHANNEL_ABANDONED          17      /* Abandoned session, eg mux */
-#define SSH_CHANNEL_MAX_TYPE           18
+#define SSH_CHANNEL_UNIX_LISTENER      18      /* Listening on a domain socket. */
+#define SSH_CHANNEL_RUNIX_LISTENER     19      /* Listening to a R-style domain socket. */
+#define SSH_CHANNEL_MAX_TYPE           20
 
 #define CHANNEL_CANCEL_PORT_STATIC     -1
 
@@ -251,6 +253,8 @@ char        *channel_open_message(void);
 int     channel_find_open(void);
 
 /* tcp forwarding */
+struct Forward;
+struct ForwardOptions;
 void    channel_set_af(int af);
 void     channel_permit_all_opens(void);
 void    channel_add_permitted_opens(char *, int);
@@ -260,19 +264,19 @@ void       channel_update_permitted_opens(int, int);
 void    channel_clear_permitted_opens(void);
 void    channel_clear_adm_permitted_opens(void);
 void    channel_print_adm_permitted_opens(void);
-int      channel_input_port_forward_request(int, int);
-Channel        *channel_connect_to(const char *, u_short, char *, char *);
+int      channel_input_port_forward_request(int, struct ForwardOptions *);
+Channel        *channel_connect_to_port(const char *, u_short, char *, char *);
+Channel *channel_connect_to_path(const char *, char *, char *);
 Channel        *channel_connect_stdio_fwd(const char*, u_short, int, int);
 Channel        *channel_connect_by_listen_address(const char *, u_short,
             char *, char *);
-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);
-int     channel_request_rforward_cancel(const char *host, u_short port);
-int     channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
-int     channel_cancel_rport_listener(const char *, u_short);
-int     channel_cancel_lport_listener(const char *, u_short, int, int);
+Channel        *channel_connect_by_listen_path(const char *, char *, char *);
+int     channel_request_remote_forwarding(struct Forward *);
+int     channel_setup_local_fwd_listener(struct Forward *, struct ForwardOptions *);
+int     channel_request_rforward_cancel(struct Forward *);
+int     channel_setup_remote_fwd_listener(struct Forward *, int *, struct ForwardOptions *);
+int     channel_cancel_rport_listener(struct Forward *);
+int     channel_cancel_lport_listener(struct Forward *, int, struct ForwardOptions *);
 int     permitopen_port(const char *);
 
 /* x11 forwarding */
index 4153688..64f4785 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.260 2014/06/27 16:41:56 markus Exp $ */
+/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include "cipher.h"
 #include "kex.h"
 #include "log.h"
+#include "misc.h"
 #include "readconf.h"
 #include "clientloop.h"
 #include "sshconnect.h"
 #include "authfd.h"
 #include "atomicio.h"
 #include "sshpty.h"
-#include "misc.h"
 #include "match.h"
 #include "msg.h"
 #include "roaming.h"
@@ -862,13 +862,11 @@ static void
 process_cmdline(void)
 {
        void (*handler)(int);
-       char *s, *cmd, *cancel_host;
-       int delete = 0, local = 0, remote = 0, dynamic = 0;
-       int cancel_port, ok;
-       Forward fwd;
+       char *s, *cmd;
+       int ok, delete = 0, local = 0, remote = 0, dynamic = 0;
+       struct Forward fwd;
 
        memset(&fwd, 0, sizeof(fwd));
-       fwd.listen_host = fwd.connect_host = NULL;
 
        leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
        handler = signal(SIGINT, SIG_IGN);
@@ -934,29 +932,20 @@ process_cmdline(void)
 
        /* XXX update list of forwards in options */
        if (delete) {
-               cancel_port = 0;
-               cancel_host = hpdelim(&s);      /* may be NULL */
-               if (s != NULL) {
-                       cancel_port = a2port(s);
-                       cancel_host = cleanhostname(cancel_host);
-               } else {
-                       cancel_port = a2port(cancel_host);
-                       cancel_host = NULL;
-               }
-               if (cancel_port <= 0) {
-                       logit("Bad forwarding close port");
+               /* We pass 1 for dynamicfwd to restrict to 1 or 2 fields. */
+               if (!parse_forward(&fwd, s, 1, 0)) {
+                       logit("Bad forwarding close specification.");
                        goto out;
                }
                if (remote)
-                       ok = channel_request_rforward_cancel(cancel_host,
-                           cancel_port) == 0;
+                       ok = channel_request_rforward_cancel(&fwd) == 0;
                else if (dynamic)
-                       ok = channel_cancel_lport_listener(cancel_host,
-                           cancel_port, 0, options.gateway_ports) > 0;
+                       ok = channel_cancel_lport_listener(&fwd,
+                           0, &options.fwd_opts) > 0;
                else
-                       ok = channel_cancel_lport_listener(cancel_host,
-                           cancel_port, CHANNEL_CANCEL_PORT_STATIC,
-                           options.gateway_ports) > 0;
+                       ok = channel_cancel_lport_listener(&fwd,
+                           CHANNEL_CANCEL_PORT_STATIC,
+                           &options.fwd_opts) > 0;
                if (!ok) {
                        logit("Unkown port forwarding.");
                        goto out;
@@ -968,16 +957,13 @@ process_cmdline(void)
                        goto out;
                }
                if (local || 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)) {
                                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(&fwd) < 0) {
                                logit("Port forwarding failed.");
                                goto out;
                        }
@@ -990,7 +976,9 @@ out:
        enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
        free(cmd);
        free(fwd.listen_host);
+       free(fwd.listen_path);
        free(fwd.connect_host);
+       free(fwd.connect_path);
 }
 
 /* reasons to suppress output of an escape command in help output */
@@ -1833,9 +1821,8 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
        originator_port = packet_get_int();
        packet_check_eom();
 
-       debug("client_request_forwarded_tcpip: listen %s port %d, "
-           "originator %s port %d", listen_address, listen_port,
-           originator_address, originator_port);
+       debug("%s: listen %s port %d, originator %s port %d", __func__,
+           listen_address, listen_port, originator_address, originator_port);
 
        c = channel_connect_by_listen_address(listen_address, listen_port,
            "forwarded-tcpip", originator_address);
@@ -1845,6 +1832,27 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
        return c;
 }
 
+static Channel *
+client_request_forwarded_streamlocal(const char *request_type, int rchan)
+{
+       Channel *c = NULL;
+       char *listen_path;
+
+       /* Get the remote path. */
+       listen_path = packet_get_string(NULL);
+       /* XXX: Skip reserved field for now. */
+       if (packet_get_string_ptr(NULL) == NULL)
+               fatal("%s: packet_get_string_ptr failed", __func__);
+       packet_check_eom();
+
+       debug("%s: %s", __func__, listen_path);
+
+       c = channel_connect_by_listen_path(listen_path,
+           "forwarded-streamlocal@openssh.com", "forwarded-streamlocal");
+       free(listen_path);
+       return c;
+}
+
 static Channel *
 client_request_x11(const char *request_type, int rchan)
 {
@@ -1966,6 +1974,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
 
        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) {
index 51fd8f7..5a63a11 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.93 2014/04/20 02:30:25 djm Exp $ */
+/* $OpenBSD: misc.c,v 1.94 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/param.h>
 
 #include <net/if.h>
@@ -1019,3 +1020,49 @@ lowercase(char *s)
        for (; *s; s++)
                *s = tolower((u_char)*s);
 }
+
+int
+unix_listener(const char *path, int backlog, int unlink_first)
+{
+       struct sockaddr_un sunaddr;
+       int saved_errno, sock;
+
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) {
+               error("%s: \"%s\" too long for Unix domain socket", __func__,
+                   path);
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       sock = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0) {
+               saved_errno = errno;
+               error("socket: %.100s", strerror(errno));
+               errno = saved_errno;
+               return -1;
+       }
+       if (unlink_first == 1) {
+               if (unlink(path) != 0 && errno != ENOENT)
+                       error("unlink(%s): %.100s", path, strerror(errno));
+       }
+       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
+               saved_errno = errno;
+               error("bind: %.100s", strerror(errno));
+               close(sock);
+               error("%s: cannot bind to path: %s", __func__, path);
+               errno = saved_errno;
+               return -1;
+       }
+       if (listen(sock, backlog) < 0) {
+               saved_errno = errno;
+               error("listen: %.100s", strerror(errno));
+               close(sock);
+               unlink(path);
+               error("%s: cannot listen on path: %s", __func__, path);
+               errno = saved_errno;
+               return -1;
+       }
+       return sock;
+}
index 693fff8..53d469b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.53 2014/05/02 03:27:54 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.54 2014/07/15 15:54:14 millert Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
 #ifndef _MISC_H
 #define _MISC_H
 
+/* Data structure for representing a forwarding request. */
+struct Forward {
+       char     *listen_host;          /* Host (address) to listen on. */
+       int       listen_port;          /* Port to forward. */
+       char     *listen_path;          /* Path to bind domain socket. */
+       char     *connect_host;         /* Host to connect. */
+       int       connect_port;         /* Port to connect on connect_host. */
+       char     *connect_path;         /* Path to connect domain socket. */
+       int       allocated_port;       /* Dynamically allocated listen port */
+       int       handle;               /* Handle for dynamic listen ports */
+};
+
+/* Common server and client forwarding options. */
+struct ForwardOptions {
+       int      gateway_ports; /* Allow remote connects to forwarded ports. */
+       mode_t   streamlocal_bind_mask; /* umask for streamlocal binds */
+       int      streamlocal_bind_unlink; /* unlink socket before bind */
+};
+
 /* misc.c */
 
 char   *chop(char *);
@@ -37,6 +56,7 @@ void   ms_subtract_diff(struct timeval *, int *);
 void    ms_to_timeval(struct timeval *, int);
 time_t  monotime(void);
 void    lowercase(char *s);
+int     unix_listener(const char *, int, int);
 
 struct passwd *pwcopy(struct passwd *);
 const char *ssh_gai_strerror(int);
@@ -66,6 +86,9 @@ int    tun_open(int, int);
 #define SSH_TUNID_ERR          (SSH_TUNID_ANY - 1)
 #define SSH_TUNID_MAX          (SSH_TUNID_ANY - 2)
 
+/* Fake port to indicate that host field is really a path. */
+#define PORT_STREAMLOCAL       -2
+
 /* Functions to extract or store big-endian words of various sizes */
 u_int64_t      get_u64(const void *)
     __attribute__((__bounded__( __minbytes__, 1, 8)));
index c00dab9..fb81186 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.134 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.135 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -66,6 +66,7 @@
 #include "sshlogin.h"
 #include "canohost.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "monitor.h"
 #include "monitor_mm.h"
@@ -74,7 +75,6 @@
 #endif
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
-#include "misc.h"
 #include "compat.h"
 #include "ssh2.h"
 #include "roaming.h"
index 7df32df..7d53596 100644 (file)
@@ -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>
  *
@@ -496,29 +496,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:
@@ -538,14 +542,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;
 
@@ -557,7 +565,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;
 
@@ -574,7 +582,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();
@@ -594,8 +603,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);
@@ -614,34 +627,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)));
 
@@ -649,25 +674,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;
        }
@@ -718,9 +748,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);
@@ -733,8 +762,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);
@@ -755,7 +783,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;
 }
@@ -763,36 +793,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)));
 
@@ -827,18 +868,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";
        }
 
@@ -847,8 +884,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);
@@ -857,8 +897,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;
 }
@@ -1120,7 +1160,6 @@ mux_tty_alloc_failed(Channel *c)
 void
 muxserver_listen(void)
 {
-       struct sockaddr_un addr;
        mode_t old_umask;
        char *orig_control_path = options.control_path;
        char rbuf[16+1];
@@ -1149,23 +1188,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;
-       addr.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, 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);
@@ -1179,13 +1205,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) {
@@ -1573,7 +1597,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;
@@ -1588,11 +1612,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)
index 5797bf0..817b201 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.197 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.198 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -62,7 +62,6 @@
 #include "crc32.h"
 #include "compress.h"
 #include "deattack.h"
-#include "channels.h"
 #include "compat.h"
 #include "ssh1.h"
 #include "ssh2.h"
@@ -73,6 +72,7 @@
 #include "log.h"
 #include "canohost.h"
 #include "misc.h"
+#include "channels.h"
 #include "ssh.h"
 #include "ssherr.h"
 #include "roaming.h"
index 453a21c..8c5195b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.219 2014/04/23 12:42:34 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -16,6 +16,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#include <sys/un.h>
 
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -40,9 +41,9 @@
 #include "pathnames.h"
 #include "log.h"
 #include "key.h"
+#include "misc.h"
 #include "readconf.h"
 #include "match.h"
-#include "misc.h"
 #include "buffer.h"
 #include "kex.h"
 #include "mac.h"
@@ -141,6 +142,7 @@ typedef enum {
        oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
        oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
        oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
+       oStreamLocalBindMask, oStreamLocalBindUnlink,
        oIgnoredUnknownOption, oDeprecated, oUnsupported
 } OpCodes;
 
@@ -253,6 +255,8 @@ static struct {
        { "canonicalizehostname", oCanonicalizeHostname },
        { "canonicalizemaxdots", oCanonicalizeMaxDots },
        { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
+       { "streamlocalbindmask", oStreamLocalBindMask },
+       { "streamlocalbindunlink", oStreamLocalBindUnlink },
        { "ignoreunknown", oIgnoreUnknown },
 
        { NULL, oBadOption }
@@ -264,12 +268,13 @@ static struct {
  */
 
 void
-add_local_forward(Options *options, const Forward *newfwd)
+add_local_forward(Options *options, const struct Forward *newfwd)
 {
-       Forward *fwd;
+       struct Forward *fwd;
        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.");
        options->local_forwards = xrealloc(options->local_forwards,
            options->num_local_forwards + 1,
@@ -278,8 +283,10 @@ add_local_forward(Options *options, const Forward *newfwd)
 
        fwd->listen_host = newfwd->listen_host;
        fwd->listen_port = newfwd->listen_port;
+       fwd->listen_path = newfwd->listen_path;
        fwd->connect_host = newfwd->connect_host;
        fwd->connect_port = newfwd->connect_port;
+       fwd->connect_path = newfwd->connect_path;
 }
 
 /*
@@ -288,9 +295,9 @@ add_local_forward(Options *options, const Forward *newfwd)
  */
 
 void
-add_remote_forward(Options *options, const Forward *newfwd)
+add_remote_forward(Options *options, const struct Forward *newfwd)
 {
-       Forward *fwd;
+       struct Forward *fwd;
 
        options->remote_forwards = xrealloc(options->remote_forwards,
            options->num_remote_forwards + 1,
@@ -299,8 +306,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
 
        fwd->listen_host = newfwd->listen_host;
        fwd->listen_port = newfwd->listen_port;
+       fwd->listen_path = newfwd->listen_path;
        fwd->connect_host = newfwd->connect_host;
        fwd->connect_port = newfwd->connect_port;
+       fwd->connect_path = newfwd->connect_path;
        fwd->handle = newfwd->handle;
        fwd->allocated_port = 0;
 }
@@ -312,7 +321,9 @@ clear_forwardings(Options *options)
 
        for (i = 0; i < options->num_local_forwards; i++) {
                free(options->local_forwards[i].listen_host);
+               free(options->local_forwards[i].listen_path);
                free(options->local_forwards[i].connect_host);
+               free(options->local_forwards[i].connect_path);
        }
        if (options->num_local_forwards > 0) {
                free(options->local_forwards);
@@ -321,7 +332,9 @@ clear_forwardings(Options *options)
        options->num_local_forwards = 0;
        for (i = 0; i < options->num_remote_forwards; i++) {
                free(options->remote_forwards[i].listen_host);
+               free(options->remote_forwards[i].listen_path);
                free(options->remote_forwards[i].connect_host);
+               free(options->remote_forwards[i].connect_path);
        }
        if (options->num_remote_forwards > 0) {
                free(options->remote_forwards);
@@ -706,7 +719,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
        LogLevel *log_level_ptr;
        long long val64;
        size_t len;
-       Forward fwd;
+       struct Forward fwd;
        const struct multistate *multistate_ptr;
        struct allowed_cname *cname;
 
@@ -796,7 +809,7 @@ parse_time:
                goto parse_time;
 
        case oGatewayPorts:
-               intptr = &options->gateway_ports;
+               intptr = &options->fwd_opts.gateway_ports;
                goto parse_flag;
 
        case oExitOnForwardFailure:
@@ -1396,6 +1409,21 @@ parse_int:
                intptr = &options->canonicalize_fallback_local;
                goto parse_flag;
 
+       case oStreamLocalBindMask:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
+               /* Parse mode in octal format */
+               value = strtol(arg, &endofnumber, 8);
+               if (arg == endofnumber || value < 0 || value > 0777)
+                       fatal("%.200s line %d: Bad mask.", filename, linenum);
+               options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
+               break;
+
+       case oStreamLocalBindUnlink:
+               intptr = &options->fwd_opts.streamlocal_bind_unlink;
+               goto parse_flag;
+
        case oDeprecated:
                debug("%s line %d: Deprecated option \"%s\"",
                    filename, linenum, keyword);
@@ -1493,7 +1521,9 @@ initialize_options(Options * options)
        options->forward_x11_timeout = -1;
        options->exit_on_forward_failure = -1;
        options->xauth_location = NULL;
-       options->gateway_ports = -1;
+       options->fwd_opts.gateway_ports = -1;
+       options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
+       options->fwd_opts.streamlocal_bind_unlink = -1;
        options->use_privileged_port = -1;
        options->rsa_authentication = -1;
        options->pubkey_authentication = -1;
@@ -1606,8 +1636,12 @@ fill_default_options(Options * options)
                options->exit_on_forward_failure = 0;
        if (options->xauth_location == NULL)
                options->xauth_location = _PATH_XAUTH;
-       if (options->gateway_ports == -1)
-               options->gateway_ports = 0;
+       if (options->fwd_opts.gateway_ports == -1)
+               options->fwd_opts.gateway_ports = 0;
+       if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
+               options->fwd_opts.streamlocal_bind_mask = 0177;
+       if (options->fwd_opts.streamlocal_bind_unlink == -1)
+               options->fwd_opts.streamlocal_bind_unlink = 0;
        if (options->use_privileged_port == -1)
                options->use_privileged_port = 0;
        if (options->rsa_authentication == -1)
@@ -1757,22 +1791,92 @@ fill_default_options(Options * options)
        /* options->preferred_authentications will be set in ssh */
 }
 
+struct fwdarg {
+       char *arg;
+       int ispath;
+};
+
+/*
+ * parse_fwd_field
+ * parses the next field in a port forwarding specification.
+ * sets fwd to the parsed field and advances p past the colon
+ * or sets it to NULL at end of string.
+ * returns 0 on success, else non-zero.
+ */
+static int
+parse_fwd_field(char **p, struct fwdarg *fwd)
+{
+       char *ep, *cp = *p;
+       int ispath = 0;
+
+       if (*cp == '\0') {
+               *p = NULL;
+               return -1;      /* end of string */
+       }
+
+       /*
+        * A field escaped with square brackets is used literally.
+        * XXX - allow ']' to be escaped via backslash?
+        */
+       if (*cp == '[') {
+               /* find matching ']' */
+               for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
+                       if (*ep == '/')
+                               ispath = 1;
+               }
+               /* no matching ']' or not at end of field. */
+               if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
+                       return -1;
+               /* NUL terminate the field and advance p past the colon */
+               *ep++ = '\0';
+               if (*ep != '\0')
+                       *ep++ = '\0';
+               fwd->arg = cp + 1;
+               fwd->ispath = ispath;
+               *p = ep;
+               return 0;
+       }
+
+       for (cp = *p; *cp != '\0'; cp++) {
+               switch (*cp) {
+               case '\\':
+                       memmove(cp, cp + 1, strlen(cp + 1) + 1);
+                       cp++;
+                       break;
+               case '/':
+                       ispath = 1;
+                       break;
+               case ':':
+                       *cp++ = '\0';
+                       goto done;
+               }
+       }
+done:
+       fwd->arg = *p;
+       fwd->ispath = ispath;
+       *p = cp;
+       return 0;
+}
+
 /*
  * parse_forward
  * parses a string containing a port forwarding specification of the form:
  *   dynamicfwd == 0
- *     [listenhost:]listenport:connecthost:connectport
+ *     [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
+ *     listenpath:connectpath
  *   dynamicfwd == 1
  *     [listenhost:]listenport
  * returns number of arguments parsed or zero on error
  */
 int
-parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
+parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
 {
+       struct fwdarg fwdargs[4];
+       char *p, *cp;
        int i;
-       char *p, *cp, *fwdarg[4];
 
-       memset(fwd, '\0', sizeof(*fwd));
+       memset(fwd, 0, sizeof(*fwd));
+       memset(fwdargs, 0, sizeof(fwdargs));
 
        cp = p = xstrdup(fwdspec);
 
@@ -1780,39 +1884,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
        while (isspace((u_char)*cp))
                cp++;
 
-       for (i = 0; i < 4; ++i)
-               if ((fwdarg[i] = hpdelim(&cp)) == NULL)
+       for (i = 0; i < 4; ++i) {
+               if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
                        break;
+       }
 
        /* Check for trailing garbage */
-       if (cp != NULL)
+       if (cp != NULL && *cp != '\0') {
                i = 0;  /* failure */
+       }
 
        switch (i) {
        case 1:
-               fwd->listen_host = NULL;
-               fwd->listen_port = a2port(fwdarg[0]);
+               if (fwdargs[0].ispath) {
+                       fwd->listen_path = xstrdup(fwdargs[0].arg);
+                       fwd->listen_port = PORT_STREAMLOCAL;
+               } else {
+                       fwd->listen_host = NULL;
+                       fwd->listen_port = a2port(fwdargs[0].arg);
+               }
                fwd->connect_host = xstrdup("socks");
                break;
 
        case 2:
-               fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
-               fwd->listen_port = a2port(fwdarg[1]);
-               fwd->connect_host = xstrdup("socks");
+               if (fwdargs[0].ispath && fwdargs[1].ispath) {
+                       fwd->listen_path = xstrdup(fwdargs[0].arg);
+                       fwd->listen_port = PORT_STREAMLOCAL;
+                       fwd->connect_path = xstrdup(fwdargs[1].arg);
+                       fwd->connect_port = PORT_STREAMLOCAL;
+               } else if (fwdargs[1].ispath) {
+                       fwd->listen_host = NULL;
+                       fwd->listen_port = a2port(fwdargs[0].arg);
+                       fwd->connect_path = xstrdup(fwdargs[1].arg);
+                       fwd->connect_port = PORT_STREAMLOCAL;
+               } else {
+                       fwd->listen_host = xstrdup(fwdargs[0].arg);
+                       fwd->listen_port = a2port(fwdargs[1].arg);
+                       fwd->connect_host = xstrdup("socks");
+               }
                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 (fwdargs[0].ispath) {
+                       fwd->listen_path = xstrdup(fwdargs[0].arg);
+                       fwd->listen_port = PORT_STREAMLOCAL;
+                       fwd->connect_host = xstrdup(fwdargs[1].arg);
+                       fwd->connect_port = a2port(fwdargs[2].arg);
+               } else if (fwdargs[2].ispath) {
+                       fwd->listen_host = xstrdup(fwdargs[0].arg);
+                       fwd->listen_port = a2port(fwdargs[1].arg);
+                       fwd->connect_path = xstrdup(fwdargs[2].arg);
+                       fwd->connect_port = PORT_STREAMLOCAL;
+               } else {
+                       fwd->listen_host = NULL;
+                       fwd->listen_port = a2port(fwdargs[0].arg);
+                       fwd->connect_host = xstrdup(fwdargs[1].arg);
+                       fwd->connect_port = a2port(fwdargs[2].arg);
+               }
                break;
 
        case 4:
-               fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
-               fwd->listen_port = a2port(fwdarg[1]);
-               fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
-               fwd->connect_port = a2port(fwdarg[3]);
+               fwd->listen_host = xstrdup(fwdargs[0].arg);
+               fwd->listen_port = a2port(fwdargs[1].arg);
+               fwd->connect_host = xstrdup(fwdargs[2].arg);
+               fwd->connect_port = a2port(fwdargs[3].arg);
                break;
        default:
                i = 0; /* failure */
@@ -1824,29 +1959,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
                if (!(i == 1 || i == 2))
                        goto fail_free;
        } else {
-               if (!(i == 3 || i == 4))
-                       goto fail_free;
-               if (fwd->connect_port <= 0)
+               if (!(i == 3 || i == 4)) {
+                       if (fwd->connect_path == NULL &&
+                           fwd->listen_path == NULL)
+                               goto fail_free;
+               }
+               if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
                        goto fail_free;
        }
 
-       if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
+       if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
+           (!remotefwd && fwd->listen_port == 0))
                goto fail_free;
-
        if (fwd->connect_host != NULL &&
            strlen(fwd->connect_host) >= NI_MAXHOST)
                goto fail_free;
+       /* XXX - if connecting to a remote socket, max sun len may not match this host */
+       if (fwd->connect_path != NULL &&
+           strlen(fwd->connect_path) >= PATH_MAX_SUN)
+               goto fail_free;
        if (fwd->listen_host != NULL &&
            strlen(fwd->listen_host) >= NI_MAXHOST)
                goto fail_free;
-
+       if (fwd->listen_path != NULL &&
+           strlen(fwd->listen_path) >= PATH_MAX_SUN)
+               goto fail_free;
 
        return (i);
 
  fail_free:
        free(fwd->connect_host);
        fwd->connect_host = NULL;
+       free(fwd->connect_path);
+       fwd->connect_path = NULL;
        free(fwd->listen_host);
        fwd->listen_host = NULL;
+       free(fwd->listen_path);
+       fwd->listen_path = NULL;
        return (0);
 }
index 75e3f8f..0b9cb77 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.101 2014/02/23 20:11:36 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
 #ifndef READCONF_H
 #define READCONF_H
 
-/* Data structure for representing a forwarding request. */
-
-typedef struct {
-       char     *listen_host;          /* Host (address) to listen on. */
-       int       listen_port;          /* Port to forward. */
-       char     *connect_host;         /* Host to connect. */
-       int       connect_port;         /* Port to connect on connect_host. */
-       int       allocated_port;       /* Dynamically allocated listen port */
-       int       handle;               /* Handle for dynamic listen ports */
-}       Forward;
 /* Data structure for representing option data. */
 
 #define MAX_SEND_ENV           256
 #define SSH_MAX_HOSTS_FILES    32
 #define MAX_CANON_DOMAINS      32
+#define PATH_MAX_SUN           (sizeof((struct sockaddr_un *)0)->sun_path)
 
 struct allowed_cname {
        char *source_list;
@@ -44,7 +35,7 @@ typedef struct {
        int     forward_x11_trusted;    /* Trust Forward X11 display. */
        int     exit_on_forward_failure;        /* Exit if bind(2) fails for -L/-R */
        char   *xauth_location; /* Location for xauth program */
-       int     gateway_ports;  /* Allow remote connects to forwarded ports. */
+       struct ForwardOptions fwd_opts; /* forwarding options */
        int     use_privileged_port;    /* Don't use privileged port if false. */
        int     rhosts_rsa_authentication;      /* Try rhosts with RSA
                                                 * authentication. */
@@ -106,11 +97,11 @@ typedef struct {
 
        /* Local TCP/IP forward requests. */
        int     num_local_forwards;
-       Forward *local_forwards;
+       struct Forward *local_forwards;
 
        /* Remote TCP/IP forward requests. */
        int     num_remote_forwards;
-       Forward *remote_forwards;
+       struct Forward *remote_forwards;
        int     clear_forwardings;
 
        int     enable_ssh_keysign;
@@ -181,12 +172,12 @@ int        process_config_line(Options *, struct passwd *, const char *, char *,
     const char *, int, int *, int);
 int     read_config_file(const char *, struct passwd *, const char *,
     Options *, int);
-int     parse_forward(Forward *, const char *, int, int);
+int     parse_forward(struct Forward *, const char *, int, int);
 int     default_ssh_port(void);
 int     option_clear_or_none(const char *);
 
-void    add_local_forward(Options *, const Forward *);
-void    add_remote_forward(Options *, const Forward *);
+void    add_local_forward(Options *, const struct Forward *);
+void    add_remote_forward(Options *, const struct Forward *);
 void    add_identity_file(Options *, const char *, const char *, int);
 
 #endif                         /* READCONF_H */
index ede4f62..7d932f0 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.250 2014/07/03 22:40:43 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
 #include "ssh.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "compat.h"
 #include "pathnames.h"
-#include "misc.h"
 #include "cipher.h"
 #include "key.h"
 #include "kex.h"
@@ -111,6 +111,7 @@ initialize_server_options(ServerOptions *options)
        options->rekey_limit = -1;
        options->rekey_interval = -1;
        options->allow_tcp_forwarding = -1;
+       options->allow_streamlocal_forwarding = -1;
        options->allow_agent_forwarding = -1;
        options->num_allow_users = 0;
        options->num_deny_users = 0;
@@ -120,7 +121,9 @@ initialize_server_options(ServerOptions *options)
        options->macs = NULL;
        options->kex_algorithms = NULL;
        options->protocol = SSH_PROTO_UNKNOWN;
-       options->gateway_ports = -1;
+       options->fwd_opts.gateway_ports = -1;
+       options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
+       options->fwd_opts.streamlocal_bind_unlink = -1;
        options->num_subsystems = 0;
        options->max_startups_begin = -1;
        options->max_startups_rate = -1;
@@ -253,10 +256,12 @@ fill_default_server_options(ServerOptions *options)
                options->rekey_interval = 0;
        if (options->allow_tcp_forwarding == -1)
                options->allow_tcp_forwarding = FORWARD_ALLOW;
+       if (options->allow_streamlocal_forwarding == -1)
+               options->allow_streamlocal_forwarding = FORWARD_ALLOW;
        if (options->allow_agent_forwarding == -1)
                options->allow_agent_forwarding = 1;
-       if (options->gateway_ports == -1)
-               options->gateway_ports = 0;
+       if (options->fwd_opts.gateway_ports == -1)
+               options->fwd_opts.gateway_ports = 0;
        if (options->max_startups == -1)
                options->max_startups = 100;
        if (options->max_startups_rate == -1)
@@ -287,6 +292,10 @@ fill_default_server_options(ServerOptions *options)
                options->ip_qos_bulk = IPTOS_THROUGHPUT;
        if (options->version_addendum == NULL)
                options->version_addendum = xstrdup("");
+       if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
+               options->fwd_opts.streamlocal_bind_mask = 0177;
+       if (options->fwd_opts.streamlocal_bind_unlink == -1)
+               options->fwd_opts.streamlocal_bind_unlink = 0;
        /* Turn privilege separation on by default */
        if (use_privsep == -1)
                use_privsep = PRIVSEP_NOSANDBOX;
@@ -322,6 +331,8 @@ typedef enum {
        sKexAlgorithms, sIPQoS, sVersionAddendum,
        sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
        sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
+       sStreamLocalBindMask, sStreamLocalBindUnlink,
+       sAllowStreamLocalForwarding,
        sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -437,6 +448,9 @@ static struct {
        { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
        { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
        { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
+       { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
+       { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
+       { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
        { NULL, sBadOption, 0 }
 };
 
@@ -1148,7 +1162,7 @@ process_server_config_line(ServerOptions *options, char *line,
                break;
 
        case sGatewayPorts:
-               intptr = &options->gateway_ports;
+               intptr = &options->fwd_opts.gateway_ports;
                multistate_ptr = multistate_gatewayports;
                goto parse_multistate;
 
@@ -1183,6 +1197,11 @@ process_server_config_line(ServerOptions *options, char *line,
                multistate_ptr = multistate_tcpfwd;
                goto parse_multistate;
 
+       case sAllowStreamLocalForwarding:
+               intptr = &options->allow_streamlocal_forwarding;
+               multistate_ptr = multistate_tcpfwd;
+               goto parse_multistate;
+
        case sAllowAgentForwarding:
                intptr = &options->allow_agent_forwarding;
                goto parse_flag;
@@ -1581,6 +1600,22 @@ process_server_config_line(ServerOptions *options, char *line,
                }
                return 0;
 
+       case sStreamLocalBindMask:
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing StreamLocalBindMask argument.",
+                           filename, linenum);
+               /* Parse mode in octal format */
+               value = strtol(arg, &p, 8);
+               if (arg == p || value < 0 || value > 0777)
+                       fatal("%s line %d: Bad mask.", filename, linenum);
+               options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
+               break;
+
+       case sStreamLocalBindUnlink:
+               intptr = &options->fwd_opts.streamlocal_bind_unlink;
+               goto parse_flag;
+
        case sDeprecated:
                logit("%s line %d: Deprecated option %s",
                    filename, linenum, arg);
@@ -1720,9 +1755,10 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
        M_CP_INTOPT(permit_empty_passwd);
 
        M_CP_INTOPT(allow_tcp_forwarding);
+       M_CP_INTOPT(allow_streamlocal_forwarding);
        M_CP_INTOPT(allow_agent_forwarding);
        M_CP_INTOPT(permit_tun);
-       M_CP_INTOPT(gateway_ports);
+       M_CP_INTOPT(fwd_opts.gateway_ports);
        M_CP_INTOPT(x11_display_offset);
        M_CP_INTOPT(x11_forwarding);
        M_CP_INTOPT(x11_use_localhost);
@@ -1820,6 +1856,8 @@ fmt_intarg(ServerOpCodes code, int val)
                return fmt_multistate_int(val, multistate_privsep);
        case sAllowTcpForwarding:
                return fmt_multistate_int(val, multistate_tcpfwd);
+       case sAllowStreamLocalForwarding:
+               return fmt_multistate_int(val, multistate_tcpfwd);
        case sProtocol:
                switch (val) {
                case SSH_PROTO_1:
@@ -1971,9 +2009,10 @@ dump_config(ServerOptions *o)
        dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
        dump_cfg_fmtint(sUseLogin, o->use_login);
        dump_cfg_fmtint(sCompression, o->compression);
-       dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
+       dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports);
        dump_cfg_fmtint(sUseDNS, o->use_dns);
        dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+       dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
        dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
 
        /* string arguments */
index 70f237a..2bca3cb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.113 2014/07/03 22:40:43 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.114 2014/07/15 15:54:14 millert Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -92,7 +92,7 @@ typedef struct {
        char   *macs;           /* Supported SSH2 macs. */
        char   *kex_algorithms; /* SSH2 kex methods in order of preference. */
        int     protocol;       /* Supported protocol versions. */
-       int     gateway_ports;  /* If true, allow remote connects to forwarded ports. */
+       struct ForwardOptions fwd_opts; /* forwarding options */
        SyslogFacility log_facility;    /* Facility for system logging. */
        LogLevel log_level;     /* Level for system logging. */
        int     rhosts_rsa_authentication;      /* If true, permit rhosts RSA
@@ -124,6 +124,7 @@ typedef struct {
        int     use_login;      /* If true, login(1) is used */
        int     compression;    /* If true, compression is allowed */
        int     allow_tcp_forwarding; /* One of FORWARD_* */
+       int     allow_streamlocal_forwarding; /* One of FORWARD_* */
        int     allow_agent_forwarding;
        u_int num_allow_users;
        char   *allow_users[MAX_ALLOW_USERS];
index 8f6e492..093d887 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.171 2014/04/29 13:10:30 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.172 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -57,6 +57,7 @@
 #include "packet.h"
 #include "buffer.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "canohost.h"
 #include "sshpty.h"
@@ -73,7 +74,6 @@
 #include "dispatch.h"
 #include "auth-options.h"
 #include "serverloop.h"
-#include "misc.h"
 #include "roaming.h"
 
 extern ServerOptions options;
@@ -938,7 +938,7 @@ server_request_direct_tcpip(void)
        /* XXX fine grained permissions */
        if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
            !no_port_forwarding_flag) {
-               c = channel_connect_to(target, target_port,
+               c = channel_connect_to_port(target, target_port,
                    "direct-tcpip", "direct-tcpip");
        } else {
                logit("refused local port forward: "
@@ -952,6 +952,38 @@ server_request_direct_tcpip(void)
        return c;
 }
 
+static Channel *
+server_request_direct_streamlocal(void)
+{
+       Channel *c = NULL;
+       char *target, *originator;
+       u_short originator_port;
+
+       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 fine grained permissions */
+       if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 &&
+           !no_port_forwarding_flag) {
+               c = channel_connect_to_path(target,
+                   "direct-streamlocal@openssh.com", "direct-streamlocal");
+       } else {
+               logit("refused streamlocal port forward: "
+                   "originator %s port %d, target %s",
+                   originator, originator_port, target);
+       }
+
+       free(originator);
+       free(target);
+
+       return c;
+}
+
 static Channel *
 server_request_tun(void)
 {
@@ -1044,6 +1076,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt)
                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();
        }
@@ -1088,44 +1122,71 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
        /* -R style forwarding */
        if (strcmp(rtype, "tcpip-forward") == 0) {
                struct passwd *pw;
-               char *listen_address;
-               u_short listen_port;
+               struct Forward fwd;
 
                pw = the_authctxt->pw;
                if (pw == NULL || !the_authctxt->valid)
                        fatal("server_input_global_request: no/invalid user");
-               listen_address = packet_get_string(NULL);
-               listen_port = (u_short)packet_get_int();
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_host = packet_get_string(NULL);
+               fwd.listen_port = (u_short)packet_get_int();
                debug("server_input_global_request: tcpip-forward listen %s port %d",
-                   listen_address, listen_port);
+                   fwd.listen_host, fwd.listen_port);
 
                /* check permissions */
                if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
                    no_port_forwarding_flag ||
-                   (!want_reply && listen_port == 0) ||
-                   (listen_port != 0 && listen_port < IPPORT_RESERVED &&
+                   (!want_reply && fwd.listen_port == 0) ||
+                   (fwd.listen_port != 0 && fwd.listen_port < IPPORT_RESERVED &&
                    pw->pw_uid != 0)) {
                        success = 0;
                        packet_send_debug("Server has disabled port forwarding.");
                } else {
                        /* Start listening on the port */
-                       success = channel_setup_remote_fwd_listener(
-                           listen_address, listen_port,
-                           &allocated_listen_port, options.gateway_ports);
+                       success = channel_setup_remote_fwd_listener(&fwd,
+                           &allocated_listen_port, &options.fwd_opts);
                }
-               free(listen_address);
+               free(fwd.listen_host);
        } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
-               char *cancel_address;
-               u_short cancel_port;
+               struct Forward fwd;
 
-               cancel_address = packet_get_string(NULL);
-               cancel_port = (u_short)packet_get_int();
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_host = packet_get_string(NULL);
+               fwd.listen_port = (u_short)packet_get_int();
                debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
-                   cancel_address, cancel_port);
+                   fwd.listen_host, fwd.listen_port);
+
+               success = channel_cancel_rport_listener(&fwd);
+               free(fwd.listen_host);
+       } else if (strcmp(rtype, "streamlocal-forward@openssh.com") == 0) {
+               struct Forward fwd;
+
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_path = packet_get_string(NULL);
+               debug("server_input_global_request: streamlocal-forward listen path %s",
+                   fwd.listen_path);
+
+               /* check permissions */
+               if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0
+                   || no_port_forwarding_flag) {
+                       success = 0;
+                       packet_send_debug("Server has disabled port forwarding.");
+               } else {
+                       /* Start listening on the socket */
+                       success = channel_setup_remote_fwd_listener(
+                           &fwd, NULL, &options.fwd_opts);
+               }
+               free(fwd.listen_path);
+       } else if (strcmp(rtype, "cancel-streamlocal-forward@openssh.com") == 0) {
+               struct Forward fwd;
+
+               memset(&fwd, 0, sizeof(fwd));
+               fwd.listen_path = packet_get_string(NULL);
+               debug("%s: cancel-streamlocal-forward path %s", __func__,
+                   fwd.listen_path);
 
-               success = channel_cancel_rport_listener(cancel_address,
-                   cancel_port);
-               free(cancel_address);
+               success = channel_cancel_rport_listener(&fwd);
+               free(fwd.listen_path);
        } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
                no_more_sessions = 1;
                success = 1;
index 6571f07..20c94ec 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.273 2014/07/03 22:40:43 djm Exp $ */
+/* $OpenBSD: session.c,v 1.274 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
 #include "authfd.h"
 #include "pathnames.h"
 #include "log.h"
+#include "misc.h"
 #include "servconf.h"
 #include "sshlogin.h"
 #include "serverloop.h"
 #include "canohost.h"
-#include "misc.h"
 #include "session.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
@@ -166,7 +166,6 @@ auth_input_request_forwarding(struct passwd * pw)
 {
        Channel *nc;
        int sock = -1;
-       struct sockaddr_un sunaddr;
 
        if (auth_sock_name != NULL) {
                error("authentication forwarding requested twice.");
@@ -192,33 +191,15 @@ auth_input_request_forwarding(struct passwd * pw)
        xasprintf(&auth_sock_name, "%s/agent.%ld",
            auth_sock_dir, (long) getpid());
 
-       /* Create the socket. */
-       sock = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (sock < 0) {
-               error("socket: %.100s", strerror(errno));
-               restore_uid();
-               goto authsock_err;
-       }
-
-       /* Bind it to the name. */
-       memset(&sunaddr, 0, sizeof(sunaddr));
-       sunaddr.sun_family = AF_UNIX;
-       strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
-
-       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
-               error("bind: %.100s", strerror(errno));
-               restore_uid();
-               goto authsock_err;
-       }
+       /* Start a Unix listener on auth_sock_name. */
+       sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0);
 
        /* Restore the privileged uid. */
        restore_uid();
 
-       /* Start listening on the socket. */
-       if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
-               error("listen: %.100s", strerror(errno));
+       /* Check for socket/bind/listen failure. */
+       if (sock < 0)
                goto authsock_err;
-       }
 
        /* Allocate a channel for the authentication agent socket. */
        nc = channel_new("auth socket",
@@ -257,6 +238,7 @@ do_authenticated(Authctxt *authctxt)
        setproctitle("%s", authctxt->pw->pw_name);
 
        /* setup the channel layer */
+       /* XXX - streamlocal? */
        if (no_port_forwarding_flag ||
            (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
                channel_disable_adm_local_opens();
@@ -376,7 +358,7 @@ do_authenticated1(Authctxt *authctxt)
                        }
                        debug("Received TCP/IP port forwarding request.");
                        if (channel_input_port_forward_request(s->pw->pw_uid == 0,
-                           options.gateway_ports) < 0) {
+                           &options.fwd_opts) < 0) {
                                debug("Port forwarding failed.");
                                break;
                        }
index 4c0b618..56cee5b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.187 2014/07/03 03:11:03 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.188 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1022,7 +1022,6 @@ main(int ac, char **av)
        u_int nalloc;
        char *shell, *format, *pidstr, *agentsocket = NULL;
        fd_set *readsetp = NULL, *writesetp = NULL;
-       struct sockaddr_un sunaddr;
        struct rlimit rlim;
        extern int optind;
        extern char *optarg;
@@ -1134,24 +1133,12 @@ main(int ac, char **av)
         * Create socket early so it will exist before command gets run from
         * the parent.
         */
-       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0);
        if (sock < 0) {
-               perror("socket");
-               *socket_name = '\0'; /* Don't unlink any existing file */
-               cleanup_exit(1);
-       }
-       memset(&sunaddr, 0, sizeof(sunaddr));
-       sunaddr.sun_family = AF_UNIX;
-       strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
-       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
-               perror("bind");
+               /* XXX - unix_listener() calls error() not perror() */
                *socket_name = '\0'; /* Don't unlink any existing file */
                cleanup_exit(1);
        }
-       if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
-               perror("listen");
-               cleanup_exit(1);
-       }
 
        /*
         * Fork, and have the parent execute the command, if any, or present
index 950d623..7d71665 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.405 2014/07/03 06:39:19 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.406 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -87,9 +87,9 @@
 #include "dispatch.h"
 #include "clientloop.h"
 #include "log.h"
+#include "misc.h"
 #include "readconf.h"
 #include "sshconnect.h"
-#include "misc.h"
 #include "kex.h"
 #include "mac.h"
 #include "sshpty.h"
@@ -409,7 +409,7 @@ main(int ac, char **av)
        int timeout_ms;
        extern int optind, optreset;
        extern char *optarg;
-       Forward fwd;
+       struct Forward fwd;
        struct addrinfo *addrs = NULL;
        struct ssh_digest_ctx *md;
        u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
@@ -516,7 +516,7 @@ main(int ac, char **av)
                        options.forward_x11_trusted = 1;
                        break;
                case 'g':
-                       options.gateway_ports = 1;
+                       options.fwd_opts.gateway_ports = 1;
                        break;
                case 'O':
                        if (stdio_forward_host != NULL)
@@ -1256,15 +1256,17 @@ fork_postauth(void)
 static void
 ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 {
-       Forward *rfwd = (Forward *)ctxt;
+       struct Forward *rfwd = (struct Forward *)ctxt;
 
        /* XXX verbose() on failure? */
        debug("remote forward %s for: listen %s%s%d, connect %s:%d",
            type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
-           rfwd->listen_host == NULL ? "" : rfwd->listen_host,
-           rfwd->listen_host == NULL ? "" : ":",
-           rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
-       if (rfwd->listen_port == 0) {
+           rfwd->listen_path ? rfwd->listen_path :
+           rfwd->listen_host ? rfwd->listen_host : "",
+           (rfwd->listen_path || rfwd->listen_host) ? ":" : "",
+           rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path :
+           rfwd->connect_host, rfwd->connect_port);
+       if (rfwd->listen_path == NULL && rfwd->listen_port == 0) {
                if (type == SSH2_MSG_REQUEST_SUCCESS) {
                        rfwd->allocated_port = packet_get_int();
                        logit("Allocated port %u for remote forward to %s:%d",
@@ -1278,12 +1280,21 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
        }
        
        if (type == SSH2_MSG_REQUEST_FAILURE) {
-               if (options.exit_on_forward_failure)
-                       fatal("Error: remote port forwarding failed for "
-                           "listen port %d", rfwd->listen_port);
-               else
-                       logit("Warning: remote port forwarding failed for "
-                           "listen port %d", rfwd->listen_port);
+               if (options.exit_on_forward_failure) {
+                       if (rfwd->listen_path != NULL)
+                               fatal("Error: remote port forwarding failed "
+                                   "for listen path %s", rfwd->listen_path);
+                       else
+                               fatal("Error: remote port forwarding failed "
+                                   "for listen port %d", rfwd->listen_port);
+               } else {
+                       if (rfwd->listen_path != NULL)
+                               logit("Warning: remote port forwarding failed "
+                                   "for listen path %s", rfwd->listen_path);
+                       else
+                               logit("Warning: remote port forwarding failed "
+                                   "for listen port %d", rfwd->listen_port);
+               }
        }
        if (++remote_forward_confirms_received == options.num_remote_forwards) {
                debug("All remote forwarding requests processed");
@@ -1331,18 +1342,18 @@ ssh_init_forwarding(void)
        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_path != NULL) ?
+                   options.local_forwards[i].listen_path :
                    (options.local_forwards[i].listen_host == NULL) ?
-                   (options.gateway_ports ? "*" : "LOCALHOST") :
+                   (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") :
                    options.local_forwards[i].listen_host,
                    options.local_forwards[i].listen_port,
+                   (options.local_forwards[i].connect_path != NULL) ?
+                   options.local_forwards[i].connect_path :
                    options.local_forwards[i].connect_host,
                    options.local_forwards[i].connect_port);
                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);
+                   &options.local_forwards[i], &options.fwd_opts);
        }
        if (i > 0 && success != i && options.exit_on_forward_failure)
                fatal("Could not request local forwarding.");
@@ -1353,17 +1364,18 @@ ssh_init_forwarding(void)
        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_path != NULL) ?
+                   options.remote_forwards[i].listen_path :
                    (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_path != NULL) ?
+                   options.remote_forwards[i].connect_path :
                    options.remote_forwards[i].connect_host,
                    options.remote_forwards[i].connect_port);
                options.remote_forwards[i].handle =
                    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);
+                   &options.remote_forwards[i]);
                if (options.remote_forwards[i].handle < 0) {
                        if (options.exit_on_forward_failure)
                                fatal("Could not request remote forwarding.");
index 71b9bdc..f9ede7a 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh_config.5,v 1.190 2014/07/07 08:19:12 djm Exp $
-.Dd $Mdocdate: July 7 2014 $
+.\" $OpenBSD: ssh_config.5,v 1.191 2014/07/15 15:54:14 millert Exp $
+.Dd $Mdocdate: July 15 2014 $
 .Dt SSH_CONFIG 5
 .Os
 .Sh NAME
@@ -1303,6 +1303,33 @@ channel to request a response from the server.
 The default
 is 0, indicating that these messages will not be sent to the server.
 This option applies to protocol version 2 only.
+.It Cm StreamLocalBindMask
+Sets the octal file creation mode mask
+.Pq umask
+used when creating a Unix-domain socket file for local or remote
+port forwarding.
+This option is only used for port forwarding to a Unix-domain socket file.
+.Pp
+The default value is 0177, which creates a Unix-domain socket file that is
+readable and writable only by the owner.
+Note that not all operating systems honor the file mode on Unix-domain
+socket files.
+.It Cm StreamLocalBindUnlink
+Specifies whether to remove an existing Unix-domain socket file for local
+or remote port forwarding before creating a new one.
+If the socket file already exists and
+.Cm StreamLocalBindUnlink
+is not enabled,
+.Nm ssh
+will be unable to forward the port to the Unix-domain socket file.
+This option is only used for port forwarding to a Unix-domain socket file.
+.Pp
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
 .It Cm StrictHostKeyChecking
 If this flag is set to
 .Dq yes ,
index e528e02..69ae94c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.250 2014/07/03 22:23:46 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -44,9 +44,9 @@
 #include "sshconnect.h"
 #include "hostfile.h"
 #include "log.h"
+#include "misc.h"
 #include "readconf.h"
 #include "atomicio.h"
-#include "misc.h"
 #include "dns.h"
 #include "roaming.h"
 #include "monitor_fdpass.h"
index d6f680f..82eeecf 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect1.c,v 1.75 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: sshconnect1.c,v 1.76 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include "kex.h"
 #include "uidswap.h"
 #include "log.h"
+#include "misc.h"
 #include "readconf.h"
 #include "authfd.h"
 #include "sshconnect.h"
 #include "authfile.h"
-#include "misc.h"
 #include "canohost.h"
 #include "hostfile.h"
 #include "auth.h"
index c41ce64..943135d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.209 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.210 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -55,8 +55,8 @@
 #include "dh.h"
 #include "authfd.h"
 #include "log.h"
-#include "readconf.h"
 #include "misc.h"
+#include "readconf.h"
 #include "match.h"
 #include "dispatch.h"
 #include "canohost.h"
index 50ebb24..3cda0d2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.427 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.428 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -75,6 +75,7 @@
 #include "packet.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 #include "uidswap.h"
 #include "compat.h"
@@ -90,7 +91,6 @@
 #include "hostfile.h"
 #include "auth.h"
 #include "authfd.h"
-#include "misc.h"
 #include "msg.h"
 #include "dispatch.h"
 #include "channels.h"
index 9cc87cb..fc2dfc2 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.174 2014/07/03 22:40:43 djm Exp $
-.Dd $Mdocdate: July 3 2014 $
+.\" $OpenBSD: sshd_config.5,v 1.175 2014/07/15 15:54:14 millert Exp $
+.Dd $Mdocdate: July 15 2014 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -140,6 +140,26 @@ The default is
 Note that disabling TCP forwarding does not improve security unless
 users are also denied shell access, as they can always install their
 own forwarders.
+.It Cm AllowStreamLocalForwarding
+Specifies whether StreamLocal (Unix-domain socket) forwarding is permitted.
+The available options are
+.Dq yes
+or
+.Dq all
+to allow StreamLocal forwarding,
+.Dq no
+to prevent all StreamLocal forwarding,
+.Dq local
+to allow local (from the perspective of
+.Xr ssh 1 )
+forwarding only or
+.Dq remote
+to allow remote forwarding only.
+The default is
+.Dq yes .
+Note that disabling StreamLocal forwarding does not improve security unless
+users are also denied shell access, as they can always install their
+own forwarders.
 .It Cm AllowUsers
 This keyword can be followed by a list of user name patterns, separated
 by spaces.
@@ -1172,6 +1192,33 @@ This option applies to protocol version 1 only.
 .It Cm ServerKeyBits
 Defines the number of bits in the ephemeral protocol version 1 server key.
 The minimum value is 512, and the default is 1024.
+.It Cm StreamLocalBindMask
+Sets the octal file creation mode mask
+.Pq umask
+used when creating a Unix-domain socket file for local or remote
+port forwarding.
+This option is only used for port forwarding to a Unix-domain socket file.
+.Pp
+The default value is 0177, which creates a Unix-domain socket file that is
+readable and writable only by the owner.
+Note that not all operating systems honor the file mode on Unix-domain
+socket files.
+.It Cm StreamLocalBindUnlink
+Specifies whether to remove an existing Unix-domain socket file for local
+or remote port forwarding before creating a new one.
+If the socket file already exists and
+.Cm StreamLocalBindUnlink
+is not enabled,
+.Nm sshd
+will be unable to forward the port to the Unix-domain socket file.
+This option is only used for port forwarding to a Unix-domain socket file.
+.Pp
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
 .It Cm StrictModes
 Specifies whether
 .Xr sshd 8
index 601d072..0f646cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshlogin.c,v 1.28 2014/01/31 16:39:19 tedu Exp $ */
+/* $OpenBSD: sshlogin.c,v 1.29 2014/07/15 15:54:14 millert Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -56,6 +56,7 @@
 #include "sshlogin.h"
 #include "log.h"
 #include "buffer.h"
+#include "misc.h"
 #include "servconf.h"
 
 extern Buffer loginmsg;