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