-# $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"
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
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
-# $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
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"
${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 \
${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 \
${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"
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
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 $
-/* $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
#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"
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 "
-/* $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
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
-/* $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
#include "uidswap.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
-/* $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;
-/* $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
#include "buffer.h"
#include "pathnames.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "auth-options.h"
#endif
#include "monitor_wrap.h"
#include "ssh.h"
-#include "misc.h"
#include "digest.h"
-/* $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.
*
#include "groupaccess.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "key.h"
#include "hostfile.h"
#include "auth-options.h"
#include "canohost.h"
#include "uidswap.h"
-#include "misc.h"
#include "packet.h"
#ifdef GSSAPI
#include "ssh-gss.h"
-/* $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
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
-/* $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.
*
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
-/* $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.
*
#include "auth.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
/* import */
-/* $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.
*
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "ssh2.h"
-/* $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.
*
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
+#include "misc.h"
#include "servconf.h"
/* import */
-/* $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.
*
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
#include "ssh-gss.h"
#endif
#include "monitor_wrap.h"
-#include "misc.h"
#include "authfile.h"
#include "match.h"
-/* $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.
*
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "compat.h"
#include "key.h"
-/* $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
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
< 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) {
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)
-/* $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
*/
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <sys/socket.h>
* 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. */
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;
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)
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:
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:
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);
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",
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);
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);
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;
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
channel_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;
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);
*/
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
}
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;
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) {
}
/* 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);
/*
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;
* 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. */
}
/*
- * 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);
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;
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];
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);
+ }
}
/*
* 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();
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;
}
/*
- * 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;
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;
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) {
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);
}
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++;
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;
}
}
= 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;
}
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;
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;
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,
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;
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;
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;
}
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,
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;
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)
{
-/* $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>
#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
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);
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 */
-/* $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"
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);
/* 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;
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;
}
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 */
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);
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)
{
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) {
-/* $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.
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/param.h>
#include <net/if.h>
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;
+}
-/* $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 *);
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);
#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)));
-/* $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>
#include "sshlogin.h"
#include "canohost.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "monitor.h"
#include "monitor_mm.h"
#endif
#include "monitor_wrap.h"
#include "monitor_fdpass.h"
-#include "misc.h"
#include "compat.h"
#include "ssh2.h"
#include "roaming.h"
-/* $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>
*
}
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:
}
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;
{
struct mux_channel_confirm_ctx *fctx = ctxt;
char *failmsg = NULL;
- Forward *rfwd;
+ struct Forward *rfwd;
Channel *c;
Buffer out;
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();
} 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);
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)));
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;
}
}
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);
} 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);
free(fwd_desc);
if (freefwd) {
free(fwd.listen_host);
+ free(fwd.listen_path);
free(fwd.connect_host);
+ free(fwd.connect_path);
}
return ret;
}
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)));
* 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";
}
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);
}
out:
free(fwd_desc);
- free(fwd.listen_host);
- free(fwd.connect_host);
+ free(listen_addr);
+ free(connect_addr);
return ret;
}
void
muxserver_listen(void)
{
- struct sockaddr_un addr;
mode_t old_umask;
char *orig_control_path = options.control_path;
char rbuf[16+1];
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);
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) {
}
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;
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)
-/* $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
#include "crc32.h"
#include "compress.h"
#include "deattack.h"
-#include "channels.h"
#include "compat.h"
#include "ssh1.h"
#include "ssh2.h"
#include "log.h"
#include "canohost.h"
#include "misc.h"
+#include "channels.h"
#include "ssh.h"
#include "ssherr.h"
#include "roaming.h"
-/* $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
#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>
#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"
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
+ oStreamLocalBindMask, oStreamLocalBindUnlink,
oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
+ { "streamlocalbindmask", oStreamLocalBindMask },
+ { "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "ignoreunknown", oIgnoreUnknown },
{ NULL, oBadOption }
*/
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,
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;
}
/*
*/
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,
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;
}
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);
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);
LogLevel *log_level_ptr;
long long val64;
size_t len;
- Forward fwd;
+ struct Forward fwd;
const struct multistate *multistate_ptr;
struct allowed_cname *cname;
goto parse_time;
case oGatewayPorts:
- intptr = &options->gateway_ports;
+ intptr = &options->fwd_opts.gateway_ports;
goto parse_flag;
case oExitOnForwardFailure:
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);
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;
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)
/* 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);
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 */
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);
}
-/* $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;
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. */
/* 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;
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 */
-/* $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"
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;
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;
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)
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;
sKexAlgorithms, sIPQoS, sVersionAddendum,
sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
+ sStreamLocalBindMask, sStreamLocalBindUnlink,
+ sAllowStreamLocalForwarding,
sDeprecated, sUnsupported
} ServerOpCodes;
{ "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 }
};
break;
case sGatewayPorts:
- intptr = &options->gateway_ports;
+ intptr = &options->fwd_opts.gateway_ports;
multistate_ptr = multistate_gatewayports;
goto parse_multistate;
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;
}
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);
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);
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:
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 */
-/* $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>
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
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];
-/* $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
#include "packet.h"
#include "buffer.h"
#include "log.h"
+#include "misc.h"
#include "servconf.h"
#include "canohost.h"
#include "sshpty.h"
#include "dispatch.h"
#include "auth-options.h"
#include "serverloop.h"
-#include "misc.h"
#include "roaming.h"
extern ServerOptions options;
/* 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: "
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)
{
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();
}
/* -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;
-/* $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"
{
Channel *nc;
int sock = -1;
- struct sockaddr_un sunaddr;
if (auth_sock_name != NULL) {
error("authentication forwarding requested twice.");
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",
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();
}
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;
}
-/* $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
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;
* 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
-/* $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
#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"
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];
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)
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",
}
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");
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.");
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.");
.\" (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
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 ,
-/* $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
#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"
-/* $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"
-/* $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.
#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"
-/* $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
#include "packet.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
#include "uidswap.h"
#include "compat.h"
#include "hostfile.h"
#include "auth.h"
#include "authfd.h"
-#include "misc.h"
#include "msg.h"
#include "dispatch.h"
#include "channels.h"
.\" (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
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.
.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
-/* $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
#include "sshlogin.h"
#include "log.h"
#include "buffer.h"
+#include "misc.h"
#include "servconf.h"
extern Buffer loginmsg;