upstream: permitlisten option for authorized_keys; ok markus@
OpenBSD-Commit-ID: 8650883018d7aa893173d703379e4456a222c672
This commit is contained in:
parent
115063a664
commit
93c06ab6b7
140
auth-options.c
140
auth-options.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth-options.c,v 1.79 2018/04/06 04:15:45 djm Exp $ */
|
||||
/* $OpenBSD: auth-options.c,v 1.80 2018/06/06 18:23:32 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2018 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
|
@ -283,6 +283,10 @@ sshauthopt_free(struct sshauthopt *opts)
|
|||
free(opts->permitopen[i]);
|
||||
free(opts->permitopen);
|
||||
|
||||
for (i = 0; i < opts->npermitlisten; i++)
|
||||
free(opts->permitlisten[i]);
|
||||
free(opts->permitlisten);
|
||||
|
||||
explicit_bzero(opts, sizeof(*opts));
|
||||
free(opts);
|
||||
}
|
||||
|
@ -304,10 +308,70 @@ sshauthopt_new_with_keys_defaults(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and record a permitopen/permitlisten directive.
|
||||
* Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
|
||||
*/
|
||||
static int
|
||||
handle_permit(const char *opts, char ***permitsp, size_t *npermitsp,
|
||||
const char **errstrp)
|
||||
{
|
||||
char *opt, *tmp, *cp, *host, **permits = *permitsp;
|
||||
size_t npermits = *npermitsp;
|
||||
const char *errstr = "unknown error";
|
||||
|
||||
if (npermits > INT_MAX) {
|
||||
*errstrp = "too many permission directives";
|
||||
return -1;
|
||||
}
|
||||
if ((opt = opt_dequote(&opts, &errstr)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if ((tmp = strdup(opt)) == NULL) {
|
||||
free(opt);
|
||||
*errstrp = "memory allocation failed";
|
||||
return -1;
|
||||
}
|
||||
cp = tmp;
|
||||
/* validate syntax before recording it. */
|
||||
host = hpdelim(&cp);
|
||||
if (host == NULL || strlen(host) >= NI_MAXHOST) {
|
||||
free(tmp);
|
||||
free(opt);
|
||||
*errstrp = "invalid permission hostname";
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* don't want to use permitopen_port to avoid
|
||||
* dependency on channels.[ch] here.
|
||||
*/
|
||||
if (cp == NULL ||
|
||||
(strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
|
||||
free(tmp);
|
||||
free(opt);
|
||||
*errstrp = "invalid permission port";
|
||||
return -1;
|
||||
}
|
||||
/* XXX - add streamlocal support */
|
||||
free(tmp);
|
||||
/* Record it */
|
||||
if ((permits = recallocarray(permits, npermits, npermits + 1,
|
||||
sizeof(*permits))) == NULL) {
|
||||
free(opt);
|
||||
/* NB. don't update *permitsp if alloc fails */
|
||||
*errstrp = "memory allocation failed";
|
||||
return -1;
|
||||
}
|
||||
permits[npermits++] = opt;
|
||||
*permitsp = permits;
|
||||
*npermitsp = npermits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sshauthopt *
|
||||
sshauthopt_parse(const char *opts, const char **errstrp)
|
||||
{
|
||||
char **oarray, *opt, *cp, *tmp, *host;
|
||||
char **oarray, *opt, *cp, *tmp;
|
||||
int r;
|
||||
struct sshauthopt *ret = NULL;
|
||||
const char *errstr = "unknown error";
|
||||
|
@ -410,48 +474,13 @@ sshauthopt_parse(const char *opts, const char **errstrp)
|
|||
}
|
||||
ret->env[ret->nenv++] = opt;
|
||||
} else if (opt_match(&opts, "permitopen")) {
|
||||
if (ret->npermitopen > INT_MAX) {
|
||||
errstr = "too many permitopens";
|
||||
if (handle_permit(opts, &ret->permitopen,
|
||||
&ret->npermitopen, &errstr) != 0)
|
||||
goto fail;
|
||||
}
|
||||
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
|
||||
} else if (opt_match(&opts, "permitlisten")) {
|
||||
if (handle_permit(opts, &ret->permitlisten,
|
||||
&ret->npermitlisten, &errstr) != 0)
|
||||
goto fail;
|
||||
if ((tmp = strdup(opt)) == NULL) {
|
||||
free(opt);
|
||||
goto alloc_fail;
|
||||
}
|
||||
cp = tmp;
|
||||
/* validate syntax of permitopen before recording it. */
|
||||
host = hpdelim(&cp);
|
||||
if (host == NULL || strlen(host) >= NI_MAXHOST) {
|
||||
free(tmp);
|
||||
free(opt);
|
||||
errstr = "invalid permitopen hostname";
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
* don't want to use permitopen_port to avoid
|
||||
* dependency on channels.[ch] here.
|
||||
*/
|
||||
if (cp == NULL ||
|
||||
(strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
|
||||
free(tmp);
|
||||
free(opt);
|
||||
errstr = "invalid permitopen port";
|
||||
goto fail;
|
||||
}
|
||||
/* XXX - add streamlocal support */
|
||||
free(tmp);
|
||||
/* Record it */
|
||||
oarray = ret->permitopen;
|
||||
if ((ret->permitopen = recallocarray(ret->permitopen,
|
||||
ret->npermitopen, ret->npermitopen + 1,
|
||||
sizeof(*ret->permitopen))) == NULL) {
|
||||
free(opt);
|
||||
ret->permitopen = oarray;
|
||||
goto alloc_fail;
|
||||
}
|
||||
ret->permitopen[ret->npermitopen++] = opt;
|
||||
} else if (opt_match(&opts, "tunnel")) {
|
||||
if ((opt = opt_dequote(&opts, &errstr)) == NULL)
|
||||
goto fail;
|
||||
|
@ -554,7 +583,10 @@ sshauthopt_merge(const struct sshauthopt *primary,
|
|||
if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
|
||||
goto alloc_fail;
|
||||
|
||||
/* force_tun_device, permitopen and environment prefer the primary. */
|
||||
/*
|
||||
* force_tun_device, permitopen/permitlisten and environment all
|
||||
* prefer the primary.
|
||||
*/
|
||||
ret->force_tun_device = primary->force_tun_device;
|
||||
if (ret->force_tun_device == -1)
|
||||
ret->force_tun_device = additional->force_tun_device;
|
||||
|
@ -577,6 +609,16 @@ sshauthopt_merge(const struct sshauthopt *primary,
|
|||
goto alloc_fail;
|
||||
}
|
||||
|
||||
if (primary->npermitlisten > 0) {
|
||||
if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
|
||||
primary->permitlisten, primary->npermitlisten) != 0)
|
||||
goto alloc_fail;
|
||||
} else if (additional->npermitlisten > 0) {
|
||||
if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
|
||||
additional->permitlisten, additional->npermitlisten) != 0)
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
/* Flags are logical-AND (i.e. must be set in both for permission) */
|
||||
#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1)
|
||||
OPTFLAG(permit_port_forwarding_flag);
|
||||
|
@ -669,7 +711,9 @@ sshauthopt_copy(const struct sshauthopt *orig)
|
|||
|
||||
if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
|
||||
dup_strings(&ret->permitopen, &ret->npermitopen,
|
||||
orig->permitopen, orig->npermitopen) != 0) {
|
||||
orig->permitopen, orig->npermitopen) != 0 ||
|
||||
dup_strings(&ret->permitlisten, &ret->npermitlisten,
|
||||
orig->permitlisten, orig->npermitlisten) != 0) {
|
||||
sshauthopt_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -805,7 +849,9 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
|
|||
if ((r = serialise_array(m, opts->env,
|
||||
untrusted ? 0 : opts->nenv)) != 0 ||
|
||||
(r = serialise_array(m, opts->permitopen,
|
||||
untrusted ? 0 : opts->npermitopen)) != 0)
|
||||
untrusted ? 0 : opts->npermitopen)) ||
|
||||
(r = serialise_array(m, opts->permitlisten,
|
||||
untrusted ? 0 : opts->npermitlisten)) != 0)
|
||||
return r;
|
||||
|
||||
/* success */
|
||||
|
@ -859,7 +905,9 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
|
|||
/* Array options */
|
||||
if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
|
||||
(r = deserialise_array(m,
|
||||
&opts->permitopen, &opts->npermitopen)) != 0)
|
||||
&opts->permitopen, &opts->npermitopen)) != 0 ||
|
||||
(r = deserialise_array(m,
|
||||
&opts->permitlisten, &opts->npermitlisten)) != 0)
|
||||
goto out;
|
||||
|
||||
/* success */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth-options.h,v 1.26 2018/03/12 00:52:01 djm Exp $ */
|
||||
/* $OpenBSD: auth-options.h,v 1.27 2018/06/06 18:23:32 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Damien Miller <djm@mindrot.org>
|
||||
|
@ -55,6 +55,10 @@ struct sshauthopt {
|
|||
size_t npermitopen;
|
||||
char **permitopen;
|
||||
|
||||
/* Permitted listens (remote forwarding) */
|
||||
size_t npermitlisten;
|
||||
char **permitlisten;
|
||||
|
||||
/*
|
||||
* Permitted host/addresses (comma-separated)
|
||||
* Caller must check source address matches both lists (if present).
|
||||
|
|
15
auth.c
15
auth.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: auth.c,v 1.129 2018/06/01 03:33:53 djm Exp $ */
|
||||
/* $OpenBSD: auth.c,v 1.130 2018/06/06 18:23:32 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -1005,17 +1005,20 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
|
|||
int do_env = options.permit_user_env && opts->nenv > 0;
|
||||
int do_permitopen = opts->npermitopen > 0 &&
|
||||
(options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
|
||||
int do_permitlisten = opts->npermitlisten > 0 &&
|
||||
(options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
|
||||
size_t i;
|
||||
char msg[1024], buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
|
||||
/* Try to keep this alphabetically sorted */
|
||||
snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
|
||||
opts->force_command == NULL ? "" : " command",
|
||||
do_env ? " environment" : "",
|
||||
opts->valid_before == 0 ? "" : "expires",
|
||||
do_permitopen ? " permitopen" : "",
|
||||
do_permitlisten ? " permitlisten" : "",
|
||||
opts->permit_port_forwarding_flag ? " port-forwarding" : "",
|
||||
opts->cert_principals == NULL ? "" : " principals",
|
||||
opts->permit_pty_flag ? " pty" : "",
|
||||
|
@ -1049,12 +1052,18 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
|
|||
}
|
||||
if (opts->force_command != NULL)
|
||||
debug("%s: forced command: \"%s\"", loc, opts->force_command);
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
|
||||
if (do_permitopen) {
|
||||
for (i = 0; i < opts->npermitopen; i++) {
|
||||
debug("%s: permitted open: %s",
|
||||
loc, opts->permitopen[i]);
|
||||
}
|
||||
}
|
||||
if (do_permitlisten) {
|
||||
for (i = 0; i < opts->npermitlisten; i++) {
|
||||
debug("%s: permitted listen: %s",
|
||||
loc, opts->permitlisten[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Activate a new set of key/cert options; merging with what is there. */
|
||||
|
|
32
servconf.c
32
servconf.c
|
@ -1,5 +1,5 @@
|
|||
|
||||
/* $OpenBSD: servconf.c,v 1.329 2018/06/06 18:22:41 djm Exp $ */
|
||||
/* $OpenBSD: servconf.c,v 1.330 2018/06/06 18:23:32 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
|
@ -160,7 +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->permitted_listens = NULL;
|
||||
options->adm_forced_command = NULL;
|
||||
options->chroot_directory = NULL;
|
||||
options->authorized_keys_command = NULL;
|
||||
|
@ -463,7 +463,7 @@ typedef enum {
|
|||
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
|
||||
sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
|
||||
sAcceptEnv, sPermitTunnel,
|
||||
sMatch, sPermitOpen, sPermitRemoteOpen, sForceCommand, sChrootDirectory,
|
||||
sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
|
||||
sUsePrivilegeSeparation, sAllowAgentForwarding,
|
||||
sHostCertificate,
|
||||
sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
|
||||
|
@ -598,7 +598,7 @@ static struct {
|
|||
{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
|
||||
{ "match", sMatch, SSHCFG_ALL },
|
||||
{ "permitopen", sPermitOpen, SSHCFG_ALL },
|
||||
{ "permitremoteopen", sPermitRemoteOpen, SSHCFG_ALL },
|
||||
{ "permitlisten", sPermitListen, SSHCFG_ALL },
|
||||
{ "forcecommand", sForceCommand, SSHCFG_ALL },
|
||||
{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
|
||||
{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
|
||||
|
@ -878,9 +878,9 @@ 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);
|
||||
process_permitopen_list(ssh, sPermitListen,
|
||||
options->permitted_listens,
|
||||
options->num_permitted_listens);
|
||||
}
|
||||
|
||||
struct connection_info *
|
||||
|
@ -1831,11 +1831,11 @@ process_server_config_line(ServerOptions *options, char *line,
|
|||
*activep = value;
|
||||
break;
|
||||
|
||||
case sPermitRemoteOpen:
|
||||
case sPermitListen:
|
||||
case sPermitOpen:
|
||||
if (opcode == sPermitRemoteOpen) {
|
||||
uintptr = &options->num_permitted_remote_opens;
|
||||
chararrayptr = &options->permitted_remote_opens;
|
||||
if (opcode == sPermitListen) {
|
||||
uintptr = &options->num_permitted_listens;
|
||||
chararrayptr = &options->permitted_listens;
|
||||
} else {
|
||||
uintptr = &options->num_permitted_opens;
|
||||
chararrayptr = &options->permitted_opens;
|
||||
|
@ -1857,7 +1857,7 @@ process_server_config_line(ServerOptions *options, char *line,
|
|||
for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
|
||||
arg2 = xstrdup(arg);
|
||||
p = hpdelim(&arg);
|
||||
/* XXX support bare port number for PermitRemoteOpen */
|
||||
/* XXX support bare port number for PermitListen */
|
||||
if (p == NULL) {
|
||||
fatal("%s line %d: missing host in %s",
|
||||
filename, linenum,
|
||||
|
@ -2596,12 +2596,12 @@ dump_config(ServerOptions *o)
|
|||
printf(" %s", o->permitted_opens[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("permitremoteopen");
|
||||
if (o->num_permitted_remote_opens == 0)
|
||||
printf("permitlisten");
|
||||
if (o->num_permitted_listens == 0)
|
||||
printf(" any");
|
||||
else {
|
||||
for (i = 0; i < o->num_permitted_remote_opens; i++)
|
||||
printf(" %s", o->permitted_remote_opens[i]);
|
||||
for (i = 0; i < o->num_permitted_listens; i++)
|
||||
printf(" %s", o->permitted_listens[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: servconf.h,v 1.132 2018/06/06 18:22:41 djm Exp $ */
|
||||
/* $OpenBSD: servconf.h,v 1.133 2018/06/06 18:23:32 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -183,8 +183,8 @@ typedef struct {
|
|||
|
||||
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 **permitted_listens; /* May also be one of PERMITOPEN_* */
|
||||
u_int num_permitted_listens;
|
||||
|
||||
char *chroot_directory;
|
||||
char *revoked_keys_file;
|
||||
|
@ -248,8 +248,7 @@ 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); \
|
||||
M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \
|
||||
} while (0)
|
||||
|
||||
struct connection_info *get_connection_info(int, int);
|
||||
|
|
52
session.c
52
session.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: session.c,v 1.296 2018/06/06 18:22:41 djm Exp $ */
|
||||
/* $OpenBSD: session.c,v 1.297 2018/06/06 18:23:32 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
|
@ -290,27 +290,43 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
|
|||
}
|
||||
|
||||
static void
|
||||
set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
|
||||
set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
|
||||
{
|
||||
char *tmp, *cp, *host;
|
||||
int port;
|
||||
size_t i;
|
||||
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
|
||||
return;
|
||||
channel_clear_permission(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 */
|
||||
if ((host = hpdelim(&cp)) == NULL)
|
||||
fatal("%s: internal error: hpdelim", __func__);
|
||||
host = cleanhostname(host);
|
||||
if (cp == NULL || (port = permitopen_port(cp)) < 0)
|
||||
fatal("%s: internal error: permitopen port",
|
||||
__func__);
|
||||
channel_add_permission(ssh, FORWARD_USER, FORWARD_LOCAL,
|
||||
host, port);
|
||||
free(tmp);
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
|
||||
channel_clear_permission(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 */
|
||||
if ((host = hpdelim(&cp)) == NULL)
|
||||
fatal("%s: internal error: hpdelim", __func__);
|
||||
host = cleanhostname(host);
|
||||
if (cp == NULL || (port = permitopen_port(cp)) < 0)
|
||||
fatal("%s: internal error: permitopen port",
|
||||
__func__);
|
||||
channel_add_permission(ssh,
|
||||
FORWARD_USER, FORWARD_LOCAL, host, port);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
|
||||
channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
|
||||
for (i = 0; i < auth_opts->npermitlisten; i++) {
|
||||
tmp = cp = xstrdup(auth_opts->permitlisten[i]);
|
||||
/* This shouldn't fail as it has already been checked */
|
||||
if ((host = hpdelim(&cp)) == NULL)
|
||||
fatal("%s: internal error: hpdelim", __func__);
|
||||
host = cleanhostname(host);
|
||||
if (cp == NULL || (port = permitopen_port(cp)) < 0)
|
||||
fatal("%s: internal error: permitlisten port",
|
||||
__func__);
|
||||
channel_add_permission(ssh,
|
||||
FORWARD_USER, FORWARD_REMOTE, host, port);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +339,7 @@ do_authenticated(struct ssh *ssh, Authctxt *authctxt)
|
|||
|
||||
/* setup the channel layer */
|
||||
/* XXX - streamlocal? */
|
||||
set_permitopen_from_authopts(ssh, auth_opts);
|
||||
set_fwdpermit_from_authopts(ssh, auth_opts);
|
||||
|
||||
if (!auth_opts->permit_port_forwarding_flag ||
|
||||
options.disable_forwarding) {
|
||||
|
|
Loading…
Reference in New Issue