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