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