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