bcecfd9e4c6c8663cd41061f47d1008ea2cbe2ca
[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
35 #ifdef WITH_EVAL_DEBUG
36 #define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
37
38 static FR_NAME_NUMBER const template_names[] = {
39         { "literal",    VPT_TYPE_LITERAL },
40         { "xlat",       VPT_TYPE_XLAT },
41         { "attr",       VPT_TYPE_ATTR },
42         { "list",       VPT_TYPE_LIST },
43         { "regex",      VPT_TYPE_REGEX },
44         { "exec",       VPT_TYPE_EXEC },
45         { "data",       VPT_TYPE_DATA },
46         { "xlat",       VPT_TYPE_XLAT_STRUCT },
47         { "regex",      VPT_TYPE_REGEX_STRUCT },
48         { NULL, 0 }
49 };
50 #else
51 #define EVAL_DEBUG(...)
52 #endif
53
54 FR_NAME_NUMBER const modreturn_table[] = {
55         { "reject",     RLM_MODULE_REJECT       },
56         { "fail",       RLM_MODULE_FAIL         },
57         { "ok",         RLM_MODULE_OK           },
58         { "handled",    RLM_MODULE_HANDLED      },
59         { "invalid",    RLM_MODULE_INVALID      },
60         { "userlock",   RLM_MODULE_USERLOCK     },
61         { "notfound",   RLM_MODULE_NOTFOUND     },
62         { "noop",       RLM_MODULE_NOOP         },
63         { "updated",    RLM_MODULE_UPDATED      },
64         { NULL, 0 }
65 };
66
67
68 static int all_digits(char const *string)
69 {
70         char const *p = string;
71
72         rad_assert(p != NULL);
73
74         if (*p == '-') p++;
75
76         while (isdigit((int) *p)) p++;
77
78         return (*p == '\0');
79 }
80
81 /** Expand the RHS of a template
82  *
83  * @note Length of expanded string can be found with talloc_array_length(*out) - 1
84  *
85  * @param out where to write a pointer to the newly allocated buffer.
86  * @param request Current request.
87  * @param vpt to evaluate.
88  * @return -1 on error, else 0.
89  */
90 static int radius_expand_tmpl(char **out, REQUEST *request, value_pair_tmpl_t const *vpt)
91 {
92         VALUE_PAIR *vp;
93         int ret;
94         *out = NULL;
95
96         rad_assert(vpt->type != VPT_TYPE_LIST);
97
98         switch (vpt->type) {
99         case VPT_TYPE_LITERAL:
100                 EVAL_DEBUG("TMPL LITERAL");
101                 *out = talloc_typed_strdup(request, vpt->name);
102                 break;
103
104         case VPT_TYPE_EXEC:
105                 EVAL_DEBUG("TMPL EXEC");
106                 *out = talloc_array(request, char, 1024);
107                 if (radius_exec_program(request, vpt->name, true, false, *out, 1024, EXEC_TIMEOUT, NULL, NULL) != 0) {
108                         TALLOC_FREE(*out);
109                         return -1;
110                 }
111                 break;
112
113         case VPT_TYPE_REGEX:
114                 EVAL_DEBUG("TMPL REGEX");
115                 /* Error in expansion, this is distinct from zero length expansion */
116                 if (radius_axlat(out, request, vpt->name, NULL, NULL) < 0) {
117                         rad_assert(!*out);
118                         return -1;
119                 }
120                 break;
121
122         case VPT_TYPE_XLAT:
123                 EVAL_DEBUG("TMPL XLAT");
124                 /* Error in expansion, this is distinct from zero length expansion */
125                 if (radius_axlat(out, request, vpt->name, NULL, NULL) < 0) {
126                         rad_assert(!*out);
127                         return -1;
128                 }
129                 break;
130
131         case VPT_TYPE_XLAT_STRUCT:
132                 EVAL_DEBUG("TMPL XLAT_STRUCT");
133                 /* Error in expansion, this is distinct from zero length expansion */
134                 if (radius_axlat_struct(out, request, vpt->vpt_xlat, NULL, NULL) < 0) {
135                         rad_assert(!*out);
136                         return -1;
137                 }
138                 RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
139                 RDEBUG2("   --> %s", *out);
140                 break;
141
142         case VPT_TYPE_ATTR:
143                 EVAL_DEBUG("TMPL ATTR");
144                 ret = radius_tmpl_get_vp(&vp, request, vpt);
145                 if (ret < 0) return ret;
146
147                 *out = vp_aprint_value(request, vp);
148                 if (!*out) {
149                         return -1;
150                 }
151                 break;
152
153         case VPT_TYPE_DATA:
154         case VPT_TYPE_REGEX_STRUCT:
155                 rad_assert(0 == 1);
156                 /* FALL-THROUGH */
157
158         default:
159                 break;
160         }
161
162         EVAL_DEBUG("Expand tmpl --> %s", *out);
163         return 0;
164 }
165
166 /** Evaluate a template
167  *
168  * @param[in] request the REQUEST
169  * @param[in] modreturn the previous module return code
170  * @param[in] depth of the recursion (only used for debugging)
171  * @param[in] vpt the template to evaluate
172  * @return -1 on error, 0 for "no match", 1 for "match".
173  */
174 int radius_evaluate_tmpl(REQUEST *request, int modreturn, UNUSED int depth,
175                          value_pair_tmpl_t const *vpt)
176 {
177         int rcode;
178         int modcode;
179         char *buffer;
180
181         switch (vpt->type) {
182         case VPT_TYPE_LITERAL:
183                 modcode = fr_str2int(modreturn_table, vpt->name, RLM_MODULE_UNKNOWN);
184                 if (modcode != RLM_MODULE_UNKNOWN) {
185                         rcode = (modcode == modreturn);
186                         break;
187                 }
188
189                 /*
190                  *      Else it's a literal string.  Empty string is
191                  *      false, non-empty string is true.
192                  *
193                  *      @todo: Maybe also check for digits?
194                  *
195                  *      The VPT *doesn't* have a "bare word" type,
196                  *      which arguably it should.
197                  */
198                 rcode = (vpt->name != '\0');
199                 break;
200
201         case VPT_TYPE_ATTR:
202         case VPT_TYPE_LIST:
203                 if (radius_tmpl_get_vp(NULL, request, vpt) < 0) {
204                         rcode = false;
205                 } else {
206                         rcode = true;
207                 }
208                 break;
209
210                 /*
211                  *      FIXME: expand the strings
212                  *      if not empty, return!
213                  */
214         case VPT_TYPE_XLAT_STRUCT:
215         case VPT_TYPE_XLAT:
216         case VPT_TYPE_EXEC:
217                 if (!*vpt->name) return false;
218                 rcode = radius_expand_tmpl(&buffer, request, vpt);
219                 if (rcode < 0) {
220                         EVAL_DEBUG("FAIL %d", __LINE__);
221                         return -1;
222                 }
223                 rcode = (buffer && (*buffer != '\0'));
224                 talloc_free(buffer);
225                 break;
226
227                 /*
228                  *      Can't have a bare ... (/foo/) ...
229                  */
230         case VPT_TYPE_REGEX:
231         case VPT_TYPE_REGEX_STRUCT:
232                 EVAL_DEBUG("FAIL %d", __LINE__);
233                 rad_assert(0 == 1);
234                 /* FALL-THROUGH */
235
236         default:
237                 rcode = -1;
238                 break;
239         }
240
241         return rcode;
242 }
243
244
245 static int do_regex(REQUEST *request, value_pair_map_t const *map)
246 {
247         int compare, rcode, ret;
248         regex_t reg, *preg;
249         char *lhs, *rhs;
250         regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
251
252         /*
253          *  Expand and then compile it.
254          */
255         switch (map->src->type) {
256         case VPT_TYPE_REGEX:
257                 rcode = radius_expand_tmpl(&rhs, request, map->src);
258                 if (rcode < 0) {
259                         EVAL_DEBUG("FAIL %d", __LINE__);
260                         return -1;
261                 }
262                 rad_assert(rhs != NULL);
263
264                 compare = regcomp(&reg, rhs, REG_EXTENDED | (map->src->vpt_iflag ? REG_ICASE : 0));
265                 if (compare != 0) {
266                         if (debug_flag) {
267                                 char errbuf[128];
268
269                                 regerror(compare, &reg, errbuf, sizeof(errbuf));
270                                 ERROR("Failed compiling regular expression: %s", errbuf);
271                         }
272                         EVAL_DEBUG("FAIL %d", __LINE__);
273                         return -1;
274                 }
275
276                 preg = &reg;
277                 break;
278
279         case VPT_TYPE_REGEX_STRUCT:
280                 preg = map->src->vpt_preg;
281                 break;
282
283         default:
284                 rad_assert(0);
285                 return -1;
286         }
287
288         rcode = radius_expand_tmpl(&lhs, request, map->dst);
289         if (rcode < 0) {
290                 EVAL_DEBUG("FAIL %d", __LINE__);
291                 ret = -1;
292                 goto finish;
293         }
294         rad_assert(lhs != NULL);
295
296         /*
297          *  regexec doesn't initialise unused elements
298          */
299         memset(&rxmatch, 0, sizeof(rxmatch));
300         compare = regexec(preg, lhs, REQUEST_MAX_REGEX + 1, rxmatch, 0);
301         rad_regcapture(request, compare, lhs, rxmatch);
302         ret = (compare == 0);
303
304 finish:
305         /*
306          *  regcomp allocs extra memory for the expression, so if the
307          *  result wasn't cached we need to free it here.
308          */
309         if (preg == &reg) regfree(&reg);
310
311         return ret;
312 }
313
314 /*
315  *      Expand a template to a string, parse it as type of "cast", and
316  *      create a VP from the data.
317  */
318 static VALUE_PAIR *get_cast_vp(REQUEST *request, value_pair_tmpl_t const *vpt, DICT_ATTR const *cast)
319 {
320         int rcode;
321         VALUE_PAIR *vp;
322         char *str;
323
324         vp = pairalloc(request, cast);
325         if (!vp) return NULL;
326
327         if (vpt->type == VPT_TYPE_DATA) {
328                 rad_assert(vp->da->type == vpt->vpt_da->type);
329                 pairdatacpy(vp, vpt->vpt_da, vpt->vpt_value, vpt->vpt_length);
330                 return vp;
331         }
332
333         rcode = radius_expand_tmpl(&str, request, vpt);
334         if (rcode < 0) {
335                 pairfree(&vp);
336                 return NULL;
337         }
338
339         if (pairparsevalue(vp, str, 0) < 0) {
340                 talloc_free(str);
341                 pairfree(&vp);
342                 return NULL;
343         }
344
345         return vp;
346 }
347
348 /*
349  *      Copy data from src to dst, where the attributes are of
350  *      different type.
351  */
352 static int do_cast_copy(VALUE_PAIR *dst, VALUE_PAIR const *src)
353 {
354         rad_assert(dst->da->type != src->da->type);
355
356         if (dst->da->type == PW_TYPE_STRING) {
357                 dst->vp_strvalue = vp_aprint_value(dst, src);
358                 dst->length = strlen(dst->vp_strvalue);
359                 return 0;
360         }
361
362         if (dst->da->type == PW_TYPE_OCTETS) {
363                 if (src->da->type == PW_TYPE_STRING) {
364                         pairmemcpy(dst, src->vp_octets, src->length);   /* Copy embedded NULLs */
365                 } else {
366                         pairmemcpy(dst, (uint8_t const *) &src->data, src->length);
367                 }
368                 return 0;
369         }
370
371         if (src->da->type == PW_TYPE_STRING) {
372                 return pairparsevalue(dst, src->vp_strvalue, 0);
373         }
374
375         if ((src->da->type == PW_TYPE_INTEGER64) &&
376             (dst->da->type == PW_TYPE_ETHERNET)) {
377                 uint8_t array[8];
378                 uint64_t i;
379
380                 i = htonll(src->vp_integer64);
381                 memcpy(array, &i, 8);
382
383                 /*
384                  *      For OUIs in the DB.
385                  */
386                 if ((array[0] != 0) || (array[1] != 0)) return -1;
387
388                 memcpy(&dst->vp_ether, &array[2], 6);
389                 dst->length = 6;
390                 return 0;
391         }
392
393         /*
394          *      The attribute we've found has to have a size which is
395          *      compatible with the type of the destination cast.
396          */
397         if ((src->length < dict_attr_sizes[dst->da->type][0]) ||
398             (src->length > dict_attr_sizes[dst->da->type][1])) {
399                 EVAL_DEBUG("Casted attribute is wrong size (%u)", (unsigned int) src->length);
400                 return -1;
401         }
402
403         if (src->da->type == PW_TYPE_OCTETS) {
404                 switch (dst->da->type) {
405                 case PW_TYPE_INTEGER64:
406                         dst->vp_integer = ntohll(*(uint64_t const *) src->vp_octets);
407                         break;
408
409
410                 case PW_TYPE_INTEGER:
411                 case PW_TYPE_DATE:
412                 case PW_TYPE_SIGNED:
413                         dst->vp_integer = ntohl(*(uint32_t const *) src->vp_octets);
414                         break;
415
416                 case PW_TYPE_SHORT:
417                         dst->vp_integer = ntohs(*(uint16_t const *) src->vp_octets);
418                         break;
419
420                 case PW_TYPE_BYTE:
421                         dst->vp_integer = src->vp_octets[0];
422                         break;
423
424                 default:
425                         memcpy(&dst->data, src->vp_octets, src->length);
426                         break;
427                 }
428
429                 dst->length = src->length;
430                 return 0;
431         }
432
433         /*
434          *      Convert host order to network byte order.
435          */
436         if ((dst->da->type == PW_TYPE_IPV4_ADDR) &&
437             ((src->da->type == PW_TYPE_INTEGER) ||
438              (src->da->type == PW_TYPE_DATE) ||
439              (src->da->type == PW_TYPE_SIGNED))) {
440                 dst->vp_ipaddr = htonl(src->vp_integer);
441
442         } else if ((src->da->type == PW_TYPE_IPV4_ADDR) &&
443                    ((dst->da->type == PW_TYPE_INTEGER) ||
444                     (dst->da->type == PW_TYPE_DATE) ||
445                     (dst->da->type == PW_TYPE_SIGNED))) {
446                 dst->vp_integer = htonl(src->vp_ipaddr);
447
448         } else {                /* they're of the same byte order */
449                 memcpy(&dst->data, &src->data, src->length);
450         }
451
452         dst->length = src->length;
453
454         return 0;
455 }
456
457
458 /** Evaluate a map
459  *
460  * @param[in] request the REQUEST
461  * @param[in] modreturn the previous module return code
462  * @param[in] depth of the recursion (only used for debugging)
463  * @param[in] c the condition to evaluate
464  * @return -1 on error, 0 for "no match", 1 for "match".
465  */
466 int radius_evaluate_map(REQUEST *request, UNUSED int modreturn, UNUSED int depth,
467                         fr_cond_t const *c)
468 {
469         int rcode;
470         char *lhs, *rhs;
471         value_pair_map_t *map;
472
473         rad_assert(c->type == COND_TYPE_MAP);
474         map = c->data.map;
475
476         rad_assert(map->dst->type != VPT_TYPE_UNKNOWN);
477         rad_assert(map->src->type != VPT_TYPE_UNKNOWN);
478         rad_assert(map->dst->type != VPT_TYPE_LIST);
479         rad_assert(map->src->type != VPT_TYPE_LIST);
480         rad_assert(map->dst->type != VPT_TYPE_REGEX);
481         rad_assert(map->dst->type != VPT_TYPE_REGEX_STRUCT);
482
483         EVAL_DEBUG("Map %s ? %s",
484                    fr_int2str(template_names, map->dst->type, "???"),
485                    fr_int2str(template_names, map->src->type, "???"));
486
487         /*
488          *      Verify regexes.
489          */
490         if ((map->src->type == VPT_TYPE_REGEX) ||
491             (map->src->type == VPT_TYPE_REGEX_STRUCT)) {
492                 rad_assert(map->op == T_OP_REG_EQ);
493         } else {
494                 rad_assert(!((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)));
495         }
496
497         /*
498          *      They're both attributes.  Do attribute-specific work.
499          *
500          *      LHS is DST.  RHS is SRC <sigh>
501          */
502         if (!c->cast && (map->src->type == VPT_TYPE_ATTR) && (map->dst->type == VPT_TYPE_ATTR)) {
503                 VALUE_PAIR *lhs_vp, *rhs_vp;
504
505                 EVAL_DEBUG("ATTR to ATTR");
506                 if ((radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) ||
507                     (radius_tmpl_get_vp(&rhs_vp, request, map->src) < 0)) return false;
508
509                 return paircmp_op(lhs_vp, map->op, rhs_vp);
510         }
511
512         /*
513          *      LHS is a cast.  Do type-specific comparisons, as if
514          *      the LHS was a real attribute.
515          */
516         if (c->cast) {
517                 VALUE_PAIR *lhs_vp, *rhs_vp;
518
519                 /*
520                  *      Try to copy data from the VP which is being
521                  *      casted, instead of printing it to a string and
522                  *      then re-parsing it.
523                  */
524                 if (map->dst->type == VPT_TYPE_ATTR) {
525                         VALUE_PAIR *cast_vp;
526
527                         if (radius_tmpl_get_vp(&cast_vp, request, map->dst) < 0) return false;
528
529                         lhs_vp = pairalloc(request, c->cast);
530                         if (!lhs_vp) return false;
531
532                         /*
533                          *      In a separate function for clarity
534                          */
535                         if (do_cast_copy(lhs_vp, cast_vp) < 0) {
536                                 talloc_free(lhs_vp);
537                                 return false;
538                         }
539
540                 } else {
541                         lhs_vp = get_cast_vp(request, map->dst, c->cast);
542                 }
543                 if (!lhs_vp) return false;
544
545                 /*
546                  *      Get either a real VP, or parse the RHS into a
547                  *      VP, and return that.
548                  */
549                 if (map->src->type == VPT_TYPE_ATTR) {
550                         if (radius_tmpl_get_vp(&rhs_vp, request, map->src) < 0) return false;
551                 } else {
552                         rhs_vp = get_cast_vp(request, map->src, c->cast);
553                 }
554
555                 if (!rhs_vp) return false;
556
557                 EVAL_DEBUG("CAST to %s",
558                            fr_int2str(dict_attr_types,
559                                       c->cast->type, "?Unknown?"));
560
561                 rcode = paircmp_op(lhs_vp, map->op, rhs_vp);
562                 pairfree(&lhs_vp);
563                 if (map->src->type != VPT_TYPE_ATTR) {
564                         pairfree(&rhs_vp);
565                 }
566                 return rcode;
567         }
568
569         /*
570          *      Might be a virtual comparison
571          */
572         if ((map->dst->type == VPT_TYPE_ATTR) &&
573             (map->src->type != VPT_TYPE_REGEX) &&
574             (map->src->type != VPT_TYPE_REGEX_STRUCT) &&
575             (c->pass2_fixup == PASS2_PAIRCOMPARE)) {
576                 int ret;
577                 VALUE_PAIR *lhs_vp;
578
579                 EVAL_DEBUG("virtual ATTR to DATA");
580
581                 lhs_vp = get_cast_vp(request, map->src, map->dst->vpt_da);
582                 if (!lhs_vp) return false;
583
584                 /*
585                  *      paircompare requires the operator be set for the
586                  *      check attribute.
587                  */
588                 lhs_vp->op = map->op;
589                 ret = paircompare(request, request->packet->vps, lhs_vp, NULL);
590                 talloc_free(lhs_vp);
591                 if (ret == 0) {
592                         return true;
593                 }
594                 return false;
595         }
596         rad_assert(c->pass2_fixup != PASS2_PAIRCOMPARE);
597
598         /*
599          *      RHS has been pre-parsed into binary data.  Go check
600          *      that.
601          */
602         if ((map->dst->type == VPT_TYPE_ATTR) &&
603             (map->src->type == VPT_TYPE_DATA)) {
604                 VALUE_PAIR *lhs_vp, *rhs_vp;
605
606                 EVAL_DEBUG("ATTR to DATA");
607
608                 if (radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) return false;
609
610                 rhs_vp = get_cast_vp(request, map->src, map->dst->vpt_da);
611                 if (!rhs_vp) return false;
612
613 #ifdef WITH_EVAL_DEBUG
614                 debug_pair(lhs_vp);
615                 debug_pair(rhs_vp);
616 #endif
617
618                 rcode = paircmp_op(lhs_vp, map->op, rhs_vp);
619                 pairfree(&rhs_vp);
620                 return rcode;
621         }
622
623         rad_assert(map->src->type != VPT_TYPE_DATA);
624         rad_assert(map->dst->type != VPT_TYPE_DATA);
625
626 #ifdef HAVE_REGEX_H
627         /*
628          *      Parse regular expressions.
629          */
630         if ((map->src->type == VPT_TYPE_REGEX) ||
631             (map->src->type == VPT_TYPE_REGEX_STRUCT)) {
632                 return do_regex(request, map);
633         }
634 #endif
635
636         /*
637          *      The RHS now needs to be expanded into a string.
638          */
639         rcode = radius_expand_tmpl(&rhs, request, map->src);
640         if (rcode < 0) {
641                 EVAL_DEBUG("FAIL %d", __LINE__);
642                 return -1;
643         }
644         rad_assert(rhs != NULL);
645
646         /*
647          *      User-Name == FOO
648          *
649          *      Parse the RHS to be the same DA as the LHS.  do
650          *      comparisons.  So long as it's not a regex, which does
651          *      string comparisons.
652          *
653          *      The LHS may be a virtual attribute, too.
654          */
655         if (map->dst->type == VPT_TYPE_ATTR) {
656                 VALUE_PAIR *lhs_vp, *rhs_vp;
657
658                 EVAL_DEBUG("ATTR to non-REGEX");
659
660                 /*
661                  *      No LHS means no match
662                  */
663                 if (radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) {
664                         /*
665                          *      Not a real attr: might be a dynamic comparison.
666                          */
667                         if ((map->dst->type == VPT_TYPE_ATTR) &&
668                             (map->dst->vpt_da->vendor == 0) &&
669                             radius_find_compare(map->dst->vpt_da)) {
670                                 rhs_vp = pairalloc(request, map->dst->vpt_da);
671                                 rad_assert(rhs_vp != NULL);
672                                 if (pairparsevalue(rhs_vp, rhs, 0) < 0) {
673                                         talloc_free(rhs);
674                                         EVAL_DEBUG("FAIL %d", __LINE__);
675                                         return -1;
676                                 }
677                                 talloc_free(rhs);
678
679                                 rcode = (radius_callback_compare(request, NULL, rhs_vp, NULL, NULL) == 0);
680                                 pairfree(&rhs_vp);
681                                 return rcode;
682                         }
683
684                         return false;
685                 }
686
687                 /*
688                  *      Get VP for RHS
689                  */
690                 rhs_vp = pairalloc(request, map->dst->vpt_da);
691                 rad_assert(rhs_vp != NULL);
692                 if (pairparsevalue(rhs_vp, rhs, 0) < 0) {
693                         talloc_free(rhs);
694                         pairfree(&rhs_vp);
695                         EVAL_DEBUG("FAIL %d", __LINE__);
696                         return -1;
697                 }
698
699                 rcode = paircmp_op(lhs_vp, map->op, rhs_vp);
700                 talloc_free(rhs);
701                 pairfree(&rhs_vp);
702                 return rcode;
703         }
704
705         /*
706          *      The LHS is a string.  Expand it.
707          */
708         rcode = radius_expand_tmpl(&lhs, request, map->dst);
709         if (rcode < 0) {
710                 EVAL_DEBUG("FAIL %d", __LINE__);
711                 return -1;
712         }
713         rad_assert(lhs != NULL);
714
715         EVAL_DEBUG("LHS is %s", lhs);
716
717         /*
718          *      Loop over the string, doing comparisons
719          */
720         if (all_digits(lhs) && all_digits(rhs)) {
721                 int lint, rint;
722
723                 lint = strtoul(lhs, NULL, 0);
724                 rint = strtoul(rhs, NULL, 0);
725                 talloc_free(lhs);
726                 talloc_free(rhs);
727
728                 switch (map->op) {
729                 case T_OP_CMP_EQ:
730                         return (lint == rint);
731
732                 case T_OP_NE:
733                         return (lint != rint);
734
735                 case T_OP_LT:
736                         return (lint < rint);
737
738                 case T_OP_GT:
739                         return (lint > rint);
740
741                 case T_OP_LE:
742                         return (lint <= rint);
743
744                 case T_OP_GE:
745                         return (lint >= rint);
746
747                 default:
748                         break;
749                 }
750
751         } else {
752                 rad_assert(lhs != NULL);
753                 rad_assert(rhs != NULL);
754
755                 rcode = strcmp(lhs, rhs);
756                 talloc_free(lhs);
757                 talloc_free(rhs);
758
759                 switch (map->op) {
760                 case T_OP_CMP_EQ:
761                         return (rcode == 0);
762
763                 case T_OP_NE:
764                         return (rcode != 0);
765
766                 case T_OP_LT:
767                         return (rcode < 0);
768
769                 case T_OP_GT:
770                         return (rcode > 0);
771
772                 case T_OP_LE:
773                         return (rcode <= 0);
774
775                 case T_OP_GE:
776                         return (rcode >= 0);
777
778                 default:
779                         break;
780                 }
781         }
782
783         EVAL_DEBUG("FAIL %d", __LINE__);
784         return -1;
785 }
786
787
788 /** Evaluate a fr_cond_t;
789  *
790  * @param[in] request the REQUEST
791  * @param[in] modreturn the previous module return code
792  * @param[in] depth of the recursion (only used for debugging)
793  * @param[in] c the condition to evaluate
794  * @return -1 on error, 0 for "no match", 1 for "match".
795  */
796 int radius_evaluate_cond(REQUEST *request, int modreturn, int depth,
797                          fr_cond_t const *c)
798 {
799         int rcode = -1;
800 #ifdef WITH_EVAL_DEBUG
801         char buffer[1024];
802
803         fr_cond_sprint(buffer, sizeof(buffer), c);
804         EVAL_DEBUG("%s", buffer);
805 #endif
806
807         while (c) {
808                 switch (c->type) {
809                 case COND_TYPE_EXISTS:
810                         rcode = radius_evaluate_tmpl(request, modreturn, depth, c->data.vpt);
811                         break;
812
813                 case COND_TYPE_MAP:
814                         rcode = radius_evaluate_map(request, modreturn, depth, c);
815                         break;
816
817                 case COND_TYPE_CHILD:
818                         rcode = radius_evaluate_cond(request, modreturn, depth + 1, c->data.child);
819                         break;
820
821                 case COND_TYPE_TRUE:
822                         rcode = true;
823                         break;
824
825                 case COND_TYPE_FALSE:
826                         rcode = false;
827                         break;
828                 default:
829                         EVAL_DEBUG("FAIL %d", __LINE__);
830                         return -1;
831                 }
832
833                 if (rcode < 0) return rcode;
834
835                 if (c->negate) rcode = !rcode;
836
837                 if (!c->next) break;
838
839                 /*
840                  *      FALSE && ... = FALSE
841                  */
842                 if (!rcode && (c->next_op == COND_AND)) return false;
843
844                 /*
845                  *      TRUE || ... = TRUE
846                  */
847                 if (rcode && (c->next_op == COND_OR)) return true;
848
849                 c = c->next;
850         }
851
852         if (rcode < 0) {
853                 EVAL_DEBUG("FAIL %d", __LINE__);
854         }
855         return rcode;
856 }
857 #endif
858
859
860 /*
861  *      The pairmove() function in src/lib/valuepair.c does all sorts of
862  *      extra magic that we don't want here.
863  *
864  *      FIXME: integrate this with the code calling it, so that we
865  *      only paircopy() those attributes that we're really going to
866  *      use.
867  */
868 void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat)
869 {
870         int i, j, count, from_count, to_count, tailto;
871         vp_cursor_t cursor;
872         VALUE_PAIR *vp, *next, **last;
873         VALUE_PAIR **from_list, **to_list;
874         int *edited = NULL;
875         REQUEST *fixup = NULL;
876
877         if (!request) return;
878
879         /*
880          *      Set up arrays for editing, to remove some of the
881          *      O(N^2) dependencies.  This also makes it easier to
882          *      insert and remove attributes.
883          *
884          *      It also means that the operators apply ONLY to the
885          *      attributes in the original list.  With the previous
886          *      implementation of pairmove(), adding two attributes
887          *      via "+=" and then "=" would mean that the second one
888          *      wasn't added, because of the existence of the first
889          *      one in the "to" list.  This implementation doesn't
890          *      have that bug.
891          *
892          *      Also, the previous implementation did NOT implement
893          *      "-=" correctly.  If two of the same attributes existed
894          *      in the "to" list, and you tried to subtract something
895          *      matching the *second* value, then the pairdelete()
896          *      function was called, and the *all* attributes of that
897          *      number were deleted.  With this implementation, only
898          *      the matching attributes are deleted.
899          */
900         count = 0;
901         for (vp = fr_cursor_init(&cursor, &from); vp; vp = fr_cursor_next(&cursor)) count++;
902         from_list = rad_malloc(sizeof(*from_list) * count);
903
904         for (vp = fr_cursor_init(&cursor, to); vp; vp = fr_cursor_next(&cursor)) count++;
905         to_list = rad_malloc(sizeof(*to_list) * count);
906
907         /*
908          *      Move the lists to the arrays, and break the list
909          *      chains.
910          */
911         from_count = 0;
912         for (vp = from; vp != NULL; vp = next) {
913                 next = vp->next;
914                 from_list[from_count++] = vp;
915                 vp->next = NULL;
916         }
917
918         to_count = 0;
919         for (vp = *to; vp != NULL; vp = next) {
920                 next = vp->next;
921                 to_list[to_count++] = vp;
922                 vp->next = NULL;
923         }
924         tailto = to_count;
925         edited = rad_malloc(sizeof(*edited) * to_count);
926         memset(edited, 0, sizeof(*edited) * to_count);
927
928         RDEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count);
929
930         /*
931          *      Now that we have the lists initialized, start working
932          *      over them.
933          */
934         for (i = 0; i < from_count; i++) {
935                 int found;
936
937                 RDEBUG4("::: Examining %s", from_list[i]->da->name);
938
939                 if (do_xlat) radius_xlat_do(request, from_list[i]);
940
941                 /*
942                  *      Attribute should be appended, OR the "to" list
943                  *      is empty, and we're supposed to replace or
944                  *      "add if not existing".
945                  */
946                 if (from_list[i]->op == T_OP_ADD) goto append;
947
948                 found = false;
949                 for (j = 0; j < to_count; j++) {
950                         if (edited[j] || !to_list[j] || !from_list[i]) continue;
951
952                         /*
953                          *      Attributes aren't the same, skip them.
954                          */
955                         if (from_list[i]->da != to_list[j]->da) {
956                                 continue;
957                         }
958
959                         /*
960                          *      We don't use a "switch" statement here
961                          *      because we want to break out of the
962                          *      "for" loop over 'j' in most cases.
963                          */
964
965                         /*
966                          *      Over-write the FIRST instance of the
967                          *      matching attribute name.  We free the
968                          *      one in the "to" list, and move over
969                          *      the one in the "from" list.
970                          */
971                         if (from_list[i]->op == T_OP_SET) {
972                                 RDEBUG4("::: OVERWRITING %s FROM %d TO %d",
973                                        to_list[j]->da->name, i, j);
974                                 pairfree(&to_list[j]);
975                                 to_list[j] = from_list[i];
976                                 from_list[i] = NULL;
977                                 edited[j] = true;
978                                 break;
979                         }
980
981                         /*
982                          *      Add the attribute only if it does not
983                          *      exist... but it exists, so we stop
984                          *      looking.
985                          */
986                         if (from_list[i]->op == T_OP_EQ) {
987                                 found = true;
988                                 break;
989                         }
990
991                         /*
992                          *      Delete every attribute, independent
993                          *      of its value.
994                          */
995                         if (from_list[i]->op == T_OP_CMP_FALSE) {
996                                 goto delete;
997                         }
998
999                         /*
1000                          *      Delete all matching attributes from
1001                          *      "to"
1002                          */
1003                         if ((from_list[i]->op == T_OP_SUB) ||
1004                             (from_list[i]->op == T_OP_CMP_EQ) ||
1005                             (from_list[i]->op == T_OP_LE) ||
1006                             (from_list[i]->op == T_OP_GE)) {
1007                                 int rcode;
1008                                 int old_op = from_list[i]->op;
1009
1010                                 /*
1011                                  *      Check for equality.
1012                                  */
1013                                 from_list[i]->op = T_OP_CMP_EQ;
1014
1015                                 /*
1016                                  *      If equal, delete the one in
1017                                  *      the "to" list.
1018                                  */
1019                                 rcode = radius_compare_vps(NULL, from_list[i],
1020                                                            to_list[j]);
1021                                 /*
1022                                  *      We may want to do more
1023                                  *      subtractions, so we re-set the
1024                                  *      operator back to it's original
1025                                  *      value.
1026                                  */
1027                                 from_list[i]->op = old_op;
1028
1029                                 switch (old_op) {
1030                                 case T_OP_CMP_EQ:
1031                                         if (rcode != 0) goto delete;
1032                                         break;
1033
1034                                 case T_OP_SUB:
1035                                         if (rcode == 0) {
1036                                         delete:
1037                                                 RDEBUG4("::: DELETING %s FROM %d TO %d",
1038                                                        from_list[i]->da->name, i, j);
1039                                                 pairfree(&to_list[j]);
1040                                                 to_list[j] = NULL;
1041                                         }
1042                                         break;
1043
1044                                         /*
1045                                          *      Enforce <=.  If it's
1046                                          *      >, replace it.
1047                                          */
1048                                 case T_OP_LE:
1049                                         if (rcode > 0) {
1050                                                 RDEBUG4("::: REPLACING %s FROM %d TO %d",
1051                                                        from_list[i]->da->name, i, j);
1052                                                 pairfree(&to_list[j]);
1053                                                 to_list[j] = from_list[i];
1054                                                 from_list[i] = NULL;
1055                                                 edited[j] = true;
1056                                         }
1057                                         break;
1058
1059                                 case T_OP_GE:
1060                                         if (rcode < 0) {
1061                                                 RDEBUG4("::: REPLACING %s FROM %d TO %d",
1062                                                        from_list[i]->da->name, i, j);
1063                                                 pairfree(&to_list[j]);
1064                                                 to_list[j] = from_list[i];
1065                                                 from_list[i] = NULL;
1066                                                 edited[j] = true;
1067                                         }
1068                                         break;
1069                                 }
1070
1071                                 continue;
1072                         }
1073
1074                         rad_assert(0 == 1); /* panic! */
1075                 }
1076
1077                 /*
1078                  *      We were asked to add it if it didn't exist,
1079                  *      and it doesn't exist.  Move it over to the
1080                  *      tail of the "to" list, UNLESS it was already
1081                  *      moved by another operator.
1082                  */
1083                 if (!found && from_list[i]) {
1084                         if ((from_list[i]->op == T_OP_EQ) ||
1085                             (from_list[i]->op == T_OP_LE) ||
1086                             (from_list[i]->op == T_OP_GE) ||
1087                             (from_list[i]->op == T_OP_SET)) {
1088                         append:
1089                                 RDEBUG4("::: APPENDING %s FROM %d TO %d",
1090                                        from_list[i]->da->name, i, tailto);
1091                                 to_list[tailto++] = from_list[i];
1092                                 from_list[i] = NULL;
1093                         }
1094                 }
1095         }
1096
1097         /*
1098          *      Delete attributes in the "from" list.
1099          */
1100         for (i = 0; i < from_count; i++) {
1101                 if (!from_list[i]) continue;
1102
1103                 pairfree(&from_list[i]);
1104         }
1105         free(from_list);
1106
1107         RDEBUG4("::: TO in %d out %d", to_count, tailto);
1108
1109         /*
1110          *      Re-chain the "to" list.
1111          */
1112         *to = NULL;
1113         last = to;
1114
1115         if (to == &request->packet->vps) {
1116                 fixup = request;
1117         } else if (request->parent && (to == &request->parent->packet->vps)) {
1118                 fixup = request->parent;
1119         }
1120         if (fixup) {
1121                 fixup->username = NULL;
1122                 fixup->password = NULL;
1123         }
1124
1125         for (i = 0; i < tailto; i++) {
1126                 if (!to_list[i]) continue;
1127
1128                 vp = to_list[i];
1129                 RDEBUG4("::: to[%d] = %s", i, vp->da->name);
1130
1131                 /*
1132                  *      Mash the operator to a simple '='.  The
1133                  *      operators in the "to" list aren't used for
1134                  *      anything.  BUT they're used in the "detail"
1135                  *      file and debug output, where we don't want to
1136                  *      see the operators.
1137                  */
1138                 vp->op = T_OP_EQ;
1139
1140                 /*
1141                  *      Fix dumb cache issues
1142                  */
1143                 if (fixup && !vp->da->vendor) {
1144                         if ((vp->da->attr == PW_USER_NAME) &&
1145                             !fixup->username) {
1146                                 fixup->username = vp;
1147
1148                         } else if (vp->da->attr == PW_STRIPPED_USER_NAME) {
1149                                 fixup->username = vp;
1150
1151                         } else if (vp->da->attr == PW_USER_PASSWORD) {
1152                                 fixup->password = vp;
1153                         }
1154                 }
1155
1156                 *last = vp;
1157                 last = &(*last)->next;
1158         }
1159
1160         rad_assert(request->packet != NULL);
1161
1162         free(to_list);
1163         free(edited);
1164 }