2 * parser.c Parse various things
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2013 Alan DeKok <aland@freeradius.org>
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/parser.h>
27 #include <freeradius-devel/rad_assert.h>
31 #define PW_CAST_BASE (1850)
33 static const FR_NAME_NUMBER allowed_return_codes[] = {
47 * This file shouldn't use any functions from the server core.
50 size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *in)
54 char *end = buffer + bufsize - 1;
55 fr_cond_t const *c = in;
59 *(p++) = '!'; /* FIXME: only allow for child? */
63 case COND_TYPE_EXISTS:
64 rad_assert(c->data.vpt != NULL);
66 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
67 c->cast->type, "??"));
71 len = radius_tmpl2str(p, end - p, c->data.vpt);
76 rad_assert(c->data.map != NULL);
78 *(p++) = '['; /* for extra-clear debugging */
81 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
82 c->cast->type, "??"));
86 len = radius_map2str(p, end - p, c->data.map);
94 rad_assert(c->data.child != NULL);
96 len = fr_cond_sprint(p, end - p, c->data.child);
102 strlcpy(buffer, "true", bufsize);
103 return strlen(buffer);
105 case COND_TYPE_FALSE:
106 strlcpy(buffer, "false", bufsize);
107 return strlen(buffer);
114 if (c->next_op == COND_NONE) {
115 rad_assert(c->next == NULL);
120 if (c->next_op == COND_AND) {
121 strlcpy(p, " && ", end - p);
124 } else if (c->next_op == COND_OR) {
125 strlcpy(p, " || ", end - p);
137 static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char const *start, char **out,
138 FR_TOKEN *op, char const **error)
140 char const *p = start;
148 *op = T_DOUBLE_QUOTED_STRING;
152 *op = T_SINGLE_QUOTED_STRING;
156 *op = T_BACK_QUOTED_STRING;
160 *op = T_OP_REG_EQ; /* a bit of a hack. */
165 *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
166 if (!*out) return -1;
180 *error = "End of string after escape";
205 *error = "Unterminated string";
209 static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
210 FR_TOKEN *op, char const **error)
213 char const *p = start;
215 if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
216 return condition_tokenize_string(ctx, start, out, op, error);
220 if (*p == '&') p++; /* special-case &User-Name */
224 * The LHS should really be limited to only a few
225 * things. For now, we allow pretty much anything.
228 *error = "Unexpected escape";
240 * Spaces or special characters delineate the word
242 if (isspace((int) *p) || (*p == '&') || (*p == '|') ||
243 (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
247 if ((*p == '"') || (*p == '\'') || (*p == '`')) {
248 *error = "Unexpected start of string";
257 *error = "Empty string is invalid";
261 *out = talloc_array(ctx, char, len + 1);
262 memcpy(*out, start, len);
268 static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda, char const **error)
270 char const *p = start;
274 while (isspace((int) *p)) p++; /* skip spaces before condition */
276 if (*p != '<') return 0;
280 while (*q && *q != '>') q++;
282 cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
283 if (cast == PW_TYPE_INVALID) {
284 *error = "Invalid data type in cast";
289 * We can only cast to basic data types. Complex ones
293 #ifdef WITH_ASCEND_BINARY
294 case PW_TYPE_ABINARY:
296 case PW_TYPE_IP_ADDR:
298 case PW_TYPE_EXTENDED:
299 case PW_TYPE_LONG_EXTENDED:
302 *error = "Forbidden data type in cast";
309 *pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
311 *error = "Cannot cast to this data type";
317 while (isspace((int) *q)) q++; /* skip spaces after cast */
323 * Less code means less bugs
325 #define return_P(_x) *error = _x;goto return_p
326 #define return_0(_x) *error = _x;goto return_0
327 #define return_lhs(_x) *error = _x;goto return_lhs
328 #define return_rhs(_x) *error = _x;goto return_rhs
329 #define return_SLEN goto return_slen
332 /** Tokenize a conditional check
334 * @param[in] ctx for talloc
335 * @param[in] ci for CONF_ITEM
336 * @param[in] start the start of the string to process. Should be "(..."
337 * @param[in] brace look for a closing brace
338 * @param[in] flags do one/two pass
339 * @param[out] pcond pointer to the returned condition structure
340 * @param[out] error the parse error (if any)
341 * @return length of the string skipped, or when negative, the offset to the offending error
343 static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace,
344 fr_cond_t **pcond, char const **error, int flags)
347 char const *p = start;
348 char const *lhs_p, *rhs_p;
351 FR_TOKEN op, lhs_type, rhs_type;
353 c = talloc_zero(ctx, fr_cond_t);
355 rad_assert(c != NULL);
357 lhs_type = rhs_type = T_OP_INVALID;
359 while (isspace((int) *p)) p++; /* skip spaces before condition */
362 return_P("Empty condition is invalid");
371 while (isspace((int) *p)) p++; /* skip spaces after negation */
377 return_P("Double negation is invalid");
388 * We've already eaten one layer of
389 * brackets. Go recurse to get more.
391 c->type = COND_TYPE_CHILD;
393 slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
398 if (!c->data.child) {
399 return_P("Empty condition is invalid");
403 while (isspace((int) *p)) p++; /* skip spaces after (COND)*/
405 } else { /* it's a bare FOO==BAR */
407 * We didn't see anything special. The condition must be one of
417 return_P("Conditional check cannot begin with a regular expression");
420 slen = condition_tokenize_cast(p, &c->cast, error);
427 slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
433 while (isspace((int)*p)) p++; /* skip spaces after LHS */
436 * We may (or not) have an operator
445 * don't skip the brace. We'll look for it later.
454 return_P("No closing brace at end of string");
462 } else if (((p[0] == '&') && (p[1] == '&')) ||
463 ((p[0] == '|') && (p[1] == '|'))) {
467 return_0("Cannot do cast for existence check");
470 c->type = COND_TYPE_EXISTS;
473 c->data.vpt = radius_str2tmpl(c, lhs, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
475 return_P("Failed creating exists");
478 rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
480 } else { /* it's an operator */
485 * The next thing should now be a comparison operator.
488 c->type = COND_TYPE_MAP;
493 return_P("Invalid text. Expected comparison operator");
500 } else if (p[1] == '~') {
506 } else if (p[1] == '*') {
507 if (lhs_type != T_BARE_WORD) {
508 return_P("Cannot use !* on a string");
515 goto invalid_operator;
524 } else if (p[1] == '~') {
530 } else if (p[1] == '*') {
531 if (lhs_type != T_BARE_WORD) {
532 return_P("Cannot use =* on a string");
540 return_P("Invalid operator");
568 while (isspace((int) *p)) p++; /* skip spaces after operator */
571 return_P("Expected text after operator");
575 * Cannot have a cast on the RHS.
576 * But produce good errors, too.
579 DICT_ATTR const *cast_da;
581 slen = condition_tokenize_cast(p, &cast_da, error);
587 return_P("Unexpected cast");
590 if (c->cast != cast_da) {
591 return_P("Cannot cast to a different data type");
594 return_P("Unnecessary cast");
601 slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
607 * Sanity checks for regexes.
611 return_P("Expected regular expression");
617 if (p[slen] == 'i') {
622 } else if (!regex && (*p == '/')) {
623 return_P("Unexpected regular expression");
626 c->data.map = radius_str2map(c, lhs, lhs_type, op, rhs, rhs_type,
627 REQUEST_CURRENT, PAIR_LIST_REQUEST,
628 REQUEST_CURRENT, PAIR_LIST_REQUEST);
631 * FIXME: if strings are T_BARE_WORD and they start with '&',
632 * then they refer to attributes which have not yet been
633 * defined. Create the template(s) as literals, and
634 * fix them up in pass2.
637 (lhs_type != T_BARE_WORD)) {
638 return_0("Syntax error");
640 c->data.map = radius_str2map(c, lhs, lhs_type + 1, op, rhs, rhs_type,
641 REQUEST_CURRENT, PAIR_LIST_REQUEST,
642 REQUEST_CURRENT, PAIR_LIST_REQUEST);
644 return_0("Unknown attribute");
646 rad_const_free(c->data.map->dst->name);
647 c->data.map->dst->name = talloc_strdup(c->data.map->dst, lhs);
648 c->pass2_fixup = PASS2_FIXUP_ATTR;
651 if (c->data.map->src->type == VPT_TYPE_REGEX) {
652 c->data.map->src->vpt_iflag = i_flag;
656 * Could have been a reference to an attribute which is registered later.
657 * Mark it as being checked in pass2.
659 if ((lhs_type == T_BARE_WORD) &&
660 (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
661 c->pass2_fixup = PASS2_FIXUP_ATTR;
665 * Save the CONF_ITEM for later.
667 c->data.map->ci = ci;
670 * @todo: check LHS and RHS separately, to
673 if ((c->data.map->src->type == VPT_TYPE_LIST) ||
674 (c->data.map->dst->type == VPT_TYPE_LIST)) {
675 return_0("Cannot use list references in condition");
679 * Check cast type. We can have the RHS
680 * a string if the LHS has a cast. But
681 * if the RHS is an attr, it MUST be the
682 * same type as the LHS.
685 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
686 (c->cast->type != c->data.map->src->vpt_da->type)) {
690 if (c->data.map->src->type == VPT_TYPE_REGEX) {
691 return_0("Cannot use cast with regex comparison");
695 * The LHS is a literal which has been cast to a data type.
696 * Cast it to the appropriate data type.
698 if ((c->data.map->dst->type == VPT_TYPE_LITERAL) &&
699 !radius_cast_tmpl(c->data.map->dst, c->cast)) {
700 *error = "Failed to parse field";
701 if (lhs) talloc_free(lhs);
702 if (rhs) talloc_free(rhs);
704 return -(lhs_p - start);
708 * The RHS is a literal, and the LHS has been cast to a data
711 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
712 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
713 !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
714 return_rhs("Failed to parse field");
718 * We may be casting incompatible
719 * types. We check this based on
722 if (c->data.map->dst->type == VPT_TYPE_ATTR) {
727 if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) &&
728 (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
733 * Run-time parsing of strings.
734 * Run-time copying of octets.
736 if ((c->data.map->dst->vpt_da->type == PW_TYPE_STRING) ||
737 (c->data.map->dst->vpt_da->type == PW_TYPE_OCTETS)) {
742 * ipaddr to ipv4prefix is OK
744 if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV4_ADDR) &&
745 (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
750 * ipv6addr to ipv6prefix is OK
752 if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV6_ADDR) &&
753 (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
758 * integer64 to ethernet is OK.
760 if ((c->data.map->dst->vpt_da->type == PW_TYPE_INTEGER64) &&
761 (c->cast->type == PW_TYPE_ETHERNET)) {
769 if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) ||
770 (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
771 return_0("Cannot cast to attribute of incompatible size");
777 * Casting to a redundant type means we don't need the cast.
779 * Do this LAST, as the rest of the code above assumes c->cast
782 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
783 (c->cast->type == c->data.map->dst->vpt_da->type)) {
789 * Two attributes? They must be of the same type
791 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
792 (c->data.map->dst->type == VPT_TYPE_ATTR) &&
793 (c->data.map->dst->vpt_da->type != c->data.map->src->vpt_da->type)) {
795 return_0("Attribute comparisons must be of the same data type");
799 * Without a cast, we can't compare "foo" to User-Name,
800 * it has to be done the other way around.
802 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
803 (c->data.map->dst->type != VPT_TYPE_ATTR)) {
804 *error = "Cannot use attribute reference on right side of condition";
806 if (lhs) talloc_free(lhs);
807 if (rhs) talloc_free(rhs);
813 * Invalid: User-Name == bob
814 * Valid: User-Name == "bob"
816 * There's no real reason for
817 * this, other than consistency.
819 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
820 (c->data.map->src->type != VPT_TYPE_ATTR) &&
821 (c->data.map->dst->vpt_da->type == PW_TYPE_STRING) &&
822 (c->data.map->op != T_OP_CMP_TRUE) &&
823 (c->data.map->op != T_OP_CMP_FALSE) &&
824 (rhs_type == T_BARE_WORD)) {
825 return_rhs("Must have string as value for attribute");
829 * Quotes around non-string
830 * attributes mean that it's
831 * either xlat, or an exec.
833 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
834 (c->data.map->src->type != VPT_TYPE_ATTR) &&
835 (c->data.map->dst->vpt_da->type != PW_TYPE_STRING) &&
836 (c->data.map->dst->vpt_da->type != PW_TYPE_OCTETS) &&
837 (c->data.map->dst->vpt_da->type != PW_TYPE_DATE) &&
838 (rhs_type == T_SINGLE_QUOTED_STRING)) {
839 *error = "Value must be an unquoted string";
841 if (lhs) talloc_free(lhs);
842 if (rhs) talloc_free(rhs);
844 return -(rhs_p - start);
848 * The LHS has been cast to a data type, and the RHS is a
849 * literal. Cast the RHS to the type of the cast.
851 if (c->cast && (c->data.map->src->type == VPT_TYPE_LITERAL) &&
852 !radius_cast_tmpl(c->data.map->src, c->cast)) {
853 return_rhs("Failed to parse field");
857 * The LHS is an attribute, and the RHS is a literal. Cast the
858 * RHS to the data type of the LHS.
860 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
861 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
862 !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
863 DICT_ATTR const *da = c->data.map->dst->vpt_da;
865 if ((da->vendor == 0) &&
866 ((da->attr == PW_AUTH_TYPE) ||
867 (da->attr == PW_AUTZ_TYPE) ||
868 (da->attr == PW_ACCT_TYPE) ||
869 (da->attr == PW_SESSION_TYPE) ||
870 (da->attr == PW_POST_AUTH_TYPE) ||
871 (da->attr == PW_PRE_PROXY_TYPE) ||
872 (da->attr == PW_POST_PROXY_TYPE) ||
873 (da->attr == PW_PRE_ACCT_TYPE) ||
874 (da->attr == PW_RECV_COA_TYPE) ||
875 (da->attr == PW_SEND_COA_TYPE))) {
877 * The types for these attributes are dynamically allocated
878 * by modules.c, so we can't enforce strictness here.
880 c->pass2_fixup = PASS2_FIXUP_TYPE;
883 return_rhs("Failed to parse value for attribute");
890 while (isspace((int) *p)) p++; /* skip spaces after RHS */
892 } /* parse a condition (COND) or FOO OP BAR*/
899 return_P("Unexpected closing brace");
903 while (isspace((int) *p)) p++; /* skip spaces after closing brace */
908 * End of string is now allowed.
912 return_P("No closing brace at end of string");
918 if (!(((p[0] == '&') && (p[1] == '&')) ||
919 ((p[0] == '|') && (p[1] == '|')))) {
920 *error = "Unexpected text after condition";
922 if (lhs) talloc_free(lhs);
923 if (rhs) talloc_free(rhs);
929 * Recurse to parse the next condition.
935 * May still be looking for a closing brace.
937 slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
940 if (lhs) talloc_free(lhs);
941 if (rhs) talloc_free(rhs);
943 return slen - (p - start);
949 * Normalize the condition before returning.
951 * We collapse multiple levels of braces to one. Then
952 * convert maps to literals. Then literals to true/false
953 * statements. Then true/false ||/&& followed by other
954 * conditions to just conditions.
956 * Order is important. The more complex cases are
957 * converted to simpler ones, from the most complex cases
958 * to the simplest ones.
963 * (FOO) ... --> FOO ...
965 if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
968 child = talloc_steal(ctx, c->data.child);
969 c->data.child = NULL;
971 child->next = talloc_steal(child, c->next);
974 child->next_op = c->next_op;
977 * Set the negation properly
979 if ((c->negate && !child->negate) ||
980 (!c->negate && child->negate)) {
981 child->negate = true;
983 child->negate = false;
992 * (FOO ...) --> FOO ...
994 * But don't do !(FOO || BAR) --> !FOO || BAR
995 * Because that's different.
997 if ((c->type == COND_TYPE_CHILD) &&
998 !c->next && !c->negate) {
1001 child = talloc_steal(ctx, c->data.child);
1002 c->data.child = NULL;
1010 * Convert maps to literals. Convert one form of map to
1011 * a standardized form. This doesn't make any
1012 * theoretical difference, but it does mean that the
1013 * run-time evaluation has fewer cases to check.
1015 if (c->type == COND_TYPE_MAP) do {
1017 * !FOO !~ BAR --> FOO =~ BAR
1019 if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
1021 c->data.map->op = T_OP_REG_EQ;
1025 * FOO !~ BAR --> !FOO =~ BAR
1027 if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
1029 c->data.map->op = T_OP_REG_EQ;
1033 * !FOO != BAR --> FOO == BAR
1035 if (c->negate && (c->data.map->op == T_OP_NE)) {
1037 c->data.map->op = T_OP_CMP_EQ;
1041 * This next one catches "LDAP-Group != foo",
1042 * which doesn't work as-is, but this hack fixes
1045 * FOO != BAR --> !FOO == BAR
1047 if (!c->negate && (c->data.map->op == T_OP_NE)) {
1049 c->data.map->op = T_OP_CMP_EQ;
1053 * FOO =* BAR --> FOO
1054 * FOO !* BAR --> !FOO
1056 if ((c->data.map->op == T_OP_CMP_TRUE) ||
1057 (c->data.map->op == T_OP_CMP_FALSE)) {
1058 value_pair_tmpl_t *vpt;
1060 vpt = talloc_steal(c, c->data.map->dst);
1061 c->data.map->dst = NULL;
1064 * Invert the negation bit.
1066 if (c->data.map->op == T_OP_CMP_FALSE) {
1067 c->negate = !c->negate;
1070 TALLOC_FREE(c->data.map);
1072 c->type = COND_TYPE_EXISTS;
1074 break; /* it's no longer a map */
1078 * Both are data (IP address, integer, etc.)
1080 * We can do the evaluation here, so that it
1081 * doesn't need to be done at run time
1083 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
1084 (c->data.map->src->type == VPT_TYPE_DATA)) {
1087 rad_assert(c->cast != NULL);
1089 rcode = radius_evaluate_map(NULL, 0, 0, c);
1090 TALLOC_FREE(c->data.map);
1093 c->type = COND_TYPE_TRUE;
1095 c->type = COND_TYPE_FALSE;
1098 break; /* it's no longer a map */
1102 * Both are literal strings. They're not parsed
1103 * as VPT_TYPE_DATA because there's no cast to an
1106 * We can do the evaluation here, so that it
1107 * doesn't need to be done at run time
1109 if ((c->data.map->src->type == VPT_TYPE_LITERAL) &&
1110 (c->data.map->dst->type == VPT_TYPE_LITERAL) &&
1114 rad_assert(c->cast == NULL);
1116 rcode = radius_evaluate_map(NULL, 0, 0, c);
1118 c->type = COND_TYPE_TRUE;
1120 DEBUG("OPTIMIZING %s %s --> FALSE",
1121 c->data.map->dst->name,
1122 c->data.map->src->name);
1123 c->type = COND_TYPE_FALSE;
1127 * Free map after using it above.
1129 TALLOC_FREE(c->data.map);
1134 * <ipaddr>"foo" CMP &Attribute-Name The cast is
1135 * unnecessary, and we can re-write it so that
1136 * the attribute reference is on the LHS.
1139 (c->data.map->src->type == VPT_TYPE_ATTR) &&
1140 (c->data.map->dst->type != VPT_TYPE_ATTR)) {
1141 value_pair_tmpl_t *tmp;
1143 tmp = c->data.map->src;
1144 c->data.map->src = c->data.map->dst;
1145 c->data.map->dst = tmp;
1149 switch (c->data.map->op) {
1155 c->data.map->op = T_OP_GE;
1159 c->data.map->op = T_OP_GT;
1163 c->data.map->op = T_OP_LE;
1167 c->data.map->op = T_OP_LT;
1171 return_0("Internal sanity check failed");
1175 * This must have been parsed into VPT_TYPE_DATA.
1177 rad_assert(c->data.map->src->type != VPT_TYPE_LITERAL);
1183 * Existence checks. We short-circuit static strings,
1186 if (c->type == COND_TYPE_EXISTS) {
1187 switch (c->data.vpt->type) {
1195 * 'true' and 'false' are special strings
1196 * which mean themselves.
1198 * For integers, 0 is false, all other
1199 * integers are true.
1201 * For strings, '' and "" are false.
1202 * 'foo' and "foo" are true.
1204 * The str2tmpl function takes care of
1205 * marking "%{foo}" as VPT_TYPE_XLAT, so
1206 * the strings here are fixed at compile
1209 * `exec` and "%{...}" are left alone.
1211 * Bare words must be module return
1214 case VPT_TYPE_LITERAL:
1215 if ((strcmp(c->data.vpt->name, "true") == 0) ||
1216 (strcmp(c->data.vpt->name, "1") == 0)) {
1217 c->type = COND_TYPE_TRUE;
1218 TALLOC_FREE(c->data.vpt);
1220 } else if ((strcmp(c->data.vpt->name, "false") == 0) ||
1221 (strcmp(c->data.vpt->name, "0") == 0)) {
1222 c->type = COND_TYPE_FALSE;
1223 TALLOC_FREE(c->data.vpt);
1225 } else if (!*c->data.vpt->name) {
1226 c->type = COND_TYPE_FALSE;
1227 TALLOC_FREE(c->data.vpt);
1229 } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
1230 (lhs_type == T_DOUBLE_QUOTED_STRING)) {
1231 c->type = COND_TYPE_TRUE;
1232 TALLOC_FREE(c->data.vpt);
1234 } else if (lhs_type == T_BARE_WORD) {
1238 for (q = c->data.vpt->name;
1241 if (!isdigit((int) *q)) {
1247 * It's all digits, and therefore
1251 c->type = COND_TYPE_TRUE;
1252 TALLOC_FREE(c->data.vpt);
1256 rcode = fr_str2int(allowed_return_codes,
1257 c->data.vpt->name, 0);
1259 return_0("Expected a module return code");
1264 * Else lhs_type==T_OP_INVALID, and this
1265 * node was made by promoting a child
1266 * which had already been normalized.
1271 return_0("Cannot use data here");
1274 return_0("Internal sanity check failed");
1281 if (c->type == COND_TYPE_TRUE) {
1284 c->type = COND_TYPE_FALSE;
1291 if (c->type == COND_TYPE_FALSE) {
1294 c->type = COND_TYPE_TRUE;
1299 * true && FOO --> FOO
1301 if ((c->type == COND_TYPE_TRUE) &&
1302 (c->next_op == COND_AND)) {
1305 next = talloc_steal(ctx, c->next);
1314 * false && FOO --> false
1316 if ((c->type == COND_TYPE_FALSE) &&
1317 (c->next_op == COND_AND)) {
1318 talloc_free(c->next);
1320 c->next_op = COND_NONE;
1324 * false || FOO --> FOO
1326 if ((c->type == COND_TYPE_FALSE) &&
1327 (c->next_op == COND_OR)) {
1330 next = talloc_steal(ctx, c->next);
1339 * true || FOO --> true
1341 if ((c->type == COND_TYPE_TRUE) &&
1342 (c->next_op == COND_OR)) {
1343 talloc_free(c->next);
1345 c->next_op = COND_NONE;
1348 if (lhs) talloc_free(lhs);
1349 if (rhs) talloc_free(rhs);
1355 /** Tokenize a conditional check
1357 * @param[in] ctx for talloc
1358 * @param[in] ci for CONF_ITEM
1359 * @param[in] start the start of the string to process. Should be "(..."
1360 * @param[out] head the parsed condition structure
1361 * @param[out] error the parse error (if any)
1362 * @param[in] flags do one/two pass
1363 * @return length of the string skipped, or when negative, the offset to the offending error
1365 ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
1367 return condition_tokenize(ctx, ci, start, false, head, error, flags);
1373 bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
1377 * Process this one, exit on error.
1379 if (!callback(ctx, c)) return false;
1382 case COND_TYPE_INVALID:
1385 case COND_TYPE_EXISTS:
1387 case COND_TYPE_TRUE:
1388 case COND_TYPE_FALSE:
1391 case COND_TYPE_CHILD:
1393 * Walk over the child.
1395 if (!fr_condition_walk(c->data.child, callback, ctx)) {
1403 if (c->next_op == COND_NONE) break;
1406 * process the next sibling