Added pairsprintf()
[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                                         WDEBUG("Found User-Password == \"...\".");
519                                         WDEBUG("Are you sure you don't mean Cleartext-Password?");
520                                         WDEBUG("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                                 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                         REDEBUG("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         RWDEBUG2("List \"%s\" is not available",
976                 fr_int2str(pair_lists, list, "<INVALID>"));
977         
978         return NULL;
979 }
980
981 /** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
982  *
983  * Takes a single value_pair_map_t, resolves request and list identifiers
984  * to pointers in the current request, then attempts to retrieve module
985  * specific value(s) using callback, and adds the resulting values to the
986  * correct request/list.
987  *
988  * @param request The current request.
989  * @param map specifying destination attribute and location and src identifier.
990  * @param func to retrieve module specific values and convert them to
991  *      VALUE_PAIRS.
992  * @param ctx to be passed to func.
993  * @param src name to be used in debugging if different from map value.
994  * @return -1 if either attribute or qualifier weren't valid in this context
995  *      or callback returned NULL pointer, else 0.
996  */
997 int radius_map2request(REQUEST *request, value_pair_map_t const *map,
998                        UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
999 {
1000         VALUE_PAIR **list, *vp, *head;
1001         char buffer[MAX_STRING_LEN];
1002         
1003         if (radius_request(&request, map->dst->request) < 0) {
1004                 RWDEBUG("Mapping \"%s\" -> \"%s\" "
1005                        "invalid in this context, skipping!",
1006                        map->src->name, map->dst->name);
1007                 
1008                 return -1;
1009         }
1010         
1011         list = radius_list(request, map->dst->list);
1012         if (!list) {
1013                 RWDEBUG("Mapping \"%s\" -> \"%s\" "
1014                        "invalid in this context, skipping!",
1015                        map->src->name, map->dst->name);
1016                 
1017                 return -1;
1018         }
1019         
1020         head = func(request, map, ctx);
1021         if (head == NULL) {
1022                 return -1;
1023         }
1024
1025         if (debug_flag) for (vp = head; vp != NULL; vp = vp->next) {
1026                  rad_assert(vp->op == map->op);
1027
1028                  vp_prints_value(buffer, sizeof(buffer), vp, 1);
1029
1030                  RDEBUG("\t\t%s %s %s", map->dst->name,
1031                         fr_int2str(fr_tokens, vp->op, "?unknown?"),
1032                         buffer);
1033         }
1034         
1035         /*
1036          *      Use pairmove so the operator is respected
1037          */
1038         radius_pairmove(request, list, head);
1039         return 0;
1040 }
1041
1042 /** Convert a map to a VALUE_PAIR.
1043  *
1044  * @param[in] request structure (used only for talloc)
1045  * @param[in] map the map.  The LHS has to be VPT_TYPE_ATTR.
1046  * @param[in] ctx unused
1047  * @return the newly allocated VALUE_PAIR
1048  */
1049 VALUE_PAIR *radius_map2vp(REQUEST *request, value_pair_map_t const *map,
1050                           UNUSED void *ctx)
1051 {
1052         VALUE_PAIR *vp, *found, **from = NULL;
1053         REQUEST *context;
1054
1055         rad_assert(request != NULL);
1056         rad_assert(map != NULL);
1057         rad_assert(map->dst->type == VPT_TYPE_ATTR);
1058         rad_assert(map->dst->da != NULL);
1059
1060         vp = pairalloc(request, map->dst->da);
1061         if (!vp) return NULL;
1062
1063         vp->op = map->op;
1064
1065         /*
1066          *      And parse the RHS
1067          */
1068         switch (map->src->type) {
1069         case VPT_TYPE_XLAT:
1070                 /*
1071                  *      Don't call unnecessary expansions
1072                  */
1073                 if (strchr(map->src->name, '%') != NULL) {
1074                         ssize_t slen;
1075                         char *str = NULL;
1076
1077                         slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
1078                         if (slen < 0) goto error;
1079                         
1080                         if (!pairparsevalue(vp, str)) {
1081                                 pairfree(&vp);
1082                         }
1083                         talloc_free(str);
1084                         break;
1085                 }
1086                 /* FALL-THROUGH */
1087
1088         case VPT_TYPE_LITERAL:
1089                 if (!pairparsevalue(vp, map->src->name)) goto error;
1090                 break;
1091
1092         case VPT_TYPE_ATTR:
1093                 rad_assert(map->src->da->type == map->dst->da->type);
1094                 context = request;
1095
1096                 if (radius_request(&context, map->src->request) == 0) {
1097                         from = radius_list(context, map->src->list);
1098                 }
1099
1100                 /*
1101                  *      Can't add the attribute if the list isn't
1102                  *      valid.
1103                  */
1104                 if (!from) goto error;
1105
1106                 /*
1107                  *      FIXME: allow tag references?
1108                  */
1109                 found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
1110                 if (!found) {
1111                         RWDEBUG("\"%s\" not found, skipping",
1112                                 map->src->name);
1113                         goto error;
1114                 }
1115
1116                 /*
1117                  *      Copy the data over verbatim, assuming it's
1118                  *      actually data.
1119                  */
1120                 rad_assert(found->type == VT_DATA);
1121                 memcpy(&vp->data, &found->data, found->length);
1122                 vp->length = found->length;
1123                 break;
1124
1125         default:
1126                 rad_assert(0 == 1);
1127         error:
1128                 pairfree(&vp);
1129                 break;
1130         }
1131
1132         return vp;
1133 }
1134
1135
1136 /** Convert a valuepair string to VALUE_PAIR and insert it into a list
1137  *
1138  * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
1139  * and inserts it into the appropriate list.
1140  *
1141  * @param request Current request.
1142  * @param raw string to parse.
1143  * @param request_def to use if attribute isn't qualified.
1144  * @param list_def to use if attribute isn't qualified.
1145  * @return 0 on success, -1 on error.
1146  */
1147 int radius_str2vp(REQUEST *request, char const *raw, request_refs_t request_def, pair_lists_t list_def)
1148 {
1149         char const *p;
1150         size_t len;
1151         request_refs_t req;
1152         pair_lists_t list;
1153         
1154         VALUE_PAIR *vp = NULL;
1155         VALUE_PAIR **vps;
1156         
1157         p = raw;
1158         
1159         req = radius_request_name(&p, request_def);
1160         len = p - raw;
1161         if (req == REQUEST_UNKNOWN) {
1162                 REDEBUG("Invalid request qualifier \"%.*s\"", (int) len, raw);
1163                 
1164                 return -1;
1165         }
1166         raw += len;
1167         
1168         list = radius_list_name(&p, list_def);
1169         if (list == PAIR_LIST_UNKNOWN) {
1170                 len = p - raw;
1171                                 
1172                 REDEBUG("Invalid list qualifier \"%.*s\"", (int) len, raw);
1173                 
1174                 return -1;
1175         }
1176         raw += len;
1177
1178         if (radius_request(&request, req) < 0) {
1179                 return -1;
1180         }
1181         
1182         vps = radius_list(request, list);
1183         if (!vps) {
1184                 return -1;
1185         }
1186         
1187         if (userparse(request, raw, &vp) == T_OP_INVALID) {
1188                 return -1;
1189         }
1190         
1191         pairmove(request, vps, &vp);
1192         
1193         return 0;
1194 }
1195
1196
1197 /** Return a VP from a value_pair_tmpl_t
1198  *
1199  * @param request current request.
1200  * @param vpt the value pair template
1201  * @return NULL if not found, or the VPs.
1202  */
1203 VALUE_PAIR *radius_vpt_get_vp(REQUEST *request, value_pair_tmpl_t const *vpt)
1204 {
1205         VALUE_PAIR **vps;
1206
1207         if (radius_request(&request, vpt->request) < 0) {
1208                 return NULL;
1209         }
1210         
1211         vps = radius_list(request, vpt->list);
1212         if (!vps) {
1213                 return NULL;
1214         }
1215         
1216         switch (vpt->type)
1217         {
1218         /*
1219          *      May not may not be found, but it *is* a known name.
1220          */
1221         case VPT_TYPE_ATTR:
1222                 return pairfind(*vps, vpt->da->attr, vpt->da->vendor, TAG_ANY);
1223                 
1224         case VPT_TYPE_LIST:
1225                 return *vps;
1226                 
1227         default:
1228                 break;
1229         }
1230
1231         return NULL;
1232 }
1233
1234
1235
1236 /** Return a VP from the specified request.
1237  *
1238  * @param request current request.
1239  * @param name attribute name including qualifiers.
1240  * @param vp_p where to write the pointer to the resolved VP.
1241  *      Will be NULL if the attribute couldn't be resolved.
1242  * @return -1 if either the attribute or qualifier were invalid, else 0
1243  */
1244 int radius_get_vp(REQUEST *request, char const *name, VALUE_PAIR **vp_p)
1245 {
1246         value_pair_tmpl_t vpt;
1247
1248         *vp_p = NULL;
1249
1250         if (radius_parse_attr(name, &vpt, REQUEST_CURRENT,
1251             PAIR_LIST_REQUEST) < 0) {
1252                 return -1;
1253         }
1254
1255         *vp_p = radius_vpt_get_vp(request, &vpt);
1256         return 0;
1257 }
1258
1259 /** Add a module failure message VALUE_PAIR to the request
1260  */
1261 DIAG_OFF(format-nonliteral)
1262 void module_failure_msg(REQUEST *request, char const *fmt, ...)
1263 {
1264         size_t len;
1265         va_list ap;
1266         VALUE_PAIR *vp;
1267
1268         va_start(ap, fmt);
1269         vp = paircreate(request->packet, PW_MODULE_FAILURE_MESSAGE, 0);
1270         if (!vp) {
1271                 va_end(ap);
1272                 return;
1273         }
1274
1275         pairsprintf(vp, "%s: ", request->module);
1276         len = vp->length;
1277         
1278         vsnprintf(vp->vp_strvalue + len, sizeof(vp->vp_strvalue) - len, fmt, ap);
1279         pairadd(&request->packet->vps, vp);
1280 }
1281 DIAG_ON(format-nonliteral)