Refactor rule_an_to_ln, creating a new helper function to handle the
authorGreg Hudson <ghudson@mit.edu>
Mon, 11 May 2009 16:57:45 +0000 (16:57 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 11 May 2009 16:57:45 +0000 (16:57 +0000)
selection string specifier.  Eliminate two (safe) uses of sscanf in
the process.  Add a test case including literal text in the selection
string specifier.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22326 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/Makefile.in
src/lib/krb5/os/an_to_ln.c

index 4998e0fae31d617b53df738cc71ea559f18b52e6..824f91365bc30363fbba9c9d1db4c05da6bb5d13 100644 (file)
@@ -221,6 +221,8 @@ check-unix::
 #      fi
        echo 'auth_to_local = RULE:[3:$$1$$3$$2](rule.*)s/rule//g' \
                >> ./t_an.conf
+       echo 'auth_to_local = RULE:[4:wi$$1ma]s/x/l/g' \
+               >> ./t_an.conf
        echo 'auth_to_local = DEFAULT' >> ./t_an.conf
        echo '}' >> ./t_an.conf
 #      if test -r ../../../admin/aname/kdb5_anadd ; then \
@@ -230,7 +232,7 @@ check-unix::
        KRB5_CONFIG=./t_an.conf ; export KRB5_CONFIG ; \
        $(KRB5_RUN_ENV) $(VALGRIND) ./t_an_to_ln rul/helpme/e@r ru/123/le@r
        KRB5_CONFIG=./t_an.conf ; export KRB5_CONFIG ; \
-       $(KRB5_RUN_ENV) $(VALGRIND) ./t_an_to_ln fred/r@r barney/r@r
+       $(KRB5_RUN_ENV) $(VALGRIND) ./t_an_to_ln fred/r@r barney/r@r x/r/r/r@r
        $(RM) ./t_an.*
 
 clean:: 
index ed9bc96ca642ebcf08225c3da409d33a25dc5688..731b76b8429e7a73eb27498278376a9ef6657e08 100644 (file)
@@ -481,141 +481,118 @@ cleanup:
 }
 
 /*
- * rule_an_to_ln()     - Handle aname to lname translations for RULE rules.
+ * Compute selection string for RULE rules.
  *
- * The initial part of this routine handles the formulation of the strings from
- * the principal name.
+ * Advance *contextp to the string position after the selectring
+ * string part if present, and set *result to the selection string.
  */
 static krb5_error_code
-rule_an_to_ln(krb5_context context, char *rule, krb5_const_principal aname, const unsigned int lnsize, char *lname)
+aname_get_selstring(krb5_context context, krb5_const_principal aname,
+                   char **contextp, char **result)
 {
-    krb5_error_code    kret;
-    char               *current;
-    char               *fprincname;
-    char               *selstring = 0;
-    int                        num_comps, compind, pos;
-    size_t selstring_used;
-    char               *cout;
-    krb5_const krb5_data *datap;
-    char               *outstring;
+    krb5_error_code kret;
+    char *fprincname, *current, *str;
+    long num_comps, compind;
+    const krb5_data *datap;
+    struct k5buf selstring;
+    size_t nlit;
 
-    /*
-     * First flatten the name.
-     */
-    current = rule;
-    if (!(kret = krb5_unparse_name(context, aname, &fprincname))) {
-       /*
-        * First part.
-        */
-       if (*current == '[') {
-           current++;
-           if (sscanf(current,"%d:%n", &num_comps, &pos) == 1) {
-               if (num_comps == aname->length) {
-                   /*
-                    * We have a match based on the number of components.
-                    */
-                   current += pos;
-                   selstring = (char *) malloc(MAX_FORMAT_BUFFER);
-                   selstring_used = 0;
-                   if (selstring) {
-                       cout = selstring;
-                       /*
-                        * Plow through the string.
-                        */
-                       while ((*current != ']') &&
-                              (*current != '\0')) {
-                           /*
-                            * Expand to a component.
-                            */
-                           if (*current == '$') {
-                               if ((sscanf(current+1, "%d", &compind) == 1) &&
-                                   (compind <= num_comps) &&
-                                   (datap =
-                                    (compind > 0)
-                                    ? krb5_princ_component(context, aname,
-                                                           compind-1)
-                                    : krb5_princ_realm(context, aname))
-                                   ) {
-                                   if ((datap->length < MAX_FORMAT_BUFFER)
-                                       &&  (selstring_used+datap->length
-                                            < MAX_FORMAT_BUFFER)) {
-                                       selstring_used += datap->length;
-                                   } else {
-                                       kret = ENOMEM;
-                                       goto errout;
-                                   }
-                                   strncpy(cout,
-                                           datap->data,
-                                           (unsigned) datap->length);
-                                   cout += datap->length;
-                                   *cout = '\0';
-                                   current++;
-                                   /* Point past number */
-                                   while (isdigit((int) (*current)))
-                                       current++;
-                               }
-                               else
-                                   kret = KRB5_CONFIG_BADFORMAT;
-                           }
-                           else {
-                               /* Copy in verbatim. */
-                               *cout = *current;
-                               cout++;
-                               *cout = '\0';
-                               current++;
-                           }
-                       }
+    *result = NULL;
+    if (**contextp != '[') {
+       /* No selstring part; use the full flattened principal name. */
+       kret = krb5_unparse_name(context, aname, &fprincname);
+       if (kret)
+           return kret;
+       str = aname_full_to_mapping_name(fprincname);
+       free(fprincname);
+       if (!str)
+           return ENOMEM;
+       *result = str;
+       return 0;
+    }
 
-                       /*
-                        * Advance past separator if appropriate.
-                        */
-                       if (*current == ']')
-                           current++;
-                       else
-                           kret = KRB5_CONFIG_BADFORMAT;
+    /* Advance past the '[' and read the number of components. */
+    current = *contextp + 1;
+    errno = 0;
+    num_comps = strtol(current, &current, 10);
+    if (errno != 0 || num_comps < 0 || *current != ':')
+       return KRB5_CONFIG_BADFORMAT;
+    if (num_comps != aname->length)
+       return KRB5_LNAME_NOTRANS;
+    current++;
+
+    krb5int_buf_init_dynamic(&selstring);
+    while (1) {
+       /* Copy in literal characters up to the next $ or ]. */
+       nlit = strcspn(current, "$]");
+       krb5int_buf_add_len(&selstring, current, nlit);
+       current += nlit;
+       if (*current != '$')
+           break;
+
+       /* Expand $ substitution to a principal component. */
+       errno = 0;
+       compind = strtol(current + 1, &current, 10);
+       if (errno || compind > num_comps)
+           break;
+       datap = (compind > 0)
+           ? krb5_princ_component(context, aname, compind - 1)
+           : krb5_princ_realm(context, aname);
+       if (!datap)
+           break;
+       krb5int_buf_add_len(&selstring, datap->data, datap->length);
+    }
 
-                       errout: if (kret)
-                           free(selstring);
-                   }
-                   else
-                       kret = ENOMEM;
-               }
-               else
-                   kret = KRB5_LNAME_NOTRANS;
-           }
-           else
-               kret = KRB5_CONFIG_BADFORMAT;
-       }
-       else {
-           if (!(selstring = aname_full_to_mapping_name(fprincname)))
-               kret = ENOMEM;
-       }
-       free(fprincname);
+    /* Check that we hit a ']' and not the end of the string. */
+    if (*current != ']') {
+       krb5int_free_buf(&selstring);
+       return KRB5_CONFIG_BADFORMAT;
     }
-    if (!kret) {
-       /*
-        * Second part
-        */
-       if (*current == '(')
-           kret = aname_do_match(selstring, &current);
 
-       /*
-        * Third part.
-        */
-       if (!kret) {
-           outstring = (char *) NULL;
-           kret = aname_replacer(selstring, &current, &outstring);
-           if (outstring) {
-               /* Copy out the value if there's enough room */
-               if (strlcpy(lname, outstring, lnsize) >= lnsize)
-                   kret = KRB5_CONFIG_NOTENUFSPACE;
-               free(outstring);
-           }
-       }
-       free(selstring);
+    str = krb5int_buf_data(&selstring);
+    if (str == NULL)
+       return ENOMEM;
+
+    *contextp = current + 1;
+    *result = str;
+    return 0;
+}
+
+/* Handle aname to lname translations for RULE rules. */
+static krb5_error_code
+rule_an_to_ln(krb5_context context, char *rule, krb5_const_principal aname,
+             const unsigned int lnsize, char *lname)
+{
+    krb5_error_code kret;
+    char *current, *selstring = 0, *outstring = 0;
+
+    /* Compute the selection string. */
+    current = rule;
+    kret = aname_get_selstring(context, aname, &current, &selstring);
+    if (kret)
+       return kret;
+
+    /* Check the selection string against the regexp, if present. */
+    if (*current == '(') {
+       kret = aname_do_match(selstring, &current);
+       if (kret)
+           goto cleanup;
     }
 
-    return(kret);
+    /* Perform the substitution. */
+    outstring = NULL;
+    kret = aname_replacer(selstring, &current, &outstring);
+    if (kret)
+       goto cleanup;
+
+    /* Copy out the value if there's enough room. */
+    if (strlcpy(lname, outstring, lnsize) >= lnsize)
+       kret = KRB5_CONFIG_NOTENUFSPACE;
+
+cleanup:
+    free(selstring);
+    free(outstring);
+    return kret;
 }
 #endif /* AN_TO_LN_RULES */