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 #define PASS2_FIXUP_NONE (0)
34 #define PASS2_FIXUP_ATTR (1)
35 #define PASS2_FIXUP_TYPE (2)
38 * This file shouldn't use any functions from the server core.
41 size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c)
45 char *end = buffer + bufsize - 1;
49 *(p++) = '!'; /* FIXME: only allow for child? */
53 case COND_TYPE_EXISTS:
54 rad_assert(c->data.vpt != NULL);
56 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
57 c->cast->type, "??"));
61 len = radius_tmpl2str(p, end - p, c->data.vpt);
66 rad_assert(c->data.map != NULL);
68 *(p++) = '['; /* for extra-clear debugging */
71 len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
72 c->cast->type, "??"));
76 len = radius_map2str(p, end - p, c->data.map);
84 rad_assert(c->data.child != NULL);
86 len = fr_cond_sprint(p, end - p, c->data.child);
92 strlcpy(buffer, "true", bufsize);
93 return strlen(buffer);
96 strlcpy(buffer, "false", bufsize);
97 return strlen(buffer);
104 if (c->next_op == COND_NONE) {
105 rad_assert(c->next == NULL);
110 if (c->next_op == COND_AND) {
111 strlcpy(p, " && ", end - p);
114 } else if (c->next_op == COND_OR) {
115 strlcpy(p, " || ", end - p);
128 * Cast a literal vpt to a value_data_t
130 static int cast_vpt(value_pair_tmpl_t *vpt, DICT_ATTR const *da)
135 rad_assert(vpt->type == VPT_TYPE_LITERAL);
137 vp = pairalloc(vpt, da);
138 if (!vp) return false;
140 if (!pairparsevalue(vp, vpt->name)) {
145 vpt->length = vp->length;
146 vpt->vpd = data = talloc(vpt, value_data_t);
147 if (!vpt->vpd) return false;
149 vpt->type = VPT_TYPE_DATA;
152 if (vp->da->flags.is_pointer) {
153 data->ptr = talloc_steal(vpt, vp->data.ptr);
156 memcpy(data, &vp->data, sizeof(*data));
164 static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char const *start, char **out,
165 FR_TOKEN *op, char const **error)
167 char const *p = start;
175 *op = T_DOUBLE_QUOTED_STRING;
179 *op = T_SINGLE_QUOTED_STRING;
183 *op = T_BACK_QUOTED_STRING;
187 *op = T_OP_REG_EQ; /* a bit of a hack. */
192 *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
193 if (!*out) return -1;
207 *error = "End of string after escape";
232 *error = "Unterminated string";
236 static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
237 FR_TOKEN *op, char const **error)
240 char const *p = start;
242 if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
243 return condition_tokenize_string(ctx, start, out, op, error);
247 if (*p == '&') p++; /* special-case &User-Name */
251 * The LHS should really be limited to only a few
252 * things. For now, we allow pretty much anything.
255 *error = "Unexpected escape";
267 * Spaces or special characters delineate the word
269 if (isspace((int) *p) || (*p == '&') || (*p == '|') ||
270 (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
274 if ((*p == '"') || (*p == '\'') || (*p == '`')) {
275 *error = "Unexpected start of string";
284 *error = "Empty string is invalid";
288 *out = talloc_array(ctx, char, len + 1);
289 memcpy(*out, start, len);
295 static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda, char const **error)
297 char const *p = start;
301 while (isspace((int) *p)) p++; /* skip spaces before condition */
303 if (*p != '<') return 0;
307 while (*q && *q != '>') q++;
309 cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
310 if (cast == PW_TYPE_INVALID) {
311 *error = "Invalid data type in cast";
315 *pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
317 *error = "Cannot cast to this data type";
323 while (isspace((int) *q)) q++; /* skip spaces after cast */
329 * Less code means less bugs
331 #define return_P(_x) *error = _x;goto return_p
332 #define return_0(_x) *error = _x;goto return_0
333 #define return_lhs(_x) *error = _x;goto return_lhs
334 #define return_rhs(_x) *error = _x;goto return_rhs
335 #define return_SLEN goto return_slen
338 /** Tokenize a conditional check
340 * @param[in] ctx for talloc
341 * @param[in] ci for CONF_ITEM
342 * @param[in] start the start of the string to process. Should be "(..."
343 * @param[in] brace look for a closing brace
344 * @param[in] flags do one/two pass
345 * @param[out] pcond pointer to the returned condition structure
346 * @param[out] error the parse error (if any)
347 * @return length of the string skipped, or when negative, the offset to the offending error
349 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)
352 char const *p = start;
353 char const *lhs_p, *rhs_p;
356 FR_TOKEN op, lhs_type, rhs_type;
358 c = talloc_zero(ctx, fr_cond_t);
360 rad_assert(c != NULL);
363 while (isspace((int) *p)) p++; /* skip spaces before condition */
366 return_P("Empty condition is invalid");
375 while (isspace((int) *p)) p++; /* skip spaces after negation */
381 return_P("Double negation is invalid");
392 * We've already eaten one layer of
393 * brackets. Go recurse to get more.
395 c->type = COND_TYPE_CHILD;
396 slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
401 if (!c->data.child) {
402 return_P("Empty condition is invalid");
406 while (isspace((int) *p)) p++; /* skip spaces after (COND)*/
408 } else { /* it's a bare FOO==BAR */
410 * We didn't see anything special. The condition must be one of
420 return_P("Conditional check cannot begin with a regular expression");
423 slen = condition_tokenize_cast(p, &c->cast, error);
430 slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
436 while (isspace((int)*p)) p++; /* skip spaces after LHS */
439 * We may (or not) have an operator
448 * don't skip the brace. We'll look for it later.
457 return_P("No closing brace at end of string");
465 } else if (((p[0] == '&') && (p[1] == '&')) ||
466 ((p[0] == '|') && (p[1] == '|'))) {
470 return_0("Cannot do cast for existence check");
473 if (lhs_type == T_BARE_WORD) {
474 if ((strcmp(lhs, "true") == 0) ||
475 ((lhs[0] == '1') && !lhs[1])) {
476 c->type = COND_TYPE_TRUE;
478 } else if ((strcmp(lhs, "false") == 0) ||
479 ((lhs[0] == '0') && !lhs[1])) {
480 c->type = COND_TYPE_FALSE;
488 c->type = COND_TYPE_EXISTS;
489 c->data.vpt = radius_str2tmpl(c, lhs, lhs_type);
491 return_P("Failed creating exists");
495 } else { /* it's an operator */
499 * The next thing should now be a comparison operator.
502 c->type = COND_TYPE_MAP;
505 return_P("Invalid text. Expected comparison operator");
512 } else if (p[1] == '~') {
518 } else if (p[1] == '*') {
519 if (lhs_type != T_BARE_WORD) {
520 return_P("Cannot use !* on a string");
527 goto invalid_operator;
536 } else if (p[1] == '~') {
542 } else if (p[1] == '*') {
543 if (lhs_type != T_BARE_WORD) {
544 return_P("Cannot use =* on a string");
552 return_P("Invalid operator");
580 while (isspace((int) *p)) p++; /* skip spaces after operator */
583 return_P("Expected text after operator");
587 * Cannot have a cast on the RHS
590 return_P("Unexpected cast");
597 slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
603 * Sanity checks for regexes.
607 return_P("Expected regular expression");
613 if (p[slen] == 'i') {
618 } else if (!regex && (*p == '/')) {
619 return_P("Unexpected regular expression");
622 c->data.map = radius_str2map(c, lhs, lhs_type, op, rhs, rhs_type,
623 REQUEST_CURRENT, PAIR_LIST_REQUEST,
624 REQUEST_CURRENT, PAIR_LIST_REQUEST);
627 * Could have been a reference to an attribute which is registered later.
628 * Mark it as being checked in pass2.
630 if (c->data.map && (lhs_type == T_BARE_WORD) &&
631 (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
632 c->pass2_fixup = PASS2_FIXUP_ATTR;
636 * Save the CONF_ITEM for later.
638 c->data.map->ci = ci;
641 * foo =* bar is just (foo)
642 * foo !* bar is just (!foo)
644 if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
645 value_pair_tmpl_t *vpt;
647 vpt = talloc_steal(c, c->data.map->dst);
648 c->data.map->dst = NULL;
650 talloc_free(c->data.map);
651 c->type = COND_TYPE_EXISTS;
655 * Invert the negation bit.
657 if (op == T_OP_CMP_FALSE) {
658 c->negate = !c->negate;
665 * @todo: check LHS and RHS separately, to
668 if ((c->data.map->src->type == VPT_TYPE_LIST) ||
669 (c->data.map->dst->type == VPT_TYPE_LIST)) {
670 return_0("Cannot use list references in condition");
674 * Check cast type. We can have the RHS
675 * a string if the LHS has a cast. But
676 * if the RHS is an attr, it MUST be the
677 * same type as the LHS.
680 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
681 (c->cast->type != c->data.map->src->da->type)) {
685 if (c->data.map->src->type == VPT_TYPE_REGEX) {
686 return_0("Cannot use cast with regex comparison");
690 * The LHS is a literal which has been cast to a data type.
691 * Cast it to the appropriate data type.
693 if ((c->data.map->dst->type == VPT_TYPE_LITERAL) &&
694 !cast_vpt(c->data.map->dst, c->cast)) {
695 *error = "Failed to parse field";
696 if (lhs) talloc_free(lhs);
697 if (rhs) talloc_free(rhs);
699 return -(lhs_p - start);
703 * The RHS is a literal, and the LHS has been cast to a data
706 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
707 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
708 !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
709 return_rhs("Failed to parse field");
713 * Casting to a redundant type means we don't need the cast.
715 * Do this LAST, as the rest of the code above assumes c->cast
718 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
719 (c->cast->type == c->data.map->dst->da->type)) {
725 * Two attributes? They must be of the same type
727 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
728 (c->data.map->dst->type == VPT_TYPE_ATTR) &&
729 (c->data.map->dst->da->type != c->data.map->src->da->type)) {
731 return_0("Attribute comparisons must be of the same attribute type");
735 * Without a cast, we can't compare "foo" to User-Name,
736 * it has to be done the other way around.
738 if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
739 (c->data.map->dst->type != VPT_TYPE_ATTR)) {
740 *error = "Cannot use attribute reference on right side of condition";
742 if (lhs) talloc_free(lhs);
743 if (rhs) talloc_free(rhs);
749 * Invalid: User-Name == bob
750 * Valid: User-Name == "bob"
752 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
753 (c->data.map->src->type != VPT_TYPE_ATTR) &&
754 (c->data.map->dst->da->type == PW_TYPE_STRING) &&
755 (rhs_type == T_BARE_WORD)) {
756 return_rhs("Must have string as value for attribute");
760 * Quotes around non-string
761 * attributes mean that it's
762 * either xlat, or an exec.
764 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
765 (c->data.map->src->type != VPT_TYPE_ATTR) &&
766 (c->data.map->dst->da->type != PW_TYPE_STRING) &&
767 (c->data.map->dst->da->type != PW_TYPE_OCTETS) &&
768 (c->data.map->dst->da->type != PW_TYPE_DATE) &&
769 (rhs_type == T_SINGLE_QUOTED_STRING)) {
770 *error = "Value must be an unquoted string";
772 if (lhs) talloc_free(lhs);
773 if (rhs) talloc_free(rhs);
775 return -(rhs_p - start);
779 * The LHS has been cast to a data type, and the RHS is a
780 * literal. Cast the RHS to the type of the cast.
782 if (c->cast && (c->data.map->src->type == VPT_TYPE_LITERAL) &&
783 !cast_vpt(c->data.map->src, c->cast)) {
784 return_rhs("Failed to parse field");
788 * The LHS is an attribute, and the RHS is a literal. Cast the
789 * RHS to the data type of the LHS.
791 if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
792 (c->data.map->src->type == VPT_TYPE_LITERAL) &&
793 !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
794 DICT_ATTR const *da = c->data.map->dst->da;
796 if ((da->vendor == 0) &&
797 ((da->attr == PW_AUTH_TYPE) ||
798 (da->attr == PW_AUTZ_TYPE) ||
799 (da->attr == PW_ACCT_TYPE) ||
800 (da->attr == PW_SESSION_TYPE) ||
801 (da->attr == PW_POST_AUTH_TYPE) ||
802 (da->attr == PW_PRE_PROXY_TYPE) ||
803 (da->attr == PW_POST_PROXY_TYPE) ||
804 (da->attr == PW_PRE_ACCT_TYPE) ||
805 (da->attr == PW_RECV_COA_TYPE) ||
806 (da->attr == PW_SEND_COA_TYPE))) {
808 * The types for these attributes are dynamically allocated
809 * by modules.c, so we can't enforce strictness here.
811 c->pass2_fixup = PASS2_FIXUP_TYPE;
814 return_rhs("Failed to parse value for attribute");
822 while (isspace((int) *p)) p++; /* skip spaces after RHS */
824 } /* parse a condition (COND) or FOO OP BAR*/
831 return_P("Unexpected closing brace");
835 while (isspace((int) *p)) p++; /* skip spaces after closing brace */
841 * End of string is now allowed.
845 return_P("No closing brace at end of string");
851 if (!(((p[0] == '&') && (p[1] == '&')) ||
852 ((p[0] == '|') && (p[1] == '|')))) {
853 *error = "Unexpected text after condition";
855 if (lhs) talloc_free(lhs);
856 if (rhs) talloc_free(rhs);
862 * Recurse to parse the next condition.
868 * May still be looking for a closing brace.
870 slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
873 if (lhs) talloc_free(lhs);
874 if (rhs) talloc_free(rhs);
876 return slen - (p - start);
882 * Normalize it before returning it.
887 * (FOO) ... --> FOO ...
889 if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
892 child = talloc_steal(ctx, c->data.child);
893 c->data.child = NULL;
895 child->next = talloc_steal(child, c->next);
898 child->next_op = c->next_op;
901 * Set the negation properly
903 if ((c->negate && !child->negate) ||
904 (!c->negate && child->negate)) {
905 child->negate = true;
907 child->negate = false;
916 * (FOO ...) --> FOO ...
918 * But don't do !(FOO || BAR) --> !FOO || BAR
919 * Because that's different.
921 if ((c->type == COND_TYPE_CHILD) &&
922 !c->next && !c->negate) {
925 child = talloc_steal(ctx, c->data.child);
926 c->data.child = NULL;
934 * Normalize negation. This doesn't really make any
935 * difference, but it simplifies the run-time code in
938 if (c->type == COND_TYPE_MAP) {
940 * !FOO !~ BAR --> FOO =~ BAR
942 if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
944 c->data.map->op = T_OP_REG_EQ;
948 * FOO !~ BAR --> !FOO =~ BAR
950 if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
952 c->data.map->op = T_OP_REG_EQ;
956 * !FOO != BAR --> FOO == BAR
958 if (c->negate && (c->data.map->op == T_OP_NE)) {
960 c->data.map->op = T_OP_CMP_EQ;
964 * This next one catches "LDAP-Group != foo",
965 * which doesn't really work, but this hack fixes it.
967 * FOO != BAR --> !FOO == BAR
969 if (!c->negate && (c->data.map->op == T_OP_NE)) {
971 c->data.map->op = T_OP_CMP_EQ;
974 if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
975 (c->data.map->src->type == VPT_TYPE_DATA)) {
978 rad_assert(c->cast != NULL);
980 rcode = radius_evaluate_map(NULL, 0, 0, c->data.map,
983 talloc_free(c->data.map);
988 c->type = COND_TYPE_TRUE;
990 c->type = COND_TYPE_FALSE;
995 if (c->type == COND_TYPE_TRUE) {
998 c->type = COND_TYPE_FALSE;
1002 if (c->type == COND_TYPE_FALSE) {
1005 c->type = COND_TYPE_TRUE;
1010 * true && FOO --> FOO
1012 if ((c->type == COND_TYPE_TRUE) &&
1013 (c->next_op == COND_AND)) {
1016 next = talloc_steal(ctx, c->next);
1025 * false && FOO --> false
1027 if ((c->type == COND_TYPE_FALSE) &&
1028 (c->next_op == COND_AND)) {
1029 talloc_free(c->next);
1031 c->next_op = COND_NONE;
1035 * false || FOO --> FOO
1037 if ((c->type == COND_TYPE_FALSE) &&
1038 (c->next_op == COND_OR)) {
1041 next = talloc_steal(ctx, c->next);
1050 * true || FOO --> true
1052 if ((c->type == COND_TYPE_TRUE) &&
1053 (c->next_op == COND_OR)) {
1054 talloc_free(c->next);
1056 c->next_op = COND_NONE;
1059 if (lhs) talloc_free(lhs);
1060 if (rhs) talloc_free(rhs);
1066 /** Tokenize a conditional check
1068 * @param[in] ctx for talloc
1069 * @param[in] ci for CONF_ITEM
1070 * @param[in] start the start of the string to process. Should be "(..."
1071 * @param[out] head the parsed condition structure
1072 * @param[out] error the parse error (if any)
1073 * @param[in] flags do one/two pass
1074 * @return length of the string skipped, or when negative, the offset to the offending error
1076 ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
1078 return condition_tokenize(ctx, ci, start, false, head, error, flags);
1084 bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
1088 * Process this one, exit on error.
1090 if (!callback(ctx, c)) return false;
1093 case COND_TYPE_INVALID:
1096 case COND_TYPE_EXISTS:
1098 case COND_TYPE_TRUE:
1099 case COND_TYPE_FALSE:
1102 case COND_TYPE_CHILD:
1104 * Walk over the child.
1106 if (!fr_condition_walk(c->data.child, callback, ctx)) {
1114 if (c->next_op == COND_NONE) break;
1117 * process the next sibling