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