3169452ceb3aa001297ed75d54880520717a82a8
[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 #ifdef HAVE_PCREPOSIX_H
38 #include <pcreposix.h>
39 #else
40 #ifdef HAVE_REGEX_H
41 #       include <regex.h>
42
43 /*
44  *  For POSIX Regular expressions.
45  *  (0) Means no extended regular expressions.
46  *  REG_EXTENDED means use extended regular expressions.
47  */
48 #ifndef REG_EXTENDED
49 #define REG_EXTENDED (0)
50 #endif
51
52 #ifndef REG_NOSUB
53 #define REG_NOSUB (0)
54 #endif
55 #endif
56 #endif
57
58 const FR_NAME_NUMBER vpt_types[] = {
59         {"unknown",             VPT_TYPE_UNKNOWN },
60         {"literal",             VPT_TYPE_LITERAL },
61         {"expanded",            VPT_TYPE_XLAT },
62         {"attribute ref",       VPT_TYPE_ATTR },
63         {"list",                VPT_TYPE_LIST },
64         {"exec",                VPT_TYPE_EXEC }
65 };
66
67 struct cmp {
68         unsigned int attribute;
69         unsigned int otherattr;
70         void *instance; /* module instance */
71         RAD_COMPARE_FUNC compare;
72         struct cmp *next;
73 };
74 static struct cmp *cmp;
75
76 /** Compares check and vp by value.
77  *
78  * Does not call any per-attribute comparison function, but does honour
79  * check.operator. Basically does "vp.value check.op check.value".
80  *
81  * @param request Current request
82  * @param check rvalue, and operator
83  * @param vp lvalue
84  */
85 int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
86 {
87         int ret = -2;
88
89         /*
90          *      Check for =* and !* and return appropriately
91          */
92         if (check->op == T_OP_CMP_TRUE)  return 0;
93         if (check->op == T_OP_CMP_FALSE) return 1;
94
95 #ifdef HAVE_REGEX_H
96         if (check->op == T_OP_REG_EQ) {
97                 int i, compare;
98                 regex_t reg;
99                 char value[1024];
100                 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
101
102                 vp_prints_value(value, sizeof(value), vp, -1);
103
104                 /*
105                  *      Include substring matches.
106                  */
107                 compare = regcomp(&reg, check->vp_strvalue, REG_EXTENDED);
108                 if (compare != 0) {
109                         char buffer[256];
110                         regerror(compare, &reg, buffer, sizeof(buffer));
111
112                         RDEBUG("Invalid regular expression %s: %s",
113                                check->vp_strvalue, buffer);
114                         return -1;
115                 }
116                 compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1,
117                                   rxmatch, 0);
118                 regfree(&reg);
119
120                 /*
121                  *      Add %{0}, %{1}, etc.
122                  */
123                 for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
124                         char *p;
125                         char buffer[sizeof(check->vp_strvalue)];
126
127                         /*
128                          *      Didn't match: delete old
129                          *      match, if it existed.
130                          */
131                         if ((compare != 0) ||
132                             (rxmatch[i].rm_so == -1)) {
133                                 p = request_data_get(request, request,
134                                                      REQUEST_DATA_REGEX | i);
135                                 if (p) {
136                                         free(p);
137                                         continue;
138                                 }
139
140                                 /*
141                                  *      No previous match
142                                  *      to delete, stop.
143                                  */
144                                 break;
145                         }
146
147                         /*
148                          *      Copy substring into buffer.
149                          */
150                         memcpy(buffer, value + rxmatch[i].rm_so,
151                                rxmatch[i].rm_eo - rxmatch[i].rm_so);
152                         buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
153
154                         /*
155                          *      Copy substring, and add it to
156                          *      the request.
157                          *
158                          *      Note that we don't check
159                          *      for out of memory, which is
160                          *      the only error we can get...
161                          */
162                         p = strdup(buffer);
163                         request_data_add(request, request,
164                                          REQUEST_DATA_REGEX | i,
165                                          p, free);
166                 }
167                 if (compare == 0) return 0;
168                 return -1;
169         }
170
171         if (check->op == T_OP_REG_NE) {
172                 int compare;
173                 regex_t reg;
174                 char value[1024];
175                 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
176
177                 vp_prints_value(value, sizeof(value), vp, -1);
178
179                 /*
180                  *      Include substring matches.
181                  */
182                 compare = regcomp(&reg, (char *)check->vp_strvalue,
183                                   REG_EXTENDED);
184                 if (compare != 0) {
185                         char buffer[256];
186                         regerror(compare, &reg, buffer, sizeof(buffer));
187
188                         RDEBUG("Invalid regular expression %s: %s",
189                                check->vp_strvalue, buffer);
190                         return -1;
191                 }
192                 compare = regexec(&reg, value,  REQUEST_MAX_REGEX + 1,
193                                   rxmatch, 0);
194                 regfree(&reg);
195
196                 if (compare != 0) return 0;
197                 return -1;
198
199         }
200 #endif
201
202         /*
203          *      Tagged attributes are equal if and only if both the
204          *      tag AND value match.
205          */
206         if (check->da->flags.has_tag) {
207                 ret = ((int) vp->tag) - ((int) check->tag);
208                 if (ret != 0) return ret;
209         }
210
211         /*
212          *      Not a regular expression, compare the types.
213          */
214         switch(check->da->type) {
215 #ifdef WITH_ASCEND_BINARY
216                 /*
217                  *      Ascend binary attributes can be treated
218                  *      as opaque objects, I guess...
219                  */
220                 case PW_TYPE_ABINARY:
221 #endif
222                 case PW_TYPE_OCTETS:
223                         if (vp->length != check->length) {
224                                 ret = 1; /* NOT equal */
225                                 break;
226                         }
227                         ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
228                                      vp->length);
229                         break;
230
231                 case PW_TYPE_STRING:
232                         ret = strcmp((char *)vp->vp_strvalue,
233                                      (char *)check->vp_strvalue);
234                         break;
235
236                 case PW_TYPE_BYTE:
237                 case PW_TYPE_SHORT:
238                 case PW_TYPE_INTEGER:
239                         ret = vp->vp_integer - check->vp_integer;
240                         break;
241
242                 case PW_TYPE_INTEGER64:
243                         /*
244                          *      Don't want integer overflow!
245                          */
246                         if (vp->vp_integer64 < check->vp_integer64) {
247                                 ret = -1;
248                         } else if (vp->vp_integer64 > check->vp_integer64) {
249                                 ret = +1;
250                         } else {
251                                 ret = 0;
252                         }
253                         break;
254
255                 case PW_TYPE_SIGNED:
256                         if (vp->vp_signed < check->vp_signed) {
257                                 ret = -1;
258                         } else if (vp->vp_signed > check->vp_signed) {
259                                 ret = +1;
260                         } else {
261                                 ret = 0;
262                         }
263                         break;
264
265                 case PW_TYPE_DATE:
266                         ret = vp->vp_date - check->vp_date;
267                         break;
268
269                 case PW_TYPE_IPADDR:
270                         ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
271                         break;
272
273                 case PW_TYPE_IPV6ADDR:
274                         ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
275                                      sizeof(vp->vp_ipv6addr));
276                         break;
277
278                 case PW_TYPE_IPV6PREFIX:
279                         ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
280                                      sizeof(vp->vp_ipv6prefix));
281                         break;
282
283                 case PW_TYPE_IFID:
284                         ret = memcmp(&vp->vp_ifid, &check->vp_ifid,
285                                      sizeof(vp->vp_ifid));
286                         break;
287
288                 default:
289                         break;
290         }
291
292         return ret;
293 }
294
295
296 /** Compare check and vp. May call the attribute compare function.
297  *
298  * Unlike radius_compare_vps() this function will call any attribute-specific
299  * comparison function.
300  *
301  * @param req Current request
302  * @param request value pairs in the reqiest
303  * @param check
304  * @param check_pairs
305  * @param reply_pairs value pairs in the reply
306  * @return
307  */
308 int radius_callback_compare(REQUEST *req, VALUE_PAIR *request,
309                             VALUE_PAIR *check, VALUE_PAIR *check_pairs,
310                             VALUE_PAIR **reply_pairs)
311 {
312         struct cmp *c;
313
314         /*
315          *      Check for =* and !* and return appropriately
316          */
317         if (check->op == T_OP_CMP_TRUE)  return 0;
318         if (check->op == T_OP_CMP_FALSE) return 1;
319
320         /*
321          *      See if there is a special compare function.
322          *
323          *      FIXME: use new RB-Tree code.
324          */
325         for (c = cmp; c; c = c->next) {
326                 if (!check->da->vendor && (c->attribute == check->da->attr)) {
327                         return (c->compare)(c->instance, req, request, check,
328                                 check_pairs, reply_pairs);
329                 }
330         }
331
332         if (!request) return -1; /* doesn't exist, don't compare it */
333
334         return radius_compare_vps(req, check, request);
335 }
336
337
338 /** Find a comparison function for two attributes.
339  *
340  * @param attribute
341  */
342 int radius_find_compare(unsigned int attribute)
343 {
344         struct cmp *c;
345
346         for (c = cmp; c; c = c->next) {
347                 if (c->attribute == attribute) {
348                         return TRUE;
349                 }
350         }
351
352         return FALSE;
353 }
354
355
356 /** See what attribute we want to compare with.
357  *
358  * @param attribute
359  */
360 static int otherattr(unsigned int attribute)
361 {
362         struct cmp *c;
363
364         for (c = cmp; c; c = c->next) {
365                 if (c->attribute == attribute) {
366                         return c->otherattr;
367                 }
368         }
369
370         return attribute;
371 }
372
373 /** Register a function as compare function.
374  *
375  * @param attribute
376  * @param other_attr we want to compare with. Normally this is the
377  *      same as attribute.
378  * You can set this to:
379  *      - -1    The same as attribute.
380  *      - 0     Always call compare function, not tied to request attribute.
381  *      - >0    Attribute to compare with. For example, PW_GROUP in a check
382  *              item needs to be compared with PW_USER_NAME in the incoming request.
383  * @param func comparison function
384  * @param instance argument to comparison function
385  * @return 0
386  */
387 int paircompare_register(unsigned int attribute, int other_attr,
388                          RAD_COMPARE_FUNC func, void *instance)
389 {
390         struct cmp *c;
391
392         paircompare_unregister(attribute, func);
393
394         c = rad_malloc(sizeof(struct cmp));
395
396         c->compare   = func;
397         c->attribute = attribute;
398         c->otherattr = other_attr;
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 attribute to unregister for.
409  * @param func comparison function to remove.
410  * @return Void.
411  */
412 void paircompare_unregister(unsigned int attribute, RAD_COMPARE_FUNC func)
413 {
414         struct cmp *c, *last;
415
416         last = NULL;
417         for (c = cmp; c; c = c->next) {
418                 if (c->attribute == attribute && c->compare == func) {
419                         break;
420                 }
421                 last = c;
422         }
423
424         if (c == NULL) return;
425
426         if (last != NULL) {
427                 last->next = c->next;
428         } else {
429                 cmp = c->next;
430         }
431
432         free(c);
433 }
434
435 /** Unregister comparison function for a module
436  *
437  *  All paircompare() functions for this module will be unregistered.
438  *
439  * @param instance the module instance
440  * @return Void.
441  */
442 void paircompare_unregister_instance(void *instance)
443 {
444         struct cmp *c, **tail;
445
446         tail = &cmp;
447         while ((c = *tail) != NULL) {
448                 if (c->instance == instance) {
449                         *tail = c->next;
450                         free(c);
451                         continue;
452                 }
453
454                 tail = &(c->next);
455         }
456 }
457
458 /** Compare two pair lists except for the password information.
459  *
460  * For every element in "check" at least one matching copy must be present
461  * in "reply".
462  *
463  * @param[in] request Current request.
464  * @param[in] req_list request valuepairs.
465  * @param[in] check Check/control valuepairs.
466  * @param[in,out] rep_list Reply value pairs.
467  *
468  * @return 0 on match.
469  */
470 int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
471                 VALUE_PAIR **rep_list)
472 {
473         VALUE_PAIR *check_item;
474         VALUE_PAIR *auth_item;
475         
476         int result = 0;
477         int compare;
478         int other;
479
480         for (check_item = check;
481              check_item != NULL;
482              check_item = check_item->next) {
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                                 break;
506
507                         /*
508                          *      IF the password attribute exists, THEN
509                          *      we can do comparisons against it.  If not,
510                          *      then the request did NOT contain a
511                          *      User-Password attribute, so we CANNOT do
512                          *      comparisons against it.
513                          *
514                          *      This hack makes CHAP-Password work..
515                          */
516                         case PW_USER_PASSWORD:
517                                 if (check_item->op == T_OP_CMP_EQ) {
518                                         DEBUGW("Found User-Password == \"...\".");
519                                         DEBUGW("Are you sure you don't mean Cleartext-Password?");
520                                         DEBUGW("See \"man rlm_pap\" for more information.");
521                                 }
522                                 if (pairfind(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
523                                         continue;
524                                 }
525                                 break;
526                 }
527
528                 /*
529                  *      See if this item is present in the request.
530                  */
531                 other = otherattr(check_item->da->attr);
532
533                 auth_item = req_list;
534         try_again:
535                 if (other >= 0) {
536                         while (auth_item != NULL) {
537                                 if ((auth_item->da->attr ==
538                                     (unsigned int) other) ||
539                                     (other == 0)) {
540                                         break;
541                                 }
542                                 auth_item = auth_item->next;
543                         }
544                 }
545
546                 /*
547                  *      Not found, it's not a match.
548                  */
549                 if (auth_item == NULL) {
550                         /*
551                          *      Didn't find it.  If we were *trying*
552                          *      to not find it, then we succeeded.
553                          */
554                         if (check_item->op == T_OP_CMP_FALSE) {
555                                 continue;
556                         } else {
557                                 return -1;
558                         }
559                 }
560
561                 /*
562                  *      Else we found it, but we were trying to not
563                  *      find it, so we failed.
564                  */
565                 if (check_item->op == T_OP_CMP_FALSE) {
566                         return -1;
567                 }
568
569
570                 /*
571                  *      We've got to xlat the string before doing
572                  *      the comparison.
573                  */
574                 radius_xlat_do(request, check_item);
575
576                 /*
577                  *      OK it is present now compare them.
578                  */
579                 compare = radius_callback_compare(request, auth_item,
580                                                   check_item, check, rep_list);
581
582                 switch (check_item->op) {
583                         case T_OP_EQ:
584                         default:
585                                 radlog(L_INFO, "Invalid operator for item %s: "
586                                        "reverting to '=='", check_item->da->name);
587                                 /* FALL-THROUGH */
588                         case T_OP_CMP_TRUE:
589                         case T_OP_CMP_FALSE:
590                         case T_OP_CMP_EQ:
591                                 if (compare != 0) result = -1;
592                                 break;
593
594                         case T_OP_NE:
595                                 if (compare == 0) result = -1;
596                                 break;
597
598                         case T_OP_LT:
599                                 if (compare >= 0) result = -1;
600                                 break;
601
602                         case T_OP_GT:
603                                 if (compare <= 0) result = -1;
604                                 break;
605
606                         case T_OP_LE:
607                                 if (compare > 0) result = -1;
608                                 break;
609
610                         case T_OP_GE:
611                                 if (compare < 0) result = -1;
612                                 break;
613
614 #ifdef HAVE_REGEX_H
615                         case T_OP_REG_EQ:
616                         case T_OP_REG_NE:
617                                 if (compare != 0) result = -1;
618                                 break;
619 #endif
620                 } /* switch over the operator of the check item */
621
622                 /*
623                  *      This attribute didn't match, but maybe there's
624                  *      another of the same attribute, which DOES match.
625                  */
626                 if ((result != 0) && (other >= 0)) {
627                         auth_item = auth_item->next;
628                         result = 0;
629                         goto try_again;
630                 }
631
632         } /* for every entry in the check item list */
633
634         return result;
635 }
636
637 /** Expands an attribute marked with pairmark_xlat
638  *
639  * Writes the new value to the vp.
640  *
641  * @param request Current request.
642  * @param vp to expand.
643  * @return 0 if successful else -1 (on xlat failure) or -2 (on parse failure).
644  *      On failure pair will still no longer be marked for xlat expansion.
645  */
646 int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
647 {
648         ssize_t len;
649         
650         char buffer[1024];
651         
652         if (vp->type != VT_XLAT) return 0;
653         
654         vp->type = VT_DATA;
655         
656         len = radius_xlat(buffer, sizeof(buffer), request, vp->value.xlat, NULL, NULL);
657
658
659         rad_const_free(vp->value.xlat);
660         vp->value.xlat = NULL;
661         if (len < 0) {
662                 return -1;
663         }
664         
665         /*
666          *      Parse the string into a new value.
667          */
668         if (!pairparsevalue(vp, buffer)){
669                 return -2;
670         }
671         
672         return 0;
673 }
674
675 /** Move pairs, replacing/over-writing them, and doing xlat.
676  *
677  * Move attributes from one list to the other if not already present.
678  */
679 void radius_xlat_move(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR **from)
680 {
681         VALUE_PAIR **tailto, *i, *j, *next;
682         VALUE_PAIR *tailfrom = NULL;
683         VALUE_PAIR *found;
684
685         /*
686          *      Point "tailto" to the end of the "to" list.
687          */
688         tailto = to;
689         for (i = *to; i; i = i->next) {
690                 tailto = &i->next;
691         }
692
693         /*
694          *      Loop over the "from" list.
695          */
696         for (i = *from; i; i = next) {
697                 next = i->next;
698
699                 /*
700                  *      Don't move 'fallthrough' over.
701                  */
702                 if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
703                         tailfrom = i;
704                         continue;
705                 }
706
707                 /*
708                  *      We've got to xlat the string before moving
709                  *      it over.
710                  */
711                 radius_xlat_do(request, i);
712                 
713                 found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
714                 switch (i->op) {
715
716                         /*
717                          *      If a similar attribute is found,
718                          *      delete it.
719                          */
720                         case T_OP_SUB:          /* -= */
721                                 if (found) {
722                                         if (!i->vp_strvalue[0] ||
723                                             (strcmp((char *)found->vp_strvalue,
724                                                     (char *)i->vp_strvalue) == 0)) {
725                                                 pairdelete(to, found->da->attr,
726                                                         found->da->vendor,
727                                                         found->tag);
728
729                                         /*
730                                          *      'tailto' may have been
731                                          *      deleted...
732                                          */
733                                         tailto = to;
734                                         for (j = *to; j; j = j->next) {
735                                                 tailto = &j->next;
736                                         }
737                                 }
738                         }
739                         tailfrom = i;
740                         continue;
741                         break;
742
743                         /*
744                          *      Add it, if it's not already there.
745                          */
746                         case T_OP_EQ:           /* = */
747                                 if (found) {
748                                         tailfrom = i;
749                                         continue; /* with the loop */
750                                 }
751                                 break;
752
753                         /*
754                          *      If a similar attribute is found,
755                          *      replace it with the new one.  Otherwise,
756                          *      add the new one to the list.
757                          */
758                         case T_OP_SET:          /* := */
759                                 if (found) {
760                                         VALUE_PAIR *vp;
761
762                                         vp = found->next;
763                                         memcpy(found, i, sizeof(*found));
764                                         found->next = vp;
765                                         tailfrom = i;
766                                         continue;
767                                 }
768                                 break;
769
770                         /*
771                          *      FIXME: Add support for <=, >=, <, >
772                          *
773                          *      which will mean (for integers)
774                          *      'make the attribute the smaller, etc'
775                          */
776
777                         /*
778                          *  Add the new element to the list, even
779                          *  if similar ones already exist.
780                          */
781                         default:
782                         case T_OP_ADD:          /* += */
783                                 break;
784                 }
785
786                 if (tailfrom) {
787                         tailfrom->next = next;
788                 } else {
789                         *from = next;
790                 }
791
792                 /*
793                  *      If ALL of the 'to' attributes have been deleted,
794                  *      then ensure that the 'tail' is updated to point
795                  *      to the head.
796                  */
797                 if (!*to) {
798                         tailto = to;
799                 }
800                 *tailto = i;
801                 if (i) {
802                         i->next = NULL;
803                         tailto = &i->next;
804                 }
805         } /* loop over the 'from' list */
806 }
807
808 /** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
809  *
810  * @note This function ALWAYS returns. If we're OOM, then it causes the
811  * @note server to exit, so you don't need to check the return value.
812  *
813  * @param[in] request Current request.
814  * @param[out] vps List to add new VALUE_PAIR to, if NULL will just
815  *      return VALUE_PAIR.
816  * @param[in] attribute number.
817  * @param[in] vendor number.
818  * @return a new VLAUE_PAIR or causes server to exit on error.
819  */
820 VALUE_PAIR *radius_paircreate(REQUEST *request, VALUE_PAIR **vps,
821                               unsigned int attribute, unsigned int vendor)
822 {
823         VALUE_PAIR *vp;
824
825         /*
826          *      FIXME: the context should ideally be the packet...
827          */
828         vp = paircreate(request, attribute, vendor);
829         if (!vp) {
830                 ERROR("No memory!");
831                 rad_assert("No memory" == NULL);
832                 _exit(1);
833         }
834
835         if (vps) pairadd(vps, vp);
836
837         return vp;
838 }
839
840 /** Print a single valuepair to stderr or error log.
841  *
842  * @param[in] vp list to print.
843  */
844 void debug_pair(VALUE_PAIR *vp)
845 {
846         if (!vp || !debug_flag || !fr_log_fp) return;
847
848         vp_print(fr_log_fp, vp);
849 }
850
851 /** Print a list of valuepairs to stderr or error log.
852  *
853  * @param[in] vp to print.
854  */
855 void debug_pair_list(VALUE_PAIR *vp)
856 {
857         if (!vp || !debug_flag || !fr_log_fp) return;
858
859         while (vp) {
860                 /*
861                  *      Take this opportunity to verify all the VALUE_PAIRs are still valid.
862                  */
863                 if (!talloc_get_type(vp, VALUE_PAIR)) {
864                         ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
865                         
866                         log_talloc_report(vp);  
867                         rad_assert(0);
868                 }
869                 
870                 vp_print(fr_log_fp, vp);
871                 vp = vp->next;
872         }
873         fflush(fr_log_fp);
874 }
875
876 /** Print a list of valuepairs to the request list.
877  *
878  * @param[in] level Debug level (1-4).
879  * @param[in] request to read logging params from.
880  * @param[in] vp to print.
881  */
882 void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp)
883 {
884         char buffer[256];
885         if (!vp || !request || !request->radlog) return;
886         
887         while (vp) {
888                 /*
889                  *      Take this opportunity to verify all the VALUE_PAIRs are still valid.
890                  */
891                 if (!talloc_get_type(vp, VALUE_PAIR)) {
892                         RDEBUGE("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
893                         
894                         log_talloc_report(vp);  
895                         rad_assert(0);
896                 }
897                 
898                 vp_prints(buffer, sizeof(buffer), vp);
899                 
900                 request->radlog(L_DBG, level, request, "\t%s", buffer);
901                 vp = vp->next;
902         }       
903 }
904
905 /** Resolve attribute pair_lists_t value to an attribute list.
906  *
907  * The value returned is a pointer to the pointer of the HEAD of the list
908  * in the REQUEST. If the head of the list changes, the pointer will still
909  * be valid.
910  *
911  * @param[in] request containing the target lists.
912  * @param[in] list pair_list_t value to resolve to VALUE_PAIR list.
913  *      Will be NULL if list name couldn't be resolved.
914  */
915 VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
916 {       
917         if (!request) return NULL;
918
919         switch (list) {
920                 case PAIR_LIST_UNKNOWN:
921                 default:
922                         break;
923
924                 case PAIR_LIST_REQUEST:
925                         return &request->packet->vps;
926
927                 case PAIR_LIST_REPLY:
928                         return &request->reply->vps;
929
930                 case PAIR_LIST_CONTROL:
931                         return &request->config_items;
932
933 #ifdef WITH_PROXY
934                 case PAIR_LIST_PROXY_REQUEST:
935                         if (!request->proxy) break;
936                         return &request->proxy->vps;
937
938                 case PAIR_LIST_PROXY_REPLY:
939                         if (!request->proxy) break;
940                         return &request->proxy_reply->vps;
941 #endif
942 #ifdef WITH_COA
943                 case PAIR_LIST_COA:
944                         if (request->coa &&
945                             (request->coa->proxy->code == PW_COA_REQUEST)) {
946                                 return &request->coa->proxy->vps;
947                         }
948                         break;
949
950                 case PAIR_LIST_COA_REPLY:
951                         if (request->coa && /* match reply with request */
952                             (request->coa->proxy->code == PW_COA_REQUEST) &&
953                             request->coa->proxy_reply) {
954                                 return &request->coa->proxy_reply->vps;
955                         }
956                         break;
957
958                 case PAIR_LIST_DM:
959                         if (request->coa &&
960                             (request->coa->proxy->code == PW_DISCONNECT_REQUEST)) {
961                                 return &request->coa->proxy->vps;
962                         }
963                         break;
964
965                 case PAIR_LIST_DM_REPLY:
966                         if (request->coa && /* match reply with request */
967                             (request->coa->proxy->code == PW_DISCONNECT_REQUEST) &&
968                             request->coa->proxy_reply) {
969                                 return &request->coa->proxy->vps;
970                         }
971                         break;
972 #endif
973         }
974         
975         RDEBUG2W("List \"%s\" is not available",
976                 fr_int2str(pair_lists, list, "<INVALID>"));
977         
978         return NULL;
979 }
980
981
982 /** Release memory allocated to value pair template.
983  *
984  * @param[in,out] tmpl to free.
985  */
986 void radius_tmplfree(value_pair_tmpl_t **tmpl)
987 {
988         if (*tmpl == NULL) return;
989         
990         dict_attr_free(&((*tmpl)->da));
991         
992         talloc_free(*tmpl);
993         
994         *tmpl = NULL;
995 }
996
997 /** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
998  *
999  * VPTs are used in various places where we need to pre-parse configuration
1000  * sections into attribute mappings.
1001  *
1002  * Note: name field is just a copy of the input pointer, if you know that
1003  * string might be freed before you're done with the vpt use radius_attr2tmpl
1004  * instead.
1005  *
1006  * @param[in] name attribute name including qualifiers.
1007  * @param[out] vpt to modify.
1008  * @param[in] request_def The default request to insert unqualified
1009  *      attributes into.
1010  * @param[in] list_def The default list to insert unqualified attributes into.
1011  * @return -1 on error or 0 on success.
1012  */
1013 int radius_parse_attr(char const *name, value_pair_tmpl_t *vpt,
1014                       request_refs_t request_def,
1015                       pair_lists_t list_def)
1016 {
1017         const DICT_ATTR *da;
1018         char const *p;
1019         size_t len;
1020
1021         memset(vpt, 0, sizeof(*vpt));
1022         vpt->name = name;
1023         p = name;
1024         
1025         vpt->request = radius_request_name(&p, request_def);
1026         len = p - name;
1027         if (vpt->request == REQUEST_UNKNOWN) {
1028                 ERROR("Invalid request qualifier \"%.*s\"", (int) len, name);
1029                 
1030                 return -1;
1031         }
1032         name += len;
1033         
1034         vpt->list = radius_list_name(&p, list_def);
1035         if (vpt->list == PAIR_LIST_UNKNOWN) {
1036                 len = p - name;
1037                 ERROR("Invalid list qualifier \"%.*s\"", (int) len, name);
1038                 
1039                 return -1;
1040         }
1041         
1042         if (*p == '\0') {
1043                 vpt->type = VPT_TYPE_LIST;
1044                 
1045                 return 0;
1046         }
1047         
1048         da = dict_attrbyname(p);
1049         if (!da) {
1050                 da = dict_attrunknownbyname(p, FALSE);
1051                 if (!da) return -1;
1052         }
1053         vpt->da = da;
1054         
1055         vpt->type = VPT_TYPE_ATTR;
1056         
1057         return 0;
1058 }
1059
1060 /** Parse qualifiers to convert attrname into a value_pair_tmpl_t.
1061  *
1062  * VPTs are used in various places where we need to pre-parse configuration
1063  * sections into attribute mappings.
1064  *
1065  * @param[in] ctx for talloc
1066  * @param[in] name attribute name including qualifiers.
1067  * @param[in] request_def The default request to insert unqualified
1068  *      attributes into.
1069  * @param[in] list_def The default list to insert unqualified attributes into.
1070  * @return pointer to a value_pair_tmpl_t struct (must be freed with
1071  *      radius_tmplfree) or NULL on error.
1072  */
1073 value_pair_tmpl_t *radius_attr2tmpl(TALLOC_CTX *ctx, char const *name,
1074                                     request_refs_t request_def,
1075                                     pair_lists_t list_def)
1076 {
1077         value_pair_tmpl_t *vpt;
1078         char const *copy;
1079         
1080         vpt = talloc(ctx, value_pair_tmpl_t); /* parse_attr zeroes it */
1081         copy = talloc_strdup(vpt, name);
1082         
1083         if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) {
1084                 radius_tmplfree(&vpt);
1085                 return NULL;
1086         }
1087         
1088         return vpt;
1089 }
1090
1091 /** Convert module specific attribute id to value_pair_tmpl_t.
1092  *
1093  * @param[in] ctx for talloc
1094  * @param[in] name string to convert.
1095  * @param[in] type Type of quoting around value.
1096  * @return pointer to new VPT.
1097  */
1098 value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type)
1099 {
1100         value_pair_tmpl_t *vpt;
1101         
1102         vpt = talloc_zero(ctx, value_pair_tmpl_t);
1103         vpt->name = talloc_strdup(vpt, name);
1104         
1105         switch (type)
1106         {
1107                 case T_BARE_WORD:
1108                 case T_SINGLE_QUOTED_STRING:
1109                         vpt->type = VPT_TYPE_LITERAL;
1110                         break;
1111                 case T_DOUBLE_QUOTED_STRING:
1112                         vpt->type = VPT_TYPE_XLAT;      
1113                         break;
1114                 case T_BACK_QUOTED_STRING:
1115                         vpt->type = VPT_TYPE_EXEC;
1116                         break;
1117                 default:
1118                         rad_assert(0);
1119                         return NULL;
1120         }
1121         
1122         return vpt;
1123 }
1124
1125 /** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t.
1126  *
1127  * Treats the left operand as an attribute reference
1128  * @verbatim<request>.<list>.<attribute>@endverbatim
1129  *
1130  * Treatment of left operand depends on quotation, barewords are treated as
1131  * attribute references, double quoted values are treated as expandable strings,
1132  * single quoted values are treated as literal strings.
1133  *
1134  * Return must be freed with talloc_free
1135  *
1136  * @param[in] ctx for talloc
1137  * @param[in] cp to convert to map.
1138  * @param[in] dst_request_def The default request to insert unqualified
1139  *      attributes into.
1140  * @param[in] dst_list_def The default list to insert unqualified attributes
1141  *      into.
1142  * @param[in] src_request_def The default request to resolve attribute
1143  *      references in.
1144  * @param[in] src_list_def The default list to resolve unqualified attributes
1145  *      in.
1146  * @return value_pair_map_t if successful or NULL on error.
1147  */
1148 value_pair_map_t *radius_cp2map(TALLOC_CTX *ctx, CONF_PAIR *cp,
1149                                 request_refs_t dst_request_def,
1150                                 pair_lists_t dst_list_def,
1151                                 request_refs_t src_request_def,
1152                                 pair_lists_t src_list_def)
1153 {
1154         value_pair_map_t *map;
1155         char const *attr;
1156         char const *value;
1157         FR_TOKEN type;
1158         CONF_ITEM *ci = cf_pairtoitem(cp);
1159         
1160         if (!cp) return NULL;
1161         
1162         map = talloc_zero(ctx, value_pair_map_t);
1163
1164         attr = cf_pair_attr(cp);
1165         value = cf_pair_value(cp);
1166         if (!value) {
1167                 cf_log_err(ci, "Missing attribute value");
1168                 
1169                 goto error;
1170         }
1171         
1172         map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def);
1173         if (!map->dst){
1174                 goto error;
1175         }
1176
1177         /*
1178          *      Bare words always mean attribute references.
1179          */
1180         type = cf_pair_value_type(cp);
1181         if (type == T_BARE_WORD) {
1182                 if (*value == '&') {
1183                         map->src = radius_attr2tmpl(map, value + 1, src_request_def, src_list_def);
1184
1185                 } else {
1186                         if (!isdigit((int) *value)) {
1187                                 map->src = radius_attr2tmpl(map, value, src_request_def, src_list_def);
1188                         }
1189                         if (map->src) {
1190                                 DEBUGW("%s[%d]: Please add '&' for attribute reference '%s = &%s'",
1191                                        cf_pair_filename(cp), cf_pair_lineno(cp),
1192                                        attr, value);
1193                         } else {
1194                                 map->src = radius_str2tmpl(map, value, type);
1195                         }
1196                 }
1197         } else {
1198                 map->src = radius_str2tmpl(map, value, type);
1199         }
1200
1201         if (!map->src) {
1202                 goto error;
1203         }
1204
1205         map->op = cf_pair_operator(cp);
1206         map->ci = ci;
1207         
1208         /*
1209          *      Lots of sanity checks for insane people...
1210          */
1211         
1212         /*
1213          *      We don't support implicit type conversion
1214          */
1215         if (map->dst->da && map->src->da &&
1216             (map->src->da->type != map->dst->da->type)) {
1217                 cf_log_err(ci, "Attribute type mismatch");
1218                 
1219                 goto error;
1220         }
1221         
1222         /*
1223          *      What exactly where you expecting to happen here?
1224          */
1225         if ((map->dst->type == VPT_TYPE_ATTR) &&
1226             (map->src->type == VPT_TYPE_LIST)) {
1227                 cf_log_err(ci, "Can't copy list into an attribute");
1228                 
1229                 goto error;
1230         }
1231
1232         /*
1233          *      Depending on the attribute type, some operators are
1234          *      disallowed.
1235          */
1236         if (map->dst->type == VPT_TYPE_ATTR) {
1237                 if ((map->op != T_OP_EQ) &&
1238                     (map->op != T_OP_CMP_EQ) &&
1239                     (map->op != T_OP_ADD) &&
1240                     (map->op != T_OP_SUB) &&
1241                     (map->op != T_OP_LE) &&
1242                     (map->op != T_OP_GE) &&
1243                     (map->op != T_OP_CMP_FALSE) &&
1244                     (map->op != T_OP_SET)) {
1245                         cf_log_err(ci, "Invalid operator for attribute");
1246                         goto error;
1247                 }
1248         }
1249
1250         switch (map->src->type)
1251         {
1252         
1253                 /*
1254                  *      Only += and -= operators are supported for list copy.
1255                  */
1256                 case VPT_TYPE_LIST:
1257                         switch (map->op) {
1258                         case T_OP_SUB:
1259                         case T_OP_ADD:
1260                                 break;
1261                         
1262                         default:
1263                                 cf_log_err(ci, "Operator \"%s\" not allowed "
1264                                            "for list copy",
1265                                            fr_int2str(fr_tokens, map->op,
1266                                                       "?unknown?"));
1267                                 goto error;
1268                         }
1269                 break;
1270
1271                 /*
1272                  *      @todo add support for exec expansion.
1273                  */
1274                 case VPT_TYPE_EXEC:
1275                         cf_log_err(ci, "Exec values are not allowed");
1276                         break;
1277
1278                 default:
1279                         break;
1280         }
1281         
1282         return map;
1283         
1284 error:
1285         talloc_free(map);
1286         return NULL;
1287 }
1288
1289 /** Convert an 'update' config section into an attribute map.
1290  *
1291  * Uses 'name2' of section to set default request and lists.
1292  *
1293  * @param[in] cs the update section
1294  * @param[out] head Where to store the head of the map.
1295  * @param[in] dst_list_def The default destination list, usually dictated by
1296  *      the section the module is being called in.
1297  * @param[in] src_list_def The default source list, usually dictated by the
1298  *      section the module is being called in.
1299  * @param[in] max number of mappings to process.
1300  * @return -1 on error, else 0.
1301  */
1302 int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head,
1303                    pair_lists_t dst_list_def, pair_lists_t src_list_def,
1304                    unsigned int max)
1305 {
1306         char const *cs_list, *p;
1307
1308         request_refs_t request_def = REQUEST_CURRENT;
1309
1310         CONF_ITEM *ci;
1311         CONF_PAIR *cp;
1312
1313         unsigned int total = 0;
1314         value_pair_map_t **tail, *map;
1315         TALLOC_CTX *ctx;
1316
1317         *head = NULL;
1318         tail = head;
1319
1320         if (!cs) return 0;
1321
1322         /*
1323          *      The first map has cs as the parent.
1324          *      The rest have the previous map as the parent.
1325          */
1326         ctx = cs;
1327
1328         ci = cf_sectiontoitem(cs);
1329         
1330         cs_list = p = cf_section_name2(cs);
1331         if (cs_list) {
1332                 request_def = radius_request_name(&p, REQUEST_UNKNOWN);
1333                 if (request_def == REQUEST_UNKNOWN) {
1334                         cf_log_err(ci, "Default request specified "
1335                                    "in mapping section is invalid");
1336                         return -1;
1337                 }
1338                 
1339                 dst_list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
1340                 if (dst_list_def == PAIR_LIST_UNKNOWN) {
1341                         cf_log_err(ci, "Default list \"%s\" specified "
1342                                    "in mapping section is invalid", p);
1343                         return -1;
1344                 }
1345         }
1346
1347         for (ci = cf_item_find_next(cs, NULL);
1348              ci != NULL;
1349              ci = cf_item_find_next(cs, ci)) {
1350                 if (total++ == max) {
1351                         cf_log_err(ci, "Map size exceeded");
1352                         goto error;
1353                 }
1354                 
1355                 if (!cf_item_is_pair(ci)) {
1356                         cf_log_err(ci, "Entry is not in \"attribute = "
1357                                        "value\" format");
1358                         goto error;
1359                 }
1360         
1361                 cp = cf_itemtopair(ci);
1362                 map = radius_cp2map(ctx, cp, request_def, dst_list_def,
1363                                     REQUEST_CURRENT, src_list_def);
1364                 if (!map) {
1365                         goto error;
1366                 }
1367                 
1368                 ctx = *tail = map;
1369                 tail = &(map->next);
1370         }
1371
1372         return 0;
1373         
1374 error:
1375         talloc_free(head);
1376         return -1;
1377 }
1378
1379
1380 /** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
1381  *
1382  * Takes a single value_pair_map_t, resolves request and list identifiers
1383  * to pointers in the current request, then attempts to retrieve module
1384  * specific value(s) using callback, and adds the resulting values to the
1385  * correct request/list.
1386  *
1387  * @param request The current request.
1388  * @param map specifying destination attribute and location and src identifier.
1389  * @param func to retrieve module specific values and convert them to
1390  *      VALUE_PAIRS.
1391  * @param ctx to be passed to func.
1392  * @param src name to be used in debugging if different from map value.
1393  * @return -1 if either attribute or qualifier weren't valid in this context
1394  *      or callback returned NULL pointer, else 0.
1395  */
1396 int radius_map2request(REQUEST *request, value_pair_map_t const *map,
1397                        UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
1398 {
1399         VALUE_PAIR **list, *vp, *head;
1400         char buffer[MAX_STRING_LEN];
1401         
1402         if (radius_request(&request, map->dst->request) < 0) {
1403                 RDEBUGW("Mapping \"%s\" -> \"%s\" "
1404                        "invalid in this context, skipping!",
1405                        map->src->name, map->dst->name);
1406                 
1407                 return -1;
1408         }
1409         
1410         list = radius_list(request, map->dst->list);
1411         if (!list) {
1412                 RDEBUGW("Mapping \"%s\" -> \"%s\" "
1413                        "invalid in this context, skipping!",
1414                        map->src->name, map->dst->name);
1415                 
1416                 return -1;
1417         }
1418         
1419         head = func(request, map, ctx);
1420         if (head == NULL) {
1421                 return -1;
1422         }
1423
1424         if (debug_flag) for (vp = head; vp != NULL; vp = vp->next) {
1425                  rad_assert(vp->op == map->op);
1426
1427                  vp_prints_value(buffer, sizeof(buffer), vp, 1);
1428
1429                  RDEBUG("\t\t%s %s %s", map->dst->name,
1430                         fr_int2str(fr_tokens, vp->op, "?unknown?"),
1431                         buffer);
1432         }
1433         
1434         /*
1435          *      Use pairmove so the operator is respected
1436          */
1437         radius_pairmove(request, list, head);
1438         return 0;
1439 }
1440
1441 /** Convert a map to a VALUE_PAIR.
1442  *
1443  * @param[in] request structure (used only for talloc)
1444  * @param[in] map the map.  The LHS has to be VPT_TYPE_ATTR.
1445  * @param[in] ctx unused
1446  * @return the newly allocated VALUE_PAIR
1447  */
1448 VALUE_PAIR *radius_map2vp(REQUEST *request, value_pair_map_t const *map,
1449                           UNUSED void *ctx)
1450 {
1451         VALUE_PAIR *vp, *found, **from = NULL;
1452         REQUEST *context;
1453
1454         rad_assert(request != NULL);
1455         rad_assert(map != NULL);
1456         rad_assert(map->dst->type == VPT_TYPE_ATTR);
1457         rad_assert(map->dst->da != NULL);
1458
1459         vp = pairalloc(request, map->dst->da);
1460         if (!vp) return NULL;
1461
1462         vp->op = map->op;
1463
1464         /*
1465          *      And parse the RHS
1466          */
1467         switch (map->src->type) {
1468         case VPT_TYPE_XLAT:
1469                 /*
1470                  *      Don't call unnecessary expansions
1471                  */
1472                 if (strchr(map->src->name, '%') != NULL) {
1473                         ssize_t slen;
1474                         char *str = NULL;
1475
1476                         slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
1477                         if (slen < 0) goto error;
1478                         
1479                         if (!pairparsevalue(vp, str)) {
1480                                 pairfree(&vp);
1481                         }
1482                         talloc_free(str);
1483                         break;
1484                 }
1485                 /* FALL-THROUGH */
1486
1487         case VPT_TYPE_LITERAL:
1488                 if (!pairparsevalue(vp, map->src->name)) goto error;
1489                 break;
1490
1491         case VPT_TYPE_ATTR:
1492                 rad_assert(map->src->da->type == map->dst->da->type);
1493                 context = request;
1494
1495                 if (radius_request(&context, map->src->request) == 0) {
1496                         from = radius_list(context, map->src->list);
1497                 }
1498
1499                 /*
1500                  *      Can't add the attribute if the list isn't
1501                  *      valid.
1502                  */
1503                 if (!from) goto error;
1504
1505                 /*
1506                  *      FIXME: allow tag references?
1507                  */
1508                 found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
1509                 if (!found) {
1510                         RDEBUGW("\"%s\" not found, skipping",
1511                                 map->src->name);
1512                         goto error;
1513                 }
1514
1515                 /*
1516                  *      Copy the data over verbatim, assuming it's
1517                  *      actually data.
1518                  */
1519                 rad_assert(found->type == VT_DATA);
1520                 memcpy(&vp->data, &found->data, found->length);
1521                 vp->length = found->length;
1522                 break;
1523
1524         default:
1525                 rad_assert(0 == 1);
1526         error:
1527                 pairfree(&vp);
1528                 break;
1529         }
1530
1531         return vp;
1532 }
1533
1534
1535 /** Convert a valuepair string to VALUE_PAIR and insert it into a list
1536  *
1537  * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
1538  * and inserts it into the appropriate list.
1539  *
1540  * @param request Current request.
1541  * @param raw string to parse.
1542  * @param request_def to use if attribute isn't qualified.
1543  * @param list_def to use if attribute isn't qualified.
1544  * @return 0 on success, -1 on error.
1545  */
1546 int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def)
1547 {
1548         char const *p;
1549         size_t len;
1550         request_refs_t req;
1551         pair_lists_t list;
1552         
1553         VALUE_PAIR *vp = NULL;
1554         VALUE_PAIR **vps;
1555         
1556         p = raw;
1557         
1558         req = radius_request_name(&p, request_def);
1559         len = p - raw;
1560         if (req == REQUEST_UNKNOWN) {
1561                 RDEBUGE("Invalid request qualifier \"%.*s\"", (int) len, raw);
1562                 
1563                 return -1;
1564         }
1565         raw += len;
1566         
1567         list = radius_list_name(&p, list_def);
1568         if (list == PAIR_LIST_UNKNOWN) {
1569                 len = p - raw;
1570                                 
1571                 RDEBUGE("Invalid list qualifier \"%.*s\"", (int) len, raw);
1572                 
1573                 return -1;
1574         }
1575         raw += len;
1576
1577         if (radius_request(&request, req) < 0) {
1578                 return -1;
1579         }
1580         
1581         vps = radius_list(request, list);
1582         if (!vps) {
1583                 return -1;
1584         }
1585         
1586         if (userparse(request, raw, &vp) == T_OP_INVALID) {
1587                 return -1;
1588         }
1589         
1590         pairmove(request, vps, &vp);
1591         
1592         return 0;
1593 }
1594
1595 /** Return a VP from the specified request.
1596  *
1597  * @param request current request.
1598  * @param name attribute name including qualifiers.
1599  * @param vp_p where to write the pointer to the resolved VP.
1600  *      Will be NULL if the attribute couldn't be resolved.
1601  * @return -1 if either the attribute or qualifier were invalid, else 0
1602  */
1603 int radius_get_vp(REQUEST *request, char const *name, VALUE_PAIR **vp_p)
1604 {
1605         value_pair_tmpl_t vpt;
1606         VALUE_PAIR **vps;
1607
1608         *vp_p = NULL;
1609         
1610         if (radius_parse_attr(name, &vpt, REQUEST_CURRENT,
1611             PAIR_LIST_REQUEST) < 0) {
1612                 return -1;
1613         }
1614         
1615         if (radius_request(&request, vpt.request) < 0) {
1616                 return 0;
1617         }
1618         
1619         vps = radius_list(request, vpt.list);
1620         if (!vps) {
1621                 return 0;
1622         }
1623         
1624         switch (vpt.type)
1625         {
1626         /*
1627          *      May not may not be found, but it *is* a known name.
1628          */
1629         case VPT_TYPE_ATTR:
1630                 *vp_p = pairfind(*vps, vpt.da->attr, vpt.da->vendor, TAG_ANY);
1631                 break;
1632                 
1633         case VPT_TYPE_LIST:
1634                 *vp_p = *vps;
1635                 break;
1636                 
1637         default:
1638                 rad_assert(0);
1639                 return -1;
1640                 break;
1641         }
1642
1643         return 0;
1644 }
1645
1646 /** Add a module failure message VALUE_PAIR to the request
1647  */
1648 void module_failure_msg(REQUEST *request, char const *fmt, ...)
1649 {
1650         size_t len;
1651         va_list ap;
1652         VALUE_PAIR *vp;
1653
1654         va_start(ap, fmt);
1655         vp = paircreate(request->packet, PW_MODULE_FAILURE_MESSAGE, 0);
1656         if (!vp) {
1657                 va_end(ap);
1658                 return;
1659         }
1660
1661         len = snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%s: ", request->module);
1662         
1663 DIAG_OFF(format-nonliteral)
1664         vsnprintf(vp->vp_strvalue + len, sizeof(vp->vp_strvalue) - len, fmt, ap);
1665 DIAG_ON(format-nonliteral)
1666         pairadd(&request->packet->vps, vp);
1667 }