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