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