All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
parser.c
Go to the documentation of this file.
1 /*
2  * parser.c Parse various things
3  *
4  * Version: $Id: b0226b3e92eb81f737213b5d625de53596a52028 $
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2013 Alan DeKok <aland@freeradius.org>
21  */
22 
23 RCSID("$Id: b0226b3e92eb81f737213b5d625de53596a52028 $")
24 
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/parser.h>
27 #include <freeradius-devel/rad_assert.h>
28 
29 #include <ctype.h>
30 
31 #define PW_CAST_BASE (1850)
32 
34  { "reject", 1 },
35  { "fail", 1 },
36  { "ok", 1 },
37  { "handled", 1 },
38  { "invalid", 1 },
39  { "userlock", 1 },
40  { "notfound", 1 },
41  { "noop", 1 },
42  { "updated", 1 },
43  { NULL, 0 }
44 };
45 
46 /*
47  * This file shouldn't use any functions from the server core.
48  */
49 
50 size_t fr_cond_snprint(char *out, size_t outlen, fr_cond_t const *in)
51 {
52  size_t len;
53  char *p = out;
54  char *end = out + outlen - 1;
55  fr_cond_t const *c = in;
56 
57  rad_assert(outlen > 0);
58 
59 next:
60  if (!c) {
61  p[0] = '\0';
62  return 0;
63  }
64 
65  if (c->negate) {
66  *(p++) = '!'; /* FIXME: only allow for child? */
67  }
68 
69  switch (c->type) {
70  case COND_TYPE_EXISTS:
71  rad_assert(c->data.vpt != NULL);
72  if (c->cast) {
73  len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
74  c->cast->type, "??"));
75  p += len;
76  }
77 
78  len = tmpl_snprint(p, end - p, c->data.vpt, NULL);
79  RETURN_IF_TRUNCATED(p, len, end - p);
80  break;
81 
82  case COND_TYPE_MAP:
83  rad_assert(c->data.map != NULL);
84 #if 0
85  *(p++) = '['; /* for extra-clear debugging */
86 #endif
87  if (c->cast) {
88  len = snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types, c->cast->type, "??"));
89  RETURN_IF_TRUNCATED(p, len, end - p);
90  }
91 
92  len = map_snprint(p, end - p, c->data.map);
93  RETURN_IF_TRUNCATED(p, len, end - p);
94 #if 0
95  *(p++) = ']';
96 #endif
97  break;
98 
99  case COND_TYPE_CHILD:
100  rad_assert(c->data.child != NULL);
101  *(p++) = '(';
102  len = fr_cond_snprint(p, (end - p) - 1, c->data.child); /* -1 for proceeding ')' */
103  RETURN_IF_TRUNCATED(p, len, end - p);
104  *(p++) = ')';
105  break;
106 
107  case COND_TYPE_TRUE:
108  len = strlcpy(out, "true", outlen);
109  RETURN_IF_TRUNCATED(p, len, end - p);
110  return p - out;
111 
112  case COND_TYPE_FALSE:
113  len = strlcpy(out, "false", outlen);
114  RETURN_IF_TRUNCATED(p, len, end - p);
115  return p - out;
116 
117  default:
118  *out = '\0';
119  return 0;
120  }
121 
122  if (c->next_op == COND_NONE) {
123  rad_assert(c->next == NULL);
124  *p = '\0';
125  return p - out;
126  }
127 
128  if (c->next_op == COND_AND) {
129  len = strlcpy(p, " && ", end - p);
130  RETURN_IF_TRUNCATED(p, len, end - p);
131 
132  } else if (c->next_op == COND_OR) {
133  len = strlcpy(p, " || ", end - p);
134  RETURN_IF_TRUNCATED(p, len, end - p);
135 
136  } else {
137  rad_assert(0 == 1);
138  }
139 
140  c = c->next;
141  goto next;
142 }
143 
144 
145 static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start,
146  FR_TOKEN *op)
147 {
148  char const *p = start;
149  char *q;
150 
151  switch (*p++) {
152  default:
153  return -1;
154 
155  case '"':
157  break;
158 
159  case '\'':
161  break;
162 
163  case '`':
164  *op = T_BACK_QUOTED_STRING;
165  break;
166 
167  case '/':
168  *op = T_OP_REG_EQ; /* a bit of a hack. */
169  break;
170 
171  }
172 
173  *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
174  if (!*out) return -1;
175 
176  q = *out;
177 
178  while (*p) {
179  if (*p == *start) {
180  /*
181  * Call the STANDARD parse function to figure out what the string is.
182  */
184  char quote = *start;
185  PW_TYPE src_type = PW_TYPE_STRING;
186 
187  /*
188  * Regex compilers can handle escapes. So we don't do it.
189  */
190  if (quote == '/') quote = '\0';
191 
192  if (value_data_from_str(ctx, &data, &src_type, NULL, start + 1, p - (start + 1), quote) < 0) {
193  *error = "error parsing string";
194  return -1;
195  }
196 
197  talloc_free(*out);
198  *out = talloc_steal(ctx, data.ptr);
199  data.strvalue = NULL;
200 
201  p++;
202  return (p - start);
203  }
204 
205  if (*p == '\\') {
206  if (!p[1]) {
207  p++;
208  *error = "End of string after escape";
209  return -(p - start);
210  }
211 
212  if (p[1] == start[0]) { /* Convert '\'' --> ' */
213  p++;
214  } else {
215  *(q++) = *(p++);
216  }
217  }
218  *(q++) = *(p++);
219  }
220 
221  *error = "Unterminated string";
222  return -1;
223 }
224 
225 static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
226  FR_TOKEN *op, char const **error)
227 {
228  size_t len;
229  char const *p = start;
230 
231  if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
232  return condition_tokenize_string(ctx, out, error, start, op);
233  }
234 
235  *op = T_BARE_WORD;
236  if (*p == '&') p++; /* special-case &User-Name */
237 
238  while (*p) {
239  /*
240  * The LHS should really be limited to only a few
241  * things. For now, we allow pretty much anything.
242  */
243  if (*p == '\\') {
244  *error = "Unexpected escape";
245  return -(p - start);
246  }
247 
248  /*
249  * ("foo") is valid.
250  */
251  if (*p == ')') {
252  break;
253  }
254 
255  /*
256  * Spaces or special characters delineate the word
257  */
258  if (isspace((int) *p) || (*p == '&') || (*p == '|') ||
259  (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
260  break;
261  }
262 
263  if ((*p == '"') || (*p == '\'') || (*p == '`')) {
264  *error = "Unexpected start of string";
265  return -(p - start);
266  }
267 
268  p++;
269  }
270 
271  len = p - start;
272  if (!len) {
273  *error = "Empty string is invalid";
274  return 0;
275  }
276 
277  *out = talloc_array(ctx, char, len + 1);
278  memcpy(*out, start, len);
279  (*out)[len] = '\0';
280  return len;
281 }
282 
283 
284 static ssize_t condition_tokenize_cast(char const *start, fr_dict_attr_t const **pda, char const **error)
285 {
286  char const *p = start;
287  char const *q;
288  PW_TYPE cast;
289 
290  while (isspace((int) *p)) p++; /* skip spaces before condition */
291 
292  if (*p != '<') return 0;
293  p++;
294 
295  q = p;
296  while (*q && *q != '>') q++;
297 
298  cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
299  if (cast == PW_TYPE_INVALID) {
300  *error = "Invalid data type in cast";
301  return -(p - start);
302  }
303 
304  /*
305  * We can only cast to basic data types. Complex ones
306  * are forbidden.
307  */
308  switch (cast) {
309 #ifdef WITH_ASCEND_BINARY
310  case PW_TYPE_ABINARY:
311 #endif
313  case PW_TYPE_TLV:
314  case PW_TYPE_EXTENDED:
316  case PW_TYPE_EVS:
317  case PW_TYPE_VSA:
318  *error = "Forbidden data type in cast";
319  return -(p - start);
320 
321  default:
322  break;
323  }
324 
325  *pda = fr_dict_attr_by_num(NULL, 0, PW_CAST_BASE + cast);
326  if (!*pda) {
327  *error = "Cannot cast to this data type";
328  return -(p - start);
329  }
330 
331  q++;
332 
333  while (isspace((int) *q)) q++; /* skip spaces after cast */
334 
335  return q - start;
336 }
337 
338 static bool condition_check_types(fr_cond_t *c, PW_TYPE lhs_type)
339 {
340  /*
341  * SOME integer mismatch is OK. If the LHS has a large type,
342  * and the RHS has a small type, it's OK.
343  *
344  * If the LHS has a small type, and the RHS has a large type,
345  * then add a cast to the LHS.
346  */
347  if (lhs_type == PW_TYPE_INTEGER64) {
348  if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
349  (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
350  (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
351  c->cast = NULL;
352  return true;
353  }
354  }
355 
356  if (lhs_type == PW_TYPE_INTEGER) {
357  if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
358  (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
359  c->cast = NULL;
360  return true;
361  }
362 
363  if (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) {
364  c->cast = c->data.map->rhs->tmpl_da;
365  return true;
366  }
367  }
368 
369  if (lhs_type == PW_TYPE_SHORT) {
370  if (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE) {
371  c->cast = NULL;
372  return true;
373  }
374 
375  if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
376  (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER)) {
377  c->cast = c->data.map->rhs->tmpl_da;
378  return true;
379  }
380  }
381 
382  if (lhs_type == PW_TYPE_BYTE) {
383  if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
384  (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
385  (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT)) {
386  c->cast = c->data.map->rhs->tmpl_da;
387  return true;
388  }
389  }
390 
391  if ((lhs_type == PW_TYPE_IPV4_PREFIX) &&
392  (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_ADDR)) {
393  return true;
394  }
395 
396  if ((lhs_type == PW_TYPE_IPV6_PREFIX) &&
397  (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_ADDR)) {
398  return true;
399  }
400 
401  /*
402  * Same checks as above, but with the types swapped, and
403  * with explicit cast for the interpretor.
404  */
405  if ((lhs_type == PW_TYPE_IPV4_ADDR) &&
406  (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_PREFIX)) {
407  c->cast = c->data.map->rhs->tmpl_da;
408  return true;
409  }
410 
411  if ((lhs_type == PW_TYPE_IPV6_ADDR) &&
412  (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_PREFIX)) {
413  c->cast = c->data.map->rhs->tmpl_da;
414  return true;
415  }
416 
417  return false;
418 }
419 
420 
421 /*
422  * Less code means less bugs
423  */
424 #define return_P(_x) *error = _x;goto return_p
425 #define return_0(_x) *error = _x;goto return_0
426 #define return_lhs(_x) *error = _x;goto return_lhs
427 #define return_rhs(_x) *error = _x;goto return_rhs
428 #define return_SLEN goto return_slen
429 
430 
431 /** Tokenize a conditional check
432  *
433  * @param[in] ctx for talloc
434  * @param[in] ci for CONF_ITEM
435  * @param[in] start the start of the string to process. Should be "(..."
436  * @param[in] brace look for a closing brace
437  * @param[out] pcond pointer to the returned condition structure
438  * @param[out] error the parse error (if any)
439  * @param[in] flags do one/two pass
440  * @return
441  * - Length of the string skipped.
442  * - < 0 (the offset to the offending error) on error.
443  */
444 static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, bool brace,
445  fr_cond_t **pcond, char const **error, int flags)
446 {
447  ssize_t slen, tlen;
448  char const *p = start;
449  char const *lhs_p, *rhs_p;
450  fr_cond_t *c;
451  char *lhs, *rhs;
452  FR_TOKEN op, lhs_type, rhs_type;
453 
454  c = talloc_zero(ctx, fr_cond_t);
455 
456  rad_assert(c != NULL);
457  lhs = rhs = NULL;
458  lhs_type = rhs_type = T_INVALID;
459 
460  while (isspace((int) *p)) p++; /* skip spaces before condition */
461 
462  if (!*p) {
463  return_P("Empty condition is invalid");
464  }
465 
466  /*
467  * !COND
468  */
469  if (*p == '!') {
470  p++;
471  c->negate = true;
472  while (isspace((int) *p)) p++; /* skip spaces after negation */
473 
474  /*
475  * Just for stupidity
476  */
477  if (*p == '!') {
478  return_P("Double negation is invalid");
479  }
480  }
481 
482  /*
483  * (COND)
484  */
485  if (*p == '(') {
486  p++;
487 
488  /*
489  * We've already eaten one layer of
490  * brackets. Go recurse to get more.
491  */
492  c->type = COND_TYPE_CHILD;
493  c->ci = ci;
494  slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
495  if (slen <= 0) return_SLEN;
496 
497  if (!c->data.child) {
498  return_P("Empty condition is invalid");
499  }
500 
501  p += slen;
502  while (isspace((int) *p)) p++; /* skip spaces after (COND)*/
503 
504  } else { /* it's a bare FOO==BAR */
505  /*
506  * We didn't see anything special. The condition must be one of
507  *
508  * FOO
509  * FOO OP BAR
510  */
511 
512  /*
513  * Grab the LHS
514  */
515  if (*p == '/') {
516  return_P("Conditional check cannot begin with a regular expression");
517  }
518 
519  slen = condition_tokenize_cast(p, &c->cast, error);
520  if (slen < 0) {
521  return_SLEN;
522  }
523  p += slen;
524 
525  lhs_p = p;
526  slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
527  if (slen <= 0) {
528  return_SLEN;
529  }
530  p += slen;
531 
532  /*
533  * If the LHS is 0xabcdef... automatically cast it to octets
534  */
535  if (!c->cast && (lhs_type == T_BARE_WORD) &&
536  (lhs[0] == '0') && (lhs[1] == 'x') &&
537  ((slen & 0x01) == 0)) {
538  if (slen == 2) {
539  return_P("Empty octet string is invalid");
540  }
541 
543  }
544 
545  while (isspace((int)*p)) p++; /* skip spaces after LHS */
546 
547  /*
548  * We may (or not) have an operator
549  */
550 
551 
552  /*
553  * (FOO)
554  */
555  if (*p == ')') {
556  /*
557  * don't skip the brace. We'll look for it later.
558  */
559  goto exists;
560 
561  /*
562  * FOO
563  */
564  } else if (!*p) {
565  if (brace) {
566  return_P("No closing brace at end of string");
567  }
568 
569  goto exists;
570 
571  /*
572  * FOO && ...
573  */
574  } else if (((p[0] == '&') && (p[1] == '&')) ||
575  ((p[0] == '|') && (p[1] == '|'))) {
576 
577  exists:
578  if (c->cast) {
579  return_0("Cannot do cast for existence check");
580  }
581 
582  c->type = COND_TYPE_EXISTS;
583  c->ci = ci;
584 
585  tlen = tmpl_afrom_str(c, &c->data.vpt, lhs, talloc_array_length(lhs) - 1,
586  lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
587  if (tlen < 0) {
588  p = lhs_p - tlen;
590  }
591 
592  rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
593 
594  if (c->data.vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
596  }
597 
598  } else { /* it's an operator */
599 #ifdef HAVE_REGEX
600  bool regex = false;
601  bool iflag = false;
602  bool mflag = false;
603 #endif
604  vp_map_t *map;
605 
606  /*
607  * The next thing should now be a comparison operator.
608  */
609  c->type = COND_TYPE_MAP;
610  c->ci = ci;
611 
612  switch (*p) {
613  default:
614  return_P("Invalid text. Expected comparison operator");
615 
616  case '!':
617  if (p[1] == '=') {
618  op = T_OP_NE;
619  p += 2;
620 
621 #ifdef HAVE_REGEX
622  } else if (p[1] == '~') {
623  regex = true;
624 
625  op = T_OP_REG_NE;
626  p += 2;
627 #endif
628 
629  } else if (p[1] == '*') {
630  if (lhs_type != T_BARE_WORD) {
631  return_P("Cannot use !* on a string");
632  }
633 
634  op = T_OP_CMP_FALSE;
635  p += 2;
636 
637  } else {
638  goto invalid_operator;
639  }
640  break;
641 
642  case '=':
643  if (p[1] == '=') {
644  op = T_OP_CMP_EQ;
645  p += 2;
646 
647 #ifdef HAVE_REGEX
648  } else if (p[1] == '~') {
649  regex = true;
650 
651  op = T_OP_REG_EQ;
652  p += 2;
653 #endif
654 
655  } else if (p[1] == '*') {
656  if (lhs_type != T_BARE_WORD) {
657  return_P("Cannot use =* on a string");
658  }
659 
660  op = T_OP_CMP_TRUE;
661  p += 2;
662 
663  } else {
664  invalid_operator:
665  return_P("Invalid operator");
666  }
667 
668  break;
669 
670  case '<':
671  if (p[1] == '=') {
672  op = T_OP_LE;
673  p += 2;
674 
675  } else {
676  op = T_OP_LT;
677  p++;
678  }
679  break;
680 
681  case '>':
682  if (p[1] == '=') {
683  op = T_OP_GE;
684  p += 2;
685 
686  } else {
687  op = T_OP_GT;
688  p++;
689  }
690  break;
691  }
692 
693  while (isspace((int) *p)) p++; /* skip spaces after operator */
694 
695  if (!*p) {
696  return_P("Expected text after operator");
697  }
698 
699  /*
700  * Cannot have a cast on the RHS.
701  * But produce good errors, too.
702  */
703  if (*p == '<') {
704  fr_dict_attr_t const *cast_da;
705 
706  slen = condition_tokenize_cast(p, &cast_da, error);
707  if (slen < 0) {
708  return_SLEN;
709  }
710 
711  if (!c->cast) {
712  return_P("Unexpected cast");
713  }
714 
715  if (c->cast != cast_da) {
716  return_P("Cannot cast to a different data type");
717  }
718 
719  return_P("Unnecessary cast");
720  }
721 
722  /*
723  * Grab the RHS
724  */
725  rhs_p = p;
726  slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
727  if (slen <= 0) {
728  return_SLEN;
729  }
730 
731 #ifdef HAVE_REGEX
732  /*
733  * Sanity checks for regexes.
734  */
735  if (regex) {
736  if (*p != '/') {
737  return_P("Expected regular expression");
738  }
739  for (;;) {
740  switch (p[slen]) {
741  /*
742  * /foo/i
743  */
744  case 'i':
745  iflag = true;
746  slen++;
747  continue;
748 
749  /*
750  * /foo/m
751  */
752  case 'm':
753  mflag = true;
754  slen++;
755  continue;
756 
757  default:
758  break;
759  }
760  break;
761  }
762  } else if (!regex && (*p == '/')) {
763  return_P("Unexpected regular expression");
764  }
765 
766 #endif
767  /*
768  * Duplicate map_from_fields here, as we
769  * want to separate parse errors in the
770  * LHS from ones in the RHS.
771  */
772  c->data.map = map = talloc_zero(c, vp_map_t);
773 
774  tlen = tmpl_afrom_str(map, &map->lhs, lhs, talloc_array_length(lhs) - 1,
775  lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
776  if (tlen < 0) {
777  p = lhs_p - tlen;
779  }
780 
781  if (tmpl_define_unknown_attr(map->lhs) < 0) {
782  return_lhs("Failed defining attribute");
783  return_lhs:
784  if (lhs) talloc_free(lhs);
785  if (rhs) talloc_free(rhs);
786  talloc_free(c);
787  return -(lhs_p - start);
788  }
789 
790  map->op = op;
791 
792  /*
793  * If the RHS is 0xabcdef... automatically cast it to octets
794  * unless the LHS is an attribute of type octets, or an
795  * integer type.
796  */
797  if (!c->cast && (rhs_type == T_BARE_WORD) &&
798  (rhs[0] == '0') && (rhs[1] == 'x') &&
799  ((slen & 0x01) == 0)) {
800  if (slen == 2) {
801  return_P("Empty octet string is invalid");
802  }
803 
804  if ((map->lhs->type != TMPL_TYPE_ATTR) ||
805  !((map->lhs->tmpl_da->type == PW_TYPE_OCTETS) ||
806  (map->lhs->tmpl_da->type == PW_TYPE_BYTE) ||
807  (map->lhs->tmpl_da->type == PW_TYPE_SHORT) ||
808  (map->lhs->tmpl_da->type == PW_TYPE_INTEGER) ||
809  (map->lhs->tmpl_da->type == PW_TYPE_INTEGER64))) {
811  }
812  }
813 
814  if ((map->lhs->type == TMPL_TYPE_ATTR) &&
815  map->lhs->tmpl_da->flags.is_unknown &&
816  map_cast_from_hex(map, rhs_type, rhs)) {
817  /* do nothing */
818 
819  } else {
820  tlen = tmpl_afrom_str(map, &map->rhs, rhs, talloc_array_length(rhs) - 1, rhs_type,
822  if (tlen < 0) {
823  p = rhs_p - tlen;
825  }
826 
827  if (tmpl_define_unknown_attr(map->rhs) < 0) {
828  return_rhs("Failed defining attribute");
829  }
830  }
831 
832  /*
833  * Unknown attributes get marked up for pass2.
834  */
835  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) ||
836  (c->data.map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED)) {
838  }
839 
840 #ifdef HAVE_REGEX
841  if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
842  c->data.map->rhs->tmpl_iflag = iflag;
843  c->data.map->rhs->tmpl_mflag = mflag;
844  }
845 #endif
846 
847  /*
848  * Save the CONF_ITEM for later.
849  */
850  c->data.map->ci = ci;
851 
852  /*
853  * @todo: check LHS and RHS separately, to
854  * get better errors
855  */
856  if ((c->data.map->rhs->type == TMPL_TYPE_LIST) ||
857  (c->data.map->lhs->type == TMPL_TYPE_LIST)) {
858  return_0("Cannot use list references in condition");
859  }
860 
861  /*
862  * Check cast type. We can have the RHS
863  * a string if the LHS has a cast. But
864  * if the RHS is an attr, it MUST be the
865  * same type as the LHS.
866  */
867  if (c->cast) {
868  if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
869  (c->cast->type != c->data.map->rhs->tmpl_da->type)) {
870  if (condition_check_types(c, c->cast->type)) {
871  goto keep_going;
872  }
873 
874  goto same_type;
875  }
876 
877 #ifdef HAVE_REGEX
878  if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
879  return_0("Cannot use cast with regex comparison");
880  }
881 #endif
882 
883  /*
884  * The LHS is a literal which has been cast to a data type.
885  * Cast it to the appropriate data type.
886  */
887  if ((c->data.map->lhs->type == TMPL_TYPE_UNPARSED) &&
888  (tmpl_cast_in_place(c->data.map->lhs, c->cast->type, c->cast) < 0)) {
889  *error = "Failed to parse field";
890  if (lhs) talloc_free(lhs);
891  if (rhs) talloc_free(rhs);
892  talloc_free(c);
893  return -(lhs_p - start);
894  }
895 
896  /*
897  * The RHS is a literal, and the LHS has been cast to a data
898  * type.
899  */
900  if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
901  (c->data.map->rhs->type == TMPL_TYPE_UNPARSED) &&
902  (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
903  return_rhs("Failed to parse field");
904  }
905 
906  /*
907  * We may be casting incompatible
908  * types. We check this based on
909  * their size.
910  */
911  if (c->data.map->lhs->type == TMPL_TYPE_ATTR) {
912  /*
913  * dst.min == src.min
914  * dst.max == src.max
915  */
916  if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) &&
917  (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
918  goto cast_ok;
919  }
920 
921  /*
922  * Run-time parsing of strings.
923  * Run-time copying of octets.
924  */
925  if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) ||
926  (c->data.map->lhs->tmpl_da->type == PW_TYPE_OCTETS)) {
927  goto cast_ok;
928  }
929 
930  /*
931  * ifid to integer64 is OK
932  */
933  if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IFID) &&
934  (c->cast->type == PW_TYPE_INTEGER64)) {
935  goto cast_ok;
936  }
937 
938  /*
939  * ipaddr to ipv4prefix is OK
940  */
941  if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) &&
942  (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
943  goto cast_ok;
944  }
945 
946  /*
947  * ipv6addr to ipv6prefix is OK
948  */
949  if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) &&
950  (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
951  goto cast_ok;
952  }
953 
954  /*
955  * integer64 to ethernet is OK.
956  */
957  if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_INTEGER64) &&
958  (c->cast->type == PW_TYPE_ETHERNET)) {
959  goto cast_ok;
960  }
961 
962  /*
963  * dst.max < src.min
964  * dst.min > src.max
965  */
966  if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) ||
967  (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
968  return_0("Cannot cast to attribute of incompatible size");
969  }
970  }
971 
972  cast_ok:
973  /*
974  * Casting to a redundant type means we don't need the cast.
975  *
976  * Do this LAST, as the rest of the code above assumes c->cast
977  * is not NULL.
978  */
979  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
980  (c->cast->type == c->data.map->lhs->tmpl_da->type)) {
981  c->cast = NULL;
982  }
983 
984  } else {
985  vp_tmpl_t *vpt;
986 
987  /*
988  * Two attributes? They must be of the same type
989  */
990  if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
991  (c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
992  (c->data.map->lhs->tmpl_da->type != c->data.map->rhs->tmpl_da->type)) {
993  if (condition_check_types(c, c->data.map->lhs->tmpl_da->type)) {
994  goto keep_going;
995  }
996 
997  same_type:
998  return_0("Attribute comparisons must be of the same data type");
999  }
1000 
1001  /*
1002  * Without a cast, we can't compare "foo" to User-Name,
1003  * it has to be done the other way around.
1004  */
1005  if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
1006  (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
1007  *error = "Cannot use attribute reference on right side of condition";
1008  return_0:
1009  if (lhs) talloc_free(lhs);
1010  if (rhs) talloc_free(rhs);
1011  talloc_free(c);
1012  return 0;
1013  }
1014 
1015  /*
1016  * Invalid: User-Name == bob
1017  * Valid: User-Name == "bob"
1018  *
1019  * There's no real reason for
1020  * this, other than consistency.
1021  */
1022  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1023  (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
1024  (c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1025  (c->data.map->op != T_OP_CMP_TRUE) &&
1026  (c->data.map->op != T_OP_CMP_FALSE) &&
1027  (rhs_type == T_BARE_WORD)) {
1028  return_rhs("Must have string as value for attribute");
1029  }
1030 
1031  /*
1032  * Quotes around non-string
1033  * attributes mean that it's
1034  * either xlat, or an exec.
1035  */
1036  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1037  (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
1038  (c->data.map->lhs->tmpl_da->type != PW_TYPE_STRING) &&
1039  (c->data.map->lhs->tmpl_da->type != PW_TYPE_OCTETS) &&
1040  (c->data.map->lhs->tmpl_da->type != PW_TYPE_DATE) &&
1041  (rhs_type == T_SINGLE_QUOTED_STRING)) {
1042  *error = "Value must be an unquoted string";
1043  return_rhs:
1044  if (lhs) talloc_free(lhs);
1045  if (rhs) talloc_free(rhs);
1046  talloc_free(c);
1047  return -(rhs_p - start);
1048  }
1049 
1050  /*
1051  * The LHS has been cast to a data type, and the RHS is a
1052  * literal. Cast the RHS to the type of the cast.
1053  */
1054  if (c->cast && (c->data.map->rhs->type == TMPL_TYPE_UNPARSED) &&
1055  (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
1056  return_rhs("Failed to parse field");
1057  }
1058 
1059  /*
1060  * The LHS is an attribute, and the RHS is a literal. Cast the
1061  * RHS to the data type of the LHS.
1062  *
1063  * Note: There's a hack in here to always parse RHS as the
1064  * equivalent prefix type if the LHS is an IP address.
1065  *
1066  * This allows Framed-IP-Address < 192.168.0.0./24
1067  */
1068  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1069  ((c->data.map->rhs->type == TMPL_TYPE_UNPARSED) ||
1070  (c->data.map->rhs->type == TMPL_TYPE_DATA))) {
1071  PW_TYPE type = c->data.map->lhs->tmpl_da->type;
1072 
1073  switch (c->data.map->lhs->tmpl_da->type) {
1074  case PW_TYPE_IPV4_ADDR:
1075  if (strchr(c->data.map->rhs->name, '/') != NULL) {
1076  type = PW_TYPE_IPV4_PREFIX;
1077  c->cast = fr_dict_attr_by_num(NULL, 0, PW_CAST_BASE + type);
1078  }
1079  break;
1080 
1081  case PW_TYPE_IPV6_ADDR:
1082  if (strchr(c->data.map->rhs->name, '/') != NULL) {
1083  type = PW_TYPE_IPV6_PREFIX;
1084  c->cast = fr_dict_attr_by_num(NULL, 0, PW_CAST_BASE + type);
1085  }
1086  break;
1087 
1088  default:
1089  break;
1090  }
1091 
1092  if (tmpl_cast_in_place(c->data.map->rhs, type, c->data.map->lhs->tmpl_da) < 0) {
1093  fr_dict_attr_t const *da = c->data.map->lhs->tmpl_da;
1094 
1095  if ((da->vendor == 0) &&
1096  ((da->attr == PW_AUTH_TYPE) ||
1097  (da->attr == PW_AUTZ_TYPE) ||
1098  (da->attr == PW_ACCT_TYPE) ||
1099  (da->attr == PW_SESSION_TYPE) ||
1100  (da->attr == PW_POST_AUTH_TYPE) ||
1101  (da->attr == PW_PRE_PROXY_TYPE) ||
1102  (da->attr == PW_POST_PROXY_TYPE) ||
1103  (da->attr == PW_PRE_ACCT_TYPE) ||
1104  (da->attr == PW_RECV_COA_TYPE) ||
1105  (da->attr == PW_SEND_COA_TYPE))) {
1106  /*
1107  * The types for these attributes are dynamically allocated
1108  * by modules.c, so we can't enforce strictness here.
1109  */
1111 
1112  } else {
1113  return_rhs("Failed to parse value for attribute");
1114  }
1115  }
1116 
1117  /*
1118  * Stupid WiMAX shit.
1119  * Cast the LHS to the
1120  * type of the RHS.
1121  */
1122  if (c->data.map->lhs->tmpl_da->type == PW_TYPE_COMBO_IP_ADDR) {
1123  fr_dict_attr_t const *da;
1124 
1125  da = fr_dict_attr_by_type(NULL, c->data.map->lhs->tmpl_da->vendor,
1126  c->data.map->lhs->tmpl_da->attr,
1127  c->data.map->rhs->tmpl_data_type);
1128  if (!da) {
1129  return_rhs("Cannot find type for attribute");
1130  }
1131  c->data.map->lhs->tmpl_da = da;
1132  }
1133  } /* attr to literal comparison */
1134 
1135  /*
1136  * The RHS will turn into... something. Allow for prefixes
1137  * there, too.
1138  */
1139  if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
1140  ((c->data.map->rhs->type == TMPL_TYPE_XLAT) ||
1141  (c->data.map->rhs->type == TMPL_TYPE_XLAT_STRUCT) ||
1142  (c->data.map->rhs->type == TMPL_TYPE_EXEC))) {
1143  if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) {
1144  c->cast = fr_dict_attr_by_num(NULL, 0,
1146  }
1147 
1148  if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) {
1149  c->cast = fr_dict_attr_by_num(NULL, 0,
1151  }
1152  }
1153 
1154  /*
1155  * If the LHS is a bare word, AND it looks like
1156  * an attribute, try to parse it as such.
1157  *
1158  * This allows LDAP-Group and SQL-Group to work.
1159  *
1160  * The real fix is to just read the config files,
1161  * and do no parsing until after all of the modules
1162  * are loaded. But that has issues, too.
1163  */
1164  if ((c->data.map->lhs->type == TMPL_TYPE_UNPARSED) &&
1165  (lhs_type == T_BARE_WORD) &&
1166  (c->data.map->rhs->type == TMPL_TYPE_UNPARSED)) {
1167  int hyphens = 0;
1168  bool may_be_attr = true;
1169  size_t i;
1170  ssize_t attr_slen;
1171 
1172  /*
1173  * Backwards compatibility: Allow Foo-Bar,
1174  * e.g. LDAP-Group and SQL-Group.
1175  */
1176  for (i = 0; i < c->data.map->lhs->len; i++) {
1177  if (!fr_dict_attr_allowed_chars[(unsigned char) c->data.map->lhs->name[i]]) {
1178  may_be_attr = false;
1179  break;
1180  }
1181 
1182  if (c->data.map->lhs->name[i] == '-') {
1183  hyphens++;
1184  if (hyphens > 1) {
1185  may_be_attr = false;
1186  break;
1187  }
1188  }
1189  }
1190 
1191  if (!hyphens || (hyphens > 3)) may_be_attr = false;
1192 
1193  if (may_be_attr) {
1194  attr_slen = tmpl_afrom_attr_str(c->data.map, &vpt, lhs,
1196  true, true);
1197  if ((attr_slen > 0) && (vpt->len == c->data.map->lhs->len)) {
1198  talloc_free(c->data.map->lhs);
1199  c->data.map->lhs = vpt;
1201  }
1202  }
1203  }
1204  } /* we didn't have a cast */
1205 
1206  keep_going:
1207  p += slen;
1208 
1209  while (isspace((int) *p)) p++; /* skip spaces after RHS */
1210  } /* parse OP RHS */
1211  } /* parse a condition (COND) or FOO OP BAR*/
1212 
1213  /*
1214  * ...COND)
1215  */
1216  if (*p == ')') {
1217  if (!brace) {
1218  return_P("Unexpected closing brace");
1219  }
1220 
1221  p++;
1222  while (isspace((int) *p)) p++; /* skip spaces after closing brace */
1223  goto done;
1224  }
1225 
1226  /*
1227  * End of string is now allowed.
1228  */
1229  if (!*p) {
1230  if (brace) {
1231  return_P("No closing brace at end of string");
1232  }
1233 
1234  goto done;
1235  }
1236 
1237  if (!(((p[0] == '&') && (p[1] == '&')) ||
1238  ((p[0] == '|') && (p[1] == '|')))) {
1239  *error = "Unexpected text after condition";
1240  return_p:
1241  if (lhs) talloc_free(lhs);
1242  if (rhs) talloc_free(rhs);
1243  talloc_free(c);
1244  return -(p - start);
1245  }
1246 
1247  /*
1248  * Recurse to parse the next condition.
1249  */
1250  c->next_op = p[0];
1251  p += 2;
1252 
1253  /*
1254  * May still be looking for a closing brace.
1255  */
1256  slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
1257  if (slen <= 0) {
1258  return_slen:
1259  if (lhs) talloc_free(lhs);
1260  if (rhs) talloc_free(rhs);
1261  talloc_free(c);
1262  return slen - (p - start);
1263  }
1264  p += slen;
1265 
1266 done:
1267  /*
1268  * Normalize the condition before returning.
1269  *
1270  * We collapse multiple levels of braces to one. Then
1271  * convert maps to literals. Then literals to true/false
1272  * statements. Then true/false ||/&& followed by other
1273  * conditions to just conditions.
1274  *
1275  * Order is important. The more complex cases are
1276  * converted to simpler ones, from the most complex cases
1277  * to the simplest ones.
1278  */
1279 
1280  /*
1281  * (FOO) --> FOO
1282  * (FOO) ... --> FOO ...
1283  */
1284  if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
1285  fr_cond_t *child;
1286 
1287  child = talloc_steal(ctx, c->data.child);
1288  c->data.child = NULL;
1289 
1290  child->next = talloc_steal(child, c->next);
1291  c->next = NULL;
1292 
1293  child->next_op = c->next_op;
1294 
1295  /*
1296  * Set the negation properly
1297  */
1298  if ((c->negate && !child->negate) ||
1299  (!c->negate && child->negate)) {
1300  child->negate = true;
1301  } else {
1302  child->negate = false;
1303  }
1304 
1305  lhs = rhs = NULL;
1306  talloc_free(c);
1307  c = child;
1308  }
1309 
1310  /*
1311  * (FOO ...) --> FOO ...
1312  *
1313  * But don't do !(FOO || BAR) --> !FOO || BAR
1314  * Because that's different.
1315  */
1316  if ((c->type == COND_TYPE_CHILD) &&
1317  !c->next && !c->negate) {
1318  fr_cond_t *child;
1319 
1320  child = talloc_steal(ctx, c->data.child);
1321  c->data.child = NULL;
1322 
1323  lhs = rhs = NULL;
1324  talloc_free(c);
1325  c = child;
1326  }
1327 
1328  /*
1329  * Convert maps to literals. Convert one form of map to
1330  * a standardized form. This doesn't make any
1331  * theoretical difference, but it does mean that the
1332  * run-time evaluation has fewer cases to check.
1333  */
1334  if (c->type == COND_TYPE_MAP) do {
1335  /*
1336  * !FOO !~ BAR --> FOO =~ BAR
1337  */
1338  if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
1339  c->negate = false;
1340  c->data.map->op = T_OP_REG_EQ;
1341  }
1342 
1343  /*
1344  * FOO !~ BAR --> !FOO =~ BAR
1345  */
1346  if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
1347  c->negate = true;
1348  c->data.map->op = T_OP_REG_EQ;
1349  }
1350 
1351  /*
1352  * !FOO != BAR --> FOO == BAR
1353  */
1354  if (c->negate && (c->data.map->op == T_OP_NE)) {
1355  c->negate = false;
1356  c->data.map->op = T_OP_CMP_EQ;
1357  }
1358 
1359  /*
1360  * This next one catches "LDAP-Group != foo",
1361  * which doesn't work as-is, but this hack fixes
1362  * it.
1363  *
1364  * FOO != BAR --> !FOO == BAR
1365  */
1366  if (!c->negate && (c->data.map->op == T_OP_NE)) {
1367  c->negate = true;
1368  c->data.map->op = T_OP_CMP_EQ;
1369  }
1370 
1371  /*
1372  * FOO =* BAR --> FOO
1373  * FOO !* BAR --> !FOO
1374  *
1375  * FOO may be a string, or a delayed attribute
1376  * reference.
1377  */
1378  if ((c->data.map->op == T_OP_CMP_TRUE) ||
1379  (c->data.map->op == T_OP_CMP_FALSE)) {
1380  vp_tmpl_t *vpt;
1381 
1382  vpt = talloc_steal(c, c->data.map->lhs);
1383  c->data.map->lhs = NULL;
1384 
1385  /*
1386  * Invert the negation bit.
1387  */
1388  if (c->data.map->op == T_OP_CMP_FALSE) {
1389  c->negate = !c->negate;
1390  }
1391 
1392  TALLOC_FREE(c->data.map);
1393 
1394  c->type = COND_TYPE_EXISTS;
1395  c->data.vpt = vpt;
1396  break; /* it's no longer a map */
1397  }
1398 
1399  /*
1400  * Both are data (IP address, integer, etc.)
1401  *
1402  * We can do the evaluation here, so that it
1403  * doesn't need to be done at run time
1404  */
1405  if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
1406  (c->data.map->rhs->type == TMPL_TYPE_DATA)) {
1407  int rcode;
1408 
1409  rad_assert(c->cast != NULL);
1410 
1411  rcode = radius_evaluate_map(NULL, 0, 0, c);
1412  TALLOC_FREE(c->data.map);
1413  c->cast = NULL;
1414  if (rcode) {
1415  c->type = COND_TYPE_TRUE;
1416  } else {
1417  c->type = COND_TYPE_FALSE;
1418  }
1419 
1420  break; /* it's no longer a map */
1421  }
1422 
1423  /*
1424  * Both are literal strings. They're not parsed
1425  * as TMPL_TYPE_DATA because there's no cast to an
1426  * attribute.
1427  *
1428  * We can do the evaluation here, so that it
1429  * doesn't need to be done at run time
1430  */
1431  if ((c->data.map->rhs->type == TMPL_TYPE_UNPARSED) &&
1432  (c->data.map->lhs->type == TMPL_TYPE_UNPARSED) &&
1433  !c->pass2_fixup) {
1434  int rcode;
1435 
1436  rad_assert(c->cast == NULL);
1437 
1438  rcode = radius_evaluate_map(NULL, 0, 0, c);
1439  if (rcode) {
1440  c->type = COND_TYPE_TRUE;
1441  } else {
1442  DEBUG3("OPTIMIZING (%s %s %s) --> FALSE",
1443  c->data.map->lhs->name,
1444  fr_int2str(fr_tokens_table, c->data.map->op, "??"),
1445  c->data.map->rhs->name);
1446  c->type = COND_TYPE_FALSE;
1447  }
1448 
1449  /*
1450  * Free map after using it above.
1451  */
1452  TALLOC_FREE(c->data.map);
1453  break;
1454  }
1455 
1456  /*
1457  * <ipaddr>"foo" CMP &Attribute-Name The cast may
1458  * not be necessary, and we can re-write it so
1459  * that the attribute reference is on the LHS.
1460  */
1461  if (c->cast &&
1462  (c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
1463  (c->cast->type == c->data.map->rhs->tmpl_da->type) &&
1464  (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
1465  vp_tmpl_t *tmp;
1466 
1467  tmp = c->data.map->rhs;
1468  c->data.map->rhs = c->data.map->lhs;
1469  c->data.map->lhs = tmp;
1470 
1471  c->cast = NULL;
1472 
1473  switch (c->data.map->op) {
1474  case T_OP_CMP_EQ:
1475  /* do nothing */
1476  break;
1477 
1478  case T_OP_LE:
1479  c->data.map->op = T_OP_GE;
1480  break;
1481 
1482  case T_OP_LT:
1483  c->data.map->op = T_OP_GT;
1484  break;
1485 
1486  case T_OP_GE:
1487  c->data.map->op = T_OP_LE;
1488  break;
1489 
1490  case T_OP_GT:
1491  c->data.map->op = T_OP_LT;
1492  break;
1493 
1494  default:
1495  return_0("Internal sanity check failed 1");
1496  }
1497 
1498  /*
1499  * This must have been parsed into TMPL_TYPE_DATA.
1500  */
1501  rad_assert(c->data.map->rhs->type != TMPL_TYPE_UNPARSED);
1502  }
1503 
1504  } while (0);
1505 
1506  /*
1507  * Existence checks. We short-circuit static strings,
1508  * too.
1509  *
1510  * FIXME: the data types should be in the template, too.
1511  * So that we know where a literal came from.
1512  *
1513  * "foo" is NOT the same as 'foo' or a bare foo.
1514  */
1515  if (c->type == COND_TYPE_EXISTS) {
1516  switch (c->data.vpt->type) {
1517  case TMPL_TYPE_XLAT:
1518  case TMPL_TYPE_ATTR:
1520  case TMPL_TYPE_LIST:
1521  case TMPL_TYPE_EXEC:
1522  break;
1523 
1524  /*
1525  * 'true' and 'false' are special strings
1526  * which mean themselves.
1527  *
1528  * For integers, 0 is false, all other
1529  * integers are true.
1530  *
1531  * For strings, '' and "" are false.
1532  * 'foo' and "foo" are true.
1533  *
1534  * The str2tmpl function takes care of
1535  * marking "%{foo}" as TMPL_TYPE_XLAT, so
1536  * the strings here are fixed at compile
1537  * time.
1538  *
1539  * `exec` and "%{...}" are left alone.
1540  *
1541  * Bare words must be module return
1542  * codes.
1543  */
1544  case TMPL_TYPE_UNPARSED:
1545  if ((strcmp(c->data.vpt->name, "true") == 0) ||
1546  (strcmp(c->data.vpt->name, "1") == 0)) {
1547  c->type = COND_TYPE_TRUE;
1548  TALLOC_FREE(c->data.vpt);
1549 
1550  } else if ((strcmp(c->data.vpt->name, "false") == 0) ||
1551  (strcmp(c->data.vpt->name, "0") == 0)) {
1552  c->type = COND_TYPE_FALSE;
1553  TALLOC_FREE(c->data.vpt);
1554 
1555  } else if (!*c->data.vpt->name) {
1556  c->type = COND_TYPE_FALSE;
1557  TALLOC_FREE(c->data.vpt);
1558 
1559  } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
1560  (lhs_type == T_DOUBLE_QUOTED_STRING)) {
1561  c->type = COND_TYPE_TRUE;
1562  TALLOC_FREE(c->data.vpt);
1563 
1564  } else if (lhs_type == T_BARE_WORD) {
1565  int rcode;
1566  bool zeros = true;
1567  char const *q;
1568 
1569  for (q = c->data.vpt->name;
1570  *q != '\0';
1571  q++) {
1572  if (!isdigit((int) *q)) {
1573  break;
1574  }
1575  if (*q != '0') zeros = false;
1576  }
1577 
1578  /*
1579  * It's all digits, and therefore
1580  * 'false' if zero, and 'true' otherwise.
1581  */
1582  if (!*q) {
1583  if (zeros) {
1584  c->type = COND_TYPE_FALSE;
1585  } else {
1586  c->type = COND_TYPE_TRUE;
1587  }
1588  TALLOC_FREE(c->data.vpt);
1589  break;
1590  }
1591 
1592  /*
1593  * Allow &Foo-Bar where Foo-Bar is an attribute
1594  * defined by a module.
1595  */
1596  if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
1597  break;
1598  }
1599 
1600  rcode = fr_str2int(allowed_return_codes,
1601  c->data.vpt->name, 0);
1602  if (!rcode) {
1603  return_0("Expected a module return code");
1604  }
1605  }
1606 
1607  /*
1608  * Else lhs_type==T_INVALID, and this
1609  * node was made by promoting a child
1610  * which had already been normalized.
1611  */
1612  break;
1613 
1614  case TMPL_TYPE_DATA:
1615  return_0("Cannot use data here");
1616 
1617  default:
1618  return_0("Internal sanity check failed 2");
1619  }
1620  }
1621 
1622  /*
1623  * !TRUE -> FALSE
1624  */
1625  if (c->type == COND_TYPE_TRUE) {
1626  if (c->negate) {
1627  c->negate = false;
1628  c->type = COND_TYPE_FALSE;
1629  }
1630  }
1631 
1632  /*
1633  * !FALSE -> TRUE
1634  */
1635  if (c->type == COND_TYPE_FALSE) {
1636  if (c->negate) {
1637  c->negate = false;
1638  c->type = COND_TYPE_TRUE;
1639  }
1640  }
1641 
1642  /*
1643  * true && FOO --> FOO
1644  */
1645  if ((c->type == COND_TYPE_TRUE) &&
1646  (c->next_op == COND_AND)) {
1647  fr_cond_t *next;
1648 
1649  next = talloc_steal(ctx, c->next);
1650  c->next = NULL;
1651 
1652  lhs = rhs = NULL;
1653  talloc_free(c);
1654  c = next;
1655  }
1656 
1657  /*
1658  * false && FOO --> false
1659  */
1660  if ((c->type == COND_TYPE_FALSE) &&
1661  (c->next_op == COND_AND)) {
1662  talloc_free(c->next);
1663  c->next = NULL;
1664  c->next_op = COND_NONE;
1665  }
1666 
1667  /*
1668  * false || FOO --> FOO
1669  */
1670  if ((c->type == COND_TYPE_FALSE) &&
1671  (c->next_op == COND_OR)) {
1672  fr_cond_t *next;
1673 
1674  next = talloc_steal(ctx, c->next);
1675  c->next = NULL;
1676 
1677  lhs = rhs = NULL;
1678  talloc_free(c);
1679  c = next;
1680  }
1681 
1682  /*
1683  * true || FOO --> true
1684  */
1685  if ((c->type == COND_TYPE_TRUE) &&
1686  (c->next_op == COND_OR)) {
1687  talloc_free(c->next);
1688  c->next = NULL;
1689  c->next_op = COND_NONE;
1690  }
1691 
1692  if (lhs) talloc_free(lhs);
1693  if (rhs) talloc_free(rhs);
1694 
1695  *pcond = c;
1696  return p - start;
1697 }
1698 
1699 /** Tokenize a conditional check
1700  *
1701  * @param[in] ctx for talloc
1702  * @param[in] ci for CONF_ITEM
1703  * @param[in] start the start of the string to process. Should be "(..."
1704  * @param[out] head the parsed condition structure
1705  * @param[out] error the parse error (if any)
1706  * @param[in] flags do one/two pass
1707  * @return
1708  * - Length of the string skipped.
1709  * - < 0 (the offset to the offending error) on error.
1710  */
1711 ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start,
1712  fr_cond_t **head, char const **error, int flags)
1713 {
1714  return condition_tokenize(ctx, ci, start, false, head, error, flags);
1715 }
1716 
1717 /*
1718  * Walk in order.
1719  */
1720 bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
1721 {
1722  while (c) {
1723  /*
1724  * Process this one, exit on error.
1725  */
1726  if (!callback(ctx, c)) return false;
1727 
1728  switch (c->type) {
1729  case COND_TYPE_INVALID:
1730  return false;
1731 
1732  case COND_TYPE_EXISTS:
1733  case COND_TYPE_MAP:
1734  case COND_TYPE_TRUE:
1735  case COND_TYPE_FALSE:
1736  break;
1737 
1738  case COND_TYPE_CHILD:
1739  /*
1740  * Walk over the child.
1741  */
1742  if (!fr_condition_walk(c->data.child, callback, ctx)) {
1743  return false;
1744  }
1745  }
1746 
1747  /*
1748  * No sibling, stop.
1749  */
1750  if (c->next_op == COND_NONE) break;
1751 
1752  /*
1753  * process the next sibling
1754  */
1755  c = c->next;
1756  }
1757 
1758  return true;
1759 }
size_t map_snprint(char *out, size_t outlen, vp_map_t const *map)
Print a map to a string.
Definition: map.c:1494
128 Bit IPv6 Address.
Definition: radius.h:40
ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, size_t inlen, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def, bool do_escape)
Convert an arbitrary string into a vp_tmpl_t.
Definition: tmpl.c:1022
#define DEBUG3(fmt,...)
Definition: log.h:177
Definition: token.h:47
#define return_rhs(_x)
Definition: parser.c:427
Definition: parser.h:42
Dictionary attribute.
Definition: dict.h:77
union fr_cond_t::@6 data
Ascend binary format a packed data structure.
Definition: radius.h:37
vp_tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:47
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
Dictionary attribute.
Definition: tmpl.h:133
#define return_P(_x)
Definition: parser.c:424
const size_t dict_attr_sizes[PW_TYPE_MAX][2]
Map data types to min / max data sizes.
Definition: dict.c:119
vp_tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:48
Pre-parsed XLAT expansion.
Definition: tmpl.h:139
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:956
Unparsed literal string.
Definition: tmpl.h:131
static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start, FR_TOKEN *op)
Definition: parser.c:145
const FR_NAME_NUMBER fr_tokens_table[]
Definition: token.c:30
IPv6 Prefix.
Definition: radius.h:41
#define PW_CAST_BASE
Definition: parser.c:31
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out, FR_TOKEN *op, char const **error)
Definition: parser.c:225
fr_dict_attr_t const * cast
Definition: parser.h:83
Long extended attribute space attribute.
Definition: radius.h:49
#define return_lhs(_x)
Definition: parser.c:426
fr_cond_t * next
Definition: parser.h:86
static expr_map_t map[]
Definition: rlm_expr.c:169
ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
Tokenize a conditional check.
Definition: parser.c:1711
size_t fr_cond_snprint(char *out, size_t outlen, fr_cond_t const *in)
Definition: parser.c:50
const int fr_dict_attr_allowed_chars[256]
Definition: dict.c:145
static bool condition_check_types(fr_cond_t *c, PW_TYPE lhs_type)
Definition: parser.c:338
static ssize_t condition_tokenize_cast(char const *start, fr_dict_attr_t const **pda, char const **error)
Definition: parser.c:284
Definition: token.h:50
Attribute not found in the global dictionary.
Definition: tmpl.h:134
#define rad_assert(expr)
Definition: rad_assert.h:38
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
int tmpl_define_unknown_attr(vp_tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a vp_tmpl_t to the main dictionary.
Definition: tmpl.c:1360
8 Bit unsigned integer.
Definition: radius.h:42
Value in native format.
Definition: tmpl.h:138
Interface ID.
Definition: radius.h:39
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
Regular expression.
Definition: tmpl.h:136
unsigned int attr
Attribute number.
Definition: dict.h:79
static bool done
Definition: radclient.c:53
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
bool negate
Definition: parser.h:80
Definition: token.h:49
Attribute list.
Definition: tmpl.h:135
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
48 Bit Mac-Address.
Definition: radius.h:44
int radius_evaluate_map(REQUEST *request, int modreturn, int depth, fr_cond_t const *c)
bool fr_condition_walk(fr_cond_t *c, bool(*callback)(void *, fr_cond_t *), void *ctx)
Definition: parser.c:1720
Invalid (uninitialised) attribute type.
Definition: radius.h:32
The current request.
Definition: tmpl.h:113
32 Bit unsigned integer.
Definition: radius.h:34
tmpl_type_t type
What type of value tmpl refers to.
Definition: tmpl.h:188
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
size_t len
Length of the raw string used to create the template.
Definition: tmpl.h:191
#define RETURN_IF_TRUNCATED(_p, _ret, _max)
Boilerplate for checking truncation.
Definition: libradius.h:216
64 Bit unsigned integer.
Definition: radius.h:51
fr_dict_attr_t const * fr_dict_attr_by_type(fr_dict_t *dict, unsigned int vendor, unsigned int attr, PW_TYPE type)
Lookup a attribute by its its vendor and attribute numbers and data type.
Definition: dict.c:3549
Definition: token.h:48
Callout to an external script or program.
Definition: tmpl.h:137
CONF_ITEM const * ci
Definition: parser.h:73
Vendor-Specific, for RADIUS attribute 26.
Definition: radius.h:53
void bool map_cast_from_hex(vp_map_t *map, FR_TOKEN rhs_type, char const *rhs)
re-parse a map where the lhs is an unknown attribute.
Definition: map.c:57
uint8_t data[]
Definition: eap_pwd.h:625
static const FR_NAME_NUMBER allowed_return_codes[]
Definition: parser.c:33
32 Bit Unix timestamp.
Definition: radius.h:36
FR_TOKEN op
The operator that controls insertion of the dst attribute.
Definition: map.h:50
Extended attribute space attribute.
Definition: radius.h:48
static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, bool brace, fr_cond_t **pcond, char const **error, int flags)
Tokenize a conditional check.
Definition: parser.c:444
fr_cond_pass2_t pass2_fixup
Definition: parser.h:81
size_t tmpl_snprint(char *buffer, size_t bufsize, vp_tmpl_t const *vpt, fr_dict_attr_t const *values)
Print a vp_tmpl_t to a string.
Definition: tmpl.c:1822
int value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE *src_type, fr_dict_attr_t const *src_enumv, char const *src, ssize_t src_len, char quote)
Convert string value to a value_data_t type.
Definition: value.c:455
#define return_SLEN
Definition: parser.c:428
#define return_0(_x)
Definition: parser.c:425
IPv4 Prefix.
Definition: radius.h:52
enum fr_token FR_TOKEN
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
XLAT expansion.
Definition: tmpl.h:132
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
PW_TYPE type
Value type.
Definition: dict.h:80
#define RCSID(id)
Definition: build.h:135
int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
Definition: token.c:471
Definition: token.h:51
32 Bit IPv4 Address.
Definition: radius.h:35
int tmpl_cast_in_place(vp_tmpl_t *vpt, PW_TYPE type, fr_dict_attr_t const *enumv)
Convert vp_tmpl_t of type TMPL_TYPE_UNPARSED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specified...
Definition: tmpl.c:1212
Value pair map.
Definition: map.h:46
A source or sink of value data.
Definition: tmpl.h:187
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
fr_cond_op_t next_op
Definition: parser.h:85
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31
Extended attribute, vendor specific.
Definition: radius.h:50
fr_cond_type_t type
Definition: parser.h:71