diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 600 |
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? */ | ||
110 | typedef struct { | 114 | typedef 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) | |||
1387 | static void | 1400 | static void |
1388 | port_open_helper(Channel *c, char *rtype) | 1401 | port_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 | */ |
2706 | static const char * | 2736 | static const char * |
2707 | channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | 2737 | channel_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 | ||
2754 | static int | 2784 | static int |
2755 | channel_setup_fwd_listener(int type, const char *listen_addr, | 2785 | channel_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 | ||
2900 | int | 2928 | static int |
2901 | channel_cancel_rport_listener(const char *host, u_short port) | 2929 | channel_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 | |||
3002 | static int | ||
3003 | channel_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 | ||
3022 | static int | ||
3023 | channel_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 | |||
2920 | int | 3044 | int |
2921 | channel_cancel_lport_listener(const char *lhost, u_short lport, | 3045 | channel_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 | |||
3053 | static int | ||
3054 | channel_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 | ||
3088 | static int | ||
3089 | channel_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 | |||
3115 | int | ||
3116 | channel_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) */ |
2956 | int | 3125 | int |
2957 | channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, | 3126 | channel_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 */ |
2966 | int | 3138 | int |
2967 | channel_setup_remote_fwd_listener(const char *listen_address, | 3139 | channel_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 | */ |
3002 | int | 3179 | int |
3003 | channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | 3180 | channel_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 | ||
3055 | static int | 3256 | static int |
3056 | open_match(ForwardPermission *allowed_open, const char *requestedhost, | 3257 | open_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 | */ |
3075 | static int | 3276 | static int |
3076 | open_listen_match(ForwardPermission *allowed_open, const char *requestedhost, | 3277 | open_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 | ||
3298 | static int | ||
3299 | open_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 | */ |
3101 | int | 3316 | static int |
3102 | channel_request_rforward_cancel(const char *host, u_short port) | 3317 | channel_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 | */ | ||
3354 | static int | ||
3355 | channel_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 | */ | ||
3390 | int | ||
3391 | channel_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 | */ |
3139 | int | 3407 | int |
3140 | channel_input_port_forward_request(int is_root, int gateway_ports) | 3408 | channel_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 | |||
3319 | connect_next(struct channel_connect *cctx) | 3592 | connect_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 | |||
3364 | channel_connect_ctx_free(struct channel_connect *cctx) | 3649 | channel_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 */ |
3373 | static Channel * | 3662 | static Channel * |
3374 | connect_to(const char *host, u_short port, char *ctype, char *rname) | 3663 | connect_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 | ||
3746 | Channel * | ||
3747 | channel_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. */ |
3430 | Channel * | 3764 | Channel * |
3431 | channel_connect_to(const char *host, u_short port, char *ctype, char *rname) | 3765 | channel_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. */ | ||
3796 | Channel * | ||
3797 | channel_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 | |||
3461 | void | 3827 | void |
3462 | channel_send_window_changes(void) | 3828 | channel_send_window_changes(void) |
3463 | { | 3829 | { |