import 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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                         if (strncasecmp(value, "0x", 2) == 0) {
738                                 vp->type = PW_TYPE_OCTETS;
739                                 goto do_octets;
740                         }                       
741
742                         /*
743                          *      Special case to convert filter to binary
744                          */
745                         strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
746                         if (ascend_parse_filter(vp) < 0 ) {
747                           fprintf(stderr, "FUCK %s\n", value);
748                                 librad_log("failed to parse Ascend binary attribute: %s",
749                                            librad_errstr);
750                                 return NULL;
751                         }
752                         break;
753
754                         /*
755                          *      If Ascend binary is NOT defined,
756                          *      then fall through to raw octets, so that
757                          *      the user can at least make them by hand...
758                          */
759         do_octets:
760 #endif
761                         /* raw octets: 0x01020304... */
762                 case PW_TYPE_OCTETS:
763                         if (strncasecmp(value, "0x", 2) == 0) {
764                                 uint8_t *us;
765                                 cp = value + 2;
766                                 us = vp->strvalue;
767                                 vp->length = 0;
768
769
770                                 /*
771                                  *      There is only one character,
772                                  *      die.
773                                  */
774                                 if ((strlen(cp) & 0x01) != 0) {
775                                         librad_log("Hex string is not an even length string.");
776                                         return NULL;
777                                 }
778                                 
779                                 
780                                 while (*cp && vp->length < MAX_STRING_LEN) {
781                                         unsigned int tmp;
782
783                                         if (sscanf(cp, "%02x", &tmp) != 1) {
784                                                 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
785                                                 return NULL;
786                                         }
787
788                                         cp += 2;
789                                         *(us++) = tmp;
790                                         vp->length++;
791                                 }
792                                 *us = '\0';
793                         }
794                         break;
795
796                 case PW_TYPE_IFID:
797                         if (ifid_aton(value, vp->strvalue) == NULL) {
798                                 librad_log("failed to parse interface-id "
799                                            "string \"%s\"", value);
800                                 return NULL;
801                         }
802                         vp->length = 8;
803                         vp->strvalue[vp->length] = '\0';
804                         break;
805
806                 case PW_TYPE_IPV6ADDR:
807                         if (ipv6_addr(value, vp->strvalue) < 0) {
808                                 librad_log("failed to parse IPv6 address "
809                                            "string \"%s\"", value);
810                                 return NULL;
811                         }
812                         vp->length = 16; /* length of IPv6 address */
813                         vp->strvalue[vp->length] = '\0';
814                         break;
815                         /*
816                          *  Anything else.
817                          */
818                 default:
819                         librad_log("unknown attribute type %d", vp->type);
820                         return NULL;
821         }
822
823         return vp;
824 }
825
826 /*
827  *      Create a VALUE_PAIR from an ASCII attribute and value,
828  *      where the attribute name is in the form:
829  *
830  *      Attr-%d
831  *      Vendor-%d-Attr-%d
832  */
833 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
834                                 int operator)
835 {
836         int             attr;
837         const char      *p;
838         VALUE_PAIR      *vp;
839         DICT_ATTR       *da;
840
841         /*
842          *      Unknown attributes MUST be of type 'octets'
843          */
844         if (value && (strncasecmp(value, "0x", 2) != 0)) {
845                 goto error;
846         }
847
848         /*
849          *      Attr-%d
850          */
851         if (strncasecmp(attribute, "Attr-", 5) == 0) {
852                 attr = atoi(attribute + 5);
853                 p = attribute + 5;
854                 p += strspn(p, "0123456789");
855                 if (*p != 0) goto error;
856
857
858                 /*
859                  *      Vendor-%d-Attr-%d
860                  */
861         } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
862                 int vendor;
863
864                 vendor = atoi(attribute + 7);
865                 if ((vendor == 0) || (vendor > 65535)) goto error;
866
867                 p = attribute + 7;
868                 p += strspn(p, "0123456789");
869
870                 /*
871                  *      Not Vendor-%d-Attr-%d
872                  */
873                 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
874
875                 p += 6;
876                 attr = atoi(p);
877
878                 p += strspn(p, "0123456789");
879                 if (*p != 0) goto error;
880
881                 if ((attr == 0) || (attr > 65535)) goto error;
882
883                 attr |= (vendor << 16);
884
885                 /*
886                  *      VendorName-Attr-%d
887                  */
888         } else if (((p = strchr(attribute, '-')) != NULL) &&
889                    (strncasecmp(p, "-Attr-", 6) == 0)) {
890                 int vendor;
891                 char buffer[256];
892
893                 if ((p - attribute) >= sizeof(buffer)) goto error;
894
895                 memcpy(buffer, attribute, p - attribute);
896                 buffer[p - attribute] = '\0';
897
898                 vendor = dict_vendorbyname(buffer);
899                 if (vendor == 0) goto error;
900
901                 p += 6;
902                 attr = atoi(p);
903
904                 p += strspn(p, "0123456789");
905                 if (*p != 0) goto error;
906
907                 if ((attr == 0) || (attr > 65535)) goto error;
908
909                 attr |= (vendor << 16);
910
911         } else {                /* very much unknown: die */
912         error:
913                 librad_log("Unknown attribute \"%s\"", attribute);
914                 return NULL;
915         }
916
917         /*
918          *      We've now parsed the attribute properly, and verified
919          *      it to have value 'octets'.  Let's create it.
920          */
921         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
922                 librad_log("out of memory");
923                 return NULL;
924         }
925         memset(vp, 0, sizeof(VALUE_PAIR));
926         vp->type = PW_TYPE_OCTETS;
927
928         /*
929          *      It may not be valid hex characters.  If not, die.
930          */
931         if (pairparsevalue(vp, value) == NULL) {
932                 pairfree(&vp);
933                 return NULL;
934         }
935
936         /*
937          *      Dictionary type over-rides what the caller says.
938          *      This "converts" the parsed value into the appropriate
939          *      type.
940          *
941          *      Also, normalize the name of the attribute...
942          *
943          *      Much of this code is copied from paircreate()
944          */
945         if ((da = dict_attrbyvalue(attr)) != NULL) {
946                 strcpy(vp->name, da->name);
947                 vp->type = da->type;
948                 vp->flags = da->flags;
949
950                 /*
951                  *      Sanity check the type for length.  We don't
952                  *      want to look at attributes which are of the
953                  *      wrong length.
954                  */
955                 switch (vp->type) {
956                 case PW_TYPE_DATE:
957                 case PW_TYPE_INTEGER:
958                 case PW_TYPE_IPADDR: /* always kept in network byte order */
959                         if (vp->length != 4) {
960                         length_error:
961                                 pairfree(&vp);
962                                 librad_log("Attribute has invalid length");
963                                 return NULL;
964                         }
965                         memcpy(&vp->lvalue, vp->strvalue, sizeof(vp->lvalue));
966                         break;
967
968                 case PW_TYPE_IFID:
969                         if (vp->length != 8) goto length_error;
970                         break;
971
972                 case PW_TYPE_IPV6ADDR:
973                         if (vp->length != 16) goto length_error;
974                         break;
975
976 #ifdef ASCEND_BINARY
977                 case PW_TYPE_ABINARY:
978                         if (vp->length != 32) goto length_error;
979                         break;
980 #endif
981                 default:        /* string, octets, etc. */
982                         break;
983                 }
984
985         } else if (VENDOR(attr) == 0) {
986                 sprintf(vp->name, "Attr-%u", attr);
987         } else {
988                 sprintf(vp->name, "Vendor-%u-Attr-%u",
989                         VENDOR(attr), attr & 0xffff);
990         }
991
992         vp->attribute = attr;
993         vp->operator = (operator == 0) ? T_OP_EQ : operator;
994         vp->next = NULL;
995
996         return vp;
997 }
998
999
1000 /*
1001  *      Create a VALUE_PAIR from an ASCII attribute and value.
1002  */
1003 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1004 {
1005         DICT_ATTR       *da;
1006         VALUE_PAIR      *vp;
1007         char            *tc, *ts;
1008         signed char     tag;
1009         int             found_tag;
1010 #ifdef HAVE_REGEX_H
1011         int             res;
1012         regex_t         cre;
1013 #endif
1014
1015         /*
1016          *    Check for tags in 'Attribute:Tag' format.
1017          */
1018         found_tag = 0;
1019         tag = 0;
1020
1021         ts = strrchr( attribute, ':' );
1022         if (ts && ts[1]) {
1023                  /* Colon found with something behind it */
1024                  if (ts[1] == '*' && ts[2] == 0) {
1025                          /* Wildcard tag for check items */
1026                          tag = TAG_ANY;
1027                          *ts = 0;
1028                  } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1029                          /* It's not a wild card tag */
1030                          tag = strtol(ts + 1, &tc, 0);
1031                          if (tc && !*tc && TAG_VALID_ZERO(tag))
1032                                  *ts = 0;
1033                          else tag = 0;
1034                  } else {
1035                          librad_log("Invalid tag for attribute %s", attribute);
1036                          return NULL;
1037                  }
1038                  found_tag = 1;
1039         }
1040
1041         /*
1042          *      It's not found in the dictionary, so we use
1043          *      another method to create the attribute.
1044          */
1045         if ((da = dict_attrbyname(attribute)) == NULL) {
1046                 return pairmake_any(attribute, value, operator);
1047         }
1048
1049         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1050                 librad_log("out of memory");
1051                 return NULL;
1052         }
1053
1054         memset(vp, 0, sizeof(VALUE_PAIR));
1055         vp->attribute = da->attr;
1056         vp->type = da->type;
1057         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1058         strcpy(vp->name, da->name);
1059         vp->flags = da->flags;
1060         vp->next = NULL;
1061
1062         /*      Check for a tag in the 'Merit' format of:
1063          *      :Tag:Value.  Print an error if we already found
1064          *      a tag in the Attribute.
1065          */
1066
1067         if (value && (*value == ':' && da->flags.has_tag)) {
1068                 /* If we already found a tag, this is invalid */
1069                 if(found_tag) {
1070                         pairbasicfree(vp);
1071                         librad_log("Duplicate tag %s for attribute %s",
1072                                    value, vp->name);
1073                         DEBUG("Duplicate tag %s for attribute %s\n",
1074                                    value, vp->name);
1075                         return NULL;
1076
1077                 }
1078                 /* Colon found and attribute allows a tag */
1079                 if (value[1] == '*' && value[2] == ':') {
1080                        /* Wildcard tag for check items */
1081                        tag = TAG_ANY;
1082                        value += 3;
1083                 } else {
1084                        /* Real tag */
1085                        tag = strtol(value + 1, &tc, 0);
1086                        if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1087                             value = tc + 1;
1088                        else tag = 0;
1089                 }
1090                 found_tag = 1;
1091         }
1092
1093         if (found_tag) {
1094           vp->flags.tag = tag;
1095         }
1096
1097         switch (vp->operator) {
1098         default:
1099                 break;
1100
1101                 /*
1102                  *      For =* and !* operators, the value is irrelevant
1103                  *      so we return now.
1104                  */
1105         case T_OP_CMP_TRUE:
1106         case T_OP_CMP_FALSE:
1107                 vp->strvalue[0] = '\0';
1108                 vp->length = 0;
1109                 return vp;
1110                 break;
1111
1112                 /*
1113                  *      Regular expression comparison of integer attributes
1114                  *      does a STRING comparison of the names of their
1115                  *      integer attributes.
1116                  */
1117         case T_OP_REG_EQ:       /* =~ */
1118         case T_OP_REG_NE:       /* !~ */
1119                 if (vp->type == PW_TYPE_INTEGER) {
1120                         return vp;
1121                 }
1122 #ifdef HAVE_REGEX_H
1123                 /*
1124                  *      Regular expression match with no regular
1125                  *      expression is wrong.
1126                  */
1127                 if (!value) {
1128                         pairfree(&vp);
1129                         return NULL;
1130                 }
1131
1132                 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1133                 if (res != 0) {
1134                         char    msg[128];
1135
1136                         regerror(res, &cre, msg, sizeof(msg));
1137                         librad_log("Illegal regular expression in attribute: %s: %s",
1138                                 vp->name, msg);
1139                         pairbasicfree(vp);
1140                         return NULL;
1141                 }
1142                 regfree(&cre);
1143 #else
1144                 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1145                                 vp->name);
1146                 pairbasicfree(vp);
1147                 return NULL;
1148 #endif
1149         }
1150
1151         if (value && (pairparsevalue(vp, value) == NULL)) {
1152                 pairbasicfree(vp);
1153                 return NULL;
1154         }
1155
1156         return vp;
1157 }
1158
1159 /*
1160  *      Read a valuepair from a buffer, and advance pointer.
1161  *      Sets *eol to T_EOL if end of line was encountered.
1162  */
1163 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1164 {
1165         char            buf[64];
1166         char            attr[64];
1167         char            value[256];
1168         char            *p;
1169         LRAD_TOKEN      token, t, xlat;
1170         VALUE_PAIR      *vp;
1171
1172         *eol = T_INVALID;
1173
1174         /* Get attribute. */
1175         token = gettoken(ptr, attr, sizeof(attr));
1176
1177         /*  If it's a comment, then exit, as we haven't read a pair */
1178         if (token == T_HASH) {
1179                 *eol = token;
1180                 librad_log("Read a comment instead of a token");
1181                 return NULL;
1182         }
1183
1184         /*  It's not a comment, so it MUST be an attribute */
1185         if ((token == T_EOL) ||
1186             (attr[0] == 0)) {
1187                 librad_log("No token read where we expected an attribute name");
1188                 return NULL;
1189         }
1190
1191         /* Now we should have an '=' here. */
1192         token = gettoken(ptr, buf, sizeof(buf));
1193         if (token < T_EQSTART || token > T_EQEND) {
1194                 librad_log("expecting '='");
1195                 return NULL;
1196         }
1197
1198         /* Read value.  Note that empty string values are allowed */
1199         xlat = gettoken(ptr, value, sizeof(value));
1200         if (xlat == T_EOL) {
1201                 librad_log("failed to get value");
1202                 return NULL;
1203         }
1204
1205         /*
1206          *      Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1207          */
1208         p = *ptr;
1209         t = gettoken(&p, buf, sizeof(buf));
1210         if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1211                 librad_log("Expected end of line or comma");
1212                 return NULL;
1213         }
1214
1215         *eol = t;
1216         if (t == T_COMMA) {
1217                 *ptr = p;
1218         }
1219
1220         switch (xlat) {
1221                 /*
1222                  *      Make the full pair now.
1223                  */
1224         default:
1225                 vp = pairmake(attr, value, token);
1226                 break;
1227
1228                 /*
1229                  *      Perhaps do xlat's
1230                  */
1231         case T_DOUBLE_QUOTED_STRING:
1232                 p = strchr(value, '%');
1233                 if (p && (p[1] == '{')) {
1234                         vp = pairmake(attr, NULL, token);
1235                         if (!vp) {
1236                                 *eol = T_INVALID;
1237                                 return NULL;
1238                         }
1239
1240                         strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
1241                         vp->flags.do_xlat = 1;
1242                         vp->length = 0;
1243                 } else {
1244                         vp = pairmake(attr, value, token);
1245                 }
1246                 break;
1247
1248
1249                 /*
1250                  *      Mark the pair to be allocated later.
1251                  */
1252         case T_BACK_QUOTED_STRING:
1253                 vp = pairmake(attr, NULL, token);
1254                 if (!vp) {
1255                         *eol = T_INVALID;
1256                         return NULL;
1257                 }
1258
1259                 vp->flags.do_xlat = 1;
1260                 strNcpy(vp->strvalue, value, sizeof(vp->strvalue));
1261                 vp->length = 0;
1262                 break;
1263         }
1264
1265         /*
1266          *      If we didn't make a pair, return an error.
1267          */
1268         if (!vp) {
1269                 *eol = T_INVALID;
1270                 return NULL;
1271         }
1272
1273         return vp;
1274 }
1275
1276 /*
1277  *      Read one line of attribute/value pairs. This might contain
1278  *      multiple pairs seperated by comma's.
1279  */
1280 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1281 {
1282         VALUE_PAIR      *vp;
1283         char            *p;
1284         LRAD_TOKEN      last_token = T_INVALID;
1285         LRAD_TOKEN      previous_token;
1286
1287         /*
1288          *      We allow an empty line.
1289          */
1290         if (buffer[0] == 0)
1291                 return T_EOL;
1292
1293         p = buffer;
1294         do {
1295                 previous_token = last_token;
1296                 if ((vp = pairread(&p, &last_token)) == NULL) {
1297                         return last_token;
1298                 }
1299                 pairadd(first_pair, vp);
1300         } while (*p && (last_token == T_COMMA));
1301
1302         /*
1303          *      Don't tell the caller that there was a comment.
1304          */
1305         if (last_token == T_HASH) {
1306                 return previous_token;
1307         }
1308
1309         /*
1310          *      And return the last token which we read.
1311          */
1312         return last_token;
1313 }
1314
1315 /*
1316  *      Read valuepairs from the fp up to End-Of-File.
1317  *
1318  *      Hmm... this function is only used by radclient..
1319  */
1320 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1321 {
1322         char buf[8192];
1323         LRAD_TOKEN last_token = T_EOL;
1324         VALUE_PAIR *vp;
1325         VALUE_PAIR *list;
1326         int error = 0;
1327
1328         list = NULL;
1329
1330         while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1331                 /*
1332                  *      If we get a '\n' by itself, we assume that's
1333                  *      the end of that VP
1334                  */
1335                 if ((buf[0] == '\n') && (list)) {
1336                         return list;
1337                 }
1338                 if ((buf[0] == '\n') && (!list)) {
1339                         continue;
1340                 }
1341
1342                 /*
1343                  *      Comments get ignored
1344                  */
1345                 if (buf[0] == '#') continue;
1346
1347                 /*
1348                  *      Read all of the attributes on the current line.
1349                  */
1350                 vp = NULL;
1351                 last_token = userparse(buf, &vp);
1352                 if (!vp) {
1353                         if (last_token != T_EOL) {
1354                                 librad_perror(errprefix);
1355                                 error = 1;
1356                                 break;
1357                         }
1358                         break;
1359                 }
1360
1361                 pairadd(&list, vp);
1362                 buf[0] = '\0';
1363         }
1364
1365         if (error) pairfree(&list);
1366
1367         *pfiledone = 1;
1368
1369         return error ? NULL: list;
1370 }
1371