diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-06-06 20:23:32 +0200 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-06-06 20:27:20 +0200 |
commit | 93c06ab6b77514e0447fe4f1d822afcbb2a9be08 (patch) | |
tree | 86b19179eaa51962f0dae9ab02d6d37197942265 /auth-options.c | |
parent | upstream: Add a PermitListen directive to control which server-side (diff) | |
download | openssh-93c06ab6b77514e0447fe4f1d822afcbb2a9be08.tar.xz openssh-93c06ab6b77514e0447fe4f1d822afcbb2a9be08.zip |
upstream: permitlisten option for authorized_keys; ok markus@
OpenBSD-Commit-ID: 8650883018d7aa893173d703379e4456a222c672
Diffstat (limited to 'auth-options.c')
-rw-r--r-- | auth-options.c | 140 |
1 files changed, 94 insertions, 46 deletions
diff --git a/auth-options.c b/auth-options.c index ef57ebf43..c55c3ed06 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 */ |