]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
hoist call to cf_expand_variables() to cf_file.c
authorAlan T. DeKok <aland@freeradius.org>
Mon, 20 Jun 2022 11:54:58 +0000 (07:54 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 20 Jun 2022 15:47:00 +0000 (11:47 -0400)
in preparation for moving to xlat expressions

src/lib/server/cf_file.c
src/lib/server/cond_tokenize.c
src/tests/unit/condition/base.txt

index 465b2cb8f2d6d0c3832946f5069b472cd23a380c..44579df9786c6aefe6279a01a4e70410952e8afd 100644 (file)
@@ -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;
 
index 4221d556e8179868d3d2b80665d39c0351ea56f1..4f9b9784731af7ff9b9eeffde3571befa1af3a21 100644 (file)
@@ -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
index cc22958cdf0614c3fa9cdb3226155a746a6fce3e..a7eb6755e28b81a3c8a525c1e747013674ef08f5 100644 (file)
@@ -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