diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 693 |
1 files changed, 559 insertions, 134 deletions
diff --git a/channels.c b/channels.c index 9efe89c9c..d67fdf48b 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.331 2014/02/26 20:29:29 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,10 +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 | u_short listen_port; /* Remote side should listen port number. */ | 117 | char *listen_host; /* Remote side should listen address. */ |
118 | char *listen_path; /* Remote side should listen path. */ | ||
119 | int listen_port; /* Remote side should listen port. */ | ||
114 | } ForwardPermission; | 120 | } ForwardPermission; |
115 | 121 | ||
116 | /* 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. */ |
@@ -473,6 +479,8 @@ channel_stop_listening(void) | |||
473 | case SSH_CHANNEL_PORT_LISTENER: | 479 | case SSH_CHANNEL_PORT_LISTENER: |
474 | case SSH_CHANNEL_RPORT_LISTENER: | 480 | case SSH_CHANNEL_RPORT_LISTENER: |
475 | case SSH_CHANNEL_X11_LISTENER: | 481 | case SSH_CHANNEL_X11_LISTENER: |
482 | case SSH_CHANNEL_UNIX_LISTENER: | ||
483 | case SSH_CHANNEL_RUNIX_LISTENER: | ||
476 | channel_close_fd(&c->sock); | 484 | channel_close_fd(&c->sock); |
477 | channel_free(c); | 485 | channel_free(c); |
478 | break; | 486 | break; |
@@ -535,6 +543,8 @@ channel_still_open(void) | |||
535 | case SSH_CHANNEL_CONNECTING: | 543 | case SSH_CHANNEL_CONNECTING: |
536 | case SSH_CHANNEL_ZOMBIE: | 544 | case SSH_CHANNEL_ZOMBIE: |
537 | case SSH_CHANNEL_ABANDONED: | 545 | case SSH_CHANNEL_ABANDONED: |
546 | case SSH_CHANNEL_UNIX_LISTENER: | ||
547 | case SSH_CHANNEL_RUNIX_LISTENER: | ||
538 | continue; | 548 | continue; |
539 | case SSH_CHANNEL_LARVAL: | 549 | case SSH_CHANNEL_LARVAL: |
540 | if (!compat20) | 550 | if (!compat20) |
@@ -581,6 +591,8 @@ channel_find_open(void) | |||
581 | case SSH_CHANNEL_CONNECTING: | 591 | case SSH_CHANNEL_CONNECTING: |
582 | case SSH_CHANNEL_ZOMBIE: | 592 | case SSH_CHANNEL_ZOMBIE: |
583 | case SSH_CHANNEL_ABANDONED: | 593 | case SSH_CHANNEL_ABANDONED: |
594 | case SSH_CHANNEL_UNIX_LISTENER: | ||
595 | case SSH_CHANNEL_RUNIX_LISTENER: | ||
584 | continue; | 596 | continue; |
585 | case SSH_CHANNEL_LARVAL: | 597 | case SSH_CHANNEL_LARVAL: |
586 | case SSH_CHANNEL_AUTH_SOCKET: | 598 | case SSH_CHANNEL_AUTH_SOCKET: |
@@ -631,6 +643,8 @@ channel_open_message(void) | |||
631 | case SSH_CHANNEL_ABANDONED: | 643 | case SSH_CHANNEL_ABANDONED: |
632 | case SSH_CHANNEL_MUX_CLIENT: | 644 | case SSH_CHANNEL_MUX_CLIENT: |
633 | case SSH_CHANNEL_MUX_LISTENER: | 645 | case SSH_CHANNEL_MUX_LISTENER: |
646 | case SSH_CHANNEL_UNIX_LISTENER: | ||
647 | case SSH_CHANNEL_RUNIX_LISTENER: | ||
634 | continue; | 648 | continue; |
635 | case SSH_CHANNEL_LARVAL: | 649 | case SSH_CHANNEL_LARVAL: |
636 | case SSH_CHANNEL_OPENING: | 650 | case SSH_CHANNEL_OPENING: |
@@ -1386,7 +1400,6 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1386 | static void | 1400 | static void |
1387 | port_open_helper(Channel *c, char *rtype) | 1401 | port_open_helper(Channel *c, char *rtype) |
1388 | { | 1402 | { |
1389 | int direct; | ||
1390 | char buf[1024]; | 1403 | char buf[1024]; |
1391 | char *local_ipaddr = get_local_ipaddr(c->sock); | 1404 | char *local_ipaddr = get_local_ipaddr(c->sock); |
1392 | 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); |
@@ -1400,8 +1413,6 @@ port_open_helper(Channel *c, char *rtype) | |||
1400 | remote_port = 65535; | 1413 | remote_port = 65535; |
1401 | } | 1414 | } |
1402 | 1415 | ||
1403 | direct = (strcmp(rtype, "direct-tcpip") == 0); | ||
1404 | |||
1405 | snprintf(buf, sizeof buf, | 1416 | snprintf(buf, sizeof buf, |
1406 | "%s: listening port %d for %.100s port %d, " | 1417 | "%s: listening port %d for %.100s port %d, " |
1407 | "connect from %.200s port %d to %.100s port %d", | 1418 | "connect from %.200s port %d to %.100s port %d", |
@@ -1417,18 +1428,29 @@ port_open_helper(Channel *c, char *rtype) | |||
1417 | packet_put_int(c->self); | 1428 | packet_put_int(c->self); |
1418 | packet_put_int(c->local_window_max); | 1429 | packet_put_int(c->local_window_max); |
1419 | packet_put_int(c->local_maxpacket); | 1430 | packet_put_int(c->local_maxpacket); |
1420 | if (direct) { | 1431 | if (strcmp(rtype, "direct-tcpip") == 0) { |
1421 | /* target host, port */ | 1432 | /* target host, port */ |
1422 | packet_put_cstring(c->path); | 1433 | packet_put_cstring(c->path); |
1423 | 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); | ||
1424 | } else { | 1441 | } else { |
1425 | /* listen address, port */ | 1442 | /* listen address, port */ |
1426 | packet_put_cstring(c->path); | 1443 | packet_put_cstring(c->path); |
1427 | packet_put_int(local_port); | 1444 | packet_put_int(local_port); |
1428 | } | 1445 | } |
1429 | /* originator host and port */ | 1446 | if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
1430 | packet_put_cstring(remote_ipaddr); | 1447 | /* reserved for future owner/mode info */ |
1431 | 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 | } | ||
1432 | packet_send(); | 1454 | packet_send(); |
1433 | } else { | 1455 | } else { |
1434 | packet_start(SSH_MSG_PORT_OPEN); | 1456 | packet_start(SSH_MSG_PORT_OPEN); |
@@ -1478,14 +1500,18 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1478 | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { | 1500 | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { |
1479 | nextstate = SSH_CHANNEL_OPENING; | 1501 | nextstate = SSH_CHANNEL_OPENING; |
1480 | 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"; | ||
1481 | } else { | 1512 | } else { |
1482 | if (c->host_port == 0) { | 1513 | nextstate = SSH_CHANNEL_OPENING; |
1483 | nextstate = SSH_CHANNEL_DYNAMIC; | 1514 | rtype = "direct-tcpip"; |
1484 | rtype = "dynamic-tcpip"; | ||
1485 | } else { | ||
1486 | nextstate = SSH_CHANNEL_OPENING; | ||
1487 | rtype = "direct-tcpip"; | ||
1488 | } | ||
1489 | } | 1515 | } |
1490 | 1516 | ||
1491 | addrlen = sizeof(addr); | 1517 | addrlen = sizeof(addr); |
@@ -1498,7 +1524,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1498 | c->notbefore = monotime() + 1; | 1524 | c->notbefore = monotime() + 1; |
1499 | return; | 1525 | return; |
1500 | } | 1526 | } |
1501 | set_nodelay(newsock); | 1527 | if (c->host_port != PORT_STREAMLOCAL) |
1528 | set_nodelay(newsock); | ||
1502 | nc = channel_new(rtype, nextstate, newsock, newsock, -1, | 1529 | nc = channel_new(rtype, nextstate, newsock, newsock, -1, |
1503 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); | 1530 | c->local_window_max, c->local_maxpacket, 0, rtype, 1); |
1504 | nc->listening_port = c->listening_port; | 1531 | nc->listening_port = c->listening_port; |
@@ -1987,6 +2014,8 @@ channel_handler_init_20(void) | |||
1987 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; | 2014 | channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
1988 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | 2015 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
1989 | 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; | ||
1990 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | 2019 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
1991 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 2020 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
1992 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 2021 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
@@ -1997,6 +2026,8 @@ channel_handler_init_20(void) | |||
1997 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; | 2026 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; |
1998 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | 2027 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
1999 | 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; | ||
2000 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 2031 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
2001 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 2032 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
2002 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 2033 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
@@ -2315,7 +2346,7 @@ void | |||
2315 | channel_input_data(int type, u_int32_t seq, void *ctxt) | 2346 | channel_input_data(int type, u_int32_t seq, void *ctxt) |
2316 | { | 2347 | { |
2317 | int id; | 2348 | int id; |
2318 | char *data; | 2349 | const u_char *data; |
2319 | u_int data_len, win_len; | 2350 | u_int data_len, win_len; |
2320 | Channel *c; | 2351 | Channel *c; |
2321 | 2352 | ||
@@ -2637,7 +2668,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) | |||
2637 | originator_string = xstrdup("unknown (remote did not supply name)"); | 2668 | originator_string = xstrdup("unknown (remote did not supply name)"); |
2638 | } | 2669 | } |
2639 | packet_check_eom(); | 2670 | packet_check_eom(); |
2640 | c = channel_connect_to(host, host_port, | 2671 | c = channel_connect_to_port(host, host_port, |
2641 | "connected socket", originator_string); | 2672 | "connected socket", originator_string); |
2642 | free(originator_string); | 2673 | free(originator_string); |
2643 | free(host); | 2674 | free(host); |
@@ -2700,23 +2731,24 @@ channel_set_af(int af) | |||
2700 | * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR | 2731 | * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR |
2701 | * "" (empty string), "*" -> wildcard v4/v6 | 2732 | * "" (empty string), "*" -> wildcard v4/v6 |
2702 | * "localhost" -> loopback v4/v6 | 2733 | * "localhost" -> loopback v4/v6 |
2734 | * "127.0.0.1" / "::1" -> accepted even if gateway_ports isn't set | ||
2703 | */ | 2735 | */ |
2704 | static const char * | 2736 | static const char * |
2705 | channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | 2737 | channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, |
2706 | int is_client, int gateway_ports) | 2738 | int is_client, struct ForwardOptions *fwd_opts) |
2707 | { | 2739 | { |
2708 | const char *addr = NULL; | 2740 | const char *addr = NULL; |
2709 | int wildcard = 0; | 2741 | int wildcard = 0; |
2710 | 2742 | ||
2711 | if (listen_addr == NULL) { | 2743 | if (listen_addr == NULL) { |
2712 | /* No address specified: default to gateway_ports setting */ | 2744 | /* No address specified: default to gateway_ports setting */ |
2713 | if (gateway_ports) | 2745 | if (fwd_opts->gateway_ports) |
2714 | wildcard = 1; | 2746 | wildcard = 1; |
2715 | } else if (gateway_ports || is_client) { | 2747 | } else if (fwd_opts->gateway_ports || is_client) { |
2716 | if (((datafellows & SSH_OLD_FORWARD_ADDR) && | 2748 | if (((datafellows & SSH_OLD_FORWARD_ADDR) && |
2717 | strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || | 2749 | strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || |
2718 | *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || | 2750 | *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || |
2719 | (!is_client && gateway_ports == 1)) { | 2751 | (!is_client && fwd_opts->gateway_ports == 1)) { |
2720 | wildcard = 1; | 2752 | wildcard = 1; |
2721 | /* | 2753 | /* |
2722 | * Notify client if they requested a specific listen | 2754 | * Notify client if they requested a specific listen |
@@ -2729,9 +2761,20 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | |||
2729 | "\"%s\" overridden by server " | 2761 | "\"%s\" overridden by server " |
2730 | "GatewayPorts", listen_addr); | 2762 | "GatewayPorts", listen_addr); |
2731 | } | 2763 | } |
2732 | } | 2764 | } else if (strcmp(listen_addr, "localhost") != 0 || |
2733 | else if (strcmp(listen_addr, "localhost") != 0) | 2765 | strcmp(listen_addr, "127.0.0.1") == 0 || |
2766 | strcmp(listen_addr, "::1") == 0) { | ||
2767 | /* Accept localhost address when GatewayPorts=yes */ | ||
2734 | addr = listen_addr; | 2768 | addr = listen_addr; |
2769 | } | ||
2770 | } else if (strcmp(listen_addr, "127.0.0.1") == 0 || | ||
2771 | strcmp(listen_addr, "::1") == 0) { | ||
2772 | /* | ||
2773 | * If a specific IPv4/IPv6 localhost address has been | ||
2774 | * requested then accept it even if gateway_ports is in | ||
2775 | * effect. This allows the client to prefer IPv4 or IPv6. | ||
2776 | */ | ||
2777 | addr = listen_addr; | ||
2735 | } | 2778 | } |
2736 | if (wildcardp != NULL) | 2779 | if (wildcardp != NULL) |
2737 | *wildcardp = wildcard; | 2780 | *wildcardp = wildcard; |
@@ -2739,9 +2782,8 @@ channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, | |||
2739 | } | 2782 | } |
2740 | 2783 | ||
2741 | static int | 2784 | static int |
2742 | channel_setup_fwd_listener(int type, const char *listen_addr, | 2785 | channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, |
2743 | u_short listen_port, int *allocated_listen_port, | 2786 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
2744 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) | ||
2745 | { | 2787 | { |
2746 | Channel *c; | 2788 | Channel *c; |
2747 | int sock, r, success = 0, wildcard = 0, is_client; | 2789 | int sock, r, success = 0, wildcard = 0, is_client; |
@@ -2751,7 +2793,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2751 | in_port_t *lport_p; | 2793 | in_port_t *lport_p; |
2752 | 2794 | ||
2753 | host = (type == SSH_CHANNEL_RPORT_LISTENER) ? | 2795 | host = (type == SSH_CHANNEL_RPORT_LISTENER) ? |
2754 | listen_addr : host_to_connect; | 2796 | fwd->listen_host : fwd->connect_host; |
2755 | is_client = (type == SSH_CHANNEL_PORT_LISTENER); | 2797 | is_client = (type == SSH_CHANNEL_PORT_LISTENER); |
2756 | 2798 | ||
2757 | if (host == NULL) { | 2799 | if (host == NULL) { |
@@ -2764,9 +2806,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2764 | } | 2806 | } |
2765 | 2807 | ||
2766 | /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ | 2808 | /* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
2767 | addr = channel_fwd_bind_addr(listen_addr, &wildcard, | 2809 | addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard, |
2768 | is_client, gateway_ports); | 2810 | is_client, fwd_opts); |
2769 | debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", | 2811 | debug3("%s: type %d wildcard %d addr %s", __func__, |
2770 | type, wildcard, (addr == NULL) ? "NULL" : addr); | 2812 | type, wildcard, (addr == NULL) ? "NULL" : addr); |
2771 | 2813 | ||
2772 | /* | 2814 | /* |
@@ -2777,15 +2819,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2777 | hints.ai_family = IPv4or6; | 2819 | hints.ai_family = IPv4or6; |
2778 | hints.ai_flags = wildcard ? AI_PASSIVE : 0; | 2820 | hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
2779 | hints.ai_socktype = SOCK_STREAM; | 2821 | hints.ai_socktype = SOCK_STREAM; |
2780 | snprintf(strport, sizeof strport, "%d", listen_port); | 2822 | snprintf(strport, sizeof strport, "%d", fwd->listen_port); |
2781 | if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { | 2823 | if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
2782 | if (addr == NULL) { | 2824 | if (addr == NULL) { |
2783 | /* This really shouldn't happen */ | 2825 | /* This really shouldn't happen */ |
2784 | packet_disconnect("getaddrinfo: fatal error: %s", | 2826 | packet_disconnect("getaddrinfo: fatal error: %s", |
2785 | ssh_gai_strerror(r)); | 2827 | ssh_gai_strerror(r)); |
2786 | } else { | 2828 | } else { |
2787 | error("channel_setup_fwd_listener: " | 2829 | error("%s: getaddrinfo(%.64s): %s", __func__, addr, |
2788 | "getaddrinfo(%.64s): %s", addr, | ||
2789 | ssh_gai_strerror(r)); | 2830 | ssh_gai_strerror(r)); |
2790 | } | 2831 | } |
2791 | return 0; | 2832 | return 0; |
@@ -2809,13 +2850,13 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2809 | * If allocating a port for -R forwards, then use the | 2850 | * If allocating a port for -R forwards, then use the |
2810 | * same port for all address families. | 2851 | * same port for all address families. |
2811 | */ | 2852 | */ |
2812 | if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && | 2853 | if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && |
2813 | allocated_listen_port != NULL && *allocated_listen_port > 0) | 2854 | allocated_listen_port != NULL && *allocated_listen_port > 0) |
2814 | *lport_p = htons(*allocated_listen_port); | 2855 | *lport_p = htons(*allocated_listen_port); |
2815 | 2856 | ||
2816 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), | 2857 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
2817 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | 2858 | strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
2818 | error("channel_setup_fwd_listener: getnameinfo failed"); | 2859 | error("%s: getnameinfo failed", __func__); |
2819 | continue; | 2860 | continue; |
2820 | } | 2861 | } |
2821 | /* Create a port to listen for the host. */ | 2862 | /* Create a port to listen for the host. */ |
@@ -2852,10 +2893,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2852 | } | 2893 | } |
2853 | 2894 | ||
2854 | /* | 2895 | /* |
2855 | * listen_port == 0 requests a dynamically allocated port - | 2896 | * fwd->listen_port == 0 requests a dynamically allocated port - |
2856 | * record what we got. | 2897 | * record what we got. |
2857 | */ | 2898 | */ |
2858 | if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && | 2899 | if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && |
2859 | allocated_listen_port != NULL && | 2900 | allocated_listen_port != NULL && |
2860 | *allocated_listen_port == 0) { | 2901 | *allocated_listen_port == 0) { |
2861 | *allocated_listen_port = get_sock_port(sock, 1); | 2902 | *allocated_listen_port = get_sock_port(sock, 1); |
@@ -2868,24 +2909,98 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2868 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | 2909 | CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
2869 | 0, "port listener", 1); | 2910 | 0, "port listener", 1); |
2870 | c->path = xstrdup(host); | 2911 | c->path = xstrdup(host); |
2871 | c->host_port = port_to_connect; | 2912 | c->host_port = fwd->connect_port; |
2872 | c->listening_addr = addr == NULL ? NULL : xstrdup(addr); | 2913 | c->listening_addr = addr == NULL ? NULL : xstrdup(addr); |
2873 | if (listen_port == 0 && allocated_listen_port != NULL && | 2914 | if (fwd->listen_port == 0 && allocated_listen_port != NULL && |
2874 | !(datafellows & SSH_BUG_DYNAMIC_RPORT)) | 2915 | !(datafellows & SSH_BUG_DYNAMIC_RPORT)) |
2875 | c->listening_port = *allocated_listen_port; | 2916 | c->listening_port = *allocated_listen_port; |
2876 | else | 2917 | else |
2877 | c->listening_port = listen_port; | 2918 | c->listening_port = fwd->listen_port; |
2878 | success = 1; | 2919 | success = 1; |
2879 | } | 2920 | } |
2880 | if (success == 0) | 2921 | if (success == 0) |
2881 | error("channel_setup_fwd_listener: cannot listen to port: %d", | 2922 | error("%s: cannot listen to port: %d", __func__, |
2882 | listen_port); | 2923 | fwd->listen_port); |
2883 | freeaddrinfo(aitop); | 2924 | freeaddrinfo(aitop); |
2884 | return success; | 2925 | return success; |
2885 | } | 2926 | } |
2886 | 2927 | ||
2887 | int | 2928 | static int |
2888 | 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) | ||
2889 | { | 3004 | { |
2890 | u_int i; | 3005 | u_int i; |
2891 | int found = 0; | 3006 | int found = 0; |
@@ -2904,13 +3019,44 @@ channel_cancel_rport_listener(const char *host, u_short port) | |||
2904 | return (found); | 3019 | return (found); |
2905 | } | 3020 | } |
2906 | 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 | |||
2907 | int | 3044 | int |
2908 | channel_cancel_lport_listener(const char *lhost, u_short lport, | 3045 | channel_cancel_rport_listener(struct Forward *fwd) |
2909 | 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) | ||
2910 | { | 3056 | { |
2911 | u_int i; | 3057 | u_int i; |
2912 | int found = 0; | 3058 | int found = 0; |
2913 | 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); |
2914 | 3060 | ||
2915 | for (i = 0; i < channels_alloc; i++) { | 3061 | for (i = 0; i < channels_alloc; i++) { |
2916 | Channel *c = channels[i]; | 3062 | Channel *c = channels[i]; |
@@ -2939,24 +3085,68 @@ channel_cancel_lport_listener(const char *lhost, u_short lport, | |||
2939 | return (found); | 3085 | return (found); |
2940 | } | 3086 | } |
2941 | 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 | |||
2942 | /* protocol local port fwd, used by ssh (and sshd in v1) */ | 3124 | /* protocol local port fwd, used by ssh (and sshd in v1) */ |
2943 | int | 3125 | int |
2944 | 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) |
2945 | const char *host_to_connect, u_short port_to_connect, int gateway_ports) | ||
2946 | { | 3127 | { |
2947 | return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, | 3128 | if (fwd->listen_path != NULL) { |
2948 | listen_host, listen_port, NULL, host_to_connect, port_to_connect, | 3129 | return channel_setup_fwd_listener_streamlocal( |
2949 | 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 | } | ||
2950 | } | 3135 | } |
2951 | 3136 | ||
2952 | /* protocol v2 remote port fwd, used by sshd */ | 3137 | /* protocol v2 remote port fwd, used by sshd */ |
2953 | int | 3138 | int |
2954 | channel_setup_remote_fwd_listener(const char *listen_address, | 3139 | channel_setup_remote_fwd_listener(struct Forward *fwd, |
2955 | u_short listen_port, int *allocated_listen_port, int gateway_ports) | 3140 | int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
2956 | { | 3141 | { |
2957 | return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, | 3142 | if (fwd->listen_path != NULL) { |
2958 | listen_address, listen_port, allocated_listen_port, | 3143 | return channel_setup_fwd_listener_streamlocal( |
2959 | 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 | } | ||
2960 | } | 3150 | } |
2961 | 3151 | ||
2962 | /* | 3152 | /* |
@@ -2987,27 +3177,32 @@ channel_rfwd_bind_host(const char *listen_host) | |||
2987 | * channel_update_permitted_opens(). | 3177 | * channel_update_permitted_opens(). |
2988 | */ | 3178 | */ |
2989 | int | 3179 | int |
2990 | channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | 3180 | channel_request_remote_forwarding(struct Forward *fwd) |
2991 | const char *host_to_connect, u_short port_to_connect) | ||
2992 | { | 3181 | { |
2993 | int type, success = 0, idx = -1; | 3182 | int type, success = 0, idx = -1; |
2994 | 3183 | ||
2995 | /* Send the forward request to the remote side. */ | 3184 | /* Send the forward request to the remote side. */ |
2996 | if (compat20) { | 3185 | if (compat20) { |
2997 | packet_start(SSH2_MSG_GLOBAL_REQUEST); | 3186 | packet_start(SSH2_MSG_GLOBAL_REQUEST); |
2998 | packet_put_cstring("tcpip-forward"); | 3187 | if (fwd->listen_path != NULL) { |
2999 | packet_put_char(1); /* boolean: want reply */ | 3188 | packet_put_cstring("streamlocal-forward@openssh.com"); |
3000 | packet_put_cstring(channel_rfwd_bind_host(listen_host)); | 3189 | packet_put_char(1); /* boolean: want reply */ |
3001 | 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 | } | ||
3002 | packet_send(); | 3197 | packet_send(); |
3003 | packet_write_wait(); | 3198 | packet_write_wait(); |
3004 | /* Assume that server accepts the request */ | 3199 | /* Assume that server accepts the request */ |
3005 | success = 1; | 3200 | success = 1; |
3006 | } else { | 3201 | } else if (fwd->listen_path == NULL) { |
3007 | packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); | 3202 | packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); |
3008 | packet_put_int(listen_port); | 3203 | packet_put_int(fwd->listen_port); |
3009 | packet_put_cstring(host_to_connect); | 3204 | packet_put_cstring(fwd->connect_host); |
3010 | packet_put_int(port_to_connect); | 3205 | packet_put_int(fwd->connect_port); |
3011 | packet_send(); | 3206 | packet_send(); |
3012 | packet_write_wait(); | 3207 | packet_write_wait(); |
3013 | 3208 | ||
@@ -3024,25 +3219,102 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | |||
3024 | packet_disconnect("Protocol error for port forward request:" | 3219 | packet_disconnect("Protocol error for port forward request:" |
3025 | "received packet type %d.", type); | 3220 | "received packet type %d.", type); |
3026 | } | 3221 | } |
3222 | } else { | ||
3223 | logit("Warning: Server does not support remote stream local forwarding."); | ||
3027 | } | 3224 | } |
3028 | if (success) { | 3225 | if (success) { |
3029 | /* Record that connection to this host/port is permitted. */ | 3226 | /* Record that connection to this host/port is permitted. */ |
3030 | permitted_opens = xrealloc(permitted_opens, | 3227 | permitted_opens = xrealloc(permitted_opens, |
3031 | num_permitted_opens + 1, sizeof(*permitted_opens)); | 3228 | num_permitted_opens + 1, sizeof(*permitted_opens)); |
3032 | idx = num_permitted_opens++; | 3229 | idx = num_permitted_opens++; |
3033 | permitted_opens[idx].host_to_connect = xstrdup(host_to_connect); | 3230 | if (fwd->connect_path != NULL) { |
3034 | permitted_opens[idx].port_to_connect = port_to_connect; | 3231 | permitted_opens[idx].host_to_connect = |
3035 | permitted_opens[idx].listen_port = listen_port; | 3232 | xstrdup(fwd->connect_path); |
3233 | permitted_opens[idx].port_to_connect = | ||
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 | } | ||
3036 | } | 3252 | } |
3037 | return (idx); | 3253 | return (idx); |
3038 | } | 3254 | } |
3039 | 3255 | ||
3256 | static int | ||
3257 | open_match(ForwardPermission *allowed_open, const char *requestedhost, | ||
3258 | int requestedport) | ||
3259 | { | ||
3260 | if (allowed_open->host_to_connect == NULL) | ||
3261 | return 0; | ||
3262 | if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT && | ||
3263 | allowed_open->port_to_connect != requestedport) | ||
3264 | return 0; | ||
3265 | if (strcmp(allowed_open->host_to_connect, requestedhost) != 0) | ||
3266 | return 0; | ||
3267 | return 1; | ||
3268 | } | ||
3269 | |||
3270 | /* | ||
3271 | * Note that in the listen host/port case | ||
3272 | * we don't support FWD_PERMIT_ANY_PORT and | ||
3273 | * need to translate between the configured-host (listen_host) | ||
3274 | * and what we've sent to the remote server (channel_rfwd_bind_host) | ||
3275 | */ | ||
3276 | static int | ||
3277 | open_listen_match_tcpip(ForwardPermission *allowed_open, | ||
3278 | const char *requestedhost, u_short requestedport, int translate) | ||
3279 | { | ||
3280 | const char *allowed_host; | ||
3281 | |||
3282 | if (allowed_open->host_to_connect == NULL) | ||
3283 | return 0; | ||
3284 | if (allowed_open->listen_port != requestedport) | ||
3285 | return 0; | ||
3286 | if (!translate && allowed_open->listen_host == NULL && | ||
3287 | requestedhost == NULL) | ||
3288 | return 1; | ||
3289 | allowed_host = translate ? | ||
3290 | channel_rfwd_bind_host(allowed_open->listen_host) : | ||
3291 | allowed_open->listen_host; | ||
3292 | if (allowed_host == NULL || | ||
3293 | strcmp(allowed_host, requestedhost) != 0) | ||
3294 | return 0; | ||
3295 | return 1; | ||
3296 | } | ||
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 | |||
3040 | /* | 3312 | /* |
3041 | * Request cancellation of remote forwarding of connection host:port from | 3313 | * Request cancellation of remote forwarding of connection host:port from |
3042 | * local side. | 3314 | * local side. |
3043 | */ | 3315 | */ |
3044 | int | 3316 | static int |
3045 | channel_request_rforward_cancel(const char *host, u_short port) | 3317 | channel_request_rforward_cancel_tcpip(const char *host, u_short port) |
3046 | { | 3318 | { |
3047 | int i; | 3319 | int i; |
3048 | 3320 | ||
@@ -3050,8 +3322,7 @@ channel_request_rforward_cancel(const char *host, u_short port) | |||
3050 | return -1; | 3322 | return -1; |
3051 | 3323 | ||
3052 | for (i = 0; i < num_permitted_opens; i++) { | 3324 | for (i = 0; i < num_permitted_opens; i++) { |
3053 | if (permitted_opens[i].host_to_connect != NULL && | 3325 | if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0)) |
3054 | permitted_opens[i].listen_port == port) | ||
3055 | break; | 3326 | break; |
3056 | } | 3327 | } |
3057 | if (i >= num_permitted_opens) { | 3328 | if (i >= num_permitted_opens) { |
@@ -3069,9 +3340,64 @@ channel_request_rforward_cancel(const char *host, u_short port) | |||
3069 | permitted_opens[i].port_to_connect = 0; | 3340 | permitted_opens[i].port_to_connect = 0; |
3070 | free(permitted_opens[i].host_to_connect); | 3341 | free(permitted_opens[i].host_to_connect); |
3071 | permitted_opens[i].host_to_connect = NULL; | 3342 | permitted_opens[i].host_to_connect = NULL; |
3343 | free(permitted_opens[i].listen_host); | ||
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; | ||
3072 | 3383 | ||
3073 | return 0; | 3384 | return 0; |
3074 | } | 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 | } | ||
3075 | 3401 | ||
3076 | /* | 3402 | /* |
3077 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates | 3403 | * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
@@ -3079,36 +3405,35 @@ channel_request_rforward_cancel(const char *host, u_short port) | |||
3079 | * message if there was an error). | 3405 | * message if there was an error). |
3080 | */ | 3406 | */ |
3081 | int | 3407 | int |
3082 | channel_input_port_forward_request(int is_root, int gateway_ports) | 3408 | channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts) |
3083 | { | 3409 | { |
3084 | u_short port, host_port; | ||
3085 | int success = 0; | 3410 | int success = 0; |
3086 | char *hostname; | 3411 | struct Forward fwd; |
3087 | 3412 | ||
3088 | /* Get arguments from the packet. */ | 3413 | /* Get arguments from the packet. */ |
3089 | port = packet_get_int(); | 3414 | memset(&fwd, 0, sizeof(fwd)); |
3090 | hostname = packet_get_string(NULL); | 3415 | fwd.listen_port = packet_get_int(); |
3091 | host_port = packet_get_int(); | 3416 | fwd.connect_host = packet_get_string(NULL); |
3417 | fwd.connect_port = packet_get_int(); | ||
3092 | 3418 | ||
3093 | #ifndef HAVE_CYGWIN | 3419 | #ifndef HAVE_CYGWIN |
3094 | /* | 3420 | /* |
3095 | * Check that an unprivileged user is not trying to forward a | 3421 | * Check that an unprivileged user is not trying to forward a |
3096 | * privileged port. | 3422 | * privileged port. |
3097 | */ | 3423 | */ |
3098 | if (port < IPPORT_RESERVED && !is_root) | 3424 | if (fwd.listen_port < IPPORT_RESERVED && !is_root) |
3099 | packet_disconnect( | 3425 | packet_disconnect( |
3100 | "Requested forwarding of port %d but user is not root.", | 3426 | "Requested forwarding of port %d but user is not root.", |
3101 | port); | 3427 | fwd.listen_port); |
3102 | if (host_port == 0) | 3428 | if (fwd.connect_port == 0) |
3103 | packet_disconnect("Dynamic forwarding denied."); | 3429 | packet_disconnect("Dynamic forwarding denied."); |
3104 | #endif | 3430 | #endif |
3105 | 3431 | ||
3106 | /* Initiate forwarding */ | 3432 | /* Initiate forwarding */ |
3107 | success = channel_setup_local_fwd_listener(NULL, port, hostname, | 3433 | success = channel_setup_local_fwd_listener(&fwd, fwd_opts); |
3108 | host_port, gateway_ports); | ||
3109 | 3434 | ||
3110 | /* Free the argument string. */ | 3435 | /* Free the argument string. */ |
3111 | free(hostname); | 3436 | free(fwd.connect_host); |
3112 | 3437 | ||
3113 | return (success ? 0 : -1); | 3438 | return (success ? 0 : -1); |
3114 | } | 3439 | } |
@@ -3134,6 +3459,9 @@ channel_add_permitted_opens(char *host, int port) | |||
3134 | num_permitted_opens + 1, sizeof(*permitted_opens)); | 3459 | num_permitted_opens + 1, sizeof(*permitted_opens)); |
3135 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); | 3460 | permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); |
3136 | permitted_opens[num_permitted_opens].port_to_connect = port; | 3461 | permitted_opens[num_permitted_opens].port_to_connect = port; |
3462 | permitted_opens[num_permitted_opens].listen_host = NULL; | ||
3463 | permitted_opens[num_permitted_opens].listen_path = NULL; | ||
3464 | permitted_opens[num_permitted_opens].listen_port = 0; | ||
3137 | num_permitted_opens++; | 3465 | num_permitted_opens++; |
3138 | 3466 | ||
3139 | all_opens_permitted = 0; | 3467 | all_opens_permitted = 0; |
@@ -3165,6 +3493,10 @@ channel_update_permitted_opens(int idx, int newport) | |||
3165 | permitted_opens[idx].port_to_connect = 0; | 3493 | permitted_opens[idx].port_to_connect = 0; |
3166 | free(permitted_opens[idx].host_to_connect); | 3494 | free(permitted_opens[idx].host_to_connect); |
3167 | permitted_opens[idx].host_to_connect = NULL; | 3495 | permitted_opens[idx].host_to_connect = NULL; |
3496 | free(permitted_opens[idx].listen_host); | ||
3497 | permitted_opens[idx].listen_host = NULL; | ||
3498 | free(permitted_opens[idx].listen_path); | ||
3499 | permitted_opens[idx].listen_path = NULL; | ||
3168 | } | 3500 | } |
3169 | } | 3501 | } |
3170 | 3502 | ||
@@ -3178,6 +3510,9 @@ channel_add_adm_permitted_opens(char *host, int port) | |||
3178 | permitted_adm_opens[num_adm_permitted_opens].host_to_connect | 3510 | permitted_adm_opens[num_adm_permitted_opens].host_to_connect |
3179 | = xstrdup(host); | 3511 | = xstrdup(host); |
3180 | permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; | 3512 | permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; |
3513 | permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; | ||
3514 | permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL; | ||
3515 | permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; | ||
3181 | return ++num_adm_permitted_opens; | 3516 | return ++num_adm_permitted_opens; |
3182 | } | 3517 | } |
3183 | 3518 | ||
@@ -3195,8 +3530,11 @@ channel_clear_permitted_opens(void) | |||
3195 | { | 3530 | { |
3196 | int i; | 3531 | int i; |
3197 | 3532 | ||
3198 | for (i = 0; i < num_permitted_opens; i++) | 3533 | for (i = 0; i < num_permitted_opens; i++) { |
3199 | free(permitted_opens[i].host_to_connect); | 3534 | free(permitted_opens[i].host_to_connect); |
3535 | free(permitted_opens[i].listen_host); | ||
3536 | free(permitted_opens[i].listen_path); | ||
3537 | } | ||
3200 | free(permitted_opens); | 3538 | free(permitted_opens); |
3201 | permitted_opens = NULL; | 3539 | permitted_opens = NULL; |
3202 | num_permitted_opens = 0; | 3540 | num_permitted_opens = 0; |
@@ -3207,8 +3545,11 @@ channel_clear_adm_permitted_opens(void) | |||
3207 | { | 3545 | { |
3208 | int i; | 3546 | int i; |
3209 | 3547 | ||
3210 | for (i = 0; i < num_adm_permitted_opens; i++) | 3548 | for (i = 0; i < num_adm_permitted_opens; i++) { |
3211 | free(permitted_adm_opens[i].host_to_connect); | 3549 | free(permitted_adm_opens[i].host_to_connect); |
3550 | free(permitted_adm_opens[i].listen_host); | ||
3551 | free(permitted_adm_opens[i].listen_path); | ||
3552 | } | ||
3212 | free(permitted_adm_opens); | 3553 | free(permitted_adm_opens); |
3213 | permitted_adm_opens = NULL; | 3554 | permitted_adm_opens = NULL; |
3214 | num_adm_permitted_opens = 0; | 3555 | num_adm_permitted_opens = 0; |
@@ -3246,30 +3587,32 @@ permitopen_port(const char *p) | |||
3246 | return -1; | 3587 | return -1; |
3247 | } | 3588 | } |
3248 | 3589 | ||
3249 | static int | ||
3250 | port_match(u_short allowedport, u_short requestedport) | ||
3251 | { | ||
3252 | if (allowedport == FWD_PERMIT_ANY_PORT || | ||
3253 | allowedport == requestedport) | ||
3254 | return 1; | ||
3255 | return 0; | ||
3256 | } | ||
3257 | |||
3258 | /* Try to start non-blocking connect to next host in cctx list */ | 3590 | /* Try to start non-blocking connect to next host in cctx list */ |
3259 | static int | 3591 | static int |
3260 | connect_next(struct channel_connect *cctx) | 3592 | connect_next(struct channel_connect *cctx) |
3261 | { | 3593 | { |
3262 | int sock, saved_errno; | 3594 | int sock, saved_errno; |
3263 | 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))]; | ||
3264 | 3597 | ||
3265 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { | 3598 | for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { |
3266 | if (cctx->ai->ai_family != AF_INET && | 3599 | switch (cctx->ai->ai_family) { |
3267 | cctx->ai->ai_family != AF_INET6) | 3600 | case AF_UNIX: |
3268 | continue; | 3601 | /* unix:pathname instead of host:port */ |
3269 | if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, | 3602 | sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr; |
3270 | ntop, sizeof(ntop), strport, sizeof(strport), | 3603 | strlcpy(ntop, "unix", sizeof(ntop)); |
3271 | NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | 3604 | strlcpy(strport, sunaddr->sun_path, sizeof(strport)); |
3272 | 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: | ||
3273 | continue; | 3616 | continue; |
3274 | } | 3617 | } |
3275 | if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, | 3618 | if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, |
@@ -3292,10 +3635,11 @@ connect_next(struct channel_connect *cctx) | |||
3292 | errno = saved_errno; | 3635 | errno = saved_errno; |
3293 | continue; /* fail -- try next */ | 3636 | continue; /* fail -- try next */ |
3294 | } | 3637 | } |
3638 | if (cctx->ai->ai_family != AF_UNIX) | ||
3639 | set_nodelay(sock); | ||
3295 | debug("connect_next: host %.100s ([%.100s]:%s) " | 3640 | debug("connect_next: host %.100s ([%.100s]:%s) " |
3296 | "in progress, fd=%d", cctx->host, ntop, strport, sock); | 3641 | "in progress, fd=%d", cctx->host, ntop, strport, sock); |
3297 | cctx->ai = cctx->ai->ai_next; | 3642 | cctx->ai = cctx->ai->ai_next; |
3298 | set_nodelay(sock); | ||
3299 | return sock; | 3643 | return sock; |
3300 | } | 3644 | } |
3301 | return -1; | 3645 | return -1; |
@@ -3305,14 +3649,18 @@ static void | |||
3305 | channel_connect_ctx_free(struct channel_connect *cctx) | 3649 | channel_connect_ctx_free(struct channel_connect *cctx) |
3306 | { | 3650 | { |
3307 | free(cctx->host); | 3651 | free(cctx->host); |
3308 | if (cctx->aitop) | 3652 | if (cctx->aitop) { |
3309 | freeaddrinfo(cctx->aitop); | 3653 | if (cctx->aitop->ai_family == AF_UNIX) |
3654 | free(cctx->aitop); | ||
3655 | else | ||
3656 | freeaddrinfo(cctx->aitop); | ||
3657 | } | ||
3310 | memset(cctx, 0, sizeof(*cctx)); | 3658 | memset(cctx, 0, sizeof(*cctx)); |
3311 | } | 3659 | } |
3312 | 3660 | ||
3313 | /* Return CONNECTING channel to remote host, port */ | 3661 | /* Return CONNECTING channel to remote host:port or local socket path */ |
3314 | static Channel * | 3662 | static Channel * |
3315 | connect_to(const char *host, u_short port, char *ctype, char *rname) | 3663 | connect_to(const char *name, int port, char *ctype, char *rname) |
3316 | { | 3664 | { |
3317 | struct addrinfo hints; | 3665 | struct addrinfo hints; |
3318 | int gaierr; | 3666 | int gaierr; |
@@ -3322,23 +3670,51 @@ connect_to(const char *host, u_short port, char *ctype, char *rname) | |||
3322 | Channel *c; | 3670 | Channel *c; |
3323 | 3671 | ||
3324 | memset(&cctx, 0, sizeof(cctx)); | 3672 | memset(&cctx, 0, sizeof(cctx)); |
3325 | memset(&hints, 0, sizeof(hints)); | 3673 | |
3326 | hints.ai_family = IPv4or6; | 3674 | if (port == PORT_STREAMLOCAL) { |
3327 | hints.ai_socktype = SOCK_STREAM; | 3675 | struct sockaddr_un *sunaddr; |
3328 | snprintf(strport, sizeof strport, "%d", port); | 3676 | struct addrinfo *ai; |
3329 | if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) { | 3677 | |
3330 | error("connect_to %.100s: unknown host (%s)", host, | 3678 | if (strlen(name) > sizeof(sunaddr->sun_path)) { |
3331 | ssh_gai_strerror(gaierr)); | 3679 | error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); |
3332 | 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 | } | ||
3333 | } | 3709 | } |
3334 | 3710 | ||
3335 | cctx.host = xstrdup(host); | 3711 | cctx.host = xstrdup(name); |
3336 | cctx.port = port; | 3712 | cctx.port = port; |
3337 | cctx.ai = cctx.aitop; | 3713 | cctx.ai = cctx.aitop; |
3338 | 3714 | ||
3339 | if ((sock = connect_next(&cctx)) == -1) { | 3715 | if ((sock = connect_next(&cctx)) == -1) { |
3340 | error("connect to %.100s port %d failed: %s", | 3716 | error("connect to %.100s port %d failed: %s", |
3341 | host, port, strerror(errno)); | 3717 | name, port, strerror(errno)); |
3342 | channel_connect_ctx_free(&cctx); | 3718 | channel_connect_ctx_free(&cctx); |
3343 | return NULL; | 3719 | return NULL; |
3344 | } | 3720 | } |
@@ -3349,13 +3725,14 @@ connect_to(const char *host, u_short port, char *ctype, char *rname) | |||
3349 | } | 3725 | } |
3350 | 3726 | ||
3351 | Channel * | 3727 | Channel * |
3352 | channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname) | 3728 | channel_connect_by_listen_address(const char *listen_host, |
3729 | u_short listen_port, char *ctype, char *rname) | ||
3353 | { | 3730 | { |
3354 | int i; | 3731 | int i; |
3355 | 3732 | ||
3356 | for (i = 0; i < num_permitted_opens; i++) { | 3733 | for (i = 0; i < num_permitted_opens; i++) { |
3357 | if (permitted_opens[i].host_to_connect != NULL && | 3734 | if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
3358 | port_match(permitted_opens[i].listen_port, listen_port)) { | 3735 | listen_port, 1)) { |
3359 | return connect_to( | 3736 | return connect_to( |
3360 | permitted_opens[i].host_to_connect, | 3737 | permitted_opens[i].host_to_connect, |
3361 | permitted_opens[i].port_to_connect, ctype, rname); | 3738 | permitted_opens[i].port_to_connect, ctype, rname); |
@@ -3366,29 +3743,45 @@ channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname) | |||
3366 | return NULL; | 3743 | return NULL; |
3367 | } | 3744 | } |
3368 | 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 | |||
3369 | /* Check if connecting to that port is permitted and connect. */ | 3763 | /* Check if connecting to that port is permitted and connect. */ |
3370 | Channel * | 3764 | Channel * |
3371 | 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) |
3372 | { | 3766 | { |
3373 | int i, permit, permit_adm = 1; | 3767 | int i, permit, permit_adm = 1; |
3374 | 3768 | ||
3375 | permit = all_opens_permitted; | 3769 | permit = all_opens_permitted; |
3376 | if (!permit) { | 3770 | if (!permit) { |
3377 | for (i = 0; i < num_permitted_opens; i++) | 3771 | for (i = 0; i < num_permitted_opens; i++) |
3378 | if (permitted_opens[i].host_to_connect != NULL && | 3772 | if (open_match(&permitted_opens[i], host, port)) { |
3379 | port_match(permitted_opens[i].port_to_connect, port) && | ||
3380 | strcmp(permitted_opens[i].host_to_connect, host) == 0) | ||
3381 | permit = 1; | 3773 | permit = 1; |
3774 | break; | ||
3775 | } | ||
3382 | } | 3776 | } |
3383 | 3777 | ||
3384 | if (num_adm_permitted_opens > 0) { | 3778 | if (num_adm_permitted_opens > 0) { |
3385 | permit_adm = 0; | 3779 | permit_adm = 0; |
3386 | for (i = 0; i < num_adm_permitted_opens; i++) | 3780 | for (i = 0; i < num_adm_permitted_opens; i++) |
3387 | if (permitted_adm_opens[i].host_to_connect != NULL && | 3781 | if (open_match(&permitted_adm_opens[i], host, port)) { |
3388 | port_match(permitted_adm_opens[i].port_to_connect, port) && | ||
3389 | strcmp(permitted_adm_opens[i].host_to_connect, host) | ||
3390 | == 0) | ||
3391 | permit_adm = 1; | 3782 | permit_adm = 1; |
3783 | break; | ||
3784 | } | ||
3392 | } | 3785 | } |
3393 | 3786 | ||
3394 | if (!permit || !permit_adm) { | 3787 | if (!permit || !permit_adm) { |
@@ -3399,6 +3792,38 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname) | |||
3399 | return connect_to(host, port, ctype, rname); | 3792 | return connect_to(host, port, ctype, rname); |
3400 | } | 3793 | } |
3401 | 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 | |||
3402 | void | 3827 | void |
3403 | channel_send_window_changes(void) | 3828 | channel_send_window_changes(void) |
3404 | { | 3829 | { |