Added support for native "byte" and "short", which are used by
[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        <freeradius-devel/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 #ifdef HAVE_MALLOC_H
35 #  include      <malloc.h>
36 #endif
37
38 #ifdef HAVE_REGEX_H
39 #  include      <regex.h>
40 #endif
41
42 #include        <freeradius-devel/missing.h>
43 #include        <freeradius-devel/libradius.h>
44
45 static const char *months[] = {
46         "jan", "feb", "mar", "apr", "may", "jun",
47         "jul", "aug", "sep", "oct", "nov", "dec" };
48
49
50 /*
51  *      Create a new valuepair.
52  */
53 VALUE_PAIR *paircreate(int attr, int type)
54 {
55         VALUE_PAIR      *vp;
56         DICT_ATTR       *da;
57
58         if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL) {
59                 librad_log("out of memory");
60                 return NULL;
61         }
62         memset(vp, 0, sizeof(VALUE_PAIR));
63         vp->attribute = attr;
64         vp->operator = T_OP_EQ;
65         vp->type = type;
66
67         /*
68          *      Dictionary type over-rides what the caller says.
69          */
70         if ((da = dict_attrbyvalue(attr)) != NULL) {
71                 strcpy(vp->name, da->name);
72                 vp->type = da->type;
73                 vp->flags = da->flags;
74         } else if (VENDOR(attr) == 0) {
75                 sprintf(vp->name, "Attr-%u", attr);
76         } else {
77                 DICT_VENDOR *v;
78
79                 v = dict_vendorbyvalue(VENDOR(attr));
80                 if (v) {
81                         sprintf(vp->name, "%s-Attr-%u",
82                                 v->name, attr & 0xffff);
83                 } else {
84                         sprintf(vp->name, "Vendor-%u-Attr-%u",
85                                 VENDOR(attr), attr & 0xffff);
86                 }
87         }
88         switch (vp->type) {
89                 case PW_TYPE_BYTE:
90                         vp->length = 1;
91                         break;
92
93                 case PW_TYPE_SHORT:
94                         vp->length = 2;
95                         break;
96
97                 case PW_TYPE_INTEGER:
98                 case PW_TYPE_IPADDR:
99                 case PW_TYPE_DATE:
100                         vp->length = 4;
101                         break;
102
103                 case PW_TYPE_IFID:
104                         vp->length = sizeof(vp->vp_ifid);
105                         break;
106
107                 case PW_TYPE_IPV6ADDR:
108                         vp->length = sizeof(vp->vp_ipv6addr);
109                         break;
110
111                 case PW_TYPE_IPV6PREFIX:
112                         vp->length = sizeof(vp->vp_ipv6prefix);
113                         break;
114
115                 default:
116                         vp->length = 0;
117                         break;
118         }
119
120         return vp;
121 }
122
123 /*
124  *      release the memory used by a single attribute-value pair
125  *      just a wrapper around free() for now.
126  */
127 void pairbasicfree(VALUE_PAIR *pair)
128 {
129         /* clear the memory here */
130         memset(pair, 0, sizeof(*pair));
131         free(pair);
132 }
133
134 /*
135  *      Release the memory used by a list of attribute-value
136  *      pairs, and sets the pair pointer to NULL.
137  */
138 void pairfree(VALUE_PAIR **pair_ptr)
139 {
140         VALUE_PAIR      *next, *pair;
141
142         if (!pair_ptr) return;
143         pair = *pair_ptr;
144
145         while (pair != NULL) {
146                 next = pair->next;
147                 pairbasicfree(pair);
148                 pair = next;
149         }
150
151         *pair_ptr = NULL;
152 }
153
154
155 /*
156  *      Find the pair with the matching attribute
157  */
158 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
159 {
160         while(first && first->attribute != attr)
161                 first = first->next;
162         return first;
163 }
164
165
166 /*
167  *      Delete the pair(s) with the matching attribute
168  */
169 void pairdelete(VALUE_PAIR **first, int attr)
170 {
171         VALUE_PAIR *i, *next;
172         VALUE_PAIR **last = first;
173
174         for(i = *first; i; i = next) {
175                 next = i->next;
176                 if (i->attribute == attr) {
177                         *last = next;
178                         pairbasicfree(i);
179                 } else {
180                         last = &i->next;
181                 }
182         }
183 }
184
185 /*
186  *      Add a pair at the end of a VALUE_PAIR list.
187  */
188 void pairadd(VALUE_PAIR **first, VALUE_PAIR *add)
189 {
190         VALUE_PAIR *i;
191
192         if (!add) return;
193
194         if (*first == NULL) {
195                 *first = add;
196                 return;
197         }
198         for(i = *first; i->next; i = i->next)
199                 ;
200         i->next = add;
201 }
202
203 /*
204  *      Add or replace a pair at the end of a VALUE_PAIR list.
205  */
206 void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace)
207 {
208         VALUE_PAIR *i, *next;
209         VALUE_PAIR **prev = first;
210
211         if (*first == NULL) {
212                 *first = replace;
213                 return;
214         }
215
216         /*
217          *      Not an empty list, so find item if it is there, and
218          *      replace it. Note, we always replace the first one, and
219          *      we ignore any others that might exist.
220          */
221         for(i = *first; i; i = next) {
222                 next = i->next;
223
224                 /*
225                  *      Found the first attribute, replace it,
226                  *      and return.
227                  */
228                 if (i->attribute == replace->attribute) {
229                         *prev = replace;
230
231                         /*
232                          *      Should really assert that replace->next == NULL
233                          */
234                         replace->next = next;
235                         pairbasicfree(i);
236                         return;
237                 }
238
239                 /*
240                  *      Point to where the attribute should go.
241                  */
242                 prev = &i->next;
243         }
244
245         /*
246          *      If we got here, we didn't find anything to replace, so
247          *      stopped at the last item, which we just append to.
248          */
249         *prev = replace;
250 }
251
252 /*
253  *      Copy just a certain type of pairs.
254  */
255 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
256 {
257         VALUE_PAIR      *first, *n, **last;
258
259         first = NULL;
260         last = &first;
261
262         while (vp) {
263                 if (attr >= 0 && vp->attribute != attr) {
264                         vp = vp->next;
265                         continue;
266                 }
267                 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
268                         librad_log("out of memory");
269                         return first;
270                 }
271                 memcpy(n, vp, sizeof(VALUE_PAIR));
272                 n->next = NULL;
273                 *last = n;
274                 last = &n->next;
275                 vp = vp->next;
276         }
277         return first;
278 }
279
280
281 /*
282  *      Copy a pairlist.
283  */
284 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
285 {
286         return paircopy2(vp, -1);
287 }
288
289
290 /*
291  *      Move attributes from one list to the other
292  *      if not already present.
293  */
294 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
295 {
296         VALUE_PAIR **tailto, *i, *j, *next;
297         VALUE_PAIR *tailfrom = NULL;
298         VALUE_PAIR *found;
299         int has_password = 0;
300
301         if (*to == NULL) {
302                 *to = *from;
303                 *from = NULL;
304                 return;
305         }
306
307         /*
308          *      First, see if there are any passwords here, and
309          *      point "tailto" to the end of the "to" list.
310          */
311         tailto = to;
312         for(i = *to; i; i = i->next) {
313                 if (i->attribute == PW_PASSWORD ||
314                     i->attribute == PW_CRYPT_PASSWORD)
315                         has_password = 1;
316                 tailto = &i->next;
317         }
318
319         /*
320          *      Loop over the "from" list.
321          */
322         for(i = *from; i; i = next) {
323                 next = i->next;
324                 /*
325                  *      If there was a password in the "to" list,
326                  *      do not move any other password from the
327                  *      "from" to the "to" list.
328                  */
329                 if (has_password &&
330                     (i->attribute == PW_PASSWORD ||
331                      i->attribute == PW_CRYPT_PASSWORD)) {
332                         tailfrom = i;
333                         continue;
334                 }
335                 /*
336                  *      If the attribute is already present in "to",
337                  *      do not move it from "from" to "to". We make
338                  *      an exception for "Hint" which can appear multiple
339                  *      times, and we never move "Fall-Through".
340                  */
341                 if (i->attribute == PW_FALL_THROUGH ||
342                     (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {
343
344                         found = pairfind(*to, i->attribute);
345                         switch (i->operator) {
346
347                           /*
348                            *    If matching attributes are found,
349                            *    delete them.
350                            */
351                         case T_OP_SUB:          /* -= */
352                                 if (found) {
353                                         if (!i->vp_strvalue[0] ||
354                                             (strcmp((char *)found->vp_strvalue,
355                                                     (char *)i->vp_strvalue) == 0)){
356                                                 pairdelete(to, found->attribute);
357
358                                                 /*
359                                                  *      'tailto' may have been
360                                                  *      deleted...
361                                                  */
362                                                 tailto = to;
363                                                 for(j = *to; j; j = j->next) {
364                                                         tailto = &j->next;
365                                                 }
366                                         }
367                                 }
368                                 tailfrom = i;
369                                 continue;
370                                 break;
371
372 /* really HAVE_REGEX_H */
373 #if 0
374                                 /*
375                                  *  Attr-Name =~ "s/find/replace/"
376                                  *
377                                  *  Very bad code.  Barely working,
378                                  *  if at all.
379                                  */
380
381                         case T_OP_REG_EQ:
382                           if (found &&
383                               (i->vp_strvalue[0] == 's')) {
384                             regex_t             reg;
385                             regmatch_t          match[1];
386
387                             char *str;
388                             char *p, *q;
389
390                             p = i->vp_strvalue + 1;
391                             q = strchr(p + 1, *p);
392                             if (!q || (q[strlen(q) - 1] != *p)) {
393                               tailfrom = i;
394                               continue;
395                             }
396                             str = strdup(i->vp_strvalue + 2);
397                             q = strchr(str, *p);
398                             *(q++) = '\0';
399                             q[strlen(q) - 1] = '\0';
400
401                             regcomp(&reg, str, 0);
402                             if (regexec(&reg, found->vp_strvalue,
403                                         1, match, 0) == 0) {
404                               fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
405                                       found->vp_strvalue, match[0].rm_so,
406                                       match[0].rm_eo, q);
407
408                             }
409                             regfree(&reg);
410                             free(str);
411                           }
412                           tailfrom = i; /* don't copy it over */
413                           continue;
414                           break;
415 #endif
416                         case T_OP_EQ:           /* = */
417                                 /*
418                                  *  FIXME: Tunnel attributes with
419                                  *  different tags are different
420                                  *  attributes.
421                                  */
422                                 if (found) {
423                                         tailfrom = i;
424                                         continue; /* with the loop */
425                                 }
426                                 break;
427
428                           /*
429                            *  If a similar attribute is found,
430                            *  replace it with the new one.  Otherwise,
431                            *  add the new one to the list.
432                            */
433                         case T_OP_SET:          /* := */
434                                 if (found) {
435                                         VALUE_PAIR *mynext = found->next;
436
437                                         /*
438                                          *      Do NOT call pairdelete()
439                                          *      here, due to issues with
440                                          *      re-writing "request->username".
441                                          *
442                                          *      Everybody calls pairmove,
443                                          *      and expects it to work.
444                                          *      We can't update request->username
445                                          *      here, so instead we over-write
446                                          *      the vp that it's pointing to.
447                                          */
448                                         memcpy(found, i, sizeof(*found));
449                                         found->next = mynext;
450
451                                         pairdelete(&found->next, found->attribute);
452
453                                         /*
454                                          *      'tailto' may have been
455                                          *      deleted...
456                                          */
457                                         for(j = found; j; j = j->next) {
458                                                 tailto = &j->next;
459                                         }
460                                         continue;
461                                 }
462                                 break;
463
464                           /*
465                            *  Add the new element to the list, even
466                            *  if similar ones already exist.
467                            */
468                         default:
469                         case T_OP_ADD: /* += */
470                                 break;
471                         }
472                 }
473                 if (tailfrom)
474                         tailfrom->next = next;
475                 else
476                         *from = next;
477
478                 /*
479                  *      If ALL of the 'to' attributes have been deleted,
480                  *      then ensure that the 'tail' is updated to point
481                  *      to the head.
482                  */
483                 if (!*to) {
484                         tailto = to;
485                 }
486                 *tailto = i;
487                 if (i) {
488                         i->next = NULL;
489                         tailto = &i->next;
490                 }
491         }
492 }
493
494 /*
495  *      Move one kind of attributes from one list to the other
496  */
497 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
498 {
499         VALUE_PAIR *to_tail, *i, *next;
500         VALUE_PAIR *iprev = NULL;
501
502         /*
503          *      Find the last pair in the "to" list and put it in "to_tail".
504          */
505         if (*to != NULL) {
506                 to_tail = *to;
507                 for(i = *to; i; i = i->next)
508                         to_tail = i;
509         } else
510                 to_tail = NULL;
511
512         for(i = *from; i; i = next) {
513                 next = i->next;
514
515
516                 /*
517                  *      If the attribute to move is NOT a VSA, then it
518                  *      ignores any attributes which do not match exactly.
519                  */
520                 if ((attr != PW_VENDOR_SPECIFIC) &&
521                     (i->attribute != attr)) {
522                         iprev = i;
523                         continue;
524                 }
525
526                 /*
527                  *      If the attribute to move IS a VSA, then it ignores
528                  *      any non-VSA attribute.
529                  */
530                 if ((attr == PW_VENDOR_SPECIFIC) &&
531                     (VENDOR(i->attribute) == 0)) {
532                         iprev = i;
533                         continue;
534                 }
535
536                 /*
537                  *      Remove the attribute from the "from" list.
538                  */
539                 if (iprev)
540                         iprev->next = next;
541                 else
542                         *from = next;
543
544                 /*
545                  *      Add the attribute to the "to" list.
546                  */
547                 if (to_tail)
548                         to_tail->next = i;
549                 else
550                         *to = i;
551                 to_tail = i;
552                 i->next = NULL;
553         }
554 }
555
556
557 /*
558  *      Sort of strtok/strsep function.
559  */
560 static char *mystrtok(char **ptr, const char *sep)
561 {
562         char    *res;
563
564         if (**ptr == 0)
565                 return NULL;
566         while (**ptr && strchr(sep, **ptr))
567                 (*ptr)++;
568         if (**ptr == 0)
569                 return NULL;
570         res = *ptr;
571         while (**ptr && strchr(sep, **ptr) == NULL)
572                 (*ptr)++;
573         if (**ptr != 0)
574                 *(*ptr)++ = 0;
575         return res;
576 }
577
578 /*
579  *      Turn printable string into time_t
580  *      Returns -1 on error, 0 on OK.
581  */
582 static int gettime(const char *valstr, time_t *lvalue)
583 {
584         int             i;
585         time_t          t;
586         struct tm       *tm, s_tm;
587         char            buf[64];
588         char            *p;
589         char            *f[4];
590         char            *tail = '\0';
591
592         /*
593          * Test for unix timestamp date
594          */
595         *lvalue = strtoul(valstr, &tail, 10);
596         if (*tail == '\0') {
597                 return 0;
598         }
599
600         tm = &s_tm;
601         memset(tm, 0, sizeof(*tm));
602         tm->tm_isdst = -1;      /* don't know, and don't care about DST */
603
604         strNcpy(buf, valstr, sizeof(buf));
605
606         p = buf;
607         f[0] = mystrtok(&p, " \t");
608         f[1] = mystrtok(&p, " \t");
609         f[2] = mystrtok(&p, " \t");
610         f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
611         if (!f[0] || !f[1] || !f[2]) return -1;
612
613         /*
614          *      The time has a colon, where nothing else does.
615          *      So if we find it, bubble it to the back of the list.
616          */
617         if (f[3]) {
618                 for (i = 0; i < 3; i++) {
619                         if (strchr(f[i], ':')) {
620                                 p = f[3];
621                                 f[3] = f[i];
622                                 f[i] = p;
623                                 break;
624                         }
625                 }
626         }
627
628         /*
629          *  The month is text, which allows us to find it easily.
630          */
631         tm->tm_mon = 12;
632         for (i = 0; i < 3; i++) {
633                 if (isalpha( (int) *f[i])) {
634                         /*
635                          *  Bubble the month to the front of the list
636                          */
637                         p = f[0];
638                         f[0] = f[i];
639                         f[i] = p;
640
641                         for (i = 0; i < 12; i++) {
642                                 if (strncasecmp(months[i], f[0], 3) == 0) {
643                                         tm->tm_mon = i;
644                                         break;
645                                 }
646                         }
647                 }
648         }
649
650         /* month not found? */
651         if (tm->tm_mon == 12) return -1;
652
653         /*
654          *  The year may be in f[1], or in f[2]
655          */
656         tm->tm_year = atoi(f[1]);
657         tm->tm_mday = atoi(f[2]);
658
659         if (tm->tm_year >= 1900) {
660                 tm->tm_year -= 1900;
661
662         } else {
663                 /*
664                  *  We can't use 2-digit years any more, they make it
665                  *  impossible to tell what's the day, and what's the year.
666                  */
667                 if (tm->tm_mday < 1900) return -1;
668
669                 /*
670                  *  Swap the year and the day.
671                  */
672                 i = tm->tm_year;
673                 tm->tm_year = tm->tm_mday - 1900;
674                 tm->tm_mday = i;
675         }
676
677         /*
678          *  If the day is out of range, die.
679          */
680         if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
681                 return -1;
682         }
683
684         /*
685          *      There may be %H:%M:%S.  Parse it in a hacky way.
686          */
687         if (f[3]) {
688                 f[0] = f[3];    /* HH */
689                 f[1] = strchr(f[0], ':'); /* find : separator */
690                 if (!f[1]) return -1;
691
692                 *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
693
694                 f[2] = strchr(f[1], ':'); /* find : separator */
695                 if (f[2]) {
696                   *(f[2]++) = '\0';     /* nuke it, and point to SS */
697                 } else {
698                   strcpy(f[2], "0");    /* assignment would discard const */
699                 }
700
701                 tm->tm_hour = atoi(f[0]);
702                 tm->tm_min = atoi(f[1]);
703                 tm->tm_sec = atoi(f[2]);
704         }
705
706         /*
707          *  Returns -1 on error.
708          */
709         t = mktime(tm);
710         if (t == (time_t) -1) return -1;
711
712         *lvalue = t;
713
714         return 0;
715 }
716
717
718 /*
719  *  Parse a string value into a given VALUE_PAIR
720  *
721  *  FIXME: we probably want to fix this function to accept
722  *  octets as values for any type of attribute.  We should then
723  *  double-check the parsed value, to be sure it's legal for that
724  *  type (length, etc.)
725  */
726 VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
727 {
728         char            *p, *s=0;
729         const char      *cp, *cs;
730         DICT_VALUE      *dval;
731
732         /*
733          *      Even for integers, dates and ip addresses we
734          *      keep the original string in vp->vp_strvalue.
735          */
736         strNcpy((char *)vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
737         vp->length = strlen(vp->vp_strvalue);
738
739         switch(vp->type) {
740                 case PW_TYPE_STRING:
741                         /*
742                          *      Already handled above.
743                          */
744                         break;
745
746                 case PW_TYPE_IPADDR:
747                         /*
748                          *      It's a comparison, not a real IP.
749                          */
750                         if ((vp->operator == T_OP_REG_EQ) ||
751                             (vp->operator == T_OP_REG_NE)) {
752                                 break;
753                         }
754
755                         /*
756                          *      FIXME: complain if hostname
757                          *      cannot be resolved, or resolve later!
758                          */
759                         if ((p = strrchr(value, '+')) != NULL && !p[1]) {
760                                 cs = s = strdup(value);
761                                 p = strrchr(s, '+');
762                                 *p = 0;
763                                 vp->flags.addport = 1;
764                         } else {
765                                 p = NULL;
766                                 cs = value;
767                         }
768                         
769                         {
770                                 lrad_ipaddr_t ipaddr;
771
772                                 if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
773                                         librad_log("Failed to find IP address for %s", cs);
774                                         return NULL;
775                                 }
776
777                                 vp->lvalue = ipaddr.ipaddr.ip4addr.s_addr;
778                         }
779                         if (s) free(s);
780                         vp->length = 4;
781                         break;
782
783                 case PW_TYPE_BYTE:
784                         /*
785                          *      Note that ALL integers are unsigned!
786                          */
787                         if (isdigit((int) value[0]) &&
788                             (strspn(value, "0123456789") == strlen(value))) {
789                                 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
790                                 if (vp->lvalue > 255) {
791                                         librad_log("Byte value \"%s\" is larger than 255", value);
792                                         return NULL;
793                                 }
794                                 vp->length = 1;
795                         }
796
797                         /*
798                          *      Look for the named value for the given
799                          *      attribute.
800                          */
801                         else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
802                                 librad_log("Unknown value %s for attribute %s",
803                                            value, vp->name);
804                                 return NULL;
805                         } else {
806                                 vp->lvalue = dval->value;
807                                 vp->length = 1;
808                         }
809                         break;
810
811                 case PW_TYPE_SHORT:
812                         /*
813                          *      Note that ALL integers are unsigned!
814                          */
815                         if (isdigit((int) value[0]) &&
816                             (strspn(value, "0123456789") == strlen(value))) {
817                                 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
818                                 if (vp->lvalue > 65535) {
819                                         librad_log("Byte value \"%s\" is larger than 65535", value);
820                                         return NULL;
821                                 }
822                                 vp->length = 2;
823                         }
824
825                         /*
826                          *      Look for the named value for the given
827                          *      attribute.
828                          */
829                         else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
830                                 librad_log("Unknown value %s for attribute %s",
831                                            value, vp->name);
832                                 return NULL;
833                         } else {
834                                 vp->lvalue = dval->value;
835                                 vp->length = 2;
836                         }
837                         break;
838
839                 case PW_TYPE_INTEGER:
840                         /*
841                          *      Note that ALL integers are unsigned!
842                          */
843                         if (isdigit((int) value[0]) &&
844                             (strspn(value, "0123456789") == strlen(value))) {
845                                 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
846                                 vp->length = 4;
847                         }
848
849                         /*
850                          *      Look for the named value for the given
851                          *      attribute.
852                          */
853                         else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
854                                 librad_log("Unknown value %s for attribute %s",
855                                            value, vp->name);
856                                 return NULL;
857                         } else {
858                                 vp->lvalue = dval->value;
859                                 vp->length = 4;
860                         }
861                         break;
862
863                 case PW_TYPE_DATE:
864                         if (gettime(value, (time_t *)&vp->lvalue) < 0) {
865                                 librad_log("failed to parse time string "
866                                            "\"%s\"", value);
867                                 return NULL;
868                         }
869                         vp->length = 4;
870                         break;
871                 case PW_TYPE_ABINARY:
872 #ifdef ASCEND_BINARY
873                         if (strncasecmp(value, "0x", 2) == 0) {
874                                 vp->type = PW_TYPE_OCTETS;
875                                 goto do_octets;
876                         }
877
878                         if (ascend_parse_filter(vp) < 0 ) {
879                                 librad_log("failed to parse Ascend binary attribute: %s",
880                                            librad_errstr);
881                                 return NULL;
882                         }
883                         break;
884
885                         /*
886                          *      If Ascend binary is NOT defined,
887                          *      then fall through to raw octets, so that
888                          *      the user can at least make them by hand...
889                          */
890         do_octets:
891 #endif
892                         /* raw octets: 0x01020304... */
893                 case PW_TYPE_OCTETS:
894                         if (strncasecmp(value, "0x", 2) == 0) {
895                                 uint8_t *us;
896                                 cp = value + 2;
897                                 us = vp->vp_strvalue;
898                                 vp->length = 0;
899
900
901                                 /*
902                                  *      There is only one character,
903                                  *      die.
904                                  */
905                                 if ((strlen(cp) & 0x01) != 0) {
906                                         librad_log("Hex string is not an even length string.");
907                                         return NULL;
908                                 }
909                                 
910                                 
911                                 while (*cp && vp->length < MAX_STRING_LEN) {
912                                         unsigned int tmp;
913
914                                         if (sscanf(cp, "%02x", &tmp) != 1) {
915                                                 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
916                                                 return NULL;
917                                         }
918
919                                         cp += 2;
920                                         *(us++) = tmp;
921                                         vp->length++;
922                                 }
923                                 *us = '\0';
924                         }
925                         break;
926
927                 case PW_TYPE_IFID:
928                         if (ifid_aton(value, vp->vp_strvalue) == NULL) {
929                                 librad_log("failed to parse interface-id "
930                                            "string \"%s\"", value);
931                                 return NULL;
932                         }
933                         vp->length = 8;
934                         vp->vp_strvalue[vp->length] = '\0';
935                         break;
936
937                 case PW_TYPE_IPV6ADDR:
938                         if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
939                                 librad_log("failed to parse IPv6 address "
940                                            "string \"%s\"", value);
941                                 return NULL;
942                         }
943                         vp->length = 16; /* length of IPv6 address */
944                         vp->vp_strvalue[vp->length] = '\0';
945                         break;
946                         /*
947                          *  Anything else.
948                          */
949                 case PW_TYPE_IPV6PREFIX:
950                         p = strchr(value, '/');
951                         if (!p || ((p - value) >= 256)) {
952                                 librad_log("invalid IPv6 prefix "
953                                            "string \"%s\"", value);
954                                 return NULL;
955                         } else {
956                                 unsigned int prefix;
957                                 char buffer[256], *eptr;
958                                 
959                                 memcpy(buffer, value, p - value);
960                                 buffer[p - value] = '\0';
961                                 
962                                 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
963                                         librad_log("failed to parse IPv6 address "
964                                                    "string \"%s\"", value);
965                                         return NULL;
966                                 }
967                                 
968                                 prefix = strtoul(p + 1, &eptr, 10);
969                                 if ((prefix > 128) || *eptr) {
970                                         librad_log("failed to parse IPv6 address "
971                                                    "string \"%s\"", value);
972                                         return NULL;
973                                 }
974                                 vp->vp_strvalue[1] = prefix;
975                         }
976                         vp->vp_strvalue[0] = '\0';
977                         vp->length = 16 + 2;
978                         break;
979
980                 default:
981                         librad_log("unknown attribute type %d", vp->type);
982                         return NULL;
983         }
984
985         return vp;
986 }
987
988 /*
989  *      Create a VALUE_PAIR from an ASCII attribute and value,
990  *      where the attribute name is in the form:
991  *
992  *      Attr-%d
993  *      Vendor-%d-Attr-%d
994  */
995 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
996                                 int operator)
997 {
998         int             attr;
999         const char      *p;
1000         VALUE_PAIR      *vp;
1001
1002         /*
1003          *      Unknown attributes MUST be of type 'octets'
1004          */
1005         if (value && (strncasecmp(value, "0x", 2) != 0)) {
1006                 goto error;
1007         }
1008
1009         /*
1010          *      Attr-%d
1011          */
1012         if (strncasecmp(attribute, "Attr-", 5) == 0) {
1013                 attr = atoi(attribute + 5);
1014                 p = attribute + 5;
1015                 p += strspn(p, "0123456789");
1016                 if (*p != 0) goto error;
1017
1018                 /*
1019                  *      Vendor-%d-Attr-%d
1020                  */
1021         } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
1022                 int vendor;
1023
1024                 vendor = atoi(attribute + 7);
1025                 if ((vendor == 0) || (vendor > 65535)) goto error;
1026
1027                 p = attribute + 7;
1028                 p += strspn(p, "0123456789");
1029
1030                 /*
1031                  *      Not Vendor-%d-Attr-%d
1032                  */
1033                 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
1034
1035                 p += 6;
1036                 attr = atoi(p);
1037
1038                 p += strspn(p, "0123456789");
1039                 if (*p != 0) goto error;
1040
1041                 if ((attr == 0) || (attr > 65535)) goto error;
1042
1043                 attr |= (vendor << 16);
1044
1045                 /*
1046                  *      VendorName-Attr-%d
1047                  */
1048         } else if (((p = strchr(attribute, '-')) != NULL) &&
1049                    (strncasecmp(p, "-Attr-", 6) == 0)) {
1050                 int vendor;
1051                 char buffer[256];
1052
1053                 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
1054
1055                 memcpy(buffer, attribute, p - attribute);
1056                 buffer[p - attribute] = '\0';
1057
1058                 vendor = dict_vendorbyname(buffer);
1059                 if (vendor == 0) goto error;
1060
1061                 p += 6;
1062                 attr = atoi(p);
1063
1064                 p += strspn(p, "0123456789");
1065                 if (*p != 0) goto error;
1066
1067                 if ((attr == 0) || (attr > 65535)) goto error;
1068
1069                 attr |= (vendor << 16);
1070
1071         } else {                /* very much unknown: die */
1072         error:
1073                 librad_log("Unknown attribute \"%s\"", attribute);
1074                 return NULL;
1075         }
1076
1077         /*
1078          *      We've now parsed the attribute properly, and verified
1079          *      it to have value 'octets'.  Let's create it.
1080          */
1081         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1082                 librad_log("out of memory");
1083                 return NULL;
1084         }
1085         memset(vp, 0, sizeof(VALUE_PAIR));
1086         vp->type = PW_TYPE_OCTETS;
1087
1088         /*
1089          *      It may not be valid hex characters.  If not, die.
1090          */
1091         if (pairparsevalue(vp, value) == NULL) {
1092                 pairfree(&vp);
1093                 return NULL;
1094         }
1095
1096         if (VENDOR(attr) == 0) {
1097                 sprintf(vp->name, "Attr-%u", attr);
1098         } else {
1099                 sprintf(vp->name, "Vendor-%u-Attr-%u",
1100                         VENDOR(attr), attr & 0xffff);
1101         }
1102
1103         vp->attribute = attr;
1104         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1105         vp->next = NULL;
1106
1107         return vp;
1108 }
1109
1110
1111 /*
1112  *      Create a VALUE_PAIR from an ASCII attribute and value.
1113  */
1114 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1115 {
1116         DICT_ATTR       *da;
1117         VALUE_PAIR      *vp;
1118         char            *tc, *ts;
1119         signed char     tag;
1120         int             found_tag;
1121 #ifdef HAVE_REGEX_H
1122         int             res;
1123         regex_t         cre;
1124 #endif
1125
1126         /*
1127          *    Check for tags in 'Attribute:Tag' format.
1128          */
1129         found_tag = 0;
1130         tag = 0;
1131
1132         ts = strrchr(attribute, ':');
1133         if (ts && !ts[1]) {
1134                 librad_log("Invalid tag for attribute %s", attribute);
1135                 return NULL;
1136         }
1137
1138         if (ts && ts[1]) {
1139                  /* Colon found with something behind it */
1140                  if (ts[1] == '*' && ts[2] == 0) {
1141                          /* Wildcard tag for check items */
1142                          tag = TAG_ANY;
1143                          *ts = 0;
1144                  } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1145                          /* It's not a wild card tag */
1146                          tag = strtol(ts + 1, &tc, 0);
1147                          if (tc && !*tc && TAG_VALID_ZERO(tag))
1148                                  *ts = 0;
1149                          else tag = 0;
1150                  } else {
1151                          librad_log("Invalid tag for attribute %s", attribute);
1152                          return NULL;
1153                  }
1154                  found_tag = 1;
1155         }
1156
1157         /*
1158          *      It's not found in the dictionary, so we use
1159          *      another method to create the attribute.
1160          */
1161         if ((da = dict_attrbyname(attribute)) == NULL) {
1162                 return pairmake_any(attribute, value, operator);
1163         }
1164
1165         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1166                 librad_log("out of memory");
1167                 return NULL;
1168         }
1169
1170         memset(vp, 0, sizeof(VALUE_PAIR));
1171         vp->attribute = da->attr;
1172         vp->type = da->type;
1173         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1174         strcpy(vp->name, da->name);
1175         vp->flags = da->flags;
1176         vp->next = NULL;
1177
1178         /*      Check for a tag in the 'Merit' format of:
1179          *      :Tag:Value.  Print an error if we already found
1180          *      a tag in the Attribute.
1181          */
1182
1183         if (value && (*value == ':' && da->flags.has_tag)) {
1184                 /* If we already found a tag, this is invalid */
1185                 if(found_tag) {
1186                         pairbasicfree(vp);
1187                         librad_log("Duplicate tag %s for attribute %s",
1188                                    value, vp->name);
1189                         DEBUG("Duplicate tag %s for attribute %s\n",
1190                                    value, vp->name);
1191                         return NULL;
1192
1193                 }
1194                 /* Colon found and attribute allows a tag */
1195                 if (value[1] == '*' && value[2] == ':') {
1196                        /* Wildcard tag for check items */
1197                        tag = TAG_ANY;
1198                        value += 3;
1199                 } else {
1200                        /* Real tag */
1201                        tag = strtol(value + 1, &tc, 0);
1202                        if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1203                             value = tc + 1;
1204                        else tag = 0;
1205                 }
1206                 found_tag = 1;
1207         }
1208
1209         if (found_tag) {
1210           vp->flags.tag = tag;
1211         }
1212
1213         switch (vp->operator) {
1214         default:
1215                 break;
1216
1217                 /*
1218                  *      For =* and !* operators, the value is irrelevant
1219                  *      so we return now.
1220                  */
1221         case T_OP_CMP_TRUE:
1222         case T_OP_CMP_FALSE:
1223                 vp->vp_strvalue[0] = '\0';
1224                 vp->length = 0;
1225                 return vp;
1226                 break;
1227
1228                 /*
1229                  *      Regular expression comparison of integer attributes
1230                  *      does a STRING comparison of the names of their
1231                  *      integer attributes.
1232                  */
1233         case T_OP_REG_EQ:       /* =~ */
1234         case T_OP_REG_NE:       /* !~ */
1235                 if (vp->type == PW_TYPE_INTEGER) {
1236                         return vp;
1237                 }
1238 #ifdef HAVE_REGEX_H
1239                 /*
1240                  *      Regular expression match with no regular
1241                  *      expression is wrong.
1242                  */
1243                 if (!value) {
1244                         pairfree(&vp);
1245                         return NULL;
1246                 }
1247
1248                 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1249                 if (res != 0) {
1250                         char    msg[128];
1251
1252                         regerror(res, &cre, msg, sizeof(msg));
1253                         librad_log("Illegal regular expression in attribute: %s: %s",
1254                                 vp->name, msg);
1255                         pairbasicfree(vp);
1256                         return NULL;
1257                 }
1258                 regfree(&cre);
1259 #else
1260                 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1261                                 vp->name);
1262                 pairbasicfree(vp);
1263                 return NULL;
1264 #endif
1265         }
1266
1267         /*
1268          *      FIXME: if (strcasecmp(attribute, vp->name) != 0)
1269          *      then the user MAY have typed in the attribute name
1270          *      as Vendor-%d-Attr-%d, and the value MAY be octets.
1271          *
1272          *      We probably want to fix pairparsevalue to accept
1273          *      octets as values for any attribute.
1274          */
1275         if (value && (pairparsevalue(vp, value) == NULL)) {
1276                 pairbasicfree(vp);
1277                 return NULL;
1278         }
1279
1280         return vp;
1281 }
1282
1283
1284 /*
1285  *      [a-zA-Z0-9_-:]+
1286  */
1287 static const int valid_attr_name[256] = {
1288         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1289         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1290         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1291         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1292         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1293         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1294         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1295         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1296         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1297         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1298         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1299         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1300         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1301         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1302         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1303         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1304 };
1305
1306 /*
1307  *      Read a valuepair from a buffer, and advance pointer.
1308  *      Sets *eol to T_EOL if end of line was encountered.
1309  */
1310 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1311 {
1312         char            buf[64];
1313         char            attr[64];
1314         char            value[512];
1315         char            *p, *q;
1316         LRAD_TOKEN      token, t, xlat;
1317         VALUE_PAIR      *vp;
1318         size_t          len;
1319
1320         *eol = T_OP_INVALID;
1321
1322         p = *ptr;
1323         while ((*p == ' ') || (*p == '\t')) p++;
1324
1325         if (!*p) {
1326                 *eol = T_OP_INVALID;
1327                 librad_log("No token read where we expected an attribute name");
1328                 return NULL;
1329         }
1330
1331         if (*p == '#') {
1332                 *eol = T_HASH;
1333                 librad_log("Read a comment instead of a token");
1334                 return NULL;
1335         }
1336
1337         q = attr;
1338         for (len = 0; len < sizeof(attr); len++) {
1339                 if (valid_attr_name[(int)*p]) {
1340                         *q++ = *p++;
1341                         continue;
1342                 }
1343                 break;
1344         }
1345
1346         if (len == sizeof(attr)) {
1347                 *eol = T_OP_INVALID;
1348                 librad_log("Attribute name is too long");
1349                 return NULL;
1350         }
1351
1352         /*
1353          *      We may have Foo-Bar:= stuff, so back up.
1354          */
1355         if (attr[len - 1] == ':') {
1356                 p--;
1357                 len--;
1358         }
1359
1360         attr[len] = '\0';
1361         *ptr = p;
1362
1363         /* Now we should have an operator here. */
1364         token = gettoken(ptr, buf, sizeof(buf));
1365         if (token < T_EQSTART || token > T_EQEND) {
1366                 librad_log("expecting operator");
1367                 return NULL;
1368         }
1369
1370         /* Read value.  Note that empty string values are allowed */
1371         xlat = gettoken(ptr, value, sizeof(value));
1372         if (xlat == T_EOL) {
1373                 librad_log("failed to get value");
1374                 return NULL;
1375         }
1376
1377         /*
1378          *      Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1379          */
1380         p = *ptr;
1381         t = gettoken(&p, buf, sizeof(buf));
1382         if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1383                 librad_log("Expected end of line or comma");
1384                 return NULL;
1385         }
1386
1387         *eol = t;
1388         if (t == T_COMMA) {
1389                 *ptr = p;
1390         }
1391
1392         vp = NULL;
1393         switch (xlat) {
1394                 /*
1395                  *      Make the full pair now.
1396                  */
1397         default:
1398                 vp = pairmake(attr, value, token);
1399                 break;
1400
1401                 /*
1402                  *      Perhaps do xlat's
1403                  */
1404         case T_DOUBLE_QUOTED_STRING:
1405                 p = strchr(value, '%');
1406                 if (p && (p[1] == '{')) {
1407                         if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1408                                 librad_log("Value too long");
1409                                 return NULL;
1410                         }
1411                         vp = pairmake(attr, NULL, token);
1412                         if (!vp) {
1413                                 *eol = T_OP_INVALID;
1414                                 return NULL;
1415                         }
1416
1417                         strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1418                         vp->flags.do_xlat = 1;
1419                         vp->length = 0;
1420                 } else {
1421                         vp = pairmake(attr, value, token);
1422                 }
1423                 break;
1424
1425
1426                 /*
1427                  *      Mark the pair to be allocated later.
1428                  */
1429         case T_BACK_QUOTED_STRING:
1430                 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1431                         librad_log("Value too long");
1432                         return NULL;
1433                 }
1434
1435                 vp = pairmake(attr, NULL, token);
1436                 if (!vp) {
1437                         *eol = T_OP_INVALID;
1438                         return NULL;
1439                 }
1440
1441                 vp->flags.do_xlat = 1;
1442                 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1443                 vp->length = 0;
1444                 break;
1445         }
1446
1447         /*
1448          *      If we didn't make a pair, return an error.
1449          */
1450         if (!vp) {
1451                 *eol = T_OP_INVALID;
1452                 return NULL;
1453         }
1454
1455         return vp;
1456 }
1457
1458 /*
1459  *      Read one line of attribute/value pairs. This might contain
1460  *      multiple pairs seperated by comma's.
1461  */
1462 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1463 {
1464         VALUE_PAIR      *vp;
1465         char            *p;
1466         LRAD_TOKEN      last_token = T_OP_INVALID;
1467         LRAD_TOKEN      previous_token;
1468
1469         /*
1470          *      We allow an empty line.
1471          */
1472         if (buffer[0] == 0)
1473                 return T_EOL;
1474
1475         p = buffer;
1476         do {
1477                 previous_token = last_token;
1478                 if ((vp = pairread(&p, &last_token)) == NULL) {
1479                         return last_token;
1480                 }
1481                 pairadd(first_pair, vp);
1482         } while (*p && (last_token == T_COMMA));
1483
1484         /*
1485          *      Don't tell the caller that there was a comment.
1486          */
1487         if (last_token == T_HASH) {
1488                 return previous_token;
1489         }
1490
1491         /*
1492          *      And return the last token which we read.
1493          */
1494         return last_token;
1495 }
1496
1497 /*
1498  *      Read valuepairs from the fp up to End-Of-File.
1499  *
1500  *      Hmm... this function is only used by radclient..
1501  */
1502 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1503 {
1504         char buf[8192];
1505         LRAD_TOKEN last_token = T_EOL;
1506         VALUE_PAIR *vp;
1507         VALUE_PAIR *list;
1508         int error = 0;
1509
1510         list = NULL;
1511
1512         while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1513                 /*
1514                  *      If we get a '\n' by itself, we assume that's
1515                  *      the end of that VP
1516                  */
1517                 if ((buf[0] == '\n') && (list)) {
1518                         return list;
1519                 }
1520                 if ((buf[0] == '\n') && (!list)) {
1521                         continue;
1522                 }
1523
1524                 /*
1525                  *      Comments get ignored
1526                  */
1527                 if (buf[0] == '#') continue;
1528
1529                 /*
1530                  *      Read all of the attributes on the current line.
1531                  */
1532                 vp = NULL;
1533                 last_token = userparse(buf, &vp);
1534                 if (!vp) {
1535                         if (last_token != T_EOL) {
1536                                 librad_perror("%s", errprefix);
1537                                 error = 1;
1538                                 break;
1539                         }
1540                         break;
1541                 }
1542
1543                 pairadd(&list, vp);
1544                 buf[0] = '\0';
1545         }
1546
1547         if (error) pairfree(&list);
1548
1549         *pfiledone = 1;
1550
1551         return error ? NULL: list;
1552 }
1553
1554
1555
1556 /*
1557  *      Compare two pairs, using the operator from "one".
1558  *
1559  *      i.e. given two attributes, it does:
1560  *
1561  *      (two->data) (one->operator) (one->data)
1562  *
1563  *      e.g. "foo" != "bar"
1564  *
1565  *      Returns true (comparison is true), or false (comparison is not true);
1566  */
1567 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1568 {
1569         int compare;
1570
1571         switch (one->operator) {
1572         case T_OP_CMP_TRUE:
1573                 return (two != NULL);
1574
1575         case T_OP_CMP_FALSE:
1576                 return (two == NULL);
1577
1578                 /*
1579                  *      One is a regex, compile it, print two to a string,
1580                  *      and then do string comparisons.
1581                  */
1582         case T_OP_REG_EQ:
1583         case T_OP_REG_NE:
1584 #ifndef HAVE_REGEX_H
1585                 return -1;
1586 #else
1587                 {
1588                         regex_t reg;
1589                         char buffer[MAX_STRING_LEN * 4 + 1];
1590                         
1591                         compare = regcomp(&reg, one->vp_strvalue,
1592                                           REG_EXTENDED);
1593                         if (compare != 0) {
1594                                 regerror(compare, &reg, buffer, sizeof(buffer));
1595                                 librad_log("Illegal regular expression in attribute: %s: %s",
1596                                            one->name, buffer);
1597                                 return -1;
1598                         }
1599
1600                         vp_prints_value(buffer, sizeof(buffer), two, 0);
1601
1602                         /*
1603                          *      Don't care about substring matches,
1604                          *      oh well...
1605                          */
1606                         compare = regexec(&reg, buffer, 0, NULL, 0);
1607
1608                         regfree(&reg);
1609                         if (one->operator == T_OP_REG_EQ) return (compare == 0);
1610                         return (compare != 0);
1611                 }
1612 #endif
1613
1614         default:                /* we're OK */
1615                 break;
1616         }
1617                 
1618         /*
1619          *      After doing the previous check for special comparisons,
1620          *      do the per-type comparison here.
1621          */
1622         switch (one->type) {
1623         case PW_TYPE_ABINARY:
1624         case PW_TYPE_OCTETS:
1625         {
1626                 size_t length;
1627                 const uint8_t *p, *q;
1628
1629                 if (one->length < two->length) {
1630                         length = one->length;
1631                 } else {
1632                         length = two->length;
1633                 }
1634                 
1635                 p = two->vp_octets;
1636                 q = one->vp_octets;
1637                 while (length) {
1638                         compare = ((int) *p) - ((int) *q);
1639                         if (compare != 0) goto type_switch;
1640                 }
1641
1642                 /*
1643                  *      Contents are the same.  The return code
1644                  *      is therefore the difference in lengths.
1645                  *
1646                  *      i.e. "0x00" is smaller than "0x0000"
1647                  */
1648                 compare = two->length - one->length;
1649         }
1650                 break;
1651
1652         case PW_TYPE_STRING:
1653                 if (one->flags.caseless) {
1654                         compare = strcasecmp(two->vp_strvalue,
1655                                              one->vp_strvalue);
1656                 } else {
1657                         compare = strcmp(two->vp_strvalue,
1658                                          one->vp_strvalue);
1659                 }
1660                 break;
1661                 
1662         case PW_TYPE_BYTE:
1663         case PW_TYPE_SHORT:
1664         case PW_TYPE_INTEGER:
1665         case PW_TYPE_DATE:
1666                 compare = two->lvalue - one->lvalue;
1667                 break;
1668
1669         case PW_TYPE_IPADDR:
1670                 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1671                 break;
1672
1673         case PW_TYPE_IPV6ADDR:
1674                 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1675                                  sizeof(two->vp_ipv6addr));
1676                 break;
1677                 
1678         case PW_TYPE_IPV6PREFIX:
1679                 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1680                                  sizeof(two->vp_ipv6prefix));
1681                 break;
1682
1683         case PW_TYPE_IFID:
1684                 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1685                                  sizeof(two->vp_ifid));
1686                 break;
1687
1688         default:
1689                 return 0;       /* unknown type */
1690         }
1691
1692         /*
1693          *      Now do the operator comparison.
1694          */
1695  type_switch:
1696         switch (one->operator) {
1697         case T_OP_CMP_EQ:
1698                 return (compare == 0);
1699                 
1700         case T_OP_NE:
1701                 return (compare != 0);
1702                 
1703         case T_OP_LT:
1704                 return (compare < 0);
1705                 
1706         case T_OP_GT:
1707                 return (compare > 0);
1708
1709         case T_OP_LE:
1710                 return (compare <= 0);
1711
1712         case T_OP_GE:
1713                 return (compare >= 0);
1714
1715         default:
1716                 return 0;
1717         }
1718
1719         return 0;
1720 }