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::
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
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
(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
value1
value2
-value1
value3
value4
value5
+
+1
+2
+
+1
+
+1
+2
+
+1
+
+1
+
+1
+
+1
+2
-# 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
--- /dev/null
+# 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
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
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,
#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;
};
errcode_t retval;
struct profile_node *node;
int do_subsection = 0;
- void *iter = 0;
if (*line == 0)
return 0;
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.
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;
}
/*
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;
}
/* 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;
/* 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)
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;
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;
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;
}
}
- 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;
}
/*
- * 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;
/* 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);
*/
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;
*value = p->value;
if (ret_name)
*ret_name = p->name;
+ if (ret_final)
+ *ret_final = p->final;
}
return 0;
}
}
if (p->deleted)
continue;
+ if (p->final)
+ iter->flags |= PROFILE_ITER_FINAL_SEEN;
break;
}
iter->num++;