diff options
Diffstat (limited to 'auth-options.c')
-rw-r--r-- | auth-options.c | 282 |
1 files changed, 180 insertions, 102 deletions
diff --git a/auth-options.c b/auth-options.c index 57a67ec79..a7040247f 100644 --- a/auth-options.c +++ b/auth-options.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth-options.c,v 1.51 2010/05/07 11:30:29 djm Exp $ */ | 1 | /* $OpenBSD: auth-options.c,v 1.52 2010/05/20 23:46:02 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -417,32 +417,31 @@ bad_option: | |||
417 | return 0; | 417 | return 0; |
418 | } | 418 | } |
419 | 419 | ||
420 | /* | 420 | #define OPTIONS_CRITICAL 1 |
421 | * Set options from critical certificate options. These supersede user key | 421 | #define OPTIONS_EXTENSIONS 2 |
422 | * options so this must be called after auth_parse_options(). | 422 | static int |
423 | */ | 423 | parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, |
424 | int | 424 | u_int which, int crit, |
425 | auth_cert_options(Key *k, struct passwd *pw) | 425 | int *cert_no_port_forwarding_flag, |
426 | int *cert_no_agent_forwarding_flag, | ||
427 | int *cert_no_x11_forwarding_flag, | ||
428 | int *cert_no_pty_flag, | ||
429 | int *cert_no_user_rc, | ||
430 | char **cert_forced_command, | ||
431 | int *cert_source_address_done) | ||
426 | { | 432 | { |
433 | char *command, *allowed; | ||
434 | const char *remote_ip; | ||
427 | u_char *name = NULL, *data_blob = NULL; | 435 | u_char *name = NULL, *data_blob = NULL; |
428 | u_int nlen, dlen, clen; | 436 | u_int nlen, dlen, clen; |
429 | Buffer c, data; | 437 | Buffer c, data; |
430 | int ret = -1; | 438 | int ret = -1, found; |
431 | |||
432 | int cert_no_port_forwarding_flag = 1; | ||
433 | int cert_no_agent_forwarding_flag = 1; | ||
434 | int cert_no_x11_forwarding_flag = 1; | ||
435 | int cert_no_pty_flag = 1; | ||
436 | int cert_no_user_rc = 1; | ||
437 | char *cert_forced_command = NULL; | ||
438 | int cert_source_address_done = 0; | ||
439 | 439 | ||
440 | buffer_init(&data); | 440 | buffer_init(&data); |
441 | 441 | ||
442 | /* Make copy to avoid altering original */ | 442 | /* Make copy to avoid altering original */ |
443 | buffer_init(&c); | 443 | buffer_init(&c); |
444 | buffer_append(&c, | 444 | buffer_append(&c, optblob, optblob_len); |
445 | buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical)); | ||
446 | 445 | ||
447 | while (buffer_len(&c) > 0) { | 446 | while (buffer_len(&c) > 0) { |
448 | if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || | 447 | if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || |
@@ -451,90 +450,114 @@ auth_cert_options(Key *k, struct passwd *pw) | |||
451 | goto out; | 450 | goto out; |
452 | } | 451 | } |
453 | buffer_append(&data, data_blob, dlen); | 452 | buffer_append(&data, data_blob, dlen); |
454 | debug3("found certificate constraint \"%.100s\" len %u", | 453 | debug3("found certificate option \"%.100s\" len %u", |
455 | name, dlen); | 454 | name, dlen); |
456 | if (strlen(name) != nlen) { | 455 | if (strlen(name) != nlen) { |
457 | error("Certificate constraint name contains \\0"); | 456 | error("Certificate constraint name contains \\0"); |
458 | goto out; | 457 | goto out; |
459 | } | 458 | } |
460 | if (strcmp(name, "permit-X11-forwarding") == 0) | 459 | found = 0; |
461 | cert_no_x11_forwarding_flag = 0; | 460 | if ((which & OPTIONS_EXTENSIONS) != 0) { |
462 | else if (strcmp(name, "permit-agent-forwarding") == 0) | 461 | if (strcmp(name, "permit-X11-forwarding") == 0) { |
463 | cert_no_agent_forwarding_flag = 0; | 462 | *cert_no_x11_forwarding_flag = 0; |
464 | else if (strcmp(name, "permit-port-forwarding") == 0) | 463 | found = 1; |
465 | cert_no_port_forwarding_flag = 0; | 464 | } else if (strcmp(name, |
466 | else if (strcmp(name, "permit-pty") == 0) | 465 | "permit-agent-forwarding") == 0) { |
467 | cert_no_pty_flag = 0; | 466 | *cert_no_agent_forwarding_flag = 0; |
468 | else if (strcmp(name, "permit-user-rc") == 0) | 467 | found = 1; |
469 | cert_no_user_rc = 0; | 468 | } else if (strcmp(name, |
470 | else if (strcmp(name, "force-command") == 0) { | 469 | "permit-port-forwarding") == 0) { |
471 | char *command = buffer_get_string_ret(&data, &clen); | 470 | *cert_no_port_forwarding_flag = 0; |
472 | 471 | found = 1; | |
473 | if (command == NULL) { | 472 | } else if (strcmp(name, "permit-pty") == 0) { |
474 | error("Certificate constraint \"%s\" corrupt", | 473 | *cert_no_pty_flag = 0; |
475 | name); | 474 | found = 1; |
476 | goto out; | 475 | } else if (strcmp(name, "permit-user-rc") == 0) { |
477 | } | 476 | *cert_no_user_rc = 0; |
478 | if (strlen(command) != clen) { | 477 | found = 1; |
479 | error("force-command constraint contains \\0"); | ||
480 | goto out; | ||
481 | } | ||
482 | if (cert_forced_command != NULL) { | ||
483 | error("Certificate has multiple " | ||
484 | "force-command options"); | ||
485 | xfree(command); | ||
486 | goto out; | ||
487 | } | ||
488 | cert_forced_command = command; | ||
489 | } else if (strcmp(name, "source-address") == 0) { | ||
490 | char *allowed = buffer_get_string_ret(&data, &clen); | ||
491 | const char *remote_ip = get_remote_ipaddr(); | ||
492 | |||
493 | if (allowed == NULL) { | ||
494 | error("Certificate constraint \"%s\" corrupt", | ||
495 | name); | ||
496 | goto out; | ||
497 | } | ||
498 | if (strlen(allowed) != clen) { | ||
499 | error("source-address constraint contains \\0"); | ||
500 | goto out; | ||
501 | } | 478 | } |
502 | if (cert_source_address_done++) { | 479 | } |
503 | error("Certificate has multiple " | 480 | if (!found && (which & OPTIONS_CRITICAL) != 0) { |
504 | "source-address options"); | 481 | if (strcmp(name, "force-command") == 0) { |
505 | xfree(allowed); | 482 | if ((command = buffer_get_string_ret(&data, |
506 | goto out; | 483 | &clen)) == NULL) { |
484 | error("Certificate constraint \"%s\" " | ||
485 | "corrupt", name); | ||
486 | goto out; | ||
487 | } | ||
488 | if (strlen(command) != clen) { | ||
489 | error("force-command constraint " | ||
490 | "contains \\0"); | ||
491 | goto out; | ||
492 | } | ||
493 | if (*cert_forced_command != NULL) { | ||
494 | error("Certificate has multiple " | ||
495 | "force-command options"); | ||
496 | xfree(command); | ||
497 | goto out; | ||
498 | } | ||
499 | *cert_forced_command = command; | ||
500 | found = 1; | ||
507 | } | 501 | } |
508 | switch (addr_match_cidr_list(remote_ip, allowed)) { | 502 | if (strcmp(name, "source-address") == 0) { |
509 | case 1: | 503 | if ((allowed = buffer_get_string_ret(&data, |
510 | /* accepted */ | 504 | &clen)) == NULL) { |
511 | xfree(allowed); | 505 | error("Certificate constraint " |
512 | break; | 506 | "\"%s\" corrupt", name); |
513 | case 0: | 507 | goto out; |
514 | /* no match */ | 508 | } |
515 | logit("Authentication tried for %.100s with " | 509 | if (strlen(allowed) != clen) { |
516 | "valid certificate but not from a " | 510 | error("source-address constraint " |
517 | "permitted host (ip=%.200s).", | 511 | "contains \\0"); |
518 | pw->pw_name, remote_ip); | 512 | goto out; |
519 | auth_debug_add("Your address '%.200s' is not " | 513 | } |
520 | "permitted to use this certificate for " | 514 | if ((*cert_source_address_done)++) { |
521 | "login.", remote_ip); | 515 | error("Certificate has multiple " |
522 | xfree(allowed); | 516 | "source-address options"); |
523 | goto out; | 517 | xfree(allowed); |
524 | case -1: | 518 | goto out; |
525 | error("Certificate source-address contents " | 519 | } |
526 | "invalid"); | 520 | remote_ip = get_remote_ipaddr(); |
527 | xfree(allowed); | 521 | switch (addr_match_cidr_list(remote_ip, |
528 | goto out; | 522 | allowed)) { |
523 | case 1: | ||
524 | /* accepted */ | ||
525 | xfree(allowed); | ||
526 | break; | ||
527 | case 0: | ||
528 | /* no match */ | ||
529 | logit("Authentication tried for %.100s " | ||
530 | "with valid certificate but not " | ||
531 | "from a permitted host " | ||
532 | "(ip=%.200s).", pw->pw_name, | ||
533 | remote_ip); | ||
534 | auth_debug_add("Your address '%.200s' " | ||
535 | "is not permitted to use this " | ||
536 | "certificate for login.", | ||
537 | remote_ip); | ||
538 | xfree(allowed); | ||
539 | goto out; | ||
540 | case -1: | ||
541 | error("Certificate source-address " | ||
542 | "contents invalid"); | ||
543 | xfree(allowed); | ||
544 | goto out; | ||
545 | } | ||
546 | found = 1; | ||
529 | } | 547 | } |
530 | } else { | ||
531 | error("Certificate constraint \"%s\" is not supported", | ||
532 | name); | ||
533 | goto out; | ||
534 | } | 548 | } |
535 | 549 | ||
536 | if (buffer_len(&data) != 0) { | 550 | if (!found) { |
537 | error("Certificate constraint \"%s\" corrupt " | 551 | if (crit) { |
552 | error("Certificate critical option \"%s\" " | ||
553 | "is not supported", name); | ||
554 | goto out; | ||
555 | } else { | ||
556 | logit("Certificate extension \"%s\" " | ||
557 | "is not supported", name); | ||
558 | } | ||
559 | } else if (buffer_len(&data) != 0) { | ||
560 | error("Certificate option \"%s\" corrupt " | ||
538 | "(extra data)", name); | 561 | "(extra data)", name); |
539 | goto out; | 562 | goto out; |
540 | } | 563 | } |
@@ -543,10 +566,73 @@ auth_cert_options(Key *k, struct passwd *pw) | |||
543 | xfree(data_blob); | 566 | xfree(data_blob); |
544 | name = data_blob = NULL; | 567 | name = data_blob = NULL; |
545 | } | 568 | } |
546 | |||
547 | /* successfully parsed all options */ | 569 | /* successfully parsed all options */ |
548 | ret = 0; | 570 | ret = 0; |
549 | 571 | ||
572 | out: | ||
573 | if (ret != 0 && | ||
574 | cert_forced_command != NULL && | ||
575 | *cert_forced_command != NULL) { | ||
576 | xfree(*cert_forced_command); | ||
577 | *cert_forced_command = NULL; | ||
578 | } | ||
579 | if (name != NULL) | ||
580 | xfree(name); | ||
581 | if (data_blob != NULL) | ||
582 | xfree(data_blob); | ||
583 | buffer_free(&data); | ||
584 | buffer_free(&c); | ||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * Set options from critical certificate options. These supersede user key | ||
590 | * options so this must be called after auth_parse_options(). | ||
591 | */ | ||
592 | int | ||
593 | auth_cert_options(Key *k, struct passwd *pw) | ||
594 | { | ||
595 | int cert_no_port_forwarding_flag = 1; | ||
596 | int cert_no_agent_forwarding_flag = 1; | ||
597 | int cert_no_x11_forwarding_flag = 1; | ||
598 | int cert_no_pty_flag = 1; | ||
599 | int cert_no_user_rc = 1; | ||
600 | char *cert_forced_command = NULL; | ||
601 | int cert_source_address_done = 0; | ||
602 | |||
603 | if (key_cert_is_legacy(k)) { | ||
604 | /* All options are in the one field for v00 certs */ | ||
605 | if (parse_option_list(buffer_ptr(&k->cert->critical), | ||
606 | buffer_len(&k->cert->critical), pw, | ||
607 | OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1, | ||
608 | &cert_no_port_forwarding_flag, | ||
609 | &cert_no_agent_forwarding_flag, | ||
610 | &cert_no_x11_forwarding_flag, | ||
611 | &cert_no_pty_flag, | ||
612 | &cert_no_user_rc, | ||
613 | &cert_forced_command, | ||
614 | &cert_source_address_done) == -1) | ||
615 | return -1; | ||
616 | } else { | ||
617 | /* Separate options and extensions for v01 certs */ | ||
618 | if (parse_option_list(buffer_ptr(&k->cert->critical), | ||
619 | buffer_len(&k->cert->critical), pw, | ||
620 | OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL, | ||
621 | &cert_forced_command, | ||
622 | &cert_source_address_done) == -1) | ||
623 | return -1; | ||
624 | if (parse_option_list(buffer_ptr(&k->cert->extensions), | ||
625 | buffer_len(&k->cert->extensions), pw, | ||
626 | OPTIONS_EXTENSIONS, 1, | ||
627 | &cert_no_port_forwarding_flag, | ||
628 | &cert_no_agent_forwarding_flag, | ||
629 | &cert_no_x11_forwarding_flag, | ||
630 | &cert_no_pty_flag, | ||
631 | &cert_no_user_rc, | ||
632 | NULL, NULL) == -1) | ||
633 | return -1; | ||
634 | } | ||
635 | |||
550 | no_port_forwarding_flag |= cert_no_port_forwarding_flag; | 636 | no_port_forwarding_flag |= cert_no_port_forwarding_flag; |
551 | no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; | 637 | no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; |
552 | no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; | 638 | no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; |
@@ -558,14 +644,6 @@ auth_cert_options(Key *k, struct passwd *pw) | |||
558 | xfree(forced_command); | 644 | xfree(forced_command); |
559 | forced_command = cert_forced_command; | 645 | forced_command = cert_forced_command; |
560 | } | 646 | } |
561 | 647 | return 0; | |
562 | out: | ||
563 | if (name != NULL) | ||
564 | xfree(name); | ||
565 | if (data_blob != NULL) | ||
566 | xfree(data_blob); | ||
567 | buffer_free(&data); | ||
568 | buffer_free(&c); | ||
569 | return ret; | ||
570 | } | 648 | } |
571 | 649 | ||