diff options
author | Colin Watson <cjwatson@debian.org> | 2014-10-07 13:33:15 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2014-10-07 14:27:30 +0100 |
commit | f0b009aea83e9ff3a50be30f51012099a5143c16 (patch) | |
tree | 3825e6f7e3b7ea4481d06ed89aba9a7a95150df5 /channels.c | |
parent | 47f0bad4330b16ec3bad870fcf9839c196e42c12 (diff) | |
parent | 762c062828f5a8f6ed189ed6e44ad38fd92f8b36 (diff) |
Merge 6.7p1.
* New upstream release (http://www.openssh.com/txt/release-6.7):
- sshd(8): The default set of ciphers and MACs has been altered to
remove unsafe algorithms. In particular, CBC ciphers and arcfour* are
disabled by default. The full set of algorithms remains available if
configured explicitly via the Ciphers and MACs sshd_config options.
- ssh(1), sshd(8): Add support for Unix domain socket forwarding. A
remote TCP port may be forwarded to a local Unix domain socket and
vice versa or both ends may be a Unix domain socket (closes: #236718).
- ssh(1), ssh-keygen(1): Add support for SSHFP DNS records for ED25519
key types.
- sftp(1): Allow resumption of interrupted uploads.
- ssh(1): When rekeying, skip file/DNS lookups of the hostkey if it is
the same as the one sent during initial key exchange.
- sshd(8): Allow explicit ::1 and 127.0.0.1 forwarding bind addresses
when GatewayPorts=no; allows client to choose address family.
- sshd(8): Add a sshd_config PermitUserRC option to control whether
~/.ssh/rc is executed, mirroring the no-user-rc authorized_keys
option.
- ssh(1): Add a %C escape sequence for LocalCommand and ControlPath that
expands to a unique identifer based on a hash of the tuple of (local
host, remote user, hostname, port). Helps avoid exceeding miserly
pathname limits for Unix domain sockets in multiplexing control paths.
- sshd(8): Make the "Too many authentication failures" message include
the user, source address, port and protocol in a format similar to the
authentication success / failure messages.
- Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC when it is
available. It considers time spent suspended, thereby ensuring
timeouts (e.g. for expiring agent keys) fire correctly (closes:
#734553).
- Use prctl() to prevent sftp-server from accessing
/proc/self/{mem,maps}.
* Restore TCP wrappers support, removed upstream in 6.7. It is true that
dropping this reduces preauth attack surface in sshd. On the other
hand, this support seems to be quite widely used, and abruptly dropping
it (from the perspective of users who don't read openssh-unix-dev) could
easily cause more serious problems in practice. It's not entirely clear
what the right long-term answer for Debian is, but it at least probably
doesn't involve dropping this feature shortly before a freeze.
* Replace patch to disable OpenSSL version check with an updated version
of Kurt Roeckx's patch from #732940 to just avoid checking the status
field.
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 | { |