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, §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;
@@ -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