From: Alan T. DeKok Date: Wed, 25 Jun 2025 18:53:47 +0000 (-0400) Subject: allow @policy foo {...} in module configuration and add test X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=851fe5ae7bc2d72828e5d50e32b4b1385eefe7f4;p=thirdparty%2Ffreeradius-server.git allow @policy foo {...} in module configuration and add test TBH we allow it almost anywhere, but this test is just for module override --- diff --git a/src/lib/server/cf_file.c b/src/lib/server/cf_file.c index c0de76b7af4..1bf5826696f 100644 --- a/src/lib/server/cf_file.c +++ b/src/lib/server/cf_file.c @@ -134,6 +134,7 @@ typedef struct { CONF_SECTION *parent; //!< which started this file CONF_SECTION *current; //!< sub-section we're reading + CONF_SECTION *at_reference; //!< was this thing an @foo ? int braces; bool from_dir; //!< this file was read from $include foo/ @@ -2179,7 +2180,12 @@ static int parse_input(cf_stack_t *stack) */ if (!cf_template_merge(parent, parent->template)) return -1; - frame->current = cf_item_to_section(parent->item.parent); + if (frame->at_reference) { + frame->current = frame->at_reference; + frame->at_reference = NULL; + } else { + frame->current = cf_item_to_section(parent->item.parent); + } ptr++; stack->ptr = ptr; @@ -2461,8 +2467,90 @@ check_for_eol: alloc_section: parent->allow_locals = false; - css = cf_section_alloc(parent, parent, buff[1], value); + /* + * @policy foo { ...} + * + * Means "add foo to the policy section". And if + * policy{} doesn't exist, create it, and then mark up + * policy{} with a flag "we need to merge it", so that + * when we read the actual policy{}, we merge the + * contents together, instead of creating a second + * policy{}. + * + * @todo - allow for '.' in @.ref Or at least test it. :( + * + * @todo - allow for two section names @ref foo bar {...} + * + * @todo - maybe we can use this to overload things in + * virtual servers, and in modules? + */ + if (buff[1][0] == '@') { + CONF_ITEM *ci; + CONF_SECTION *root; + char const *name = &buff[1][1]; + + if (!value) { + ERROR("%s[%d]: Missing section name for reference", frame->filename, frame->lineno); + return -1; + } + + root = cf_root(parent); + + ci = cf_reference_item(root, parent, name); + if (!ci) { + if (name[1] == '.') { + PERROR("%s[%d]: Failed finding reference \"%s\"", frame->filename, frame->lineno, name); + return -1; + } + + css = cf_section_alloc(root, root, name, NULL); + if (!css) goto oom; + + cf_filename_set(css, frame->filename); + cf_lineno_set(css, frame->lineno); + css->name2_quote = name2_token; + css->unlang = CF_UNLANG_NONE; + css->allow_locals = false; + css->at_reference = true; + parent = css; + + /* + * Copy this code from below. :( + */ + if (cf_item_to_section(parent->item.parent) == root) { + if (strcmp(css->name1, "server") == 0) css->unlang = CF_UNLANG_SERVER; + if (strcmp(css->name1, "policy") == 0) css->unlang = CF_UNLANG_POLICY; + if (strcmp(css->name1, "modules") == 0) css->unlang = CF_UNLANG_MODULES; + if (strcmp(css->name1, "templates") == 0) css->unlang = CF_UNLANG_CAN_HAVE_UPDATE; + } + + } else { + if (!cf_item_is_section(ci)) { + ERROR("%s[%d]: Reference \"%s\" is not a section", frame->filename, frame->lineno, name); + return -1; + } + } + + frame->at_reference = frame->current; + name2_token = T_BARE_WORD; + + css = cf_section_alloc(parent, parent, value, NULL); + } else { + /* + * Check if there's already an auto-created + * section of this name. If so, just use that + * section instead of allocating a new one. + */ + css = cf_section_find(parent, buff[1], value); + if (css && css->at_reference) { + css->at_reference = false; + } else { + css = cf_section_alloc(parent, parent, buff[1], value); + } + } + if (!css) { + oom: ERROR("%s[%d]: Failed allocating memory for section", frame->filename, frame->lineno); return -1; diff --git a/src/lib/server/cf_priv.h b/src/lib/server/cf_priv.h index 3746f12944f..920897e6b97 100644 --- a/src/lib/server/cf_priv.h +++ b/src/lib/server/cf_priv.h @@ -114,6 +114,7 @@ struct cf_section { int depth; cf_unlang_t unlang; bool allow_locals; //!< allow local variables + bool at_reference; //!< this thing was created from an @... CONF_SECTION *template; }; diff --git a/src/tests/keywords/at_policy b/src/tests/keywords/at_policy new file mode 100644 index 00000000000..bf7dbbff70e --- /dev/null +++ b/src/tests/keywords/at_policy @@ -0,0 +1,15 @@ +# +# Test @policy foo {...} with overrides +# + +at_policy + +if !control.Tmp-String-0 { + test_fail +} + +if control.Tmp-String-0 != 'at_policy' { + test_fail +} + +success diff --git a/src/tests/keywords/radius.conf b/src/tests/keywords/radius.conf index 3adc4da6ccd..8e56712baac 100644 --- a/src/tests/keywords/radius.conf +++ b/src/tests/keywords/radius.conf @@ -29,6 +29,16 @@ modules { } test.short = 65535 + # + # Local policies with override + # + test at_policy { + + } + @policy at_policy { + at_policy + control.Tmp-String-0 := "at_policy" + } csv { key = "%str.lower(%{User-Name})" @@ -110,7 +120,6 @@ modules { test1 test2 } - } policy {