summaryrefslogtreecommitdiff
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@
OpenBSD-Commit-ID: 8650883018d7aa893173d703379e4456a222c672
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 ef57ebf43..c55c3ed06 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth-options.c,v 1.79 2018/04/06 04:15:45 djm Exp $ */ 1/* $OpenBSD: auth-options.c,v 1.80 2018/06/06 18:23:32 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2018 Damien Miller <djm@mindrot.org> 3 * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
4 * 4 *
@@ -283,6 +283,10 @@ sshauthopt_free(struct sshauthopt *opts)
283 free(opts->permitopen[i]); 283 free(opts->permitopen[i]);
284 free(opts->permitopen); 284 free(opts->permitopen);
285 285
286 for (i = 0; i < opts->npermitlisten; i++)
287 free(opts->permitlisten[i]);
288 free(opts->permitlisten);
289
286 explicit_bzero(opts, sizeof(*opts)); 290 explicit_bzero(opts, sizeof(*opts));
287 free(opts); 291 free(opts);
288} 292}
@@ -304,10 +308,70 @@ sshauthopt_new_with_keys_defaults(void)
304 return ret; 308 return ret;
305} 309}
306 310
311/*
312 * Parse and record a permitopen/permitlisten directive.
313 * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
314 */
315static int
316handle_permit(const char *opts, char ***permitsp, size_t *npermitsp,
317 const char **errstrp)
318{
319 char *opt, *tmp, *cp, *host, **permits = *permitsp;
320 size_t npermits = *npermitsp;
321 const char *errstr = "unknown error";
322
323 if (npermits > INT_MAX) {
324 *errstrp = "too many permission directives";
325 return -1;
326 }
327 if ((opt = opt_dequote(&opts, &errstr)) == NULL) {
328 return -1;
329 }
330 if ((tmp = strdup(opt)) == NULL) {
331 free(opt);
332 *errstrp = "memory allocation failed";
333 return -1;
334 }
335 cp = tmp;
336 /* validate syntax before recording it. */
337 host = hpdelim(&cp);
338 if (host == NULL || strlen(host) >= NI_MAXHOST) {
339 free(tmp);
340 free(opt);
341 *errstrp = "invalid permission hostname";
342 return -1;
343 }
344 /*
345 * don't want to use permitopen_port to avoid
346 * dependency on channels.[ch] here.
347 */
348 if (cp == NULL ||
349 (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
350 free(tmp);
351 free(opt);
352 *errstrp = "invalid permission port";
353 return -1;
354 }
355 /* XXX - add streamlocal support */
356 free(tmp);
357 /* Record it */
358 if ((permits = recallocarray(permits, npermits, npermits + 1,
359 sizeof(*permits))) == NULL) {
360 free(opt);
361 /* NB. don't update *permitsp if alloc fails */
362 *errstrp = "memory allocation failed";
363 return -1;
364 }
365 permits[npermits++] = opt;
366 *permitsp = permits;
367 *npermitsp = npermits;
368 return 0;
369}
370
307struct sshauthopt * 371struct sshauthopt *
308sshauthopt_parse(const char *opts, const char **errstrp) 372sshauthopt_parse(const char *opts, const char **errstrp)
309{ 373{
310 char **oarray, *opt, *cp, *tmp, *host; 374 char **oarray, *opt, *cp, *tmp;
311 int r; 375 int r;
312 struct sshauthopt *ret = NULL; 376 struct sshauthopt *ret = NULL;
313 const char *errstr = "unknown error"; 377 const char *errstr = "unknown error";
@@ -410,48 +474,13 @@ sshauthopt_parse(const char *opts, const char **errstrp)
410 } 474 }
411 ret->env[ret->nenv++] = opt; 475 ret->env[ret->nenv++] = opt;
412 } else if (opt_match(&opts, "permitopen")) { 476 } else if (opt_match(&opts, "permitopen")) {
413 if (ret->npermitopen > INT_MAX) { 477 if (handle_permit(opts, &ret->permitopen,
414 errstr = "too many permitopens"; 478 &ret->npermitopen, &errstr) != 0)
415 goto fail;
416 }
417 if ((opt = opt_dequote(&opts, &errstr)) == NULL)
418 goto fail;
419 if ((tmp = strdup(opt)) == NULL) {
420 free(opt);
421 goto alloc_fail;
422 }
423 cp = tmp;
424 /* validate syntax of permitopen before recording it. */
425 host = hpdelim(&cp);
426 if (host == NULL || strlen(host) >= NI_MAXHOST) {
427 free(tmp);
428 free(opt);
429 errstr = "invalid permitopen hostname";
430 goto fail; 479 goto fail;
431 } 480 } else if (opt_match(&opts, "permitlisten")) {
432 /* 481 if (handle_permit(opts, &ret->permitlisten,
433 * don't want to use permitopen_port to avoid 482 &ret->npermitlisten, &errstr) != 0)
434 * dependency on channels.[ch] here.
435 */
436 if (cp == NULL ||
437 (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
438 free(tmp);
439 free(opt);
440 errstr = "invalid permitopen port";
441 goto fail; 483 goto fail;
442 }
443 /* XXX - add streamlocal support */
444 free(tmp);
445 /* Record it */
446 oarray = ret->permitopen;
447 if ((ret->permitopen = recallocarray(ret->permitopen,
448 ret->npermitopen, ret->npermitopen + 1,
449 sizeof(*ret->permitopen))) == NULL) {
450 free(opt);
451 ret->permitopen = oarray;
452 goto alloc_fail;
453 }
454 ret->permitopen[ret->npermitopen++] = opt;
455 } else if (opt_match(&opts, "tunnel")) { 484 } else if (opt_match(&opts, "tunnel")) {
456 if ((opt = opt_dequote(&opts, &errstr)) == NULL) 485 if ((opt = opt_dequote(&opts, &errstr)) == NULL)
457 goto fail; 486 goto fail;
@@ -554,7 +583,10 @@ sshauthopt_merge(const struct sshauthopt *primary,
554 if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL) 583 if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
555 goto alloc_fail; 584 goto alloc_fail;
556 585
557 /* force_tun_device, permitopen and environment prefer the primary. */ 586 /*
587 * force_tun_device, permitopen/permitlisten and environment all
588 * prefer the primary.
589 */
558 ret->force_tun_device = primary->force_tun_device; 590 ret->force_tun_device = primary->force_tun_device;
559 if (ret->force_tun_device == -1) 591 if (ret->force_tun_device == -1)
560 ret->force_tun_device = additional->force_tun_device; 592 ret->force_tun_device = additional->force_tun_device;
@@ -577,6 +609,16 @@ sshauthopt_merge(const struct sshauthopt *primary,
577 goto alloc_fail; 609 goto alloc_fail;
578 } 610 }
579 611
612 if (primary->npermitlisten > 0) {
613 if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
614 primary->permitlisten, primary->npermitlisten) != 0)
615 goto alloc_fail;
616 } else if (additional->npermitlisten > 0) {
617 if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
618 additional->permitlisten, additional->npermitlisten) != 0)
619 goto alloc_fail;
620 }
621
580 /* Flags are logical-AND (i.e. must be set in both for permission) */ 622 /* Flags are logical-AND (i.e. must be set in both for permission) */
581#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1) 623#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1)
582 OPTFLAG(permit_port_forwarding_flag); 624 OPTFLAG(permit_port_forwarding_flag);
@@ -669,7 +711,9 @@ sshauthopt_copy(const struct sshauthopt *orig)
669 711
670 if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 || 712 if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
671 dup_strings(&ret->permitopen, &ret->npermitopen, 713 dup_strings(&ret->permitopen, &ret->npermitopen,
672 orig->permitopen, orig->npermitopen) != 0) { 714 orig->permitopen, orig->npermitopen) != 0 ||
715 dup_strings(&ret->permitlisten, &ret->npermitlisten,
716 orig->permitlisten, orig->npermitlisten) != 0) {
673 sshauthopt_free(ret); 717 sshauthopt_free(ret);
674 return NULL; 718 return NULL;
675 } 719 }
@@ -805,7 +849,9 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
805 if ((r = serialise_array(m, opts->env, 849 if ((r = serialise_array(m, opts->env,
806 untrusted ? 0 : opts->nenv)) != 0 || 850 untrusted ? 0 : opts->nenv)) != 0 ||
807 (r = serialise_array(m, opts->permitopen, 851 (r = serialise_array(m, opts->permitopen,
808 untrusted ? 0 : opts->npermitopen)) != 0) 852 untrusted ? 0 : opts->npermitopen)) ||
853 (r = serialise_array(m, opts->permitlisten,
854 untrusted ? 0 : opts->npermitlisten)) != 0)
809 return r; 855 return r;
810 856
811 /* success */ 857 /* success */
@@ -859,7 +905,9 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
859 /* Array options */ 905 /* Array options */
860 if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 || 906 if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
861 (r = deserialise_array(m, 907 (r = deserialise_array(m,
862 &opts->permitopen, &opts->npermitopen)) != 0) 908 &opts->permitopen, &opts->npermitopen)) != 0 ||
909 (r = deserialise_array(m,
910 &opts->permitlisten, &opts->npermitlisten)) != 0)
863 goto out; 911 goto out;
864 912
865 /* success */ 913 /* success */