version 1.380, 2018/04/10 00:10:49 |
version 1.381, 2018/06/06 18:22:41 |
|
|
#include "key.h" |
#include "key.h" |
#include "authfd.h" |
#include "authfd.h" |
#include "pathnames.h" |
#include "pathnames.h" |
|
#include "match.h" |
|
|
/* -- agent forwarding */ |
/* -- agent forwarding */ |
#define NUM_SOCKS 10 |
#define NUM_SOCKS 10 |
|
|
/* Maximum number of fake X11 displays to try. */ |
/* Maximum number of fake X11 displays to try. */ |
#define MAX_DISPLAYS 1000 |
#define MAX_DISPLAYS 1000 |
|
|
|
/* Per-channel callback for pre/post select() actions */ |
|
typedef void chan_fn(struct ssh *, Channel *c, |
|
fd_set *readset, fd_set *writeset); |
|
|
/* |
/* |
* Data structure for storing which hosts are permitted for forward requests. |
* Data structure for storing which hosts are permitted for forward requests. |
* The local sides of any remote forwards are stored in this array to prevent |
* The local sides of any remote forwards are stored in this array to prevent |
|
|
/* XXX: streamlocal wants a path instead of host:port */ |
/* XXX: streamlocal wants a path instead of host:port */ |
/* Overload host_to_connect; we could just make this match Forward */ |
/* Overload host_to_connect; we could just make this match Forward */ |
/* XXX - can we use listen_host instead of listen_path? */ |
/* XXX - can we use listen_host instead of listen_path? */ |
typedef struct { |
struct permission { |
char *host_to_connect; /* Connect to 'host'. */ |
char *host_to_connect; /* Connect to 'host'. */ |
int 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. */ |
char *listen_path; /* Remote side should listen path. */ |
char *listen_path; /* Remote side should listen path. */ |
int listen_port; /* Remote side should listen port. */ |
int listen_port; /* Remote side should listen port. */ |
Channel *downstream; /* Downstream mux*/ |
Channel *downstream; /* Downstream mux*/ |
} ForwardPermission; |
}; |
|
|
typedef void chan_fn(struct ssh *, Channel *c, |
/* |
fd_set *readset, fd_set *writeset); |
* Stores the forwarding permission state for a single direction (local or |
|
* remote). |
|
*/ |
|
struct permission_set { |
|
/* |
|
* List of all local permitted host/port pairs to allow for the |
|
* user. |
|
*/ |
|
u_int num_permitted_user; |
|
struct permission *permitted_user; |
|
|
|
/* |
|
* List of all permitted host/port pairs to allow for the admin. |
|
*/ |
|
u_int num_permitted_admin; |
|
struct permission *permitted_admin; |
|
|
|
/* |
|
* If this is true, all opens/listens are permitted. This is the |
|
* case on the server on which we have to trust the client anyway, |
|
* and the user could do anything after logging in. |
|
*/ |
|
int all_permitted; |
|
}; |
|
|
/* Master structure for channels state */ |
/* Master structure for channels state */ |
struct ssh_channels { |
struct ssh_channels { |
/* |
/* |
|
|
chan_fn **channel_post; |
chan_fn **channel_post; |
|
|
/* -- tcp forwarding */ |
/* -- tcp forwarding */ |
|
struct permission_set local_perms; |
|
struct permission_set remote_perms; |
|
|
/* List of all permitted host/port pairs to connect by the user. */ |
|
ForwardPermission *permitted_opens; |
|
|
|
/* List of all permitted host/port pairs to connect by the admin. */ |
|
ForwardPermission *permitted_adm_opens; |
|
|
|
/* |
|
* Number of permitted host/port pairs in the array permitted by |
|
* the user. |
|
*/ |
|
u_int num_permitted_opens; |
|
|
|
/* |
|
* Number of permitted host/port pair in the array permitted by |
|
* the admin. |
|
*/ |
|
u_int num_adm_permitted_opens; |
|
|
|
/* |
|
* If this is true, all opens are permitted. This is the case on |
|
* the server on which we have to trust the client anyway, and the |
|
* user could do anything after logging in anyway. |
|
*/ |
|
int all_opens_permitted; |
|
|
|
/* -- X11 forwarding */ |
/* -- X11 forwarding */ |
|
|
/* Saved X11 local (client) display. */ |
/* Saved X11 local (client) display. */ |
|
|
} |
} |
|
|
static void |
static void |
fwd_perm_clear(ForwardPermission *fp) |
fwd_perm_clear(struct permission *perm) |
{ |
{ |
free(fp->host_to_connect); |
free(perm->host_to_connect); |
free(fp->listen_host); |
free(perm->listen_host); |
free(fp->listen_path); |
free(perm->listen_path); |
bzero(fp, sizeof(*fp)); |
bzero(perm, sizeof(*perm)); |
} |
} |
|
|
enum { FWDPERM_USER, FWDPERM_ADMIN }; |
/* Returns an printable name for the specified forwarding permission list */ |
|
static const char * |
|
fwd_ident(int who, int where) |
|
{ |
|
if (who == FORWARD_ADM) { |
|
if (where == FORWARD_LOCAL) |
|
return "admin local"; |
|
else if (where == FORWARD_REMOTE) |
|
return "admin remote"; |
|
} else if (who == FORWARD_USER) { |
|
if (where == FORWARD_LOCAL) |
|
return "user local"; |
|
else if (where == FORWARD_REMOTE) |
|
return "user remote"; |
|
} |
|
fatal("Unknown forward permission list %d/%d", who, where); |
|
} |
|
|
static int |
/* Returns the forwarding permission list for the specified direction */ |
fwd_perm_list_add(struct ssh *ssh, int which, |
static struct permission_set * |
const char *host_to_connect, int port_to_connect, |
permission_set_get(struct ssh *ssh, int where) |
const char *listen_host, const char *listen_path, int listen_port, |
|
Channel *downstream) |
|
{ |
{ |
ForwardPermission **fpl; |
struct ssh_channels *sc = ssh->chanctxt; |
u_int n, *nfpl; |
|
|
|
switch (which) { |
switch (where) { |
case FWDPERM_USER: |
case FORWARD_LOCAL: |
fpl = &ssh->chanctxt->permitted_opens; |
return &sc->local_perms; |
nfpl = &ssh->chanctxt->num_permitted_opens; |
|
break; |
break; |
case FWDPERM_ADMIN: |
case FORWARD_REMOTE: |
fpl = &ssh->chanctxt->permitted_adm_opens; |
return &sc->remote_perms; |
nfpl = &ssh->chanctxt->num_adm_permitted_opens; |
|
break; |
break; |
default: |
default: |
fatal("%s: invalid list %d", __func__, which); |
fatal("%s: invalid forwarding direction %d", __func__, where); |
} |
} |
|
} |
|
|
if (*nfpl >= INT_MAX) |
/* Reutrns pointers to the specified forwarding list and its element count */ |
fatal("%s: overflow", __func__); |
static void |
|
permission_set_get_array(struct ssh *ssh, int who, int where, |
|
struct permission ***permpp, u_int **npermpp) |
|
{ |
|
struct permission_set *pset = permission_set_get(ssh, where); |
|
|
*fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl)); |
switch (who) { |
n = (*nfpl)++; |
case FORWARD_USER: |
|
*permpp = &pset->permitted_user; |
|
*npermpp = &pset->num_permitted_user; |
|
break; |
|
case FORWARD_ADM: |
|
*permpp = &pset->permitted_admin; |
|
*npermpp = &pset->num_permitted_admin; |
|
break; |
|
default: |
|
fatal("%s: invalid forwarding client %d", __func__, who); |
|
} |
|
} |
|
|
|
/* Adds an entry to the spcified forwarding list */ |
|
static int |
|
permission_set_add(struct ssh *ssh, int who, int where, |
|
const char *host_to_connect, int port_to_connect, |
|
const char *listen_host, const char *listen_path, int listen_port, |
|
Channel *downstream) |
|
{ |
|
struct permission **permp; |
|
u_int n, *npermp; |
|
|
|
permission_set_get_array(ssh, who, where, &permp, &npermp); |
|
|
|
if (*npermp >= INT_MAX) |
|
fatal("%s: %s overflow", __func__, fwd_ident(who, where)); |
|
|
|
*permp = xrecallocarray(*permp, *npermp, *npermp + 1, sizeof(**permp)); |
|
n = (*npermp)++; |
#define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) |
#define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) |
(*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect); |
(*permp)[n].host_to_connect = MAYBE_DUP(host_to_connect); |
(*fpl)[n].port_to_connect = port_to_connect; |
(*permp)[n].port_to_connect = port_to_connect; |
(*fpl)[n].listen_host = MAYBE_DUP(listen_host); |
(*permp)[n].listen_host = MAYBE_DUP(listen_host); |
(*fpl)[n].listen_path = MAYBE_DUP(listen_path); |
(*permp)[n].listen_path = MAYBE_DUP(listen_path); |
(*fpl)[n].listen_port = listen_port; |
(*permp)[n].listen_port = listen_port; |
(*fpl)[n].downstream = downstream; |
(*permp)[n].downstream = downstream; |
#undef MAYBE_DUP |
#undef MAYBE_DUP |
return (int)n; |
return (int)n; |
} |
} |
|
|
mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) |
mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
ForwardPermission *fp; |
struct permission_set *pset = &sc->local_perms; |
|
struct permission *perm; |
int r; |
int r; |
u_int i; |
u_int i; |
|
|
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (fp->downstream != c) |
if (perm->downstream != c) |
continue; |
continue; |
|
|
/* cancel on the server, since mux client is gone */ |
/* cancel on the server, since mux client is gone */ |
debug("channel %d: cleanup remote forward for %s:%u", |
debug("channel %d: cleanup remote forward for %s:%u", |
c->self, fp->listen_host, fp->listen_port); |
c->self, perm->listen_host, perm->listen_port); |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
(r = sshpkt_put_cstring(ssh, |
(r = sshpkt_put_cstring(ssh, |
"cancel-tcpip-forward")) != 0 || |
"cancel-tcpip-forward")) != 0 || |
(r = sshpkt_put_u8(ssh, 0)) != 0 || |
(r = sshpkt_put_u8(ssh, 0)) != 0 || |
(r = sshpkt_put_cstring(ssh, |
(r = sshpkt_put_cstring(ssh, |
channel_rfwd_bind_host(fp->listen_host))) != 0 || |
channel_rfwd_bind_host(perm->listen_host))) != 0 || |
(r = sshpkt_put_u32(ssh, fp->listen_port)) != 0 || |
(r = sshpkt_put_u32(ssh, perm->listen_port)) != 0 || |
(r = sshpkt_send(ssh)) != 0) { |
(r = sshpkt_send(ssh)) != 0) { |
fatal("%s: channel %i: %s", __func__, |
fatal("%s: channel %i: %s", __func__, |
c->self, ssh_err(r)); |
c->self, ssh_err(r)); |
} |
} |
fwd_perm_clear(fp); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
} |
} |
} |
} |
|
|
|
|
goto out; |
goto out; |
} |
} |
/* Record that connection to this host/port is permitted. */ |
/* Record that connection to this host/port is permitted. */ |
fwd_perm_list_add(ssh, FWDPERM_USER, "<mux>", -1, |
permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL, "<mux>", -1, |
listen_host, NULL, (int)listen_port, downstream); |
listen_host, NULL, (int)listen_port, downstream); |
listen_host = NULL; |
listen_host = NULL; |
break; |
break; |
|
|
} |
} |
} |
} |
|
|
|
/* Matches a remote forwarding permission against a requested forwarding */ |
|
static int |
|
remote_open_match(struct permission *allowed_open, struct Forward *fwd) |
|
{ |
|
int ret; |
|
char *lhost; |
|
|
|
/* XXX add ACLs for streamlocal */ |
|
if (fwd->listen_path != NULL) |
|
return 1; |
|
|
|
if (fwd->listen_host == NULL || allowed_open->listen_host == NULL) |
|
return 0; |
|
|
|
if (allowed_open->listen_port != FWD_PERMIT_ANY_PORT && |
|
allowed_open->listen_port != fwd->listen_port) |
|
return 0; |
|
|
|
/* Match hostnames case-insensitively */ |
|
lhost = xstrdup(fwd->listen_host); |
|
lowercase(lhost); |
|
ret = match_pattern(lhost, allowed_open->listen_host); |
|
free(lhost); |
|
|
|
return ret; |
|
} |
|
|
|
/* Checks whether a requested remote forwarding is permitted */ |
|
static int |
|
check_rfwd_permission(struct ssh *ssh, struct Forward *fwd) |
|
{ |
|
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->remote_perms; |
|
u_int i, permit, permit_adm = 1; |
|
struct permission *perm; |
|
|
|
/* XXX apply GatewayPorts override before checking? */ |
|
|
|
permit = pset->all_permitted; |
|
if (!permit) { |
|
for (i = 0; i < pset->num_permitted_user; i++) { |
|
perm = &pset->permitted_user[i]; |
|
if (remote_open_match(perm, fwd)) { |
|
permit = 1; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (pset->num_permitted_admin > 0) { |
|
permit_adm = 0; |
|
for (i = 0; i < pset->num_permitted_admin; i++) { |
|
perm = &pset->permitted_admin[i]; |
|
if (remote_open_match(perm, fwd)) { |
|
permit_adm = 1; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return permit && permit_adm; |
|
} |
|
|
/* protocol v2 remote port fwd, used by sshd */ |
/* protocol v2 remote port fwd, used by sshd */ |
int |
int |
channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, |
channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, |
int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
int *allocated_listen_port, struct ForwardOptions *fwd_opts) |
{ |
{ |
|
if (!check_rfwd_permission(ssh, fwd)) { |
|
packet_send_debug("port forwarding refused"); |
|
return 0; |
|
} |
if (fwd->listen_path != NULL) { |
if (fwd->listen_path != NULL) { |
return channel_setup_fwd_listener_streamlocal(ssh, |
return channel_setup_fwd_listener_streamlocal(ssh, |
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); |
SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); |
|
|
* Initiate forwarding of connections to port "port" on remote host through |
* Initiate forwarding of connections to port "port" on remote host through |
* the secure channel to host:port from local side. |
* the secure channel to host:port from local side. |
* Returns handle (index) for updating the dynamic listen port with |
* Returns handle (index) for updating the dynamic listen port with |
* channel_update_permitted_opens(). |
* channel_update_permission(). |
*/ |
*/ |
int |
int |
channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) |
channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) |
|
|
listen_host = xstrdup(fwd->listen_host); |
listen_host = xstrdup(fwd->listen_host); |
listen_port = fwd->listen_port; |
listen_port = fwd->listen_port; |
} |
} |
idx = fwd_perm_list_add(ssh, FWDPERM_USER, |
idx = permission_set_add(ssh, FORWARD_USER, FORWARD_LOCAL, |
host_to_connect, port_to_connect, |
host_to_connect, port_to_connect, |
listen_host, listen_path, listen_port, NULL); |
listen_host, listen_path, listen_port, NULL); |
} |
} |
|
|
} |
} |
|
|
static int |
static int |
open_match(ForwardPermission *allowed_open, const char *requestedhost, |
open_match(struct permission *allowed_open, const char *requestedhost, |
int requestedport) |
int requestedport) |
{ |
{ |
if (allowed_open->host_to_connect == NULL) |
if (allowed_open->host_to_connect == NULL) |
|
|
* 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_tcpip(ForwardPermission *allowed_open, |
open_listen_match_tcpip(struct permission *allowed_open, |
const char *requestedhost, u_short requestedport, int translate) |
const char *requestedhost, u_short requestedport, int translate) |
{ |
{ |
const char *allowed_host; |
const char *allowed_host; |
|
|
} |
} |
|
|
static int |
static int |
open_listen_match_streamlocal(ForwardPermission *allowed_open, |
open_listen_match_streamlocal(struct permission *allowed_open, |
const char *requestedpath) |
const char *requestedpath) |
{ |
{ |
if (allowed_open->host_to_connect == NULL) |
if (allowed_open->host_to_connect == NULL) |
|
|
const char *host, u_short port) |
const char *host, u_short port) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
int r; |
int r; |
u_int i; |
u_int i; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_listen_match_tcpip(fp, host, port, 0)) |
if (open_listen_match_tcpip(perm, host, port, 0)) |
break; |
break; |
fp = NULL; |
perm = NULL; |
} |
} |
if (fp == NULL) { |
if (perm == NULL) { |
debug("%s: requested forward not found", __func__); |
debug("%s: requested forward not found", __func__); |
return -1; |
return -1; |
} |
} |
|
|
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
|
|
fwd_perm_clear(fp); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
|
|
return 0; |
return 0; |
} |
} |
|
|
channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) |
channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
int r; |
int r; |
u_int i; |
u_int i; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_listen_match_streamlocal(fp, path)) |
if (open_listen_match_streamlocal(perm, path)) |
break; |
break; |
fp = NULL; |
perm = NULL; |
} |
} |
if (fp == NULL) { |
if (perm == NULL) { |
debug("%s: requested forward not found", __func__); |
debug("%s: requested forward not found", __func__); |
return -1; |
return -1; |
} |
} |
|
|
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
fatal("%s: send cancel: %s", __func__, ssh_err(r)); |
|
|
fwd_perm_clear(fp); /* unregister */ |
fwd_perm_clear(perm); /* unregister */ |
|
|
return 0; |
return 0; |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
* Permits opening to any host/port if permitted_opens[] is empty. This is |
* Permits opening to any host/port if permitted_user[] is empty. This is |
* usually called by the server, because the user could connect to any port |
* usually called by the server, because the user could connect to any port |
* anyway, and the server has no way to know but to trust the client anyway. |
* anyway, and the server has no way to know but to trust the client anyway. |
*/ |
*/ |
void |
void |
channel_permit_all_opens(struct ssh *ssh) |
channel_permit_all(struct ssh *ssh, int where) |
{ |
{ |
if (ssh->chanctxt->num_permitted_opens == 0) |
struct permission_set *pset = permission_set_get(ssh, where); |
ssh->chanctxt->all_opens_permitted = 1; |
|
|
if (pset->num_permitted_user == 0) |
|
pset->all_permitted = 1; |
} |
} |
|
|
|
/* |
|
* Permit the specified host/port for forwarding. |
|
*/ |
void |
void |
channel_add_permitted_opens(struct ssh *ssh, char *host, int port) |
channel_add_permission(struct ssh *ssh, int who, int where, |
|
char *host, int port) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
int local = where == FORWARD_LOCAL; |
|
struct permission_set *pset = permission_set_get(ssh, where); |
|
|
debug("allow port forwarding to host %s port %d", host, port); |
debug("allow %s forwarding to host %s port %d", |
fwd_perm_list_add(ssh, FWDPERM_USER, host, port, NULL, NULL, 0, NULL); |
fwd_ident(who, where), host, port); |
sc->all_opens_permitted = 0; |
/* |
|
* Remote forwards set listen_host/port, local forwards set |
|
* host/port_to_connect. |
|
*/ |
|
permission_set_add(ssh, who, where, |
|
local ? host : 0, local ? port : 0, |
|
local ? NULL : host, NULL, local ? 0 : port, NULL); |
|
pset->all_permitted = 0; |
} |
} |
|
|
/* |
/* |
|
* Administratively disable forwarding. |
|
*/ |
|
void |
|
channel_disable_admin(struct ssh *ssh, int where) |
|
{ |
|
channel_clear_permission(ssh, FORWARD_ADM, where); |
|
permission_set_add(ssh, FORWARD_ADM, where, |
|
NULL, 0, NULL, NULL, 0, NULL); |
|
} |
|
|
|
/* |
|
* Clear a list of permitted opens. |
|
*/ |
|
void |
|
channel_clear_permission(struct ssh *ssh, int who, int where) |
|
{ |
|
struct permission **permp; |
|
u_int *npermp; |
|
|
|
permission_set_get_array(ssh, who, where, &permp, &npermp); |
|
*permp = xrecallocarray(*permp, *npermp, 0, sizeof(**permp)); |
|
*npermp = 0; |
|
} |
|
|
|
/* |
* Update the listen port for a dynamic remote forward, after |
* Update the listen port for a dynamic remote forward, after |
* the actual 'newport' has been allocated. If 'newport' < 0 is |
* the actual 'newport' has been allocated. If 'newport' < 0 is |
* passed then they entry will be invalidated. |
* passed then they entry will be invalidated. |
*/ |
*/ |
void |
void |
channel_update_permitted_opens(struct ssh *ssh, int idx, int newport) |
channel_update_permission(struct ssh *ssh, int idx, int newport) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct permission_set *pset = &ssh->chanctxt->local_perms; |
|
|
if (idx < 0 || (u_int)idx >= sc->num_permitted_opens) { |
if (idx < 0 || (u_int)idx >= pset->num_permitted_user) { |
debug("%s: index out of range: %d num_permitted_opens %d", |
debug("%s: index out of range: %d num_permitted_user %d", |
__func__, idx, sc->num_permitted_opens); |
__func__, idx, pset->num_permitted_user); |
return; |
return; |
} |
} |
debug("%s allowed port %d for forwarding to host %s port %d", |
debug("%s allowed port %d for forwarding to host %s port %d", |
newport > 0 ? "Updating" : "Removing", |
newport > 0 ? "Updating" : "Removing", |
newport, |
newport, |
sc->permitted_opens[idx].host_to_connect, |
pset->permitted_user[idx].host_to_connect, |
sc->permitted_opens[idx].port_to_connect); |
pset->permitted_user[idx].port_to_connect); |
if (newport <= 0) |
if (newport <= 0) |
fwd_perm_clear(&sc->permitted_opens[idx]); |
fwd_perm_clear(&pset->permitted_user[idx]); |
else { |
else { |
sc->permitted_opens[idx].listen_port = |
pset->permitted_user[idx].listen_port = |
(datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; |
(datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport; |
} |
} |
} |
} |
|
|
int |
|
channel_add_adm_permitted_opens(struct ssh *ssh, char *host, int port) |
|
{ |
|
debug("config allows port forwarding to host %s port %d", host, port); |
|
return fwd_perm_list_add(ssh, FWDPERM_ADMIN, host, port, |
|
NULL, NULL, 0, NULL); |
|
} |
|
|
|
void |
|
channel_disable_adm_local_opens(struct ssh *ssh) |
|
{ |
|
channel_clear_adm_permitted_opens(ssh); |
|
fwd_perm_list_add(ssh, FWDPERM_ADMIN, NULL, 0, NULL, NULL, 0, NULL); |
|
} |
|
|
|
void |
|
channel_clear_permitted_opens(struct ssh *ssh) |
|
{ |
|
struct ssh_channels *sc = ssh->chanctxt; |
|
|
|
sc->permitted_opens = xrecallocarray(sc->permitted_opens, |
|
sc->num_permitted_opens, 0, sizeof(*sc->permitted_opens)); |
|
sc->num_permitted_opens = 0; |
|
} |
|
|
|
void |
|
channel_clear_adm_permitted_opens(struct ssh *ssh) |
|
{ |
|
struct ssh_channels *sc = ssh->chanctxt; |
|
|
|
sc->permitted_adm_opens = xrecallocarray(sc->permitted_adm_opens, |
|
sc->num_adm_permitted_opens, 0, sizeof(*sc->permitted_adm_opens)); |
|
sc->num_adm_permitted_opens = 0; |
|
} |
|
|
|
/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ |
/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */ |
int |
int |
permitopen_port(const char *p) |
permitopen_port(const char *p) |
|
|
u_short listen_port, char *ctype, char *rname) |
u_short listen_port, char *ctype, char *rname) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
u_int i; |
u_int i; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { |
if (open_listen_match_tcpip(perm, |
if (fp->downstream) |
listen_host, listen_port, 1)) { |
return fp->downstream; |
if (perm->downstream) |
if (fp->port_to_connect == 0) |
return perm->downstream; |
|
if (perm->port_to_connect == 0) |
return rdynamic_connect_prepare(ssh, |
return rdynamic_connect_prepare(ssh, |
ctype, rname); |
ctype, rname); |
return connect_to(ssh, |
return connect_to(ssh, |
fp->host_to_connect, fp->port_to_connect, |
perm->host_to_connect, perm->port_to_connect, |
ctype, rname); |
ctype, rname); |
} |
} |
} |
} |
|
|
char *ctype, char *rname) |
char *ctype, char *rname) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
u_int i; |
u_int i; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_listen_match_streamlocal(fp, path)) { |
if (open_listen_match_streamlocal(perm, path)) { |
return connect_to(ssh, |
return connect_to(ssh, |
fp->host_to_connect, fp->port_to_connect, |
perm->host_to_connect, perm->port_to_connect, |
ctype, rname); |
ctype, rname); |
} |
} |
} |
} |
|
|
char *ctype, char *rname, int *reason, const char **errmsg) |
char *ctype, char *rname, int *reason, const char **errmsg) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
struct channel_connect cctx; |
struct channel_connect cctx; |
Channel *c; |
Channel *c; |
u_int i, permit, permit_adm = 1; |
u_int i, permit, permit_adm = 1; |
int sock; |
int sock; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
permit = sc->all_opens_permitted; |
permit = pset->all_permitted; |
if (!permit) { |
if (!permit) { |
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_match(fp, host, port)) { |
if (open_match(perm, host, port)) { |
permit = 1; |
permit = 1; |
break; |
break; |
} |
} |
} |
} |
} |
} |
|
|
if (sc->num_adm_permitted_opens > 0) { |
if (pset->num_permitted_admin > 0) { |
permit_adm = 0; |
permit_adm = 0; |
for (i = 0; i < sc->num_adm_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_admin; i++) { |
fp = &sc->permitted_adm_opens[i]; |
perm = &pset->permitted_admin[i]; |
if (open_match(fp, host, port)) { |
if (open_match(perm, host, port)) { |
permit_adm = 1; |
permit_adm = 1; |
break; |
break; |
} |
} |
|
|
char *ctype, char *rname) |
char *ctype, char *rname) |
{ |
{ |
struct ssh_channels *sc = ssh->chanctxt; |
struct ssh_channels *sc = ssh->chanctxt; |
|
struct permission_set *pset = &sc->local_perms; |
u_int i, permit, permit_adm = 1; |
u_int i, permit, permit_adm = 1; |
ForwardPermission *fp; |
struct permission *perm; |
|
|
permit = sc->all_opens_permitted; |
permit = pset->all_permitted; |
if (!permit) { |
if (!permit) { |
for (i = 0; i < sc->num_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_user; i++) { |
fp = &sc->permitted_opens[i]; |
perm = &pset->permitted_user[i]; |
if (open_match(fp, path, PORT_STREAMLOCAL)) { |
if (open_match(perm, path, PORT_STREAMLOCAL)) { |
permit = 1; |
permit = 1; |
break; |
break; |
} |
} |
} |
} |
} |
} |
|
|
if (sc->num_adm_permitted_opens > 0) { |
if (pset->num_permitted_admin > 0) { |
permit_adm = 0; |
permit_adm = 0; |
for (i = 0; i < sc->num_adm_permitted_opens; i++) { |
for (i = 0; i < pset->num_permitted_admin; i++) { |
fp = &sc->permitted_adm_opens[i]; |
perm = &pset->permitted_admin[i]; |
if (open_match(fp, path, PORT_STREAMLOCAL)) { |
if (open_match(perm, path, PORT_STREAMLOCAL)) { |
permit_adm = 1; |
permit_adm = 1; |
break; |
break; |
} |
} |