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)
34 * This file shouldn't use any functions from the server core.
37 size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c)
41 char *end = buffer + bufsize - 1;
45 *(p++) = '!'; /* FIXME: only allow for child? */
49 case COND_TYPE_EXISTS:
50 rad_assert(c->data.vpt != NULL);
52 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
53 c->cast->type, "??"));
57 len = radius_tmpl2str(p, end - p, c->data.vpt);
62 rad_assert(c->data.map != NULL);
64 *(p++) = '['; /* for extra-clear debugging */
67 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
68 c->cast->type, "??"));
72 len = radius_map2str(p, end - p, c->data.map);
80 rad_assert(c->data.child != NULL);
82 len = fr_cond_sprint(p, end - p, c->data.child);
88 strlcpy(buffer, "true", bufsize);
89 return strlen(buffer);
92 strlcpy(buffer, "false", bufsize);
93 return strlen(buffer);
100 if (c->next_op == COND_NONE) {
101 rad_assert(c->next == NULL);
106 if (c->next_op == COND_AND) {
107 strlcpy(p, " && ", end - p);
110 } else if (c->next_op == COND_OR) {
111 strlcpy(p, " || ", end - p);
124 * Cast a literal vpt to a value_data_t
126 static int cast_vpt(value_pair_tmpl_t *vpt, DICT_ATTR const *da)
131 rad_assert(vpt->type == VPT_TYPE_LITERAL);
133 vp = pairalloc(vpt, da);
134 if (!vp) return false;
136 if (!pairparsevalue(vp, vpt->name)) {
141 vpt->length = vp->length;
142 vpt->vpd = data = talloc(vpt, value_data_t);
143 if (!vpt->vpd) return false;
145 vpt->type = VPT_TYPE_DATA;
148 if (vp->da->flags.is_pointer) {
149 data->ptr = talloc_steal(vpt, vp->data.ptr);
152 memcpy(data, &vp->data, sizeof(*data));
160 static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char const *start, char **out,
161 FR_TOKEN *op, char const **error)
163 char const *p = start;
171 *op = T_DOUBLE_QUOTED_STRING;
175 *op = T_SINGLE_QUOTED_STRING;
179 *op = T_BACK_QUOTED_STRING;
183 *op = T_OP_REG_EQ; /* a bit of a hack. */
188 *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
189 if (!*out) return -1;
203 *error = "End of string after escape";
228 *error = "Unterminated string";
232 static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
233 FR_TOKEN *op, char const **error)
236 char const *p = start;
238 if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
239 return condition_tokenize_string(ctx, start, out, op, error);
243 if (*p == '&') p++; /* special-case &User-Name */
247 * The LHS should really be limited to only a few
248 * things. For now, we allow pretty much anything.
251 *error = "Unexpected escape";
263 * Spaces or special characters delineate the word
265 if (isspace((int) *p) || (*p == '&') || (*p == '|') ||
266 (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
270 if ((*p == '"') || (*p == '\'') || (*p == '`')) {
271 *error = "Unexpected start of string";
280 *error = "Empty string is invalid";
284 *out = talloc_array(ctx, char, len + 1);
285 memcpy(*out, start, len);
291 static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda, char const **error)
293 char const *p = start;
297 while (isspace((int) *p)) p++; /* skip spaces before condition */
299 if (*p != '<') return 0;
303 while (*q && *q != '>') q++;
305 cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
306 if (cast == PW_TYPE_INVALID) {
307 *error = "Invalid data type in cast";
311 *pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
313 *error = "Cannot cast to this data type";
319 while (isspace((int) *q)) q++; /* skip spaces after cast */
325 * Less code means less bugs
327 #define return_P(_x) *error = _x;goto return_p
328 #define return_0(_x) *error = _x;goto return_0
329 #define return_lhs(_x) *error = _x;goto return_lhs
330 #define return_rhs(_x) *error = _x;goto return_rhs
331 #define return_SLEN goto return_slen
334 /** Tokenize a conditional check
336 * @param[in] ctx for talloc
337 * @param[in] ci for CONF_ITEM
338 * @param[in] start the start of the string to process. Should be "(..."
339 * @param[in] brace look for a closing brace
340 * @param[in] flags do one/two pass
341 * @param[out] pcond pointer to the returned condition structure
342 * @param[out] error the parse error (if any)
343 * @return length of the string skipped, or when negative, the offset to the offending error
345 static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace, fr_cond_t **pcond, char const **error, int flags)
348 char const *p = start;
349 char const *lhs_p, *rhs_p;
352 FR_TOKEN op, lhs_type, rhs_type;
354 c = talloc_zero(ctx, fr_cond_t);
356 rad_assert(c != NULL);
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;
392 slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
397 if (!c->data.child) {
398 return_P("Empty condition is invalid");
402 while (isspace((int) *p)) p++; /* skip spaces after (COND)*/
404 } else { /* it's a bare FOO==BAR */
406 * We didn't see anything special. The condition must be one of
416 return_P("Conditional check cannot begin with a regular expression");
419 slen = condition_tokenize_cast(p, &c->cast, error);
426 slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
432 while (isspace((int)*p)) p++; /* skip spaces after LHS */
435 * We may (or not) have an operator
444 * don't skip the brace. We'll look for it later.
453 return_P("No closing brace at end of string");
461 } else if (((p[0] == '&') && (p[1] == '&')) ||
462 ((p[0] == '|') && (p[1] == '|'))) {
466 return_0("Cannot do cast for existence check");
469 if (lhs_type == T_BARE_WORD) {
470 if ((strcmp(lhs, "true") == 0) ||
471 ((lhs[0] == '1') && !lhs[1])) {
472 c->type = COND_TYPE_TRUE;
474 } else if ((strcmp(lhs, "false") == 0) ||
475 ((lhs[0] == '0') && !lhs[1])) {
476 c->type = COND_TYPE_FALSE;
484 c->type = COND_TYPE_EXISTS;
485 c->data.vpt = radius_str2tmpl(c, lhs, lhs_type);
487 return_P("Failed creating exists");
491 } else { /* it's an operator */
495 * The next thing should now be a comparison operator.
498 c->type = COND_TYPE_MAP;
501 return_P("Invalid text. Expected comparison operator");
508 } else if (p[1] == '~') {
514 } else if (p[1] == '*') {
515 if (lhs_type != T_BARE_WORD) {
516 return_P("Cannot use !* on a string");
523 goto invalid_operator;
532 } else if (p[1] == '~') {
538 } else if (p[1] == '*') {
539 if (lhs_type != T_BARE_WORD) {
540 return_P("Cannot use =* on a string");
548 return_P("Invalid operator");
576 while (isspace((int) *p)) p++; /* skip spaces after operator */
579 return_P("Expected text after operator");
583 * Cannot have a cast on the RHS.
584 * But produce good errors, too.
587 DICT_ATTR const *cast_da;
589 slen = condition_tokenize_cast(p, &cast_da, error);
595 return_P("Unexpected cast");
598 if (c->cast != cast_da) {
599 return_P("Cannot cast to a different data type");
602 return_P("Unnecessary cast");
609 slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
615 * Sanity checks for regexes.
619 return_P("Expected regular expression");
625 if (p[slen] == 'i') {
630 } else if (!regex && (*p == '/')) {
631 return_P("Unexpected regular expression");
634 c->data.map = radius_str2map(c, lhs, lhs_type, op, rhs, rhs_type,
635 REQUEST_CURRENT, PAIR_LIST_REQUEST,
636 REQUEST_CURRENT, PAIR_LIST_REQUEST);
639 return_0("Syntax error");
643 * Could have been a reference to an attribute which is registered later.
644 * Mark it as being checked in pass2.
646 if ((lhs_type == T_BARE_WORD) &&
647 (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
648 c->pass2_fixup = PASS2_FIXUP_ATTR;
652 * Save the CONF_ITEM for later.
654 c->data.map->ci = ci;
657 * foo =* bar is just (foo)
658 * foo !* bar is just (!foo)
660 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
661 value_pair_tmpl_t *vpt;
663 vpt = talloc_steal(c, c->data.map->dst);
664 c->data.map->dst = NULL;
666 talloc_free(c->data.map);
667 c->type = COND_TYPE_EXISTS;
671 * Invert the negation bit.
673 if (op == T_OP_CMP_FALSE) {
674 c->negate = !c->negate;
681 * @todo: check LHS and RHS separately, to
684 if ((c->data.map->src->type == VPT_TYPE_LIST) ||
685 (c->data.map->dst->type == VPT_TYPE_LIST)) {
686 return_0("Cannot use list references in condition");
690 * Check cast type. We can have the RHS
691 * a string if the LHS has a cast. But
692 * if the RHS is an attr, it MUST be the
693 * same type as the LHS.
696 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
697 (c->cast->type != c->data.map->src->da->type)) {
701 if (c->data.map->src->type == VPT_TYPE_REGEX) {
702 return_0("Cannot use cast with regex comparison");
706 * The LHS is a literal which has been cast to a data type.
707 * Cast it to the appropriate data type.
709 if ((c->data.map->dst->type == VPT_TYPE_LITERAL) &&
710 !cast_vpt(c->data.map->dst, c->cast)) {
711 *error = "Failed to parse field";
712 if (lhs) talloc_free(lhs);
713 if (rhs) talloc_free(rhs);
715 return -(lhs_p - start);
719 * The RHS is a literal, and the LHS has been cast to a data
722 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
723 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
724 !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
725 return_rhs("Failed to parse field");
729 * Casting to a redundant type means we don't need the cast.
731 * Do this LAST, as the rest of the code above assumes c->cast
734 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
735 (c->cast->type == c->data.map->dst->da->type)) {
741 * Two attributes? They must be of the same type
743 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
744 (c->data.map->dst->type == VPT_TYPE_ATTR) &&
745 (c->data.map->dst->da->type != c->data.map->src->da->type)) {
747 return_0("Attribute comparisons must be of the same attribute type");
751 * Without a cast, we can't compare "foo" to User-Name,
752 * it has to be done the other way around.
754 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
755 (c->data.map->dst->type != VPT_TYPE_ATTR)) {
756 *error = "Cannot use attribute reference on right side of condition";
758 if (lhs) talloc_free(lhs);
759 if (rhs) talloc_free(rhs);
765 * Invalid: User-Name == bob
766 * Valid: User-Name == "bob"
768 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
769 (c->data.map->src->type != VPT_TYPE_ATTR) &&
770 (c->data.map->dst->da->type == PW_TYPE_STRING) &&
771 (rhs_type == T_BARE_WORD)) {
772 return_rhs("Must have string as value for attribute");
776 * Quotes around non-string
777 * attributes mean that it's
778 * either xlat, or an exec.
780 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
781 (c->data.map->src->type != VPT_TYPE_ATTR) &&
782 (c->data.map->dst->da->type != PW_TYPE_STRING) &&
783 (c->data.map->dst->da->type != PW_TYPE_OCTETS) &&
784 (c->data.map->dst->da->type != PW_TYPE_DATE) &&
785 (rhs_type == T_SINGLE_QUOTED_STRING)) {
786 *error = "Value must be an unquoted string";
788 if (lhs) talloc_free(lhs);
789 if (rhs) talloc_free(rhs);
791 return -(rhs_p - start);
795 * The LHS has been cast to a data type, and the RHS is a
796 * literal. Cast the RHS to the type of the cast.
798 if (c->cast && (c->data.map->src->type == VPT_TYPE_LITERAL) &&
799 !cast_vpt(c->data.map->src, c->cast)) {
800 return_rhs("Failed to parse field");
804 * The LHS is an attribute, and the RHS is a literal. Cast the
805 * RHS to the data type of the LHS.
807 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
808 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
809 !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
810 DICT_ATTR const *da = c->data.map->dst->da;
812 if ((da->vendor == 0) &&
813 ((da->attr == PW_AUTH_TYPE) ||
814 (da->attr == PW_AUTZ_TYPE) ||
815 (da->attr == PW_ACCT_TYPE) ||
816 (da->attr == PW_SESSION_TYPE) ||
817 (da->attr == PW_POST_AUTH_TYPE) ||
818 (da->attr == PW_PRE_PROXY_TYPE) ||
819 (da->attr == PW_POST_PROXY_TYPE) ||
820 (da->attr == PW_PRE_ACCT_TYPE) ||
821 (da->attr == PW_RECV_COA_TYPE) ||
822 (da->attr == PW_SEND_COA_TYPE))) {
824 * The types for these attributes are dynamically allocated
825 * by modules.c, so we can't enforce strictness here.
827 c->pass2_fixup = PASS2_FIXUP_TYPE;
830 return_rhs("Failed to parse value for attribute");
838 while (isspace((int) *p)) p++; /* skip spaces after RHS */
840 } /* parse a condition (COND) or FOO OP BAR*/
847 return_P("Unexpected closing brace");
851 while (isspace((int) *p)) p++; /* skip spaces after closing brace */
856 * End of string is now allowed.
860 return_P("No closing brace at end of string");
866 if (!(((p[0] == '&') && (p[1] == '&')) ||
867 ((p[0] == '|') && (p[1] == '|')))) {
868 *error = "Unexpected text after condition";
870 if (lhs) talloc_free(lhs);
871 if (rhs) talloc_free(rhs);
877 * Recurse to parse the next condition.
883 * May still be looking for a closing brace.
885 slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
888 if (lhs) talloc_free(lhs);
889 if (rhs) talloc_free(rhs);
891 return slen - (p - start);
897 * Normalize it before returning it.
902 * (FOO) ... --> FOO ...
904 if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
907 child = talloc_steal(ctx, c->data.child);
908 c->data.child = NULL;
910 child->next = talloc_steal(child, c->next);
913 child->next_op = c->next_op;
916 * Set the negation properly
918 if ((c->negate && !child->negate) ||
919 (!c->negate && child->negate)) {
920 child->negate = true;
922 child->negate = false;
931 * (FOO ...) --> FOO ...
933 * But don't do !(FOO || BAR) --> !FOO || BAR
934 * Because that's different.
936 if ((c->type == COND_TYPE_CHILD) &&
937 !c->next && !c->negate) {
940 child = talloc_steal(ctx, c->data.child);
941 c->data.child = NULL;
949 * Normalize negation. This doesn't really make any
950 * difference, but it simplifies the run-time code in
953 if (c->type == COND_TYPE_MAP) do {
955 * !FOO !~ BAR --> FOO =~ BAR
957 if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
959 c->data.map->op = T_OP_REG_EQ;
963 * FOO !~ BAR --> !FOO =~ BAR
965 if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
967 c->data.map->op = T_OP_REG_EQ;
971 * !FOO != BAR --> FOO == BAR
973 if (c->negate && (c->data.map->op == T_OP_NE)) {
975 c->data.map->op = T_OP_CMP_EQ;
979 * This next one catches "LDAP-Group != foo",
980 * which doesn't really work, but this hack fixes it.
982 * FOO != BAR --> !FOO == BAR
984 if (!c->negate && (c->data.map->op == T_OP_NE)) {
986 c->data.map->op = T_OP_CMP_EQ;
990 * Is a data type. e.g. IP address, integer,
993 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
994 (c->data.map->src->type == VPT_TYPE_DATA)) {
997 rad_assert(c->cast != NULL);
999 rcode = radius_evaluate_map(NULL, 0, 0, c);
1000 TALLOC_FREE(c->data.map);
1004 c->type = COND_TYPE_TRUE;
1006 c->type = COND_TYPE_FALSE;
1009 break; /* don't do the next check */
1013 * Two literal strings. They're not parsed as
1014 * VPT_TYPE_DATA because there's no cast to an
1017 if ((c->data.map->src->type == VPT_TYPE_LITERAL) &&
1018 (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
1021 rad_assert(c->cast == NULL);
1022 rad_assert(c->regex_i == false);
1024 rcode = radius_evaluate_map(NULL, 0, 0, c);
1026 c->type = COND_TYPE_TRUE;
1028 c->type = COND_TYPE_FALSE;
1032 * Free map after using it above.
1034 TALLOC_FREE(c->data.map);
1042 if (c->type == COND_TYPE_TRUE) {
1045 c->type = COND_TYPE_FALSE;
1052 if (c->type == COND_TYPE_FALSE) {
1055 c->type = COND_TYPE_TRUE;
1060 * true && FOO --> FOO
1062 if ((c->type == COND_TYPE_TRUE) &&
1063 (c->next_op == COND_AND)) {
1066 next = talloc_steal(ctx, c->next);
1075 * false && FOO --> false
1077 if ((c->type == COND_TYPE_FALSE) &&
1078 (c->next_op == COND_AND)) {
1079 talloc_free(c->next);
1081 c->next_op = COND_NONE;
1085 * false || FOO --> FOO
1087 if ((c->type == COND_TYPE_FALSE) &&
1088 (c->next_op == COND_OR)) {
1091 next = talloc_steal(ctx, c->next);
1100 * true || FOO --> true
1102 if ((c->type == COND_TYPE_TRUE) &&
1103 (c->next_op == COND_OR)) {
1104 talloc_free(c->next);
1106 c->next_op = COND_NONE;
1109 if (lhs) talloc_free(lhs);
1110 if (rhs) talloc_free(rhs);
1116 /** Tokenize a conditional check
1118 * @param[in] ctx for talloc
1119 * @param[in] ci for CONF_ITEM
1120 * @param[in] start the start of the string to process. Should be "(..."
1121 * @param[out] head the parsed condition structure
1122 * @param[out] error the parse error (if any)
1123 * @param[in] flags do one/two pass
1124 * @return length of the string skipped, or when negative, the offset to the offending error
1126 ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
1128 return condition_tokenize(ctx, ci, start, false, head, error, flags);
1134 bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
1138 * Process this one, exit on error.
1140 if (!callback(ctx, c)) return false;
1143 case COND_TYPE_INVALID:
1146 case COND_TYPE_EXISTS:
1148 case COND_TYPE_TRUE:
1149 case COND_TYPE_FALSE:
1152 case COND_TYPE_CHILD:
1154 * Walk over the child.
1156 if (!fr_condition_walk(c->data.child, callback, ctx)) {
1164 if (c->next_op == COND_NONE) break;
1167 * process the next sibling