krb5 commit: Improve profile final flag support

ghudson at mit.edu ghudson at mit.edu
Sat Apr 20 20:19:30 EDT 2024


https://github.com/krb5/krb5/commit/f951625e6bd3ff44f1056958b56e35a1a043e362
commit f951625e6bd3ff44f1056958b56e35a1a043e362
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Apr 15 18:47:27 2024 -0400

    Improve profile final flag support
    
    When parsing a file, ignore sections appearing after a final-flagged
    section of the same name.  Adjust the meaning of group_level in the
    parser state so that it is 1 inside of top-level sections instead of
    0, and simplify the addition of top-level sections to the tree by
    relying on profile_add_node()'s section merging.
    
    Make the final flag work for relations as well as sections.  Check it
    while parsing via a new check_final parameter in profile_add_node(),
    and during iteration.
    
    Output final flags for relations in dump_profile().  Make the final
    flag available to it via a new output parameter in
    profile_find_node_relation().
    
    ticket: 9120

 doc/admin/conf_files/krb5_conf.rst | 16 +++++---
 src/util/profile/Makefile.in       |  8 ++++
 src/util/profile/final.expected    | 18 ++++++++-
 src/util/profile/final2.ini        |  4 +-
 src/util/profile/final6.ini        | 45 ++++++++++++++++++++++
 src/util/profile/prof_int.h        |  4 +-
 src/util/profile/prof_parse.c      | 78 ++++++++++++++++++++------------------
 src/util/profile/prof_set.c        |  4 +-
 src/util/profile/prof_tree.c       | 19 ++++++++--
 9 files changed, 143 insertions(+), 53 deletions(-)

diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 1b92170da..ab73a694d 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -35,12 +35,6 @@ or::
         baz = quux
     }
 
-Placing a '\*' after the closing bracket of a section name indicates
-that the section is *final*, meaning that if the same section appears
-within a later file specified in **KRB5_CONFIG**, it will be ignored.
-A subsection can be marked as final by placing a '\*' after either the
-tag name or the closing brace.
-
 The krb5.conf file can include other files using either of the
 following directives at the beginning of a line::
 
@@ -58,6 +52,16 @@ section header.  Starting in release 1.17, files are read in
 alphanumeric order; in previous releases, they may be read in any
 order.
 
+Placing a '\*' after the closing bracket of a section name indicates
+that the section is *final*, meaning that if the same section appears
+again later, it will be ignored.  A subsection can be marked as final
+by placing a '\*' after either the tag name or the closing brace.  A
+relation can be marked as final by placing a '\*' after the tag name.
+Prior to release 1.22, only sections and subsections can be marked as
+final, and the flag only causes values to be ignored if they appear in
+later files specified in **KRB5_CONFIG**, not if they appear later
+within the same file or an included file.
+
 The krb5.conf file can specify that configuration should be obtained
 from a loadable module, rather than the file itself, using the
 following directive at the beginning of a line before any section
diff --git a/src/util/profile/Makefile.in b/src/util/profile/Makefile.in
index 18c6d2dd5..e4316e1f7 100644
--- a/src/util/profile/Makefile.in
+++ b/src/util/profile/Makefile.in
@@ -140,6 +140,7 @@ F2=$(srcdir)/final2.ini
 F3=$(srcdir)/final3.ini
 F4=$(srcdir)/final4.ini
 F5=$(srcdir)/final5.ini
+F6=$(srcdir)/final6.ini
 QUERY=query section subsection key
 check-unix-final: test_profile
 	$(RM) final.out
@@ -148,6 +149,13 @@ check-unix-final: test_profile
 	(echo; $(RUN_TEST) ./test_profile $(F3):$(F1) $(QUERY)) >> final.out
 	(echo; $(RUN_TEST) ./test_profile $(F4):$(F1) $(QUERY)) >> final.out
 	(echo; $(RUN_TEST) ./test_profile $(F5):$(F1) $(QUERY)) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query a ab) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query a ac) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query b ba) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query b bb bba) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query c ca caa) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query c cb cba) >> final.out
+	(echo; $(RUN_TEST) ./test_profile $(F6) query c cc) >> final.out
 	cmp final.out $(srcdir)/final.expected
 	$(RM) final.out
 
diff --git a/src/util/profile/final.expected b/src/util/profile/final.expected
index fb23b3ccc..1d5354378 100644
--- a/src/util/profile/final.expected
+++ b/src/util/profile/final.expected
@@ -3,10 +3,26 @@ value1
 value1
 
 value2
-value1
 
 value3
 
 value4
 
 value5
+
+1
+2
+
+1
+
+1
+2
+
+1
+
+1
+
+1
+
+1
+2
diff --git a/src/util/profile/final2.ini b/src/util/profile/final2.ini
index 4b1e15b79..827ec25dc 100644
--- a/src/util/profile/final2.ini
+++ b/src/util/profile/final2.ini
@@ -1,6 +1,4 @@
-# In this variant the relation is marked final.  There is parsing
-# support for this but no iteration or dumping support, so the marker
-# currently has no effect.
+# In this variant the relation is marked final.
 [section]
 	subsection = {
 		key* = value2
diff --git a/src/util/profile/final6.ini b/src/util/profile/final6.ini
new file mode 100644
index 000000000..c1e44b747
--- /dev/null
+++ b/src/util/profile/final6.ini
@@ -0,0 +1,45 @@
+# A profile exercising suppression of final-flagged sections,
+# subsections, and relations within the same file.
+
+[a]
+	ab = 1
+	ab* = 2
+	ab = 3
+	ab* = 4
+	ac* = 1
+
+[a]
+	ac = 2
+	ac* = 3
+	ac = 4
+
+[b]*
+	ba = 1
+	ba* = 2
+	bb = {
+		bba = 1
+	}
+
+[b]
+	ba = 3
+	bb = {
+		bba = 2
+	}
+
+[c]
+	ca* = {
+		caa* = 1
+	}
+	cb = {
+		cba = 1
+	}*
+	cc = 1
+
+[c]
+	ca = {
+		caa = 2
+	}
+	cb* = {
+		cba = 2
+	}
+	cc = 2
diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h
index 21c535a5c..95f7b346f 100644
--- a/src/util/profile/prof_int.h
+++ b/src/util/profile/prof_int.h
@@ -144,7 +144,7 @@ errcode_t profile_verify_node
 
 errcode_t profile_add_node
 	(struct profile_node *section,
-		    const char *name, const char *value,
+		    const char *name, const char *value, int check_final,
 		    struct profile_node **ret_node);
 
 errcode_t profile_make_node_final
@@ -168,7 +168,7 @@ errcode_t profile_find_node
 errcode_t profile_find_node_relation
 	(struct profile_node *section,
 		    const char *name, void **state,
-		    char **ret_name, char **value);
+		    char **ret_name, char **value, int *ret_final);
 
 errcode_t profile_find_node_subsection
 	(struct profile_node *section,
diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c
index 7ba44aca6..c581fb722 100644
--- a/src/util/profile/prof_parse.c
+++ b/src/util/profile/prof_parse.c
@@ -20,8 +20,9 @@
 #define STATE_GET_OBRACE        3
 
 struct parse_state {
-    int     state;
-    int     group_level;
+    int state;
+    int group_level;
+    int discard;                /* group_level of a final-flagged section */
     struct profile_node *root_section;
     struct profile_node *current_section;
 };
@@ -78,7 +79,6 @@ static errcode_t parse_std_line(char *line, struct parse_state *state)
     errcode_t retval;
     struct profile_node     *node;
     int do_subsection = 0;
-    void *iter = 0;
 
     if (*line == 0)
         return 0;
@@ -90,24 +90,22 @@ static errcode_t parse_std_line(char *line, struct parse_state *state)
     if (ch == 0)
         return 0;
     if (ch == '[') {
-        if (state->group_level > 0)
+        if (state->group_level > 1)
             return PROF_SECTION_NOTOP;
         cp++;
         p = strchr(cp, ']');
         if (p == NULL)
             return PROF_SECTION_SYNTAX;
         *p = '\0';
-        retval = profile_find_node_subsection(state->root_section,
-                                              cp, &iter, 0,
-                                              &state->current_section);
-        if (retval == PROF_NO_SECTION) {
-            retval = profile_add_node(state->root_section,
-                                      cp, 0,
-                                      &state->current_section);
-            if (retval)
-                return retval;
-        } else if (retval)
+        retval = profile_add_node(state->root_section, cp, NULL, 0,
+                                  &state->current_section);
+        if (retval)
             return retval;
+        state->group_level = 1;
+        /* If we previously saw this section name with the final flag,
+         * discard values until the next top-level section. */
+        state->discard = profile_is_node_final(state->current_section) ?
+            1 : 0;
 
         /*
          * Finish off the rest of the line.
@@ -135,6 +133,9 @@ static errcode_t parse_std_line(char *line, struct parse_state *state)
         if (retval)
             return retval;
         state->group_level--;
+        /* Check if we are done discarding values from a subsection. */
+        if (state->group_level < state->discard)
+            state->discard = 0;
         return 0;
     }
     /*
@@ -180,21 +181,29 @@ static errcode_t parse_std_line(char *line, struct parse_state *state)
         p = strchr(tag, '*');
         if (p)
             *p = '\0';
-        retval = profile_add_node(state->current_section,
-                                  tag, 0, &state->current_section);
-        if (retval)
-            return retval;
-        if (p)
-            profile_make_node_final(state->current_section);
         state->group_level++;
+        if (!state->discard) {
+            retval = profile_add_node(state->current_section, tag, NULL, 0,
+                                      &state->current_section);
+            if (retval)
+                return retval;
+            /* If we previously saw this subsection with the final flag,
+             * discard values until the subsection is done. */
+            if (profile_is_node_final(state->current_section))
+                state->discard = state->group_level;
+            if (p)
+                profile_make_node_final(state->current_section);
+        }
         return 0;
     }
     p = strchr(tag, '*');
     if (p)
         *p = '\0';
-    profile_add_node(state->current_section, tag, value, &node);
-    if (p)
-        profile_make_node_final(node);
+    if (!state->discard) {
+        profile_add_node(state->current_section, tag, value, 1, &node);
+        if (p && node)
+            profile_make_node_final(node);
+    }
     return 0;
 }
 
@@ -209,7 +218,7 @@ static errcode_t parse_include_file(const char *filename,
     /* Create a new state so that fragments are syntactically independent but
      * share a root section. */
     state.state = STATE_INIT_COMMENT;
-    state.group_level = 0;
+    state.group_level = state.discard = 0;
     state.root_section = root_section;
     state.current_section = NULL;
 
@@ -407,7 +416,7 @@ errcode_t profile_parse_file(FILE *f, struct profile_node **root,
 
     /* Initialize parsing state with a new root node. */
     state.state = STATE_INIT_COMMENT;
-    state.group_level = 0;
+    state.group_level = state.discard = 0;
     state.current_section = NULL;
     retval = profile_create_node("(root)", 0, &state.root_section);
     if (retval)
@@ -513,7 +522,7 @@ static void output_quoted_string(char *str, void (*cb)(const char *,void *),
 static void dump_profile(struct profile_node *root, int level,
                          void (*cb)(const char *, void *), void *data)
 {
-    int i;
+    int i, final;
     struct profile_node *p;
     void *iter;
     long retval;
@@ -522,22 +531,19 @@ static void dump_profile(struct profile_node *root, int level,
     iter = 0;
     do {
         retval = profile_find_node_relation(root, 0, &iter,
-                                            &name, &value);
+                                            &name, &value, &final);
         if (retval)
             break;
         for (i=0; i < level; i++)
             cb("\t", data);
-        if (need_double_quotes(value)) {
-            cb(name, data);
-            cb(" = ", data);
+        cb(name, data);
+        cb(final ? "*" : "", data);
+        cb(" = ", data);
+        if (need_double_quotes(value))
             output_quoted_string(value, cb, data);
-            cb(EOL, data);
-        } else {
-            cb(name, data);
-            cb(" = ", data);
+        else
             cb(value, data);
-            cb(EOL, data);
-        }
+        cb(EOL, data);
     } while (iter != 0);
 
     iter = 0;
diff --git a/src/util/profile/prof_set.c b/src/util/profile/prof_set.c
index aeea676cb..e4971d12f 100644
--- a/src/util/profile/prof_set.c
+++ b/src/util/profile/prof_set.c
@@ -270,7 +270,7 @@ profile_add_relation(profile_t profile, const char **names,
         retval = profile_find_node(section, *cpp, 0, 1,
                                    &state, &section);
         if (retval == PROF_NO_SECTION)
-            retval = profile_add_node(section, *cpp, 0, &section);
+            retval = profile_add_node(section, *cpp, NULL, 0, &section);
         if (retval) {
             k5_mutex_unlock(&profile->first_file->data->lock);
             return retval;
@@ -289,7 +289,7 @@ profile_add_relation(profile_t profile, const char **names,
         }
     }
 
-    retval = profile_add_node(section, *cpp, new_value, 0);
+    retval = profile_add_node(section, *cpp, new_value, 0, NULL);
     if (retval) {
         k5_mutex_unlock(&profile->first_file->data->lock);
         return retval;
diff --git a/src/util/profile/prof_tree.c b/src/util/profile/prof_tree.c
index b3c15ca1c..b6bdbf3f6 100644
--- a/src/util/profile/prof_tree.c
+++ b/src/util/profile/prof_tree.c
@@ -145,10 +145,12 @@ errcode_t profile_verify_node(struct profile_node *node)
 }
 
 /*
- * Add a node to a particular section
+ * Add a node to a particular section.  If check_final is true, don't add the
+ * node if we find a final node for the same name.
  */
 errcode_t profile_add_node(struct profile_node *section, const char *name,
-                           const char *value, struct profile_node **ret_node)
+                           const char *value, int check_final,
+                           struct profile_node **ret_node)
 {
     errcode_t retval;
     struct profile_node *p, *last, *new;
@@ -174,6 +176,12 @@ errcode_t profile_add_node(struct profile_node *section, const char *name,
             /* Found duplicate subsection, so don't make a new one. */
             *ret_node = p;
             return 0;
+        } else if (check_final && cmp == 0 && p->final) {
+            /* This key already exists with the final flag and we were asked
+             * to check it, so don't add this node. */
+            if (ret_node)
+                *ret_node = NULL;
+            return 0;
         }
     }
     retval = profile_create_node(name, value, &new);
@@ -326,7 +334,8 @@ errcode_t profile_find_node(struct profile_node *section, const char *name,
  */
 errcode_t profile_find_node_relation(struct profile_node *section,
                                      const char *name, void **state,
-                                     char **ret_name, char **value)
+                                     char **ret_name, char **value,
+                                     int *ret_final)
 {
     struct profile_node *p;
     errcode_t       retval;
@@ -340,6 +349,8 @@ errcode_t profile_find_node_relation(struct profile_node *section,
             *value = p->value;
         if (ret_name)
             *ret_name = p->name;
+        if (ret_final)
+            *ret_final = p->final;
     }
     return 0;
 }
@@ -569,6 +580,8 @@ get_new_file:
         }
         if (p->deleted)
             continue;
+        if (p->final)
+            iter->flags |= PROFILE_ITER_FINAL_SEEN;
         break;
     }
     iter->num++;


More information about the cvs-krb5 mailing list