47a40ebd71a4e6608a986d0cfdce0565f31857c7
[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 && !TAG_EQ(check->tag, vp->tag)) {
149                 ret = ((int) vp->tag) - ((int) check->tag);
150                 if (ret != 0) 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_IPV4_ADDR:
212                         ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
213                         break;
214
215                 case PW_TYPE_IPV6_ADDR:
216                         ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
217                                      sizeof(vp->vp_ipv6addr));
218                         break;
219
220                 case PW_TYPE_IPV6_PREFIX:
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  * @param da to find comparison function for.
291  * @return true if a comparison function was found, else false.
292  */
293 int radius_find_compare(DICT_ATTR const *da)
294 {
295         struct cmp *c;
296
297         for (c = cmp; c; c = c->next) {
298                 if (c->da == da) {
299                         return true;
300                 }
301         }
302
303         return false;
304 }
305
306
307 /** See what attribute we want to compare with.
308  *
309  * @param da to find comparison function for.
310  * @param from reference to compare with
311  * @return true if the comparison callback require a matching attribue in the request, else false.
312  */
313 static bool otherattr(DICT_ATTR const *da, DICT_ATTR const **from)
314 {
315         struct cmp *c;
316
317         for (c = cmp; c; c = c->next) {
318                 if (c->da == da) {
319                         *from = c->from;
320                         return c->first_only;
321                 }
322         }
323
324         *from = da;
325         return false;
326 }
327
328 /** Register a function as compare function.
329  *
330  * @param da to register comparison function for.
331  * @param from the attribute we want to compare with. Normally this is the same as attribute.
332  *  If null call the comparison function on every attributes in the request if first_only is false
333  * @param first_only will decide if we loop over the request attributes or stop on the first one
334  * @param func comparison function
335  * @param instance argument to comparison function
336  * @return 0
337  */
338 int paircompare_register(DICT_ATTR const *da, DICT_ATTR const *from,
339                          bool first_only, RAD_COMPARE_FUNC func, void *instance)
340 {
341         struct cmp *c;
342
343         rad_assert(da != NULL);
344
345         paircompare_unregister(da, func);
346
347         c = rad_malloc(sizeof(struct cmp));
348
349         c->compare   = func;
350         c->da = da;
351         c->from = from;
352         c->first_only = first_only;
353         c->instance  = instance;
354         c->next      = cmp;
355         cmp = c;
356
357         return 0;
358 }
359
360 /** Unregister comparison function for an attribute
361  *
362  * @param da dict reference to unregister for.
363  * @param func comparison function to remove.
364  */
365 void paircompare_unregister(DICT_ATTR const *da, RAD_COMPARE_FUNC func)
366 {
367         struct cmp *c, *last;
368
369         last = NULL;
370         for (c = cmp; c; c = c->next) {
371                 if (c->da == da && c->compare == func) {
372                         break;
373                 }
374                 last = c;
375         }
376
377         if (c == NULL) return;
378
379         if (last != NULL) {
380                 last->next = c->next;
381         } else {
382                 cmp = c->next;
383         }
384
385         free(c);
386 }
387
388 /** Unregister comparison function for a module
389  *
390  *  All paircompare() functions for this module will be unregistered.
391  *
392  * @param instance the module instance
393  */
394 void paircompare_unregister_instance(void *instance)
395 {
396         struct cmp *c, **tail;
397
398         tail = &cmp;
399         while ((c = *tail) != NULL) {
400                 if (c->instance == instance) {
401                         *tail = c->next;
402                         free(c);
403                         continue;
404                 }
405
406                 tail = &(c->next);
407         }
408 }
409
410 /** Compare two pair lists except for the password information.
411  *
412  * For every element in "check" at least one matching copy must be present
413  * in "reply".
414  *
415  * @param[in] request Current request.
416  * @param[in] req_list request valuepairs.
417  * @param[in] check Check/control valuepairs.
418  * @param[in,out] rep_list Reply value pairs.
419  *
420  * @return 0 on match.
421  */
422 int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
423                 VALUE_PAIR **rep_list)
424 {
425         vp_cursor_t cursor;
426         VALUE_PAIR *check_item;
427         VALUE_PAIR *auth_item;
428         DICT_ATTR const *from;
429
430         int result = 0;
431         int compare;
432         bool first_only;
433
434         for (check_item = fr_cursor_init(&cursor, &check);
435              check_item;
436              check_item = fr_cursor_next(&cursor)) {
437                 /*
438                  *      If the user is setting a configuration value,
439                  *      then don't bother comparing it to any attributes
440                  *      sent to us by the user.  It ALWAYS matches.
441                  */
442                 if ((check_item->op == T_OP_SET) ||
443                     (check_item->op == T_OP_ADD)) {
444                         continue;
445                 }
446
447                 if (!check_item->da->vendor) switch (check_item->da->attr) {
448                 /*
449                  *      Attributes we skip during comparison.
450                  *      These are "server" check items.
451                  */
452                 case PW_CRYPT_PASSWORD:
453                 case PW_AUTH_TYPE:
454                 case PW_AUTZ_TYPE:
455                 case PW_ACCT_TYPE:
456                 case PW_SESSION_TYPE:
457                 case PW_STRIP_USER_NAME:
458                         continue;
459                         break;
460
461                 /*
462                  *      IF the password attribute exists, THEN
463                  *      we can do comparisons against it.  If not,
464                  *      then the request did NOT contain a
465                  *      User-Password attribute, so we CANNOT do
466                  *      comparisons against it.
467                  *
468                  *      This hack makes CHAP-Password work..
469                  */
470                 case PW_USER_PASSWORD:
471                         if (check_item->op == T_OP_CMP_EQ) {
472                                 WARN("Found User-Password == \"...\"");
473                                 WARN("Are you sure you don't mean Cleartext-Password?");
474                                 WARN("See \"man rlm_pap\" for more information");
475                         }
476                         if (pairfind(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
477                                 continue;
478                         }
479                         break;
480                 }
481
482                 /*
483                  *      See if this item is present in the request.
484                  */
485                 first_only = otherattr(check_item->da, &from);
486
487                 auth_item = req_list;
488         try_again:
489                 if (!first_only) {
490                         while (auth_item != NULL) {
491                                 if ((auth_item->da == from) || (!from)) {
492                                         break;
493                                 }
494                                 auth_item = auth_item->next;
495                         }
496                 }
497
498                 /*
499                  *      Not found, it's not a match.
500                  */
501                 if (auth_item == NULL) {
502                         /*
503                          *      Didn't find it.  If we were *trying*
504                          *      to not find it, then we succeeded.
505                          */
506                         if (check_item->op == T_OP_CMP_FALSE) {
507                                 continue;
508                         } else {
509                                 return -1;
510                         }
511                 }
512
513                 /*
514                  *      Else we found it, but we were trying to not
515                  *      find it, so we failed.
516                  */
517                 if (check_item->op == T_OP_CMP_FALSE) {
518                         return -1;
519                 }
520
521
522                 /*
523                  *      We've got to xlat the string before doing
524                  *      the comparison.
525                  */
526                 radius_xlat_do(request, check_item);
527
528                 /*
529                  *      OK it is present now compare them.
530                  */
531                 compare = radius_callback_compare(request, auth_item,
532                                                   check_item, check, rep_list);
533
534                 switch (check_item->op) {
535                 case T_OP_EQ:
536                 default:
537                         RWDEBUG("Invalid operator '%s' for item %s: reverting to '=='",
538                                 fr_int2str(fr_tokens, check_item->op, "<INVALID>"), check_item->da->name);
539                         /* FALL-THROUGH */
540                 case T_OP_CMP_TRUE:
541                 case T_OP_CMP_FALSE:
542                 case T_OP_CMP_EQ:
543                         if (compare != 0) result = -1;
544                         break;
545
546                 case T_OP_NE:
547                         if (compare == 0) result = -1;
548                         break;
549
550                 case T_OP_LT:
551                         if (compare >= 0) result = -1;
552                         break;
553
554                 case T_OP_GT:
555                         if (compare <= 0) result = -1;
556                         break;
557
558                 case T_OP_LE:
559                         if (compare > 0) result = -1;
560                         break;
561
562                 case T_OP_GE:
563                         if (compare < 0) result = -1;
564                         break;
565
566 #ifdef HAVE_REGEX_H
567                 case T_OP_REG_EQ:
568                 case T_OP_REG_NE:
569                         if (compare != 0) result = -1;
570                         break;
571 #endif
572                 } /* switch over the operator of the check item */
573
574                 /*
575                  *      This attribute didn't match, but maybe there's
576                  *      another of the same attribute, which DOES match.
577                  */
578                 if ((result != 0) && (!first_only)) {
579                         auth_item = auth_item->next;
580                         result = 0;
581                         goto try_again;
582                 }
583
584         } /* for every entry in the check item list */
585
586         return result;
587 }
588
589 /** Expands an attribute marked with pairmark_xlat
590  *
591  * Writes the new value to the vp.
592  *
593  * @param request Current request.
594  * @param vp to expand.
595  * @return 0 if successful else -1 (on xlat failure) or -2 (on parse failure).
596  *      On failure pair will still no longer be marked for xlat expansion.
597  */
598 int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
599 {
600         ssize_t len;
601
602         char buffer[1024];
603
604         if (vp->type != VT_XLAT) return 0;
605
606         vp->type = VT_DATA;
607
608         len = radius_xlat(buffer, sizeof(buffer), request, vp->value.xlat, NULL, NULL);
609
610         rad_const_free(vp->value.xlat);
611         vp->value.xlat = NULL;
612         if (len < 0) {
613                 return -1;
614         }
615
616         /*
617          *      Parse the string into a new value.
618          */
619         if (pairparsevalue(vp, buffer, 0) < 0){
620                 return -2;
621         }
622
623         return 0;
624 }
625
626 /** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
627  *
628  * @note This function ALWAYS returns. If we're OOM, then it causes the
629  * @note server to exit, so you don't need to check the return value.
630  *
631  * @param[in] ctx for talloc
632  * @param[out] vps List to add new VALUE_PAIR to, if NULL will just
633  *      return VALUE_PAIR.
634  * @param[in] attribute number.
635  * @param[in] vendor number.
636  * @return a new VLAUE_PAIR or causes server to exit on error.
637  */
638 VALUE_PAIR *radius_paircreate(TALLOC_CTX *ctx, VALUE_PAIR **vps,
639                               unsigned int attribute, unsigned int vendor)
640 {
641         VALUE_PAIR *vp;
642
643         vp = paircreate(ctx, attribute, vendor);
644         if (!vp) {
645                 ERROR("No memory!");
646                 rad_assert("No memory" == NULL);
647                 fr_exit_now(1);
648         }
649
650         if (vps) pairadd(vps, vp);
651
652         return vp;
653 }
654
655 /** Print a single valuepair to stderr or error log.
656  *
657  * @param[in] vp list to print.
658  */
659 void debug_pair(VALUE_PAIR *vp)
660 {
661         if (!vp || !debug_flag || !fr_log_fp) return;
662
663         vp_print(fr_log_fp, vp);
664 }
665
666 /** Print a list of valuepairs to stderr or error log.
667  *
668  * @param[in] vp to print.
669  */
670 void debug_pair_list(VALUE_PAIR *vp)
671 {
672         vp_cursor_t cursor;
673         if (!vp || !debug_flag || !fr_log_fp) return;
674
675         for (vp = fr_cursor_init(&cursor, &vp);
676              vp;
677              vp = fr_cursor_next(&cursor)) {
678                 vp_print(fr_log_fp, vp);
679         }
680         fflush(fr_log_fp);
681 }
682
683 /** Print a list of valuepairs to the request list.
684  *
685  * @param[in] level Debug level (1-4).
686  * @param[in] request to read logging params from.
687  * @param[in] vp to print.
688  */
689 void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp)
690 {
691         vp_cursor_t cursor;
692         char buffer[256];
693         if (!vp || !request || !request->log.func) return;
694
695         for (vp = fr_cursor_init(&cursor, &vp);
696              vp;
697              vp = fr_cursor_next(&cursor)) {
698                 /*
699                  *      Take this opportunity to verify all the VALUE_PAIRs are still valid.
700                  */
701                 if (!talloc_get_type(vp, VALUE_PAIR)) {
702                         REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
703
704                         fr_log_talloc_report(vp);
705                         rad_assert(0);
706                 }
707
708                 vp_prints(buffer, sizeof(buffer), vp);
709                 RDEBUGX(level, "\t%s", buffer);
710         }
711 }
712
713 /** Resolve attribute pair_lists_t value to an attribute list.
714  *
715  * The value returned is a pointer to the pointer of the HEAD of the list
716  * in the REQUEST. If the head of the list changes, the pointer will still
717  * be valid.
718  *
719  * @param[in] request containing the target lists.
720  * @param[in] list pair_list_t value to resolve to VALUE_PAIR list.
721  *      Will be NULL if list name couldn't be resolved.
722  */
723 VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
724 {
725         if (!request) return NULL;
726
727         switch (list) {
728         case PAIR_LIST_UNKNOWN:
729         default:
730                 break;
731
732         case PAIR_LIST_REQUEST:
733                 return &request->packet->vps;
734
735         case PAIR_LIST_REPLY:
736                 return &request->reply->vps;
737
738         case PAIR_LIST_CONTROL:
739                 return &request->config_items;
740
741 #ifdef WITH_PROXY
742         case PAIR_LIST_PROXY_REQUEST:
743                 if (!request->proxy) break;
744                 return &request->proxy->vps;
745
746         case PAIR_LIST_PROXY_REPLY:
747                 if (!request->proxy) break;
748                 return &request->proxy_reply->vps;
749 #endif
750 #ifdef WITH_COA
751         case PAIR_LIST_COA:
752                 if (request->coa &&
753                     (request->coa->proxy->code == PW_CODE_COA_REQUEST)) {
754                         return &request->coa->proxy->vps;
755                 }
756                 break;
757
758         case PAIR_LIST_COA_REPLY:
759                 if (request->coa && /* match reply with request */
760                     (request->coa->proxy->code == PW_CODE_COA_REQUEST) &&
761                     request->coa->proxy_reply) {
762                         return &request->coa->proxy_reply->vps;
763                 }
764                 break;
765
766         case PAIR_LIST_DM:
767                 if (request->coa &&
768                     (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST)) {
769                         return &request->coa->proxy->vps;
770                 }
771                 break;
772
773         case PAIR_LIST_DM_REPLY:
774                 if (request->coa && /* match reply with request */
775                     (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST) &&
776                     request->coa->proxy_reply) {
777                         return &request->coa->proxy->vps;
778                 }
779                 break;
780 #endif
781         }
782
783         RWDEBUG2("List \"%s\" is not available",
784                 fr_int2str(pair_lists, list, "<INVALID>"));
785
786         return NULL;
787 }
788
789
790 TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list_name)
791 {
792         if (!request) return NULL;
793
794                 switch (list_name) {
795                 case PAIR_LIST_REQUEST:
796                         return request->packet;
797
798                 case PAIR_LIST_REPLY:
799                         return request->reply;
800
801                 case PAIR_LIST_CONTROL:
802                         return request;
803
804 #ifdef WITH_PROXY
805                 case PAIR_LIST_PROXY_REQUEST:
806                         return request->proxy;
807
808                 case PAIR_LIST_PROXY_REPLY:
809                         return request->proxy_reply;
810 #endif
811
812 #ifdef WITH_COA
813                 case PAIR_LIST_COA:
814                         if (!request->coa) return NULL;
815                         rad_assert(request->coa->proxy != NULL);
816                         if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
817                         return request->coa->proxy;
818
819                 case PAIR_LIST_COA_REPLY:
820                         if (!request->coa) return NULL;
821                         rad_assert(request->coa->proxy != NULL);
822                         if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
823                         return request->coa->proxy_reply;
824
825                 case PAIR_LIST_DM:
826                         if (!request->coa) return NULL;
827                         rad_assert(request->coa->proxy != NULL);
828                         if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
829                         return request->coa->proxy;
830
831                 case PAIR_LIST_DM_REPLY:
832                         if (!request->coa) return NULL;
833                         rad_assert(request->coa->proxy != NULL);
834                         if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
835                         return request->coa->proxy_reply;
836 #endif
837
838                 default:
839                         break;
840                 }
841
842                 return NULL;
843 }
844
845 /*
846  *      Debug print a map / VP
847  */
848 void radius_map_debug(REQUEST *request, value_pair_map_t const *map, VALUE_PAIR const *vp)
849 {
850         char *value;
851         char buffer[1024];
852
853         rad_assert(vp || (map->src->type == VPT_TYPE_NULL));
854
855         switch (map->src->type) {
856         /*
857          *      Just print the value being assigned
858          */
859         default:
860         case VPT_TYPE_LITERAL:
861                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
862                 value = buffer;
863                 break;
864
865         case VPT_TYPE_XLAT:
866         case VPT_TYPE_XLAT_STRUCT:
867                 vp_prints_value(buffer, sizeof(buffer), vp, '"');
868                 value = buffer;
869                 break;
870
871         case VPT_TYPE_DATA:
872                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
873                 value = buffer;
874                 break;
875
876         /*
877          *      Just printing the value doesn't make sense, but we still
878          *      want to know what it was...
879          */
880         case VPT_TYPE_LIST:
881                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
882
883                 if (map->src->vpt_request == REQUEST_OUTER) {
884                         value = talloc_typed_asprintf(request, "&outer.%s:%s -> %s",
885                                                       fr_int2str(pair_lists, map->src->vpt_list, "<INVALID>"),
886                                                       vp->da->name, buffer);
887                 } else {
888                         value = talloc_typed_asprintf(request, "&%s:%s -> %s",
889                                                       fr_int2str(pair_lists, map->src->vpt_list, "<INVALID>"),
890                                                       vp->da->name, buffer);
891                 }
892                 break;
893
894         case VPT_TYPE_ATTR:
895                 vp_prints_value(buffer, sizeof(buffer), vp, '\'');
896                 value = talloc_typed_asprintf(request, "&%s -> %s", map->src->vpt_da->name, buffer);
897                 break;
898
899         case VPT_TYPE_NULL:
900                 strcpy(buffer, "ANY");
901                 value = buffer;
902                 break;
903         }
904
905         switch (map->dst->type) {
906         case VPT_TYPE_LIST:
907                 RDEBUG("\t%s%s %s %s", map->dst->name, vp ? vp->da->name : "",
908                        fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
909                 break;
910
911         case VPT_TYPE_ATTR:
912                 RDEBUG("\t%s %s %s", map->dst->name,
913                        fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
914                 break;
915
916         default:
917                 break;
918         }
919
920         if (value != buffer) talloc_free(value);
921 }
922
923 #define DEBUG_OVERWRITE(_old, _new) \
924 do {\
925         if (RDEBUG_ENABLED3) {\
926                 char *old = vp_aprint_value(request, _old);\
927                 char *new = vp_aprint_value(request, _new);\
928                 RDEBUG3("Overwriting value \"%s\" with \"%s\"", old, new);\
929                 talloc_free(old);\
930                 talloc_free(new);\
931         }\
932 } while (0)
933
934 /** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
935  *
936  * Takes a single value_pair_map_t, resolves request and list identifiers
937  * to pointers in the current request, then attempts to retrieve module
938  * specific value(s) using callback, and adds the resulting values to the
939  * correct request/list.
940  *
941  * @param request The current request.
942  * @param map specifying destination attribute and location and src identifier.
943  * @param func to retrieve module specific values and convert them to
944  *      VALUE_PAIRS.
945  * @param ctx to be passed to func.
946  * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
947  */
948 int radius_map2request(REQUEST *request, value_pair_map_t const *map, radius_tmpl_getvalue_t func, void *ctx)
949 {
950         int rcode = 0;
951         int num;
952         VALUE_PAIR **list, *vp, *dst, *head = NULL;
953         bool found = false;
954         REQUEST *context;
955         TALLOC_CTX *parent;
956         vp_cursor_t dst_list, src_list;
957
958         /*
959          *      Sanity check inputs.  We can have a list or attribute
960          *      as a destination.
961          */
962         if ((map->dst->type != VPT_TYPE_LIST) &&
963             (map->dst->type != VPT_TYPE_ATTR)) {
964                 REDEBUG("Invalid mapping destination");
965                 return -2;
966         }
967
968         context = request;
969         if (radius_request(&context, map->dst->vpt_request) < 0) {
970                 REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
971                 return -2;
972         }
973
974         /*
975          *      If there's no CoA packet and we're updating it,
976          *      auto-allocate it.
977          */
978         if (((map->dst->vpt_list == PAIR_LIST_COA) ||
979              (map->dst->vpt_list == PAIR_LIST_DM)) && !request->coa) {
980                 request_alloc_coa(context);
981                 context->coa->proxy->code = (map->dst->vpt_list == PAIR_LIST_COA) ?
982                                             PW_CODE_COA_REQUEST :
983                                             PW_CODE_DISCONNECT_REQUEST;
984         }
985
986         list = radius_list(context, map->dst->vpt_list);
987         if (!list) {
988                 REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
989
990                 return -2;
991         }
992
993         parent = radius_list_ctx(context, map->dst->vpt_list);
994         rad_assert(parent);
995
996         /*
997          *      The callback should either return -1 to signify operations error,
998          *      -2 when it can't find the attribute or list being referenced, or
999          *      0 to signify success. It may return "sucess", but still have no
1000          *      VPs to work with.
1001          */
1002         if (map->src->type != VPT_TYPE_NULL) {
1003                 rcode = func(&head, request, map, ctx);
1004                 if (rcode < 0) {
1005                         rad_assert(!head);
1006                         return rcode;
1007                 }
1008                 if (!head) return rcode;
1009         } else {
1010                 if (debug_flag) radius_map_debug(request, map, NULL);
1011         }
1012
1013         /*
1014          *      Reparent the VPs (func may return multiple)
1015          */
1016         for (vp = fr_cursor_init(&src_list, &head);
1017              vp;
1018              vp = fr_cursor_next(&src_list)) {
1019                 VERIFY_VP(vp);
1020
1021                 if (debug_flag) radius_map_debug(request, map, vp);
1022                 (void) talloc_steal(parent, vp);
1023         }
1024
1025         /*
1026          *      The destination is a list (which is a completely different set of operations)
1027          */
1028         if (map->dst->type == VPT_TYPE_LIST) {
1029                 switch (map->op) {
1030                 case T_OP_CMP_FALSE:
1031                         /* We don't need the src VPs (should just be 'ANY') */
1032                         rad_assert(!head);
1033
1034                         /* Clear the entire dst list */
1035                         pairfree(list);
1036
1037                         if (map->dst->vpt_list == PAIR_LIST_REQUEST) {
1038                                 context->username = NULL;
1039                                 context->password = NULL;
1040                         }
1041                         return 0;
1042
1043                 case T_OP_SET:
1044                         if (map->src->type == VPT_TYPE_LIST) {
1045                                 pairfree(list);
1046                                 *list = head;
1047                         } else {
1048                 case T_OP_EQ:
1049                                 rad_assert(map->src->type == VPT_TYPE_EXEC);
1050                                 pairmove(parent, list, &head);
1051                                 pairfree(&head);
1052                         }
1053                         goto finish;
1054
1055                 case T_OP_ADD:
1056                         pairadd(list, head);
1057                         head = NULL;
1058                         goto finish;
1059
1060                 default:
1061                         pairfree(&head);
1062                         return -1;
1063                 }
1064         }
1065
1066         /*
1067          *      Find the destination attribute.  We leave with either
1068          *      the dst_list and vp pointing to the attribute or the VP
1069          *      being NULL (no attribute at that index).
1070          */
1071         num = map->dst->vpt_num;
1072         (void) fr_cursor_init(&dst_list, list);
1073         if (num != NUM_ANY) {
1074                 while ((dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag))) {
1075                         if (num-- == 0) break;
1076                 }
1077         } else {
1078                 dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag);
1079         }
1080         rad_assert(!dst || (map->dst->vpt_da == dst->da));
1081
1082         /*
1083          *      The destination is an attribute
1084          */
1085         switch (map->op) {
1086         default:
1087                 break;
1088         /*
1089          *      !* - Remove all attributes which match dst in the specified list.
1090          *      This doesn't use attributes returned by the func(), and immediately frees them.
1091          */
1092         case T_OP_CMP_FALSE:
1093                 /* We don't need the src VPs (should just be 'ANY') */
1094                 rad_assert(!head);
1095                 if (!dst) return 0;
1096
1097                 /*
1098                  *      Wildcard: delete all of the matching ones, based on tag.
1099                  */
1100                 if (map->dst->vpt_num == NUM_ANY) {
1101                         pairdelete(list, map->dst->vpt_da->attr, map->dst->vpt_da->vendor, map->dst->vpt_tag);
1102                         dst = NULL;
1103                 /*
1104                  *      We've found the Nth one.  Delete it, and only it.
1105                  */
1106                 } else {
1107                         dst = fr_cursor_remove(&dst_list);
1108                         pairfree(&dst);
1109                 }
1110
1111                 /*
1112                  *      Check that the User-Name and User-Password
1113                  *      caches point to the correct attribute.
1114                  */
1115                 goto finish;
1116
1117         /*
1118          *      -= - Delete attributes in the dst list which match any of the
1119          *      src_list attributes.
1120          *
1121          *      This operation has two modes:
1122          *      - If map->dst->vpt_num > 0, we check each of the src_list attributes against
1123          *        the dst attribute, to see if any of their values match.
1124          *      - If map->dst->vpt_num == NUM_ANY, we compare all instances of the dst attribute
1125          *        against each of the src_list attributes.
1126          */
1127         case T_OP_SUB:
1128                 /* We didn't find any attributes earlier */
1129                 if (!dst) {
1130                         pairfree(&head);
1131                         return 0;
1132                 }
1133
1134                 /*
1135                  *      Instance specific[n] delete
1136                  */
1137                 if (map->dst->vpt_num != NUM_ANY) {
1138                         for (vp = fr_cursor_first(&src_list);
1139                              vp;
1140                              vp = fr_cursor_next(&src_list)) {
1141                                 head->op = T_OP_CMP_EQ;
1142                                 rcode = radius_compare_vps(request, vp, dst);
1143                                 if (rcode == 0) {
1144                                         dst = fr_cursor_remove(&dst_list);
1145                                         pairfree(&dst);
1146                                         found = true;
1147                                 }
1148                         }
1149                         pairfree(&head);
1150                         if (!found) return 0;
1151                         goto finish;
1152                 }
1153
1154                 /*
1155                  *      All instances[*] delete
1156                  */
1157                 for (dst = fr_cursor_current(&dst_list);
1158                      dst;
1159                      dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag)) {
1160                         for (vp = fr_cursor_first(&src_list);
1161                              vp;
1162                              vp = fr_cursor_next(&src_list)) {
1163                                 head->op = T_OP_CMP_EQ;
1164                                 rcode = radius_compare_vps(request, vp, dst);
1165                                 if (rcode == 0) {
1166                                         dst = fr_cursor_remove(&dst_list);
1167                                         pairfree(&dst);
1168                                         found = true;
1169                                 }
1170                         }
1171                 }
1172                 pairfree(&head);
1173                 if (!found) return 0;
1174                 goto finish;
1175         }
1176
1177         /*
1178          *      Another fixup pass to set tags on attributes were about to insert
1179          */
1180         if (map->dst->vpt_tag != TAG_ANY) {
1181                 for (vp = fr_cursor_init(&src_list, &head);
1182                      vp;
1183                      vp = fr_cursor_next(&src_list)) {
1184                         vp->tag = map->dst->vpt_tag;
1185                 }
1186         }
1187
1188         switch (map->op) {
1189         /*
1190          *      = - Set only if not already set
1191          */
1192         case T_OP_EQ:
1193                 if (dst) {
1194                         RDEBUG3("Refusing to overwrite (use :=)");
1195                         pairfree(&head);
1196                         return 0;
1197                 }
1198
1199                 /* Insert first instance (if multiple) */
1200                 fr_cursor_first(&src_list);
1201                 fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
1202                 /* Free any we didn't insert */
1203                 pairfree(&head);
1204                 break;
1205
1206         /*
1207          *      := - Overwrite existing attribute with last src_list attribute
1208          */
1209         case T_OP_SET:
1210                 /* Wind to last instance */
1211                 fr_cursor_last(&src_list);
1212                 if (dst) {
1213                         dst = fr_cursor_remove(&dst_list);
1214                         DEBUG_OVERWRITE(dst, fr_cursor_current(&src_list));
1215                         pairfree(&dst);
1216                 }
1217                 fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
1218                 /* Free any we didn't insert */
1219                 pairfree(&head);
1220                 break;
1221
1222         /*
1223          *      += - Add all src_list attributes to the destination
1224          */
1225         case T_OP_ADD:
1226                 /* Insert all the instances! (if multiple) */
1227                 pairadd(list, head);
1228                 head = NULL;
1229                 break;
1230
1231         /*
1232          *      Filtering operators
1233          */
1234         default:
1235                 /*
1236                  *      If the dst doesn't exist, the filters will add
1237                  *      it with the given value.
1238                  */
1239                 if (!dst) {
1240                         RDEBUG3("No existing attribute to filter, adding instead");
1241                         fr_cursor_insert(&dst_list, head);
1242                         head = NULL;
1243                         goto finish;
1244                 }
1245
1246                 /*
1247                  *      The LHS exists.  We need to limit it's value based on
1248                  *      the operator, and the value of the RHS.
1249                  */
1250                 found = false;
1251                 for (vp = fr_cursor_first(&src_list);
1252                      vp;
1253                      vp = fr_cursor_next(&src_list)) {
1254                         vp->op = map->op;
1255                         rcode = radius_compare_vps(request, vp, dst);
1256                         vp->op = T_OP_SET;
1257
1258                         switch (map->op) {
1259                         case T_OP_CMP_EQ:
1260                                 if (rcode == 0) continue;
1261                         replace:
1262                                 dst = fr_cursor_remove(&dst_list);
1263                                 DEBUG_OVERWRITE(dst, fr_cursor_current(&src_list));
1264                                 pairfree(&dst);
1265                                 fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
1266                                 found = true;
1267                                 continue;
1268
1269                         case T_OP_LE:
1270                                 if (rcode <= 0) continue;
1271                                 goto replace;
1272
1273                         case T_OP_GE:
1274                                 if (rcode >= 0) continue;
1275                                 goto replace;
1276
1277                         default:
1278                                 pairfree(&head);
1279                                 return -1;
1280                         }
1281                 }
1282                 pairfree(&head);
1283                 if (!found) return 0;
1284
1285                 break;
1286         }
1287
1288 finish:
1289         rad_assert(!head);
1290
1291         if (map->dst->vpt_list == PAIR_LIST_REQUEST) {
1292                 context->username = pairfind(*list, PW_USER_NAME, 0, TAG_ANY);
1293                 context->password = pairfind(*list, PW_USER_PASSWORD, 0, TAG_ANY);
1294         }
1295         return 0;
1296 }
1297
1298 /** Process map which has exec as a src
1299  *
1300  * Evaluate maps which specify exec as a src. This may be used by various sorts of update sections, and so
1301  * has been broken out into it's own function.
1302  *
1303  * @param[out] out Where to write the VALUE_PAIR(s).
1304  * @param[in] request structure (used only for talloc).
1305  * @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.
1306  * @return -1 on failure, 0 on success.
1307  */
1308 int radius_mapexec(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map)
1309 {
1310         int result;
1311         char *expanded = NULL;
1312         char answer[1024];
1313         VALUE_PAIR **input_pairs = NULL;
1314         VALUE_PAIR *output_pairs = NULL;
1315
1316         *out = NULL;
1317
1318         rad_assert(map->src->type == VPT_TYPE_EXEC);
1319         rad_assert((map->dst->type == VPT_TYPE_ATTR) || (map->dst->type == VPT_TYPE_LIST));
1320
1321         /*
1322          *      We always put the request pairs into the environment
1323          */
1324         input_pairs = radius_list(request, PAIR_LIST_REQUEST);
1325
1326         /*
1327          *      Automagically switch output type depending on our destination
1328          *      If dst is a list, then we create attributes from the output of the program
1329          *      if dst is an attribute, then we create an attribute of that type and then
1330          *      call pairparsevalue on the output of the script.
1331          */
1332         result = radius_exec_program(request, map->src->name, true, true,
1333                                      answer, sizeof(answer), EXEC_TIMEOUT,
1334                                      input_pairs ? *input_pairs : NULL,
1335                                      (map->dst->type == VPT_TYPE_LIST) ? &output_pairs : NULL);
1336         talloc_free(expanded);
1337         if (result != 0) {
1338                 talloc_free(output_pairs);
1339                 return -1;
1340         }
1341
1342         switch (map->dst->type) {
1343         case VPT_TYPE_LIST:
1344                 if (!output_pairs) {
1345                         REDEBUG("No valid attributes received from program");
1346                         return -2;
1347                 }
1348                 *out = output_pairs;
1349                 return 0;
1350
1351         case VPT_TYPE_ATTR:
1352         {
1353                 VALUE_PAIR *vp;
1354
1355                 vp = pairalloc(request, map->dst->vpt_da);
1356                 if (!vp) return -1;
1357                 vp->op = map->op;
1358                 if (pairparsevalue(vp, answer, 0) < 0) {
1359                         pairfree(&vp);
1360                         return -2;
1361                 }
1362                 *out = vp;
1363
1364                 return 0;
1365         }
1366
1367         default:
1368                 rad_assert(0);
1369         }
1370
1371         return -1;
1372 }
1373
1374 /** Convert a map to a VALUE_PAIR.
1375  *
1376  * @param[out] out Where to write the VALUE_PAIR(s), which may be NULL if not found
1377  * @param[in] request structure (used only for talloc)
1378  * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
1379  * @param[in] ctx unused
1380  * @return 0 on success, -1 on failure
1381  */
1382 int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx)
1383 {
1384         int rcode = 0;
1385         VALUE_PAIR *vp = NULL, *new, *found = NULL;
1386         DICT_ATTR const *da;
1387         REQUEST *context = request;
1388         vp_cursor_t cursor;
1389
1390         *out = NULL;
1391
1392         /*
1393          *      Special case for !*, we don't need to parse RHS as this is a unary operator.
1394          */
1395         if (map->op == T_OP_CMP_FALSE) return 0;
1396
1397         /*
1398          *      List to list found, this is a special case because we don't need
1399          *      to allocate any attributes, just finding the current list, and change
1400          *      the op.
1401          */
1402         if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
1403                 VALUE_PAIR **from = NULL;
1404
1405                 if (radius_request(&context, map->src->vpt_request) == 0) {
1406                         from = radius_list(context, map->src->vpt_list);
1407                 }
1408                 if (!from) return 0;
1409
1410                 found = paircopy(request, *from);
1411
1412                 /*
1413                  *      List to list copy is empty if the src list has no attributes.
1414                  */
1415                 if (!found) return 0;
1416
1417                 for (vp = fr_cursor_init(&cursor, &found);
1418                      vp;
1419                      vp = fr_cursor_next(&cursor)) {
1420                         vp->op = T_OP_ADD;
1421                 }
1422
1423                 *out = found;
1424
1425                 return 0;
1426         }
1427
1428         /*
1429          *      Deal with all non-list operations.
1430          */
1431         da = map->dst->vpt_da ? map->dst->vpt_da : map->src->vpt_da;
1432
1433         /*
1434          *      And parse the RHS
1435          */
1436         switch (map->src->type) {
1437                 ssize_t slen;
1438                 char *str;
1439
1440         case VPT_TYPE_XLAT_STRUCT:
1441                 rad_assert(map->dst->vpt_da);   /* Need to know where were going to write the new attribute */
1442                 rad_assert(map->src->vpt_xlat != NULL);
1443
1444                 new = pairalloc(request, da);
1445                 if (!new) return -1;
1446
1447                 str = NULL;
1448                 slen = radius_axlat_struct(&str, request, map->src->vpt_xlat, NULL, NULL);
1449                 if (slen < 0) {
1450                         rcode = slen;
1451                         goto error;
1452                 }
1453
1454                 /*
1455                  *      We do the debug printing because radius_axlat_struct
1456                  *      doesn't have access to the original string.  It's been
1457                  *      mangled during the parsing to xlat_exp_t
1458                  */
1459                 RDEBUG2("EXPAND %s", map->src->name);
1460                 RDEBUG2("   --> %s", str);
1461
1462                 rcode = pairparsevalue(new, str, 0);
1463                 talloc_free(str);
1464                 if (rcode < 0) {
1465                         pairfree(&new);
1466                         goto error;
1467                 }
1468                 new->op = map->op;
1469                 *out = new;
1470                 break;
1471
1472         case VPT_TYPE_XLAT:
1473                 rad_assert(map->dst->vpt_da);   /* Need to know where were going to write the new attribute */
1474
1475                 new = pairalloc(request, da);
1476                 if (!new) return -1;
1477
1478                 str = NULL;
1479                 slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
1480                 if (slen < 0) {
1481                         rcode = slen;
1482                         goto error;
1483                 }
1484
1485                 rcode = pairparsevalue(new, str, 0);
1486                 talloc_free(str);
1487                 if (rcode < 0) {
1488                         pairfree(&new);
1489                         goto error;
1490                 }
1491                 new->op = map->op;
1492                 *out = new;
1493                 break;
1494
1495         case VPT_TYPE_LITERAL:
1496                 new = pairalloc(request, da);
1497                 if (!new) return -1;
1498
1499                 if (pairparsevalue(new, map->src->name, 0) < 0) {
1500                         rcode = 0;
1501                         goto error;
1502                 }
1503                 new->op = map->op;
1504                 *out = new;
1505                 break;
1506
1507         case VPT_TYPE_ATTR:
1508         {
1509                 vp_cursor_t from;
1510
1511                 rad_assert(!map->dst->vpt_da ||
1512                            (map->src->vpt_da->type == map->dst->vpt_da->type) ||
1513                            (map->src->vpt_da->type == PW_TYPE_OCTETS) ||
1514                            (map->dst->vpt_da->type == PW_TYPE_OCTETS));
1515
1516                 /*
1517                  * @todo should log error, and return -1 for v3.1 (causes update to fail)
1518                  */
1519                 if (radius_tmpl_copy_vp(request, &found, request, map->src) < 0) return 0;
1520
1521                 vp = fr_cursor_init(&from, &found);
1522                 /*
1523                  *  Src/Dst attributes don't match, convert src attributes
1524                  *  to match dst.
1525                  */
1526                 if (map->src->vpt_da->type != map->dst->vpt_da->type) {
1527                         vp_cursor_t to;
1528
1529                         (void) fr_cursor_init(&to, out);
1530                         for (; vp; vp = fr_cursor_next(&from)) {
1531                                 new = pairalloc(request, da);
1532                                 if (!new) return -1;
1533                                 if (pairdatacpy(new, vp->da, &vp->data, vp->length) < 0) {
1534                                         REDEBUG("Attribute conversion failed: %s", fr_strerror());
1535                                         pairfree(&found);
1536                                         pairfree(&new);
1537                                         return -1;
1538                                 }
1539                                 vp = fr_cursor_remove(&from);
1540                                 talloc_free(vp);
1541
1542                                 new->op = map->op;
1543                                 fr_cursor_insert(&to, new);
1544                         }
1545                         return 0;
1546                 }
1547
1548                 /*
1549                  *   Otherwise we just need to fixup the attribute types
1550                  *   and operators
1551                  */
1552                 for (; vp; vp = fr_cursor_next(&from)) {
1553                         vp->da = da;
1554                         vp->op = map->op;
1555                 }
1556                 *out = found;
1557         }
1558                 break;
1559
1560         case VPT_TYPE_DATA:
1561                 rad_assert(map->src && map->src->vpt_da);
1562                 rad_assert(map->dst && map->dst->vpt_da);
1563                 rad_assert(map->src->vpt_da->type == map->dst->vpt_da->type);
1564
1565                 new = pairalloc(request, da);
1566                 if (!new) return -1;
1567
1568                 if (pairdatacpy(new, map->src->vpt_da, map->src->vpt_value, map->src->vpt_length) < 0) goto error;
1569                 new->op = map->op;
1570                 *out = new;
1571                 break;
1572
1573         /*
1574          *      This essentially does the same as rlm_exec xlat, except it's non-configurable.
1575          *      It's only really here as a convenience for people who expect the contents of
1576          *      backticks to be executed in a shell.
1577          *
1578          *      exec string is xlat expanded and arguments are shell escaped.
1579          */
1580         case VPT_TYPE_EXEC:
1581                 return radius_mapexec(out, request, map);
1582
1583         default:
1584                 rad_assert(0);  /* Should have been caught at parse time */
1585
1586         error:
1587                 pairfree(&vp);
1588                 return rcode;
1589         }
1590
1591         return 0;
1592 }
1593
1594 /** Convert a valuepair string to valuepair map
1595  *
1596  * Takes a valuepair string with list and request qualifiers, converts it into a
1597  * value_pair_map_t and inserts it into the appropriate list.
1598  *
1599  * @param out Where to write the new map (must be freed with talloc_free()).
1600  * @param request Current request.
1601  * @param raw string to parse.
1602  * @param dst_request_def to use if attribute isn't qualified.
1603  * @param dst_list_def to use if attribute isn't qualified.
1604  * @param src_request_def to use if attribute isn't qualified.
1605  * @param src_list_def to use if attribute isn't qualified.
1606  * @return 0 on success, < 0 on error.
1607  */
1608 int radius_strpair2map(value_pair_map_t **out, REQUEST *request, char const *raw,
1609                        request_refs_t dst_request_def, pair_lists_t dst_list_def,
1610                        request_refs_t src_request_def, pair_lists_t src_list_def)
1611 {
1612         char const *p = raw;
1613         FR_TOKEN ret;
1614
1615         VALUE_PAIR_RAW tokens;
1616         value_pair_map_t *map;
1617
1618         ret = pairread(&p, &tokens);
1619         if (ret != T_EOL) {
1620                 REDEBUG("Failed tokenising attribute string: %s", fr_strerror());
1621                 return -1;
1622         }
1623
1624         map = radius_str2map(request, tokens.l_opand, T_BARE_WORD, tokens.op, tokens.r_opand, tokens.quote,
1625                              dst_request_def, dst_list_def, src_request_def, src_list_def);
1626         if (!map) {
1627                 REDEBUG("Failed parsing attribute string: %s", fr_strerror());
1628                 return -1;
1629         }
1630         *out = map;
1631
1632         return 0;
1633 }
1634
1635 /** Check whether the destination of a map is currently valid
1636  *
1637  * @param request The current request.
1638  * @param map to check.
1639  * @return true if the map resolves to a request and list else false.
1640  */
1641 bool radius_map_dst_valid(REQUEST *request, value_pair_map_t const *map)
1642 {
1643         REQUEST *context = request;
1644
1645         if (radius_request(&context, map->dst->vpt_request) < 0) return false;
1646         if (!radius_list(context, map->dst->vpt_list)) return false;
1647
1648         return true;
1649 }
1650
1651 /** Return a VP from a value_pair_tmpl_t
1652  *
1653  * @param out where to write the retrieved vp.
1654  * @param request current request.
1655  * @param vpt the value pair template
1656  * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found.
1657  */
1658 int radius_tmpl_get_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt)
1659 {
1660         VALUE_PAIR **vps, *vp;
1661
1662         if (out) *out = NULL;
1663
1664         if (radius_request(&request, vpt->vpt_request) < 0) {
1665                 return -3;
1666         }
1667
1668         vps = radius_list(request, vpt->vpt_list);
1669         if (!vps) {
1670                 return -2;
1671         }
1672
1673         switch (vpt->type) {
1674         /*
1675          *      May not may not be found, but it *is* a known
1676          *      name.
1677          */
1678         case VPT_TYPE_ATTR:
1679         {
1680                 int num;
1681                 vp_cursor_t cursor;
1682
1683                 if (vpt->vpt_num == NUM_ANY) {
1684                         vp = pairfind(*vps, vpt->vpt_da->attr, vpt->vpt_da->vendor, vpt->vpt_tag);
1685                         if (!vp) return -1;
1686                         break;
1687                 }
1688
1689                 (void) fr_cursor_init(&cursor, vps);
1690                 num = vpt->vpt_num;
1691                 while ((vp = fr_cursor_next_by_da(&cursor, vpt->vpt_da, vpt->vpt_tag))) {
1692                         VERIFY_VP(vp);
1693                         if (num-- <= 0) goto finish;
1694                 }
1695                 return -1;
1696         }
1697
1698         case VPT_TYPE_LIST:
1699                 vp = *vps;
1700                 break;
1701
1702         default:
1703                 /*
1704                  *      literal, xlat, regex, exec, data.
1705                  *      no attribute.
1706                  */
1707                 return -1;
1708         }
1709
1710 finish:
1711         if (out) *out = vp;
1712
1713         return 0;
1714 }
1715
1716 /** Return a VP from the specified request.
1717  *
1718  * @param out where to write the pointer to the resolved VP.
1719  *      Will be NULL if the attribute couldn't be resolved.
1720  * @param request current request.
1721  * @param name attribute name including qualifiers.
1722  * @return -4 if either the attribute or qualifier were invalid, and the same error codes as radius_tmpl_get_vp for other
1723  *      error conditions.
1724  */
1725 int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
1726 {
1727         value_pair_tmpl_t vpt;
1728
1729         *out = NULL;
1730
1731         if (radius_parse_attr(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
1732                 return -4;
1733         }
1734
1735         return radius_tmpl_get_vp(out, request, &vpt);
1736 }
1737
1738 /** Copy pairs matching a VPT in the current request
1739  *
1740  * @param out where to write the copied vps.
1741  * @param request current request.
1742  * @param vpt the value pair template
1743  * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found.
1744  */
1745 int radius_tmpl_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt)
1746 {
1747         VALUE_PAIR **vps, *vp;
1748         REQUEST *current = request;
1749         vp_cursor_t from, to;
1750
1751         if (out) *out = NULL;
1752
1753         if (radius_request(&current, vpt->vpt_request) < 0) {
1754                 return -3;
1755         }
1756
1757         vps = radius_list(request, vpt->vpt_list);
1758         if (!vps) {
1759                 return -2;
1760         }
1761
1762         switch (vpt->type) {
1763         /*
1764          *      May not may not be found, but it *is* a known name.
1765          */
1766         case VPT_TYPE_ATTR:
1767         {
1768                 int num;
1769
1770                 (void) fr_cursor_init(&to, out);
1771                 (void) fr_cursor_init(&from, vps);
1772
1773                 vp = fr_cursor_next_by_da(&from, vpt->vpt_da, vpt->vpt_tag);
1774                 if (!vp) return -1;
1775
1776                 switch (vpt->vpt_num) {
1777                 /* Copy all pairs of this type (and tag) */
1778                 case NUM_ALL:
1779                         do {
1780                                 VERIFY_VP(vp);
1781                                 vp = paircopyvp(ctx, vp);
1782                                 if (!vp) {
1783                                         pairfree(out);
1784                                         return -4;
1785                                 }
1786                                 fr_cursor_insert(&to, vp);
1787                         } while ((vp = fr_cursor_next_by_da(&from, vpt->vpt_da, vpt->vpt_tag)));
1788                         break;
1789
1790                 /* Specific attribute number */
1791                 default:
1792                         for (num = vpt->vpt_num;
1793                              num && vp;
1794                              num--, vp = fr_cursor_next_by_da(&from, vpt->vpt_da, vpt->vpt_tag)) {
1795                              VERIFY_VP(vp);
1796                         }
1797                         if (!vp) return -1;
1798                         /* FALL-THROUGH */
1799
1800                 /* Just copy the first pair */
1801                 case NUM_ANY:
1802                         vp = paircopyvp(ctx, vp);
1803                         if (!vp) {
1804                                 pairfree(out);
1805                                 return -4;
1806                         }
1807                         fr_cursor_insert(&to, vp);
1808                 }
1809         }
1810                 break;
1811
1812         case VPT_TYPE_LIST:
1813                 vp = paircopy(ctx, *vps);
1814                 if (!vp) return 0;
1815
1816                 fr_cursor_insert(&to, vp);
1817                 break;
1818
1819         default:
1820                 /*
1821                  *      literal, xlat, regex, exec, data.
1822                  *      no attribute.
1823                  */
1824                 return -1;
1825         }
1826
1827         return 0;
1828 }
1829
1830 /** Copy VP(s) from the specified request.
1831  *
1832  * @param ctx to alloc new VALUE_PAIRs in.
1833  * @param out where to write the pointer to the copied VP.
1834  *      Will be NULL if the attribute couldn't be resolved.
1835  * @param request current request.
1836  * @param name attribute name including qualifiers.
1837  * @return -4 if either the attribute or qualifier were invalid, and the same error codes as radius_tmpl_get_vp for other
1838  *      error conditions.
1839  */
1840 int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
1841 {
1842         value_pair_tmpl_t vpt;
1843
1844         *out = NULL;
1845
1846         if (radius_parse_attr(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
1847                 return -4;
1848         }
1849
1850         return radius_tmpl_copy_vp(ctx, out, request, &vpt);
1851 }
1852
1853 void module_failure_msg(REQUEST *request, char const *fmt, ...)
1854 {
1855         va_list ap;
1856
1857         va_start(ap, fmt);
1858         vmodule_failure_msg(request, fmt, ap);
1859         va_end(ap);
1860 }
1861
1862 /** Add a module failure message VALUE_PAIR to the request
1863  */
1864 void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
1865 {
1866         char *p;
1867         VALUE_PAIR *vp;
1868         va_list aq;
1869
1870         if (!fmt || !request->packet) {
1871                 return;
1872         }
1873
1874         /*
1875          *  If we don't copy the original ap we get a segfault from vasprintf. This is apparently
1876          *  due to ap sometimes being implemented with a stack offset which is invalidated if
1877          *  ap is passed into another function. See here:
1878          *  http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
1879          *
1880          *  I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
1881          *  running unit tests which generate errors under CI.
1882          */
1883         va_copy(aq, ap);
1884         p = talloc_vasprintf(request, fmt, aq);
1885         va_end(aq);
1886
1887         MEM(vp = pairmake_packet("Module-Failure-Message", NULL, T_OP_ADD));
1888         if (request->module && (request->module[0] != '\0')) {
1889                 pairsprintf(vp, "%s: %s", request->module, p);
1890         } else {
1891                 pairsprintf(vp, "%s", p);
1892         }
1893         talloc_free(p);
1894 }