Bugzilla – Attachment 3152 Details for
Bug 2038
permitopen functionality but for remote forwards
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
PermitRemoteOpen directive
bz2038.diff (text/plain), 34.02 KB, created by
Damien Miller
on 2018-05-22 10:11:41 AEST
(
hide
)
Description:
PermitRemoteOpen directive
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2018-05-22 10:11:41 AEST
Size:
34.02 KB
patch
obsolete
>diff --git a/channels.c b/channels.c >index 65d9dbd5..4881d993 100644 >--- a/channels.c >+++ b/channels.c >@@ -82,6 +82,7 @@ > #include "key.h" > #include "authfd.h" > #include "pathnames.h" >+#include "match.h" > > /* -- agent forwarding */ > #define NUM_SOCKS 10 >@@ -97,6 +98,10 @@ > /* Maximum number of fake X11 displays to try. */ > #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. > * The local sides of any remote forwards are stored in this array to prevent >@@ -115,8 +120,32 @@ typedef struct { > 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 fwdperms { >+ /* >+ * List of all local permitted host/port pairs to connect by the >+ * user. >+ */ >+ u_int num_permitted_opens; >+ ForwardPermission *permitted_opens; >+ >+ /* >+ * List of all permitted host/port pairs to connect by the >+ * admin. >+ */ >+ u_int num_adm_permitted_opens; >+ ForwardPermission *permitted_adm_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; >+}; > > /* Master structure for channels state */ > struct ssh_channels { >@@ -149,31 +178,8 @@ struct ssh_channels { > chan_fn **channel_post; > > /* -- tcp forwarding */ >- >- /* 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; >+ struct fwdperms fpms_local; >+ struct fwdperms fpms_remote; > > /* -- X11 forwarding */ > >@@ -456,42 +462,87 @@ fwd_perm_clear(ForwardPermission *fp) > bzero(fp, sizeof(*fp)); > } > >-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); >+} > >+/* Returns the forwarding permission list for the specified direction */ >+struct fwdperms * >+fwdperms_get(struct ssh *ssh, int where) >+{ >+ struct ssh_channels *sc = ssh->chanctxt; >+ >+ switch (where) { >+ case FORWARD_LOCAL: >+ return &sc->fpms_local; >+ break; >+ case FORWARD_REMOTE: >+ return &sc->fpms_remote; >+ break; >+ default: >+ fatal("%s: invalid forwarding direction %d", __func__, where); >+ } >+} >+ >+/* Reutrns pointers to the specified forwarding list and its element count */ >+static void >+fwdperms_get_array(struct ssh *ssh, int who, int where, >+ ForwardPermission ***fppp, u_int **nfppp) >+{ >+ struct fwdperms *fpms = fwdperms_get(ssh, where); >+ >+ switch (who) { >+ case FORWARD_USER: >+ *fppp = &fpms->permitted_opens; >+ *nfppp = &fpms->num_permitted_opens; >+ break; >+ case FORWARD_ADM: >+ *fppp = &fpms->permitted_adm_opens; >+ *nfppp = &fpms->num_adm_permitted_opens; >+ break; >+ default: >+ fatal("%s: invalid forwarding client %d", __func__, who); >+ } >+} >+ >+/* Adds an entry to the spcified forwarding list */ > static int >-fwd_perm_list_add(struct ssh *ssh, int which, >+fwdperms_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) > { >- ForwardPermission **fpl; >- u_int n, *nfpl; >+ ForwardPermission **fpp; >+ u_int n, *nfpp; > >- switch (which) { >- case FWDPERM_USER: >- fpl = &ssh->chanctxt->permitted_opens; >- nfpl = &ssh->chanctxt->num_permitted_opens; >- break; >- case FWDPERM_ADMIN: >- fpl = &ssh->chanctxt->permitted_adm_opens; >- nfpl = &ssh->chanctxt->num_adm_permitted_opens; >- break; >- default: >- fatal("%s: invalid list %d", __func__, which); >- } >+ fwdperms_get_array(ssh, who, where, &fpp, &nfpp); > >- if (*nfpl >= INT_MAX) >- fatal("%s: overflow", __func__); >+ if (*nfpp >= INT_MAX) >+ fatal("%s: %s overflow", __func__, fwd_ident(who, where)); > >- *fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl)); >- n = (*nfpl)++; >+ *fpp = xrecallocarray(*fpp, *nfpp, *nfpp + 1, sizeof(**fpp)); >+ n = (*nfpp)++; > #define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s)) >- (*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect); >- (*fpl)[n].port_to_connect = port_to_connect; >- (*fpl)[n].listen_host = MAYBE_DUP(listen_host); >- (*fpl)[n].listen_path = MAYBE_DUP(listen_path); >- (*fpl)[n].listen_port = listen_port; >- (*fpl)[n].downstream = downstream; >+ (*fpp)[n].host_to_connect = MAYBE_DUP(host_to_connect); >+ (*fpp)[n].port_to_connect = port_to_connect; >+ (*fpp)[n].listen_host = MAYBE_DUP(listen_host); >+ (*fpp)[n].listen_path = MAYBE_DUP(listen_path); >+ (*fpp)[n].listen_port = listen_port; >+ (*fpp)[n].downstream = downstream; > #undef MAYBE_DUP > return (int)n; > } >@@ -500,12 +551,13 @@ static void > mux_remove_remote_forwardings(struct ssh *ssh, Channel *c) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > ForwardPermission *fp; > int r; > u_int i; > >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (fp->downstream != c) > continue; > >@@ -2729,7 +2781,7 @@ channel_proxy_downstream(struct ssh *ssh, Channel *downstream) > goto out; > } > /* Record that connection to this host/port is permitted. */ >- fwd_perm_list_add(ssh, FWDPERM_USER, "<mux>", -1, >+ fwdperms_add(ssh, FORWARD_USER, FORWARD_LOCAL, "<mux>", -1, > listen_host, NULL, (int)listen_port, downstream); > listen_host = NULL; > break; >@@ -3637,11 +3689,78 @@ channel_setup_local_fwd_listener(struct ssh *ssh, > } > } > >+/* Matches a remote forwarding permission against a requested forwarding */ >+static int >+remote_open_match(ForwardPermission *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 fwdperms *fpms = &sc->fpms_remote; >+ u_int i, permit, permit_adm = 1; >+ ForwardPermission *fp; >+ >+ /* XXX apply GatewayPorts override before checking? */ >+ >+ permit = fpms->all_opens_permitted; >+ if (!permit) { >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; >+ if (remote_open_match(fp, fwd)) { >+ permit = 1; >+ break; >+ } >+ } >+ } >+ >+ if (fpms->num_adm_permitted_opens > 0) { >+ permit_adm = 0; >+ for (i = 0; i < fpms->num_adm_permitted_opens; i++) { >+ fp = &fpms->permitted_adm_opens[i]; >+ if (remote_open_match(fp, fwd)) { >+ permit_adm = 1; >+ break; >+ } >+ } >+ } >+ >+ return permit && permit_adm; >+} >+ > /* protocol v2 remote port fwd, used by sshd */ > int > channel_setup_remote_fwd_listener(struct ssh *ssh, struct Forward *fwd, > 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) { > return channel_setup_fwd_listener_streamlocal(ssh, > SSH_CHANNEL_RUNIX_LISTENER, fwd, fwd_opts); >@@ -3724,7 +3843,7 @@ channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) > listen_host = xstrdup(fwd->listen_host); > listen_port = fwd->listen_port; > } >- idx = fwd_perm_list_add(ssh, FWDPERM_USER, >+ idx = fwdperms_add(ssh, FORWARD_USER, FORWARD_LOCAL, > host_to_connect, port_to_connect, > listen_host, listen_path, listen_port, NULL); > } >@@ -3797,12 +3916,13 @@ channel_request_rforward_cancel_tcpip(struct ssh *ssh, > const char *host, u_short port) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > int r; > u_int i; > ForwardPermission *fp; > >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_listen_match_tcpip(fp, host, port, 0)) > break; > fp = NULL; >@@ -3832,12 +3952,13 @@ static int > channel_request_rforward_cancel_streamlocal(struct ssh *ssh, const char *path) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > int r; > u_int i; > ForwardPermission *fp; > >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_listen_match_streamlocal(fp, path)) > break; > fp = NULL; >@@ -3881,20 +4002,59 @@ channel_request_rforward_cancel(struct ssh *ssh, struct Forward *fwd) > * anyway, and the server has no way to know but to trust the client anyway. > */ > void >-channel_permit_all_opens(struct ssh *ssh) >+channel_permit_all_opens(struct ssh *ssh, int where) > { >- if (ssh->chanctxt->num_permitted_opens == 0) >- ssh->chanctxt->all_opens_permitted = 1; >+ struct fwdperms *fpms = fwdperms_get(ssh, where); >+ >+ if (fpms->num_permitted_opens == 0) >+ fpms->all_opens_permitted = 1; >+} >+ >+/* >+ * Permit the specified host/port for forwarding. >+ */ >+void >+channel_add_permitted_open(struct ssh *ssh, int who, int where, >+ char *host, int port) >+{ >+ int local = where == FORWARD_LOCAL; >+ struct fwdperms *fpms = fwdperms_get(ssh, where); >+ >+ debug("allow %s forwarding to host %s port %d", >+ fwd_ident(who, where), host, port); >+ /* >+ * Remote forwards set listen_host/port, local forwards set >+ * host/port_to_connect. >+ */ >+ fwdperms_add(ssh, who, where, >+ local ? host : 0, local ? port : 0, >+ local ? NULL : host, NULL, local ? 0 : port, NULL); >+ fpms->all_opens_permitted = 0; >+} >+ >+/* >+ * Administratively disable forwarding. >+ */ >+void >+channel_disable_adm_opens(struct ssh *ssh, int where) >+{ >+ channel_clear_permitted_opens(ssh, FORWARD_ADM, where); >+ fwdperms_add(ssh, FORWARD_ADM, where, >+ NULL, 0, NULL, NULL, 0, NULL); > } > >+/* >+ * Clear a list of permitted opens. >+ */ > void >-channel_add_permitted_opens(struct ssh *ssh, char *host, int port) >+channel_clear_permitted_opens(struct ssh *ssh, int who, int where) > { >- struct ssh_channels *sc = ssh->chanctxt; >+ ForwardPermission **fpp; >+ u_int *nfpp; > >- debug("allow port forwarding to host %s port %d", host, port); >- fwd_perm_list_add(ssh, FWDPERM_USER, host, port, NULL, NULL, 0, NULL); >- sc->all_opens_permitted = 0; >+ fwdperms_get_array(ssh, who, where, &fpp, &nfpp); >+ *fpp = xrecallocarray(*fpp, *nfpp, 0, sizeof(**fpp)); >+ *nfpp = 0; > } > > /* >@@ -3905,61 +4065,26 @@ channel_add_permitted_opens(struct ssh *ssh, char *host, int port) > void > channel_update_permitted_opens(struct ssh *ssh, int idx, int newport) > { >- struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &ssh->chanctxt->fpms_local; > >- if (idx < 0 || (u_int)idx >= sc->num_permitted_opens) { >+ if (idx < 0 || (u_int)idx >= fpms->num_permitted_opens) { > debug("%s: index out of range: %d num_permitted_opens %d", >- __func__, idx, sc->num_permitted_opens); >+ __func__, idx, fpms->num_permitted_opens); > return; > } > debug("%s allowed port %d for forwarding to host %s port %d", > newport > 0 ? "Updating" : "Removing", > newport, >- sc->permitted_opens[idx].host_to_connect, >- sc->permitted_opens[idx].port_to_connect); >+ fpms->permitted_opens[idx].host_to_connect, >+ fpms->permitted_opens[idx].port_to_connect); > if (newport <= 0) >- fwd_perm_clear(&sc->permitted_opens[idx]); >+ fwd_perm_clear(&fpms->permitted_opens[idx]); > else { >- sc->permitted_opens[idx].listen_port = >+ fpms->permitted_opens[idx].listen_port = > (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 */ > int > permitopen_port(const char *p) >@@ -4148,11 +4273,12 @@ channel_connect_by_listen_address(struct ssh *ssh, const char *listen_host, > u_short listen_port, char *ctype, char *rname) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > u_int i; > ForwardPermission *fp; > >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_listen_match_tcpip(fp, listen_host, listen_port, 1)) { > if (fp->downstream) > return fp->downstream; >@@ -4174,11 +4300,12 @@ channel_connect_by_listen_path(struct ssh *ssh, const char *path, > char *ctype, char *rname) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > u_int i; > ForwardPermission *fp; > >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_listen_match_streamlocal(fp, path)) { > return connect_to(ssh, > fp->host_to_connect, fp->port_to_connect, >@@ -4196,16 +4323,17 @@ channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, > char *ctype, char *rname, int *reason, const char **errmsg) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > struct channel_connect cctx; > Channel *c; > u_int i, permit, permit_adm = 1; > int sock; > ForwardPermission *fp; > >- permit = sc->all_opens_permitted; >+ permit = fpms->all_opens_permitted; > if (!permit) { >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_match(fp, host, port)) { > permit = 1; > break; >@@ -4213,10 +4341,10 @@ channel_connect_to_port(struct ssh *ssh, const char *host, u_short port, > } > } > >- if (sc->num_adm_permitted_opens > 0) { >+ if (fpms->num_adm_permitted_opens > 0) { > permit_adm = 0; >- for (i = 0; i < sc->num_adm_permitted_opens; i++) { >- fp = &sc->permitted_adm_opens[i]; >+ for (i = 0; i < fpms->num_adm_permitted_opens; i++) { >+ fp = &fpms->permitted_adm_opens[i]; > if (open_match(fp, host, port)) { > permit_adm = 1; > break; >@@ -4255,13 +4383,14 @@ channel_connect_to_path(struct ssh *ssh, const char *path, > char *ctype, char *rname) > { > struct ssh_channels *sc = ssh->chanctxt; >+ struct fwdperms *fpms = &sc->fpms_local; > u_int i, permit, permit_adm = 1; > ForwardPermission *fp; > >- permit = sc->all_opens_permitted; >+ permit = fpms->all_opens_permitted; > if (!permit) { >- for (i = 0; i < sc->num_permitted_opens; i++) { >- fp = &sc->permitted_opens[i]; >+ for (i = 0; i < fpms->num_permitted_opens; i++) { >+ fp = &fpms->permitted_opens[i]; > if (open_match(fp, path, PORT_STREAMLOCAL)) { > permit = 1; > break; >@@ -4269,10 +4398,10 @@ channel_connect_to_path(struct ssh *ssh, const char *path, > } > } > >- if (sc->num_adm_permitted_opens > 0) { >+ if (fpms->num_adm_permitted_opens > 0) { > permit_adm = 0; >- for (i = 0; i < sc->num_adm_permitted_opens; i++) { >- fp = &sc->permitted_adm_opens[i]; >+ for (i = 0; i < fpms->num_adm_permitted_opens; i++) { >+ fp = &fpms->permitted_adm_opens[i]; > if (open_match(fp, path, PORT_STREAMLOCAL)) { > permit_adm = 1; > break; >diff --git a/channels.h b/channels.h >index 126b0434..aec08fa0 100644 >--- a/channels.h >+++ b/channels.h >@@ -63,6 +63,15 @@ > > #define CHANNEL_CANCEL_PORT_STATIC -1 > >+/* TCP forwarding */ >+#define FORWARD_DENY 0 >+#define FORWARD_REMOTE (1) >+#define FORWARD_LOCAL (1<<1) >+#define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL) >+ >+#define FORWARD_ADM 0x100 >+#define FORWARD_USER 0x101 >+ > struct ssh; > struct Channel; > typedef struct Channel Channel; >@@ -283,16 +292,11 @@ int channel_find_open(struct ssh *); > struct Forward; > struct ForwardOptions; > void channel_set_af(struct ssh *, int af); >-void channel_permit_all_opens(struct ssh *); >-void channel_add_permitted_opens(struct ssh *, char *, int); >-int channel_add_adm_permitted_opens(struct ssh *, char *, int); >-void channel_copy_adm_permitted_opens(struct ssh *, >- const struct fwd_perm_list *); >-void channel_disable_adm_local_opens(struct ssh *); >+void channel_permit_all_opens(struct ssh *, int); >+void channel_add_permitted_open(struct ssh *, int, int, char *, int); >+void channel_clear_permitted_opens(struct ssh *, int, int); >+void channel_disable_adm_opens(struct ssh *, int); > void channel_update_permitted_opens(struct ssh *, int, int); >-void channel_clear_permitted_opens(struct ssh *); >-void channel_clear_adm_permitted_opens(struct ssh *); >-void channel_print_adm_permitted_opens(struct ssh *); > Channel *channel_connect_to_port(struct ssh *, const char *, u_short, > char *, char *, int *, const char **); > Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *); >diff --git a/regress/forward-control.sh b/regress/forward-control.sh >index 93d05cf6..a83174a0 100644 >--- a/regress/forward-control.sh >+++ b/regress/forward-control.sh >@@ -67,7 +67,7 @@ check_rfwd() { > _message=$2 > rm -f $READY > ${SSH} -F $OBJ/ssh_proxy \ >- -R$RFWD_PORT:127.0.0.1:$PORT \ >+ -R127.0.0.1:$RFWD_PORT:127.0.0.1:$PORT \ > -o ExitOnForwardFailure=yes \ > -n host exec sh -c \'"sleep 60 & echo \$! > $READY ; wait "\' \ > >/dev/null 2>&1 & >@@ -100,8 +100,8 @@ cp ${OBJ}/authorized_keys_${USER} ${OBJ}/authorized_keys_${USER}.bak > check_lfwd Y "default configuration" > check_rfwd Y "default configuration" > >-# Usage: all_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N >-all_tests() { >+# Usage: lperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N >+lperm_tests() { > _tcpfwd=$1 > _plain_lfwd=$2 > _plain_rfwd=$3 >@@ -113,12 +113,14 @@ all_tests() { > _goodfwd=127.0.0.1:${PORT} > cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} > _prefix="AllowTcpForwarding=$_tcpfwd" >+ > # No PermitOpen > ( cat ${OBJ}/sshd_proxy.bak ; > echo "AllowTcpForwarding $_tcpfwd" ) \ > > ${OBJ}/sshd_proxy > check_lfwd $_plain_lfwd "$_prefix" > check_rfwd $_plain_rfwd "$_prefix" >+ > # PermitOpen via sshd_config that doesn't match > ( cat ${OBJ}/sshd_proxy.bak ; > echo "AllowTcpForwarding $_tcpfwd" ; >@@ -131,6 +133,10 @@ all_tests() { > echo "AllowTcpForwarding $_tcpfwd" ; > echo "PermitOpen $_badfwd $_goodfwd" ) \ > > ${OBJ}/sshd_proxy >+ check_lfwd $_plain_lfwd "$_prefix, PermitOpen" >+ check_rfwd $_plain_rfwd "$_prefix, PermitOpen" >+ >+ # permitopen keys option. > # NB. permitopen via authorized_keys should have same > # success/fail as via sshd_config > # permitopen via authorized_keys that doesn't match >@@ -151,6 +157,7 @@ all_tests() { > > ${OBJ}/sshd_proxy > check_lfwd $_permit_lfwd "$_prefix, permitopen" > check_rfwd $_permit_rfwd "$_prefix, permitopen" >+ > # Check port-forwarding flags in authorized_keys. > # These two should refuse all. > sed "s/^/no-port-forwarding /" \ >@@ -180,9 +187,47 @@ all_tests() { > check_rfwd $_plain_rfwd "$_prefix, restrict,port-forwarding" > } > >-# no-permitopen mismatch-permitopen match-permitopen >-# AllowTcpForwarding local remote local remote local remote >-all_tests yes Y Y N Y Y Y >-all_tests local Y N N N Y N >-all_tests remote N Y N Y N Y >-all_tests no N N N N N N >+# permit-open none mismatch match >+# AllowTcpForwarding local remote local remote local remote >+lperm_tests yes Y Y N Y Y Y >+lperm_tests local Y N N N Y N >+lperm_tests remote N Y N Y N Y >+lperm_tests no N N N N N N >+ >+# Usage: rperm_tests yes|local|remote|no Y|N Y|N Y|N Y|N Y|N Y|N >+rperm_tests() { >+ _tcpfwd=$1 >+ _plain_lfwd=$2 >+ _plain_rfwd=$3 >+ _nopermit_lfwd=$4 >+ _nopermit_rfwd=$5 >+ _permit_lfwd=$6 >+ _permit_rfwd=$7 >+ _badfwd=127.0.0.1:22 >+ _goodfwd=127.0.0.1:${RFWD_PORT} >+ cp ${OBJ}/authorized_keys_${USER}.bak ${OBJ}/authorized_keys_${USER} >+ _prefix="AllowTcpForwarding=$_tcpfwd" >+ >+ # PermitRemoteOpen via sshd_config that doesn't match >+ ( cat ${OBJ}/sshd_proxy.bak ; >+ echo "AllowTcpForwarding $_tcpfwd" ; >+ echo "PermitRemoteOpen $_badfwd" ) \ >+ > ${OBJ}/sshd_proxy >+ check_lfwd $_nopermit_lfwd "$_prefix, !PermitRemoteOpen" >+ check_rfwd $_nopermit_rfwd "$_prefix, !PermitRemoteOpen" >+ # PermitRemoteOpen via sshd_config that does match >+ ( cat ${OBJ}/sshd_proxy.bak ; >+ echo "AllowTcpForwarding $_tcpfwd" ; >+ echo "PermitRemoteOpen $_badfwd $_goodfwd" ) \ >+ > ${OBJ}/sshd_proxy >+ check_lfwd $_plain_lfwd "$_prefix, PermitRemoteOpen" >+ check_rfwd $_plain_rfwd "$_prefix, PermitRemoteOpen" >+} >+ >+# permit-remote-open none mismatch match >+# AllowTcpForwarding local remote local remote local remote >+rperm_tests yes Y Y Y N Y Y >+rperm_tests local Y N Y N Y N >+rperm_tests remote N Y N N N Y >+rperm_tests no N N N N N N >+ >diff --git a/regress/test-exec.sh b/regress/test-exec.sh >index b6169f15..5814ac56 100644 >--- a/regress/test-exec.sh >+++ b/regress/test-exec.sh >@@ -375,7 +375,10 @@ fail () > save_debug_log "FAIL: $@" > RESULT=1 > echo "$@" >- >+ if test "x$TEST_SSH_FATAL_FAILURES" != "x" ; then >+ cleanup >+ exit $RESULT >+ fi > } > > fatal () >diff --git a/servconf.c b/servconf.c >index 5ca84515..a54f3cc2 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -160,6 +160,7 @@ initialize_server_options(ServerOptions *options) > options->num_accept_env = 0; > options->permit_tun = -1; > options->permitted_opens = NULL; >+ options->permitted_remote_opens = NULL; > options->adm_forced_command = NULL; > options->chroot_directory = NULL; > options->authorized_keys_command = NULL; >@@ -462,7 +463,7 @@ typedef enum { > sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, > sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, > sAcceptEnv, sPermitTunnel, >- sMatch, sPermitOpen, sForceCommand, sChrootDirectory, >+ sMatch, sPermitOpen, sPermitRemoteOpen, sForceCommand, sChrootDirectory, > sUsePrivilegeSeparation, sAllowAgentForwarding, > sHostCertificate, > sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, >@@ -597,6 +598,7 @@ static struct { > { "permituserrc", sPermitUserRC, SSHCFG_ALL }, > { "match", sMatch, SSHCFG_ALL }, > { "permitopen", sPermitOpen, SSHCFG_ALL }, >+ { "permitremoteopen", sPermitRemoteOpen, SSHCFG_ALL }, > { "forcecommand", sForceCommand, SSHCFG_ALL }, > { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, > { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, >@@ -632,6 +634,20 @@ static struct { > { -1, NULL } > }; > >+/* Returns an opcode name from its number */ >+ >+static const char * >+lookup_opcode_name(ServerOpCodes code) >+{ >+ u_int i; >+ >+ for (i = 0; keywords[i].name != NULL; i++) >+ if (keywords[i].opcode == code) >+ return(keywords[i].name); >+ return "UNKNOWN"; >+} >+ >+ > /* > * Returns the number of the token pointed to by cp or sBadOption. > */ >@@ -814,43 +830,59 @@ process_queued_listen_addrs(ServerOptions *options) > } > > /* >- * Inform channels layer of permitopen options from configuration. >+ * Inform channels layer of permitopen options for a single forwarding >+ * direction (local/remote). > */ >-void >-process_permitopen(struct ssh *ssh, ServerOptions *options) >+static void >+process_permitopen_list(struct ssh *ssh, ServerOpCodes opcode, >+ char **opens, u_int num_opens) > { > u_int i; > int port; > char *host, *arg, *oarg; >+ int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE; >+ const char *what = lookup_opcode_name(opcode); > >- channel_clear_adm_permitted_opens(ssh); >- if (options->num_permitted_opens == 0) >+ channel_clear_permitted_opens(ssh, FORWARD_ADM, where); >+ if (num_opens == 0) > return; /* permit any */ > > /* handle keywords: "any" / "none" */ >- if (options->num_permitted_opens == 1 && >- strcmp(options->permitted_opens[0], "any") == 0) >+ if (num_opens == 1 && strcmp(opens[0], "any") == 0) > return; >- if (options->num_permitted_opens == 1 && >- strcmp(options->permitted_opens[0], "none") == 0) { >- channel_disable_adm_local_opens(ssh); >+ if (num_opens == 1 && strcmp(opens[0], "none") == 0) { >+ channel_disable_adm_opens(ssh, where); > return; > } > /* Otherwise treat it as a list of permitted host:port */ >- for (i = 0; i < options->num_permitted_opens; i++) { >- oarg = arg = xstrdup(options->permitted_opens[i]); >+ for (i = 0; i < num_opens; i++) { >+ oarg = arg = xstrdup(opens[i]); > host = hpdelim(&arg); > if (host == NULL) >- fatal("%s: missing host in PermitOpen", __func__); >+ fatal("%s: missing host in %s", __func__, what); > host = cleanhostname(host); > if (arg == NULL || ((port = permitopen_port(arg)) < 0)) >- fatal("%s: bad port number in PermitOpen", __func__); >+ fatal("%s: bad port number in %s", __func__, what); > /* Send it to channels layer */ >- channel_add_adm_permitted_opens(ssh, host, port); >+ channel_add_permitted_open(ssh, FORWARD_ADM, >+ where, host, port); > free(oarg); > } > } > >+/* >+ * Inform channels layer of permitopen options from configuration. >+ */ >+void >+process_permitopen(struct ssh *ssh, ServerOptions *options) >+{ >+ process_permitopen_list(ssh, sPermitOpen, >+ options->permitted_opens, options->num_permitted_opens); >+ process_permitopen_list(ssh, sPermitRemoteOpen, >+ options->permitted_remote_opens, >+ options->num_permitted_remote_opens); >+} >+ > struct connection_info * > get_connection_info(int populate, int use_dns) > { >@@ -1144,12 +1176,12 @@ process_server_config_line(ServerOptions *options, char *line, > const char *filename, int linenum, int *activep, > struct connection_info *connectinfo) > { >- char *cp, **charptr, *arg, *arg2, *p; >+ char *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; > int cmdline = 0, *intptr, value, value2, n, port; > SyslogFacility *log_facility_ptr; > LogLevel *log_level_ptr; > ServerOpCodes opcode; >- u_int i, flags = 0; >+ u_int i, *uintptr, uvalue, flags = 0; > size_t len; > long long val64; > const struct multistate *multistate_ptr; >@@ -1799,36 +1831,49 @@ process_server_config_line(ServerOptions *options, char *line, > *activep = value; > break; > >+ case sPermitRemoteOpen: > case sPermitOpen: >+ if (opcode == sPermitRemoteOpen) { >+ uintptr = &options->num_permitted_remote_opens; >+ chararrayptr = &options->permitted_remote_opens; >+ } else { >+ uintptr = &options->num_permitted_opens; >+ chararrayptr = &options->permitted_opens; >+ } > arg = strdelim(&cp); > if (!arg || *arg == '\0') >- fatal("%s line %d: missing PermitOpen specification", >- filename, linenum); >- value = options->num_permitted_opens; /* modified later */ >+ fatal("%s line %d: missing %s specification", >+ filename, linenum, lookup_opcode_name(opcode)); >+ uvalue = *uintptr; /* modified later */ > if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) { >- if (*activep && value == 0) { >- options->num_permitted_opens = 1; >- options->permitted_opens = xcalloc(1, >- sizeof(*options->permitted_opens)); >- options->permitted_opens[0] = xstrdup(arg); >+ if (*activep && uvalue == 0) { >+ *uintptr = 1; >+ *chararrayptr = xcalloc(1, >+ sizeof(**chararrayptr)); >+ (*chararrayptr)[0] = xstrdup(arg); > } > break; > } > for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) { > arg2 = xstrdup(arg); > p = hpdelim(&arg); >- if (p == NULL) >- fatal("%s line %d: missing host in PermitOpen", >- filename, linenum); >+ /* XXX support bare port number for PermitRemoteOpen */ >+ if (p == NULL) { >+ fatal("%s line %d: missing host in %s", >+ filename, linenum, >+ lookup_opcode_name(opcode)); >+ } > p = cleanhostname(p); >- if (arg == NULL || ((port = permitopen_port(arg)) < 0)) >- fatal("%s line %d: bad port number in " >- "PermitOpen", filename, linenum); >- if (*activep && value == 0) { >+ if (arg == NULL || >+ ((port = permitopen_port(arg)) < 0)) { >+ fatal("%s line %d: bad port number in %s", >+ filename, linenum, >+ lookup_opcode_name(opcode)); >+ } >+ if (*activep && uvalue == 0) { > array_append(filename, linenum, >- "PermitOpen", >- &options->permitted_opens, >- &options->num_permitted_opens, arg2); >+ lookup_opcode_name(opcode), >+ chararrayptr, uintptr, arg2); > } > free(arg2); > } >@@ -2307,17 +2352,6 @@ fmt_intarg(ServerOpCodes code, int val) > } > } > >-static const char * >-lookup_opcode_name(ServerOpCodes code) >-{ >- u_int i; >- >- for (i = 0; keywords[i].name != NULL; i++) >- if (keywords[i].opcode == code) >- return(keywords[i].name); >- return "UNKNOWN"; >-} >- > static void > dump_cfg_int(ServerOpCodes code, int val) > { >@@ -2562,4 +2596,12 @@ dump_config(ServerOptions *o) > printf(" %s", o->permitted_opens[i]); > } > printf("\n"); >+ printf("permitremoteopen"); >+ if (o->num_permitted_remote_opens == 0) >+ printf(" any"); >+ else { >+ for (i = 0; i < o->num_permitted_remote_opens; i++) >+ printf(" %s", o->permitted_remote_opens[i]); >+ } >+ printf("\n"); > } >diff --git a/servconf.h b/servconf.h >index 6d2553c3..f619045f 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -32,12 +32,6 @@ > #define PRIVSEP_ON 1 > #define PRIVSEP_NOSANDBOX 2 > >-/* AllowTCPForwarding */ >-#define FORWARD_DENY 0 >-#define FORWARD_REMOTE (1) >-#define FORWARD_LOCAL (1<<1) >-#define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL) >- > /* PermitOpen */ > #define PERMITOPEN_ANY 0 > #define PERMITOPEN_NONE -2 >@@ -187,8 +181,10 @@ typedef struct { > > int permit_tun; > >- char **permitted_opens; >- u_int num_permitted_opens; /* May also be one of PERMITOPEN_* */ >+ char **permitted_opens; /* May also be one of PERMITOPEN_* */ >+ u_int num_permitted_opens; >+ char **permitted_remote_opens; /* May also be one of PERMITOPEN_* */ >+ u_int num_permitted_remote_opens; > > char *chroot_directory; > char *revoked_keys_file; >@@ -252,6 +248,8 @@ struct connection_info { > M_CP_STRARRAYOPT(accept_env, num_accept_env); \ > M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \ > M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \ >+ M_CP_STRARRAYOPT(permitted_remote_opens, \ >+ num_permitted_remote_opens); \ > } while (0) > > struct connection_info *get_connection_info(int, int); >diff --git a/session.c b/session.c >index 58826db1..33a6dd90 100644 >--- a/session.c >+++ b/session.c >@@ -298,7 +298,7 @@ set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts) > > if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) > return; >- channel_clear_permitted_opens(ssh); >+ channel_clear_permitted_opens(ssh, FORWARD_USER, FORWARD_LOCAL); > for (i = 0; i < auth_opts->npermitopen; i++) { > tmp = cp = xstrdup(auth_opts->permitopen[i]); > /* This shouldn't fail as it has already been checked */ >@@ -308,7 +308,8 @@ set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts) > if (cp == NULL || (port = permitopen_port(cp)) < 0) > fatal("%s: internal error: permitopen port", > __func__); >- channel_add_permitted_opens(ssh, host, port); >+ channel_add_permitted_open(ssh, FORWARD_USER, FORWARD_LOCAL, >+ host, port); > free(tmp); > } > } >@@ -323,13 +324,21 @@ do_authenticated(struct ssh *ssh, Authctxt *authctxt) > /* setup the channel layer */ > /* XXX - streamlocal? */ > set_permitopen_from_authopts(ssh, auth_opts); >+ > if (!auth_opts->permit_port_forwarding_flag || >- options.disable_forwarding || >- (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) >- channel_disable_adm_local_opens(ssh); >- else >- channel_permit_all_opens(ssh); >- >+ options.disable_forwarding) { >+ channel_disable_adm_opens(ssh, FORWARD_LOCAL); >+ channel_disable_adm_opens(ssh, FORWARD_REMOTE); >+ } else { >+ if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0) >+ channel_disable_adm_opens(ssh, FORWARD_LOCAL); >+ else >+ channel_permit_all_opens(ssh, FORWARD_LOCAL); >+ if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0) >+ channel_disable_adm_opens(ssh, FORWARD_REMOTE); >+ else >+ channel_permit_all_opens(ssh, FORWARD_REMOTE); >+ } > auth_debug_send(); > > prepare_auth_info_file(authctxt->pw, authctxt->session_info);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2038
:
2436
|
2517
|
3054
| 3152 |
3153