diff options
Diffstat (limited to 'sshsig.c')
-rw-r--r-- | sshsig.c | 114 |
1 files changed, 87 insertions, 27 deletions
@@ -679,56 +679,116 @@ sshsigopt_free(struct sshsigopt *opts) | |||
679 | } | 679 | } |
680 | 680 | ||
681 | static int | 681 | static int |
682 | check_allowed_keys_line(const char *path, u_long linenum, char *line, | 682 | parse_principals_key_and_options(const char *path, u_long linenum, char *line, |
683 | const struct sshkey *sign_key, const char *principal, | 683 | const char *required_principal, char **principalsp, struct sshkey **keyp, |
684 | const char *sig_namespace) | 684 | struct sshsigopt **sigoptsp) |
685 | { | 685 | { |
686 | struct sshkey *found_key = NULL; | 686 | char *opts = NULL, *tmp, *cp, *principals = NULL; |
687 | char *cp, *opts = NULL, *identities = NULL; | ||
688 | int r, found = 0; | ||
689 | const char *reason = NULL; | 687 | const char *reason = NULL; |
690 | struct sshsigopt *sigopts = NULL; | 688 | struct sshsigopt *sigopts = NULL; |
689 | struct sshkey *key = NULL; | ||
690 | int r = SSH_ERR_INTERNAL_ERROR; | ||
691 | 691 | ||
692 | if ((found_key = sshkey_new(KEY_UNSPEC)) == NULL) { | 692 | if (principalsp != NULL) |
693 | error("%s: sshkey_new failed", __func__); | 693 | *principalsp = NULL; |
694 | return SSH_ERR_ALLOC_FAIL; | 694 | if (sigoptsp != NULL) |
695 | } | 695 | *sigoptsp = NULL; |
696 | if (keyp != NULL) | ||
697 | *keyp = NULL; | ||
696 | 698 | ||
697 | /* format: identity[,identity...] [option[,option...]] key */ | ||
698 | cp = line; | 699 | cp = line; |
699 | cp = cp + strspn(cp, " \t"); /* skip leading whitespace */ | 700 | cp = cp + strspn(cp, " \t"); /* skip leading whitespace */ |
700 | if (*cp == '#' || *cp == '\0') | 701 | if (*cp == '#' || *cp == '\0') |
701 | goto done; | 702 | return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */ |
702 | if ((identities = strdelimw(&cp)) == NULL) { | 703 | |
704 | /* format: identity[,identity...] [option[,option...]] key */ | ||
705 | if ((tmp = strdelimw(&cp)) == NULL) { | ||
703 | error("%s:%lu: invalid line", path, linenum); | 706 | error("%s:%lu: invalid line", path, linenum); |
704 | goto done; | 707 | r = SSH_ERR_INVALID_FORMAT; |
708 | goto out; | ||
705 | } | 709 | } |
706 | if (match_pattern_list(principal, identities, 0) != 1) { | 710 | if ((principals = strdup(tmp)) == NULL) { |
707 | /* principal didn't match */ | 711 | error("%s: strdup failed", __func__); |
708 | goto done; | 712 | r = SSH_ERR_ALLOC_FAIL; |
713 | goto out; | ||
714 | } | ||
715 | /* | ||
716 | * Bail out early if we're looking for a particular principal and this | ||
717 | * line does not list it. | ||
718 | */ | ||
719 | if (required_principal != NULL) { | ||
720 | if (match_pattern_list(required_principal, | ||
721 | principals, 0) != 1) { | ||
722 | /* principal didn't match */ | ||
723 | r = SSH_ERR_KEY_NOT_FOUND; | ||
724 | goto out; | ||
725 | } | ||
726 | debug("%s: %s:%lu: matched principal \"%s\"", | ||
727 | __func__, path, linenum, required_principal); | ||
709 | } | 728 | } |
710 | debug("%s: %s:%lu: matched principal \"%s\"", | ||
711 | __func__, path, linenum, principal); | ||
712 | 729 | ||
713 | if (sshkey_read(found_key, &cp) != 0) { | 730 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) { |
731 | error("%s: sshkey_new failed", __func__); | ||
732 | r = SSH_ERR_ALLOC_FAIL; | ||
733 | goto out; | ||
734 | } | ||
735 | if (sshkey_read(key, &cp) != 0) { | ||
714 | /* no key? Check for options */ | 736 | /* no key? Check for options */ |
715 | opts = cp; | 737 | opts = cp; |
716 | if (sshkey_advance_past_options(&cp) != 0) { | 738 | if (sshkey_advance_past_options(&cp) != 0) { |
717 | error("%s:%lu: invalid options", | 739 | error("%s:%lu: invalid options", path, linenum); |
718 | path, linenum); | 740 | r = SSH_ERR_INVALID_FORMAT; |
719 | goto done; | 741 | goto out; |
720 | } | 742 | } |
721 | *cp++ = '\0'; | 743 | *cp++ = '\0'; |
722 | skip_space(&cp); | 744 | skip_space(&cp); |
723 | if (sshkey_read(found_key, &cp) != 0) { | 745 | if (sshkey_read(key, &cp) != 0) { |
724 | error("%s:%lu: invalid key", path, | 746 | error("%s:%lu: invalid key", path, linenum); |
725 | linenum); | 747 | r = SSH_ERR_INVALID_FORMAT; |
726 | goto done; | 748 | goto out; |
727 | } | 749 | } |
728 | } | 750 | } |
729 | debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts); | 751 | debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts); |
730 | if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) { | 752 | if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) { |
731 | error("%s:%lu: bad options: %s", path, linenum, reason); | 753 | error("%s:%lu: bad options: %s", path, linenum, reason); |
754 | r = SSH_ERR_INVALID_FORMAT; | ||
755 | goto out; | ||
756 | } | ||
757 | /* success */ | ||
758 | if (principalsp != NULL) { | ||
759 | *principalsp = principals; | ||
760 | principals = NULL; /* transferred */ | ||
761 | } | ||
762 | if (sigoptsp != NULL) { | ||
763 | *sigoptsp = sigopts; | ||
764 | sigopts = NULL; /* transferred */ | ||
765 | } | ||
766 | if (keyp != NULL) { | ||
767 | *keyp = key; | ||
768 | key = NULL; /* transferred */ | ||
769 | } | ||
770 | r = 0; | ||
771 | out: | ||
772 | free(principals); | ||
773 | sshsigopt_free(sigopts); | ||
774 | sshkey_free(key); | ||
775 | return r; | ||
776 | } | ||
777 | |||
778 | static int | ||
779 | check_allowed_keys_line(const char *path, u_long linenum, char *line, | ||
780 | const struct sshkey *sign_key, const char *principal, | ||
781 | const char *sig_namespace) | ||
782 | { | ||
783 | struct sshkey *found_key = NULL; | ||
784 | int r, found = 0; | ||
785 | const char *reason = NULL; | ||
786 | struct sshsigopt *sigopts = NULL; | ||
787 | |||
788 | /* Parse the line */ | ||
789 | if ((r = parse_principals_key_and_options(path, linenum, line, | ||
790 | principal, NULL, &found_key, &sigopts)) != 0) { | ||
791 | /* error already logged */ | ||
732 | goto done; | 792 | goto done; |
733 | } | 793 | } |
734 | 794 | ||