fea349ee3155586b1e9b247d66de6e26e84bbeb6
[freeradius.git] / src / main / pair.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/pair.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 struct cmp {
38         DICT_ATTR const *attribute;
39         DICT_ATTR const *from;
40         bool    first_only;
41         void *instance; /* module instance */
42         RAD_COMPARE_FUNC compare;
43         struct cmp *next;
44 };
45 static struct cmp *cmp;
46
47 /** Compares check and vp by value.
48  *
49  * Does not call any per-attribute comparison function, but does honour
50  * check.operator. Basically does "vp.value check.op check.value".
51  *
52  * @param request Current request.
53  * @param check rvalue, and operator.
54  * @param vp lvalue.
55  * @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
56  *      value, -2 on error.
57  */
58 #ifdef HAVE_REGEX
59 int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
60 #else
61 int radius_compare_vps(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
62 #endif
63 {
64         int ret = 0;
65
66         /*
67          *      Check for =* and !* and return appropriately
68          */
69         if (check->op == T_OP_CMP_TRUE)  return 0;
70         if (check->op == T_OP_CMP_FALSE) return 1;
71
72 #ifdef HAVE_REGEX
73         if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) {
74                 ssize_t         slen;
75                 regex_t         *preg = NULL;
76                 regmatch_t      rxmatch[REQUEST_MAX_REGEX + 1]; /* +1 for %{0} (whole match) capture group */
77                 size_t          nmatch = sizeof(rxmatch) / sizeof(regmatch_t);
78
79                 char *expr = NULL, *value = NULL;
80                 char const *expr_p, *value_p;
81
82                 if (check->da->type == PW_TYPE_STRING) {
83                         expr_p = check->vp_strvalue;
84                 } else {
85                         expr_p = expr = vp_aprints_value(check, check, '\0');
86                 }
87
88                 if (vp->da->type == PW_TYPE_STRING) {
89                         value_p = vp->vp_strvalue;
90                 } else {
91                         value_p = value = vp_aprints_value(vp, vp, '\0');
92                 }
93
94                 if (!expr_p || !value_p) {
95                         REDEBUG("Error stringifying operand for regular expression");
96
97                 regex_error:
98                         talloc_free(preg);
99                         talloc_free(expr);
100                         talloc_free(value);
101                         return -2;
102                 }
103
104                 /*
105                  *      Include substring matches.
106                  */
107                 slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1, false, false, true, true);
108                 if (slen <= 0) {
109                         REMARKER(expr_p, -slen, fr_strerror());
110
111                         goto regex_error;
112                 }
113
114                 slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, rxmatch, &nmatch);
115                 if (slen < 0) {
116                         RERROR("%s", fr_strerror());
117
118                         goto regex_error;
119                 }
120
121                 if (check->op == T_OP_REG_EQ) {
122                         /*
123                          *      Add in %{0}. %{1}, etc.
124                          */
125                         regex_sub_to_request(request, &preg, value_p, talloc_array_length(value_p) - 1,
126                                              rxmatch, nmatch);
127                         ret = (slen == 1) ? 0 : -1;
128                 } else {
129                         ret = (slen != 1) ? 0 : -1;
130                 }
131
132                 talloc_free(preg);
133                 talloc_free(expr);
134                 talloc_free(value);
135                 goto finish;
136         }
137 #endif
138
139         /*
140          *      Attributes must be of the same type.
141          *
142          *      FIXME: deal with type mismatch properly if one side contain
143          *      ABINARY, OCTETS or STRING by converting the other side to
144          *      a string
145          *
146          */
147         if (vp->da->type != check->da->type) return -1;
148
149         /*
150          *      Tagged attributes are equal if and only if both the
151          *      tag AND value match.
152          */
153         if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
154                 ret = ((int) vp->tag) - ((int) check->tag);
155                 if (ret != 0) goto finish;
156         }
157
158         /*
159          *      Not a regular expression, compare the types.
160          */
161         switch (check->da->type) {
162 #ifdef WITH_ASCEND_BINARY
163                 /*
164                  *      Ascend binary attributes can be treated
165                  *      as opaque objects, I guess...
166                  */
167                 case PW_TYPE_ABINARY:
168 #endif
169                 case PW_TYPE_OCTETS:
170                         if (vp->vp_length != check->vp_length) {
171                                 ret = 1; /* NOT equal */
172                                 break;
173                         }
174                         ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
175                                      vp->vp_length);
176                         break;
177
178                 case PW_TYPE_STRING:
179                         ret = strcmp(vp->vp_strvalue,
180                                      check->vp_strvalue);
181                         break;
182
183                 case PW_TYPE_BYTE:
184                         ret = vp->vp_byte - check->vp_byte;
185                         break;
186                 case PW_TYPE_SHORT:
187                         ret = vp->vp_short - check->vp_short;
188                         break;
189                 case PW_TYPE_INTEGER:
190                         ret = vp->vp_integer - check->vp_integer;
191                         break;
192
193                 case PW_TYPE_INTEGER64:
194                         /*
195                          *      Don't want integer overflow!
196                          */
197                         if (vp->vp_integer64 < check->vp_integer64) {
198                                 ret = -1;
199                         } else if (vp->vp_integer64 > check->vp_integer64) {
200                                 ret = +1;
201                         } else {
202                                 ret = 0;
203                         }
204                         break;
205
206                 case PW_TYPE_SIGNED:
207                         if (vp->vp_signed < check->vp_signed) {
208                                 ret = -1;
209                         } else if (vp->vp_signed > check->vp_signed) {
210                                 ret = +1;
211                         } else {
212                                 ret = 0;
213                         }
214                         break;
215
216                 case PW_TYPE_DATE:
217                         ret = vp->vp_date - check->vp_date;
218                         break;
219
220                 case PW_TYPE_IPV4_ADDR:
221                         ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
222                         break;
223
224                 case PW_TYPE_IPV6_ADDR:
225                         ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
226                         break;
227
228                 case PW_TYPE_IPV6_PREFIX:
229                         ret = memcmp(vp->vp_ipv6prefix, check->vp_ipv6prefix, sizeof(vp->vp_ipv6prefix));
230                         break;
231
232                 case PW_TYPE_IFID:
233                         ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid));
234                         break;
235
236                 default:
237                         break;
238         }
239
240 finish:
241         if (ret > 0) return 1;
242         if (ret < 0) return -1;
243         return 0;
244 }
245
246
247 /** Compare check and vp. May call the attribute comparison function.
248  *
249  * Unlike radius_compare_vps() this function will call any attribute-specific
250  * comparison functions registered.
251  *
252  * @param request Current request.
253  * @param req list pairs.
254  * @param check item to compare.
255  * @param check_pairs list.
256  * @param reply_pairs list.
257  * @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
258  *      value.
259  */
260 int radius_callback_compare(REQUEST *request, VALUE_PAIR *req,
261                             VALUE_PAIR *check, VALUE_PAIR *check_pairs,
262                             VALUE_PAIR **reply_pairs)
263 {
264         struct cmp *c;
265
266         /*
267          *      Check for =* and !* and return appropriately
268          */
269         if (check->op == T_OP_CMP_TRUE)  return 0;
270         if (check->op == T_OP_CMP_FALSE) return 1;
271
272         /*
273          *      See if there is a special compare function.
274          *
275          *      FIXME: use new RB-Tree code.
276          */
277         for (c = cmp; c; c = c->next) {
278                 if (c->attribute == check->da) {
279                         return (c->compare)(c->instance, request, req, check,
280                                 check_pairs, reply_pairs);
281                 }
282         }
283
284         if (!req) return -1; /* doesn't exist, don't compare it */
285
286         return radius_compare_vps(request, check, req);
287 }
288
289
290 /** Find a comparison function for two attributes.
291  *
292  * @todo this should probably take DA's.
293  * @param attribute to find comparison function for.
294  * @return true if a comparison function was found, else false.
295  */
296 int radius_find_compare(DICT_ATTR const *attribute)
297 {
298         struct cmp *c;
299
300         for (c = cmp; c; c = c->next) {
301                 if (c->attribute == attribute) {
302                         return true;
303                 }
304         }
305
306         return false;
307 }
308
309
310 /** See what attribute we want to compare with.
311  *
312  * @param attribute to find comparison function for.
313  * @param from reference to compare with
314  * @return true if the comparison callback require a matching attribue in the request, else false.
315  */
316 static bool otherattr(DICT_ATTR const *attribute, DICT_ATTR const **from)
317 {
318         struct cmp *c;
319
320         for (c = cmp; c; c = c->next) {
321                 if (c->attribute == attribute) {
322                         *from = c->from;
323                         return c->first_only;
324                 }
325         }
326
327         *from = attribute;
328         return false;
329 }
330
331 /** Register a function as compare function.
332  *
333  * @param name the attribute comparison to register
334  * @param from the attribute we want to compare with. Normally this is the same as attribute.
335  *  If null call the comparison function on every attributes in the request if first_only is false
336  * @param first_only will decide if we loop over the request attributes or stop on the first one
337  * @param func comparison function
338  * @param instance argument to comparison function
339  * @return 0
340  */
341 int paircompare_register_byname(char const *name, DICT_ATTR const *from,
342                                 bool first_only, RAD_COMPARE_FUNC func, void *instance)
343 {
344         ATTR_FLAGS flags;
345         DICT_ATTR const *da;
346
347         memset(&flags, 0, sizeof(flags));
348         flags.compare = 1;
349
350         da = dict_attrbyname(name);
351         if (da) {
352                 if (!da->flags.compare) {
353                         fr_strerror_printf("Attribute '%s' already exists.", name);
354                         return -1;
355                 }
356         } else if (from) {
357                 if (dict_addattr(name, -1, 0, from->type, flags) < 0) {
358                         fr_strerror_printf("Failed creating attribute '%s'", name);
359                         return -1;
360                 }
361
362                 da = dict_attrbyname(name);
363                 if (!da) {
364                         fr_strerror_printf("Failed finding attribute '%s'", name);
365                         return -1;
366                 }
367
368                 DEBUG("Creating attribute %s", name);
369         }
370
371         return paircompare_register(da, from, first_only, func, instance);
372 }
373
374 /** Register a function as compare function.
375  *
376  * @param attribute to register comparison function for.
377  * @param from the attribute we want to compare with. Normally this is the same as attribute.
378  *  If null call the comparison function on every attributes in the request if first_only is false
379  * @param first_only will decide if we loop over the request attributes or stop on the first one
380  * @param func comparison function
381  * @param instance argument to comparison function
382  * @return 0
383  */
384 int paircompare_register(DICT_ATTR const *attribute, DICT_ATTR const *from,
385                          bool first_only, RAD_COMPARE_FUNC func, void *instance)
386 {
387         struct cmp *c;
388
389         rad_assert(attribute != NULL);
390
391         paircompare_unregister(attribute, func);
392
393         c = rad_malloc(sizeof(struct cmp));
394
395         c->compare   = func;
396         c->attribute = attribute;
397         c->from = from;
398         c->first_only = first_only;
399         c->instance  = instance;
400         c->next      = cmp;
401         cmp = c;
402
403         return 0;
404 }
405
406 /** Unregister comparison function for an attribute
407  *
408  * @param attribute dict reference to unregister for.
409  * @param func comparison function to remove.
410  */
411 void paircompare_unregister(DICT_ATTR const *attribute, RAD_COMPARE_FUNC func)
412 {
413         struct cmp *c, *last;
414
415         last = NULL;
416         for (c = cmp; c; c = c->next) {
417                 if (c->attribute == attribute && c->compare == func) {
418                         break;
419                 }
420                 last = c;
421         }
422
423         if (c == NULL) return;
424
425         if (last != NULL) {
426                 last->next = c->next;
427         } else {
428                 cmp = c->next;
429         }
430
431         free(c);
432 }
433
434 /** Unregister comparison function for a module
435  *
436  *  All paircompare() functions for this module will be unregistered.
437  *
438  * @param instance the module instance
439  */
440 void paircompare_unregister_instance(void *instance)
441 {
442         struct cmp *c, **tail;
443
444         tail = &cmp;
445         while ((c = *tail) != NULL) {
446                 if (c->instance == instance) {
447                         *tail = c->next;
448                         free(c);
449                         continue;
450                 }
451
452                 tail = &(c->next);
453         }
454 }
455
456 /** Compare two pair lists except for the password information.
457  *
458  * For every element in "check" at least one matching copy must be present
459  * in "reply".
460  *
461  * @param[in] request Current request.
462  * @param[in] req_list request valuepairs.
463  * @param[in] check Check/control valuepairs.
464  * @param[in,out] rep_list Reply value pairs.
465  *
466  * @return 0 on match.
467  */
468 int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
469                 VALUE_PAIR **rep_list)
470 {
471         vp_cursor_t cursor;
472         VALUE_PAIR *check_item;
473         VALUE_PAIR *auth_item = NULL;
474         DICT_ATTR const *from;
475
476         int result = 0;
477         int compare;
478         bool first_only;
479
480         for (check_item = fr_cursor_init(&cursor, &check);
481              check_item;
482              check_item = fr_cursor_next(&cursor)) {
483                 /*
484                  *      If the user is setting a configuration value,
485                  *      then don't bother comparing it to any attributes
486                  *      sent to us by the user.  It ALWAYS matches.
487                  */
488                 if ((check_item->op == T_OP_SET) ||
489                     (check_item->op == T_OP_ADD)) {
490                         continue;
491                 }
492
493                 if (!check_item->da->vendor) switch (check_item->da->attr) {
494                 /*
495                  *      Attributes we skip during comparison.
496                  *      These are "server" check items.
497                  */
498                 case PW_CRYPT_PASSWORD:
499                 case PW_AUTH_TYPE:
500                 case PW_AUTZ_TYPE:
501                 case PW_ACCT_TYPE:
502                 case PW_SESSION_TYPE:
503                 case PW_STRIP_USER_NAME:
504                         continue;
505
506                 /*
507                  *      IF the password attribute exists, THEN
508                  *      we can do comparisons against it.  If not,
509                  *      then the request did NOT contain a
510                  *      User-Password attribute, so we CANNOT do
511                  *      comparisons against it.
512                  *
513                  *      This hack makes CHAP-Password work..
514                  */
515                 case PW_USER_PASSWORD:
516                         if (check_item->op == T_OP_CMP_EQ) {
517                                 WARN("Found User-Password == \"...\"");
518                                 WARN("Are you sure you don't mean Cleartext-Password?");
519                                 WARN("See \"man rlm_pap\" for more information");
520                         }
521                         if (fr_pair_find_by_num(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
522                                 continue;
523                         }
524                         break;
525                 }
526
527                 /*
528                  *      See if this item is present in the request.
529                  */
530                 first_only = otherattr(check_item->da, &from);
531
532                 auth_item = req_list;
533         try_again:
534                 if (!first_only) {
535                         while (auth_item != NULL) {
536                                 VERIFY_VP(auth_item);
537                                 if ((auth_item->da == from) || (!from)) {
538                                         break;
539                                 }
540                                 auth_item = auth_item->next;
541                         }
542                 }
543
544                 /*
545                  *      Not found, it's not a match.
546                  */
547                 if (auth_item == NULL) {
548                         /*
549                          *      Didn't find it.  If we were *trying*
550                          *      to not find it, then we succeeded.
551                          */
552                         if (check_item->op == T_OP_CMP_FALSE) {
553                                 continue;
554                         } else {
555                                 return -1;
556                         }
557                 }
558
559                 /*
560                  *      Else we found it, but we were trying to not
561                  *      find it, so we failed.
562                  */
563                 if (check_item->op == T_OP_CMP_FALSE) {
564                         return -1;
565                 }
566
567                 /*
568                  *      We've got to xlat the string before doing
569                  *      the comparison.
570                  */
571                 radius_xlat_do(request, check_item);
572
573                 /*
574                  *      OK it is present now compare them.
575                  */
576                 compare = radius_callback_compare(request, auth_item,
577                                                   check_item, check, rep_list);
578
579                 switch (check_item->op) {
580                 case T_OP_EQ:
581                 default:
582                         RWDEBUG("Invalid operator '%s' for item %s: reverting to '=='",
583                                 fr_int2str(fr_tokens, check_item->op, "<INVALID>"), check_item->da->name);
584                         /* FALL-THROUGH */
585                 case T_OP_CMP_TRUE:
586                 case T_OP_CMP_FALSE:
587                 case T_OP_CMP_EQ:
588                         if (compare != 0) result = -1;
589                         break;
590
591                 case T_OP_NE:
592                         if (compare == 0) result = -1;
593                         break;
594
595                 case T_OP_LT:
596                         if (compare >= 0) result = -1;
597                         break;
598
599                 case T_OP_GT:
600                         if (compare <= 0) result = -1;
601                         break;
602
603                 case T_OP_LE:
604                         if (compare > 0) result = -1;
605                         break;
606
607                 case T_OP_GE:
608                         if (compare < 0) result = -1;
609                         break;
610
611 #ifdef HAVE_REGEX
612                 case T_OP_REG_EQ:
613                 case T_OP_REG_NE:
614                         if (compare != 0) result = -1;
615                         break;
616 #endif
617                 } /* switch over the operator of the check item */
618
619                 /*
620                  *      This attribute didn't match, but maybe there's
621                  *      another of the same attribute, which DOES match.
622                  */
623                 if ((result != 0) && (!first_only)) {
624                         fr_assert(auth_item != NULL);
625                         auth_item = auth_item->next;
626                         result = 0;
627                         goto try_again;
628                 }
629
630         } /* for every entry in the check item list */
631
632         return result;
633 }
634
635 /** Expands an attribute marked with fr_pair_mark_xlat
636  *
637  * Writes the new value to the vp.
638  *
639  * @param request Current request.
640  * @param vp to expand.
641  * @return 0 if successful else -1 (on xlat failure) or -2 (on parse failure).
642  *      On failure pair will still no longer be marked for xlat expansion.
643  */
644 int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
645 {
646         ssize_t slen;
647
648         char *expanded = NULL;
649         if (vp->type != VT_XLAT) return 0;
650
651         vp->type = VT_DATA;
652
653         slen = radius_axlat(&expanded, request, vp->value.xlat, NULL, NULL);
654         rad_const_free(vp->value.xlat);
655         vp->value.xlat = NULL;
656         if (slen < 0) {
657                 return -1;
658         }
659
660         /*
661          *      Parse the string into a new value.
662          *
663          *      If the VALUE_PAIR is being used in a regular expression
664          *      then we just want to copy the new value in unmolested.
665          */
666         if ((vp->op == T_OP_REG_EQ) || (vp->op == T_OP_REG_NE)) {
667                 fr_pair_value_strsteal(vp, expanded);
668                 return 0;
669         }
670
671         if (fr_pair_value_from_str(vp, expanded, -1) < 0){
672                 talloc_free(expanded);
673                 return -2;
674         }
675
676         talloc_free(expanded);
677
678         return 0;
679 }
680
681 /** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
682  *
683  * @note This function ALWAYS returns. If we're OOM, then it causes the
684  * @note server to exit, so you don't need to check the return value.
685  *
686  * @param[in] ctx for talloc
687  * @param[out] vps List to add new VALUE_PAIR to, if NULL will just
688  *      return VALUE_PAIR.
689  * @param[in] attribute number.
690  * @param[in] vendor number.
691  * @return a new VLAUE_PAIR or causes server to exit on error.
692  */
693 VALUE_PAIR *radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps,
694                               unsigned int attribute, unsigned int vendor)
695 {
696         VALUE_PAIR *vp;
697
698         vp = fr_pair_afrom_num(ctx, attribute, vendor);
699         if (!vp) {
700                 ERROR("No memory!");
701                 rad_assert("No memory" == NULL);
702                 fr_exit_now(1);
703         }
704
705         if (vps) fr_pair_add(vps, vp);
706
707         return vp;
708 }
709
710 /** Print a single valuepair to stderr or error log.
711  *
712  * @param[in] vp list to print.
713  */
714 void debug_pair(VALUE_PAIR *vp)
715 {
716         if (!vp || !rad_debug_lvl || !fr_log_fp) return;
717
718         vp_print(fr_log_fp, vp);
719 }
720
721 /** Print a single valuepair to stderr or error log.
722  *
723  * @param[in] level Debug level (1-4).
724  * @param[in] request to read logging params from.
725  * @param[in] vp to print.
726  * @param[in] prefix (optional).
727  */
728 void rdebug_pair(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
729 {
730         char buffer[256];
731         if (!vp || !request || !request->log.func) return;
732
733         if (!radlog_debug_enabled(L_DBG, level, request)) return;
734
735         vp_prints(buffer, sizeof(buffer), vp);
736         RDEBUGX(level, "%s%s", prefix ? prefix : "",  buffer);
737 }
738
739 /** Print a list of VALUE_PAIRs.
740  *
741  * @param[in] level Debug level (1-4).
742  * @param[in] request to read logging params from.
743  * @param[in] vp to print.
744  * @param[in] prefix (optional).
745  */
746 void rdebug_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
747 {
748         vp_cursor_t cursor;
749         char buffer[256];
750         if (!vp || !request || !request->log.func) return;
751
752         if (!radlog_debug_enabled(L_DBG, level, request)) return;
753
754         RINDENT();
755         for (vp = fr_cursor_init(&cursor, &vp);
756              vp;
757              vp = fr_cursor_next(&cursor)) {
758                 VERIFY_VP(vp);
759
760                 vp_prints(buffer, sizeof(buffer), vp);
761                 RDEBUGX(level, "%s%s", prefix ? prefix : "",  buffer);
762         }
763         REXDENT();
764 }
765
766 /** Print a list of protocol VALUE_PAIRs.
767  *
768  * @param[in] level Debug level (1-4).
769  * @param[in] request to read logging params from.
770  * @param[in] vp to print.
771  */
772 void rdebug_proto_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp)
773 {
774         vp_cursor_t cursor;
775         char buffer[256];
776         if (!vp || !request || !request->log.func) return;
777
778         if (!radlog_debug_enabled(L_DBG, level, request)) return;
779
780         RINDENT();
781         for (vp = fr_cursor_init(&cursor, &vp);
782              vp;
783              vp = fr_cursor_next(&cursor)) {
784                 VERIFY_VP(vp);
785                 if ((vp->da->vendor == 0) &&
786                     ((vp->da->attr & 0xFFFF) > 0xff)) continue;
787                 vp_prints(buffer, sizeof(buffer), vp);
788                 RDEBUGX(level, "%s", buffer);
789         }
790         REXDENT();
791 }
792
793 /** Return a VP from the specified request.
794  *
795  * @param out where to write the pointer to the resolved VP.
796  *      Will be NULL if the attribute couldn't be resolved.
797  * @param request current request.
798  * @param name attribute name including qualifiers.
799  * @return -4 if either the attribute or qualifier were invalid, and the same error codes as tmpl_find_vp for other
800  *      error conditions.
801  */
802 int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
803 {
804         int rcode;
805         vp_tmpl_t vpt;
806
807         *out = NULL;
808
809         if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
810                 return -4;
811         }
812
813         rcode = tmpl_find_vp(out, request, &vpt);
814
815         return rcode;
816 }
817
818 /** Copy VP(s) from the specified request.
819  *
820  * @param ctx to alloc new VALUE_PAIRs in.
821  * @param out where to write the pointer to the copied VP.
822  *      Will be NULL if the attribute couldn't be resolved.
823  * @param request current request.
824  * @param name attribute name including qualifiers.
825  * @return -4 if either the attribute or qualifier were invalid, and the same error codes as tmpl_find_vp for other
826  *      error conditions.
827  */
828 int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
829 {
830         int rcode;
831         vp_tmpl_t vpt;
832
833         *out = NULL;
834
835         if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
836                 return -4;
837         }
838
839         rcode = tmpl_copy_vps(ctx, out, request, &vpt);
840
841         return rcode;
842 }
843
844 void module_failure_msg(REQUEST *request, char const *fmt, ...)
845 {
846         va_list ap;
847
848         va_start(ap, fmt);
849         vmodule_failure_msg(request, fmt, ap);
850         va_end(ap);
851 }
852
853 /** Add a module failure message VALUE_PAIR to the request
854  */
855 void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
856 {
857         char *p;
858         VALUE_PAIR *vp;
859         va_list aq;
860
861         if (!fmt || !request || !request->packet) {
862                 return;
863         }
864
865         /*
866          *  If we don't copy the original ap we get a segfault from vasprintf. This is apparently
867          *  due to ap sometimes being implemented with a stack offset which is invalidated if
868          *  ap is passed into another function. See here:
869          *  http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
870          *
871          *  I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
872          *  running unit tests which generate errors under CI.
873          */
874         va_copy(aq, ap);
875         p = talloc_vasprintf(request, fmt, aq);
876         va_end(aq);
877
878         MEM(vp = pair_make_request("Module-Failure-Message", NULL, T_OP_ADD));
879         if (request->module && (request->module[0] != '\0')) {
880                 fr_pair_value_sprintf(vp, "%s: %s", request->module, p);
881         } else {
882                 fr_pair_value_sprintf(vp, "%s", p);
883         }
884         talloc_free(p);
885 }