From: Alan T. DeKok Date: Mon, 20 Jun 2022 11:54:58 +0000 (-0400) Subject: hoist call to cf_expand_variables() to cf_file.c X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1fb0f5bd06cfb64f0d0cfd3dae2fb12820d7189a;p=thirdparty%2Ffreeradius-server.git hoist call to cf_expand_variables() to cf_file.c in preparation for moving to xlat expressions --- diff --git a/src/lib/server/cf_file.c b/src/lib/server/cf_file.c index 465b2cb8f2d..44579df9786 100644 --- a/src/lib/server/cf_file.c +++ b/src/lib/server/cf_file.c @@ -1157,15 +1157,24 @@ static CONF_ITEM *process_if(cf_stack_t *stack) cf_stack_frame_t *frame = &stack->frame[stack->depth]; CONF_SECTION *parent = frame->current; char *buff[4]; + tmpl_rules_t t_rules; /* * Short names are nicer. */ buff[1] = stack->buff[1]; buff[2] = stack->buff[2]; + buff[3] = stack->buff[3]; dict = virtual_server_dict_by_child_ci(cf_section_to_item(parent)); + t_rules = (tmpl_rules_t) { + .attr = { + .dict_def = dict, + .allow_unresolved = true, + .allow_unknown = true + } + }; /* * fr_cond_tokenize needs the current section, so we * create it first. We don't pass a name2, as it hasn't @@ -1179,61 +1188,43 @@ static CONF_ITEM *process_if(cf_stack_t *stack) cf_filename_set(cs, frame->filename); cf_lineno_set(cs, frame->lineno); + RULES_VERIFY(cs, &t_rules); + /* - * Skip (...) to find the { + * Keep parsing the condition until we hit EOL, or a real error. */ while (true) { - tmpl_rules_t t_rules = { - .attr = { - .dict_def = dict, - .allow_unresolved = true, - .allow_unknown = true - } - }; - - RULES_VERIFY(cs, &t_rules); + ssize_t end; + char *spaces, *text; + /* + * Parse the condition. If it succeeded, stop + * trying to expand the buffer. + */ slen = fr_cond_tokenize(cs, &cond, &t_rules, &FR_SBUFF_IN(ptr, strlen(ptr))); - if (slen < 0) { - ssize_t end = -slen; + if (slen > 0) break; - /* - * For paranoia, check that "end" is valid. - */ - if ((ptr + end) > (stack->buff[0] + stack->bufsize)) { - cf_log_err(parent, "Failed parsing condition"); - return NULL; - } - - /* - * The condition failed to parse at EOL. - * Therefore we try to read another line. - */ - if (!ptr[end]) { - int rcode; + end = -slen; + fr_assert((ptr + end) < (stack->buff[0] + stack->bufsize)); - memcpy(&stack->fill, &ptr, sizeof(ptr)); /* const issues */ - stack->fill += end; - rcode = cf_file_fill(stack); - if (rcode < 0) return NULL; - continue; - } + /* + * We hit EOL, so the parse error is really "read more data". + */ + if (!ptr[end]) { + int rcode; - /* - * @todo - suppress leading spaces - */ + memcpy(&stack->fill, &ptr, sizeof(ptr)); /* const issues */ + stack->fill += end; + rcode = cf_file_fill(stack); + if (rcode < 0) return NULL; + continue; } - break; - } - - /* - * We either read the whole line, OR there was a - * different error parsing the condition. - */ - if (slen < 0) { - char *spaces, *text; + /* + * We didn't hit EOL, so it's a real error. + */ + parse_error: fr_canonicalize_error(cs, &spaces, &text, slen, ptr); cf_log_err(cs, "Parse error in condition"); @@ -1246,20 +1237,11 @@ static CONF_ITEM *process_if(cf_stack_t *stack) return NULL; } - /* - * The input file buffer may be larger - * than the buffer we put the condition - * into. - */ - if ((size_t) slen >= (stack->bufsize - 1)) { - cf_log_err(cs, "Condition is too large after \"%s\"", buff[1]); - talloc_free(cs); - return NULL; - } + fr_assert((size_t) slen < (stack->bufsize - 1)); /* - * Copy the expanded and parsed condition into buff[2]. - * Then suppress any trailing whitespace. + * Save the parsed condition (minus trailing whitespace) + * into a buffer. */ memcpy(buff[2], ptr, slen); buff[2][slen] = '\0'; @@ -1269,6 +1251,31 @@ static CONF_ITEM *process_if(cf_stack_t *stack) p--; } + /* + * Now that we know how big the condition is, see if we + * need to expand the variables. If so, free the old + * condition, expand the variables, and reparse the + * condition. + */ + if (strchr(ptr, '$') != NULL) { + ssize_t my_slen; + + talloc_free(cond); + + if (!cf_expand_variables(frame->filename, frame->lineno, parent, + buff[3], stack->bufsize, buff[2], slen, NULL)) { + fr_strerror_const("Failed expanding configuration variable"); + return NULL; + } + + my_slen = fr_cond_tokenize(cs, &cond, &t_rules, &FR_SBUFF_IN(buff[3], strlen(buff[3]))); + if (my_slen <= 0) { + ptr = buff[3]; + slen = my_slen; + goto parse_error; + } + } + MEM(cs->name2 = talloc_typed_strdup(cs, buff[2])); cs->name2_quote = T_BARE_WORD; diff --git a/src/lib/server/cond_tokenize.c b/src/lib/server/cond_tokenize.c index 4221d556e81..4f9b9784731 100644 --- a/src/lib/server/cond_tokenize.c +++ b/src/lib/server/cond_tokenize.c @@ -1486,20 +1486,12 @@ static void cond_reparent(fr_cond_t *c, fr_cond_t *parent) */ ssize_t fr_cond_tokenize(CONF_SECTION *cs, fr_cond_t **head, tmpl_rules_t const *rules, fr_sbuff_t *in) { - char buffer[8192]; - ssize_t diff, slen; + ssize_t slen; + fr_sbuff_t our_in = FR_SBUFF(in); *head = NULL; - if (!cf_expand_variables(cf_filename(cs), cf_lineno(cs), cf_item_to_section(cf_parent(cs)), - buffer, sizeof(buffer), - fr_sbuff_current(in), fr_sbuff_remaining(in), NULL)) { - fr_strerror_const("Failed expanding configuration variable"); - return 0; - } - - diff = fr_sbuff_remaining(in) - strlen(buffer); /* Hack so that we appear to consume more of the string */ - slen = cond_tokenize(cs, head, cs, &FR_SBUFF_IN(buffer, strlen(buffer)), 0, rules); + slen = cond_tokenize(cs, head, cs, &our_in, 0, rules); if (slen <= 0) return slen; /* @@ -1527,7 +1519,7 @@ ssize_t fr_cond_tokenize(CONF_SECTION *cs, fr_cond_t **head, tmpl_rules_t const cond_reparent(*head, NULL); } - return slen + diff; + return fr_sbuff_set(in, &our_in); } /** Initialise a cond iterator diff --git a/src/tests/unit/condition/base.txt b/src/tests/unit/condition/base.txt index cc22958cdf0..a7eb6755e28 100644 --- a/src/tests/unit/condition/base.txt +++ b/src/tests/unit/condition/base.txt @@ -606,8 +606,13 @@ match &reply # Expansions of environment variables # and empty strings # -condition ("$ENV{SOMETHING_OR_OTHER}" == '') -match true +# @todo - disabled due to moving cf_expand_variables() from +# cond_tokenize() to cf_file.c. The new xlat expression parser +# will *not* optimize this at parse time, but *will* optimize +# this at purification time. +# +#condition ("$ENV{SOMETHING_OR_OTHER}" == '') +#match true # # Attributes with a protocol namespace @@ -640,4 +645,4 @@ condition (&User-Name == "bob") && ((&User-Password == "bob") || &EAP-Message) match (&User-Name == "bob") && ((&User-Password == "bob") || &EAP-Message) count -match 309 +match 307