summaryrefslogtreecommitdiffstats
path: root/auth-options.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2018-06-06 18:23:32 +0000
committerDamien Miller <djm@mindrot.org>2018-06-07 04:27:20 +1000
commit93c06ab6b77514e0447fe4f1d822afcbb2a9be08 (patch)
tree86b19179eaa51962f0dae9ab02d6d37197942265 /auth-options.c
parent115063a6647007286cc8ca70abfd2a7585f26ccc (diff)
upstream: permitlisten option for authorized_keys; ok markus@
Diffstat (limited to 'auth-options.c')
-rw-r--r--auth-options.c140
1 files changed, 94 insertions, 46 deletions
diff --git a/auth-options.c b/auth-options.c
index ef57ebf4..c55c3ed0 100644
--- a/auth-options.c
+++ b/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";
- goto fail;
- }
- if ((opt = opt_dequote(&opts, &errstr)) == NULL)
- 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";
+ if (handle_permit(opts, &ret->permitopen,
+ &ret->npermitopen, &errstr) != 0)
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";
+ } else if (opt_match(&opts, "permitlisten")) {
+ if (handle_permit(opts, &ret->permitlisten,
+ &ret->npermitlisten, &errstr) != 0)
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 */