upstream: ssh: add PermitRemoteOpen for remote dynamic forwarding

with SOCKS ok djm@, dtucker@

OpenBSD-Commit-ID: 64fe7b6360acc4ea56aa61b66498b5ecc0a96a7c
This commit is contained in:
markus@openbsd.org 2021-02-15 20:43:15 +00:00 committed by Darren Tucker
parent b696858a7f
commit da0a9afcc4
6 changed files with 170 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.404 2021/01/27 09:26:53 djm Exp $ */
/* $OpenBSD: channels.c,v 1.405 2021/02/15 20:43:15 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -4478,9 +4478,28 @@ rdynamic_connect_prepare(struct ssh *ssh, char *ctype, char *rname)
static int
rdynamic_connect_finish(struct ssh *ssh, Channel *c)
{
struct ssh_channels *sc = ssh->chanctxt;
struct permission_set *pset = &sc->local_perms;
struct permission *perm;
struct channel_connect cctx;
u_int i, permit_adm = 1;
int sock;
if (pset->num_permitted_admin > 0) {
permit_adm = 0;
for (i = 0; i < pset->num_permitted_admin; i++) {
perm = &pset->permitted_admin[i];
if (open_match(perm, c->path, c->host_port)) {
permit_adm = 1;
break;
}
}
}
if (!permit_adm) {
debug_f("requested forward not permitted");
return -1;
}
memset(&cctx, 0, sizeof(cctx));
sock = connect_to_helper(ssh, c->path, c->host_port, SOCK_STREAM, NULL,
NULL, &cctx, NULL, NULL);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.350 2021/01/26 05:32:21 dtucker Exp $ */
/* $OpenBSD: readconf.c,v 1.351 2021/02/15 20:43:15 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -147,6 +147,7 @@ typedef enum {
oPasswordAuthentication,
oChallengeResponseAuthentication, oXAuthLocation,
oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
oPermitRemoteOpen,
oCertificateFile, oAddKeysToAgent, oIdentityAgent,
oUser, oEscapeChar, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
@ -247,6 +248,7 @@ static struct {
{ "macs", oMacs },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
{ "permitremoteopen", oPermitRemoteOpen },
{ "user", oUser },
{ "host", oHost },
{ "match", oMatch },
@ -318,6 +320,7 @@ static struct {
{ NULL, oBadOption }
};
static const char *lookup_opcode_name(OpCodes code);
const char *
kex_default_pk_alg(void)
@ -912,9 +915,9 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
const char *original_host, char *line, const char *filename,
int linenum, int *activep, int flags, int *want_final_pass, int depth)
{
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, *p, ch;
char **cpptr, ***cppptr, fwdarg[256];
u_int i, *uintptr, max_entries = 0;
u_int i, *uintptr, uvalue, max_entries = 0;
int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
int remotefwd, dynamicfwd;
LogLevel *log_level_ptr;
@ -1482,6 +1485,51 @@ parse_pubkey_algos:
}
break;
case oPermitRemoteOpen:
uintptr = &options->num_permitted_remote_opens;
cppptr = &options->permitted_remote_opens;
arg = strdelim(&s);
if (!arg || *arg == '\0')
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 && uvalue == 0) {
*uintptr = 1;
*cppptr = xcalloc(1, sizeof(**cppptr));
(*cppptr)[0] = xstrdup(arg);
}
break;
}
for (; arg != NULL && *arg != '\0'; arg = strdelim(&s)) {
arg2 = xstrdup(arg);
ch = '\0';
p = hpdelim2(&arg, &ch);
if (p == NULL || ch == '/') {
fatal("%s line %d: missing host in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
p = cleanhostname(p);
/*
* don't want to use permitopen_port to avoid
* dependency on channels.[ch] here.
*/
if (arg == NULL ||
(strcmp(arg, "*") != 0 && a2port(arg) <= 0)) {
fatal("%s line %d: bad port number in %s",
filename, linenum,
lookup_opcode_name(opcode));
}
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum,
lookup_opcode_name(opcode),
cppptr, uintptr, arg2);
}
free(arg2);
}
break;
case oClearAllForwardings:
intptr = &options->clear_forwardings;
goto parse_flag;
@ -2173,6 +2221,8 @@ initialize_options(Options * options)
options->num_local_forwards = 0;
options->remote_forwards = NULL;
options->num_remote_forwards = 0;
options->permitted_remote_opens = NULL;
options->num_permitted_remote_opens = 0;
options->log_facility = SYSLOG_FACILITY_NOT_SET;
options->log_level = SYSLOG_LEVEL_NOT_SET;
options->num_log_verbose = 0;
@ -3126,6 +3176,13 @@ dump_client_config(Options *o, const char *host)
/* Special cases */
/* PermitRemoteOpen */
if (o->num_permitted_remote_opens == 0)
printf("%s any\n", lookup_opcode_name(oPermitRemoteOpen));
else
dump_cfg_strarray_oneline(oPermitRemoteOpen,
o->num_permitted_remote_opens, o->permitted_remote_opens);
/* AddKeysToAgent */
if (o->add_keys_to_agent_lifespan <= 0)
dump_cfg_fmtint(oAddKeysToAgent, o->add_keys_to_agent);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.139 2021/01/26 05:32:21 dtucker Exp $ */
/* $OpenBSD: readconf.h,v 1.140 2021/02/15 20:43:15 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -110,6 +110,10 @@ typedef struct {
struct Forward *remote_forwards;
int clear_forwardings;
/* Restrict remote dynamic forwarding */
char **permitted_remote_opens;
u_int num_permitted_remote_opens;
/* stdio forwarding (-W) host and port */
char *stdio_forward_host;
int stdio_forward_port;

5
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.418 2021/01/26 15:40:17 naddy Exp $
.Dd $Mdocdate: January 26 2021 $
.\" $OpenBSD: ssh.1,v 1.419 2021/02/15 20:43:15 markus Exp $
.Dd $Mdocdate: February 15 2021 $
.Dt SSH 1
.Os
.Sh NAME
@ -531,6 +531,7 @@ For full details of the options listed below, and their possible values, see
.It NumberOfPasswordPrompts
.It PasswordAuthentication
.It PermitLocalCommand
.It PermitRemoteOpen
.It PKCS11Provider
.It Port
.It PreferredAuthentications

43
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.550 2021/02/02 22:36:59 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.551 2021/02/15 20:43:15 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1874,12 +1874,53 @@ ssh_init_stdio_forwarding(struct ssh *ssh)
channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL);
}
static void
ssh_init_forward_permissions(struct ssh *ssh, const char *what, char **opens,
u_int num_opens)
{
u_int i;
int port;
char *addr, *arg, *oarg, ch;
int where = FORWARD_LOCAL;
channel_clear_permission(ssh, FORWARD_ADM, where);
if (num_opens == 0)
return; /* permit any */
/* handle keywords: "any" / "none" */
if (num_opens == 1 && strcmp(opens[0], "any") == 0)
return;
if (num_opens == 1 && strcmp(opens[0], "none") == 0) {
channel_disable_admin(ssh, where);
return;
}
/* Otherwise treat it as a list of permitted host:port */
for (i = 0; i < num_opens; i++) {
oarg = arg = xstrdup(opens[i]);
ch = '\0';
addr = hpdelim2(&arg, &ch);
if (addr == NULL || ch == '/')
fatal_f("missing host in %s", what);
addr = cleanhostname(addr);
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
fatal_f("bad port number in %s", what);
/* Send it to channels layer */
channel_add_permission(ssh, FORWARD_ADM,
where, addr, port);
free(oarg);
}
}
static void
ssh_init_forwarding(struct ssh *ssh, char **ifname)
{
int success = 0;
int i;
ssh_init_forward_permissions(ssh, "permitremoteopen",
options.permitted_remote_opens,
options.num_permitted_remote_opens);
if (options.exit_on_forward_failure)
forward_confirms_pending = 0; /* track pending requests */
/* Initiate local TCP/IP port forwardings. */

View File

@ -33,7 +33,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.346 2021/02/15 11:09:22 dlg Exp $
.\" $OpenBSD: ssh_config.5,v 1.347 2021/02/15 20:43:15 markus Exp $
.Dd $Mdocdate: February 15 2021 $
.Dt SSH_CONFIG 5
.Os
@ -1290,6 +1290,42 @@ The argument must be
or
.Cm no
(the default).
.It Cm PermitRemoteOpen
Specifies the destinations to which remote TCP port forwarding is permitted when
.Cm RemoteForward
is used as a SOCKS proxy.
The forwarding specification must be one of the following forms:
.Pp
.Bl -item -offset indent -compact
.It
.Cm PermitRemoteOpen
.Sm off
.Ar host : port
.Sm on
.It
.Cm PermitRemoteOpen
.Sm off
.Ar IPv4_addr : port
.Sm on
.It
.Cm PermitRemoteOpen
.Sm off
.Ar \&[ IPv6_addr \&] : port
.Sm on
.El
.Pp
Multiple forwards may be specified by separating them with whitespace.
An argument of
.Cm any
can be used to remove all restrictions and permit any forwarding requests.
An argument of
.Cm none
can be used to prohibit all forwarding requests.
The wildcard
.Sq *
can be used for host or port to allow all hosts or ports respectively.
Otherwise, no pattern matching or address lookups are performed on supplied
names.
.It Cm PKCS11Provider
Specifies which PKCS#11 provider to use or
.Cm none
@ -1484,6 +1520,9 @@ If forwarding to a specific destination then the second argument must be
or a Unix domain socket path,
otherwise if no destination argument is specified then the remote forwarding
will be established as a SOCKS proxy.
When acting as a SOCKS proxy the destination of the connection can be
restricted by
.Cm PermitRemoteOpen .
.Pp
IPv6 addresses can be specified by enclosing addresses in square brackets.
Multiple forwardings may be specified, and additional