add timeout arg to radius_exec_program, with default EXEC_TIMEOUT
[freeradius.git] / src / main / valuepair.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16
17 /*
18  * $Id$
19  *
20  * @brief Valuepair functions that are radiusd-specific and as such do not
21  *        belong in the library.
22  * @file main/valuepair.c
23  *
24  * @ingroup AVP
25  *
26  * @copyright 2000,2006  The FreeRADIUS server project
27  * @copyright 2000  Alan DeKok <aland@ox.org>
28  */
29
30 RCSID("$Id$")
31
32 #include <ctype.h>
33
34 #include <freeradius-devel/radiusd.h>
35 #include <freeradius-devel/rad_assert.h>
36
37 const FR_NAME_NUMBER vpt_types[] = {
38         {"unknown",             VPT_TYPE_UNKNOWN },
39         {"literal",             VPT_TYPE_LITERAL },
40         {"expanded",            VPT_TYPE_XLAT },
41         {"attribute ref",       VPT_TYPE_ATTR },
42         {"list",                VPT_TYPE_LIST },
43         {"exec",                VPT_TYPE_EXEC },
44         {"value-pair-data",     VPT_TYPE_DATA }
45 };
46
47 struct cmp {
48         DICT_ATTR const *da;
49         DICT_ATTR const *from;
50         bool    first_only;
51         void *instance; /* module instance */
52         RAD_COMPARE_FUNC compare;
53         struct cmp *next;
54 };
55 static struct cmp *cmp;
56
57 /** Compares check and vp by value.
58  *
59  * Does not call any per-attribute comparison function, but does honour
60  * check.operator. Basically does "vp.value check.op check.value".
61  *
62  * @param request Current request.
63  * @param check rvalue, and operator.
64  * @param vp lvalue.
65  * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
66  *      value, -2 on error.
67  */
68 int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
69 {
70         int ret = 0;
71
72         /*
73          *      Check for =* and !* and return appropriately
74          */
75         if (check->op == T_OP_CMP_TRUE)  return 0;
76         if (check->op == T_OP_CMP_FALSE) return 1;
77
78 #ifdef HAVE_REGEX_H
79         if (check->op == T_OP_REG_EQ) {
80                 int compare;
81                 regex_t reg;
82                 char value[1024];
83                 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
84
85                 vp_prints_value(value, sizeof(value), vp, -1);
86
87                 /*
88                  *      Include substring matches.
89                  */
90                 compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
91                 if (compare != 0) {
92                         char buffer[256];
93                         regerror(compare, &reg, buffer, sizeof(buffer));
94
95                         RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
96                         return -2;
97                 }
98
99                 memset(&rxmatch, 0, sizeof(rxmatch));   /* regexec does not seem to initialise unused elements */
100                 compare = regexec(&reg, value, REQUEST_MAX_REGEX + 1, rxmatch, 0);
101                 regfree(&reg);
102                 rad_regcapture(request, compare, value, rxmatch);
103
104                 ret = (compare == 0) ? 0 : -1;
105                 goto finish;
106         }
107
108         if (check->op == T_OP_REG_NE) {
109                 int compare;
110                 regex_t reg;
111                 char value[1024];
112                 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
113
114                 vp_prints_value(value, sizeof(value), vp, -1);
115
116                 /*
117                  *      Include substring matches.
118                  */
119                 compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
120                 if (compare != 0) {
121                         char buffer[256];
122                         regerror(compare, &reg, buffer, sizeof(buffer));
123
124                         RDEBUG("Invalid regular expression %s: %s", check->vp_strvalue, buffer);
125                         return -2;
126                 }
127                 compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1, rxmatch, 0);
128                 regfree(&reg);
129
130                 ret = (compare != 0) ? 0 : -1;
131         }
132 #endif
133
134         /*
135          *      Attributes must be of the same type.
136          *
137          *      FIXME: deal with type mismatch properly if one side contain
138          *      ABINARY, OCTETS or STRING by converting the other side to
139          *      a string
140          *
141          */
142         if (vp->da->type != check->da->type) return -1;
143
144         /*
145          *      Tagged attributes are equal if and only if both the
146          *      tag AND value match.
147          */
148         if (check->da->flags.has_tag) {
149                 ret = ((int) vp->tag) - ((int) check->tag);
150                 goto finish;
151         }
152
153         /*
154          *      Not a regular expression, compare the types.
155          */
156         switch(check->da->type) {
157 #ifdef WITH_ASCEND_BINARY
158                 /*
159                  *      Ascend binary attributes can be treated
160                  *      as opaque objects, I guess...
161                  */
162                 case PW_TYPE_ABINARY:
163 #endif
164                 case PW_TYPE_OCTETS:
165                         if (vp->length != check->length) {
166                                 ret = 1; /* NOT equal */
167                                 break;
168                         }
169                         ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
170                                      vp->length);
171                         break;
172
173                 case PW_TYPE_STRING:
174                         ret = strcmp(vp->vp_strvalue,
175                                      check->vp_strvalue);
176                         break;
177
178                 case PW_TYPE_BYTE:
179                 case PW_TYPE_SHORT:
180                 case PW_TYPE_INTEGER:
181                         ret = vp->vp_integer - check->vp_integer;
182                         break;
183
184                 case PW_TYPE_INTEGER64:
185                         /*
186                          *      Don't want integer overflow!
187                          */
188                         if (vp->vp_integer64 < check->vp_integer64) {
189                                 ret = -1;
190                         } else if (vp->vp_integer64 > check->vp_integer64) {
191                                 ret = +1;
192                         } else {
193                                 ret = 0;
194                         }
195                         break;
196
197                 case PW_TYPE_SIGNED:
198                         if (vp->vp_signed < check->vp_signed) {
199                                 ret = -1;
200                         } else if (vp->vp_signed > check->vp_signed) {
201                                 ret = +1;
202                         } else {
203                                 ret = 0;
204                         }
205                         break;
206
207                 case PW_TYPE_DATE:
208                         ret = vp->vp_date - check->vp_date;
209                         break;
210
211                 case PW_TYPE_IPADDR:
212                         ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
213                         break;
214
215                 case PW_TYPE_IPV6ADDR:
216                         ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
217                                      sizeof(vp->vp_ipv6addr));
218                         break;
219
220                 case PW_TYPE_IPV6PREFIX:
221                         ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
222                                      sizeof(vp->vp_ipv6prefix));
223                         break;
224
225                 case PW_TYPE_IFID:
226                         ret = memcmp(&vp->vp_ifid, &check->vp_ifid,
227                                      sizeof(vp->vp_ifid));
228                         break;
229
230                 default:
231                         break;
232         }
233
234         finish:
235         if (ret > 0) {
236                 return 1;
237         }
238         if (ret < 0) {
239                 return -1;
240         }
241         return 0;
242 }
243
244
245 /** Compare check and vp. May call the attribute comparison function.
246  *
247  * Unlike radius_compare_vps() this function will call any attribute-specific
248  * comparison functions registered.
249  *
250  * @param request Current request.
251  * @param req list pairs.
252  * @param check item to compare.
253  * @param check_pairs list.
254  * @param reply_pairs list.
255  * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
256  *      value.
257  */
258 int radius_callback_compare(REQUEST *request, VALUE_PAIR *req,
259                             VALUE_PAIR *check, VALUE_PAIR *check_pairs,
260                             VALUE_PAIR **reply_pairs)
261 {
262         struct cmp *c;
263
264         /*
265          *      Check for =* and !* and return appropriately
266          */
267         if (check->op == T_OP_CMP_TRUE)  return 0;
268         if (check->op == T_OP_CMP_FALSE) return 1;
269
270         /*
271          *      See if there is a special compare function.
272          *
273          *      FIXME: use new RB-Tree code.
274          */
275         for (c = cmp; c; c = c->next) {
276                 if (c->da == check->da) {
277                         return (c->compare)(c->instance, request, req, check,
278                                 check_pairs, reply_pairs);
279                 }
280         }
281
282         if (!req) return -1; /* doesn't exist, don't compare it */
283
284         return radius_compare_vps(request, check, req);
285 }
286
287
288 /** Find a comparison function for two attributes.
289  *
290  * @todo this should probably take DA's.
291  * @param da to find comparison function for.
292  * @return true if a comparison function was found, else false.
293  */
294 int radius_find_compare(DICT_ATTR const *da)
295 {
296         struct cmp *c;
297
298         for (c = cmp; c; c = c->next) {
299                 if (c->da == da) {
300                         return true;
301                 }
302         }
303
304         return false;
305 }
306
307
308 /** See what attribute we want to compare with.
309  *
310  * @param da to find comparison function for.
311  * @param from reference to compare with
312  * @return true if the comparison callback require a matching attribue in the request, else false.
313  */
314 static bool otherattr(DICT_ATTR const *da, DICT_ATTR const **from)
315 {
316         struct cmp *c;
317
318         for (c = cmp; c; c = c->next) {
319                 if (c->da == da) {
320                         *from = c->from;
321                         return c->first_only;
322                 }
323         }
324
325         *from = da;
326         return false;
327 }
328
329 /** Register a function as compare function.
330  *
331  * @param da to register comparison function for.
332  * @param from the attribute we want to compare with. Normally this is the same as attribute.
333  *  If null call the comparison function on every attributes in the request if first_only is false
334  * @param first_only will decide if we loop over the request attributes or stop on the first one
335  * @param func comparison function
336  * @param instance argument to comparison function
337  * @return 0
338  */
339 int paircompare_register(DICT_ATTR const *da, DICT_ATTR const *from,
340                          bool first_only, RAD_COMPARE_FUNC func, void *instance)
341 {
342         struct cmp *c;
343
344         rad_assert(da != NULL);
345
346         paircompare_unregister(da, func);
347
348         c = rad_malloc(sizeof(struct cmp));
349
350         c->compare   = func;
351         c->da = da;
352         c->from = from;
353         c->first_only = first_only;
354         c->instance  = instance;
355         c->next      = cmp;
356         cmp = c;
357
358         return 0;
359 }
360
361 /** Unregister comparison function for an attribute
362  *
363  * @param da dict reference to unregister for.
364  * @param func comparison function to remove.
365  */
366 void paircompare_unregister(DICT_ATTR const *da, RAD_COMPARE_FUNC func)
367 {
368         struct cmp *c, *last;
369
370         last = NULL;
371         for (c = cmp; c; c = c->next) {
372                 if (c->da == da && c->compare == func) {
373                         break;
374                 }
375                 last = c;
376         }
377
378         if (c == NULL) return;
379
380         if (last != NULL) {
381                 last->next = c->next;
382         } else {
383                 cmp = c->next;
384         }
385
386         free(c);
387 }
388
389 /** Unregister comparison function for a module
390  *
391  *  All paircompare() functions for this module will be unregistered.
392  *
393  * @param instance the module instance
394  */
395 void paircompare_unregister_instance(void *instance)
396 {
397         struct cmp *c, **tail;
398
399         tail = &cmp;
400         while ((c = *tail) != NULL) {
401                 if (c->instance == instance) {
402                         *tail = c->next;
403                         free(c);
404                         continue;
405                 }
406
407                 tail = &(c->next);
408         }
409 }
410
411 /** Compare two pair lists except for the password information.
412  *
413  * For every element in "check" at least one matching copy must be present
414  * in "reply".
415  *
416  * @param[in] request Current request.
417  * @param[in] req_list request valuepairs.
418  * @param[in] check Check/control valuepairs.
419  * @param[in,out] rep_list Reply value pairs.
420  *
421  * @return 0 on match.
422  */
423 int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
424                 VALUE_PAIR **rep_list)
425 {
426         vp_cursor_t cursor;
427         VALUE_PAIR *check_item;
428         VALUE_PAIR *auth_item;
429         DICT_ATTR const *from;
430
431         int result = 0;
432         int compare;
433         bool first_only;
434
435         for (check_item = paircursor(&cursor, &check);
436              check_item;
437              check_item = pairnext(&cursor)) {
438                 /*
439                  *      If the user is setting a configuration value,
440                  *      then don't bother comparing it to any attributes
441                  *      sent to us by the user.  It ALWAYS matches.
442                  */
443                 if ((check_item->op == T_OP_SET) ||
444                     (check_item->op == T_OP_ADD)) {
445                         continue;
446                 }
447
448                 if (!check_item->da->vendor) switch (check_item->da->attr) {
449                         /*
450                          *      Attributes we skip during comparison.
451                          *      These are "server" check items.
452                          */
453                         case PW_CRYPT_PASSWORD:
454                         case PW_AUTH_TYPE:
455                         case PW_AUTZ_TYPE:
456                         case PW_ACCT_TYPE:
457                         case PW_SESSION_TYPE:
458                         case PW_STRIP_USER_NAME:
459                                 continue;
460                                 break;
461
462                         /*
463                          *      IF the password attribute exists, THEN
464                          *      we can do comparisons against it.  If not,
465                          *      then the request did NOT contain a
466                          *      User-Password attribute, so we CANNOT do
467                          *      comparisons against it.
468                          *
469                          *      This hack makes CHAP-Password work..
470                          */
471                         case PW_USER_PASSWORD:
472                                 if (check_item->op == T_OP_CMP_EQ) {
473                                         WDEBUG("Found User-Password == \"...\".");
474                                         WDEBUG("Are you sure you don't mean Cleartext-Password?");
475                                         WDEBUG("See \"man rlm_pap\" for more information.");
476                                 }
477                                 if (pairfind(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
478                                         continue;
479                                 }
480                                 break;
481                 }
482
483                 /*
484                  *      See if this item is present in the request.
485                  */
486                 first_only = otherattr(check_item->da, &from);
487
488                 auth_item = req_list;
489         try_again:
490                 if (!first_only) {
491                         while (auth_item != NULL) {
492                                 if ((auth_item->da == from) || (!from)) {
493                                         break;
494                                 }
495                                 auth_item = auth_item->next;
496                         }
497                 }
498
499                 /*
500                  *      Not found, it's not a match.
501                  */
502                 if (auth_item == NULL) {
503                         /*
504                          *      Didn't find it.  If we were *trying*
505                          *      to not find it, then we succeeded.
506                          */
507                         if (check_item->op == T_OP_CMP_FALSE) {
508                                 continue;
509                         } else {
510                                 return -1;
511                         }
512                 }
513
514                 /*
515                  *      Else we found it, but we were trying to not
516                  *      find it, so we failed.
517                  */
518                 if (check_item->op == T_OP_CMP_FALSE) {
519                         return -1;
520                 }
521
522
523                 /*
524                  *      We've got to xlat the string before doing
525                  *      the comparison.
526                  */
527                 radius_xlat_do(request, check_item);
528
529                 /*
530                  *      OK it is present now compare them.
531                  */
532                 compare = radius_callback_compare(request, auth_item,
533                                                   check_item, check, rep_list);
534
535                 switch (check_item->op) {
536                         case T_OP_EQ:
537                         default:
538                                 INFO("Invalid operator for item %s: "
539                                        "reverting to '=='", check_item->da->name);
540                                 /* FALL-THROUGH */
541                         case T_OP_CMP_TRUE:
542                         case T_OP_CMP_FALSE:
543                         case T_OP_CMP_EQ:
544                                 if (compare != 0) result = -1;
545                                 break;
546
547                         case T_OP_NE:
548                                 if (compare == 0) result = -1;
549                                 break;
550
551                         case T_OP_LT:
552                                 if (compare >= 0) result = -1;
553                                 break;
554
555                         case T_OP_GT:
556                                 if (compare <= 0) result = -1;
557                                 break;
558
559                         case T_OP_LE:
560                                 if (compare > 0) result = -1;
561                                 break;
562
563                         case T_OP_GE:
564                                 if (compare < 0) result = -1;
565                                 break;
566
567 #ifdef HAVE_REGEX_H
568                         case T_OP_REG_EQ:
569                         case T_OP_REG_NE:
570                                 if (compare != 0) result = -1;
571                                 break;
572 #endif
573                 } /* switch over the operator of the check item */
574
575                 /*
576                  *      This attribute didn't match, but maybe there's
577                  *      another of the same attribute, which DOES match.
578                  */
579                 if ((result != 0) && (!first_only)) {
580                         auth_item = auth_item->next;
581                         result = 0;
582                         goto try_again;
583                 }
584
585         } /* for every entry in the check item list */
586
587         return result;
588 }
589
590 /** Expands an attribute marked with pairmark_xlat
591  *
592  * Writes the new value to the vp.
593  *
594  * @param request Current request.
595  * @param vp to expand.
596  * @return 0 if successful else -1 (on xlat failure) or -2 (on parse failure).
597  *      On failure pair will still no longer be marked for xlat expansion.
598  */
599 int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
600 {
601         ssize_t len;
602
603         char buffer[1024];
604
605         if (vp->type != VT_XLAT) return 0;
606
607         vp->type = VT_DATA;
608
609         len = radius_xlat(buffer, sizeof(buffer), request, vp->value.xlat, NULL, NULL);
610
611
612         rad_const_free(vp->value.xlat);
613         vp->value.xlat = NULL;
614         if (len < 0) {
615                 return -1;
616         }
617
618         /*
619          *      Parse the string into a new value.
620          */
621         if (!pairparsevalue(vp, buffer)){
622                 return -2;
623         }
624
625         return 0;
626 }
627
628 /** Move pairs, replacing/over-writing them, and doing xlat.
629  *
630  * Move attributes from one list to the other if not already present.
631  */
632 void radius_xlat_move(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR **from)
633 {
634         VALUE_PAIR **tailto, *i, *j, *next;
635         VALUE_PAIR *tailfrom = NULL;
636         VALUE_PAIR *found;
637
638         /*
639          *      Point "tailto" to the end of the "to" list.
640          */
641         tailto = to;
642         for (i = *to; i; i = i->next) {
643                 tailto = &i->next;
644         }
645
646         /*
647          *      Loop over the "from" list.
648          */
649         for (i = *from; i; i = next) {
650                 next = i->next;
651
652                 /*
653                  *      Don't move 'fallthrough' over.
654                  */
655                 if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
656                         tailfrom = i;
657                         continue;
658                 }
659
660                 /*
661                  *      We've got to xlat the string before moving
662                  *      it over.
663                  */
664                 radius_xlat_do(request, i);
665
666                 found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
667                 switch (i->op) {
668
669                         /*
670                          *      If a similar attribute is found,
671                          *      delete it.
672                          */
673                         case T_OP_SUB:          /* -= */
674                                 if (found) {
675                                         if (!i->vp_strvalue[0] ||
676                                             (strcmp(found->vp_strvalue,
677                                                     i->vp_strvalue) == 0)) {
678                                                 pairdelete(to, found->da->attr,
679                                                         found->da->vendor,
680                                                         found->tag);
681
682                                         /*
683                                          *      'tailto' may have been
684                                          *      deleted...
685                                          */
686                                         tailto = to;
687                                         for (j = *to; j; j = j->next) {
688                                                 tailto = &j->next;
689                                         }
690                                 }
691                         }
692                         tailfrom = i;
693                         continue;
694                         break;
695
696                         /*
697                          *      Add it, if it's not already there.
698                          */
699                         case T_OP_EQ:           /* = */
700                                 if (found) {
701                                         tailfrom = i;
702                                         continue; /* with the loop */
703                                 }
704                                 break;
705
706                         /*
707                          *      If a similar attribute is found,
708                          *      replace it with the new one.  Otherwise,
709                          *      add the new one to the list.
710                          */
711                         case T_OP_SET:          /* := */
712                                 if (found) {
713                                         VALUE_PAIR *vp;
714
715                                         vp = found->next;
716                                         memcpy(found, i, sizeof(*found));
717                                         found->next = vp;
718                                         tailfrom = i;
719                                         continue;
720                                 }
721                                 break;
722
723                         /*
724                          *      FIXME: Add support for <=, >=, <, >
725                          *
726                          *      which will mean (for integers)
727                          *      'make the attribute the smaller, etc'
728                          */
729
730                         /*
731                          *  Add the new element to the list, even
732                          *  if similar ones already exist.
733                          */
734                         default:
735                         case T_OP_ADD:          /* += */
736                                 break;
737                 }
738
739                 if (tailfrom) {
740                         tailfrom->next = next;
741                 } else {
742                         *from = next;
743                 }
744
745                 /*
746                  *      If ALL of the 'to' attributes have been deleted,
747                  *      then ensure that the 'tail' is updated to point
748                  *      to the head.
749                  */
750                 if (!*to) {
751                         tailto = to;
752                 }
753                 *tailto = i;
754                 if (i) {
755                         i->next = NULL;
756                         tailto = &i->next;
757                 }
758         } /* loop over the 'from' list */
759 }
760
761 /** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
762  *
763  * @note This function ALWAYS returns. If we're OOM, then it causes the
764  * @note server to exit, so you don't need to check the return value.
765  *
766  * @param[in] request Current request.
767  * @param[out] vps List to add new VALUE_PAIR to, if NULL will just
768  *      return VALUE_PAIR.
769  * @param[in] attribute number.
770  * @param[in] vendor number.
771  * @return a new VLAUE_PAIR or causes server to exit on error.
772  */
773 VALUE_PAIR *radius_paircreate(REQUEST *request, VALUE_PAIR **vps,
774                               unsigned int attribute, unsigned int vendor)
775 {
776         VALUE_PAIR *vp;
777
778         /*
779          *      FIXME: the context should ideally be the packet...
780          */
781         vp = paircreate(request, attribute, vendor);
782         if (!vp) {
783                 ERROR("No memory!");
784                 rad_assert("No memory" == NULL);
785                 fr_exit_now(1);
786         }
787
788         if (vps) pairadd(vps, vp);
789
790         return vp;
791 }
792
793 /** Print a single valuepair to stderr or error log.
794  *
795  * @param[in] vp list to print.
796  */
797 void debug_pair(VALUE_PAIR *vp)
798 {
799         if (!vp || !debug_flag || !fr_log_fp) return;
800
801         vp_print(fr_log_fp, vp);
802 }
803
804 /** Print a list of valuepairs to stderr or error log.
805  *
806  * @param[in] vp to print.
807  */
808 void debug_pair_list(VALUE_PAIR *vp)
809 {
810         vp_cursor_t cursor;
811         if (!vp || !debug_flag || !fr_log_fp) return;
812
813         for (vp = paircursor(&cursor, &vp);
814              vp;
815              vp = pairnext(&cursor)) {
816                 /*
817                  *      Take this opportunity to verify all the VALUE_PAIRs are still valid.
818                  */
819                 if (!talloc_get_type(vp, VALUE_PAIR)) {
820                         ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
821
822                         log_talloc_report(vp);
823                         rad_assert(0);
824                 }
825
826                 vp_print(fr_log_fp, vp);
827         }
828         fflush(fr_log_fp);
829 }
830
831 /** Print a list of valuepairs to the request list.
832  *
833  * @param[in] level Debug level (1-4).
834  * @param[in] request to read logging params from.
835  * @param[in] vp to print.
836  */
837 void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp)
838 {
839         vp_cursor_t cursor;
840         char buffer[256];
841         if (!vp || !request || !request->radlog) return;
842
843         for (vp = paircursor(&cursor, &vp);
844              vp;
845              vp = pairnext(&cursor)) {
846                 /*
847                  *      Take this opportunity to verify all the VALUE_PAIRs are still valid.
848                  */
849                 if (!talloc_get_type(vp, VALUE_PAIR)) {
850                         REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
851
852                         log_talloc_report(vp);
853                         rad_assert(0);
854                 }
855
856                 vp_prints(buffer, sizeof(buffer), vp);
857
858                 request->radlog(L_DBG, level, request, "\t%s", buffer);
859         }
860 }
861
862 /** Resolve attribute pair_lists_t value to an attribute list.
863  *
864  * The value returned is a pointer to the pointer of the HEAD of the list
865  * in the REQUEST. If the head of the list changes, the pointer will still
866  * be valid.
867  *
868  * @param[in] request containing the target lists.
869  * @param[in] list pair_list_t value to resolve to VALUE_PAIR list.
870  *      Will be NULL if list name couldn't be resolved.
871  */
872 VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
873 {
874         if (!request) return NULL;
875
876         switch (list) {
877                 case PAIR_LIST_UNKNOWN:
878                 default:
879                         break;
880
881                 case PAIR_LIST_REQUEST:
882                         return &request->packet->vps;
883
884                 case PAIR_LIST_REPLY:
885                         return &request->reply->vps;
886
887                 case PAIR_LIST_CONTROL:
888                         return &request->config_items;
889
890 #ifdef WITH_PROXY
891                 case PAIR_LIST_PROXY_REQUEST:
892                         if (!request->proxy) break;
893                         return &request->proxy->vps;
894
895                 case PAIR_LIST_PROXY_REPLY:
896                         if (!request->proxy) break;
897                         return &request->proxy_reply->vps;
898 #endif
899 #ifdef WITH_COA
900                 case PAIR_LIST_COA:
901                         if (request->coa &&
902                             (request->coa->proxy->code == PW_COA_REQUEST)) {
903                                 return &request->coa->proxy->vps;
904                         }
905                         break;
906
907                 case PAIR_LIST_COA_REPLY:
908                         if (request->coa && /* match reply with request */
909                             (request->coa->proxy->code == PW_COA_REQUEST) &&
910                             request->coa->proxy_reply) {
911                                 return &request->coa->proxy_reply->vps;
912                         }
913                         break;
914
915                 case PAIR_LIST_DM:
916                         if (request->coa &&
917                             (request->coa->proxy->code == PW_DISCONNECT_REQUEST)) {
918                                 return &request->coa->proxy->vps;
919                         }
920                         break;
921
922                 case PAIR_LIST_DM_REPLY:
923                         if (request->coa && /* match reply with request */
924                             (request->coa->proxy->code == PW_DISCONNECT_REQUEST) &&
925                             request->coa->proxy_reply) {
926                                 return &request->coa->proxy->vps;
927                         }
928                         break;
929 #endif
930         }
931
932         RWDEBUG2("List \"%s\" is not available",
933                 fr_int2str(pair_lists, list, "<INVALID>"));
934
935         return NULL;
936 }
937
938 /** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
939  *
940  * Takes a single value_pair_map_t, resolves request and list identifiers
941  * to pointers in the current request, then attempts to retrieve module
942  * specific value(s) using callback, and adds the resulting values to the
943  * correct request/list.
944  *
945  * @param request The current request.
946  * @param map specifying destination attribute and location and src identifier.
947  * @param func to retrieve module specific values and convert them to
948  *      VALUE_PAIRS.
949  * @param ctx to be passed to func.
950  * @param src name to be used in debugging if different from map value.
951  * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
952  */
953 int radius_map2request(REQUEST *request, value_pair_map_t const *map,
954                        UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
955 {
956         int rcode;
957         vp_cursor_t cursor;
958         VALUE_PAIR **list, *vp, *head = NULL;
959         char buffer[1024];
960
961         if (radius_request(&request, map->dst->request) < 0) {
962                 REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
963
964                 return -2;
965         }
966
967         list = radius_list(request, map->dst->list);
968         if (!list) {
969                 REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
970
971                 return -2;
972         }
973
974
975         /*
976          *      The callback should either return -1 to signify operations error, -2 when it can't find the
977          *      attribute or list being referenced, or 0 to signify success.
978          *      It may return "sucess", but still have no VPs to work with.
979          *      Only if it returned an error code should it not write anything to the head pointer.
980          */
981         rcode = func(&head, request, map, ctx);
982         if (rcode < 0) {
983                 rad_assert(!head);
984
985                 return rcode;
986         }
987
988         if (!head) return 0;
989
990         VERIFY_VP(head);
991
992         if (debug_flag) for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) {
993                 char *value;
994
995                 switch (map->src->type) {
996                         /*
997                          *      Just print the value being assigned
998                          */
999                         default:
1000
1001                         case VPT_TYPE_LITERAL:
1002                                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
1003                                 value = buffer;
1004                                 break;
1005                         case VPT_TYPE_XLAT:
1006                                 vp_prints_value(buffer, sizeof(buffer), vp, '"');
1007                                 value = buffer;
1008                                 break;
1009                         case VPT_TYPE_DATA:
1010                                 vp_prints_value(buffer, sizeof(buffer), vp, 0);
1011                                 value = buffer;
1012                                 break;
1013                         /*
1014                          *      Just printing the value doesn't make sense, but we still
1015                          *      want to know what it was...
1016                          */
1017                         case VPT_TYPE_LIST:
1018                                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
1019                                 value = talloc_asprintf(request, "&%s%s -> %s", map->src->name, vp->da->name, buffer);
1020                                 break;
1021                         case VPT_TYPE_ATTR:
1022                                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
1023                                 value = talloc_asprintf(request, "&%s -> %s", map->src->name, buffer);
1024                                 break;
1025                 }
1026
1027
1028                 RDEBUG("\t\t%s %s %s", map->dst->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), value);
1029
1030                 if (value != buffer) talloc_free(value);
1031         }
1032
1033         /*
1034          *      Use pairmove so the operator is respected
1035          */
1036         radius_pairmove(request, list, head);
1037         return 0;
1038 }
1039
1040 /** Process map which has exec as a src
1041  *
1042  * Evaluate maps which specify exec as a src. This may be used by various sorts of update sections, and so
1043  * has been broken out into it's own function.
1044  *
1045  * @param[out] out Where to write the VALUE_PAIR(s).
1046  * @param[in] request structure (used only for talloc).
1047  * @param[in] map the map. The LHS (dst) must be VPT_TYPE_ATTR or VPT_TYPE_LIST. The RHS (src) must be VPT_TYPE_EXEC.
1048  * @return -1 on failure, 0 on success.
1049  */
1050 int radius_mapexec(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map)
1051 {
1052         int result;
1053         char *expanded = NULL;
1054         char answer[1024];
1055         VALUE_PAIR **input_pairs = NULL;
1056         VALUE_PAIR **output_pairs = NULL;
1057
1058         *out = NULL;
1059
1060         rad_assert(map->src->type == VPT_TYPE_EXEC);
1061         rad_assert((map->dst->type == VPT_TYPE_ATTR) || (map->dst->type == VPT_TYPE_LIST));
1062
1063         /*
1064          *      We always put the request pairs into the environment
1065          */
1066         input_pairs = radius_list(request, PAIR_LIST_REQUEST);
1067
1068         /*
1069          *      Automagically switch output type depending on our destination
1070          *      If dst is a list, then we create attributes from the output of the program
1071          *      if dst is an attribute, then we create an attribute of that type and then
1072          *      call pairparsevalue on the output of the script.
1073          */
1074         out[0] = '\0';
1075         result = radius_exec_program(request, map->src->name, true, true,
1076                                      answer, sizeof(answer), EXEC_TIMEOUT,
1077                                      input_pairs ? *input_pairs : NULL,
1078                                      (map->dst->type == VPT_TYPE_LIST) ? output_pairs : NULL);
1079         talloc_free(expanded);
1080         if (result != 0) {
1081                 REDEBUG("%s", answer);
1082                 talloc_free(output_pairs);
1083                 return -1;
1084         }
1085
1086         switch (map->dst->type) {
1087         case VPT_TYPE_LIST:
1088                 if (!output_pairs) {
1089                         return -2;
1090                 }
1091                 *out = *output_pairs;
1092
1093                 return 0;
1094         case VPT_TYPE_ATTR:
1095                 {
1096                         VALUE_PAIR *vp;
1097
1098                         vp = pairalloc(request, map->dst->da);
1099                         if (!vp) return -1;
1100                         vp->op = map->op;
1101                         if (!pairparsevalue(vp, answer)) {
1102                                 pairfree(&vp);
1103                                 return -2;
1104                         }
1105                         *out = vp;
1106
1107                         return 0;
1108                 }
1109         default:
1110                 rad_assert(0);
1111         }
1112
1113         return -1;
1114 }
1115
1116 /** Convert a map to a VALUE_PAIR.
1117  *
1118  * @param[out] out Where to write the VALUE_PAIR(s).
1119  * @param[in] request structure (used only for talloc)
1120  * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
1121  * @param[in] ctx unused
1122  * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent
1123  */
1124 int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx)
1125 {
1126         int rcode = 0;
1127         VALUE_PAIR *vp = NULL, *found, **from = NULL;
1128         DICT_ATTR const *da;
1129         REQUEST *context;
1130         vp_cursor_t cursor;
1131
1132         rad_assert(request != NULL);
1133         rad_assert(map != NULL);
1134
1135         *out = NULL;
1136
1137         /*
1138          *      Special case for !*, we don't need to parse the value, just allocate an attribute with
1139          *      the right operator.
1140          */
1141         if (map->op == T_OP_CMP_FALSE) {
1142                 vp = pairalloc(request, map->dst->da);
1143                 if (!vp) return -1;
1144                 vp->op = map->op;
1145                 *out = vp;
1146
1147                 return 0;
1148         }
1149
1150         /*
1151          *      List to list found, this is a special case because we don't need
1152          *      to allocate any attributes, just found the current list, and change
1153          *      the op.
1154          */
1155         if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
1156                 from = radius_list(request, map->src->list);
1157                 if (!from) return -2;
1158
1159                 found = paircopy(request, *from);
1160                 /*
1161                  *      List to list copy is invalid if the src list has no attributes.
1162                  */
1163                 if (!found) return -2;
1164
1165                 for (vp = paircursor(&cursor, &found);
1166                      vp;
1167                      vp = pairnext(&cursor)) {
1168                         vp->op = T_OP_ADD;
1169                 }
1170
1171                 *out = found;
1172
1173                 return 0;
1174         }
1175
1176         /*
1177          *      Deal with all non-list founding operations.
1178          */
1179         da = map->dst->da ? map->dst->da : map->src->da;
1180
1181         switch (map->src->type) {
1182         case VPT_TYPE_XLAT:
1183         case VPT_TYPE_LITERAL:
1184         case VPT_TYPE_DATA:
1185                 vp = pairalloc(request, da);
1186                 if (!vp) return -1;
1187                 vp->op = map->op;
1188                 break;
1189         default:
1190                 break;
1191         }
1192
1193
1194         /*
1195          *      And parse the RHS
1196          */
1197         switch (map->src->type) {
1198         case VPT_TYPE_XLAT:
1199                 rad_assert(map->dst->da);       /* Need to know where were going to write the new attribute */
1200                 /*
1201                  *      Don't call unnecessary expansions
1202                  */
1203                 if (strchr(map->src->name, '%') != NULL) {
1204                         ssize_t slen;
1205                         char *str = NULL;
1206
1207                         slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
1208                         if (slen < 0) {
1209                                 rcode = slen;
1210                                 goto error;
1211                         }
1212                         rcode = pairparsevalue(vp, str);
1213                         talloc_free(str);
1214                         if (!rcode) {
1215                                 pairfree(&vp);
1216                                 rcode = -1;
1217                                 goto error;
1218                         }
1219
1220                         break;
1221                 }
1222                 /* FALL-THROUGH */
1223
1224         case VPT_TYPE_LITERAL:
1225                 if (!pairparsevalue(vp, map->src->name)) {
1226                         rcode = -2;
1227                         goto error;
1228                 }
1229                 break;
1230
1231         case VPT_TYPE_ATTR:
1232                 rad_assert(!map->dst->da ||
1233                            (map->src->da->type == map->dst->da->type) ||
1234                            (map->src->da->type == PW_TYPE_OCTETS) ||
1235                            (map->dst->da->type == PW_TYPE_OCTETS));
1236                 context = request;
1237
1238                 if (radius_request(&context, map->src->request) == 0) {
1239                         from = radius_list(context, map->src->list);
1240                 }
1241
1242                 /*
1243                  *      Can't add the attribute if the list isn't
1244                  *      valid.
1245                  */
1246                 if (!from) {
1247                         rcode = -2;
1248                         goto error;
1249                 }
1250
1251                 /*
1252                  *      Special case, destination is a list, found all instance of an attribute.
1253                  */
1254                 if (map->dst->type == VPT_TYPE_LIST) {
1255                         found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
1256                         if (!found) {
1257                                 REDEBUG("Attribute \"%s\" not found in request", map->src->name);
1258                                 rcode = -2;
1259                                 goto error;
1260                         }
1261
1262                         for (vp = paircursor(&cursor, &found);
1263                              vp;
1264                              vp = pairnext(&cursor)) {
1265                                 vp->op = T_OP_ADD;
1266                         }
1267
1268                         *out = found;
1269                         return 0;
1270                 }
1271
1272                 /*
1273                  *      FIXME: allow tag references?
1274                  */
1275                 found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
1276                 if (!found) {
1277                         REDEBUG("Attribute \"%s\" not found in request", map->src->name);
1278                         rcode = -2;
1279                         goto error;
1280                 }
1281
1282                 /*
1283                  *      Copy the data over verbatim, assuming it's
1284                  *      actually data.
1285                  */
1286 //              rad_assert(found->type == VT_DATA);
1287                 vp = paircopyvpdata(request, da, found);
1288                 if (!vp) {
1289                         return -1;
1290                 }
1291                 vp->op = map->op;
1292
1293                 break;
1294
1295         case VPT_TYPE_DATA:
1296                 rad_assert(map->src->da->type == map->dst->da->type);
1297                 memcpy(&vp->data, map->src->vpd, sizeof(vp->data));
1298                 vp->length = map->src->length;
1299                 break;
1300
1301         /*
1302          *      This essentially does the same as rlm_exec xlat, except it's non-configurable.
1303          *      It's only really here as a convenience for people who expect the contents of
1304          *      backticks to be executed in a shell.
1305          *
1306          *      exec string is xlat expanded and arguments are shell escaped.
1307          */
1308         case VPT_TYPE_EXEC:
1309                 return radius_mapexec(out, request, map);
1310         default:
1311                 rad_assert(0);  /* Should of been caught at parse time */
1312         error:
1313                 pairfree(&vp);
1314                 return rcode;
1315         }
1316
1317         *out = vp;
1318         return 0;
1319 }
1320
1321
1322 /** Convert a valuepair string to VALUE_PAIR and insert it into a list
1323  *
1324  * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
1325  * and inserts it into the appropriate list.
1326  *
1327  * @param request Current request.
1328  * @param raw string to parse.
1329  * @param request_def to use if attribute isn't qualified.
1330  * @param list_def to use if attribute isn't qualified.
1331  * @return 0 on success, -1 on error.
1332  */
1333 int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def)
1334 {
1335         char const *p;
1336         size_t len;
1337         request_refs_t req;
1338         pair_lists_t list;
1339
1340         VALUE_PAIR *vp = NULL;
1341         VALUE_PAIR **vps;
1342
1343         p = raw;
1344
1345         req = radius_request_name(&p, request_def);
1346         len = p - raw;
1347         if (req == REQUEST_UNKNOWN) {
1348                 REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw);
1349
1350                 return -1;
1351         }
1352         raw += len;
1353
1354         list = radius_list_name(&p, list_def);
1355         if (list == PAIR_LIST_UNKNOWN) {
1356                 len = p - raw;
1357
1358                 REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw);
1359
1360                 return -1;
1361         }
1362         raw += len;
1363
1364         if (radius_request(&request, req) < 0) {
1365                 return -1;
1366         }
1367
1368         vps = radius_list(request, list);
1369         if (!vps) {
1370                 return -1;
1371         }
1372
1373         if (userparse(request, raw, &vp) == T_OP_INVALID) {
1374                 return -1;
1375         }
1376
1377         pairmove(request, vps, &vp);
1378
1379         return 0;
1380 }
1381
1382
1383 /** Return a VP from a value_pair_tmpl_t
1384  *
1385  * @param request current request.
1386  * @param vpt the value pair template
1387  * @return NULL if not found, or the VPs.
1388  */
1389 VALUE_PAIR *radius_vpt_get_vp(REQUEST *request, value_pair_tmpl_t const *vpt)
1390 {
1391         VALUE_PAIR **vps;
1392
1393         if (radius_request(&request, vpt->request) < 0) {
1394                 return NULL;
1395         }
1396
1397         vps = radius_list(request, vpt->list);
1398         if (!vps) {
1399                 return NULL;
1400         }
1401
1402         switch (vpt->type) {
1403         /*
1404          *      May not may not be found, but it *is* a known name.
1405          */
1406         case VPT_TYPE_ATTR:
1407                 return pairfind(*vps, vpt->da->attr, vpt->da->vendor, TAG_ANY);
1408
1409         case VPT_TYPE_LIST:
1410                 return *vps;
1411
1412         default:
1413                 break;
1414         }
1415
1416         return NULL;
1417 }
1418
1419
1420
1421 /** Return a VP from the specified request.
1422  *
1423  * @param request current request.
1424  * @param name attribute name including qualifiers.
1425  * @param vp_p where to write the pointer to the resolved VP.
1426  *      Will be NULL if the attribute couldn't be resolved.
1427  * @return -1 if either the attribute or qualifier were invalid, else 0
1428  */
1429 int radius_get_vp(REQUEST *request, char const *name, VALUE_PAIR **vp_p)
1430 {
1431         value_pair_tmpl_t vpt;
1432
1433         *vp_p = NULL;
1434
1435         if (radius_parse_attr(name, &vpt, REQUEST_CURRENT,
1436             PAIR_LIST_REQUEST) < 0) {
1437                 return -1;
1438         }
1439
1440         *vp_p = radius_vpt_get_vp(request, &vpt);
1441         return 0;
1442 }
1443
1444 /** Add a module failure message VALUE_PAIR to the request
1445  */
1446 void module_failure_msg(REQUEST *request, char const *fmt, ...)
1447 {
1448         va_list ap;
1449         char *p;
1450         VALUE_PAIR *vp;
1451
1452         if (!fmt || !request->packet) {
1453                 va_start(ap, fmt);
1454                 va_end(ap);
1455                 return;
1456         }
1457
1458         va_start(ap, fmt);
1459         vp = paircreate(request->packet, PW_MODULE_FAILURE_MESSAGE, 0);
1460         if (!vp) {
1461                 va_end(ap);
1462                 return;
1463         }
1464
1465         p = talloc_vasprintf(vp, fmt, ap);
1466
1467         if (request->module && *request->module) {
1468                 pairsprintf(vp, "%s: %s", request->module, p);
1469         } else {
1470                 pairsprintf(vp, "%s", p);
1471         }
1472         talloc_free(p);
1473         pairadd(&request->packet->vps, vp);
1474 }