]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: factor out parsing of allowed-signers lines
authordjm@openbsd.org <djm@openbsd.org>
Wed, 22 Jan 2020 02:25:21 +0000 (02:25 +0000)
committerDamien Miller <djm@mindrot.org>
Wed, 22 Jan 2020 06:17:51 +0000 (17:17 +1100)
OpenBSD-Commit-ID: 85ee6aeff608371826019ea85e55bfa87f79d06e

sshsig.c

index abba3f67b447be4fce685793d3f5bf8e23fdfda7..6d72f92f5f1f07747cf73cf44c24bc6006516e08 100644 (file)
--- a/sshsig.c
+++ b/sshsig.c
@@ -679,56 +679,116 @@ sshsigopt_free(struct sshsigopt *opts)
 }
 
 static int
-check_allowed_keys_line(const char *path, u_long linenum, char *line,
-    const struct sshkey *sign_key, const char *principal,
-    const char *sig_namespace)
+parse_principals_key_and_options(const char *path, u_long linenum, char *line,
+    const char *required_principal, char **principalsp, struct sshkey **keyp,
+    struct sshsigopt **sigoptsp)
 {
-       struct sshkey *found_key = NULL;
-       char *cp, *opts = NULL, *identities = NULL;
-       int r, found = 0;
+       char *opts = NULL, *tmp, *cp, *principals = NULL;
        const char *reason = NULL;
        struct sshsigopt *sigopts = NULL;
+       struct sshkey *key = NULL;
+       int r = SSH_ERR_INTERNAL_ERROR;
 
-       if ((found_key = sshkey_new(KEY_UNSPEC)) == NULL) {
-               error("%s: sshkey_new failed", __func__);
-               return SSH_ERR_ALLOC_FAIL;
-       }
+       if (principalsp != NULL)
+               *principalsp = NULL;
+       if (sigoptsp != NULL)
+               *sigoptsp = NULL;
+       if (keyp != NULL)
+               *keyp = NULL;
 
-       /* format: identity[,identity...] [option[,option...]] key */
        cp = line;
        cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
        if (*cp == '#' || *cp == '\0')
-               goto done;
-       if ((identities = strdelimw(&cp)) == NULL) {
+               return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
+
+       /* format: identity[,identity...] [option[,option...]] key */
+       if ((tmp = strdelimw(&cp)) == NULL) {
                error("%s:%lu: invalid line", path, linenum);
-               goto done;
+               r = SSH_ERR_INVALID_FORMAT;
+               goto out;
        }
-       if (match_pattern_list(principal, identities, 0) != 1) {
-               /* principal didn't match */
-               goto done;
+       if ((principals = strdup(tmp)) == NULL) {
+               error("%s: strdup failed", __func__);
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       /*
+        * Bail out early if we're looking for a particular principal and this
+        * line does not list it.
+        */
+       if (required_principal != NULL) {
+               if (match_pattern_list(required_principal,
+                   principals, 0) != 1) {
+                       /* principal didn't match */
+                       r = SSH_ERR_KEY_NOT_FOUND;
+                       goto out;
+               }
+               debug("%s: %s:%lu: matched principal \"%s\"",
+                   __func__, path, linenum, required_principal);
        }
-       debug("%s: %s:%lu: matched principal \"%s\"",
-           __func__, path, linenum, principal);
 
-       if (sshkey_read(found_key, &cp) != 0) {
+       if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
+               error("%s: sshkey_new failed", __func__);
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (sshkey_read(key, &cp) != 0) {
                /* no key? Check for options */
                opts = cp;
                if (sshkey_advance_past_options(&cp) != 0) {
-                       error("%s:%lu: invalid options",
-                           path, linenum);
-                       goto done;
+                       error("%s:%lu: invalid options", path, linenum);
+                       r = SSH_ERR_INVALID_FORMAT;
+                       goto out;
                }
                *cp++ = '\0';
                skip_space(&cp);
-               if (sshkey_read(found_key, &cp) != 0) {
-                       error("%s:%lu: invalid key", path,
-                           linenum);
-                       goto done;
+               if (sshkey_read(key, &cp) != 0) {
+                       error("%s:%lu: invalid key", path, linenum);
+                       r = SSH_ERR_INVALID_FORMAT;
+                       goto out;
                }
        }
        debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
        if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
                error("%s:%lu: bad options: %s", path, linenum, reason);
+               r = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       /* success */
+       if (principalsp != NULL) {
+               *principalsp = principals;
+               principals = NULL; /* transferred */
+       }
+       if (sigoptsp != NULL) {
+               *sigoptsp = sigopts;
+               sigopts = NULL; /* transferred */
+       }
+       if (keyp != NULL) {
+               *keyp = key;
+               key = NULL; /* transferred */
+       }
+       r = 0;
+ out:
+       free(principals);
+       sshsigopt_free(sigopts);
+       sshkey_free(key);
+       return r;
+}
+
+static int
+check_allowed_keys_line(const char *path, u_long linenum, char *line,
+    const struct sshkey *sign_key, const char *principal,
+    const char *sig_namespace)
+{
+       struct sshkey *found_key = NULL;
+       int r, found = 0;
+       const char *reason = NULL;
+       struct sshsigopt *sigopts = NULL;
+
+       /* Parse the line */
+       if ((r = parse_principals_key_and_options(path, linenum, line,
+           principal, NULL, &found_key, &sigopts)) != 0) {
+               /* error already logged */
                goto done;
        }