summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/channels.c21
-rw-r--r--usr.bin/ssh/readconf.c63
-rw-r--r--usr.bin/ssh/readconf.h6
-rw-r--r--usr.bin/ssh/ssh.15
-rw-r--r--usr.bin/ssh/ssh.c43
-rw-r--r--usr.bin/ssh/ssh_config.541
6 files changed, 170 insertions, 9 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 06a3cc0da33..4f55aa47b0e 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -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
@@ -4437,9 +4437,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);
diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c
index e42b4b0d4aa..baf9414c38a 100644
--- a/usr.bin/ssh/readconf.c
+++ b/usr.bin/ssh/readconf.c
@@ -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
@@ -133,6 +133,7 @@ typedef enum {
oPasswordAuthentication,
oChallengeResponseAuthentication, oXAuthLocation,
oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
+ oPermitRemoteOpen,
oCertificateFile, oAddKeysToAgent, oIdentityAgent,
oUser, oEscapeChar, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
@@ -233,6 +234,7 @@ static struct {
{ "macs", oMacs },
{ "remoteforward", oRemoteForward },
{ "localforward", oLocalForward },
+ { "permitremoteopen", oPermitRemoteOpen },
{ "user", oUser },
{ "host", oHost },
{ "match", oMatch },
@@ -304,6 +306,7 @@ static struct {
{ NULL, oBadOption }
};
+static const char *lookup_opcode_name(OpCodes code);
const char *
kex_default_pk_alg(void)
@@ -898,9 +901,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;
@@ -1468,6 +1471,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;
@@ -2159,6 +2207,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;
@@ -3105,6 +3155,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);
diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h
index 6e7e95e7fbf..2fba866eb53 100644
--- a/usr.bin/ssh/readconf.h
+++ b/usr.bin/ssh/readconf.h
@@ -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;
diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1
index 5884b471ffc..0a01767ed9a 100644
--- a/usr.bin/ssh/ssh.1
+++ b/usr.bin/ssh/ssh.1
@@ -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
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index c5440d40525..448934dc143 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -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
@@ -1854,11 +1854,52 @@ ssh_init_stdio_forwarding(struct ssh *ssh)
}
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. */
diff --git a/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5
index 29a199cbfe5..99e7033f661 100644
--- a/usr.bin/ssh/ssh_config.5
+++ b/usr.bin/ssh/ssh_config.5
@@ -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
@@ -1291,6 +1291,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
@@ -1485,6 +1521,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