From 063e4f4f1277651fbe5e2ddbee4078031c5b0198 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Mon, 15 Apr 2024 18:47:27 -0400 Subject: [PATCH] Improve profile final flag support When parsing a file, ignore sections appearing after a file-flagged section of the same name. Adjust the meaning of group_level in the parser state so that it is 1 for top-level sections, not 0, and simplify the addition of top-level sections to the tree by taking advantage of section-merging by profile_add_node(). Make the final flag work for relations as well as sections. Check it while parsing via check_final parameter in profile_add_node(), and during iteration so we don't continue on to later files in the profile path. Preserve 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 | 15 +++--- 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 | 17 +++++-- 9 files changed, 140 insertions(+), 53 deletions(-) create mode 100644 src/util/profile/final6.ini diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst index 1b92170da89..46806a3f97f 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,15 @@ 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 coan be marked as +final, and the flag only causes values to be ignored if they appear in +later files specified in **KRB5_CONFIG**. + 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 18c6d2dd556..e4316e1f7cd 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 fb23b3ccc07..1d5354378d0 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 4b1e15b7990..827ec25dcad 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 00000000000..516fcf7aac7 --- /dev/null +++ b/src/util/profile/final6.ini @@ -0,0 +1,45 @@ +# A profile exercising suppression of finalized relations, sections, +# and subsections 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 1ee9a8ca1c3..7d82aa35de7 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 7ba44aca6ee..97a49e94d06 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 af4b2f853fb..69165d84d83 100644 --- a/src/util/profile/prof_set.c +++ b/src/util/profile/prof_set.c @@ -275,7 +275,7 @@ profile_add_relation(profile_t profile, const char **names, retval = profile_find_node(section, *cpp, 0, 1, &state, §ion); if (retval == PROF_NO_SECTION) - retval = profile_add_node(section, *cpp, 0, §ion); + retval = profile_add_node(section, *cpp, NULL, 0, §ion); if (retval) { k5_mutex_unlock(&profile->first_file->data->lock); return retval; @@ -294,7 +294,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 b3c15ca1c66..00e837db7a1 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,10 @@ 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) { + if (ret_node) + *ret_node = NULL; + return 0; } } retval = profile_create_node(name, value, &new); @@ -326,7 +332,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 +347,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 +578,8 @@ errcode_t profile_node_iterator(void **iter_p, } if (p->deleted) continue; + if (p->final) + iter->flags |= PROFILE_ITER_FINAL_SEEN; break; } iter->num++;