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;
57 rad_assert(bufsize > 0);
66 *(p++) = '!'; /* FIXME: only allow for child? */
70 case COND_TYPE_EXISTS:
71 rad_assert(c->data.vpt != NULL);
73 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
74 c->cast->type, "??"));
78 len = tmpl_prints(p, end - p, c->data.vpt, NULL);
83 rad_assert(c->data.map != NULL);
85 *(p++) = '['; /* for extra-clear debugging */
88 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
89 c->cast->type, "??"));
93 len = map_prints(p, end - p, c->data.map);
100 case COND_TYPE_CHILD:
101 rad_assert(c->data.child != NULL);
103 len = fr_cond_sprint(p, end - p, c->data.child);
109 strlcpy(buffer, "true", bufsize);
110 return strlen(buffer);
112 case COND_TYPE_FALSE:
113 strlcpy(buffer, "false", bufsize);
114 return strlen(buffer);
121 if (c->next_op == COND_NONE) {
122 rad_assert(c->next == NULL);
127 if (c->next_op == COND_AND) {
128 strlcpy(p, " && ", end - p);
131 } else if (c->next_op == COND_OR) {
132 strlcpy(p, " || ", end - p);
144 static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start,
147 char const *p = start;
155 *op = T_DOUBLE_QUOTED_STRING;
159 *op = T_SINGLE_QUOTED_STRING;
163 *op = T_BACK_QUOTED_STRING;
167 *op = T_OP_REG_EQ; /* a bit of a hack. */
172 *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
173 if (!*out) return -1;
180 * Call the STANDARD parse function to figure out what the string is.
186 PW_TYPE src_type = PW_TYPE_STRING;
189 * Regex compilers can handle escapes. So we don't do it.
191 if (quote == '/') quote = '\0';
193 slen = value_data_from_str(ctx, &data, &src_type, NULL, start + 1, p - (start + 1), quote);
195 *error = "error parsing string";
200 *out = talloc_steal(ctx, data.ptr);
201 data.strvalue = NULL;
205 *(q++) = '\0'; /* terminate the output string */
207 out2 = talloc_realloc(ctx, *out, char, (q - *out));
209 *error = "Out of memory";
222 *error = "End of string after escape";
227 * Hacks for backwards compatibility
230 if (p[1] == start[0]) { /* Convert '\'' --> ' */
259 *error = "Unterminated string";
263 static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
264 FR_TOKEN *op, char const **error)
267 char const *p = start;
269 if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
270 return condition_tokenize_string(ctx, out, error, start, op);
274 if (*p == '&') p++; /* special-case &User-Name */
278 * The LHS should really be limited to only a few
279 * things. For now, we allow pretty much anything.
282 *error = "Unexpected escape";
294 * Spaces or special characters delineate the word
296 if (isspace((int) *p) || (*p == '&') || (*p == '|') ||
297 (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
301 if ((*p == '"') || (*p == '\'') || (*p == '`')) {
302 *error = "Unexpected start of string";
311 *error = "Empty string is invalid";
315 *out = talloc_array(ctx, char, len + 1);
316 memcpy(*out, start, len);
322 static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda, char const **error)
324 char const *p = start;
328 while (isspace((int) *p)) p++; /* skip spaces before condition */
330 if (*p != '<') return 0;
334 while (*q && *q != '>') q++;
336 cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
337 if (cast == PW_TYPE_INVALID) {
338 *error = "Invalid data type in cast";
343 * We can only cast to basic data types. Complex ones
347 #ifdef WITH_ASCEND_BINARY
348 case PW_TYPE_ABINARY:
350 case PW_TYPE_COMBO_IP_ADDR:
352 case PW_TYPE_EXTENDED:
353 case PW_TYPE_LONG_EXTENDED:
356 *error = "Forbidden data type in cast";
363 *pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
365 *error = "Cannot cast to this data type";
371 while (isspace((int) *q)) q++; /* skip spaces after cast */
376 static bool condition_check_types(fr_cond_t *c, PW_TYPE lhs_type)
379 * SOME integer mismatch is OK. If the LHS has a large type,
380 * and the RHS has a small type, it's OK.
382 * If the LHS has a small type, and the RHS has a large type,
383 * then add a cast to the LHS.
385 if (lhs_type == PW_TYPE_INTEGER64) {
386 if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
387 (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
388 (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
394 if (lhs_type == PW_TYPE_INTEGER) {
395 if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
396 (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
401 if (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) {
402 c->cast = c->data.map->rhs->tmpl_da;
407 if (lhs_type == PW_TYPE_SHORT) {
408 if (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE) {
413 if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
414 (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER)) {
415 c->cast = c->data.map->rhs->tmpl_da;
420 if (lhs_type == PW_TYPE_BYTE) {
421 if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
422 (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
423 (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT)) {
424 c->cast = c->data.map->rhs->tmpl_da;
429 if ((lhs_type == PW_TYPE_IPV4_PREFIX) &&
430 (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_ADDR)) {
434 if ((lhs_type == PW_TYPE_IPV6_PREFIX) &&
435 (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_ADDR)) {
444 * Less code means less bugs
446 #define return_P(_x) *error = _x;goto return_p
447 #define return_0(_x) *error = _x;goto return_0
448 #define return_lhs(_x) *error = _x;goto return_lhs
449 #define return_rhs(_x) *error = _x;goto return_rhs
450 #define return_SLEN goto return_slen
453 /** Tokenize a conditional check
455 * @param[in] ctx for talloc
456 * @param[in] ci for CONF_ITEM
457 * @param[in] start the start of the string to process. Should be "(..."
458 * @param[in] brace look for a closing brace
459 * @param[out] pcond pointer to the returned condition structure
460 * @param[out] error the parse error (if any)
461 * @param[in] flags do one/two pass
462 * @return length of the string skipped, or when negative, the offset to the offending error
464 static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, bool brace,
465 fr_cond_t **pcond, char const **error, int flags)
468 char const *p = start;
469 char const *lhs_p, *rhs_p;
472 FR_TOKEN op, lhs_type, rhs_type;
474 c = talloc_zero(ctx, fr_cond_t);
476 rad_assert(c != NULL);
478 lhs_type = rhs_type = T_INVALID;
480 while (isspace((int) *p)) p++; /* skip spaces before condition */
483 return_P("Empty condition is invalid");
492 while (isspace((int) *p)) p++; /* skip spaces after negation */
498 return_P("Double negation is invalid");
509 * We've already eaten one layer of
510 * brackets. Go recurse to get more.
512 c->type = COND_TYPE_CHILD;
514 slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
519 if (!c->data.child) {
520 return_P("Empty condition is invalid");
524 while (isspace((int) *p)) p++; /* skip spaces after (COND)*/
526 } else { /* it's a bare FOO==BAR */
528 * We didn't see anything special. The condition must be one of
538 return_P("Conditional check cannot begin with a regular expression");
541 slen = condition_tokenize_cast(p, &c->cast, error);
548 slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
555 * If the LHS is 0xabcdef... automatically cast it to octets
557 if (!c->cast && (lhs_type == T_BARE_WORD) &&
558 (lhs[0] == '0') && (lhs[1] == 'x') &&
559 ((slen & 0x01) == 0)) {
561 return_P("Empty octet string is invalid");
564 c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_OCTETS, 0);
567 while (isspace((int)*p)) p++; /* skip spaces after LHS */
570 * We may (or not) have an operator
579 * don't skip the brace. We'll look for it later.
588 return_P("No closing brace at end of string");
596 } else if (((p[0] == '&') && (p[1] == '&')) ||
597 ((p[0] == '|') && (p[1] == '|'))) {
601 return_0("Cannot do cast for existence check");
604 c->type = COND_TYPE_EXISTS;
607 tlen = tmpl_afrom_str(c, &c->data.vpt, lhs, talloc_array_length(lhs) - 1,
608 lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
611 return_P(fr_strerror());
614 rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
616 if (c->data.vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
617 c->pass2_fixup = PASS2_FIXUP_ATTR;
620 } else { /* it's an operator */
629 * The next thing should now be a comparison operator.
631 c->type = COND_TYPE_MAP;
636 return_P("Invalid text. Expected comparison operator");
644 } else if (p[1] == '~') {
651 } else if (p[1] == '*') {
652 if (lhs_type != T_BARE_WORD) {
653 return_P("Cannot use !* on a string");
660 goto invalid_operator;
670 } else if (p[1] == '~') {
677 } else if (p[1] == '*') {
678 if (lhs_type != T_BARE_WORD) {
679 return_P("Cannot use =* on a string");
687 return_P("Invalid operator");
715 while (isspace((int) *p)) p++; /* skip spaces after operator */
718 return_P("Expected text after operator");
722 * Cannot have a cast on the RHS.
723 * But produce good errors, too.
726 DICT_ATTR const *cast_da;
728 slen = condition_tokenize_cast(p, &cast_da, error);
734 return_P("Unexpected cast");
737 if (c->cast != cast_da) {
738 return_P("Cannot cast to a different data type");
741 return_P("Unnecessary cast");
748 slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
755 * Sanity checks for regexes.
759 return_P("Expected regular expression");
784 } else if (!regex && (*p == '/')) {
785 return_P("Unexpected regular expression");
790 * Duplicate map_from_fields here, as we
791 * want to separate parse errors in the
792 * LHS from ones in the RHS.
794 c->data.map = map = talloc_zero(c, vp_map_t);
796 tlen = tmpl_afrom_str(map, &map->lhs, lhs, talloc_array_length(lhs) - 1,
797 lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
800 return_P(fr_strerror());
803 if (tmpl_define_unknown_attr(map->lhs) < 0) {
804 return_lhs("Failed defining attribute");
806 if (lhs) talloc_free(lhs);
807 if (rhs) talloc_free(rhs);
809 return -(lhs_p - start);
815 * If the RHS is 0xabcdef... automatically cast it to octets
816 * unless the LHS is an attribute of type octets, or an
819 if (!c->cast && (rhs_type == T_BARE_WORD) &&
820 (rhs[0] == '0') && (rhs[1] == 'x') &&
821 ((slen & 0x01) == 0)) {
823 return_P("Empty octet string is invalid");
826 if ((map->lhs->type != TMPL_TYPE_ATTR) ||
827 !((map->lhs->tmpl_da->type == PW_TYPE_OCTETS) ||
828 (map->lhs->tmpl_da->type == PW_TYPE_BYTE) ||
829 (map->lhs->tmpl_da->type == PW_TYPE_SHORT) ||
830 (map->lhs->tmpl_da->type == PW_TYPE_INTEGER) ||
831 (map->lhs->tmpl_da->type == PW_TYPE_INTEGER64))) {
832 c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_OCTETS, 0);
836 if ((map->lhs->type == TMPL_TYPE_ATTR) &&
837 map->lhs->tmpl_da->flags.is_unknown &&
838 map_cast_from_hex(map, rhs_type, rhs)) {
842 tlen = tmpl_afrom_str(map, &map->rhs, rhs, talloc_array_length(rhs) - 1, rhs_type,
843 REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
846 return_P(fr_strerror());
849 if (tmpl_define_unknown_attr(map->rhs) < 0) {
850 return_rhs("Failed defining attribute");
855 * Unknown attributes get marked up for pass2.
857 if ((c->data.map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) ||
858 (c->data.map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED)) {
859 c->pass2_fixup = PASS2_FIXUP_ATTR;
863 if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
864 c->data.map->rhs->tmpl_iflag = iflag;
865 c->data.map->rhs->tmpl_mflag = mflag;
870 * Save the CONF_ITEM for later.
872 c->data.map->ci = ci;
875 * @todo: check LHS and RHS separately, to
878 if ((c->data.map->rhs->type == TMPL_TYPE_LIST) ||
879 (c->data.map->lhs->type == TMPL_TYPE_LIST)) {
880 return_0("Cannot use list references in condition");
884 * Check cast type. We can have the RHS
885 * a string if the LHS has a cast. But
886 * if the RHS is an attr, it MUST be the
887 * same type as the LHS.
890 if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
891 (c->cast->type != c->data.map->rhs->tmpl_da->type)) {
892 if (condition_check_types(c, c->cast->type)) {
900 if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
901 return_0("Cannot use cast with regex comparison");
906 * The LHS is a literal which has been cast to a data type.
907 * Cast it to the appropriate data type.
909 if ((c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
910 (tmpl_cast_in_place(c->data.map->lhs, c->cast->type, c->cast) < 0)) {
911 *error = "Failed to parse field";
912 if (lhs) talloc_free(lhs);
913 if (rhs) talloc_free(rhs);
915 return -(lhs_p - start);
919 * The RHS is a literal, and the LHS has been cast to a data
922 if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
923 (c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
924 (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
925 return_rhs("Failed to parse field");
929 * We may be casting incompatible
930 * types. We check this based on
933 if (c->data.map->lhs->type == TMPL_TYPE_ATTR) {
938 if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) &&
939 (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
944 * Run-time parsing of strings.
945 * Run-time copying of octets.
947 if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) ||
948 (c->data.map->lhs->tmpl_da->type == PW_TYPE_OCTETS)) {
953 * ifid to integer64 is OK
955 if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IFID) &&
956 (c->cast->type == PW_TYPE_INTEGER64)) {
961 * ipaddr to ipv4prefix is OK
963 if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) &&
964 (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
969 * ipv6addr to ipv6prefix is OK
971 if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) &&
972 (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
977 * integer64 to ethernet is OK.
979 if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_INTEGER64) &&
980 (c->cast->type == PW_TYPE_ETHERNET)) {
988 if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) ||
989 (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
990 return_0("Cannot cast to attribute of incompatible size");
996 * Casting to a redundant type means we don't need the cast.
998 * Do this LAST, as the rest of the code above assumes c->cast
1001 if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1002 (c->cast->type == c->data.map->lhs->tmpl_da->type)) {
1010 * Two attributes? They must be of the same type
1012 if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
1013 (c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1014 (c->data.map->lhs->tmpl_da->type != c->data.map->rhs->tmpl_da->type)) {
1015 if (condition_check_types(c, c->data.map->lhs->tmpl_da->type)) {
1020 return_0("Attribute comparisons must be of the same data type");
1024 * Without a cast, we can't compare "foo" to User-Name,
1025 * it has to be done the other way around.
1027 if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
1028 (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
1029 *error = "Cannot use attribute reference on right side of condition";
1031 if (lhs) talloc_free(lhs);
1032 if (rhs) talloc_free(rhs);
1038 * Invalid: User-Name == bob
1039 * Valid: User-Name == "bob"
1041 * There's no real reason for
1042 * this, other than consistency.
1044 if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1045 (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
1046 (c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1047 (c->data.map->op != T_OP_CMP_TRUE) &&
1048 (c->data.map->op != T_OP_CMP_FALSE) &&
1049 (rhs_type == T_BARE_WORD)) {
1050 return_rhs("Must have string as value for attribute");
1054 * Quotes around non-string
1055 * attributes mean that it's
1056 * either xlat, or an exec.
1058 if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1059 (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
1060 (c->data.map->lhs->tmpl_da->type != PW_TYPE_STRING) &&
1061 (c->data.map->lhs->tmpl_da->type != PW_TYPE_OCTETS) &&
1062 (c->data.map->lhs->tmpl_da->type != PW_TYPE_DATE) &&
1063 (rhs_type == T_SINGLE_QUOTED_STRING)) {
1064 *error = "Value must be an unquoted string";
1066 if (lhs) talloc_free(lhs);
1067 if (rhs) talloc_free(rhs);
1069 return -(rhs_p - start);
1073 * The LHS has been cast to a data type, and the RHS is a
1074 * literal. Cast the RHS to the type of the cast.
1076 if (c->cast && (c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
1077 (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
1078 return_rhs("Failed to parse field");
1082 * The LHS is an attribute, and the RHS is a literal. Cast the
1083 * RHS to the data type of the LHS.
1085 * Note: There's a hack in here to always parse RHS as the
1086 * equivalent prefix type if the LHS is an IP address.
1088 * This allows Framed-IP-Address < 192.168.0.0./24
1090 if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1091 (c->data.map->rhs->type == TMPL_TYPE_LITERAL)) {
1094 switch (c->data.map->lhs->tmpl_da->type) {
1095 case PW_TYPE_IPV4_ADDR:
1096 type = PW_TYPE_IPV4_PREFIX;
1099 case PW_TYPE_IPV6_ADDR:
1100 type = PW_TYPE_IPV6_PREFIX;
1104 type = c->data.map->lhs->tmpl_da->type;
1108 if (tmpl_cast_in_place(c->data.map->rhs, type, c->data.map->lhs->tmpl_da) < 0) {
1109 DICT_ATTR const *da = c->data.map->lhs->tmpl_da;
1111 if ((da->vendor == 0) &&
1112 ((da->attr == PW_AUTH_TYPE) ||
1113 (da->attr == PW_AUTZ_TYPE) ||
1114 (da->attr == PW_ACCT_TYPE) ||
1115 (da->attr == PW_SESSION_TYPE) ||
1116 (da->attr == PW_POST_AUTH_TYPE) ||
1117 (da->attr == PW_PRE_PROXY_TYPE) ||
1118 (da->attr == PW_POST_PROXY_TYPE) ||
1119 (da->attr == PW_PRE_ACCT_TYPE) ||
1120 (da->attr == PW_RECV_COA_TYPE) ||
1121 (da->attr == PW_SEND_COA_TYPE))) {
1123 * The types for these attributes are dynamically allocated
1124 * by modules.c, so we can't enforce strictness here.
1126 c->pass2_fixup = PASS2_FIXUP_TYPE;
1129 return_rhs("Failed to parse value for attribute");
1134 * Stupid WiMAX shit.
1135 * Cast the LHS to the
1138 if (c->data.map->lhs->tmpl_da->type == PW_TYPE_COMBO_IP_ADDR) {
1139 DICT_ATTR const *da;
1141 da = dict_attrbytype(c->data.map->lhs->tmpl_da->attr,
1142 c->data.map->lhs->tmpl_da->vendor,
1143 c->data.map->rhs->tmpl_data_type);
1145 return_rhs("Cannot find type for attribute");
1147 c->data.map->lhs->tmpl_da = da;
1149 } /* attr to literal comparison */
1152 * If the LHS is a bare word, AND it looks like
1153 * an attribute, try to parse it as such.
1155 * This allows LDAP-Group and SQL-Group to work.
1157 * The real fix is to just read the config files,
1158 * and do no parsing until after all of the modules
1159 * are loaded. But that has issues, too.
1161 if ((c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
1162 (lhs_type == T_BARE_WORD) &&
1163 (c->data.map->rhs->type == TMPL_TYPE_LITERAL)) {
1165 bool may_be_attr = true;
1170 * Backwards compatibility: Allow Foo-Bar,
1171 * e.g. LDAP-Group and SQL-Group.
1173 for (i = 0; i < c->data.map->lhs->len; i++) {
1174 if (!dict_attr_allowed_chars[(unsigned char) c->data.map->lhs->name[i]]) {
1175 may_be_attr = false;
1179 if (c->data.map->lhs->name[i] == '-') {
1182 may_be_attr = false;
1188 if (!hyphens || (hyphens > 3)) may_be_attr = false;
1191 attr_slen = tmpl_afrom_attr_str(c->data.map, &vpt, lhs,
1192 REQUEST_CURRENT, PAIR_LIST_REQUEST,
1194 if ((attr_slen > 0) && (vpt->len == c->data.map->lhs->len)) {
1195 talloc_free(c->data.map->lhs);
1196 c->data.map->lhs = vpt;
1197 c->pass2_fixup = PASS2_FIXUP_ATTR;
1201 } /* we didn't have a cast */
1206 while (isspace((int) *p)) p++; /* skip spaces after RHS */
1207 } /* parse OP RHS */
1208 } /* parse a condition (COND) or FOO OP BAR*/
1215 return_P("Unexpected closing brace");
1219 while (isspace((int) *p)) p++; /* skip spaces after closing brace */
1224 * End of string is now allowed.
1228 return_P("No closing brace at end of string");
1234 if (!(((p[0] == '&') && (p[1] == '&')) ||
1235 ((p[0] == '|') && (p[1] == '|')))) {
1236 *error = "Unexpected text after condition";
1238 if (lhs) talloc_free(lhs);
1239 if (rhs) talloc_free(rhs);
1241 return -(p - start);
1245 * Recurse to parse the next condition.
1251 * May still be looking for a closing brace.
1253 slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
1256 if (lhs) talloc_free(lhs);
1257 if (rhs) talloc_free(rhs);
1259 return slen - (p - start);
1265 * Normalize the condition before returning.
1267 * We collapse multiple levels of braces to one. Then
1268 * convert maps to literals. Then literals to true/false
1269 * statements. Then true/false ||/&& followed by other
1270 * conditions to just conditions.
1272 * Order is important. The more complex cases are
1273 * converted to simpler ones, from the most complex cases
1274 * to the simplest ones.
1279 * (FOO) ... --> FOO ...
1281 if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
1284 child = talloc_steal(ctx, c->data.child);
1285 c->data.child = NULL;
1287 child->next = talloc_steal(child, c->next);
1290 child->next_op = c->next_op;
1293 * Set the negation properly
1295 if ((c->negate && !child->negate) ||
1296 (!c->negate && child->negate)) {
1297 child->negate = true;
1299 child->negate = false;
1308 * (FOO ...) --> FOO ...
1310 * But don't do !(FOO || BAR) --> !FOO || BAR
1311 * Because that's different.
1313 if ((c->type == COND_TYPE_CHILD) &&
1314 !c->next && !c->negate) {
1317 child = talloc_steal(ctx, c->data.child);
1318 c->data.child = NULL;
1326 * Convert maps to literals. Convert one form of map to
1327 * a standardized form. This doesn't make any
1328 * theoretical difference, but it does mean that the
1329 * run-time evaluation has fewer cases to check.
1331 if (c->type == COND_TYPE_MAP) do {
1333 * !FOO !~ BAR --> FOO =~ BAR
1335 if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
1337 c->data.map->op = T_OP_REG_EQ;
1341 * FOO !~ BAR --> !FOO =~ BAR
1343 if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
1345 c->data.map->op = T_OP_REG_EQ;
1349 * !FOO != BAR --> FOO == BAR
1351 if (c->negate && (c->data.map->op == T_OP_NE)) {
1353 c->data.map->op = T_OP_CMP_EQ;
1357 * This next one catches "LDAP-Group != foo",
1358 * which doesn't work as-is, but this hack fixes
1361 * FOO != BAR --> !FOO == BAR
1363 if (!c->negate && (c->data.map->op == T_OP_NE)) {
1365 c->data.map->op = T_OP_CMP_EQ;
1369 * FOO =* BAR --> FOO
1370 * FOO !* BAR --> !FOO
1372 * FOO may be a string, or a delayed attribute
1375 if ((c->data.map->op == T_OP_CMP_TRUE) ||
1376 (c->data.map->op == T_OP_CMP_FALSE)) {
1379 vpt = talloc_steal(c, c->data.map->lhs);
1380 c->data.map->lhs = NULL;
1383 * Invert the negation bit.
1385 if (c->data.map->op == T_OP_CMP_FALSE) {
1386 c->negate = !c->negate;
1389 TALLOC_FREE(c->data.map);
1391 c->type = COND_TYPE_EXISTS;
1393 break; /* it's no longer a map */
1397 * Both are data (IP address, integer, etc.)
1399 * We can do the evaluation here, so that it
1400 * doesn't need to be done at run time
1402 if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
1403 (c->data.map->rhs->type == TMPL_TYPE_DATA)) {
1406 rad_assert(c->cast != NULL);
1408 rcode = radius_evaluate_map(NULL, 0, 0, c);
1409 TALLOC_FREE(c->data.map);
1412 c->type = COND_TYPE_TRUE;
1414 c->type = COND_TYPE_FALSE;
1417 break; /* it's no longer a map */
1421 * Both are literal strings. They're not parsed
1422 * as TMPL_TYPE_DATA because there's no cast to an
1425 * We can do the evaluation here, so that it
1426 * doesn't need to be done at run time
1428 if ((c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
1429 (c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
1433 rad_assert(c->cast == NULL);
1435 rcode = radius_evaluate_map(NULL, 0, 0, c);
1437 c->type = COND_TYPE_TRUE;
1439 DEBUG3("OPTIMIZING (%s %s %s) --> FALSE",
1440 c->data.map->lhs->name,
1441 fr_int2str(fr_tokens, c->data.map->op, "??"),
1442 c->data.map->rhs->name);
1443 c->type = COND_TYPE_FALSE;
1447 * Free map after using it above.
1449 TALLOC_FREE(c->data.map);
1454 * <ipaddr>"foo" CMP &Attribute-Name The cast may
1455 * not be necessary, and we can re-write it so
1456 * that the attribute reference is on the LHS.
1459 (c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
1460 (c->cast->type == c->data.map->rhs->tmpl_da->type) &&
1461 (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
1464 tmp = c->data.map->rhs;
1465 c->data.map->rhs = c->data.map->lhs;
1466 c->data.map->lhs = tmp;
1470 switch (c->data.map->op) {
1476 c->data.map->op = T_OP_GE;
1480 c->data.map->op = T_OP_GT;
1484 c->data.map->op = T_OP_LE;
1488 c->data.map->op = T_OP_LT;
1492 return_0("Internal sanity check failed 1");
1496 * This must have been parsed into TMPL_TYPE_DATA.
1498 rad_assert(c->data.map->rhs->type != TMPL_TYPE_LITERAL);
1504 * Existence checks. We short-circuit static strings,
1507 * FIXME: the data types should be in the template, too.
1508 * So that we know where a literal came from.
1510 * "foo" is NOT the same as 'foo' or a bare foo.
1512 if (c->type == COND_TYPE_EXISTS) {
1513 switch (c->data.vpt->type) {
1514 case TMPL_TYPE_XLAT:
1515 case TMPL_TYPE_ATTR:
1516 case TMPL_TYPE_ATTR_UNDEFINED:
1517 case TMPL_TYPE_LIST:
1518 case TMPL_TYPE_EXEC:
1522 * 'true' and 'false' are special strings
1523 * which mean themselves.
1525 * For integers, 0 is false, all other
1526 * integers are true.
1528 * For strings, '' and "" are false.
1529 * 'foo' and "foo" are true.
1531 * The str2tmpl function takes care of
1532 * marking "%{foo}" as TMPL_TYPE_XLAT, so
1533 * the strings here are fixed at compile
1536 * `exec` and "%{...}" are left alone.
1538 * Bare words must be module return
1541 case TMPL_TYPE_LITERAL:
1542 if ((strcmp(c->data.vpt->name, "true") == 0) ||
1543 (strcmp(c->data.vpt->name, "1") == 0)) {
1544 c->type = COND_TYPE_TRUE;
1545 TALLOC_FREE(c->data.vpt);
1547 } else if ((strcmp(c->data.vpt->name, "false") == 0) ||
1548 (strcmp(c->data.vpt->name, "0") == 0)) {
1549 c->type = COND_TYPE_FALSE;
1550 TALLOC_FREE(c->data.vpt);
1552 } else if (!*c->data.vpt->name) {
1553 c->type = COND_TYPE_FALSE;
1554 TALLOC_FREE(c->data.vpt);
1556 } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
1557 (lhs_type == T_DOUBLE_QUOTED_STRING)) {
1558 c->type = COND_TYPE_TRUE;
1559 TALLOC_FREE(c->data.vpt);
1561 } else if (lhs_type == T_BARE_WORD) {
1566 for (q = c->data.vpt->name;
1569 if (!isdigit((int) *q)) {
1572 if (*q != '0') zeros = false;
1576 * It's all digits, and therefore
1577 * 'false' if zero, and 'true' otherwise.
1581 c->type = COND_TYPE_FALSE;
1583 c->type = COND_TYPE_TRUE;
1585 TALLOC_FREE(c->data.vpt);
1590 * Allow &Foo-Bar where Foo-Bar is an attribute
1591 * defined by a module.
1593 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
1597 rcode = fr_str2int(allowed_return_codes,
1598 c->data.vpt->name, 0);
1600 return_0("Expected a module return code");
1605 * Else lhs_type==T_INVALID, and this
1606 * node was made by promoting a child
1607 * which had already been normalized.
1611 case TMPL_TYPE_DATA:
1612 return_0("Cannot use data here");
1615 return_0("Internal sanity check failed 2");
1622 if (c->type == COND_TYPE_TRUE) {
1625 c->type = COND_TYPE_FALSE;
1632 if (c->type == COND_TYPE_FALSE) {
1635 c->type = COND_TYPE_TRUE;
1640 * true && FOO --> FOO
1642 if ((c->type == COND_TYPE_TRUE) &&
1643 (c->next_op == COND_AND)) {
1646 next = talloc_steal(ctx, c->next);
1655 * false && FOO --> false
1657 if ((c->type == COND_TYPE_FALSE) &&
1658 (c->next_op == COND_AND)) {
1659 talloc_free(c->next);
1661 c->next_op = COND_NONE;
1665 * false || FOO --> FOO
1667 if ((c->type == COND_TYPE_FALSE) &&
1668 (c->next_op == COND_OR)) {
1671 next = talloc_steal(ctx, c->next);
1680 * true || FOO --> true
1682 if ((c->type == COND_TYPE_TRUE) &&
1683 (c->next_op == COND_OR)) {
1684 talloc_free(c->next);
1686 c->next_op = COND_NONE;
1689 if (lhs) talloc_free(lhs);
1690 if (rhs) talloc_free(rhs);
1696 /** Tokenize a conditional check
1698 * @param[in] ctx for talloc
1699 * @param[in] ci for CONF_ITEM
1700 * @param[in] start the start of the string to process. Should be "(..."
1701 * @param[out] head the parsed condition structure
1702 * @param[out] error the parse error (if any)
1703 * @param[in] flags do one/two pass
1704 * @return length of the string skipped, or when negative, the offset to the offending error
1706 ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
1708 return condition_tokenize(ctx, ci, start, false, head, error, flags);
1714 bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
1718 * Process this one, exit on error.
1720 if (!callback(ctx, c)) return false;
1723 case COND_TYPE_INVALID:
1726 case COND_TYPE_EXISTS:
1728 case COND_TYPE_TRUE:
1729 case COND_TYPE_FALSE:
1732 case COND_TYPE_CHILD:
1734 * Walk over the child.
1736 if (!fr_condition_walk(c->data.child, callback, ctx)) {
1744 if (c->next_op == COND_NONE) break;
1747 * process the next sibling