diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-06-06 18:23:32 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-06-07 04:27:20 +1000 |
commit | 93c06ab6b77514e0447fe4f1d822afcbb2a9be08 (patch) | |
tree | 86b19179eaa51962f0dae9ab02d6d37197942265 /auth-options.c | |
parent | 115063a6647007286cc8ca70abfd2a7585f26ccc (diff) |
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 @@ | |||
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 | */ | ||
315 | static int | ||
316 | handle_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 | |||
307 | struct sshauthopt * | 371 | struct sshauthopt * |
308 | sshauthopt_parse(const char *opts, const char **errstrp) | 372 | sshauthopt_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 */ |