backport from HEAD
[freeradius.git] / src / lib / valuepair.c
1 /*
2  * valuepair.c  Functions to handle VALUE_PAIRs
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  */
22
23 static const char rcsid[] = "$Id$";
24
25 #include        "autoconf.h"
26
27 #include        <sys/types.h>
28
29 #include        <stdio.h>
30 #include        <stdlib.h>
31 #include        <string.h>
32 #include        <ctype.h>
33
34 #include        "libradius.h"
35
36 #ifdef HAVE_MALLOC_H
37 #  include      <malloc.h>
38 #endif
39
40 #ifdef HAVE_REGEX_H
41 #  include      <regex.h>
42 #endif
43
44 #include        "missing.h"
45
46 static const char *months[] = {
47         "jan", "feb", "mar", "apr", "may", "jun",
48         "jul", "aug", "sep", "oct", "nov", "dec" };
49
50
51 /*
52  *      Create a new valuepair.
53  */
54 VALUE_PAIR *paircreate(int attr, int type)
55 {
56         VALUE_PAIR      *vp;
57         DICT_ATTR       *da;
58
59         if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
60                 librad_log("out of memory");
61                 return NULL;
62         }
63         memset(vp, 0, sizeof(VALUE_PAIR));
64         vp->attribute = attr;
65         vp->operator = T_OP_EQ;
66         vp->type = type;
67
68         /*
69          *      Dictionary type over-rides what the caller says.
70          */
71         if ((da = dict_attrbyvalue(attr)) != NULL) {
72                 strcpy(vp->name, da->name);
73                 vp->type = da->type;
74                 vp->flags = da->flags;
75         } else if (VENDOR(attr) == 0) {
76                 sprintf(vp->name, "Attr-%u", attr);
77         } else {
78                 DICT_VENDOR *v;
79
80                 v = dict_vendorbyvalue(VENDOR(attr));
81                 if (v) {
82                         sprintf(vp->name, "%s-Attr-%u",
83                                 v->name, attr & 0xffff);
84                 } else {
85                         sprintf(vp->name, "Vendor-%u-Attr-%u",
86                                 VENDOR(attr), attr & 0xffff);
87                 }
88         }
89         switch (vp->type) {
90                 case PW_TYPE_INTEGER:
91                 case PW_TYPE_IPADDR:
92                 case PW_TYPE_DATE:
93                         vp->length = 4;
94                         break;
95                 default:
96                         vp->length = 0;
97                         break;
98         }
99
100         return vp;
101 }
102
103 /*
104  *      release the memory used by a single attribute-value pair
105  *      just a wrapper around free() for now.
106  */
107 void pairbasicfree(VALUE_PAIR *pair)
108 {
109         /* clear the memory here */
110         memset(pair, 0, sizeof(*pair));
111         free(pair);
112 }
113
114 /*
115  *      Release the memory used by a list of attribute-value
116  *      pairs, and sets the pair pointer to NULL.
117  */
118 void pairfree(VALUE_PAIR **pair_ptr)
119 {
120         VALUE_PAIR      *next, *pair;
121
122         if (!pair_ptr) return;
123         pair = *pair_ptr;
124
125         while (pair != NULL) {
126                 next = pair->next;
127                 pairbasicfree(pair);
128                 pair = next;
129         }
130
131         *pair_ptr = NULL;
132 }
133
134
135 /*
136  *      Find the pair with the matching attribute
137  */
138 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
139 {
140         while(first && first->attribute != attr)
141                 first = first->next;
142         return first;
143 }
144
145
146 /*
147  *      Delete the pair(s) with the matching attribute
148  */
149 void pairdelete(VALUE_PAIR **first, int attr)
150 {
151         VALUE_PAIR *i, *next;
152         VALUE_PAIR **last = first;
153
154         for(i = *first; i; i = next) {
155                 next = i->next;
156                 if (i->attribute == attr) {
157                         *last = next;
158                         pairbasicfree(i);
159                 } else {
160                         last = &i->next;
161                 }
162         }
163 }
164
165 /*
166  *      Add a pair at the end of a VALUE_PAIR list.
167  */
168 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
169 {
170         VALUE_PAIR *i;
171
172         if (*first == NULL) {
173                 *first = add;
174                 return;
175         }
176         for(i = *first; i->next; i = i->next)
177                 ;
178         i->next = add;
179 }
180
181 /*
182  *      Add or replace a pair at the end of a VALUE_PAIR list.
183  */
184 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
185 {
186         VALUE_PAIR *i, *next;
187         VALUE_PAIR **prev = first;
188
189         if (*first == NULL) {
190                 *first = replace;
191                 return;
192         }
193
194         /*
195          *      Not an empty list, so find item if it is there, and
196          *      replace it. Note, we always replace the first one, and
197          *      we ignore any others that might exist.
198          */
199         for(i = *first; i; i = next) {
200                 next = i->next;
201
202                 /*
203                  *      Found the first attribute, replace it,
204                  *      and return.
205                  */
206                 if (i->attribute == replace->attribute) {
207                         *prev = replace;
208
209                         /*
210                          *      Should really assert that replace->next == NULL
211                          */
212                         replace->next = next;
213                         pairbasicfree(i);
214                         return;
215                 }
216
217                 /*
218                  *      Point to where the attribute should go.
219                  */
220                 prev = &i->next;
221         }
222
223         /*
224          *      If we got here, we didn't find anything to replace, so
225          *      stopped at the last item, which we just append to.
226          */
227         *prev = replace;
228 }
229
230 /*
231  *      Copy just a certain type of pairs.
232  */
233 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
234 {
235         VALUE_PAIR      *first, *n, **last;
236
237         first = NULL;
238         last = &first;
239
240         while (vp) {
241                 if (attr >= 0 && vp->attribute != attr) {
242                         vp = vp->next;
243                         continue;
244                 }
245                 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
246                         librad_log("out of memory");
247                         return first;
248                 }
249                 memcpy(n, vp, sizeof(VALUE_PAIR));
250                 n->next = NULL;
251                 *last = n;
252                 last = &n->next;
253                 vp = vp->next;
254         }
255         return first;
256 }
257
258
259 /*
260  *      Copy a pairlist.
261  */
262 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
263 {
264         return paircopy2(vp, -1);
265 }
266
267
268 /*
269  *      Move attributes from one list to the other
270  *      if not already present.
271  */
272 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
273 {
274         VALUE_PAIR **tailto, *i, *j, *next;
275         VALUE_PAIR *tailfrom = NULL;
276         VALUE_PAIR *found;
277         int has_password = 0;
278
279         if (*to == NULL) {
280                 *to = *from;
281                 *from = NULL;
282                 return;
283         }
284
285         /*
286          *      First, see if there are any passwords here, and
287          *      point "tailto" to the end of the "to" list.
288          */
289         tailto = to;
290         for(i = *to; i; i = i->next) {
291                 if (i->attribute == PW_PASSWORD ||
292                     i->attribute == PW_CRYPT_PASSWORD)
293                         has_password = 1;
294                 tailto = &i->next;
295         }
296
297         /*
298          *      Loop over the "from" list.
299          */
300         for(i = *from; i; i = next) {
301                 next = i->next;
302                 /*
303                  *      If there was a password in the "to" list,
304                  *      do not move any other password from the
305                  *      "from" to the "to" list.
306                  */
307                 if (has_password &&
308                     (i->attribute == PW_PASSWORD ||
309                      i->attribute == PW_CRYPT_PASSWORD)) {
310                         tailfrom = i;
311                         continue;
312                 }
313                 /*
314                  *      If the attribute is already present in "to",
315                  *      do not move it from "from" to "to". We make
316                  *      an exception for "Hint" which can appear multiple
317                  *      times, and we never move "Fall-Through".
318                  */
319                 if (i->attribute == PW_FALL_THROUGH ||
320                     (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
321
322                         found = pairfind(*to, i->attribute);
323                         switch (i->operator) {
324
325                           /*
326                            *  If a similar attribute is found,
327                            *  delete it.
328                            */
329                         case T_OP_SUB:          /* -= */
330                                 if (found) {
331                                         if (!i->strvalue[0] ||
332                                             (strcmp((char *)found->strvalue,
333                                                     (char *)i->strvalue) == 0)){
334                                                 pairdelete(to, found->attribute);
335
336                                                 /*
337                                                  *      'tailto' may have been
338                                                  *      deleted...
339                                                  */
340                                                 tailto = to;
341                                                 for(j = *to; j; j = j->next) {
342                                                         tailto = &j->next;
343                                                 }
344                                         }
345                                 }
346                                 tailfrom = i;
347                                 continue;
348                                 break;
349
350 /* really HAVE_REGEX_H */
351 #if 0
352                                 /*
353                                  *  Attr-Name =~ "s/find/replace/"
354                                  *
355                                  *  Very bad code.  Barely working,
356                                  *  if at all.
357                                  */
358
359                         case T_OP_REG_EQ:
360                           if (found &&
361                               (i->strvalue[0] == 's')) {
362                             regex_t             reg;
363                             regmatch_t          match[1];
364
365                             char *str;
366                             char *p, *q;
367
368                             p = i->strvalue + 1;
369                             q = strchr(p + 1, *p);
370                             if (!q || (q[strlen(q) - 1] != *p)) {
371                               tailfrom = i;
372                               continue;
373                             }
374                             str = strdup(i->strvalue + 2);
375                             q = strchr(str, *p);
376                             *(q++) = '\0';
377                             q[strlen(q) - 1] = '\0';
378
379                             regcomp(&reg, str, 0);
380                             if (regexec(&reg, found->strvalue,
381                                         1, match, 0) == 0) {
382                               fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
383                                       found->strvalue, match[0].rm_so,
384                                       match[0].rm_eo, q);
385
386                             }
387                             regfree(&reg);
388                             free(str);
389                           }
390                           tailfrom = i; /* don't copy it over */
391                           continue;
392                           break;
393 #endif
394                         case T_OP_EQ:           /* = */
395                                 /*
396                                  *  FIXME: Tunnel attributes with
397                                  *  different tags are different
398                                  *  attributes.
399                                  */
400                                 if (found) {
401                                         tailfrom = i;
402                                         continue; /* with the loop */
403                                 }
404                                 break;
405
406                           /*
407                            *  If a similar attribute is found,
408                            *  replace it with the new one.  Otherwise,
409                            *  add the new one to the list.
410                            */
411                         case T_OP_SET:          /* := */
412                                 if (found) {
413                                         pairdelete(to, found->attribute);
414                                         /*
415                                          *      'tailto' may have been
416                                          *      deleted...
417                                          */
418                                         tailto = to;
419                                         for(j = *to; j; j = j->next) {
420                                                 tailto = &j->next;
421                                         }
422                                 }
423                                 break;
424
425                           /*
426                            *  Add the new element to the list, even
427                            *  if similar ones already exist.
428                            */
429                         default:
430                         case T_OP_ADD: /* += */
431                                 break;
432                         }
433                 }
434                 if (tailfrom)
435                         tailfrom->next = next;
436                 else
437                         *from = next;
438
439                 /*
440                  *      If ALL of the 'to' attributes have been deleted,
441                  *      then ensure that the 'tail' is updated to point
442                  *      to the head.
443                  */
444                 if (!*to) {
445                         tailto = to;
446                 }
447                 *tailto = i;
448                 if (i) {
449                         i->next = NULL;
450                         tailto = &i->next;
451                 }
452         }
453 }
454
455 /*
456  *      Move one kind of attributes from one list to the other
457  */
458 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
459 {
460         VALUE_PAIR *to_tail, *i, *next;
461         VALUE_PAIR *iprev = NULL;
462
463         /*
464          *      Find the last pair in the "to" list and put it in "to_tail".
465          */
466         if (*to != NULL) {
467                 to_tail = *to;
468                 for(i = *to; i; i = i->next)
469                         to_tail = i;
470         } else
471                 to_tail = NULL;
472
473         for(i = *from; i; i = next) {
474                 next = i->next;
475
476
477                 /*
478                  *      If the attribute to move is NOT a VSA, then it
479                  *      ignores any attributes which do not match exactly.
480                  */
481                 if ((attr != PW_VENDOR_SPECIFIC) &&
482                     (i->attribute != attr)) {
483                         iprev = i;
484                         continue;
485                 }
486
487                 /*
488                  *      If the attribute to move IS a VSA, then it ignores
489                  *      any non-VSA attribute.
490                  */
491                 if ((attr == PW_VENDOR_SPECIFIC) &&
492                     (VENDOR(i->attribute) == 0)) {
493                         iprev = i;
494                         continue;
495                 }
496
497                 /*
498                  *      Remove the attribute from the "from" list.
499                  */
500                 if (iprev)
501                         iprev->next = next;
502                 else
503                         *from = next;
504
505                 /*
506                  *      Add the attribute to the "to" list.
507                  */
508                 if (to_tail)
509                         to_tail->next = i;
510                 else
511                         *to = i;
512                 to_tail = i;
513                 i->next = NULL;
514         }
515 }
516
517
518 /*
519  *      Sort of strtok/strsep function.
520  */
521 static char *mystrtok(char **ptr, const char *sep)
522 {
523         char    *res;
524
525         if (**ptr == 0)
526                 return NULL;
527         while (**ptr && strchr(sep, **ptr))
528                 (*ptr)++;
529         if (**ptr == 0)
530                 return NULL;
531         res = *ptr;
532         while (**ptr && strchr(sep, **ptr) == NULL)
533                 (*ptr)++;
534         if (**ptr != 0)
535                 *(*ptr)++ = 0;
536         return res;
537 }
538
539 /*
540  *      Turn printable string into time_t
541  *      Returns -1 on error, 0 on OK.
542  */
543 static int gettime(const char *valstr, time_t *lvalue)
544 {
545         int             i;
546         time_t          t;
547         struct tm       *tm, s_tm;
548         char            buf[64];
549         char            *p;
550         char            *f[4];
551         char            *tail = '\0';
552
553         /*
554          * Test for unix timestamp date
555          */
556         *lvalue = strtoul(valstr, &tail, 10);
557         if (*tail == '\0') {
558                 return 0;
559         }
560
561         tm = &s_tm;
562         memset(tm, 0, sizeof(*tm));
563         tm->tm_isdst = -1;      /* don't know, and don't care about DST */
564
565         strNcpy(buf, valstr, sizeof(buf));
566
567         p = buf;
568         f[0] = mystrtok(&p, " \t");
569         f[1] = mystrtok(&p, " \t");
570         f[2] = mystrtok(&p, " \t");
571         f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
572         if (!f[0] || !f[1] || !f[2]) return -1;
573
574         /*
575          *  The month is text, which allows us to find it easily.
576          */
577         tm->tm_mon = 12;
578         for (i = 0; i < 3; i++) {
579                 if (isalpha( (int) *f[i])) {
580                         /*
581                          *  Bubble the month to the front of the list
582                          */
583                         p = f[0];
584                         f[0] = f[i];
585                         f[i] = p;
586
587                         for (i = 0; i < 12; i++) {
588                                 if (strncasecmp(months[i], f[0], 3) == 0) {
589                                         tm->tm_mon = i;
590                                         break;
591                                 }
592                         }
593                 }
594         }
595
596         /* month not found? */
597         if (tm->tm_mon == 12) return -1;
598
599         /*
600          *  The year may be in f[1], or in f[2]
601          */
602         tm->tm_year = atoi(f[1]);
603         tm->tm_mday = atoi(f[2]);
604
605         if (tm->tm_year >= 1900) {
606                 tm->tm_year -= 1900;
607
608         } else {
609                 /*
610                  *  We can't use 2-digit years any more, they make it
611                  *  impossible to tell what's the day, and what's the year.
612                  */
613                 if (tm->tm_mday < 1900) return -1;
614
615                 /*
616                  *  Swap the year and the day.
617                  */
618                 i = tm->tm_year;
619                 tm->tm_year = tm->tm_mday - 1900;
620                 tm->tm_mday = i;
621         }
622
623         /*
624          *  If the day is out of range, die.
625          */
626         if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
627                 return -1;
628         }
629
630         /*
631          *      There may be %H:%M:%S.  Parse it in a hacky way.
632          */
633         if (f[3]) {
634                 f[0] = f[3];    /* HH */
635                 f[1] = strchr(f[0], ':'); /* find : separator */
636                 if (!f[1]) return -1;
637
638                 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
639
640                 f[2] = strchr(f[1], ':'); /* find : separator */
641                 if (!f[2]) return -1;
642                 *(f[2]++) = '\0';       /* nuke it, and point to SS */
643
644                 tm->tm_hour = atoi(f[0]);
645                 tm->tm_min = atoi(f[1]);
646                 tm->tm_sec = atoi(f[2]);
647         }
648
649         /*
650          *  Returns -1 on error.
651          */
652         t = mktime(tm);
653         if (t == (time_t) -1) return -1;
654
655         *lvalue = t;
656
657         return 0;
658 }
659
660 /*
661  *  Parse a string value into a given VALUE_PAIR
662  */
663 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
664 {
665         char            *p, *s=0;
666         const char      *cp, *cs;
667         DICT_VALUE      *dval;
668
669         /*
670          *      Even for integers, dates and ip addresses we
671          *      keep the original string in vp->strvalue.
672          */
673         strNcpy((char *)vp->strvalue, value, sizeof(vp->strvalue));
674         vp->length = strlen(vp->strvalue);
675
676         switch(vp->type) {
677                 case PW_TYPE_STRING:
678                         /*
679                          *      Already handled above.
680                          */
681                         break;
682
683                 case PW_TYPE_IPADDR:
684                         /*
685                          *      FIXME: complain if hostname
686                          *      cannot be resolved, or resolve later!
687                          */
688                         if ((p = strrchr(value, '+')) != NULL && !p[1]) {
689                                 cs = s = strdup(value);
690                                 p = strrchr(s, '+');
691                                 *p = 0;
692                                 vp->flags.addport = 1;
693                         } else {
694                                 p = NULL;
695                                 cs = value;
696                         }
697                         vp->lvalue = librad_dodns ? ip_getaddr(cs) :
698                                                     ip_addr(cs);
699                         if (s) free(s);
700                         vp->length = 4;
701                         break;
702                 case PW_TYPE_INTEGER:
703                         /*
704                          *      If it starts with a digit, it must
705                          *      be a number (or a range).
706                          *
707                          *      Note that ALL integers are unsigned!
708                          */
709                         if (isdigit((int) *value)) {
710                                 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
711                                 vp->length = 4;
712                         }
713                         /*
714                          *      Look for the named value for the given
715                          *      attribute.
716                          */
717                         else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
718                                 librad_log("Unknown value %s for attribute %s",
719                                            value, vp->name);
720                                 return NULL;
721                         } else {
722                                 vp->lvalue = dval->value;
723                                 vp->length = 4;
724                         }
725                         break;
726
727                 case PW_TYPE_DATE:
728                         if (gettime(value, (time_t *)&vp->lvalue) < 0) {
729                                 librad_log("failed to parse time string "
730                                            "\"%s\"", value);
731                                 return NULL;
732                         }
733                         vp->length = 4;
734                         break;
735                 case PW_TYPE_ABINARY:
736 #ifdef ASCEND_BINARY
737                         /*
738                          *      Special case to convert filter to binary
739                          */
740                         strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
741                         if (ascend_parse_filter(vp) < 0 ) {
742                                 librad_log("failed to parse Ascend binary attribute: %s",
743                                            librad_errstr);
744                                 return NULL;
745                         }
746                         break;
747                         /*
748                          *      If Ascend binary is NOT defined,
749                          *      then fall through to raw octets, so that
750                          *      the user can at least make them by hand...
751                          */
752 #endif
753                         /* raw octets: 0x01020304... */
754                 case PW_TYPE_OCTETS:
755                         if (strncasecmp(value, "0x", 2) == 0) {
756                                 u_char *us;
757                                 cp = value + 2;
758                                 us = vp->strvalue;
759                                 vp->length = 0;
760
761
762                                 /*
763                                  *      There is only one character,
764                                  *      die.
765                                  */
766                                 if ((strlen(cp) & 0x01) != 0) {
767                                         librad_log("Hex string is not an even length string.");
768                                         return NULL;
769                                 }
770                                 
771                                 
772                                 while (*cp && vp->length < MAX_STRING_LEN) {
773                                         unsigned int tmp;
774
775                                         if (sscanf(cp, "%02x", &tmp) != 1) {
776                                                 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
777                                                 return NULL;
778                                         }
779
780                                         cp += 2;
781                                         *(us++) = tmp;
782                                         vp->length++;
783                                 }
784                                 *us = '\0';
785                         }
786                         break;
787
788                 case PW_TYPE_IFID:
789                         if (ifid_aton(value, vp->strvalue) == NULL) {
790                                 librad_log("failed to parse interface-id "
791                                            "string \"%s\"", value);
792                                 return NULL;
793                         }
794                         vp->length = 8;
795                         vp->strvalue[vp->length] = '\0';
796                         break;
797
798                 case PW_TYPE_IPV6ADDR:
799                         if (ipv6_addr(value, vp->strvalue) < 0) {
800                                 librad_log("failed to parse IPv6 address "
801                                            "string \"%s\"", value);
802                                 return NULL;
803                         }
804                         vp->length = 16; /* length of IPv6 address */
805                         vp->strvalue[vp->length] = '\0';
806                         break;
807                         /*
808                          *  Anything else.
809                          */
810                 default:
811                         librad_log("unknown attribute type %d", vp->type);
812                         return NULL;
813         }
814
815         return vp;
816 }
817
818 /*
819  *      Create a VALUE_PAIR from an ASCII attribute and value,
820  *      where the attribute name is in the form:
821  *
822  *      Attr-%d
823  *      Vendor-%d-Attr-%d
824  */
825 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
826                                 int operator)
827 {
828         int             attr;
829         const char      *p;
830         VALUE_PAIR      *vp;
831         DICT_ATTR       *da;
832
833         /*
834          *      Unknown attributes MUST be of type 'octets'
835          */
836         if (value && (strncasecmp(value, "0x", 2) != 0)) {
837                 goto error;
838         }
839
840         /*
841          *      Attr-%d
842          */
843         if (strncasecmp(attribute, "Attr-", 5) == 0) {
844                 attr = atoi(attribute + 5);
845                 p = attribute + 5;
846                 p += strspn(p, "0123456789");
847                 if (*p != 0) goto error;
848
849
850                 /*
851                  *      Vendor-%d-Attr-%d
852                  */
853         } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
854                 int vendor;
855
856                 vendor = atoi(attribute + 7);
857                 if ((vendor == 0) || (vendor > 65535)) goto error;
858
859                 p = attribute + 7;
860                 p += strspn(p, "0123456789");
861
862                 /*
863                  *      Not Vendor-%d-Attr-%d
864                  */
865                 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
866
867                 p += 6;
868                 attr = atoi(p);
869
870                 p += strspn(p, "0123456789");
871                 if (*p != 0) goto error;
872
873                 if ((attr == 0) || (attr > 65535)) goto error;
874
875                 attr |= (vendor << 16);
876
877                 /*
878                  *      VendorName-Attr-%d
879                  */
880         } else if (((p = strchr(attribute, '-')) != NULL) &&
881                    (strncasecmp(p, "-Attr-", 6) == 0)) {
882                 int vendor;
883                 char buffer[256];
884
885                 if ((p - attribute) >= sizeof(buffer)) goto error;
886
887                 memcpy(buffer, attribute, p - attribute);
888                 buffer[p - attribute] = '\0';
889
890                 vendor = dict_vendorbyname(buffer);
891                 if (vendor == 0) goto error;
892
893                 p += 6;
894                 attr = atoi(p);
895
896                 p += strspn(p, "0123456789");
897                 if (*p != 0) goto error;
898
899                 if ((attr == 0) || (attr > 65535)) goto error;
900
901                 attr |= (vendor << 16);
902
903         } else {                /* very much unknown: die */
904         error:
905                 librad_log("Unknown attribute \"%s\"", attribute);
906                 return NULL;
907         }
908
909         /*
910          *      We've now parsed the attribute properly, and verified
911          *      it to have value 'octets'.  Let's create it.
912          */
913         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
914                 librad_log("out of memory");
915                 return NULL;
916         }
917         memset(vp, 0, sizeof(VALUE_PAIR));
918         vp->type = PW_TYPE_OCTETS;
919
920         /*
921          *      It may not be valid hex characters.  If not, die.
922          */
923         if (pairparsevalue(vp, value) == NULL) {
924                 pairfree(&vp);
925                 return NULL;
926         }
927
928         /*
929          *      Dictionary type over-rides what the caller says.
930          *      This "converts" the parsed value into the appropriate
931          *      type.
932          *
933          *      Also, normalize the name of the attribute...
934          *
935          *      Much of this code is copied from paircreate()
936          */
937         if ((da = dict_attrbyvalue(attr)) != NULL) {
938                 strcpy(vp->name, da->name);
939                 vp->type = da->type;
940                 vp->flags = da->flags;
941
942                 /*
943                  *      Sanity check the type for length.  We don't
944                  *      want to look at attributes which are of the
945                  *      wrong length.
946                  */
947                 switch (vp->type) {
948                 case PW_TYPE_DATE:
949                 case PW_TYPE_INTEGER:
950                 case PW_TYPE_IPADDR: /* always kept in network byte order */
951                         if (vp->length != 4) {
952                         length_error:
953                                 pairfree(&vp);
954                                 librad_log("Attribute has invalid length");
955                                 return NULL;
956                         }
957                         memcpy(&vp->lvalue, vp->strvalue, sizeof(vp->lvalue));
958                         break;
959
960                 case PW_TYPE_IFID:
961                         if (vp->length != 8) goto length_error;
962                         break;
963
964                 case PW_TYPE_IPV6ADDR:
965                         if (vp->length != 16) goto length_error;
966                         break;
967
968 #ifdef ASCEND_BINARY
969                 case PW_TYPE_ABINARY:
970                         if (vp->length != 32) goto length_error;
971                         break;
972 #endif
973                 default:        /* string, octets, etc. */
974                         break;
975                 }
976
977         } else if (VENDOR(attr) == 0) {
978                 sprintf(vp->name, "Attr-%u", attr);
979         } else {
980                 sprintf(vp->name, "Vendor-%u-Attr-%u",
981                         VENDOR(attr), attr & 0xffff);
982         }
983
984         vp->attribute = attr;
985         vp->operator = (operator == 0) ? T_OP_EQ : operator;
986         vp->next = NULL;
987
988         return vp;
989 }
990
991
992 /*
993  *      Create a VALUE_PAIR from an ASCII attribute and value.
994  */
995 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
996 {
997         DICT_ATTR       *da;
998         VALUE_PAIR      *vp;
999         char            *tc, *ts;
1000         signed char     tag;
1001         int             found_tag;
1002 #ifdef HAVE_REGEX_H
1003         int             res;
1004         regex_t         cre;
1005 #endif
1006
1007         /*
1008          *    Check for tags in 'Attribute:Tag' format.
1009          */
1010         found_tag = 0;
1011         tag = 0;
1012
1013         ts = strrchr( attribute, ':' );
1014         if (ts && ts[1]) {
1015                  /* Colon found with something behind it */
1016                  if (ts[1] == '*' && ts[2] == 0) {
1017                          /* Wildcard tag for check items */
1018                          tag = TAG_ANY;
1019                          *ts = 0;
1020                  } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1021                          /* It's not a wild card tag */
1022                          tag = strtol(ts + 1, &tc, 0);
1023                          if (tc && !*tc && TAG_VALID_ZERO(tag))
1024                                  *ts = 0;
1025                          else tag = 0;
1026                  } else {
1027                          librad_log("Invalid tag for attribute %s", attribute);
1028                          return NULL;
1029                  }
1030                  found_tag = 1;
1031         }
1032
1033         /*
1034          *      It's not found in the dictionary, so we use
1035          *      another method to create the attribute.
1036          */
1037         if ((da = dict_attrbyname(attribute)) == NULL) {
1038                 return pairmake_any(attribute, value, operator);
1039         }
1040
1041         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1042                 librad_log("out of memory");
1043                 return NULL;
1044         }
1045
1046         memset(vp, 0, sizeof(VALUE_PAIR));
1047         vp->attribute = da->attr;
1048         vp->type = da->type;
1049         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1050         strcpy(vp->name, da->name);
1051         vp->flags = da->flags;
1052         vp->next = NULL;
1053
1054         /*      Check for a tag in the 'Merit' format of:
1055          *      :Tag:Value.  Print an error if we already found
1056          *      a tag in the Attribute.
1057          */
1058
1059         if (value && (*value == ':' && da->flags.has_tag)) {
1060                 /* If we already found a tag, this is invalid */
1061                 if(found_tag) {
1062                         pairbasicfree(vp);
1063                         librad_log("Duplicate tag %s for attribute %s",
1064                                    value, vp->name);
1065                         DEBUG("Duplicate tag %s for attribute %s\n",
1066                                    value, vp->name);
1067                         return NULL;
1068
1069                 }
1070                 /* Colon found and attribute allows a tag */
1071                 if (value[1] == '*' && value[2] == ':') {
1072                        /* Wildcard tag for check items */
1073                        tag = TAG_ANY;
1074                        value += 3;
1075                 } else {
1076                        /* Real tag */
1077                        tag = strtol(value + 1, &tc, 0);
1078                        if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1079                             value = tc + 1;
1080                        else tag = 0;
1081                 }
1082                 found_tag = 1;
1083         }
1084
1085         if (found_tag) {
1086           vp->flags.tag = tag;
1087         }
1088
1089         switch (vp->operator) {
1090         default:
1091                 break;
1092
1093                 /*
1094                  *      For =* and !* operators, the value is irrelevant
1095                  *      so we return now.
1096                  */
1097         case T_OP_CMP_TRUE:
1098         case T_OP_CMP_FALSE:
1099                 vp->strvalue[0] = '\0';
1100                 vp->length = 0;
1101                 return vp;
1102                 break;
1103
1104                 /*
1105                  *      Regular expression comparison of integer attributes
1106                  *      does a STRING comparison of the names of their
1107                  *      integer attributes.
1108                  */
1109         case T_OP_REG_EQ:       /* =~ */
1110         case T_OP_REG_NE:       /* !~ */
1111                 if (vp->type == PW_TYPE_INTEGER) {
1112                         return vp;
1113                 }
1114 #ifdef HAVE_REGEX_H
1115                 /*
1116                  *      Regular expression match with no regular
1117                  *      expression is wrong.
1118                  */
1119                 if (!value) {
1120                         pairfree(&vp);
1121                         return NULL;
1122                 }
1123
1124                 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1125                 if (res != 0) {
1126                         char    msg[128];
1127
1128                         regerror(res, &cre, msg, sizeof(msg));
1129                         librad_log("Illegal regular expression in attribute: %s: %s",
1130                                 vp->name, msg);
1131                         pairbasicfree(vp);
1132                         return NULL;
1133                 }
1134                 regfree(&cre);
1135 #else
1136                 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1137                                 vp->name);
1138                 pairbasicfree(vp);
1139                 return NULL;
1140 #endif
1141         }
1142
1143         if (value && (pairparsevalue(vp, value) == NULL)) {
1144                 pairbasicfree(vp);
1145                 return NULL;
1146         }
1147
1148         return vp;
1149 }
1150
1151 /*
1152  *      Read a valuepair from a buffer, and advance pointer.
1153  *      Sets *eol to T_EOL if end of line was encountered.
1154  */
1155 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1156 {
1157         char            buf[64];
1158         char            attr[64];
1159         char            value[256];
1160         char            *p;
1161         LRAD_TOKEN      token, t, xlat;
1162         VALUE_PAIR      *vp;
1163
1164         *eol = T_INVALID;
1165
1166         /* Get attribute. */
1167         token = gettoken(ptr, attr, sizeof(attr));
1168
1169         /*  If it's a comment, then exit, as we haven't read a pair */
1170         if (token == T_HASH) {
1171                 *eol = token;
1172                 librad_log("Read a comment instead of a token");
1173                 return NULL;
1174         }
1175
1176         /*  It's not a comment, so it MUST be an attribute */
1177         if ((token == T_EOL) ||
1178             (attr[0] == 0)) {
1179                 librad_log("No token read where we expected an attribute name");
1180                 return NULL;
1181         }
1182
1183         /* Now we should have an '=' here. */
1184         token = gettoken(ptr, buf, sizeof(buf));
1185         if (token < T_EQSTART || token > T_EQEND) {
1186                 librad_log("expecting '='");
1187                 return NULL;
1188         }
1189
1190         /* Read value.  Note that empty string values are allowed */
1191         xlat = gettoken(ptr, value, sizeof(value));
1192         if (xlat == T_EOL) {
1193                 librad_log("failed to get value");
1194                 return NULL;
1195         }
1196
1197         /*
1198          *      Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1199          */
1200         p = *ptr;
1201         t = gettoken(&p, buf, sizeof(buf));
1202         if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1203                 librad_log("Expected end of line or comma");
1204                 return NULL;
1205         }
1206
1207         *eol = t;
1208         if (t == T_COMMA) {
1209                 *ptr = p;
1210         }
1211
1212         switch (xlat) {
1213                 /*
1214                  *      Make the full pair now.
1215                  */
1216         default:
1217                 vp = pairmake(attr, value, token);
1218                 break;
1219
1220                 /*
1221                  *      Perhaps do xlat's
1222                  */
1223         case T_DOUBLE_QUOTED_STRING:
1224                 p = strchr(value, '%');
1225                 if (p && (p[1] == '{')) {
1226                         vp = pairmake(attr, NULL, token);
1227                         if (!vp) {
1228                                 *eol = T_INVALID;
1229                                 return NULL;
1230                         }
1231
1232                         strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
1233                         vp->flags.do_xlat = 1;
1234                         vp->length = 0;
1235                 } else {
1236                         vp = pairmake(attr, value, token);
1237                 }
1238                 break;
1239
1240
1241                 /*
1242                  *      Mark the pair to be allocated later.
1243                  */
1244         case T_BACK_QUOTED_STRING:
1245                 vp = pairmake(attr, NULL, token);
1246                 if (!vp) {
1247                         *eol = T_INVALID;
1248                         return NULL;
1249                 }
1250
1251                 vp->flags.do_xlat = 1;
1252                 strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
1253                 vp->length = 0;
1254                 break;
1255         }
1256
1257         return vp;
1258 }
1259
1260 /*
1261  *      Read one line of attribute/value pairs. This might contain
1262  *      multiple pairs seperated by comma's.
1263  */
1264 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1265 {
1266         VALUE_PAIR      *vp;
1267         char            *p;
1268         LRAD_TOKEN      last_token = T_INVALID;
1269         LRAD_TOKEN      previous_token;
1270
1271         /*
1272          *      We allow an empty line.
1273          */
1274         if (buffer[0] == 0)
1275                 return T_EOL;
1276
1277         p = buffer;
1278         do {
1279                 previous_token = last_token;
1280                 if ((vp = pairread(&p, &last_token)) == NULL) {
1281                         return last_token;
1282                 }
1283                 pairadd(first_pair, vp);
1284         } while (*p && (last_token == T_COMMA));
1285
1286         /*
1287          *      Don't tell the caller that there was a comment.
1288          */
1289         if (last_token == T_HASH) {
1290                 return previous_token;
1291         }
1292
1293         /*
1294          *      And return the last token which we read.
1295          */
1296         return last_token;
1297 }
1298
1299 /*
1300  *      Read valuepairs from the fp up to End-Of-File.
1301  *
1302  *      Hmm... this function is only used by radclient..
1303  */
1304 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1305 {
1306         char buf[8192];
1307         LRAD_TOKEN last_token = T_EOL;
1308         VALUE_PAIR *vp;
1309         VALUE_PAIR *list;
1310         int error = 0;
1311
1312         list = NULL;
1313
1314         while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1315                 /*
1316                  *      If we get a '\n' by itself, we assume that's
1317                  *      the end of that VP
1318                  */
1319                 if ((buf[0] == '\n') && (list)) {
1320                         return list;
1321                 }
1322                 if ((buf[0] == '\n') && (!list)) {
1323                         continue;
1324                 }
1325
1326                 /*
1327                  *      Comments get ignored
1328                  */
1329                 if (buf[0] == '#') continue;
1330
1331                 /*
1332                  *      Read all of the attributes on the current line.
1333                  */
1334                 vp = NULL;
1335                 last_token = userparse(buf, &vp);
1336                 if (!vp) {
1337                         if (last_token != T_EOL) {
1338                                 librad_perror(errprefix);
1339                                 error = 1;
1340                                 break;
1341                         }
1342                         break;
1343                 }
1344
1345                 pairadd(&list, vp);
1346                 buf[0] = '\0';
1347         }
1348
1349         if (error) pairfree(&list);
1350
1351         *pfiledone = 1;
1352
1353         return error ? NULL: list;
1354 }
1355