convert assert to run-time check.
[freeradius.git] / src / main / evaluate.c
1 /*
2  * evaluate.c   Evaluate complex conditions
3  *
4  * Version:     $Id$
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 2007  The FreeRADIUS server project
21  * Copyright 2007  Alan DeKok <aland@deployingradius.com>
22  */
23
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/parser.h>
29 #include <freeradius-devel/rad_assert.h>
30
31 #include <ctype.h>
32
33 #ifdef WITH_UNLANG
34 #ifdef WITH_EVAL_DEBUG
35 #  define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
36 #else
37 #  define EVAL_DEBUG(...)
38 #endif
39
40 FR_NAME_NUMBER const modreturn_table[] = {
41         { "reject",             RLM_MODULE_REJECT       },
42         { "fail",               RLM_MODULE_FAIL         },
43         { "ok",                 RLM_MODULE_OK           },
44         { "handled",            RLM_MODULE_HANDLED      },
45         { "invalid",            RLM_MODULE_INVALID      },
46         { "userlock",           RLM_MODULE_USERLOCK     },
47         { "notfound",           RLM_MODULE_NOTFOUND     },
48         { "noop",               RLM_MODULE_NOOP         },
49         { "updated",            RLM_MODULE_UPDATED      },
50         { NULL, 0 }
51 };
52
53
54 static bool all_digits(char const *string)
55 {
56         char const *p = string;
57
58         rad_assert(p != NULL);
59
60         if (*p == '\0') return false;
61
62         if (*p == '-') p++;
63
64         while (isdigit((int) *p)) p++;
65
66         return (*p == '\0');
67 }
68
69 /** Evaluate a template
70  *
71  * Converts a vp_tmpl_t to a boolean value.
72  *
73  * @param[in] request the REQUEST
74  * @param[in] modreturn the previous module return code
75  * @param[in] depth of the recursion (only used for debugging)
76  * @param[in] vpt the template to evaluate
77  * @return -1 on error, 0 for "no match", 1 for "match".
78  */
79 int radius_evaluate_tmpl(REQUEST *request, int modreturn, UNUSED int depth, vp_tmpl_t const *vpt)
80 {
81         int rcode;
82         int modcode;
83         value_data_t data;
84
85         switch (vpt->type) {
86         case TMPL_TYPE_LITERAL:
87                 modcode = fr_str2int(modreturn_table, vpt->name, RLM_MODULE_UNKNOWN);
88                 if (modcode != RLM_MODULE_UNKNOWN) {
89                         rcode = (modcode == modreturn);
90                         break;
91                 }
92
93                 /*
94                  *      Else it's a literal string.  Empty string is
95                  *      false, non-empty string is true.
96                  *
97                  *      @todo: Maybe also check for digits?
98                  *
99                  *      The VPT *doesn't* have a "bare word" type,
100                  *      which arguably it should.
101                  */
102                 rcode = (*vpt->name != '\0');
103                 break;
104
105         case TMPL_TYPE_ATTR:
106         case TMPL_TYPE_LIST:
107                 if (tmpl_find_vp(NULL, request, vpt) == 0) {
108                         rcode = true;
109                 } else {
110                         rcode = false;
111                 }
112                 break;
113
114         case TMPL_TYPE_XLAT_STRUCT:
115         case TMPL_TYPE_XLAT:
116         case TMPL_TYPE_EXEC:
117         {
118                 char *p;
119
120                 if (!*vpt->name) return false;
121                 rcode = tmpl_aexpand(request, &p, request, vpt, NULL, NULL);
122                 if (rcode < 0) {
123                         EVAL_DEBUG("FAIL %d", __LINE__);
124                         return -1;
125                 }
126                 data.strvalue = p;
127                 rcode = (data.strvalue && (*data.strvalue != '\0'));
128                 talloc_free(data.ptr);
129         }
130                 break;
131
132         /*
133          *      Can't have a bare ... (/foo/) ...
134          */
135         case TMPL_TYPE_REGEX:
136         case TMPL_TYPE_REGEX_STRUCT:
137                 rad_assert(0 == 1);
138                 /* FALL-THROUGH */
139
140         default:
141                 EVAL_DEBUG("FAIL %d", __LINE__);
142                 rcode = -1;
143                 break;
144         }
145
146         return rcode;
147 }
148
149 #ifdef HAVE_REGEX
150 /** Perform a regular expressions comparison between two operands
151  *
152  * @return -1 on error, 0 for "no match", 1 for "match".
153  */
154 static int cond_do_regex(REQUEST *request, fr_cond_t const *c,
155                          PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
156                          PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
157 {
158         vp_map_t const *map = c->data.map;
159
160         ssize_t         slen;
161         int             ret;
162
163         regex_t         *preg, *rreg = NULL;
164         regmatch_t      rxmatch[REQUEST_MAX_REGEX + 1]; /* +1 for %{0} (whole match) capture group */
165         size_t          nmatch = sizeof(rxmatch) / sizeof(regmatch_t);
166
167         if (!lhs || (lhs_type != PW_TYPE_STRING)) return -1;
168
169         EVAL_DEBUG("CMP WITH REGEX %s %s",
170                    map->rhs->tmpl_iflag ? "CASE INSENSITIVE" : "CASE SENSITIVE",
171                    map->rhs->tmpl_mflag ? "MULTILINE" : "SINGLELINE");
172
173         switch (map->rhs->type) {
174         case TMPL_TYPE_REGEX_STRUCT: /* pre-compiled to a regex */
175                 preg = map->rhs->tmpl_preg;
176                 break;
177
178         default:
179                 rad_assert(rhs_type == PW_TYPE_STRING);
180                 rad_assert(rhs->strvalue);
181                 slen = regex_compile(request, &rreg, rhs->strvalue, rhs_len,
182                                      map->rhs->tmpl_iflag, map->rhs->tmpl_mflag, true, true);
183                 if (slen <= 0) {
184                         REMARKER(rhs->strvalue, -slen, fr_strerror());
185                         EVAL_DEBUG("FAIL %d", __LINE__);
186
187                         return -1;
188                 }
189                 preg = rreg;
190                 break;
191         }
192
193         ret = regex_exec(preg, lhs->strvalue, lhs_len, rxmatch, &nmatch);
194         switch (ret) {
195         case 0:
196                 EVAL_DEBUG("CLEARING SUBCAPTURES");
197                 regex_sub_to_request(request, NULL, NULL, 0, NULL, 0);  /* clear out old entries */
198                 break;
199
200         case 1:
201                 EVAL_DEBUG("SETTING SUBCAPTURES");
202                 regex_sub_to_request(request, &preg, lhs->strvalue, lhs_len, rxmatch, nmatch);
203                 break;
204
205         case -1:
206                 EVAL_DEBUG("REGEX ERROR");
207                 REDEBUG("regex failed: %s", fr_strerror());
208                 break;
209
210         default:
211                 break;
212         }
213
214         if (preg) talloc_free(rreg);
215
216         return ret;
217 }
218 #endif
219
220 #ifdef WITH_EVAL_DEBUG
221 static void cond_print_operands(REQUEST *request,
222                                 PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
223                                 PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
224 {
225         if (lhs) {
226                 if (lhs_type == PW_TYPE_STRING) {
227                         EVAL_DEBUG("LHS: \"%s\" (%zu)" , lhs->strvalue, lhs_len);
228                 } else {
229                         char *lhs_hex;
230
231                         lhs_hex = talloc_array(request, char, (lhs_len * 2) + 1);
232
233                         if (lhs_type == PW_TYPE_OCTETS) {
234                                 fr_bin2hex(lhs_hex, lhs->octets, lhs_len);
235                         } else {
236                                 fr_bin2hex(lhs_hex, (uint8_t const *)lhs, lhs_len);
237                         }
238
239                         EVAL_DEBUG("LHS: 0x%s (%zu)", lhs_hex, lhs_len);
240
241                         talloc_free(lhs_hex);
242                 }
243         } else {
244                 EVAL_DEBUG("LHS: VIRTUAL");
245         }
246
247         if (rhs) {
248                 if (rhs_type == PW_TYPE_STRING) {
249                         EVAL_DEBUG("RHS: \"%s\" (%zu)" , rhs->strvalue, rhs_len);
250                 } else {
251                         char *rhs_hex;
252
253                         rhs_hex = talloc_array(request, char, (rhs_len * 2) + 1);
254
255                         if (rhs_type == PW_TYPE_OCTETS) {
256                                 fr_bin2hex(rhs_hex, rhs->octets, rhs_len);
257                         } else {
258                                 fr_bin2hex(rhs_hex, (uint8_t const *)rhs, rhs_len);
259                         }
260
261                         EVAL_DEBUG("RHS: 0x%s (%zu)", rhs_hex, rhs_len);
262
263                         talloc_free(rhs_hex);
264                 }
265         } else {
266                 EVAL_DEBUG("RHS: COMPILED");
267         }
268 }
269 #endif
270
271 /** Call the correct data comparison function for the condition
272  *
273  * Deals with regular expression comparisons, virtual attribute
274  * comparisons, and data comparisons.
275  *
276  * @return -1 on error, 0 for "no match", 1 for "match".
277  */
278 static int cond_cmp_values(REQUEST *request, fr_cond_t const *c,
279                            PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
280                            PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
281 {
282         vp_map_t const *map = c->data.map;
283         int rcode;
284
285 #ifdef WITH_EVAL_DEBUG
286                 EVAL_DEBUG("CMP OPERANDS");
287                 cond_print_operands(request, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
288 #endif
289
290 #ifdef HAVE_REGEX
291         /*
292          *      Regex comparison
293          */
294         if (map->op == T_OP_REG_EQ) {
295                 rcode = cond_do_regex(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
296                 goto finish;
297         }
298 #endif
299         /*
300          *      Virtual attribute comparison.
301          */
302         if (c->pass2_fixup == PASS2_PAIRCOMPARE) {
303                 VALUE_PAIR *vp;
304
305                 EVAL_DEBUG("CMP WITH PAIRCOMPARE");
306                 rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
307
308                 vp = fr_pair_afrom_da(request, map->lhs->tmpl_da);
309                 vp->op = c->data.map->op;
310
311                 value_data_copy(vp, &vp->data, rhs_type, rhs, rhs_len);
312                 vp->vp_length = rhs_len;
313
314                 rcode = paircompare(request, request->packet->vps, vp, NULL);
315                 rcode = (rcode == 0) ? 1 : 0;
316                 talloc_free(vp);
317                 goto finish;
318         }
319
320         /*
321          *      At this point both operands should have been normalised
322          *      to the same type, and there's no special comparisons
323          *      left.
324          */
325         rad_assert(lhs_type == rhs_type);
326
327         EVAL_DEBUG("CMP WITH VALUE DATA");
328         rcode = value_data_cmp_op(map->op, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
329 finish:
330         switch (rcode) {
331         case 0:
332                 EVAL_DEBUG("FALSE");
333                 break;
334
335         case 1:
336                 EVAL_DEBUG("TRUE");
337                 break;
338
339         default:
340                 EVAL_DEBUG("ERROR %i", rcode);
341                 break;
342         }
343
344         return rcode;
345 }
346
347
348 static size_t regex_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
349 {
350         char *p = out;
351
352         while (*in && (outlen > 2)) {
353                 switch (*in) {
354                 case '\\':
355                 case '.':
356                 case '*':
357                 case '+':
358                 case '?':
359                 case '|':
360                 case '^':
361                 case '$':
362                 case '[':       /* we don't list close braces */
363                 case '{':
364                 case '(':
365                         if (outlen < 3) goto done;
366
367                         *(p++) = '\\';
368                         outlen--;
369                         /* FALL-THROUGH */
370
371                 default:
372                         *(p++) = *(in++);
373                         outlen--;
374                         break;
375                 }
376         }
377
378 done:
379         *(p++) = '\0';
380         return p - out;
381 }
382
383
384 /** Convert both operands to the same type
385  *
386  * If casting is successful, we call cond_cmp_values to do the comparison
387  *
388  * @return -1 on error, 0 for "no match", 1 for "match".
389  */
390 static int cond_normalise_and_cmp(REQUEST *request, fr_cond_t const *c,
391                                   PW_TYPE lhs_type, DICT_ATTR const *lhs_enumv,
392                                   value_data_t const *lhs, size_t lhs_len)
393 {
394         vp_map_t const *map = c->data.map;
395
396         DICT_ATTR const *cast = NULL;
397         PW_TYPE cast_type = PW_TYPE_INVALID;
398
399         int rcode;
400
401         PW_TYPE rhs_type = PW_TYPE_INVALID;
402         DICT_ATTR const *rhs_enumv = NULL;
403         value_data_t const *rhs = NULL;
404         size_t rhs_len;
405
406         value_data_t lhs_cast, rhs_cast;
407         void *lhs_cast_buff = NULL, *rhs_cast_buff = NULL;
408
409         xlat_escape_t escape = NULL;
410
411         /*
412          *      Cast operand to correct type.
413          *
414          *      With hack for strings that look like integers, to cast them
415          *      to 64 bit unsigned integers.
416          *
417          * @fixme For things like this it'd be useful to have a 64bit signed type.
418          */
419 #define CAST(_s) \
420 do {\
421         if ((cast_type != PW_TYPE_INVALID) && (_s ## _type != PW_TYPE_INVALID) && (cast_type != _s ## _type)) {\
422                 ssize_t r;\
423                 EVAL_DEBUG("CASTING " #_s " FROM %s TO %s",\
424                            fr_int2str(dict_attr_types, _s ## _type, "<INVALID>"),\
425                            fr_int2str(dict_attr_types, cast_type, "<INVALID>"));\
426                 r = value_data_cast(request, &_s ## _cast, cast_type, cast, _s ## _type, _s ## _enumv, _s, _s ## _len);\
427                 if (r < 0) {\
428                         REDEBUG("Failed casting " #_s " operand: %s", fr_strerror());\
429                         rcode = -1;\
430                         goto finish;\
431                 }\
432                 if (cast && cast->flags.is_pointer) _s ## _cast_buff = _s ## _cast.ptr;\
433                 _s ## _type = cast_type;\
434                 _s ## _len = (size_t)r;\
435                 _s = &_s ## _cast;\
436         }\
437 } while (0)
438
439 #define CHECK_INT_CAST(_l, _r) \
440 do {\
441         if ((cast_type == PW_TYPE_INVALID) &&\
442             _l && (_l ## _type == PW_TYPE_STRING) &&\
443             _r && (_r ## _type == PW_TYPE_STRING) &&\
444             all_digits(lhs->strvalue) && all_digits(rhs->strvalue)) {\
445                 cast_type = PW_TYPE_INTEGER64;\
446                 EVAL_DEBUG("OPERANDS ARE NUMBER STRINGS, SETTING CAST TO integer64");\
447         }\
448 } while (0)
449
450         /*
451          *      Regular expressions need both operands to be strings
452          */
453 #ifdef HAVE_REGEX
454         if (map->op == T_OP_REG_EQ) {
455                 cast_type = PW_TYPE_STRING;
456
457                 if (map->rhs->type == TMPL_TYPE_XLAT_STRUCT) escape = regex_escape;
458         }
459         else
460 #endif
461         /*
462          *      If it's a pair comparison, data gets cast to the
463          *      type of the pair comparison attribute.
464          *
465          *      Magic attribute is always the LHS.
466          */
467         if (c->pass2_fixup == PASS2_PAIRCOMPARE) {
468                 rad_assert(!c->cast);
469                 rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
470 #ifndef NDEBUG
471                 /* expensive assert */
472                 rad_assert((map->rhs->type != TMPL_TYPE_ATTR) || !radius_find_compare(map->rhs->tmpl_da));
473 #endif
474                 cast = map->lhs->tmpl_da;
475                 cast_type = cast->type;
476
477                 EVAL_DEBUG("NORMALISATION TYPE %s (PAIRCMP TYPE)",
478                            fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
479         /*
480          *      Otherwise we use the explicit cast, or implicit
481          *      cast (from an attribute reference).
482          *      We already have the data for the lhs, so we convert
483          *      it here.
484          */
485         } else if (c->cast) {
486                 cast = c->cast;
487                 EVAL_DEBUG("NORMALISATION TYPE %s (EXPLICIT CAST)",
488                            fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
489         } else if (map->lhs->type == TMPL_TYPE_ATTR) {
490                 cast = map->lhs->tmpl_da;
491                 EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM LHS REF)",
492                            fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
493         } else if (map->rhs->type == TMPL_TYPE_ATTR) {
494                 cast = map->rhs->tmpl_da;
495                 EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM RHS REF)",
496                            fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
497         } else if (map->lhs->type == TMPL_TYPE_DATA) {
498                 cast_type = map->lhs->tmpl_data_type;
499                 EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM LHS DATA)",
500                            fr_int2str(dict_attr_types, cast_type, "<INVALID>"));
501         } else if (map->rhs->type == TMPL_TYPE_DATA) {
502                 cast_type = map->rhs->tmpl_data_type;
503                 EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM RHS DATA)",
504                            fr_int2str(dict_attr_types, cast_type, "<INVALID>"));
505         }
506
507         if (cast) cast_type = cast->type;
508
509         switch (map->rhs->type) {
510         case TMPL_TYPE_ATTR:
511         {
512                 VALUE_PAIR *vp;
513                 vp_cursor_t cursor;
514
515                 for (vp = tmpl_cursor_init(&rcode, &cursor, request, map->rhs);
516                      vp;
517                      vp = tmpl_cursor_next(&cursor, map->rhs)) {
518                         rhs_type = vp->da->type;
519                         rhs_enumv = vp->da;
520                         rhs = &vp->data;
521                         rhs_len = vp->vp_length;
522
523                         CHECK_INT_CAST(lhs, rhs);
524                         CAST(lhs);
525                         CAST(rhs);
526
527                         rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
528                         if (rcode != 0) break;
529
530                         TALLOC_FREE(rhs_cast_buff);
531                 }
532         }
533                 break;
534
535         case TMPL_TYPE_DATA:
536                 rhs_type = map->rhs->tmpl_data_type;
537                 rhs = &map->rhs->tmpl_data_value;
538                 rhs_len = map->rhs->tmpl_data_length;
539
540                 CHECK_INT_CAST(lhs, rhs);
541                 CAST(lhs);
542                 CAST(rhs);
543
544                 rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
545                 break;
546
547         /*
548          *      Expanded types start as strings, then get converted
549          *      to the type of the attribute or the explicit cast.
550          */
551         case TMPL_TYPE_LITERAL:
552         case TMPL_TYPE_EXEC:
553         case TMPL_TYPE_XLAT:
554         case TMPL_TYPE_XLAT_STRUCT:
555         {
556                 ssize_t ret;
557                 value_data_t data;
558
559                 if (map->rhs->type != TMPL_TYPE_LITERAL) {
560                         char *p;
561
562                         ret = tmpl_aexpand(request, &p, request, map->rhs, escape, NULL);
563                         if (ret < 0) {
564                                 EVAL_DEBUG("FAIL [%i]", __LINE__);
565                                 rcode = -1;
566                                 goto finish;
567                         }
568                         data.strvalue = p;
569                         rhs_len = ret;
570
571                 } else {
572                         data.strvalue = map->rhs->name;
573                         rhs_len = map->rhs->len;
574                 }
575                 rad_assert(data.strvalue);
576
577                 rhs_type = PW_TYPE_STRING;
578                 rhs = &data;
579
580                 CHECK_INT_CAST(lhs, rhs);
581                 CAST(lhs);
582                 CAST(rhs);
583
584                 rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
585                 if (map->rhs->type != TMPL_TYPE_LITERAL)talloc_free(data.ptr);
586
587                 break;
588         }
589
590         /*
591          *      RHS is a compiled regex, we don't need to do anything with it.
592          */
593         case TMPL_TYPE_REGEX_STRUCT:
594                 CAST(lhs);
595                 rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, PW_TYPE_INVALID, NULL, 0);
596                 break;
597         /*
598          *      Unsupported types (should have been parse errors)
599          */
600         case TMPL_TYPE_NULL:
601         case TMPL_TYPE_LIST:
602         case TMPL_TYPE_UNKNOWN:
603         case TMPL_TYPE_ATTR_UNDEFINED:
604         case TMPL_TYPE_REGEX:   /* Should now be a TMPL_TYPE_REGEX_STRUCT or TMPL_TYPE_XLAT_STRUCT */
605                 rad_assert(0);
606                 rcode = -1;
607                 break;
608         }
609
610 finish:
611         talloc_free(lhs_cast_buff);
612         talloc_free(rhs_cast_buff);
613
614         return rcode;
615 }
616
617
618 /** Evaluate a map
619  *
620  * @param[in] request the REQUEST
621  * @param[in] modreturn the previous module return code
622  * @param[in] depth of the recursion (only used for debugging)
623  * @param[in] c the condition to evaluate
624  * @return -1 on error, 0 for "no match", 1 for "match".
625  */
626 int radius_evaluate_map(REQUEST *request, UNUSED int modreturn, UNUSED int depth, fr_cond_t const *c)
627 {
628         int rcode = 0;
629
630         vp_map_t const *map = c->data.map;
631
632         EVAL_DEBUG(">>> MAP TYPES LHS: %s, RHS: %s",
633                    fr_int2str(tmpl_names, map->lhs->type, "???"),
634                    fr_int2str(tmpl_names, map->rhs->type, "???"));
635
636         switch (map->lhs->type) {
637         /*
638          *      LHS is an attribute or list
639          */
640         case TMPL_TYPE_LIST:
641         case TMPL_TYPE_ATTR:
642         {
643                 VALUE_PAIR *vp;
644                 vp_cursor_t cursor;
645                 /*
646                  *      Legacy paircompare call, skip processing the magic attribute
647                  *      if it's the LHS and cast RHS to the same type.
648                  */
649                 if ((c->pass2_fixup == PASS2_PAIRCOMPARE) && (map->op != T_OP_REG_EQ)) {
650 #ifndef NDEBUG
651                         rad_assert(radius_find_compare(map->lhs->tmpl_da)); /* expensive assert */
652 #endif
653                         rcode = cond_normalise_and_cmp(request, c, PW_TYPE_INVALID, NULL, NULL, 0);
654                         break;
655                 }
656                 for (vp = tmpl_cursor_init(&rcode, &cursor, request, map->lhs);
657                      vp;
658                      vp = tmpl_cursor_next(&cursor, map->lhs)) {
659                         /*
660                          *      Evaluate all LHS values, condition evaluates to true
661                          *      if we get at least one set of operands that
662                          *      evaluates to true.
663                          */
664                         rcode = cond_normalise_and_cmp(request, c, vp->da->type, vp->da, &vp->data, vp->vp_length);
665                         if (rcode != 0) break;
666                 }
667         }
668                 break;
669
670         case TMPL_TYPE_DATA:
671                 rcode = cond_normalise_and_cmp(request, c,
672                                               map->lhs->tmpl_data_type, NULL, &map->lhs->tmpl_data_value,
673                                               map->lhs->tmpl_data_length);
674                 break;
675
676         case TMPL_TYPE_LITERAL:
677         case TMPL_TYPE_EXEC:
678         case TMPL_TYPE_XLAT:
679         case TMPL_TYPE_XLAT_STRUCT:
680         {
681                 ssize_t ret;
682                 value_data_t data;
683
684                 if (map->lhs->type != TMPL_TYPE_LITERAL) {
685                         char *p;
686
687                         ret = tmpl_aexpand(request, &p, request, map->lhs, NULL, NULL);
688                         if (ret < 0) {
689                                 EVAL_DEBUG("FAIL [%i]", __LINE__);
690                                 return ret;
691                         }
692                         data.strvalue = p;
693                 } else {
694                         data.strvalue = map->lhs->name;
695                         ret = map->lhs->len;
696                 }
697                 rad_assert(data.strvalue);
698
699                 rcode = cond_normalise_and_cmp(request, c, PW_TYPE_STRING, NULL, &data, ret);
700                 if (map->lhs->type != TMPL_TYPE_LITERAL) talloc_free(data.ptr);
701         }
702                 break;
703
704         /*
705          *      Unsupported types (should have been parse errors)
706          */
707         case TMPL_TYPE_NULL:
708         case TMPL_TYPE_ATTR_UNDEFINED:
709         case TMPL_TYPE_UNKNOWN:
710         case TMPL_TYPE_REGEX:           /* should now be a TMPL_TYPE_REGEX_STRUCT or TMPL_TYPE_XLAT_STRUCT */
711         case TMPL_TYPE_REGEX_STRUCT:    /* not allowed as LHS */
712                 rad_assert(0);
713                 rcode = -1;
714                 break;
715         }
716
717         EVAL_DEBUG("<<<");
718
719         return rcode;
720 }
721
722 /** Evaluate a fr_cond_t;
723  *
724  * @param[in] request the REQUEST
725  * @param[in] modreturn the previous module return code
726  * @param[in] depth of the recursion (only used for debugging)
727  * @param[in] c the condition to evaluate
728  * @return -1 on failure, -2 on attribute not found, 0 for "no match", 1 for "match".
729  */
730 int radius_evaluate_cond(REQUEST *request, int modreturn, int depth, fr_cond_t const *c)
731 {
732         int rcode = -1;
733 #ifdef WITH_EVAL_DEBUG
734         char buffer[1024];
735
736         fr_cond_sprint(buffer, sizeof(buffer), c);
737         EVAL_DEBUG("%s", buffer);
738 #endif
739
740         while (c) {
741                 switch (c->type) {
742                 case COND_TYPE_EXISTS:
743                         rcode = radius_evaluate_tmpl(request, modreturn, depth, c->data.vpt);
744                         /* Existence checks are special, because we expect them to fail */
745                         if (rcode < 0) rcode = 0;
746                         break;
747
748                 case COND_TYPE_MAP:
749                         rcode = radius_evaluate_map(request, modreturn, depth, c);
750                         break;
751
752                 case COND_TYPE_CHILD:
753                         rcode = radius_evaluate_cond(request, modreturn, depth + 1, c->data.child);
754                         break;
755
756                 case COND_TYPE_TRUE:
757                         rcode = true;
758                         break;
759
760                 case COND_TYPE_FALSE:
761                         rcode = false;
762                         break;
763                 default:
764                         EVAL_DEBUG("FAIL %d", __LINE__);
765                         return -1;
766                 }
767
768                 if (rcode < 0) return rcode;
769
770                 if (c->negate) rcode = !rcode;
771
772                 if (!c->next) break;
773
774                 /*
775                  *      FALSE && ... = FALSE
776                  */
777                 if (!rcode && (c->next_op == COND_AND)) return false;
778
779                 /*
780                  *      TRUE || ... = TRUE
781                  */
782                 if (rcode && (c->next_op == COND_OR)) return true;
783
784                 c = c->next;
785         }
786
787         if (rcode < 0) {
788                 EVAL_DEBUG("FAIL %d", __LINE__);
789         }
790         return rcode;
791 }
792 #endif
793
794
795 /*
796  *      The fr_pair_list_move() function in src/lib/valuepair.c does all sorts of
797  *      extra magic that we don't want here.
798  *
799  *      FIXME: integrate this with the code calling it, so that we
800  *      only fr_pair_list_copy() those attributes that we're really going to
801  *      use.
802  */
803 void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat)
804 {
805         int i, j, count, from_count, to_count, tailto;
806         vp_cursor_t cursor;
807         VALUE_PAIR *vp, *next, **last;
808         VALUE_PAIR **from_list, **to_list;
809         VALUE_PAIR *append, **append_tail;
810         VALUE_PAIR *to_copy;
811         bool *edited = NULL;
812         REQUEST *fixup = NULL;
813         TALLOC_CTX *ctx;
814
815         /*
816          *      Set up arrays for editing, to remove some of the
817          *      O(N^2) dependencies.  This also makes it easier to
818          *      insert and remove attributes.
819          *
820          *      It also means that the operators apply ONLY to the
821          *      attributes in the original list.  With the previous
822          *      implementation of fr_pair_list_move(), adding two attributes
823          *      via "+=" and then "=" would mean that the second one
824          *      wasn't added, because of the existence of the first
825          *      one in the "to" list.  This implementation doesn't
826          *      have that bug.
827          *
828          *      Also, the previous implementation did NOT implement
829          *      "-=" correctly.  If two of the same attributes existed
830          *      in the "to" list, and you tried to subtract something
831          *      matching the *second* value, then the fr_pair_delete_by_num()
832          *      function was called, and the *all* attributes of that
833          *      number were deleted.  With this implementation, only
834          *      the matching attributes are deleted.
835          */
836         count = 0;
837         for (vp = fr_cursor_init(&cursor, &from); vp; vp = fr_cursor_next(&cursor)) count++;
838         from_list = talloc_array(request, VALUE_PAIR *, count);
839
840         for (vp = fr_cursor_init(&cursor, to); vp; vp = fr_cursor_next(&cursor)) count++;
841         to_list = talloc_array(request, VALUE_PAIR *, count);
842
843         append = NULL;
844         append_tail = &append;
845
846         /*
847          *      Move the lists to the arrays, and break the list
848          *      chains.
849          */
850         from_count = 0;
851         for (vp = from; vp != NULL; vp = next) {
852                 next = vp->next;
853                 from_list[from_count++] = vp;
854                 vp->next = NULL;
855         }
856
857         to_count = 0;
858         ctx = talloc_parent(*to);
859         to_copy = fr_pair_list_copy(ctx, *to);
860         for (vp = to_copy; vp != NULL; vp = next) {
861                 next = vp->next;
862                 to_list[to_count++] = vp;
863                 vp->next = NULL;
864         }
865         tailto = to_count;
866         edited = talloc_zero_array(request, bool, to_count);
867
868         RDEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count);
869
870         /*
871          *      Now that we have the lists initialized, start working
872          *      over them.
873          */
874         for (i = 0; i < from_count; i++) {
875                 int found;
876
877                 RDEBUG4("::: Examining %s", from_list[i]->da->name);
878
879                 if (do_xlat) radius_xlat_do(request, from_list[i]);
880
881                 /*
882                  *      Attribute should be appended, OR the "to" list
883                  *      is empty, and we're supposed to replace or
884                  *      "add if not existing".
885                  */
886                 if (from_list[i]->op == T_OP_ADD) goto do_append;
887
888                 found = false;
889                 for (j = 0; j < to_count; j++) {
890                         if (edited[j] || !to_list[j] || !from_list[i]) continue;
891
892                         /*
893                          *      Attributes aren't the same, skip them.
894                          */
895                         if (from_list[i]->da != to_list[j]->da) {
896                                 continue;
897                         }
898
899                         /*
900                          *      We don't use a "switch" statement here
901                          *      because we want to break out of the
902                          *      "for" loop over 'j' in most cases.
903                          */
904
905                         /*
906                          *      Over-write the FIRST instance of the
907                          *      matching attribute name.  We free the
908                          *      one in the "to" list, and move over
909                          *      the one in the "from" list.
910                          */
911                         if (from_list[i]->op == T_OP_SET) {
912                                 RDEBUG4("::: OVERWRITING %s FROM %d TO %d",
913                                        to_list[j]->da->name, i, j);
914                                 fr_pair_list_free(&to_list[j]);
915                                 to_list[j] = from_list[i];
916                                 from_list[i] = NULL;
917                                 edited[j] = true;
918                                 break;
919                         }
920
921                         /*
922                          *      Add the attribute only if it does not
923                          *      exist... but it exists, so we stop
924                          *      looking.
925                          */
926                         if (from_list[i]->op == T_OP_EQ) {
927                                 found = true;
928                                 break;
929                         }
930
931                         /*
932                          *      Delete every attribute, independent
933                          *      of its value.
934                          */
935                         if (from_list[i]->op == T_OP_CMP_FALSE) {
936                                 goto delete;
937                         }
938
939                         /*
940                          *      Delete all matching attributes from
941                          *      "to"
942                          */
943                         if ((from_list[i]->op == T_OP_SUB) ||
944                             (from_list[i]->op == T_OP_CMP_EQ) ||
945                             (from_list[i]->op == T_OP_LE) ||
946                             (from_list[i]->op == T_OP_GE)) {
947                                 int rcode;
948                                 int old_op = from_list[i]->op;
949
950                                 /*
951                                  *      Check for equality.
952                                  */
953                                 from_list[i]->op = T_OP_CMP_EQ;
954
955                                 /*
956                                  *      If equal, delete the one in
957                                  *      the "to" list.
958                                  */
959                                 rcode = radius_compare_vps(NULL, from_list[i],
960                                                            to_list[j]);
961                                 /*
962                                  *      We may want to do more
963                                  *      subtractions, so we re-set the
964                                  *      operator back to it's original
965                                  *      value.
966                                  */
967                                 from_list[i]->op = old_op;
968
969                                 switch (old_op) {
970                                 case T_OP_CMP_EQ:
971                                         if (rcode != 0) goto delete;
972                                         break;
973
974                                 case T_OP_SUB:
975                                         if (rcode == 0) {
976                                         delete:
977                                                 RDEBUG4("::: DELETING %s FROM %d TO %d",
978                                                        from_list[i]->da->name, i, j);
979                                                 fr_pair_list_free(&to_list[j]);
980                                                 to_list[j] = NULL;
981                                         }
982                                         break;
983
984                                         /*
985                                          *      Enforce <=.  If it's
986                                          *      >, replace it.
987                                          */
988                                 case T_OP_LE:
989                                         if (rcode > 0) {
990                                                 RDEBUG4("::: REPLACING %s FROM %d TO %d",
991                                                        from_list[i]->da->name, i, j);
992                                                 fr_pair_list_free(&to_list[j]);
993                                                 to_list[j] = from_list[i];
994                                                 from_list[i] = NULL;
995                                                 edited[j] = true;
996                                         }
997                                         break;
998
999                                 case T_OP_GE:
1000                                         if (rcode < 0) {
1001                                                 RDEBUG4("::: REPLACING %s FROM %d TO %d",
1002                                                        from_list[i]->da->name, i, j);
1003                                                 fr_pair_list_free(&to_list[j]);
1004                                                 to_list[j] = from_list[i];
1005                                                 from_list[i] = NULL;
1006                                                 edited[j] = true;
1007                                         }
1008                                         break;
1009                                 }
1010
1011                                 continue;
1012                         }
1013
1014                         rad_assert(0 == 1); /* panic! */
1015                 }
1016
1017                 /*
1018                  *      We were asked to add it if it didn't exist,
1019                  *      and it doesn't exist.  Move it over to the
1020                  *      tail of the "to" list, UNLESS it was already
1021                  *      moved by another operator.
1022                  */
1023                 if (!found && from_list[i]) {
1024                         if ((from_list[i]->op == T_OP_EQ) ||
1025                             (from_list[i]->op == T_OP_LE) ||
1026                             (from_list[i]->op == T_OP_GE) ||
1027                             (from_list[i]->op == T_OP_SET)) {
1028                         do_append:
1029                                 RDEBUG4("::: APPENDING %s FROM %d TO %d",
1030                                        from_list[i]->da->name, i, tailto);
1031                                 *append_tail = from_list[i];
1032                                 from_list[i]->op = T_OP_EQ;
1033                                 from_list[i] = NULL;
1034                                 append_tail = &(*append_tail)->next;
1035                         }
1036                 }
1037         }
1038
1039         /*
1040          *      Delete attributes in the "from" list.
1041          */
1042         for (i = 0; i < from_count; i++) {
1043                 if (!from_list[i]) continue;
1044
1045                 fr_pair_list_free(&from_list[i]);
1046         }
1047         talloc_free(from_list);
1048
1049         RDEBUG4("::: TO in %d out %d", to_count, tailto);
1050
1051         /*
1052          *      Re-chain the "to" list.
1053          */
1054         fr_pair_list_free(to);
1055         last = to;
1056
1057         if (to == &request->packet->vps) {
1058                 fixup = request;
1059         } else if (request->parent && (to == &request->parent->packet->vps)) {
1060                 fixup = request->parent;
1061         }
1062
1063         for (i = 0; i < tailto; i++) {
1064                 if (!to_list[i]) continue;
1065
1066                 vp = to_list[i];
1067                 RDEBUG4("::: to[%d] = %s", i, vp->da->name);
1068
1069                 /*
1070                  *      Mash the operator to a simple '='.  The
1071                  *      operators in the "to" list aren't used for
1072                  *      anything.  BUT they're used in the "detail"
1073                  *      file and debug output, where we don't want to
1074                  *      see the operators.
1075                  */
1076                 vp->op = T_OP_EQ;
1077
1078                 *last = vp;
1079                 last = &(*last)->next;
1080         }
1081
1082         /*
1083          *      And finally add in the attributes we're appending to
1084          *      the tail of the "to" list.
1085          */
1086         *last = append;
1087
1088         /*
1089          *      Fix dumb cache issues
1090          */
1091         if (fixup) {
1092                 fixup->username = NULL;
1093                 fixup->password = NULL;
1094
1095                 for (vp = fixup->packet->vps; vp != NULL; vp = vp->next) {
1096                         if (vp->da->vendor) continue;
1097
1098                         if ((vp->da->attr == PW_USER_NAME) && !fixup->username) {
1099                                 fixup->username = vp;
1100
1101                         } else if (vp->da->attr == PW_STRIPPED_USER_NAME) {
1102                                 fixup->username = vp;
1103
1104                         } else if (vp->da->attr == PW_USER_PASSWORD) {
1105                                 fixup->password = vp;
1106                         }
1107                 }
1108         }
1109
1110         rad_assert(request->packet != NULL);
1111
1112         talloc_free(to_list);
1113         talloc_free(edited);
1114 }