summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
committerDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
commit7acefbbcbeab725420ea07397ae35992f505f702 (patch)
treebfb07917715d425438dab987a47ccd7a8d7f118b /channels.c
parent6262d760e00714523633bd989d62e273a3dca99a (diff)
- millert@cvs.openbsd.org 2014/07/15 15:54:14
[PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c] [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h] [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c] [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c] [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c] [sshd_config.5 sshlogin.c] Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket. This is a reimplementation of the streamlocal patches by William Ahern from: http://www.25thandclement.com/~william/projects/streamlocal.html OK djm@ markus@
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c600
1 files changed, 483 insertions, 117 deletions
diff --git a/channels.c b/channels.c
index dcd75346b..d67fdf48b 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.335 2014/07/05 23:11:48 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.336 2014/07/15 15:54:14 millert Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -42,6 +42,7 @@
42#include "includes.h" 42#include "includes.h"
43 43
44#include <sys/types.h> 44#include <sys/types.h>
45#include <sys/stat.h>
45#include <sys/ioctl.h> 46#include <sys/ioctl.h>
46#include <sys/un.h> 47#include <sys/un.h>
47#include <sys/socket.h> 48#include <sys/socket.h>
@@ -107,11 +108,15 @@ static int channel_max_fd = 0;
107 * a corrupt remote server from accessing arbitrary TCP/IP ports on our local 108 * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
108 * network (which might be behind a firewall). 109 * network (which might be behind a firewall).
109 */ 110 */
111/* XXX: streamlocal wants a path instead of host:port */
112/* Overload host_to_connect; we could just make this match Forward */
113/* XXX - can we use listen_host instead of listen_path? */
110typedef struct { 114typedef struct {
111 char *host_to_connect; /* Connect to 'host'. */ 115 char *host_to_connect; /* Connect to 'host'. */
112 u_short port_to_connect; /* Connect to 'port'. */ 116 int port_to_connect; /* Connect to 'port'. */
113 char *listen_host; /* Remote side should listen address. */ 117 char *listen_host; /* Remote side should listen address. */
114 u_short listen_port; /* Remote side should listen port. */ 118 char *listen_path; /* Remote side should listen path. */
119 int listen_port; /* Remote side should listen port. */
115} ForwardPermission; 120} ForwardPermission;
116 121
117/* List of all permitted host/port pairs to connect by the user. */ 122/* List of all permitted host/port pairs to connect by the user. */
@@ -474,6 +479,8 @@ channel_stop_listening(void)
474 case SSH_CHANNEL_PORT_LISTENER: 479 case SSH_CHANNEL_PORT_LISTENER:
475 case SSH_CHANNEL_RPORT_LISTENER: 480 case SSH_CHANNEL_RPORT_LISTENER:
476 case SSH_CHANNEL_X11_LISTENER: 481 case SSH_CHANNEL_X11_LISTENER:
482 case SSH_CHANNEL_UNIX_LISTENER:
483 case SSH_CHANNEL_RUNIX_LISTENER:
477 channel_close_fd(&c->sock); 484 channel_close_fd(&c->sock);
478 channel_free(c); 485 channel_free(c);
479 break; 486 break;
@@ -536,6 +543,8 @@ channel_still_open(void)
536 case SSH_CHANNEL_CONNECTING: 543 case SSH_CHANNEL_CONNECTING:
537 case SSH_CHANNEL_ZOMBIE: 544 case SSH_CHANNEL_ZOMBIE:
538 case SSH_CHANNEL_ABANDONED: 545 case SSH_CHANNEL_ABANDONED:
546 case SSH_CHANNEL_UNIX_LISTENER:
547 case SSH_CHANNEL_RUNIX_LISTENER:
539 continue; 548 continue;
540 case SSH_CHANNEL_LARVAL: 549 case SSH_CHANNEL_LARVAL:
541 if (!compat20) 550 if (!compat20)
@@ -582,6 +591,8 @@ channel_find_open(void)
582 case SSH_CHANNEL_CONNECTING: 591 case SSH_CHANNEL_CONNECTING:
583 case SSH_CHANNEL_ZOMBIE: 592 case SSH_CHANNEL_ZOMBIE:
584 case SSH_CHANNEL_ABANDONED: 593 case SSH_CHANNEL_ABANDONED:
594 case SSH_CHANNEL_UNIX_LISTENER:
595 case SSH_CHANNEL_RUNIX_LISTENER:
585 continue; 596 continue;
586 case SSH_CHANNEL_LARVAL: 597 case SSH_CHANNEL_LARVAL:
587 case SSH_CHANNEL_AUTH_SOCKET: 598 case SSH_CHANNEL_AUTH_SOCKET:
@@ -632,6 +643,8 @@ channel_open_message(void)
632 case SSH_CHANNEL_ABANDONED: 643 case SSH_CHANNEL_ABANDONED:
633 case SSH_CHANNEL_MUX_CLIENT: 644 case SSH_CHANNEL_MUX_CLIENT:
634 case SSH_CHANNEL_MUX_LISTENER: 645 case SSH_CHANNEL_MUX_LISTENER:
646 case SSH_CHANNEL_UNIX_LISTENER:
647 case SSH_CHANNEL_RUNIX_LISTENER:
635 continue; 648 continue;
636 case SSH_CHANNEL_LARVAL: 649 case SSH_CHANNEL_LARVAL:
637 case SSH_CHANNEL_OPENING: 650 case SSH_CHANNEL_OPENING:
@@ -1387,7 +1400,6 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
1387static void 1400static void
1388port_open_helper(Channel *c, char *rtype) 1401port_open_helper(Channel *c, char *rtype)
1389{ 1402{
1390 int direct;
1391 char buf[1024]; 1403 char buf[1024];
1392 char *local_ipaddr = get_local_ipaddr(c->sock); 1404 char *local_ipaddr = get_local_ipaddr(c->sock);
1393 int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1); 1405 int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1);
@@ -1401,8 +1413,6 @@ port_open_helper(Channel *c, char *rtype)
1401 remote_port = 65535; 1413 remote_port = 65535;
1402 } 1414 }
1403 1415
1404 direct = (strcmp(rtype, "direct-tcpip") == 0);
1405
1406 snprintf(buf, sizeof buf, 1416 snprintf(buf, sizeof buf,
1407 "%s: listening port %d for %.100s port %d, " 1417 "%s: listening port %d for %.100s port %d, "
1408 "connect from %.200s port %d to %.100s port %d", 1418 "connect from %.200s port %d to %.100s port %d",
@@ -1418,18 +1428,29 @@ port_open_helper(Channel *c, char *rtype)
1418 packet_put_int(c->self); 1428 packet_put_int(c->self);
1419 packet_put_int(c->local_window_max); 1429 packet_put_int(c->local_window_max);
1420 packet_put_int(c->local_maxpacket); 1430 packet_put_int(c->local_maxpacket);
1421 if (direct) { 1431 if (strcmp(rtype, "direct-tcpip") == 0) {
1422 /* target host, port */ 1432 /* target host, port */
1423 packet_put_cstring(c->path); 1433 packet_put_cstring(c->path);
1424 packet_put_int(c->host_port); 1434 packet_put_int(c->host_port);
1435 } else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
1436 /* target path */
1437 packet_put_cstring(c->path);
1438 } else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1439 /* listen path */
1440 packet_put_cstring(c->path);
1425 } else { 1441 } else {
1426 /* listen address, port */ 1442 /* listen address, port */
1427 packet_put_cstring(c->path); 1443 packet_put_cstring(c->path);
1428 packet_put_int(local_port); 1444 packet_put_int(local_port);
1429 } 1445 }
1430 /* originator host and port */ 1446 if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
1431 packet_put_cstring(remote_ipaddr); 1447 /* reserved for future owner/mode info */
1432 packet_put_int((u_int)remote_port); 1448 packet_put_cstring("");
1449 } else {
1450 /* originator host and port */
1451 packet_put_cstring(remote_ipaddr);
1452 packet_put_int((u_int)remote_port);
1453 }
1433 packet_send(); 1454 packet_send();
1434 } else { 1455 } else {
1435 packet_start(SSH_MSG_PORT_OPEN); 1456 packet_start(SSH_MSG_PORT_OPEN);
@@ -1479,14 +1500,18 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1479 if (c->type == SSH_CHANNEL_RPORT_LISTENER) { 1500 if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
1480 nextstate = SSH_CHANNEL_OPENING; 1501 nextstate = SSH_CHANNEL_OPENING;
1481 rtype = "forwarded-tcpip"; 1502 rtype = "forwarded-tcpip";
1503 } else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) {
1504 nextstate = SSH_CHANNEL_OPENING;
1505 rtype = "forwarded-streamlocal@openssh.com";
1506 } else if (c->host_port == PORT_STREAMLOCAL) {
1507 nextstate = SSH_CHANNEL_OPENING;
1508 rtype = "direct-streamlocal@openssh.com";
1509 } else if (c->host_port == 0) {
1510 nextstate = SSH_CHANNEL_DYNAMIC;
1511 rtype = "dynamic-tcpip";
1482 } else { 1512 } else {
1483 if (c->host_port == 0) { 1513 nextstate = SSH_CHANNEL_OPENING;
1484 nextstate = SSH_CHANNEL_DYNAMIC; 1514 rtype = "direct-tcpip";
1485 rtype = "dynamic-tcpip";
1486 } else {
1487 nextstate = SSH_CHANNEL_OPENING;
1488 rtype = "direct-tcpip";
1489 }
1490 } 1515 }
1491 1516
1492 addrlen = sizeof(addr); 1517 addrlen = sizeof(addr);
@@ -1499,7 +1524,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1499 c->notbefore = monotime() + 1; 1524 c->notbefore = monotime() + 1;
1500 return; 1525 return;
1501 } 1526 }
1502 set_nodelay(newsock); 1527 if (c->host_port != PORT_STREAMLOCAL)
1528 set_nodelay(newsock);
1503 nc = channel_new(rtype, nextstate, newsock, newsock, -1, 1529 nc = channel_new(rtype, nextstate, newsock, newsock, -1,
1504 c->local_window_max, c->local_maxpacket, 0, rtype, 1); 1530 c->local_window_max, c->local_maxpacket, 0, rtype, 1);
1505 nc->listening_port = c->listening_port; 1531 nc->listening_port = c->listening_port;
@@ -1988,6 +2014,8 @@ channel_handler_init_20(void)
1988 channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; 2014 channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
1989 channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; 2015 channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
1990 channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; 2016 channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener;
2017 channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener;
2018 channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener;
1991 channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; 2019 channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
1992 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 2020 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
1993 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 2021 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
@@ -1998,6 +2026,8 @@ channel_handler_init_20(void)
1998 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 2026 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
1999 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 2027 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
2000 channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; 2028 channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener;
2029 channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener;
2030 channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener;
2001 channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; 2031 channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
2002 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 2032 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
2003 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 2033 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
@@ -2638,7 +2668,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
2638 originator_string = xstrdup("unknown (remote did not supply name)"); 2668 originator_string = xstrdup("unknown (remote did not supply name)");
2639 } 2669 }
2640 packet_check_eom(); 2670 packet_check_eom();
2641 c = channel_connect_to(host, host_port, 2671 c = channel_connect_to_port(host, host_port,
2642 "connected socket", originator_string); 2672 "connected socket", originator_string);
2643 free(originator_string); 2673 free(originator_string);
2644 free(host); 2674 free(host);
@@ -2705,20 +2735,20 @@ channel_set_af(int af)
2705 */ 2735 */
2706static const char * 2736static const char *
2707channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, 2737channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2708 int is_client, int gateway_ports) 2738 int is_client, struct ForwardOptions *fwd_opts)
2709{ 2739{
2710 const char *addr = NULL; 2740 const char *addr = NULL;
2711 int wildcard = 0; 2741 int wildcard = 0;
2712 2742
2713 if (listen_addr == NULL) { 2743 if (listen_addr == NULL) {
2714 /* No address specified: default to gateway_ports setting */ 2744 /* No address specified: default to gateway_ports setting */
2715 if (gateway_ports) 2745 if (fwd_opts->gateway_ports)
2716 wildcard = 1; 2746 wildcard = 1;
2717 } else if (gateway_ports || is_client) { 2747 } else if (fwd_opts->gateway_ports || is_client) {
2718 if (((datafellows & SSH_OLD_FORWARD_ADDR) && 2748 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2719 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || 2749 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2720 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || 2750 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2721 (!is_client && gateway_ports == 1)) { 2751 (!is_client && fwd_opts->gateway_ports == 1)) {
2722 wildcard = 1; 2752 wildcard = 1;
2723 /* 2753 /*
2724 * Notify client if they requested a specific listen 2754 * Notify client if they requested a specific listen
@@ -2752,9 +2782,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2752} 2782}
2753 2783
2754static int 2784static int
2755channel_setup_fwd_listener(int type, const char *listen_addr, 2785channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd,
2756 u_short listen_port, int *allocated_listen_port, 2786 int *allocated_listen_port, struct ForwardOptions *fwd_opts)
2757 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2758{ 2787{
2759 Channel *c; 2788 Channel *c;
2760 int sock, r, success = 0, wildcard = 0, is_client; 2789 int sock, r, success = 0, wildcard = 0, is_client;
@@ -2764,7 +2793,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2764 in_port_t *lport_p; 2793 in_port_t *lport_p;
2765 2794
2766 host = (type == SSH_CHANNEL_RPORT_LISTENER) ? 2795 host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
2767 listen_addr : host_to_connect; 2796 fwd->listen_host : fwd->connect_host;
2768 is_client = (type == SSH_CHANNEL_PORT_LISTENER); 2797 is_client = (type == SSH_CHANNEL_PORT_LISTENER);
2769 2798
2770 if (host == NULL) { 2799 if (host == NULL) {
@@ -2777,9 +2806,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2777 } 2806 }
2778 2807
2779 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ 2808 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2780 addr = channel_fwd_bind_addr(listen_addr, &wildcard, 2809 addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard,
2781 is_client, gateway_ports); 2810 is_client, fwd_opts);
2782 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", 2811 debug3("%s: type %d wildcard %d addr %s", __func__,
2783 type, wildcard, (addr == NULL) ? "NULL" : addr); 2812 type, wildcard, (addr == NULL) ? "NULL" : addr);
2784 2813
2785 /* 2814 /*
@@ -2790,15 +2819,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2790 hints.ai_family = IPv4or6; 2819 hints.ai_family = IPv4or6;
2791 hints.ai_flags = wildcard ? AI_PASSIVE : 0; 2820 hints.ai_flags = wildcard ? AI_PASSIVE : 0;
2792 hints.ai_socktype = SOCK_STREAM; 2821 hints.ai_socktype = SOCK_STREAM;
2793 snprintf(strport, sizeof strport, "%d", listen_port); 2822 snprintf(strport, sizeof strport, "%d", fwd->listen_port);
2794 if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { 2823 if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
2795 if (addr == NULL) { 2824 if (addr == NULL) {
2796 /* This really shouldn't happen */ 2825 /* This really shouldn't happen */
2797 packet_disconnect("getaddrinfo: fatal error: %s", 2826 packet_disconnect("getaddrinfo: fatal error: %s",
2798 ssh_gai_strerror(r)); 2827 ssh_gai_strerror(r));
2799 } else { 2828 } else {
2800 error("channel_setup_fwd_listener: " 2829 error("%s: getaddrinfo(%.64s): %s", __func__, addr,
2801 "getaddrinfo(%.64s): %s", addr,
2802 ssh_gai_strerror(r)); 2830 ssh_gai_strerror(r));
2803 } 2831 }
2804 return 0; 2832 return 0;
@@ -2822,13 +2850,13 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2822 * If allocating a port for -R forwards, then use the 2850 * If allocating a port for -R forwards, then use the
2823 * same port for all address families. 2851 * same port for all address families.
2824 */ 2852 */
2825 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && 2853 if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2826 allocated_listen_port != NULL && *allocated_listen_port > 0) 2854 allocated_listen_port != NULL && *allocated_listen_port > 0)
2827 *lport_p = htons(*allocated_listen_port); 2855 *lport_p = htons(*allocated_listen_port);
2828 2856
2829 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), 2857 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
2830 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 2858 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
2831 error("channel_setup_fwd_listener: getnameinfo failed"); 2859 error("%s: getnameinfo failed", __func__);
2832 continue; 2860 continue;
2833 } 2861 }
2834 /* Create a port to listen for the host. */ 2862 /* Create a port to listen for the host. */
@@ -2865,10 +2893,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2865 } 2893 }
2866 2894
2867 /* 2895 /*
2868 * listen_port == 0 requests a dynamically allocated port - 2896 * fwd->listen_port == 0 requests a dynamically allocated port -
2869 * record what we got. 2897 * record what we got.
2870 */ 2898 */
2871 if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && 2899 if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 &&
2872 allocated_listen_port != NULL && 2900 allocated_listen_port != NULL &&
2873 *allocated_listen_port == 0) { 2901 *allocated_listen_port == 0) {
2874 *allocated_listen_port = get_sock_port(sock, 1); 2902 *allocated_listen_port = get_sock_port(sock, 1);
@@ -2881,24 +2909,98 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2881 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 2909 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2882 0, "port listener", 1); 2910 0, "port listener", 1);
2883 c->path = xstrdup(host); 2911 c->path = xstrdup(host);
2884 c->host_port = port_to_connect; 2912 c->host_port = fwd->connect_port;
2885 c->listening_addr = addr == NULL ? NULL : xstrdup(addr); 2913 c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2886 if (listen_port == 0 && allocated_listen_port != NULL && 2914 if (fwd->listen_port == 0 && allocated_listen_port != NULL &&
2887 !(datafellows & SSH_BUG_DYNAMIC_RPORT)) 2915 !(datafellows & SSH_BUG_DYNAMIC_RPORT))
2888 c->listening_port = *allocated_listen_port; 2916 c->listening_port = *allocated_listen_port;
2889 else 2917 else
2890 c->listening_port = listen_port; 2918 c->listening_port = fwd->listen_port;
2891 success = 1; 2919 success = 1;
2892 } 2920 }
2893 if (success == 0) 2921 if (success == 0)
2894 error("channel_setup_fwd_listener: cannot listen to port: %d", 2922 error("%s: cannot listen to port: %d", __func__,
2895 listen_port); 2923 fwd->listen_port);
2896 freeaddrinfo(aitop); 2924 freeaddrinfo(aitop);
2897 return success; 2925 return success;
2898} 2926}
2899 2927
2900int 2928static int
2901channel_cancel_rport_listener(const char *host, u_short port) 2929channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd,
2930 struct ForwardOptions *fwd_opts)
2931{
2932 struct sockaddr_un sunaddr;
2933 const char *path;
2934 Channel *c;
2935 int port, sock;
2936 mode_t omask;
2937
2938 switch (type) {
2939 case SSH_CHANNEL_UNIX_LISTENER:
2940 if (fwd->connect_path != NULL) {
2941 if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) {
2942 error("Local connecting path too long: %s",
2943 fwd->connect_path);
2944 return 0;
2945 }
2946 path = fwd->connect_path;
2947 port = PORT_STREAMLOCAL;
2948 } else {
2949 if (fwd->connect_host == NULL) {
2950 error("No forward host name.");
2951 return 0;
2952 }
2953 if (strlen(fwd->connect_host) >= NI_MAXHOST) {
2954 error("Forward host name too long.");
2955 return 0;
2956 }
2957 path = fwd->connect_host;
2958 port = fwd->connect_port;
2959 }
2960 break;
2961 case SSH_CHANNEL_RUNIX_LISTENER:
2962 path = fwd->listen_path;
2963 port = PORT_STREAMLOCAL;
2964 break;
2965 default:
2966 error("%s: unexpected channel type %d", __func__, type);
2967 return 0;
2968 }
2969
2970 if (fwd->listen_path == NULL) {
2971 error("No forward path name.");
2972 return 0;
2973 }
2974 if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) {
2975 error("Local listening path too long: %s", fwd->listen_path);
2976 return 0;
2977 }
2978
2979 debug3("%s: type %d path %s", __func__, type, fwd->listen_path);
2980
2981 /* Start a Unix domain listener. */
2982 omask = umask(fwd_opts->streamlocal_bind_mask);
2983 sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG,
2984 fwd_opts->streamlocal_bind_unlink);
2985 umask(omask);
2986 if (sock < 0)
2987 return 0;
2988
2989 debug("Local forwarding listening on path %s.", fwd->listen_path);
2990
2991 /* Allocate a channel number for the socket. */
2992 c = channel_new("unix listener", type, sock, sock, -1,
2993 CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
2994 0, "unix listener", 1);
2995 c->path = xstrdup(path);
2996 c->host_port = port;
2997 c->listening_port = PORT_STREAMLOCAL;
2998 c->listening_addr = xstrdup(fwd->listen_path);
2999 return 1;
3000}
3001
3002static int
3003channel_cancel_rport_listener_tcpip(const char *host, u_short port)
2902{ 3004{
2903 u_int i; 3005 u_int i;
2904 int found = 0; 3006 int found = 0;
@@ -2917,13 +3019,44 @@ channel_cancel_rport_listener(const char *host, u_short port)
2917 return (found); 3019 return (found);
2918} 3020}
2919 3021
3022static int
3023channel_cancel_rport_listener_streamlocal(const char *path)
3024{
3025 u_int i;
3026 int found = 0;
3027
3028 for (i = 0; i < channels_alloc; i++) {
3029 Channel *c = channels[i];
3030 if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER)
3031 continue;
3032 if (c->path == NULL)
3033 continue;
3034 if (strcmp(c->path, path) == 0) {
3035 debug2("%s: close channel %d", __func__, i);
3036 channel_free(c);
3037 found = 1;
3038 }
3039 }
3040
3041 return (found);
3042}
3043
2920int 3044int
2921channel_cancel_lport_listener(const char *lhost, u_short lport, 3045channel_cancel_rport_listener(struct Forward *fwd)
2922 int cport, int gateway_ports) 3046{
3047 if (fwd->listen_path != NULL)
3048 return channel_cancel_rport_listener_streamlocal(fwd->listen_path);
3049 else
3050 return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port);
3051}
3052
3053static int
3054channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport,
3055 int cport, struct ForwardOptions *fwd_opts)
2923{ 3056{
2924 u_int i; 3057 u_int i;
2925 int found = 0; 3058 int found = 0;
2926 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports); 3059 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts);
2927 3060
2928 for (i = 0; i < channels_alloc; i++) { 3061 for (i = 0; i < channels_alloc; i++) {
2929 Channel *c = channels[i]; 3062 Channel *c = channels[i];
@@ -2952,24 +3085,68 @@ channel_cancel_lport_listener(const char *lhost, u_short lport,
2952 return (found); 3085 return (found);
2953} 3086}
2954 3087
3088static int
3089channel_cancel_lport_listener_streamlocal(const char *path)
3090{
3091 u_int i;
3092 int found = 0;
3093
3094 if (path == NULL) {
3095 error("%s: no path specified.", __func__);
3096 return 0;
3097 }
3098
3099 for (i = 0; i < channels_alloc; i++) {
3100 Channel *c = channels[i];
3101 if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER)
3102 continue;
3103 if (c->listening_addr == NULL)
3104 continue;
3105 if (strcmp(c->listening_addr, path) == 0) {
3106 debug2("%s: close channel %d", __func__, i);
3107 channel_free(c);
3108 found = 1;
3109 }
3110 }
3111
3112 return (found);
3113}
3114
3115int
3116channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts)
3117{
3118 if (fwd->listen_path != NULL)
3119 return channel_cancel_lport_listener_streamlocal(fwd->listen_path);
3120 else
3121 return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts);
3122}
3123
2955/* protocol local port fwd, used by ssh (and sshd in v1) */ 3124/* protocol local port fwd, used by ssh (and sshd in v1) */
2956int 3125int
2957channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, 3126channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts)
2958 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2959{ 3127{
2960 return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, 3128 if (fwd->listen_path != NULL) {
2961 listen_host, listen_port, NULL, host_to_connect, port_to_connect, 3129 return channel_setup_fwd_listener_streamlocal(
2962 gateway_ports); 3130 SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts);
3131 } else {
3132 return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER,
3133 fwd, NULL, fwd_opts);
3134 }
2963} 3135}
2964 3136
2965/* protocol v2 remote port fwd, used by sshd */ 3137/* protocol v2 remote port fwd, used by sshd */
2966int 3138int
2967channel_setup_remote_fwd_listener(const char *listen_address, 3139channel_setup_remote_fwd_listener(struct Forward *fwd,
2968 u_short listen_port, int *allocated_listen_port, int gateway_ports) 3140 int *allocated_listen_port, struct ForwardOptions *fwd_opts)
2969{ 3141{
2970 return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, 3142 if (fwd->listen_path != NULL) {
2971 listen_address, listen_port, allocated_listen_port, 3143 return channel_setup_fwd_listener_streamlocal(
2972 NULL, 0, gateway_ports); 3144 SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts);
3145 } else {
3146 return channel_setup_fwd_listener_tcpip(
3147 SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port,
3148 fwd_opts);
3149 }
2973} 3150}
2974 3151
2975/* 3152/*
@@ -3000,27 +3177,32 @@ channel_rfwd_bind_host(const char *listen_host)
3000 * channel_update_permitted_opens(). 3177 * channel_update_permitted_opens().
3001 */ 3178 */
3002int 3179int
3003channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 3180channel_request_remote_forwarding(struct Forward *fwd)
3004 const char *host_to_connect, u_short port_to_connect)
3005{ 3181{
3006 int type, success = 0, idx = -1; 3182 int type, success = 0, idx = -1;
3007 3183
3008 /* Send the forward request to the remote side. */ 3184 /* Send the forward request to the remote side. */
3009 if (compat20) { 3185 if (compat20) {
3010 packet_start(SSH2_MSG_GLOBAL_REQUEST); 3186 packet_start(SSH2_MSG_GLOBAL_REQUEST);
3011 packet_put_cstring("tcpip-forward"); 3187 if (fwd->listen_path != NULL) {
3012 packet_put_char(1); /* boolean: want reply */ 3188 packet_put_cstring("streamlocal-forward@openssh.com");
3013 packet_put_cstring(channel_rfwd_bind_host(listen_host)); 3189 packet_put_char(1); /* boolean: want reply */
3014 packet_put_int(listen_port); 3190 packet_put_cstring(fwd->listen_path);
3191 } else {
3192 packet_put_cstring("tcpip-forward");
3193 packet_put_char(1); /* boolean: want reply */
3194 packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
3195 packet_put_int(fwd->listen_port);
3196 }
3015 packet_send(); 3197 packet_send();
3016 packet_write_wait(); 3198 packet_write_wait();
3017 /* Assume that server accepts the request */ 3199 /* Assume that server accepts the request */
3018 success = 1; 3200 success = 1;
3019 } else { 3201 } else if (fwd->listen_path == NULL) {
3020 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 3202 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
3021 packet_put_int(listen_port); 3203 packet_put_int(fwd->listen_port);
3022 packet_put_cstring(host_to_connect); 3204 packet_put_cstring(fwd->connect_host);
3023 packet_put_int(port_to_connect); 3205 packet_put_int(fwd->connect_port);
3024 packet_send(); 3206 packet_send();
3025 packet_write_wait(); 3207 packet_write_wait();
3026 3208
@@ -3037,24 +3219,43 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
3037 packet_disconnect("Protocol error for port forward request:" 3219 packet_disconnect("Protocol error for port forward request:"
3038 "received packet type %d.", type); 3220 "received packet type %d.", type);
3039 } 3221 }
3222 } else {
3223 logit("Warning: Server does not support remote stream local forwarding.");
3040 } 3224 }
3041 if (success) { 3225 if (success) {
3042 /* Record that connection to this host/port is permitted. */ 3226 /* Record that connection to this host/port is permitted. */
3043 permitted_opens = xrealloc(permitted_opens, 3227 permitted_opens = xrealloc(permitted_opens,
3044 num_permitted_opens + 1, sizeof(*permitted_opens)); 3228 num_permitted_opens + 1, sizeof(*permitted_opens));
3045 idx = num_permitted_opens++; 3229 idx = num_permitted_opens++;
3046 permitted_opens[idx].host_to_connect = xstrdup(host_to_connect); 3230 if (fwd->connect_path != NULL) {
3047 permitted_opens[idx].port_to_connect = port_to_connect; 3231 permitted_opens[idx].host_to_connect =
3048 permitted_opens[idx].listen_host = listen_host ? 3232 xstrdup(fwd->connect_path);
3049 xstrdup(listen_host) : NULL; 3233 permitted_opens[idx].port_to_connect =
3050 permitted_opens[idx].listen_port = listen_port; 3234 PORT_STREAMLOCAL;
3235 } else {
3236 permitted_opens[idx].host_to_connect =
3237 xstrdup(fwd->connect_host);
3238 permitted_opens[idx].port_to_connect =
3239 fwd->connect_port;
3240 }
3241 if (fwd->listen_path != NULL) {
3242 permitted_opens[idx].listen_host = NULL;
3243 permitted_opens[idx].listen_path =
3244 xstrdup(fwd->listen_path);
3245 permitted_opens[idx].listen_port = PORT_STREAMLOCAL;
3246 } else {
3247 permitted_opens[idx].listen_host =
3248 fwd->listen_host ? xstrdup(fwd->listen_host) : NULL;
3249 permitted_opens[idx].listen_path = NULL;
3250 permitted_opens[idx].listen_port = fwd->listen_port;
3251 }
3051 } 3252 }
3052 return (idx); 3253 return (idx);
3053} 3254}
3054 3255
3055static int 3256static int
3056open_match(ForwardPermission *allowed_open, const char *requestedhost, 3257open_match(ForwardPermission *allowed_open, const char *requestedhost,
3057 u_short requestedport) 3258 int requestedport)
3058{ 3259{
3059 if (allowed_open->host_to_connect == NULL) 3260 if (allowed_open->host_to_connect == NULL)
3060 return 0; 3261 return 0;
@@ -3067,14 +3268,14 @@ open_match(ForwardPermission *allowed_open, const char *requestedhost,
3067} 3268}
3068 3269
3069/* 3270/*
3070 * Note that in he listen host/port case 3271 * Note that in the listen host/port case
3071 * we don't support FWD_PERMIT_ANY_PORT and 3272 * we don't support FWD_PERMIT_ANY_PORT and
3072 * need to translate between the configured-host (listen_host) 3273 * need to translate between the configured-host (listen_host)
3073 * and what we've sent to the remote server (channel_rfwd_bind_host) 3274 * and what we've sent to the remote server (channel_rfwd_bind_host)
3074 */ 3275 */
3075static int 3276static int
3076open_listen_match(ForwardPermission *allowed_open, const char *requestedhost, 3277open_listen_match_tcpip(ForwardPermission *allowed_open,
3077 u_short requestedport, int translate) 3278 const char *requestedhost, u_short requestedport, int translate)
3078{ 3279{
3079 const char *allowed_host; 3280 const char *allowed_host;
3080 3281
@@ -3094,12 +3295,26 @@ open_listen_match(ForwardPermission *allowed_open, const char *requestedhost,
3094 return 1; 3295 return 1;
3095} 3296}
3096 3297
3298static int
3299open_listen_match_streamlocal(ForwardPermission *allowed_open,
3300 const char *requestedpath)
3301{
3302 if (allowed_open->host_to_connect == NULL)
3303 return 0;
3304 if (allowed_open->listen_port != PORT_STREAMLOCAL)
3305 return 0;
3306 if (allowed_open->listen_path == NULL ||
3307 strcmp(allowed_open->listen_path, requestedpath) != 0)
3308 return 0;
3309 return 1;
3310}
3311
3097/* 3312/*
3098 * Request cancellation of remote forwarding of connection host:port from 3313 * Request cancellation of remote forwarding of connection host:port from
3099 * local side. 3314 * local side.
3100 */ 3315 */
3101int 3316static int
3102channel_request_rforward_cancel(const char *host, u_short port) 3317channel_request_rforward_cancel_tcpip(const char *host, u_short port)
3103{ 3318{
3104 int i; 3319 int i;
3105 3320
@@ -3107,7 +3322,7 @@ channel_request_rforward_cancel(const char *host, u_short port)
3107 return -1; 3322 return -1;
3108 3323
3109 for (i = 0; i < num_permitted_opens; i++) { 3324 for (i = 0; i < num_permitted_opens; i++) {
3110 if (open_listen_match(&permitted_opens[i], host, port, 0)) 3325 if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
3111 break; 3326 break;
3112 } 3327 }
3113 if (i >= num_permitted_opens) { 3328 if (i >= num_permitted_opens) {
@@ -3121,15 +3336,68 @@ channel_request_rforward_cancel(const char *host, u_short port)
3121 packet_put_int(port); 3336 packet_put_int(port);
3122 packet_send(); 3337 packet_send();
3123 3338
3124 permitted_opens[i].port_to_connect = 0;
3125 permitted_opens[i].listen_port = 0; 3339 permitted_opens[i].listen_port = 0;
3340 permitted_opens[i].port_to_connect = 0;
3126 free(permitted_opens[i].host_to_connect); 3341 free(permitted_opens[i].host_to_connect);
3127 permitted_opens[i].host_to_connect = NULL; 3342 permitted_opens[i].host_to_connect = NULL;
3128 free(permitted_opens[i].listen_host); 3343 free(permitted_opens[i].listen_host);
3129 permitted_opens[i].listen_host = NULL; 3344 permitted_opens[i].listen_host = NULL;
3345 permitted_opens[i].listen_path = NULL;
3346
3347 return 0;
3348}
3349
3350/*
3351 * Request cancellation of remote forwarding of Unix domain socket
3352 * path from local side.
3353 */
3354static int
3355channel_request_rforward_cancel_streamlocal(const char *path)
3356{
3357 int i;
3358
3359 if (!compat20)
3360 return -1;
3361
3362 for (i = 0; i < num_permitted_opens; i++) {
3363 if (open_listen_match_streamlocal(&permitted_opens[i], path))
3364 break;
3365 }
3366 if (i >= num_permitted_opens) {
3367 debug("%s: requested forward not found", __func__);
3368 return -1;
3369 }
3370 packet_start(SSH2_MSG_GLOBAL_REQUEST);
3371 packet_put_cstring("cancel-streamlocal-forward@openssh.com");
3372 packet_put_char(0);
3373 packet_put_cstring(path);
3374 packet_send();
3375
3376 permitted_opens[i].listen_port = 0;
3377 permitted_opens[i].port_to_connect = 0;
3378 free(permitted_opens[i].host_to_connect);
3379 permitted_opens[i].host_to_connect = NULL;
3380 permitted_opens[i].listen_host = NULL;
3381 free(permitted_opens[i].listen_path);
3382 permitted_opens[i].listen_path = NULL;
3130 3383
3131 return 0; 3384 return 0;
3132} 3385}
3386
3387/*
3388 * Request cancellation of remote forwarding of a connection from local side.
3389 */
3390int
3391channel_request_rforward_cancel(struct Forward *fwd)
3392{
3393 if (fwd->listen_path != NULL) {
3394 return (channel_request_rforward_cancel_streamlocal(
3395 fwd->listen_path));
3396 } else {
3397 return (channel_request_rforward_cancel_tcpip(fwd->listen_host,
3398 fwd->listen_port ? fwd->listen_port : fwd->allocated_port));
3399 }
3400}
3133 3401
3134/* 3402/*
3135 * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates 3403 * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
@@ -3137,36 +3405,35 @@ channel_request_rforward_cancel(const char *host, u_short port)
3137 * message if there was an error). 3405 * message if there was an error).
3138 */ 3406 */
3139int 3407int
3140channel_input_port_forward_request(int is_root, int gateway_ports) 3408channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts)
3141{ 3409{
3142 u_short port, host_port;
3143 int success = 0; 3410 int success = 0;
3144 char *hostname; 3411 struct Forward fwd;
3145 3412
3146 /* Get arguments from the packet. */ 3413 /* Get arguments from the packet. */
3147 port = packet_get_int(); 3414 memset(&fwd, 0, sizeof(fwd));
3148 hostname = packet_get_string(NULL); 3415 fwd.listen_port = packet_get_int();
3149 host_port = packet_get_int(); 3416 fwd.connect_host = packet_get_string(NULL);
3417 fwd.connect_port = packet_get_int();
3150 3418
3151#ifndef HAVE_CYGWIN 3419#ifndef HAVE_CYGWIN
3152 /* 3420 /*
3153 * Check that an unprivileged user is not trying to forward a 3421 * Check that an unprivileged user is not trying to forward a
3154 * privileged port. 3422 * privileged port.
3155 */ 3423 */
3156 if (port < IPPORT_RESERVED && !is_root) 3424 if (fwd.listen_port < IPPORT_RESERVED && !is_root)
3157 packet_disconnect( 3425 packet_disconnect(
3158 "Requested forwarding of port %d but user is not root.", 3426 "Requested forwarding of port %d but user is not root.",
3159 port); 3427 fwd.listen_port);
3160 if (host_port == 0) 3428 if (fwd.connect_port == 0)
3161 packet_disconnect("Dynamic forwarding denied."); 3429 packet_disconnect("Dynamic forwarding denied.");
3162#endif 3430#endif
3163 3431
3164 /* Initiate forwarding */ 3432 /* Initiate forwarding */
3165 success = channel_setup_local_fwd_listener(NULL, port, hostname, 3433 success = channel_setup_local_fwd_listener(&fwd, fwd_opts);
3166 host_port, gateway_ports);
3167 3434
3168 /* Free the argument string. */ 3435 /* Free the argument string. */
3169 free(hostname); 3436 free(fwd.connect_host);
3170 3437
3171 return (success ? 0 : -1); 3438 return (success ? 0 : -1);
3172} 3439}
@@ -3193,6 +3460,7 @@ channel_add_permitted_opens(char *host, int port)
3193 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 3460 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
3194 permitted_opens[num_permitted_opens].port_to_connect = port; 3461 permitted_opens[num_permitted_opens].port_to_connect = port;
3195 permitted_opens[num_permitted_opens].listen_host = NULL; 3462 permitted_opens[num_permitted_opens].listen_host = NULL;
3463 permitted_opens[num_permitted_opens].listen_path = NULL;
3196 permitted_opens[num_permitted_opens].listen_port = 0; 3464 permitted_opens[num_permitted_opens].listen_port = 0;
3197 num_permitted_opens++; 3465 num_permitted_opens++;
3198 3466
@@ -3227,6 +3495,8 @@ channel_update_permitted_opens(int idx, int newport)
3227 permitted_opens[idx].host_to_connect = NULL; 3495 permitted_opens[idx].host_to_connect = NULL;
3228 free(permitted_opens[idx].listen_host); 3496 free(permitted_opens[idx].listen_host);
3229 permitted_opens[idx].listen_host = NULL; 3497 permitted_opens[idx].listen_host = NULL;
3498 free(permitted_opens[idx].listen_path);
3499 permitted_opens[idx].listen_path = NULL;
3230 } 3500 }
3231} 3501}
3232 3502
@@ -3241,6 +3511,7 @@ channel_add_adm_permitted_opens(char *host, int port)
3241 = xstrdup(host); 3511 = xstrdup(host);
3242 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; 3512 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
3243 permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; 3513 permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL;
3514 permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL;
3244 permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; 3515 permitted_adm_opens[num_adm_permitted_opens].listen_port = 0;
3245 return ++num_adm_permitted_opens; 3516 return ++num_adm_permitted_opens;
3246} 3517}
@@ -3262,6 +3533,7 @@ channel_clear_permitted_opens(void)
3262 for (i = 0; i < num_permitted_opens; i++) { 3533 for (i = 0; i < num_permitted_opens; i++) {
3263 free(permitted_opens[i].host_to_connect); 3534 free(permitted_opens[i].host_to_connect);
3264 free(permitted_opens[i].listen_host); 3535 free(permitted_opens[i].listen_host);
3536 free(permitted_opens[i].listen_path);
3265 } 3537 }
3266 free(permitted_opens); 3538 free(permitted_opens);
3267 permitted_opens = NULL; 3539 permitted_opens = NULL;
@@ -3276,6 +3548,7 @@ channel_clear_adm_permitted_opens(void)
3276 for (i = 0; i < num_adm_permitted_opens; i++) { 3548 for (i = 0; i < num_adm_permitted_opens; i++) {
3277 free(permitted_adm_opens[i].host_to_connect); 3549 free(permitted_adm_opens[i].host_to_connect);
3278 free(permitted_adm_opens[i].listen_host); 3550 free(permitted_adm_opens[i].listen_host);
3551 free(permitted_adm_opens[i].listen_path);
3279 } 3552 }
3280 free(permitted_adm_opens); 3553 free(permitted_adm_opens);
3281 permitted_adm_opens = NULL; 3554 permitted_adm_opens = NULL;
@@ -3319,16 +3592,27 @@ static int
3319connect_next(struct channel_connect *cctx) 3592connect_next(struct channel_connect *cctx)
3320{ 3593{
3321 int sock, saved_errno; 3594 int sock, saved_errno;
3322 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 3595 struct sockaddr_un *sunaddr;
3596 char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))];
3323 3597
3324 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { 3598 for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
3325 if (cctx->ai->ai_family != AF_INET && 3599 switch (cctx->ai->ai_family) {
3326 cctx->ai->ai_family != AF_INET6) 3600 case AF_UNIX:
3327 continue; 3601 /* unix:pathname instead of host:port */
3328 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, 3602 sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr;
3329 ntop, sizeof(ntop), strport, sizeof(strport), 3603 strlcpy(ntop, "unix", sizeof(ntop));
3330 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 3604 strlcpy(strport, sunaddr->sun_path, sizeof(strport));
3331 error("connect_next: getnameinfo failed"); 3605 break;
3606 case AF_INET:
3607 case AF_INET6:
3608 if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
3609 ntop, sizeof(ntop), strport, sizeof(strport),
3610 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
3611 error("connect_next: getnameinfo failed");
3612 continue;
3613 }
3614 break;
3615 default:
3332 continue; 3616 continue;
3333 } 3617 }
3334 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, 3618 if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
@@ -3351,10 +3635,11 @@ connect_next(struct channel_connect *cctx)
3351 errno = saved_errno; 3635 errno = saved_errno;
3352 continue; /* fail -- try next */ 3636 continue; /* fail -- try next */
3353 } 3637 }
3638 if (cctx->ai->ai_family != AF_UNIX)
3639 set_nodelay(sock);
3354 debug("connect_next: host %.100s ([%.100s]:%s) " 3640 debug("connect_next: host %.100s ([%.100s]:%s) "
3355 "in progress, fd=%d", cctx->host, ntop, strport, sock); 3641 "in progress, fd=%d", cctx->host, ntop, strport, sock);
3356 cctx->ai = cctx->ai->ai_next; 3642 cctx->ai = cctx->ai->ai_next;
3357 set_nodelay(sock);
3358 return sock; 3643 return sock;
3359 } 3644 }
3360 return -1; 3645 return -1;
@@ -3364,14 +3649,18 @@ static void
3364channel_connect_ctx_free(struct channel_connect *cctx) 3649channel_connect_ctx_free(struct channel_connect *cctx)
3365{ 3650{
3366 free(cctx->host); 3651 free(cctx->host);
3367 if (cctx->aitop) 3652 if (cctx->aitop) {
3368 freeaddrinfo(cctx->aitop); 3653 if (cctx->aitop->ai_family == AF_UNIX)
3654 free(cctx->aitop);
3655 else
3656 freeaddrinfo(cctx->aitop);
3657 }
3369 memset(cctx, 0, sizeof(*cctx)); 3658 memset(cctx, 0, sizeof(*cctx));
3370} 3659}
3371 3660
3372/* Return CONNECTING channel to remote host, port */ 3661/* Return CONNECTING channel to remote host:port or local socket path */
3373static Channel * 3662static Channel *
3374connect_to(const char *host, u_short port, char *ctype, char *rname) 3663connect_to(const char *name, int port, char *ctype, char *rname)
3375{ 3664{
3376 struct addrinfo hints; 3665 struct addrinfo hints;
3377 int gaierr; 3666 int gaierr;
@@ -3381,23 +3670,51 @@ connect_to(const char *host, u_short port, char *ctype, char *rname)
3381 Channel *c; 3670 Channel *c;
3382 3671
3383 memset(&cctx, 0, sizeof(cctx)); 3672 memset(&cctx, 0, sizeof(cctx));
3384 memset(&hints, 0, sizeof(hints)); 3673
3385 hints.ai_family = IPv4or6; 3674 if (port == PORT_STREAMLOCAL) {
3386 hints.ai_socktype = SOCK_STREAM; 3675 struct sockaddr_un *sunaddr;
3387 snprintf(strport, sizeof strport, "%d", port); 3676 struct addrinfo *ai;
3388 if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) { 3677
3389 error("connect_to %.100s: unknown host (%s)", host, 3678 if (strlen(name) > sizeof(sunaddr->sun_path)) {
3390 ssh_gai_strerror(gaierr)); 3679 error("%.100s: %.100s", name, strerror(ENAMETOOLONG));
3391 return NULL; 3680 return (NULL);
3681 }
3682
3683 /*
3684 * Fake up a struct addrinfo for AF_UNIX connections.
3685 * channel_connect_ctx_free() must check ai_family
3686 * and use free() not freeaddirinfo() for AF_UNIX.
3687 */
3688 ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr));
3689 memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr));
3690 ai->ai_addr = (struct sockaddr *)(ai + 1);
3691 ai->ai_addrlen = sizeof(*sunaddr);
3692 ai->ai_family = AF_UNIX;
3693 ai->ai_socktype = SOCK_STREAM;
3694 ai->ai_protocol = PF_UNSPEC;
3695 sunaddr = (struct sockaddr_un *)ai->ai_addr;
3696 sunaddr->sun_family = AF_UNIX;
3697 strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path));
3698 cctx.aitop = ai;
3699 } else {
3700 memset(&hints, 0, sizeof(hints));
3701 hints.ai_family = IPv4or6;
3702 hints.ai_socktype = SOCK_STREAM;
3703 snprintf(strport, sizeof strport, "%d", port);
3704 if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) {
3705 error("connect_to %.100s: unknown host (%s)", name,
3706 ssh_gai_strerror(gaierr));
3707 return NULL;
3708 }
3392 } 3709 }
3393 3710
3394 cctx.host = xstrdup(host); 3711 cctx.host = xstrdup(name);
3395 cctx.port = port; 3712 cctx.port = port;
3396 cctx.ai = cctx.aitop; 3713 cctx.ai = cctx.aitop;
3397 3714
3398 if ((sock = connect_next(&cctx)) == -1) { 3715 if ((sock = connect_next(&cctx)) == -1) {
3399 error("connect to %.100s port %d failed: %s", 3716 error("connect to %.100s port %d failed: %s",
3400 host, port, strerror(errno)); 3717 name, port, strerror(errno));
3401 channel_connect_ctx_free(&cctx); 3718 channel_connect_ctx_free(&cctx);
3402 return NULL; 3719 return NULL;
3403 } 3720 }
@@ -3414,7 +3731,7 @@ channel_connect_by_listen_address(const char *listen_host,
3414 int i; 3731 int i;
3415 3732
3416 for (i = 0; i < num_permitted_opens; i++) { 3733 for (i = 0; i < num_permitted_opens; i++) {
3417 if (open_listen_match(&permitted_opens[i], listen_host, 3734 if (open_listen_match_tcpip(&permitted_opens[i], listen_host,
3418 listen_port, 1)) { 3735 listen_port, 1)) {
3419 return connect_to( 3736 return connect_to(
3420 permitted_opens[i].host_to_connect, 3737 permitted_opens[i].host_to_connect,
@@ -3426,9 +3743,26 @@ channel_connect_by_listen_address(const char *listen_host,
3426 return NULL; 3743 return NULL;
3427} 3744}
3428 3745
3746Channel *
3747channel_connect_by_listen_path(const char *path, char *ctype, char *rname)
3748{
3749 int i;
3750
3751 for (i = 0; i < num_permitted_opens; i++) {
3752 if (open_listen_match_streamlocal(&permitted_opens[i], path)) {
3753 return connect_to(
3754 permitted_opens[i].host_to_connect,
3755 permitted_opens[i].port_to_connect, ctype, rname);
3756 }
3757 }
3758 error("WARNING: Server requests forwarding for unknown path %.100s",
3759 path);
3760 return NULL;
3761}
3762
3429/* Check if connecting to that port is permitted and connect. */ 3763/* Check if connecting to that port is permitted and connect. */
3430Channel * 3764Channel *
3431channel_connect_to(const char *host, u_short port, char *ctype, char *rname) 3765channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname)
3432{ 3766{
3433 int i, permit, permit_adm = 1; 3767 int i, permit, permit_adm = 1;
3434 3768
@@ -3458,6 +3792,38 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
3458 return connect_to(host, port, ctype, rname); 3792 return connect_to(host, port, ctype, rname);
3459} 3793}
3460 3794
3795/* Check if connecting to that path is permitted and connect. */
3796Channel *
3797channel_connect_to_path(const char *path, char *ctype, char *rname)
3798{
3799 int i, permit, permit_adm = 1;
3800
3801 permit = all_opens_permitted;
3802 if (!permit) {
3803 for (i = 0; i < num_permitted_opens; i++)
3804 if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) {
3805 permit = 1;
3806 break;
3807 }
3808 }
3809
3810 if (num_adm_permitted_opens > 0) {
3811 permit_adm = 0;
3812 for (i = 0; i < num_adm_permitted_opens; i++)
3813 if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) {
3814 permit_adm = 1;
3815 break;
3816 }
3817 }
3818
3819 if (!permit || !permit_adm) {
3820 logit("Received request to connect to path %.100s, "
3821 "but the request was denied.", path);
3822 return NULL;
3823 }
3824 return connect_to(path, PORT_STREAMLOCAL, ctype, rname);
3825}
3826
3461void 3827void
3462channel_send_window_changes(void) 3828channel_send_window_changes(void)
3463{ 3829{