version 1.335, 2014/07/05 23:11:48 |
version 1.336, 2014/07/15 15:54:14 |
|
|
*/ |
*/ |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/stat.h> |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/un.h> |
#include <sys/un.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
|
|
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local |
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local |
* network (which might be behind a firewall). |
* network (which might be behind a firewall). |
*/ |
*/ |
|
/* XXX: streamlocal wants a path instead of host:port */ |
|
/* Overload host_to_connect; we could just make this match Forward */ |
|
/* XXX - can we use listen_host instead of listen_path? */ |
typedef struct { |
typedef struct { |
char *host_to_connect; /* Connect to 'host'. */ |
char *host_to_connect; /* Connect to 'host'. */ |
u_short port_to_connect; /* Connect to 'port'. */ |
int port_to_connect; /* Connect to 'port'. */ |
char *listen_host; /* Remote side should listen address. */ |
char *listen_host; /* Remote side should listen address. */ |
u_short listen_port; /* Remote side should listen port. */ |
char *listen_path; /* Remote side should listen path. */ |
|
int listen_port; /* Remote side should listen port. */ |
} ForwardPermission; |
} ForwardPermission; |
|
|
/* List of all permitted host/port pairs to connect by the user. */ |
/* List of all permitted host/port pairs to connect by the user. */ |
|
|
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_PORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_RPORT_LISTENER: |
case SSH_CHANNEL_X11_LISTENER: |
case SSH_CHANNEL_X11_LISTENER: |
|
case SSH_CHANNEL_UNIX_LISTENER: |
|
case SSH_CHANNEL_RUNIX_LISTENER: |
channel_close_fd(&c->sock); |
channel_close_fd(&c->sock); |
channel_free(c); |
channel_free(c); |
break; |
break; |
|
|
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_ABANDONED: |
|
case SSH_CHANNEL_UNIX_LISTENER: |
|
case SSH_CHANNEL_RUNIX_LISTENER: |
continue; |
continue; |
case SSH_CHANNEL_LARVAL: |
case SSH_CHANNEL_LARVAL: |
if (!compat20) |
if (!compat20) |
|
|
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_CONNECTING: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ZOMBIE: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_ABANDONED: |
|
case SSH_CHANNEL_UNIX_LISTENER: |
|
case SSH_CHANNEL_RUNIX_LISTENER: |
continue; |
continue; |
case SSH_CHANNEL_LARVAL: |
case SSH_CHANNEL_LARVAL: |
case SSH_CHANNEL_AUTH_SOCKET: |
case SSH_CHANNEL_AUTH_SOCKET: |
|
|
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_ABANDONED: |
case SSH_CHANNEL_MUX_CLIENT: |
case SSH_CHANNEL_MUX_CLIENT: |
case SSH_CHANNEL_MUX_LISTENER: |
case SSH_CHANNEL_MUX_LISTENER: |
|
case SSH_CHANNEL_UNIX_LISTENER: |
|
case SSH_CHANNEL_RUNIX_LISTENER: |
continue; |
continue; |
case SSH_CHANNEL_LARVAL: |
case SSH_CHANNEL_LARVAL: |
case SSH_CHANNEL_OPENING: |
case SSH_CHANNEL_OPENING: |
|
|
static void |
static void |
port_open_helper(Channel *c, char *rtype) |
port_open_helper(Channel *c, char *rtype) |
{ |
{ |
int direct; |
|
char buf[1024]; |
char buf[1024]; |
char *local_ipaddr = get_local_ipaddr(c->sock); |
char *local_ipaddr = get_local_ipaddr(c->sock); |
int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1); |
int local_port = c->sock == -1 ? 65536 : get_sock_port(c->sock, 1); |
|
|
remote_port = 65535; |
remote_port = 65535; |
} |
} |
|
|
direct = (strcmp(rtype, "direct-tcpip") == 0); |
|
|
|
snprintf(buf, sizeof buf, |
snprintf(buf, sizeof buf, |
"%s: listening port %d for %.100s port %d, " |
"%s: listening port %d for %.100s port %d, " |
"connect from %.200s port %d to %.100s port %d", |
"connect from %.200s port %d to %.100s port %d", |
|
|
packet_put_int(c->self); |
packet_put_int(c->self); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_window_max); |
packet_put_int(c->local_maxpacket); |
packet_put_int(c->local_maxpacket); |
if (direct) { |
if (strcmp(rtype, "direct-tcpip") == 0) { |
/* target host, port */ |
/* target host, port */ |
packet_put_cstring(c->path); |
packet_put_cstring(c->path); |
packet_put_int(c->host_port); |
packet_put_int(c->host_port); |
|
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) { |
|
/* target path */ |
|
packet_put_cstring(c->path); |
|
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
|
/* listen path */ |
|
packet_put_cstring(c->path); |
} else { |
} else { |
/* listen address, port */ |
/* listen address, port */ |
packet_put_cstring(c->path); |
packet_put_cstring(c->path); |
packet_put_int(local_port); |
packet_put_int(local_port); |
} |
} |
/* originator host and port */ |
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) { |
packet_put_cstring(remote_ipaddr); |
/* reserved for future owner/mode info */ |
packet_put_int((u_int)remote_port); |
packet_put_cstring(""); |
|
} else { |
|
/* originator host and port */ |
|
packet_put_cstring(remote_ipaddr); |
|
packet_put_int((u_int)remote_port); |
|
} |
packet_send(); |
packet_send(); |
} else { |
} else { |
packet_start(SSH_MSG_PORT_OPEN); |
packet_start(SSH_MSG_PORT_OPEN); |
|
|
if (c->type == SSH_CHANNEL_RPORT_LISTENER) { |
if (c->type == SSH_CHANNEL_RPORT_LISTENER) { |
nextstate = SSH_CHANNEL_OPENING; |
nextstate = SSH_CHANNEL_OPENING; |
rtype = "forwarded-tcpip"; |
rtype = "forwarded-tcpip"; |
|
} else if (c->type == SSH_CHANNEL_RUNIX_LISTENER) { |
|
nextstate = SSH_CHANNEL_OPENING; |
|
rtype = "forwarded-streamlocal@openssh.com"; |
|
} else if (c->host_port == PORT_STREAMLOCAL) { |
|
nextstate = SSH_CHANNEL_OPENING; |
|
rtype = "direct-streamlocal@openssh.com"; |
|
} else if (c->host_port == 0) { |
|
nextstate = SSH_CHANNEL_DYNAMIC; |
|
rtype = "dynamic-tcpip"; |
} else { |
} else { |
if (c->host_port == 0) { |
nextstate = SSH_CHANNEL_OPENING; |
nextstate = SSH_CHANNEL_DYNAMIC; |
rtype = "direct-tcpip"; |
rtype = "dynamic-tcpip"; |
|
} else { |
|
nextstate = SSH_CHANNEL_OPENING; |
|
rtype = "direct-tcpip"; |
|
} |
|
} |
} |
|
|
addrlen = sizeof(addr); |
addrlen = sizeof(addr); |
|
|
c->notbefore = monotime() + 1; |
c->notbefore = monotime() + 1; |
return; |
return; |
} |
} |
set_nodelay(newsock); |
if (c->host_port != PORT_STREAMLOCAL) |
|
set_nodelay(newsock); |
nc = channel_new(rtype, nextstate, newsock, newsock, -1, |
nc = channel_new(rtype, nextstate, newsock, newsock, -1, |
c->local_window_max, c->local_maxpacket, 0, rtype, 1); |
c->local_window_max, c->local_maxpacket, 0, rtype, 1); |
nc->listening_port = c->listening_port; |
nc->listening_port = c->listening_port; |
|
|
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; |
|
channel_pre[SSH_CHANNEL_UNIX_LISTENER] = &channel_pre_listener; |
|
channel_pre[SSH_CHANNEL_RUNIX_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
|
|
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; |
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; |
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; |
channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; |
|
channel_post[SSH_CHANNEL_UNIX_LISTENER] = &channel_post_port_listener; |
|
channel_post[SSH_CHANNEL_RUNIX_LISTENER] = &channel_post_port_listener; |
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
|
|
originator_string = xstrdup("unknown (remote did not supply name)"); |
originator_string = xstrdup("unknown (remote did not supply name)"); |
} |
} |
packet_check_eom(); |
packet_check_eom(); |
c = channel_connect_to(host, host_port, |
c = channel_connect_to_port(host, host_port, |
"connected socket", originator_string); |
"connected socket", originator_string); |
free(originator_string); |
free(originator_string); |
free(host); |
free(host); |
|
|
*/ |
*/ |
static const char * |
static const char * |
channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, |
channel_fwd_bind_addr(const char *listen_addr, int *wildcardp, |
int is_client, int gateway_ports) |
int is_client, struct ForwardOptions *fwd_opts) |
{ |
{ |
const char *addr = NULL; |
const char *addr = NULL; |
int wildcard = 0; |
int wildcard = 0; |
|
|
if (listen_addr == NULL) { |
if (listen_addr == NULL) { |
/* No address specified: default to gateway_ports setting */ |
/* No address specified: default to gateway_ports setting */ |
if (gateway_ports) |
if (fwd_opts->gateway_ports) |
wildcard = 1; |
wildcard = 1; |
} else if (gateway_ports || is_client) { |
} else if (fwd_opts->gateway_ports || is_client) { |
if (((datafellows & SSH_OLD_FORWARD_ADDR) && |
if (((datafellows & SSH_OLD_FORWARD_ADDR) && |
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || |
strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) || |
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || |
*listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || |
(!is_client && gateway_ports == 1)) { |
(!is_client && fwd_opts->gateway_ports == 1)) { |
wildcard = 1; |
wildcard = 1; |
/* |
/* |
* Notify client if they requested a specific listen |
* Notify client if they requested a specific listen |
|
|
} |
} |
|
|
static int |
static int |
channel_setup_fwd_listener(int type, const char *listen_addr, |
channel_setup_fwd_listener_tcpip(int type, struct Forward *fwd, |
u_short listen_port, int *allocated_listen_port, |
int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
|
{ |
{ |
Channel *c; |
Channel *c; |
int sock, r, success = 0, wildcard = 0, is_client; |
int sock, r, success = 0, wildcard = 0, is_client; |
|
|
in_port_t *lport_p; |
in_port_t *lport_p; |
|
|
host = (type == SSH_CHANNEL_RPORT_LISTENER) ? |
host = (type == SSH_CHANNEL_RPORT_LISTENER) ? |
listen_addr : host_to_connect; |
fwd->listen_host : fwd->connect_host; |
is_client = (type == SSH_CHANNEL_PORT_LISTENER); |
is_client = (type == SSH_CHANNEL_PORT_LISTENER); |
|
|
if (host == NULL) { |
if (host == NULL) { |
|
|
} |
} |
|
|
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
/* Determine the bind address, cf. channel_fwd_bind_addr() comment */ |
addr = channel_fwd_bind_addr(listen_addr, &wildcard, |
addr = channel_fwd_bind_addr(fwd->listen_host, &wildcard, |
is_client, gateway_ports); |
is_client, fwd_opts); |
debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", |
debug3("%s: type %d wildcard %d addr %s", __func__, |
type, wildcard, (addr == NULL) ? "NULL" : addr); |
type, wildcard, (addr == NULL) ? "NULL" : addr); |
|
|
/* |
/* |
|
|
hints.ai_family = IPv4or6; |
hints.ai_family = IPv4or6; |
hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
hints.ai_flags = wildcard ? AI_PASSIVE : 0; |
hints.ai_socktype = SOCK_STREAM; |
hints.ai_socktype = SOCK_STREAM; |
snprintf(strport, sizeof strport, "%d", listen_port); |
snprintf(strport, sizeof strport, "%d", fwd->listen_port); |
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { |
if (addr == NULL) { |
if (addr == NULL) { |
/* This really shouldn't happen */ |
/* This really shouldn't happen */ |
packet_disconnect("getaddrinfo: fatal error: %s", |
packet_disconnect("getaddrinfo: fatal error: %s", |
ssh_gai_strerror(r)); |
ssh_gai_strerror(r)); |
} else { |
} else { |
error("channel_setup_fwd_listener: " |
error("%s: getaddrinfo(%.64s): %s", __func__, addr, |
"getaddrinfo(%.64s): %s", addr, |
|
ssh_gai_strerror(r)); |
ssh_gai_strerror(r)); |
} |
} |
return 0; |
return 0; |
|
|
* If allocating a port for -R forwards, then use the |
* If allocating a port for -R forwards, then use the |
* same port for all address families. |
* same port for all address families. |
*/ |
*/ |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && |
allocated_listen_port != NULL && *allocated_listen_port > 0) |
allocated_listen_port != NULL && *allocated_listen_port > 0) |
*lport_p = htons(*allocated_listen_port); |
*lport_p = htons(*allocated_listen_port); |
|
|
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
error("channel_setup_fwd_listener: getnameinfo failed"); |
error("%s: getnameinfo failed", __func__); |
continue; |
continue; |
} |
} |
/* Create a port to listen for the host. */ |
/* Create a port to listen for the host. */ |
|
|
} |
} |
|
|
/* |
/* |
* listen_port == 0 requests a dynamically allocated port - |
* fwd->listen_port == 0 requests a dynamically allocated port - |
* record what we got. |
* record what we got. |
*/ |
*/ |
if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 && |
if (type == SSH_CHANNEL_RPORT_LISTENER && fwd->listen_port == 0 && |
allocated_listen_port != NULL && |
allocated_listen_port != NULL && |
*allocated_listen_port == 0) { |
*allocated_listen_port == 0) { |
*allocated_listen_port = get_sock_port(sock, 1); |
*allocated_listen_port = get_sock_port(sock, 1); |
|
|
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, "port listener", 1); |
0, "port listener", 1); |
c->path = xstrdup(host); |
c->path = xstrdup(host); |
c->host_port = port_to_connect; |
c->host_port = fwd->connect_port; |
c->listening_addr = addr == NULL ? NULL : xstrdup(addr); |
c->listening_addr = addr == NULL ? NULL : xstrdup(addr); |
if (listen_port == 0 && allocated_listen_port != NULL && |
if (fwd->listen_port == 0 && allocated_listen_port != NULL && |
!(datafellows & SSH_BUG_DYNAMIC_RPORT)) |
!(datafellows & SSH_BUG_DYNAMIC_RPORT)) |
c->listening_port = *allocated_listen_port; |
c->listening_port = *allocated_listen_port; |
else |
else |
c->listening_port = listen_port; |
c->listening_port = fwd->listen_port; |
success = 1; |
success = 1; |
} |
} |
if (success == 0) |
if (success == 0) |
error("channel_setup_fwd_listener: cannot listen to port: %d", |
error("%s: cannot listen to port: %d", __func__, |
listen_port); |
fwd->listen_port); |
freeaddrinfo(aitop); |
freeaddrinfo(aitop); |
return success; |
return success; |
} |
} |
|
|
int |
static int |
channel_cancel_rport_listener(const char *host, u_short port) |
channel_setup_fwd_listener_streamlocal(int type, struct Forward *fwd, |
|
struct ForwardOptions *fwd_opts) |
{ |
{ |
|
struct sockaddr_un sunaddr; |
|
const char *path; |
|
Channel *c; |
|
int port, sock; |
|
mode_t omask; |
|
|
|
switch (type) { |
|
case SSH_CHANNEL_UNIX_LISTENER: |
|
if (fwd->connect_path != NULL) { |
|
if (strlen(fwd->connect_path) > sizeof(sunaddr.sun_path)) { |
|
error("Local connecting path too long: %s", |
|
fwd->connect_path); |
|
return 0; |
|
} |
|
path = fwd->connect_path; |
|
port = PORT_STREAMLOCAL; |
|
} else { |
|
if (fwd->connect_host == NULL) { |
|
error("No forward host name."); |
|
return 0; |
|
} |
|
if (strlen(fwd->connect_host) >= NI_MAXHOST) { |
|
error("Forward host name too long."); |
|
return 0; |
|
} |
|
path = fwd->connect_host; |
|
port = fwd->connect_port; |
|
} |
|
break; |
|
case SSH_CHANNEL_RUNIX_LISTENER: |
|
path = fwd->listen_path; |
|
port = PORT_STREAMLOCAL; |
|
break; |
|
default: |
|
error("%s: unexpected channel type %d", __func__, type); |
|
return 0; |
|
} |
|
|
|
if (fwd->listen_path == NULL) { |
|
error("No forward path name."); |
|
return 0; |
|
} |
|
if (strlen(fwd->listen_path) > sizeof(sunaddr.sun_path)) { |
|
error("Local listening path too long: %s", fwd->listen_path); |
|
return 0; |
|
} |
|
|
|
debug3("%s: type %d path %s", __func__, type, fwd->listen_path); |
|
|
|
/* Start a Unix domain listener. */ |
|
omask = umask(fwd_opts->streamlocal_bind_mask); |
|
sock = unix_listener(fwd->listen_path, SSH_LISTEN_BACKLOG, |
|
fwd_opts->streamlocal_bind_unlink); |
|
umask(omask); |
|
if (sock < 0) |
|
return 0; |
|
|
|
debug("Local forwarding listening on path %s.", fwd->listen_path); |
|
|
|
/* Allocate a channel number for the socket. */ |
|
c = channel_new("unix listener", type, sock, sock, -1, |
|
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
|
0, "unix listener", 1); |
|
c->path = xstrdup(path); |
|
c->host_port = port; |
|
c->listening_port = PORT_STREAMLOCAL; |
|
c->listening_addr = xstrdup(fwd->listen_path); |
|
return 1; |
|
} |
|
|
|
static int |
|
channel_cancel_rport_listener_tcpip(const char *host, u_short port) |
|
{ |
u_int i; |
u_int i; |
int found = 0; |
int found = 0; |
|
|
|
|
return (found); |
return (found); |
} |
} |
|
|
|
static int |
|
channel_cancel_rport_listener_streamlocal(const char *path) |
|
{ |
|
u_int i; |
|
int found = 0; |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
Channel *c = channels[i]; |
|
if (c == NULL || c->type != SSH_CHANNEL_RUNIX_LISTENER) |
|
continue; |
|
if (c->path == NULL) |
|
continue; |
|
if (strcmp(c->path, path) == 0) { |
|
debug2("%s: close channel %d", __func__, i); |
|
channel_free(c); |
|
found = 1; |
|
} |
|
} |
|
|
|
return (found); |
|
} |
|
|
int |
int |
channel_cancel_lport_listener(const char *lhost, u_short lport, |
channel_cancel_rport_listener(struct Forward *fwd) |
int cport, int gateway_ports) |
|
{ |
{ |
|
if (fwd->listen_path != NULL) |
|
return channel_cancel_rport_listener_streamlocal(fwd->listen_path); |
|
else |
|
return channel_cancel_rport_listener_tcpip(fwd->listen_host, fwd->listen_port); |
|
} |
|
|
|
static int |
|
channel_cancel_lport_listener_tcpip(const char *lhost, u_short lport, |
|
int cport, struct ForwardOptions *fwd_opts) |
|
{ |
u_int i; |
u_int i; |
int found = 0; |
int found = 0; |
const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports); |
const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, fwd_opts); |
|
|
for (i = 0; i < channels_alloc; i++) { |
for (i = 0; i < channels_alloc; i++) { |
Channel *c = channels[i]; |
Channel *c = channels[i]; |
|
|
return (found); |
return (found); |
} |
} |
|
|
|
static int |
|
channel_cancel_lport_listener_streamlocal(const char *path) |
|
{ |
|
u_int i; |
|
int found = 0; |
|
|
|
if (path == NULL) { |
|
error("%s: no path specified.", __func__); |
|
return 0; |
|
} |
|
|
|
for (i = 0; i < channels_alloc; i++) { |
|
Channel *c = channels[i]; |
|
if (c == NULL || c->type != SSH_CHANNEL_UNIX_LISTENER) |
|
continue; |
|
if (c->listening_addr == NULL) |
|
continue; |
|
if (strcmp(c->listening_addr, path) == 0) { |
|
debug2("%s: close channel %d", __func__, i); |
|
channel_free(c); |
|
found = 1; |
|
} |
|
} |
|
|
|
return (found); |
|
} |
|
|
|
int |
|
channel_cancel_lport_listener(struct Forward *fwd, int cport, struct ForwardOptions *fwd_opts) |
|
{ |
|
if (fwd->listen_path != NULL) |
|
return channel_cancel_lport_listener_streamlocal(fwd->listen_path); |
|
else |
|
return channel_cancel_lport_listener_tcpip(fwd->listen_host, fwd->listen_port, cport, fwd_opts); |
|
} |
|
|
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
/* protocol local port fwd, used by ssh (and sshd in v1) */ |
int |
int |
channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, |
channel_setup_local_fwd_listener(struct Forward *fwd, struct ForwardOptions *fwd_opts) |
const char *host_to_connect, u_short port_to_connect, int gateway_ports) |
|
{ |
{ |
return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, |
if (fwd->listen_path != NULL) { |
listen_host, listen_port, NULL, host_to_connect, port_to_connect, |
return channel_setup_fwd_listener_streamlocal( |
gateway_ports); |
SSH_CHANNEL_UNIX_LISTENER, fwd, fwd_opts); |
|
} else { |
|
return channel_setup_fwd_listener_tcpip(SSH_CHANNEL_PORT_LISTENER, |
|
fwd, NULL, fwd_opts); |
|
} |
} |
} |
|
|
/* protocol v2 remote port fwd, used by sshd */ |
/* protocol v2 remote port fwd, used by sshd */ |
int |
int |
channel_setup_remote_fwd_listener(const char *listen_address, |
channel_setup_remote_fwd_listener(struct Forward *fwd, |
u_short listen_port, int *allocated_listen_port, int gateway_ports) |
int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
{ |
{ |
return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, |
if (fwd->listen_path != NULL) { |
listen_address, listen_port, allocated_listen_port, |
return channel_setup_fwd_listener_streamlocal( |
NULL, 0, gateway_ports); |
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); |
|
} else { |
|
return channel_setup_fwd_listener_tcpip( |
|
SSH_CHANNEL_RPORT_LISTENER, fwd, allocated_listen_port, |
|
fwd_opts); |
|
} |
} |
} |
|
|
/* |
/* |
|
|
* channel_update_permitted_opens(). |
* channel_update_permitted_opens(). |
*/ |
*/ |
int |
int |
channel_request_remote_forwarding(const char *listen_host, u_short listen_port, |
channel_request_remote_forwarding(struct Forward *fwd) |
const char *host_to_connect, u_short port_to_connect) |
|
{ |
{ |
int type, success = 0, idx = -1; |
int type, success = 0, idx = -1; |
|
|
/* Send the forward request to the remote side. */ |
/* Send the forward request to the remote side. */ |
if (compat20) { |
if (compat20) { |
packet_start(SSH2_MSG_GLOBAL_REQUEST); |
packet_start(SSH2_MSG_GLOBAL_REQUEST); |
packet_put_cstring("tcpip-forward"); |
if (fwd->listen_path != NULL) { |
packet_put_char(1); /* boolean: want reply */ |
packet_put_cstring("streamlocal-forward@openssh.com"); |
packet_put_cstring(channel_rfwd_bind_host(listen_host)); |
packet_put_char(1); /* boolean: want reply */ |
packet_put_int(listen_port); |
packet_put_cstring(fwd->listen_path); |
|
} else { |
|
packet_put_cstring("tcpip-forward"); |
|
packet_put_char(1); /* boolean: want reply */ |
|
packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host)); |
|
packet_put_int(fwd->listen_port); |
|
} |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
/* Assume that server accepts the request */ |
/* Assume that server accepts the request */ |
success = 1; |
success = 1; |
} else { |
} else if (fwd->listen_path == NULL) { |
packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); |
packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); |
packet_put_int(listen_port); |
packet_put_int(fwd->listen_port); |
packet_put_cstring(host_to_connect); |
packet_put_cstring(fwd->connect_host); |
packet_put_int(port_to_connect); |
packet_put_int(fwd->connect_port); |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
|
|
|
|
packet_disconnect("Protocol error for port forward request:" |
packet_disconnect("Protocol error for port forward request:" |
"received packet type %d.", type); |
"received packet type %d.", type); |
} |
} |
|
} else { |
|
logit("Warning: Server does not support remote stream local forwarding."); |
} |
} |
if (success) { |
if (success) { |
/* Record that connection to this host/port is permitted. */ |
/* Record that connection to this host/port is permitted. */ |
permitted_opens = xrealloc(permitted_opens, |
permitted_opens = xrealloc(permitted_opens, |
num_permitted_opens + 1, sizeof(*permitted_opens)); |
num_permitted_opens + 1, sizeof(*permitted_opens)); |
idx = num_permitted_opens++; |
idx = num_permitted_opens++; |
permitted_opens[idx].host_to_connect = xstrdup(host_to_connect); |
if (fwd->connect_path != NULL) { |
permitted_opens[idx].port_to_connect = port_to_connect; |
permitted_opens[idx].host_to_connect = |
permitted_opens[idx].listen_host = listen_host ? |
xstrdup(fwd->connect_path); |
xstrdup(listen_host) : NULL; |
permitted_opens[idx].port_to_connect = |
permitted_opens[idx].listen_port = listen_port; |
PORT_STREAMLOCAL; |
|
} else { |
|
permitted_opens[idx].host_to_connect = |
|
xstrdup(fwd->connect_host); |
|
permitted_opens[idx].port_to_connect = |
|
fwd->connect_port; |
|
} |
|
if (fwd->listen_path != NULL) { |
|
permitted_opens[idx].listen_host = NULL; |
|
permitted_opens[idx].listen_path = |
|
xstrdup(fwd->listen_path); |
|
permitted_opens[idx].listen_port = PORT_STREAMLOCAL; |
|
} else { |
|
permitted_opens[idx].listen_host = |
|
fwd->listen_host ? xstrdup(fwd->listen_host) : NULL; |
|
permitted_opens[idx].listen_path = NULL; |
|
permitted_opens[idx].listen_port = fwd->listen_port; |
|
} |
} |
} |
return (idx); |
return (idx); |
} |
} |
|
|
static int |
static int |
open_match(ForwardPermission *allowed_open, const char *requestedhost, |
open_match(ForwardPermission *allowed_open, const char *requestedhost, |
u_short requestedport) |
int requestedport) |
{ |
{ |
if (allowed_open->host_to_connect == NULL) |
if (allowed_open->host_to_connect == NULL) |
return 0; |
return 0; |
|
|
} |
} |
|
|
/* |
/* |
* Note that in he listen host/port case |
* Note that in the listen host/port case |
* we don't support FWD_PERMIT_ANY_PORT and |
* we don't support FWD_PERMIT_ANY_PORT and |
* need to translate between the configured-host (listen_host) |
* need to translate between the configured-host (listen_host) |
* and what we've sent to the remote server (channel_rfwd_bind_host) |
* and what we've sent to the remote server (channel_rfwd_bind_host) |
*/ |
*/ |
static int |
static int |
open_listen_match(ForwardPermission *allowed_open, const char *requestedhost, |
open_listen_match_tcpip(ForwardPermission *allowed_open, |
u_short requestedport, int translate) |
const char *requestedhost, u_short requestedport, int translate) |
{ |
{ |
const char *allowed_host; |
const char *allowed_host; |
|
|
|
|
return 1; |
return 1; |
} |
} |
|
|
|
static int |
|
open_listen_match_streamlocal(ForwardPermission *allowed_open, |
|
const char *requestedpath) |
|
{ |
|
if (allowed_open->host_to_connect == NULL) |
|
return 0; |
|
if (allowed_open->listen_port != PORT_STREAMLOCAL) |
|
return 0; |
|
if (allowed_open->listen_path == NULL || |
|
strcmp(allowed_open->listen_path, requestedpath) != 0) |
|
return 0; |
|
return 1; |
|
} |
|
|
/* |
/* |
* Request cancellation of remote forwarding of connection host:port from |
* Request cancellation of remote forwarding of connection host:port from |
* local side. |
* local side. |
*/ |
*/ |
int |
static int |
channel_request_rforward_cancel(const char *host, u_short port) |
channel_request_rforward_cancel_tcpip(const char *host, u_short port) |
{ |
{ |
int i; |
int i; |
|
|
|
|
return -1; |
return -1; |
|
|
for (i = 0; i < num_permitted_opens; i++) { |
for (i = 0; i < num_permitted_opens; i++) { |
if (open_listen_match(&permitted_opens[i], host, port, 0)) |
if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0)) |
break; |
break; |
} |
} |
if (i >= num_permitted_opens) { |
if (i >= num_permitted_opens) { |
|
|
packet_put_int(port); |
packet_put_int(port); |
packet_send(); |
packet_send(); |
|
|
permitted_opens[i].port_to_connect = 0; |
|
permitted_opens[i].listen_port = 0; |
permitted_opens[i].listen_port = 0; |
|
permitted_opens[i].port_to_connect = 0; |
free(permitted_opens[i].host_to_connect); |
free(permitted_opens[i].host_to_connect); |
permitted_opens[i].host_to_connect = NULL; |
permitted_opens[i].host_to_connect = NULL; |
free(permitted_opens[i].listen_host); |
free(permitted_opens[i].listen_host); |
permitted_opens[i].listen_host = NULL; |
permitted_opens[i].listen_host = NULL; |
|
permitted_opens[i].listen_path = NULL; |
|
|
return 0; |
return 0; |
} |
} |
|
|
/* |
/* |
|
* Request cancellation of remote forwarding of Unix domain socket |
|
* path from local side. |
|
*/ |
|
static int |
|
channel_request_rforward_cancel_streamlocal(const char *path) |
|
{ |
|
int i; |
|
|
|
if (!compat20) |
|
return -1; |
|
|
|
for (i = 0; i < num_permitted_opens; i++) { |
|
if (open_listen_match_streamlocal(&permitted_opens[i], path)) |
|
break; |
|
} |
|
if (i >= num_permitted_opens) { |
|
debug("%s: requested forward not found", __func__); |
|
return -1; |
|
} |
|
packet_start(SSH2_MSG_GLOBAL_REQUEST); |
|
packet_put_cstring("cancel-streamlocal-forward@openssh.com"); |
|
packet_put_char(0); |
|
packet_put_cstring(path); |
|
packet_send(); |
|
|
|
permitted_opens[i].listen_port = 0; |
|
permitted_opens[i].port_to_connect = 0; |
|
free(permitted_opens[i].host_to_connect); |
|
permitted_opens[i].host_to_connect = NULL; |
|
permitted_opens[i].listen_host = NULL; |
|
free(permitted_opens[i].listen_path); |
|
permitted_opens[i].listen_path = NULL; |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* Request cancellation of remote forwarding of a connection from local side. |
|
*/ |
|
int |
|
channel_request_rforward_cancel(struct Forward *fwd) |
|
{ |
|
if (fwd->listen_path != NULL) { |
|
return (channel_request_rforward_cancel_streamlocal( |
|
fwd->listen_path)); |
|
} else { |
|
return (channel_request_rforward_cancel_tcpip(fwd->listen_host, |
|
fwd->listen_port ? fwd->listen_port : fwd->allocated_port)); |
|
} |
|
} |
|
|
|
/* |
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates |
* listening for the port, and sends back a success reply (or disconnect |
* listening for the port, and sends back a success reply (or disconnect |
* message if there was an error). |
* message if there was an error). |
*/ |
*/ |
int |
int |
channel_input_port_forward_request(int is_root, int gateway_ports) |
channel_input_port_forward_request(int is_root, struct ForwardOptions *fwd_opts) |
{ |
{ |
u_short port, host_port; |
|
int success = 0; |
int success = 0; |
char *hostname; |
struct Forward fwd; |
|
|
/* Get arguments from the packet. */ |
/* Get arguments from the packet. */ |
port = packet_get_int(); |
memset(&fwd, 0, sizeof(fwd)); |
hostname = packet_get_string(NULL); |
fwd.listen_port = packet_get_int(); |
host_port = packet_get_int(); |
fwd.connect_host = packet_get_string(NULL); |
|
fwd.connect_port = packet_get_int(); |
|
|
/* |
/* |
* Check that an unprivileged user is not trying to forward a |
* Check that an unprivileged user is not trying to forward a |
* privileged port. |
* privileged port. |
*/ |
*/ |
if (port < IPPORT_RESERVED && !is_root) |
if (fwd.listen_port < IPPORT_RESERVED && !is_root) |
packet_disconnect( |
packet_disconnect( |
"Requested forwarding of port %d but user is not root.", |
"Requested forwarding of port %d but user is not root.", |
port); |
fwd.listen_port); |
if (host_port == 0) |
if (fwd.connect_port == 0) |
packet_disconnect("Dynamic forwarding denied."); |
packet_disconnect("Dynamic forwarding denied."); |
|
|
/* Initiate forwarding */ |
/* Initiate forwarding */ |
success = channel_setup_local_fwd_listener(NULL, port, hostname, |
success = channel_setup_local_fwd_listener(&fwd, fwd_opts); |
host_port, gateway_ports); |
|
|
|
/* Free the argument string. */ |
/* Free the argument string. */ |
free(hostname); |
free(fwd.connect_host); |
|
|
return (success ? 0 : -1); |
return (success ? 0 : -1); |
} |
} |
|
|
permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); |
permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); |
permitted_opens[num_permitted_opens].port_to_connect = port; |
permitted_opens[num_permitted_opens].port_to_connect = port; |
permitted_opens[num_permitted_opens].listen_host = NULL; |
permitted_opens[num_permitted_opens].listen_host = NULL; |
|
permitted_opens[num_permitted_opens].listen_path = NULL; |
permitted_opens[num_permitted_opens].listen_port = 0; |
permitted_opens[num_permitted_opens].listen_port = 0; |
num_permitted_opens++; |
num_permitted_opens++; |
|
|
|
|
permitted_opens[idx].host_to_connect = NULL; |
permitted_opens[idx].host_to_connect = NULL; |
free(permitted_opens[idx].listen_host); |
free(permitted_opens[idx].listen_host); |
permitted_opens[idx].listen_host = NULL; |
permitted_opens[idx].listen_host = NULL; |
|
free(permitted_opens[idx].listen_path); |
|
permitted_opens[idx].listen_path = NULL; |
} |
} |
} |
} |
|
|
|
|
= xstrdup(host); |
= xstrdup(host); |
permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; |
permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; |
permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; |
permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; |
|
permitted_adm_opens[num_adm_permitted_opens].listen_path = NULL; |
permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; |
permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; |
return ++num_adm_permitted_opens; |
return ++num_adm_permitted_opens; |
} |
} |
|
|
for (i = 0; i < num_permitted_opens; i++) { |
for (i = 0; i < num_permitted_opens; i++) { |
free(permitted_opens[i].host_to_connect); |
free(permitted_opens[i].host_to_connect); |
free(permitted_opens[i].listen_host); |
free(permitted_opens[i].listen_host); |
|
free(permitted_opens[i].listen_path); |
} |
} |
free(permitted_opens); |
free(permitted_opens); |
permitted_opens = NULL; |
permitted_opens = NULL; |
|
|
for (i = 0; i < num_adm_permitted_opens; i++) { |
for (i = 0; i < num_adm_permitted_opens; i++) { |
free(permitted_adm_opens[i].host_to_connect); |
free(permitted_adm_opens[i].host_to_connect); |
free(permitted_adm_opens[i].listen_host); |
free(permitted_adm_opens[i].listen_host); |
|
free(permitted_adm_opens[i].listen_path); |
} |
} |
free(permitted_adm_opens); |
free(permitted_adm_opens); |
permitted_adm_opens = NULL; |
permitted_adm_opens = NULL; |
|
|
connect_next(struct channel_connect *cctx) |
connect_next(struct channel_connect *cctx) |
{ |
{ |
int sock, saved_errno; |
int sock, saved_errno; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
struct sockaddr_un *sunaddr; |
|
char ntop[NI_MAXHOST], strport[MAX(NI_MAXSERV,sizeof(sunaddr->sun_path))]; |
|
|
for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { |
for (; cctx->ai; cctx->ai = cctx->ai->ai_next) { |
if (cctx->ai->ai_family != AF_INET && |
switch (cctx->ai->ai_family) { |
cctx->ai->ai_family != AF_INET6) |
case AF_UNIX: |
|
/* unix:pathname instead of host:port */ |
|
sunaddr = (struct sockaddr_un *)cctx->ai->ai_addr; |
|
strlcpy(ntop, "unix", sizeof(ntop)); |
|
strlcpy(strport, sunaddr->sun_path, sizeof(strport)); |
|
break; |
|
case AF_INET: |
|
case AF_INET6: |
|
if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, |
|
ntop, sizeof(ntop), strport, sizeof(strport), |
|
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
|
error("connect_next: getnameinfo failed"); |
|
continue; |
|
} |
|
break; |
|
default: |
continue; |
continue; |
if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen, |
|
ntop, sizeof(ntop), strport, sizeof(strport), |
|
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
|
error("connect_next: getnameinfo failed"); |
|
continue; |
|
} |
} |
if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, |
if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, |
cctx->ai->ai_protocol)) == -1) { |
cctx->ai->ai_protocol)) == -1) { |
|
|
errno = saved_errno; |
errno = saved_errno; |
continue; /* fail -- try next */ |
continue; /* fail -- try next */ |
} |
} |
|
if (cctx->ai->ai_family != AF_UNIX) |
|
set_nodelay(sock); |
debug("connect_next: host %.100s ([%.100s]:%s) " |
debug("connect_next: host %.100s ([%.100s]:%s) " |
"in progress, fd=%d", cctx->host, ntop, strport, sock); |
"in progress, fd=%d", cctx->host, ntop, strport, sock); |
cctx->ai = cctx->ai->ai_next; |
cctx->ai = cctx->ai->ai_next; |
set_nodelay(sock); |
|
return sock; |
return sock; |
} |
} |
return -1; |
return -1; |
|
|
channel_connect_ctx_free(struct channel_connect *cctx) |
channel_connect_ctx_free(struct channel_connect *cctx) |
{ |
{ |
free(cctx->host); |
free(cctx->host); |
if (cctx->aitop) |
if (cctx->aitop) { |
freeaddrinfo(cctx->aitop); |
if (cctx->aitop->ai_family == AF_UNIX) |
|
free(cctx->aitop); |
|
else |
|
freeaddrinfo(cctx->aitop); |
|
} |
memset(cctx, 0, sizeof(*cctx)); |
memset(cctx, 0, sizeof(*cctx)); |
} |
} |
|
|
/* Return CONNECTING channel to remote host, port */ |
/* Return CONNECTING channel to remote host:port or local socket path */ |
static Channel * |
static Channel * |
connect_to(const char *host, u_short port, char *ctype, char *rname) |
connect_to(const char *name, int port, char *ctype, char *rname) |
{ |
{ |
struct addrinfo hints; |
struct addrinfo hints; |
int gaierr; |
int gaierr; |
|
|
Channel *c; |
Channel *c; |
|
|
memset(&cctx, 0, sizeof(cctx)); |
memset(&cctx, 0, sizeof(cctx)); |
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = IPv4or6; |
if (port == PORT_STREAMLOCAL) { |
hints.ai_socktype = SOCK_STREAM; |
struct sockaddr_un *sunaddr; |
snprintf(strport, sizeof strport, "%d", port); |
struct addrinfo *ai; |
if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) { |
|
error("connect_to %.100s: unknown host (%s)", host, |
if (strlen(name) > sizeof(sunaddr->sun_path)) { |
ssh_gai_strerror(gaierr)); |
error("%.100s: %.100s", name, strerror(ENAMETOOLONG)); |
return NULL; |
return (NULL); |
|
} |
|
|
|
/* |
|
* Fake up a struct addrinfo for AF_UNIX connections. |
|
* channel_connect_ctx_free() must check ai_family |
|
* and use free() not freeaddirinfo() for AF_UNIX. |
|
*/ |
|
ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr)); |
|
memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr)); |
|
ai->ai_addr = (struct sockaddr *)(ai + 1); |
|
ai->ai_addrlen = sizeof(*sunaddr); |
|
ai->ai_family = AF_UNIX; |
|
ai->ai_socktype = SOCK_STREAM; |
|
ai->ai_protocol = PF_UNSPEC; |
|
sunaddr = (struct sockaddr_un *)ai->ai_addr; |
|
sunaddr->sun_family = AF_UNIX; |
|
strlcpy(sunaddr->sun_path, name, sizeof(sunaddr->sun_path)); |
|
cctx.aitop = ai; |
|
} else { |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = IPv4or6; |
|
hints.ai_socktype = SOCK_STREAM; |
|
snprintf(strport, sizeof strport, "%d", port); |
|
if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) { |
|
error("connect_to %.100s: unknown host (%s)", name, |
|
ssh_gai_strerror(gaierr)); |
|
return NULL; |
|
} |
} |
} |
|
|
cctx.host = xstrdup(host); |
cctx.host = xstrdup(name); |
cctx.port = port; |
cctx.port = port; |
cctx.ai = cctx.aitop; |
cctx.ai = cctx.aitop; |
|
|
if ((sock = connect_next(&cctx)) == -1) { |
if ((sock = connect_next(&cctx)) == -1) { |
error("connect to %.100s port %d failed: %s", |
error("connect to %.100s port %d failed: %s", |
host, port, strerror(errno)); |
name, port, strerror(errno)); |
channel_connect_ctx_free(&cctx); |
channel_connect_ctx_free(&cctx); |
return NULL; |
return NULL; |
} |
} |
|
|
int i; |
int i; |
|
|
for (i = 0; i < num_permitted_opens; i++) { |
for (i = 0; i < num_permitted_opens; i++) { |
if (open_listen_match(&permitted_opens[i], listen_host, |
if (open_listen_match_tcpip(&permitted_opens[i], listen_host, |
listen_port, 1)) { |
listen_port, 1)) { |
return connect_to( |
return connect_to( |
permitted_opens[i].host_to_connect, |
permitted_opens[i].host_to_connect, |
|
|
return NULL; |
return NULL; |
} |
} |
|
|
|
Channel * |
|
channel_connect_by_listen_path(const char *path, char *ctype, char *rname) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < num_permitted_opens; i++) { |
|
if (open_listen_match_streamlocal(&permitted_opens[i], path)) { |
|
return connect_to( |
|
permitted_opens[i].host_to_connect, |
|
permitted_opens[i].port_to_connect, ctype, rname); |
|
} |
|
} |
|
error("WARNING: Server requests forwarding for unknown path %.100s", |
|
path); |
|
return NULL; |
|
} |
|
|
/* Check if connecting to that port is permitted and connect. */ |
/* Check if connecting to that port is permitted and connect. */ |
Channel * |
Channel * |
channel_connect_to(const char *host, u_short port, char *ctype, char *rname) |
channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname) |
{ |
{ |
int i, permit, permit_adm = 1; |
int i, permit, permit_adm = 1; |
|
|
|
|
return NULL; |
return NULL; |
} |
} |
return connect_to(host, port, ctype, rname); |
return connect_to(host, port, ctype, rname); |
|
} |
|
|
|
/* Check if connecting to that path is permitted and connect. */ |
|
Channel * |
|
channel_connect_to_path(const char *path, char *ctype, char *rname) |
|
{ |
|
int i, permit, permit_adm = 1; |
|
|
|
permit = all_opens_permitted; |
|
if (!permit) { |
|
for (i = 0; i < num_permitted_opens; i++) |
|
if (open_match(&permitted_opens[i], path, PORT_STREAMLOCAL)) { |
|
permit = 1; |
|
break; |
|
} |
|
} |
|
|
|
if (num_adm_permitted_opens > 0) { |
|
permit_adm = 0; |
|
for (i = 0; i < num_adm_permitted_opens; i++) |
|
if (open_match(&permitted_adm_opens[i], path, PORT_STREAMLOCAL)) { |
|
permit_adm = 1; |
|
break; |
|
} |
|
} |
|
|
|
if (!permit || !permit_adm) { |
|
logit("Received request to connect to path %.100s, " |
|
"but the request was denied.", path); |
|
return NULL; |
|
} |
|
return connect_to(path, PORT_STREAMLOCAL, ctype, rname); |
} |
} |
|
|
void |
void |