Be a little smarter about allowing VALUE names that start
[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                   strcpy(f[2], "0");    /* assignment would discard const */
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                          *      Note that ALL integers are unsigned!
777                          */
778                         if (isdigit((int) value[0]) &&
779                             (strspn(value, "0123456789") == strlen(value))) {
780                                 vp->lvalue = (uint32_t) strtoul(value, NULL, 10);
781                                 vp->length = 4;
782                         }
783
784                         /*
785                          *      Look for the named value for the given
786                          *      attribute.
787                          */
788                         else if ((dval = dict_valbyname(vp->attribute, value)) == NULL) {
789                                 librad_log("Unknown value %s for attribute %s",
790                                            value, vp->name);
791                                 return NULL;
792                         } else {
793                                 vp->lvalue = dval->value;
794                                 vp->length = 4;
795                         }
796                         break;
797
798                 case PW_TYPE_DATE:
799                         if (gettime(value, (time_t *)&vp->lvalue) < 0) {
800                                 librad_log("failed to parse time string "
801                                            "\"%s\"", value);
802                                 return NULL;
803                         }
804                         vp->length = 4;
805                         break;
806                 case PW_TYPE_ABINARY:
807 #ifdef ASCEND_BINARY
808                         if (strncasecmp(value, "0x", 2) == 0) {
809                                 vp->type = PW_TYPE_OCTETS;
810                                 goto do_octets;
811                         }
812
813                         if (ascend_parse_filter(vp) < 0 ) {
814                                 librad_log("failed to parse Ascend binary attribute: %s",
815                                            librad_errstr);
816                                 return NULL;
817                         }
818                         break;
819
820                         /*
821                          *      If Ascend binary is NOT defined,
822                          *      then fall through to raw octets, so that
823                          *      the user can at least make them by hand...
824                          */
825         do_octets:
826 #endif
827                         /* raw octets: 0x01020304... */
828                 case PW_TYPE_OCTETS:
829                         if (strncasecmp(value, "0x", 2) == 0) {
830                                 uint8_t *us;
831                                 cp = value + 2;
832                                 us = vp->vp_strvalue;
833                                 vp->length = 0;
834
835
836                                 /*
837                                  *      There is only one character,
838                                  *      die.
839                                  */
840                                 if ((strlen(cp) & 0x01) != 0) {
841                                         librad_log("Hex string is not an even length string.");
842                                         return NULL;
843                                 }
844                                 
845                                 
846                                 while (*cp && vp->length < MAX_STRING_LEN) {
847                                         unsigned int tmp;
848
849                                         if (sscanf(cp, "%02x", &tmp) != 1) {
850                                                 librad_log("Non-hex characters at %c%c", cp[0], cp[1]);
851                                                 return NULL;
852                                         }
853
854                                         cp += 2;
855                                         *(us++) = tmp;
856                                         vp->length++;
857                                 }
858                                 *us = '\0';
859                         }
860                         break;
861
862                 case PW_TYPE_IFID:
863                         if (ifid_aton(value, vp->vp_strvalue) == NULL) {
864                                 librad_log("failed to parse interface-id "
865                                            "string \"%s\"", value);
866                                 return NULL;
867                         }
868                         vp->length = 8;
869                         vp->vp_strvalue[vp->length] = '\0';
870                         break;
871
872                 case PW_TYPE_IPV6ADDR:
873                         if (inet_pton(AF_INET6, value, vp->vp_strvalue) <= 0) {
874                                 librad_log("failed to parse IPv6 address "
875                                            "string \"%s\"", value);
876                                 return NULL;
877                         }
878                         vp->length = 16; /* length of IPv6 address */
879                         vp->vp_strvalue[vp->length] = '\0';
880                         break;
881                         /*
882                          *  Anything else.
883                          */
884                 case PW_TYPE_IPV6PREFIX:
885                         p = strchr(value, '/');
886                         if (!p || ((p - value) >= 256)) {
887                                 librad_log("invalid IPv6 prefix "
888                                            "string \"%s\"", value);
889                                 return NULL;
890                         } else {
891                                 unsigned int prefix;
892                                 char buffer[256], *eptr;
893                                 
894                                 memcpy(buffer, value, p - value);
895                                 buffer[p - value] = '\0';
896                                 
897                                 if (inet_pton(AF_INET6, buffer, vp->vp_strvalue + 2) <= 0) {
898                                         librad_log("failed to parse IPv6 address "
899                                                    "string \"%s\"", value);
900                                         return NULL;
901                                 }
902                                 
903                                 prefix = strtoul(p + 1, &eptr, 10);
904                                 if ((prefix > 128) || *eptr) {
905                                         librad_log("failed to parse IPv6 address "
906                                                    "string \"%s\"", value);
907                                         return NULL;
908                                 }
909                                 vp->vp_strvalue[1] = prefix;
910                         }
911                         vp->vp_strvalue[0] = '\0';
912                         vp->length = 16 + 2;
913                         break;
914
915                 default:
916                         librad_log("unknown attribute type %d", vp->type);
917                         return NULL;
918         }
919
920         return vp;
921 }
922
923 /*
924  *      Create a VALUE_PAIR from an ASCII attribute and value,
925  *      where the attribute name is in the form:
926  *
927  *      Attr-%d
928  *      Vendor-%d-Attr-%d
929  */
930 static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
931                                 int operator)
932 {
933         int             attr;
934         const char      *p;
935         VALUE_PAIR      *vp;
936
937         /*
938          *      Unknown attributes MUST be of type 'octets'
939          */
940         if (value && (strncasecmp(value, "0x", 2) != 0)) {
941                 goto error;
942         }
943
944         /*
945          *      Attr-%d
946          */
947         if (strncasecmp(attribute, "Attr-", 5) == 0) {
948                 attr = atoi(attribute + 5);
949                 p = attribute + 5;
950                 p += strspn(p, "0123456789");
951                 if (*p != 0) goto error;
952
953                 /*
954                  *      Vendor-%d-Attr-%d
955                  */
956         } else if (strncasecmp(attribute, "Vendor-", 7) == 0) {
957                 int vendor;
958
959                 vendor = atoi(attribute + 7);
960                 if ((vendor == 0) || (vendor > 65535)) goto error;
961
962                 p = attribute + 7;
963                 p += strspn(p, "0123456789");
964
965                 /*
966                  *      Not Vendor-%d-Attr-%d
967                  */
968                 if (strncasecmp(p, "-Attr-", 6) != 0) goto error;
969
970                 p += 6;
971                 attr = atoi(p);
972
973                 p += strspn(p, "0123456789");
974                 if (*p != 0) goto error;
975
976                 if ((attr == 0) || (attr > 65535)) goto error;
977
978                 attr |= (vendor << 16);
979
980                 /*
981                  *      VendorName-Attr-%d
982                  */
983         } else if (((p = strchr(attribute, '-')) != NULL) &&
984                    (strncasecmp(p, "-Attr-", 6) == 0)) {
985                 int vendor;
986                 char buffer[256];
987
988                 if (((size_t) (p - attribute)) >= sizeof(buffer)) goto error;
989
990                 memcpy(buffer, attribute, p - attribute);
991                 buffer[p - attribute] = '\0';
992
993                 vendor = dict_vendorbyname(buffer);
994                 if (vendor == 0) goto error;
995
996                 p += 6;
997                 attr = atoi(p);
998
999                 p += strspn(p, "0123456789");
1000                 if (*p != 0) goto error;
1001
1002                 if ((attr == 0) || (attr > 65535)) goto error;
1003
1004                 attr |= (vendor << 16);
1005
1006         } else {                /* very much unknown: die */
1007         error:
1008                 librad_log("Unknown attribute \"%s\"", attribute);
1009                 return NULL;
1010         }
1011
1012         /*
1013          *      We've now parsed the attribute properly, and verified
1014          *      it to have value 'octets'.  Let's create it.
1015          */
1016         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1017                 librad_log("out of memory");
1018                 return NULL;
1019         }
1020         memset(vp, 0, sizeof(VALUE_PAIR));
1021         vp->type = PW_TYPE_OCTETS;
1022
1023         /*
1024          *      It may not be valid hex characters.  If not, die.
1025          */
1026         if (pairparsevalue(vp, value) == NULL) {
1027                 pairfree(&vp);
1028                 return NULL;
1029         }
1030
1031         if (VENDOR(attr) == 0) {
1032                 sprintf(vp->name, "Attr-%u", attr);
1033         } else {
1034                 sprintf(vp->name, "Vendor-%u-Attr-%u",
1035                         VENDOR(attr), attr & 0xffff);
1036         }
1037
1038         vp->attribute = attr;
1039         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1040         vp->next = NULL;
1041
1042         return vp;
1043 }
1044
1045
1046 /*
1047  *      Create a VALUE_PAIR from an ASCII attribute and value.
1048  */
1049 VALUE_PAIR *pairmake(const char *attribute, const char *value, int operator)
1050 {
1051         DICT_ATTR       *da;
1052         VALUE_PAIR      *vp;
1053         char            *tc, *ts;
1054         signed char     tag;
1055         int             found_tag;
1056 #ifdef HAVE_REGEX_H
1057         int             res;
1058         regex_t         cre;
1059 #endif
1060
1061         /*
1062          *    Check for tags in 'Attribute:Tag' format.
1063          */
1064         found_tag = 0;
1065         tag = 0;
1066
1067         ts = strrchr(attribute, ':');
1068         if (ts && !ts[1]) {
1069                 librad_log("Invalid tag for attribute %s", attribute);
1070                 return NULL;
1071         }
1072
1073         if (ts && ts[1]) {
1074                  /* Colon found with something behind it */
1075                  if (ts[1] == '*' && ts[2] == 0) {
1076                          /* Wildcard tag for check items */
1077                          tag = TAG_ANY;
1078                          *ts = 0;
1079                  } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1080                          /* It's not a wild card tag */
1081                          tag = strtol(ts + 1, &tc, 0);
1082                          if (tc && !*tc && TAG_VALID_ZERO(tag))
1083                                  *ts = 0;
1084                          else tag = 0;
1085                  } else {
1086                          librad_log("Invalid tag for attribute %s", attribute);
1087                          return NULL;
1088                  }
1089                  found_tag = 1;
1090         }
1091
1092         /*
1093          *      It's not found in the dictionary, so we use
1094          *      another method to create the attribute.
1095          */
1096         if ((da = dict_attrbyname(attribute)) == NULL) {
1097                 return pairmake_any(attribute, value, operator);
1098         }
1099
1100         if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
1101                 librad_log("out of memory");
1102                 return NULL;
1103         }
1104
1105         memset(vp, 0, sizeof(VALUE_PAIR));
1106         vp->attribute = da->attr;
1107         vp->type = da->type;
1108         vp->operator = (operator == 0) ? T_OP_EQ : operator;
1109         strcpy(vp->name, da->name);
1110         vp->flags = da->flags;
1111         vp->next = NULL;
1112
1113         /*      Check for a tag in the 'Merit' format of:
1114          *      :Tag:Value.  Print an error if we already found
1115          *      a tag in the Attribute.
1116          */
1117
1118         if (value && (*value == ':' && da->flags.has_tag)) {
1119                 /* If we already found a tag, this is invalid */
1120                 if(found_tag) {
1121                         pairbasicfree(vp);
1122                         librad_log("Duplicate tag %s for attribute %s",
1123                                    value, vp->name);
1124                         DEBUG("Duplicate tag %s for attribute %s\n",
1125                                    value, vp->name);
1126                         return NULL;
1127
1128                 }
1129                 /* Colon found and attribute allows a tag */
1130                 if (value[1] == '*' && value[2] == ':') {
1131                        /* Wildcard tag for check items */
1132                        tag = TAG_ANY;
1133                        value += 3;
1134                 } else {
1135                        /* Real tag */
1136                        tag = strtol(value + 1, &tc, 0);
1137                        if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1138                             value = tc + 1;
1139                        else tag = 0;
1140                 }
1141                 found_tag = 1;
1142         }
1143
1144         if (found_tag) {
1145           vp->flags.tag = tag;
1146         }
1147
1148         switch (vp->operator) {
1149         default:
1150                 break;
1151
1152                 /*
1153                  *      For =* and !* operators, the value is irrelevant
1154                  *      so we return now.
1155                  */
1156         case T_OP_CMP_TRUE:
1157         case T_OP_CMP_FALSE:
1158                 vp->vp_strvalue[0] = '\0';
1159                 vp->length = 0;
1160                 return vp;
1161                 break;
1162
1163                 /*
1164                  *      Regular expression comparison of integer attributes
1165                  *      does a STRING comparison of the names of their
1166                  *      integer attributes.
1167                  */
1168         case T_OP_REG_EQ:       /* =~ */
1169         case T_OP_REG_NE:       /* !~ */
1170                 if (vp->type == PW_TYPE_INTEGER) {
1171                         return vp;
1172                 }
1173 #ifdef HAVE_REGEX_H
1174                 /*
1175                  *      Regular expression match with no regular
1176                  *      expression is wrong.
1177                  */
1178                 if (!value) {
1179                         pairfree(&vp);
1180                         return NULL;
1181                 }
1182
1183                 res = regcomp(&cre, value, REG_EXTENDED|REG_NOSUB);
1184                 if (res != 0) {
1185                         char    msg[128];
1186
1187                         regerror(res, &cre, msg, sizeof(msg));
1188                         librad_log("Illegal regular expression in attribute: %s: %s",
1189                                 vp->name, msg);
1190                         pairbasicfree(vp);
1191                         return NULL;
1192                 }
1193                 regfree(&cre);
1194 #else
1195                 librad_log("Regelar expressions not enabled in this build, error in attribute %s",
1196                                 vp->name);
1197                 pairbasicfree(vp);
1198                 return NULL;
1199 #endif
1200         }
1201
1202         /*
1203          *      FIXME: if (strcasecmp(attribute, vp->name) != 0)
1204          *      then the user MAY have typed in the attribute name
1205          *      as Vendor-%d-Attr-%d, and the value MAY be octets.
1206          *
1207          *      We probably want to fix pairparsevalue to accept
1208          *      octets as values for any attribute.
1209          */
1210         if (value && (pairparsevalue(vp, value) == NULL)) {
1211                 pairbasicfree(vp);
1212                 return NULL;
1213         }
1214
1215         return vp;
1216 }
1217
1218
1219 /*
1220  *      [a-zA-Z0-9_-:]+
1221  */
1222 static const int valid_attr_name[256] = {
1223         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 1, 0, 0,
1226         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1227         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1228         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1229         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1230         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
1231         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
1240
1241 /*
1242  *      Read a valuepair from a buffer, and advance pointer.
1243  *      Sets *eol to T_EOL if end of line was encountered.
1244  */
1245 VALUE_PAIR *pairread(char **ptr, LRAD_TOKEN *eol)
1246 {
1247         char            buf[64];
1248         char            attr[64];
1249         char            value[512];
1250         char            *p, *q;
1251         LRAD_TOKEN      token, t, xlat;
1252         VALUE_PAIR      *vp;
1253         size_t          len;
1254
1255         *eol = T_OP_INVALID;
1256
1257         p = *ptr;
1258         while ((*p == ' ') || (*p == '\t')) p++;
1259
1260         if (!*p) {
1261                 *eol = T_OP_INVALID;
1262                 librad_log("No token read where we expected an attribute name");
1263                 return NULL;
1264         }
1265
1266         if (*p == '#') {
1267                 *eol = T_HASH;
1268                 librad_log("Read a comment instead of a token");
1269                 return NULL;
1270         }
1271
1272         q = attr;
1273         for (len = 0; len < sizeof(attr); len++) {
1274                 if (valid_attr_name[(int)*p]) {
1275                         *q++ = *p++;
1276                         continue;
1277                 }
1278                 break;
1279         }
1280
1281         if (len == sizeof(attr)) {
1282                 *eol = T_OP_INVALID;
1283                 librad_log("Attribute name is too long");
1284                 return NULL;
1285         }
1286
1287         /*
1288          *      We may have Foo-Bar:= stuff, so back up.
1289          */
1290         if (attr[len - 1] == ':') {
1291                 p--;
1292                 len--;
1293         }
1294
1295         attr[len] = '\0';
1296         *ptr = p;
1297
1298         /* Now we should have an operator here. */
1299         token = gettoken(ptr, buf, sizeof(buf));
1300         if (token < T_EQSTART || token > T_EQEND) {
1301                 librad_log("expecting operator");
1302                 return NULL;
1303         }
1304
1305         /* Read value.  Note that empty string values are allowed */
1306         xlat = gettoken(ptr, value, sizeof(value));
1307         if (xlat == T_EOL) {
1308                 librad_log("failed to get value");
1309                 return NULL;
1310         }
1311
1312         /*
1313          *      Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1314          */
1315         p = *ptr;
1316         t = gettoken(&p, buf, sizeof(buf));
1317         if (t != T_EOL && t != T_COMMA && t != T_HASH) {
1318                 librad_log("Expected end of line or comma");
1319                 return NULL;
1320         }
1321
1322         *eol = t;
1323         if (t == T_COMMA) {
1324                 *ptr = p;
1325         }
1326
1327         vp = NULL;
1328         switch (xlat) {
1329                 /*
1330                  *      Make the full pair now.
1331                  */
1332         default:
1333                 vp = pairmake(attr, value, token);
1334                 break;
1335
1336                 /*
1337                  *      Perhaps do xlat's
1338                  */
1339         case T_DOUBLE_QUOTED_STRING:
1340                 p = strchr(value, '%');
1341                 if (p && (p[1] == '{')) {
1342                         if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1343                                 librad_log("Value too long");
1344                                 return NULL;
1345                         }
1346                         vp = pairmake(attr, NULL, token);
1347                         if (!vp) {
1348                                 *eol = T_OP_INVALID;
1349                                 return NULL;
1350                         }
1351
1352                         strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1353                         vp->flags.do_xlat = 1;
1354                         vp->length = 0;
1355                 } else {
1356                         vp = pairmake(attr, value, token);
1357                 }
1358                 break;
1359
1360
1361                 /*
1362                  *      Mark the pair to be allocated later.
1363                  */
1364         case T_BACK_QUOTED_STRING:
1365                 if (strlen(value) >= sizeof(vp->vp_strvalue)) {
1366                         librad_log("Value too long");
1367                         return NULL;
1368                 }
1369
1370                 vp = pairmake(attr, NULL, token);
1371                 if (!vp) {
1372                         *eol = T_OP_INVALID;
1373                         return NULL;
1374                 }
1375
1376                 vp->flags.do_xlat = 1;
1377                 strNcpy(vp->vp_strvalue, value, sizeof(vp->vp_strvalue));
1378                 vp->length = 0;
1379                 break;
1380         }
1381
1382         /*
1383          *      If we didn't make a pair, return an error.
1384          */
1385         if (!vp) {
1386                 *eol = T_OP_INVALID;
1387                 return NULL;
1388         }
1389
1390         return vp;
1391 }
1392
1393 /*
1394  *      Read one line of attribute/value pairs. This might contain
1395  *      multiple pairs seperated by comma's.
1396  */
1397 LRAD_TOKEN userparse(char *buffer, VALUE_PAIR **first_pair)
1398 {
1399         VALUE_PAIR      *vp;
1400         char            *p;
1401         LRAD_TOKEN      last_token = T_OP_INVALID;
1402         LRAD_TOKEN      previous_token;
1403
1404         /*
1405          *      We allow an empty line.
1406          */
1407         if (buffer[0] == 0)
1408                 return T_EOL;
1409
1410         p = buffer;
1411         do {
1412                 previous_token = last_token;
1413                 if ((vp = pairread(&p, &last_token)) == NULL) {
1414                         return last_token;
1415                 }
1416                 pairadd(first_pair, vp);
1417         } while (*p && (last_token == T_COMMA));
1418
1419         /*
1420          *      Don't tell the caller that there was a comment.
1421          */
1422         if (last_token == T_HASH) {
1423                 return previous_token;
1424         }
1425
1426         /*
1427          *      And return the last token which we read.
1428          */
1429         return last_token;
1430 }
1431
1432 /*
1433  *      Read valuepairs from the fp up to End-Of-File.
1434  *
1435  *      Hmm... this function is only used by radclient..
1436  */
1437 VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix)
1438 {
1439         char buf[8192];
1440         LRAD_TOKEN last_token = T_EOL;
1441         VALUE_PAIR *vp;
1442         VALUE_PAIR *list;
1443         int error = 0;
1444
1445         list = NULL;
1446
1447         while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
1448                 /*
1449                  *      If we get a '\n' by itself, we assume that's
1450                  *      the end of that VP
1451                  */
1452                 if ((buf[0] == '\n') && (list)) {
1453                         return list;
1454                 }
1455                 if ((buf[0] == '\n') && (!list)) {
1456                         continue;
1457                 }
1458
1459                 /*
1460                  *      Comments get ignored
1461                  */
1462                 if (buf[0] == '#') continue;
1463
1464                 /*
1465                  *      Read all of the attributes on the current line.
1466                  */
1467                 vp = NULL;
1468                 last_token = userparse(buf, &vp);
1469                 if (!vp) {
1470                         if (last_token != T_EOL) {
1471                                 librad_perror("%s", errprefix);
1472                                 error = 1;
1473                                 break;
1474                         }
1475                         break;
1476                 }
1477
1478                 pairadd(&list, vp);
1479                 buf[0] = '\0';
1480         }
1481
1482         if (error) pairfree(&list);
1483
1484         *pfiledone = 1;
1485
1486         return error ? NULL: list;
1487 }
1488
1489
1490
1491 /*
1492  *      Compare two pairs, using the operator from "one".
1493  *
1494  *      i.e. given two attributes, it does:
1495  *
1496  *      (two->data) (one->operator) (one->data)
1497  *
1498  *      e.g. "foo" != "bar"
1499  *
1500  *      Returns true (comparison is true), or false (comparison is not true);
1501  */
1502 int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
1503 {
1504         int compare;
1505
1506         switch (one->operator) {
1507         case T_OP_CMP_TRUE:
1508                 return (two != NULL);
1509
1510         case T_OP_CMP_FALSE:
1511                 return (two == NULL);
1512
1513                 /*
1514                  *      One is a regex, compile it, print two to a string,
1515                  *      and then do string comparisons.
1516                  */
1517         case T_OP_REG_EQ:
1518         case T_OP_REG_NE:
1519 #ifndef HAVE_REGEX_H
1520                 return -1;
1521 #else
1522                 {
1523                         regex_t reg;
1524                         char buffer[MAX_STRING_LEN * 4 + 1];
1525                         
1526                         compare = regcomp(&reg, one->vp_strvalue,
1527                                           REG_EXTENDED);
1528                         if (compare != 0) {
1529                                 regerror(compare, &reg, buffer, sizeof(buffer));
1530                                 librad_log("Illegal regular expression in attribute: %s: %s",
1531                                            one->name, buffer);
1532                                 return -1;
1533                         }
1534
1535                         vp_prints_value(buffer, sizeof(buffer), two, 0);
1536
1537                         /*
1538                          *      Don't care about substring matches,
1539                          *      oh well...
1540                          */
1541                         compare = regexec(&reg, buffer, 0, NULL, 0);
1542
1543                         regfree(&reg);
1544                         if (one->operator == T_OP_REG_EQ) return (compare == 0);
1545                         return (compare != 0);
1546                 }
1547 #endif
1548
1549         default:                /* we're OK */
1550                 break;
1551         }
1552                 
1553         /*
1554          *      After doing the previous check for special comparisons,
1555          *      do the per-type comparison here.
1556          */
1557         switch (one->type) {
1558         case PW_TYPE_ABINARY:
1559         case PW_TYPE_OCTETS:
1560         {
1561                 size_t length;
1562                 const uint8_t *p, *q;
1563
1564                 if (one->length < two->length) {
1565                         length = one->length;
1566                 } else {
1567                         length = two->length;
1568                 }
1569                 
1570                 p = two->vp_octets;
1571                 q = one->vp_octets;
1572                 while (length) {
1573                         compare = ((int) *p) - ((int) *q);
1574                         if (compare != 0) goto type_switch;
1575                 }
1576
1577                 /*
1578                  *      Contents are the same.  The return code
1579                  *      is therefore the difference in lengths.
1580                  *
1581                  *      i.e. "0x00" is smaller than "0x0000"
1582                  */
1583                 compare = two->length - one->length;
1584         }
1585                 break;
1586
1587         case PW_TYPE_STRING:
1588                 if (one->flags.caseless) {
1589                         compare = strcasecmp(two->vp_strvalue,
1590                                              one->vp_strvalue);
1591                 } else {
1592                         compare = strcmp(two->vp_strvalue,
1593                                          one->vp_strvalue);
1594                 }
1595                 break;
1596                 
1597         case PW_TYPE_INTEGER:
1598         case PW_TYPE_DATE:
1599                 compare = two->lvalue - one->lvalue;
1600                 break;
1601
1602         case PW_TYPE_IPADDR:
1603                 compare = ntohl(two->vp_ipaddr) - ntohl(one->vp_ipaddr);
1604                 break;
1605
1606         case PW_TYPE_IPV6ADDR:
1607                 compare = memcmp(&two->vp_ipv6addr, &one->vp_ipv6addr,
1608                                  sizeof(two->vp_ipv6addr));
1609                 break;
1610                 
1611         case PW_TYPE_IPV6PREFIX:
1612                 compare = memcmp(&two->vp_ipv6prefix, &one->vp_ipv6prefix,
1613                                  sizeof(two->vp_ipv6prefix));
1614                 break;
1615
1616         case PW_TYPE_IFID:
1617                 compare = memcmp(&two->vp_ifid, &one->vp_ifid,
1618                                  sizeof(two->vp_ifid));
1619                 break;
1620
1621         default:
1622                 return 0;       /* unknown type */
1623         }
1624
1625         /*
1626          *      Now do the operator comparison.
1627          */
1628  type_switch:
1629         switch (one->operator) {
1630         case T_OP_CMP_EQ:
1631                 return (compare == 0);
1632                 
1633         case T_OP_NE:
1634                 return (compare != 0);
1635                 
1636         case T_OP_LT:
1637                 return (compare < 0);
1638                 
1639         case T_OP_GT:
1640                 return (compare > 0);
1641
1642         case T_OP_LE:
1643                 return (compare <= 0);
1644
1645         case T_OP_GE:
1646                 return (compare >= 0);
1647
1648         default:
1649                 return 0;
1650         }
1651
1652         return 0;
1653 }