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