Only WiMAX attributes can be of type tlv
[freeradius.git] / src / lib / dict.c
1 /*
2  * dict.c       Routines to read the dictionary file.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/libradius.h>
27
28 #include        <ctype.h>
29
30 #ifdef HAVE_MALLOC_H
31 #include        <malloc.h>
32 #endif
33
34 #ifdef HAVE_SYS_STAT_H
35 #include        <sys/stat.h>
36 #endif
37
38 #define DICT_VALUE_MAX_NAME_LEN (128)
39 #define DICT_VENDOR_MAX_NAME_LEN (128)
40 #define DICT_ATTR_MAX_NAME_LEN (128)
41
42 static fr_hash_table_t *vendors_byname = NULL;
43 static fr_hash_table_t *vendors_byvalue = NULL;
44
45 static fr_hash_table_t *attributes_byname = NULL;
46 static fr_hash_table_t *attributes_byvalue = NULL;
47
48 static fr_hash_table_t *values_byvalue = NULL;
49 static fr_hash_table_t *values_byname = NULL;
50
51 static DICT_ATTR *dict_base_attrs[256];
52
53 /*
54  *      For faster HUP's, we cache the stat information for
55  *      files we've $INCLUDEd
56  */
57 typedef struct dict_stat_t {
58         struct dict_stat_t *next;
59         char               *name;
60         time_t             mtime;
61 } dict_stat_t;
62
63 static char *stat_root_dir = NULL;
64 static char *stat_root_file = NULL;
65
66 static dict_stat_t *stat_head = NULL;
67 static dict_stat_t *stat_tail = NULL;
68
69 typedef struct value_fixup_t {
70         char            attrstr[DICT_ATTR_MAX_NAME_LEN];
71         DICT_VALUE      *dval;
72         struct value_fixup_t *next;
73 } value_fixup_t;
74
75
76 /*
77  *      So VALUEs in the dictionary can have forward references.
78  */
79 static value_fixup_t *value_fixup = NULL;
80
81 static const FR_NAME_NUMBER type_table[] = {
82         { "integer",    PW_TYPE_INTEGER },
83         { "string",     PW_TYPE_STRING },
84         { "ipaddr",     PW_TYPE_IPADDR },
85         { "date",       PW_TYPE_DATE },
86         { "abinary",    PW_TYPE_ABINARY },
87         { "octets",     PW_TYPE_OCTETS },
88         { "ifid",       PW_TYPE_IFID },
89         { "ipv6addr",   PW_TYPE_IPV6ADDR },
90         { "ipv6prefix", PW_TYPE_IPV6PREFIX },
91         { "byte",       PW_TYPE_BYTE },
92         { "short",      PW_TYPE_SHORT },
93         { "ether",      PW_TYPE_ETHERNET },
94         { "combo-ip",   PW_TYPE_COMBO_IP },
95         { "tlv",        PW_TYPE_TLV },
96         { "signed",     PW_TYPE_SIGNED },
97         { NULL, 0 }
98 };
99
100
101 /*
102  *      WiMAX craziness.
103  */
104 #define MAX_TLV_NEST (4)
105 /*
106  *      Bit packing:
107  *      8 bits of base VSA
108  *      8 bits for nested TLV 1
109  *      8 bits for nested TLV 2
110  *      5 bits for nested TLV 3
111  *      3 bits for nested TLV 4
112  */
113 const int fr_wimax_max_tlv = MAX_TLV_NEST;
114 const int fr_wimax_shift[MAX_TLV_NEST + 1] = {
115   0, 8, 16, 24, 29
116 };
117
118 const int fr_wimax_mask[MAX_TLV_NEST + 1] = {
119   0, 0xff, 0xff, 0x1f, 0x07
120 };
121
122
123 /*
124  *      Create the hash of the name.
125  *
126  *      We copy the hash function here because it's substantially faster.
127  */
128 #define FNV_MAGIC_INIT (0x811c9dc5)
129 #define FNV_MAGIC_PRIME (0x01000193)
130
131 static uint32_t dict_hashname(const char *name)
132 {
133         uint32_t hash = FNV_MAGIC_INIT;
134         const char *p;
135
136         for (p = name; *p != '\0'; p++) {
137                 int c = *(const unsigned char *) p;
138                 if (isalpha(c)) c = tolower(c);
139
140                 hash *= FNV_MAGIC_PRIME;
141                 hash ^= (uint32_t ) (c & 0xff);
142         }
143
144         return hash;
145 }
146
147
148 /*
149  *      Hash callback functions.
150  */
151 static uint32_t dict_attr_name_hash(const void *data)
152 {
153         return dict_hashname(((const DICT_ATTR *)data)->name);
154 }
155
156 static int dict_attr_name_cmp(const void *one, const void *two)
157 {
158         const DICT_ATTR *a = one;
159         const DICT_ATTR *b = two;
160
161         return strcasecmp(a->name, b->name);
162 }
163
164 static uint32_t dict_attr_value_hash(const void *data)
165 {
166         uint32_t hash;
167         const DICT_ATTR *attr = data;
168
169         hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
170         return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
171 }
172
173 static int dict_attr_value_cmp(const void *one, const void *two)
174 {
175         const DICT_ATTR *a = one;
176         const DICT_ATTR *b = two;
177
178         if (a->vendor < b->vendor) return -1;
179         if (a->vendor > b->vendor) return +1;
180
181         return a->attr - b->attr;
182 }
183
184 static uint32_t dict_vendor_name_hash(const void *data)
185 {
186         return dict_hashname(((const DICT_VENDOR *)data)->name);
187 }
188
189 static int dict_vendor_name_cmp(const void *one, const void *two)
190 {
191         const DICT_VENDOR *a = one;
192         const DICT_VENDOR *b = two;
193
194         return strcasecmp(a->name, b->name);
195 }
196
197 static uint32_t dict_vendor_value_hash(const void *data)
198 {
199         return fr_hash(&(((const DICT_VENDOR *)data)->vendorpec),
200                          sizeof(((const DICT_VENDOR *)data)->vendorpec));
201 }
202
203 static int dict_vendor_value_cmp(const void *one, const void *two)
204 {
205         const DICT_VENDOR *a = one;
206         const DICT_VENDOR *b = two;
207
208         return a->vendorpec - b->vendorpec;
209 }
210
211 static uint32_t dict_value_name_hash(const void *data)
212 {
213         uint32_t hash;
214         const DICT_VALUE *dval = data;
215
216         hash = dict_hashname(dval->name);
217         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
218         return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
219 }
220
221 static int dict_value_name_cmp(const void *one, const void *two)
222 {
223         int rcode;
224         const DICT_VALUE *a = one;
225         const DICT_VALUE *b = two;
226
227         rcode = a->attr - b->attr;
228         if (rcode != 0) return rcode;
229
230         rcode = a->vendor - b->vendor;
231         if (rcode != 0) return rcode;
232
233         return strcasecmp(a->name, b->name);
234 }
235
236 static uint32_t dict_value_value_hash(const void *data)
237 {
238         uint32_t hash;
239         const DICT_VALUE *dval = data;
240
241         hash = fr_hash(&dval->attr, sizeof(dval->attr));
242         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
243         return fr_hash_update(&dval->value, sizeof(dval->value), hash);
244 }
245
246 static int dict_value_value_cmp(const void *one, const void *two)
247 {
248         int rcode;
249         const DICT_VALUE *a = one;
250         const DICT_VALUE *b = two;
251
252         if (a->vendor < b->vendor) return -1;
253         if (a->vendor > b->vendor) return +1;
254
255         rcode = a->attr - b->attr;
256         if (rcode != 0) return rcode;
257
258         return a->value - b->value;
259 }
260
261
262 /*
263  *      Free the list of stat buffers
264  */
265 static void dict_stat_free(void)
266 {
267         dict_stat_t *this, *next;
268
269         free(stat_root_dir);
270         stat_root_dir = NULL;
271         free(stat_root_file);
272         stat_root_file = NULL;
273
274         if (!stat_head) {
275                 stat_tail = NULL;
276                 return;
277         }
278
279         for (this = stat_head; this != NULL; this = next) {
280                 next = this->next;
281                 free(this->name);
282                 free(this);
283         }
284
285         stat_head = stat_tail = NULL;
286 }
287
288
289 /*
290  *      Add an entry to the list of stat buffers.
291  */
292 static void dict_stat_add(const char *name, const struct stat *stat_buf)
293 {
294         dict_stat_t *this;
295
296         this = malloc(sizeof(*this));
297         if (!this) return;
298         memset(this, 0, sizeof(*this));
299
300         this->name = strdup(name);
301         this->mtime = stat_buf->st_mtime;
302
303         if (!stat_head) {
304                 stat_head = stat_tail = this;
305         } else {
306                 stat_tail->next = this;
307                 stat_tail = this;
308         }
309 }
310
311
312 /*
313  *      See if any dictionaries have changed.  If not, don't
314  *      do anything.
315  */
316 static int dict_stat_check(const char *root_dir, const char *root_file)
317 {
318         struct stat buf;
319         dict_stat_t *this;
320
321         if (!stat_root_dir) return 0;
322         if (!stat_root_file) return 0;
323
324         if (strcmp(root_dir, stat_root_dir) != 0) return 0;
325         if (strcmp(root_file, stat_root_file) != 0) return 0;
326
327         if (!stat_head) return 0; /* changed, reload */
328
329         for (this = stat_head; this != NULL; this = this->next) {
330                 if (stat(this->name, &buf) < 0) return 0;
331
332                 if (buf.st_mtime != this->mtime) return 0;
333         }
334
335         return 1;
336 }
337
338 typedef struct fr_pool_t {
339         void    *page_end;
340         void    *free_ptr;
341         struct fr_pool_t *page_free;
342         struct fr_pool_t *page_next;
343 } fr_pool_t;
344
345 #define FR_POOL_SIZE (32768)
346 #define FR_ALLOC_ALIGN (8)
347
348 static fr_pool_t *dict_pool = NULL;
349
350 static fr_pool_t *fr_pool_create(void)
351 {
352         fr_pool_t *fp = malloc(FR_POOL_SIZE);
353
354         if (!fp) return NULL;
355
356         memset(fp, 0, FR_POOL_SIZE);
357
358         fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
359         fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
360         fp->page_free = fp;
361         fp->page_next = NULL;
362         return fp;
363 }
364
365 static void fr_pool_delete(fr_pool_t **pfp)
366 {
367         fr_pool_t *fp, *next;
368
369         if (!pfp || !*pfp) return;
370
371         for (fp = *pfp; fp != NULL; fp = next) {
372                 next = fp->page_next;
373                 free(fp);
374         }
375 }
376
377
378 static void *fr_pool_alloc(size_t size)
379 {
380         void *ptr;
381
382         if (size == 0) return NULL;
383
384         if (size > 256) return NULL; /* shouldn't happen */
385
386         if (!dict_pool) {
387                 dict_pool = fr_pool_create();
388                 if (!dict_pool) return NULL;
389         }
390
391         if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
392                 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
393         }
394
395         if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
396                 dict_pool->page_free->page_next = fr_pool_create();
397                 if (!dict_pool->page_free->page_next) return NULL;
398                 dict_pool->page_free = dict_pool->page_free->page_next;
399         }
400
401         ptr = dict_pool->page_free->free_ptr;
402         dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
403
404         return ptr;
405 }
406
407
408 static void fr_pool_free(UNUSED void *ptr)
409 {
410         /*
411          *      Place-holder for later code.
412          */
413 }
414
415 /*
416  *      Free the dictionary_attributes and dictionary_values lists.
417  */
418 void dict_free(void)
419 {
420         /*
421          *      Free the tables
422          */
423         fr_hash_table_free(vendors_byname);
424         fr_hash_table_free(vendors_byvalue);
425         vendors_byname = NULL;
426         vendors_byvalue = NULL;
427
428         fr_hash_table_free(attributes_byname);
429         fr_hash_table_free(attributes_byvalue);
430         attributes_byname = NULL;
431         attributes_byvalue = NULL;
432
433         fr_hash_table_free(values_byname);
434         fr_hash_table_free(values_byvalue);
435         values_byname = NULL;
436         values_byvalue = NULL;
437
438         memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
439
440         fr_pool_delete(&dict_pool);
441
442         dict_stat_free();
443 }
444
445
446 /*
447  *      Add vendor to the list.
448  */
449 int dict_addvendor(const char *name, int value)
450 {
451         size_t length;
452         DICT_VENDOR *dv;
453
454         if (value > 65535) {
455                 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 65535");
456                 return -1;
457         }
458
459         if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
460                 fr_strerror_printf("dict_addvendor: vendor name too long");
461                 return -1;
462         }
463
464         if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
465                 fr_strerror_printf("dict_addvendor: out of memory");
466                 return -1;
467         }
468
469         strcpy(dv->name, name);
470         dv->vendorpec  = value;
471         dv->type = dv->length = 1; /* defaults */
472
473         if (!fr_hash_table_insert(vendors_byname, dv)) {
474                 DICT_VENDOR *old_dv;
475
476                 old_dv = fr_hash_table_finddata(vendors_byname, dv);
477                 if (!old_dv) {
478                         fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
479                         return -1;
480                 }
481                 if (old_dv->vendorpec != dv->vendorpec) {
482                         fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
483                         return -1;
484                 }
485
486                 /*
487                  *      Already inserted.  Discard the duplicate entry.
488                  */
489                 fr_pool_free(dv);
490                 return 0;
491         }
492
493         /*
494          *      Insert the SAME pointer (not free'd when this table is
495          *      deleted), into another table.
496          *
497          *      We want this behaviour because we want OLD names for
498          *      the attributes to be read from the configuration
499          *      files, but when we're printing them, (and looking up
500          *      by value) we want to use the NEW name.
501          */
502         if (!fr_hash_table_replace(vendors_byvalue, dv)) {
503                 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
504                            name);
505                 return -1;
506         }
507
508         return 0;
509 }
510
511 /*
512  *      Add an attribute to the dictionary.
513  */
514 int dict_addattr(const char *name, int attr, int vendor, int type,
515                  ATTR_FLAGS flags)
516 {
517         size_t namelen;
518         static int      max_attr = 0;
519         DICT_ATTR       *da;
520
521         namelen = strlen(name);
522         if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
523                 fr_strerror_printf("dict_addattr: attribute name too long");
524                 return -1;
525         }
526
527         /*
528          *      If the attr is '-1', that means use a pre-existing
529          *      one (if it already exists).  If one does NOT already exist,
530          *      then create a new attribute, with a non-conflicting value,
531          *      and use that.
532          */
533         if (attr == -1) {
534                 if (dict_attrbyname(name)) {
535                         return 0; /* exists, don't add it again */
536                 }
537
538                 attr = ++max_attr;
539
540         } else if (vendor == 0) {
541                 /*
542                  *  Update 'max_attr'
543                  */
544                 if (attr > max_attr) {
545                         max_attr = attr;
546                 }
547         }
548
549         if (attr < 0) {
550                 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
551                 return -1;
552         }
553
554         if (vendor) {
555                 DICT_VENDOR *dv;
556                 static DICT_VENDOR *last_vendor = NULL;
557
558                 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
559                         fr_strerror_printf("TLV's cannot be encrypted");
560                         return -1;
561                 }
562
563                 if (flags.is_tlv && flags.has_tag) {
564                         fr_strerror_printf("Sub-TLV's cannot have a tag");
565                         return -1;
566                 }
567
568                 if (flags.has_tlv && flags.has_tag) {
569                         fr_strerror_printf("TLV's cannot have a tag");
570                         return -1;
571                 }
572
573                 /*
574                  *      Most ATTRIBUTEs are bunched together by
575                  *      VENDOR.  We can save a lot of lookups on
576                  *      dictionary initialization by caching the last
577                  *      vendor.
578                  */
579                 if (last_vendor && (vendor == last_vendor->vendorpec)) {
580                         dv = last_vendor;
581                 } else {
582                         dv = dict_vendorbyvalue(vendor);
583                         last_vendor = dv;
584                 }
585
586                 /*
587                  *      If the vendor isn't defined, die.
588                  */
589                 if (!dv) {
590                         fr_strerror_printf("dict_addattr: Unknown vendor");
591                         return -1;
592                 }
593
594                 /*
595                  *      FIXME: Switch over dv->type, and limit things
596                  *      properly.
597                  */
598                 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
599                         fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
600                         return -1;
601                 } /* else 256..65535 are allowed */
602         }
603
604         /*
605          *      Create a new attribute for the list
606          */
607         if ((da = fr_pool_alloc(sizeof(*da) + namelen)) == NULL) {
608                 fr_strerror_printf("dict_addattr: out of memory");
609                 return -1;
610         }
611
612         memcpy(da->name, name, namelen);
613         da->name[namelen] = '\0';
614         da->attr = attr;
615         da->vendor = vendor;
616         da->type = type;
617         da->flags = flags;
618         da->vendor = vendor;
619
620         /*
621          *      Insert the attribute, only if it's not a duplicate.
622          */
623         if (!fr_hash_table_insert(attributes_byname, da)) {
624                 DICT_ATTR       *a;
625
626                 /*
627                  *      If the attribute has identical number, then
628                  *      ignore the duplicate.
629                  */
630                 a = fr_hash_table_finddata(attributes_byname, da);
631                 if (a && (strcasecmp(a->name, da->name) == 0)) {
632                         if (a->attr != da->attr) {
633                                 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
634                                 fr_pool_free(da);
635                                 return -1;
636                         }
637
638                         /*
639                          *      Same name, same vendor, same attr,
640                          *      maybe the flags and/or type is
641                          *      different.  Let the new value
642                          *      over-ride the old one.
643                          */
644                 }
645
646
647                 fr_hash_table_delete(attributes_byvalue, a);
648
649                 if (!fr_hash_table_replace(attributes_byname, da)) {
650                         fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
651                         fr_pool_free(da);
652                         return -1;
653                 }
654         }
655
656         /*
657          *      Insert the SAME pointer (not free'd when this entry is
658          *      deleted), into another table.
659          *
660          *      We want this behaviour because we want OLD names for
661          *      the attributes to be read from the configuration
662          *      files, but when we're printing them, (and looking up
663          *      by value) we want to use the NEW name.
664          */
665         if (!fr_hash_table_replace(attributes_byvalue, da)) {
666                 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
667                 return -1;
668         }
669
670         if (!vendor && (attr > 0) && (attr < 256)) {
671                  dict_base_attrs[attr] = da;
672         }
673
674         return 0;
675 }
676
677
678 /*
679  *      Add a value for an attribute to the dictionary.
680  */
681 int dict_addvalue(const char *namestr, const char *attrstr, int value)
682 {
683         size_t          length;
684         DICT_ATTR       *dattr;
685         DICT_VALUE      *dval;
686
687         static DICT_ATTR *last_attr = NULL;
688
689         if (!*namestr) {
690                 fr_strerror_printf("dict_addvalue: empty names are not permitted");
691                 return -1;
692         }
693
694         if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
695                 fr_strerror_printf("dict_addvalue: value name too long");
696                 return -1;
697         }
698
699         if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
700                 fr_strerror_printf("dict_addvalue: out of memory");
701                 return -1;
702         }
703         memset(dval, 0, sizeof(*dval));
704
705         strcpy(dval->name, namestr);
706         dval->value = value;
707
708         /*
709          *      Most VALUEs are bunched together by ATTRIBUTE.  We can
710          *      save a lot of lookups on dictionary initialization by
711          *      caching the last attribute.
712          */
713         if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
714                 dattr = last_attr;
715         } else {
716                 dattr = dict_attrbyname(attrstr);
717                 last_attr = dattr;
718         }
719
720         /*
721          *      Remember which attribute is associated with this
722          *      value, if possible.
723          */
724         if (dattr) {
725                 if (dattr->flags.has_value_alias) {
726                         fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
727                         return -1;
728                 }
729
730                 dval->attr = dattr->attr;
731                 dval->vendor = dattr->vendor;
732
733                 /*
734                  *      Enforce valid values
735                  *
736                  *      Don't worry about fixups...
737                  */
738                 switch (dattr->type) {
739                         case PW_TYPE_BYTE:
740                                 if (value > 255) {
741                                         fr_pool_free(dval);
742                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
743                                         return -1;
744                                 }
745                                 break;
746                         case PW_TYPE_SHORT:
747                                 if (value > 65535) {
748                                         fr_pool_free(dval);
749                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
750                                         return -1;
751                                 }
752                                 break;
753
754                                 /*
755                                  *      Allow octets for now, because
756                                  *      of dictionary.cablelabs
757                                  */
758                         case PW_TYPE_OCTETS:
759
760                         case PW_TYPE_INTEGER:
761                                 break;
762
763                         default:
764                                 fr_pool_free(dval);
765                                 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
766                                            fr_int2str(type_table, dattr->type, "?Unknown?"));
767                                 return -1;
768                 }
769
770                 dattr->flags.has_value = 1;
771         } else {
772                 value_fixup_t *fixup;
773
774                 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
775                 if (!fixup) {
776                         fr_pool_free(dval);
777                         fr_strerror_printf("dict_addvalue: out of memory");
778                         return -1;
779                 }
780                 memset(fixup, 0, sizeof(*fixup));
781
782                 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
783                 fixup->dval = dval;
784
785                 /*
786                  *      Insert to the head of the list.
787                  */
788                 fixup->next = value_fixup;
789                 value_fixup = fixup;
790
791                 return 0;
792         }
793
794         /*
795          *      Add the value into the dictionary.
796          */
797         if (!fr_hash_table_insert(values_byname, dval)) {
798                 if (dattr) {
799                         DICT_VALUE *old;
800
801                         /*
802                          *      Suppress duplicates with the same
803                          *      name and value.  There are lots in
804                          *      dictionary.ascend.
805                          */
806                         old = dict_valbyname(dattr->attr, dattr->vendor, namestr);
807                         if (old && (old->value == dval->value)) {
808                                 fr_pool_free(dval);
809                                 return 0;
810                         }
811                 }
812
813                 fr_pool_free(dval);
814                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
815                 return -1;
816         }
817
818         /*
819          *      There are multiple VALUE's, keyed by attribute, so we
820          *      take care of that here.
821          */
822         if (!fr_hash_table_replace(values_byvalue, dval)) {
823                 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
824                            namestr);
825                 return -1;
826         }
827
828         return 0;
829 }
830
831 static int sscanf_i(const char *str, int *pvalue)
832 {
833         int rcode = 0;
834         int base = 10;
835         const char *tab = "0123456789";
836
837         if ((str[0] == '0') &&
838             ((str[1] == 'x') || (str[1] == 'X'))) {
839                 tab = "0123456789abcdef";
840                 base = 16;
841
842                 str += 2;
843         }
844
845         while (*str) {
846                 const char *c;
847
848                 c = memchr(tab, tolower((int) *str), base);
849                 if (!c) return 0;
850
851                 rcode *= base;
852                 rcode += (c - tab);
853                 str++;
854         }
855
856         *pvalue = rcode;
857         return 1;
858 }
859
860
861 /*
862  *      Process the ATTRIBUTE command
863  */
864 static int process_attribute(const char* fn, const int line,
865                              const int block_vendor, DICT_ATTR *block_tlv,
866                              int tlv_depth, char **argv, int argc)
867 {
868         int             vendor = 0;
869         int             value;
870         int             type;
871         ATTR_FLAGS      flags;
872
873         if ((argc < 3) || (argc > 4)) {
874                 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
875                         fn, line);
876                 return -1;
877         }
878
879         /*
880          *      Validate all entries
881          */
882         if (!sscanf_i(argv[1], &value)) {
883                 fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
884                 return -1;
885         }
886
887         /*
888          *      find the type of the attribute.
889          */
890         type = fr_str2int(type_table, argv[2], -1);
891         if (type < 0) {
892                 fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
893                         fn, line, argv[2]);
894                 return -1;
895         }
896
897         /*
898          *      Only look up the vendor if the string
899          *      is non-empty.
900          */
901         memset(&flags, 0, sizeof(flags));
902         if (argc == 4) {
903                 char *key, *next, *last;
904
905                 key = argv[3];
906                 do {
907                         next = strchr(key, ',');
908                         if (next) *(next++) = '\0';
909
910                         if (strcmp(key, "has_tag") == 0 ||
911                             strcmp(key, "has_tag=1") == 0) {
912                                 /* Boolean flag, means this is a
913                                    tagged attribute */
914                                 flags.has_tag = 1;
915                                 
916                         } else if (strncmp(key, "encrypt=", 8) == 0) {
917                                 /* Encryption method, defaults to 0 (none).
918                                    Currently valid is just type 2,
919                                    Tunnel-Password style, which can only
920                                    be applied to strings. */
921                                 flags.encrypt = strtol(key + 8, &last, 0);
922                                 if (*last) {
923                                         fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
924                                                     fn, line, key);
925                                         return -1;
926                                 }
927                                 
928                         } else if (strncmp(key, "array", 8) == 0) {
929                                 flags.array = 1;
930                                 
931                                 switch (type) {
932                                         case PW_TYPE_IPADDR:
933                                         case PW_TYPE_BYTE:
934                                         case PW_TYPE_SHORT:
935                                         case PW_TYPE_INTEGER:
936                                         case PW_TYPE_DATE:
937                                                 break;
938
939                                         default:
940                                                 fr_strerror_printf( "dict_init: %s[%d] Only IP addresses can have the \"array\" flag set.",
941                                                             fn, line);
942                                                 return -1;
943                                 }
944
945                                 /*
946                                  *      The only thing is the vendor name,
947                                  *      and it's a known name: allow it.
948                                  */
949                         } else if ((key == argv[3]) && !next && !block_vendor &&
950                                    ((vendor = dict_vendorbyname(key)) !=0)) {
951                                 break;
952
953                         } else {
954                                 fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
955                                             fn, line, key);
956                                 return -1;
957                         }
958
959                         key = next;
960                         if (key && !*key) break;
961                 } while (key);
962         }
963
964         if (block_vendor) vendor = block_vendor;
965
966         /*
967          *      Special checks for tags, they make our life much more
968          *      difficult.
969          */
970         if (flags.has_tag) {
971                 /*
972                  *      Only string, octets, and integer can be tagged.
973                  */
974                 switch (type) {
975                 case PW_TYPE_STRING:
976                 case PW_TYPE_INTEGER:
977                         break;
978
979                 default:
980                         fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
981                                    fn, line,
982                                    fr_int2str(type_table, type, "?Unknown?"));
983                         return -1;
984                 }
985         }
986
987         if (type == PW_TYPE_TLV) {
988                 if (!block_vendor || (block_vendor != VENDORPEC_WIMAX)) {
989                         fr_strerror_printf("dict_init: %s[%d]: Only WiMAX attributes can be of type \"tlv\"",
990                                            fn, line);
991                         return -1;
992                 }
993
994                 flags.has_tlv = 1;
995         }
996
997         if (block_tlv) {
998                 /*
999                  *      TLV's can be only one octet.
1000                  */
1001           if ((value <= 0) || ((value & ~fr_wimax_mask[tlv_depth]) != 0)) {
1002                         fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1003                                     fn, line);
1004                         return -1;
1005                 }
1006
1007                 /*
1008                  *      
1009                  */
1010                 value <<= fr_wimax_shift[tlv_depth];
1011                 value |= block_tlv->attr;
1012                 flags.is_tlv = 1;
1013         }
1014
1015         /*
1016          *      Add it in.
1017          */
1018         if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1019                 char buffer[256];
1020
1021                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1022
1023                 fr_strerror_printf("dict_init: %s[%d]: %s",
1024                                    fn, line, buffer);
1025                 return -1;
1026         }
1027
1028         return 0;
1029 }
1030
1031
1032 /*
1033  *      Process the VALUE command
1034  */
1035 static int process_value(const char* fn, const int line, char **argv,
1036                          int argc)
1037 {
1038         int     value;
1039
1040         if (argc != 3) {
1041                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1042                         fn, line);
1043                 return -1;
1044         }
1045         /*
1046          *      For Compatibility, skip "Server-Config"
1047          */
1048         if (strcasecmp(argv[0], "Server-Config") == 0)
1049                 return 0;
1050
1051         /*
1052          *      Validate all entries
1053          */
1054         if (!sscanf_i(argv[2], &value)) {
1055                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1056                         fn, line);
1057                 return -1;
1058         }
1059
1060         if (dict_addvalue(argv[1], argv[0], value) < 0) {
1061                 char buffer[256];
1062
1063                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1064
1065                 fr_strerror_printf("dict_init: %s[%d]: %s",
1066                                    fn, line, buffer);
1067                 return -1;
1068         }
1069
1070         return 0;
1071 }
1072
1073
1074 /*
1075  *      Process the VALUE-ALIAS command
1076  *
1077  *      This allows VALUE mappings to be shared among multiple
1078  *      attributes.
1079  */
1080 static int process_value_alias(const char* fn, const int line, char **argv,
1081                                int argc)
1082 {
1083         DICT_ATTR *my_da, *da;
1084         DICT_VALUE *dval;
1085
1086         if (argc != 2) {
1087                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1088                         fn, line);
1089                 return -1;
1090         }
1091
1092         my_da = dict_attrbyname(argv[0]);
1093         if (!my_da) {
1094                 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1095                            fn, line, argv[1]);
1096                 return -1;
1097         }
1098
1099         if (my_da->flags.has_value) {
1100                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE",
1101                            fn, line, argv[0]);
1102                 return -1;
1103         }
1104
1105         if (my_da->flags.has_value_alias) {
1106                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
1107                            fn, line, argv[0]);
1108                 return -1;
1109         }
1110
1111         da = dict_attrbyname(argv[1]);
1112         if (!da) {
1113                 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
1114                            fn, line, argv[1]);
1115                 return -1;
1116         }
1117
1118         if (!da->flags.has_value) {
1119                 fr_strerror_printf("dict_init: %s[%d]: VALUE-ALIAS cannot refer to ATTRIBUTE %s: It has no values",
1120                            fn, line, argv[1]);
1121                 return -1;
1122         }
1123
1124         if (da->flags.has_value_alias) {
1125                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
1126                            fn, line, argv[1]);
1127                 return -1;
1128         }
1129
1130         if (my_da->type != da->type) {
1131                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
1132                            fn, line);
1133                 return -1;
1134         }
1135
1136         if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
1137                 fr_strerror_printf("dict_addvalue: out of memory");
1138                 return -1;
1139         }
1140
1141         dval->name[0] = '\0';   /* empty name */
1142         dval->attr = my_da->attr;
1143         dval->vendor = my_da->vendor;
1144         dval->value = da->attr;
1145
1146         if (!fr_hash_table_insert(values_byname, dval)) {
1147                 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
1148                            fn, line);
1149                 fr_pool_free(dval);
1150                 return -1;
1151         }
1152
1153         return 0;
1154 }
1155
1156
1157 /*
1158  *      Process the VENDOR command
1159  */
1160 static int process_vendor(const char* fn, const int line, char **argv,
1161                           int argc)
1162 {
1163         int     value;
1164         int     continuation = 0;
1165         const   char *format = NULL;
1166
1167         if ((argc < 2) || (argc > 3)) {
1168                 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
1169                             fn, line);
1170                 return -1;
1171         }
1172
1173         /*
1174          *       Validate all entries
1175          */
1176         if (!isdigit((int) argv[1][0])) {
1177                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1178                         fn, line);
1179                 return -1;
1180         }
1181         value = atoi(argv[1]);
1182
1183         /* Create a new VENDOR entry for the list */
1184         if (dict_addvendor(argv[0], value) < 0) {
1185                 char buffer[256];
1186
1187                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1188
1189                 fr_strerror_printf("dict_init: %s[%d]: %s",
1190                            fn, line, buffer);
1191                 return -1;
1192         }
1193
1194         /*
1195          *      Look for a format statement
1196          */
1197         if (argc == 3) {
1198                 format = argv[2];
1199
1200         } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
1201                 format = "format=4,0";
1202
1203         } else if (value == VENDORPEC_LUCENT) {
1204                 format = "format=2,1";
1205
1206         } else if (value == VENDORPEC_STARENT) {
1207                 format = "format=2,2";
1208
1209         } /* else no fixups to do */
1210
1211         if (format) {
1212                 int type, length;
1213                 const char *p;
1214                 DICT_VENDOR *dv;
1215
1216                 if (strncasecmp(format, "format=", 7) != 0) {
1217                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
1218                                    fn, line, format);
1219                         return -1;
1220                 }
1221
1222                 p = format + 7;
1223                 if ((strlen(p) < 3) ||
1224                     !isdigit((int) p[0]) ||
1225                     (p[1] != ',') ||
1226                     !isdigit((int) p[2]) ||
1227                     (p[3] && (p[3] != ','))) {
1228                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1229                                    fn, line, p);
1230                         return -1;
1231                 }
1232
1233                 type = (int) (p[0] - '0');
1234                 length = (int) (p[2] - '0');
1235
1236                 if (p[3] == ',') {
1237                         if ((p[4] != 'c') ||
1238                             (p[5] != '\0')) {
1239                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1240                                            fn, line, p);
1241                                 return -1;
1242                         }
1243                         continuation = 1;
1244
1245                         if ((value != VENDORPEC_WIMAX) ||
1246                             (type != 1) || (length != 1)) {
1247                                 fr_strerror_printf("dict_init: %s[%d]: Only WiMAX VSAs can have continuations",
1248                                            fn, line);
1249                                 return -1;
1250                         }
1251                 }
1252
1253                 dv = dict_vendorbyvalue(value);
1254                 if (!dv) {
1255                         fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
1256                                    fn, line);
1257                         return -1;
1258                 }
1259
1260                 if ((type != 1) && (type != 2) && (type != 4)) {
1261                         fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
1262                                    fn, line, type);
1263                         return -1;
1264                 }
1265
1266                 if ((length != 0) && (length != 1) && (length != 2)) {
1267                         fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
1268                                    fn, line, length);
1269                         return -1;
1270                 }
1271
1272                 dv->type = type;
1273                 dv->length = length;
1274                 dv->flags = continuation;
1275         }
1276
1277         return 0;
1278 }
1279
1280 /*
1281  *      String split routine.  Splits an input string IN PLACE
1282  *      into pieces, based on spaces.
1283  */
1284 static int str2argv(char *str, char **argv, int max_argc)
1285 {
1286         int argc = 0;
1287
1288         while (*str) {
1289                 if (argc >= max_argc) return argc;
1290
1291                 /*
1292                  *      Chop out comments early.
1293                  */
1294                 if (*str == '#') {
1295                         *str = '\0';
1296                         break;
1297                 }
1298
1299                 while ((*str == ' ') ||
1300                        (*str == '\t') ||
1301                        (*str == '\r') ||
1302                        (*str == '\n')) *(str++) = '\0';
1303
1304                 if (!*str) return argc;
1305
1306                 argv[argc] = str;
1307                 argc++;
1308
1309                 while (*str &&
1310                        (*str != ' ') &&
1311                        (*str != '\t') &&
1312                        (*str != '\r') &&
1313                        (*str != '\n')) str++;
1314         }
1315
1316         return argc;
1317 }
1318
1319 #define MAX_ARGV (16)
1320
1321 /*
1322  *      Initialize the dictionary.
1323  */
1324 static int my_dict_init(const char *dir, const char *fn,
1325                         const char *src_file, int src_line)
1326 {
1327         FILE    *fp;
1328         char    dirtmp[256];
1329         char    buf[256];
1330         char    *p;
1331         int     line = 0;
1332         int     vendor;
1333         int     block_vendor;
1334         struct stat statbuf;
1335         char    *argv[MAX_ARGV];
1336         int     argc;
1337         DICT_ATTR *da, *block_tlv[MAX_TLV_NEST + 1];
1338         int     which_block_tlv = 0;
1339
1340         block_tlv[0] = NULL;
1341         block_tlv[1] = NULL;
1342         block_tlv[2] = NULL;
1343
1344         if (strlen(fn) >= sizeof(dirtmp) / 2 ||
1345             strlen(dir) >= sizeof(dirtmp) / 2) {
1346                 fr_strerror_printf("dict_init: filename name too long");
1347                 return -1;
1348         }
1349
1350         /*
1351          *      First see if fn is relative to dir. If so, create
1352          *      new filename. If not, remember the absolute dir.
1353          */
1354         if ((p = strrchr(fn, FR_DIR_SEP)) != NULL) {
1355                 strcpy(dirtmp, fn);
1356                 dirtmp[p - fn] = 0;
1357                 dir = dirtmp;
1358         } else if (dir && dir[0] && strcmp(dir, ".") != 0) {
1359                 snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn);
1360                 fn = dirtmp;
1361         }
1362
1363         if ((fp = fopen(fn, "r")) == NULL) {
1364                 if (!src_file) {
1365                         fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
1366                                    fn, strerror(errno));
1367                 } else {
1368                         fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
1369                                    src_file, src_line, fn, strerror(errno));
1370                 }
1371                 return -1;
1372         }
1373
1374         stat(fn, &statbuf); /* fopen() guarantees this will succeed */
1375         if (!S_ISREG(statbuf.st_mode)) {
1376                 fclose(fp);
1377                 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
1378                            fn);
1379                 return -1;
1380         }
1381
1382         /*
1383          *      Globally writable dictionaries means that users can control
1384          *      the server configuration with little difficulty.
1385          */
1386 #ifdef S_IWOTH
1387         if ((statbuf.st_mode & S_IWOTH) != 0) {
1388                 fclose(fp);
1389                 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable.  Refusing to start due to insecure configuration.",
1390                            fn);
1391                 return -1;
1392         }
1393 #endif
1394
1395         dict_stat_add(fn, &statbuf);
1396
1397         /*
1398          *      Seed the random pool with data.
1399          */
1400         fr_rand_seed(&statbuf, sizeof(statbuf));
1401
1402         block_vendor = 0;
1403
1404         while (fgets(buf, sizeof(buf), fp) != NULL) {
1405                 line++;
1406                 if (buf[0] == '#' || buf[0] == 0 ||
1407                     buf[0] == '\n' || buf[0] == '\r')
1408                         continue;
1409
1410                 /*
1411                  *  Comment characters should NOT be appearing anywhere but
1412                  *  as start of a comment;
1413                  */
1414                 p = strchr(buf, '#');
1415                 if (p) *p = '\0';
1416
1417                 argc = str2argv(buf, argv, MAX_ARGV);
1418                 if (argc == 0) continue;
1419
1420                 if (argc == 1) {
1421                         fr_strerror_printf( "dict_init: %s[%d] invalid entry",
1422                                     fn, line);
1423                         fclose(fp);
1424                         return -1;
1425                 }
1426
1427                 /*
1428                  *      Process VALUE lines.
1429                  */
1430                 if (strcasecmp(argv[0], "VALUE") == 0) {
1431                         if (process_value(fn, line,
1432                                           argv + 1, argc - 1) == -1) {
1433                                 fclose(fp);
1434                                 return -1;
1435                         }
1436                         continue;
1437                 }
1438
1439                 /*
1440                  *      Perhaps this is an attribute.
1441                  */
1442                 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
1443                         if (process_attribute(fn, line, block_vendor,
1444                                               block_tlv[which_block_tlv],
1445                                               which_block_tlv,
1446                                               argv + 1, argc - 1) == -1) {
1447                                 fclose(fp);
1448                                 return -1;
1449                         }
1450                         continue;
1451                 }
1452
1453                 /*
1454                  *      See if we need to import another dictionary.
1455                  */
1456                 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
1457                         if (my_dict_init(dir, argv[1], fn, line) < 0) {
1458                                 fclose(fp);
1459                                 return -1;
1460                         }
1461                         continue;
1462                 } /* $INCLUDE */
1463
1464                 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
1465                         if (process_value_alias(fn, line,
1466                                                 argv + 1, argc - 1) == -1) {
1467                                 fclose(fp);
1468                                 return -1;
1469                         }
1470                         continue;
1471                 }
1472
1473                 /*
1474                  *      Process VENDOR lines.
1475                  */
1476                 if (strcasecmp(argv[0], "VENDOR") == 0) {
1477                         if (process_vendor(fn, line,
1478                                            argv + 1, argc - 1) == -1) {
1479                                 fclose(fp);
1480                                 return -1;
1481                         }
1482                         continue;
1483                 }
1484
1485                 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
1486                         if (argc != 2) {
1487                                 fr_strerror_printf(
1488                                 "dict_init: %s[%d] invalid BEGIN-TLV entry",
1489                                         fn, line);
1490                                 fclose(fp);
1491                                 return -1;
1492                         }
1493
1494                         da = dict_attrbyname(argv[1]);
1495                         if (!da) {
1496                                 fr_strerror_printf(
1497                                         "dict_init: %s[%d]: unknown attribute %s",
1498                                         fn, line, argv[1]);
1499                                 fclose(fp);
1500                                 return -1;
1501                         }
1502
1503                         if (da->type != PW_TYPE_TLV) {
1504                                 fr_strerror_printf(
1505                                         "dict_init: %s[%d]: attribute %s is not of type tlv",
1506                                         fn, line, argv[1]);
1507                                 fclose(fp);
1508                                 return -1;
1509                         }
1510
1511                         if (which_block_tlv >= MAX_TLV_NEST) {
1512                                 fr_strerror_printf(
1513                                         "dict_init: %s[%d]: TLVs are nested too deep",
1514                                         fn, line);
1515                                 fclose(fp);
1516                                 return -1;
1517                         }
1518
1519
1520                         block_tlv[++which_block_tlv] = da;
1521                         continue;
1522                 } /* BEGIN-TLV */
1523
1524                 if (strcasecmp(argv[0], "END-TLV") == 0) {
1525                         if (argc != 2) {
1526                                 fr_strerror_printf(
1527                                 "dict_init: %s[%d] invalid END-TLV entry",
1528                                         fn, line);
1529                                 fclose(fp);
1530                                 return -1;
1531                         }
1532
1533                         da = dict_attrbyname(argv[1]);
1534                         if (!da) {
1535                                 fr_strerror_printf(
1536                                         "dict_init: %s[%d]: unknown attribute %s",
1537                                         fn, line, argv[1]);
1538                                 fclose(fp);
1539                                 return -1;
1540                         }
1541
1542                         if (da != block_tlv[which_block_tlv]) {
1543                                 fr_strerror_printf(
1544                                         "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
1545                                         fn, line, argv[1]);
1546                                 fclose(fp);
1547                                 return -1;
1548                         }
1549                         block_tlv[which_block_tlv--] = NULL;
1550                         continue;
1551                 } /* END-VENDOR */
1552
1553                 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
1554                         if (argc != 2) {
1555                                 fr_strerror_printf(
1556                                 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
1557                                         fn, line);
1558                                 fclose(fp);
1559                                 return -1;
1560                         }
1561
1562                         vendor = dict_vendorbyname(argv[1]);
1563                         if (!vendor) {
1564                                 fr_strerror_printf(
1565                                         "dict_init: %s[%d]: unknown vendor %s",
1566                                         fn, line, argv[1]);
1567                                 fclose(fp);
1568                                 return -1;
1569                         }
1570                         block_vendor = vendor;
1571                         continue;
1572                 } /* BEGIN-VENDOR */
1573
1574                 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
1575                         if (argc != 2) {
1576                                 fr_strerror_printf(
1577                                 "dict_init: %s[%d] invalid END-VENDOR entry",
1578                                         fn, line);
1579                                 fclose(fp);
1580                                 return -1;
1581                         }
1582
1583                         vendor = dict_vendorbyname(argv[1]);
1584                         if (!vendor) {
1585                                 fr_strerror_printf(
1586                                         "dict_init: %s[%d]: unknown vendor %s",
1587                                         fn, line, argv[1]);
1588                                 fclose(fp);
1589                                 return -1;
1590                         }
1591
1592                         if (vendor != block_vendor) {
1593                                 fr_strerror_printf(
1594                                         "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
1595                                         fn, line, argv[1]);
1596                                 fclose(fp);
1597                                 return -1;
1598                         }
1599                         block_vendor = 0;
1600                         continue;
1601                 } /* END-VENDOR */
1602
1603                 /*
1604                  *      Any other string: We don't recognize it.
1605                  */
1606                 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
1607                            fn, line, argv[0]);
1608                 fclose(fp);
1609                 return -1;
1610         }
1611         fclose(fp);
1612         return 0;
1613 }
1614
1615
1616 /*
1617  *      Empty callback for hash table initialization.
1618  */
1619 static int null_callback(void *ctx, void *data)
1620 {
1621         ctx = ctx;              /* -Wunused */
1622         data = data;            /* -Wunused */
1623
1624         return 0;
1625 }
1626
1627
1628 /*
1629  *      Initialize the directory, then fix the attr member of
1630  *      all attributes.
1631  */
1632 int dict_init(const char *dir, const char *fn)
1633 {
1634         /*
1635          *      Check if we need to change anything.  If not, don't do
1636          *      anything.
1637          */
1638         if (dict_stat_check(dir, fn)) {
1639                 return 0;
1640         }
1641
1642         /*
1643          *      Free the dictionaries, and the stat cache.
1644          */
1645         dict_free();
1646         stat_root_dir = strdup(dir);
1647         stat_root_file = strdup(fn);
1648
1649         /*
1650          *      Create the table of vendor by name.   There MAY NOT
1651          *      be multiple vendors of the same name.
1652          *
1653          *      Each vendor is malloc'd, so the free function is free.
1654          */
1655         vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
1656                                                 dict_vendor_name_cmp,
1657                                                 fr_pool_free);
1658         if (!vendors_byname) {
1659                 return -1;
1660         }
1661
1662         /*
1663          *      Create the table of vendors by value.  There MAY
1664          *      be vendors of the same value.  If there are, we
1665          *      pick the latest one.
1666          */
1667         vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
1668                                                  dict_vendor_value_cmp,
1669                                                  fr_pool_free);
1670         if (!vendors_byvalue) {
1671                 return -1;
1672         }
1673
1674         /*
1675          *      Create the table of attributes by name.   There MAY NOT
1676          *      be multiple attributes of the same name.
1677          *
1678          *      Each attribute is malloc'd, so the free function is free.
1679          */
1680         attributes_byname = fr_hash_table_create(dict_attr_name_hash,
1681                                                    dict_attr_name_cmp,
1682                                                    fr_pool_free);
1683         if (!attributes_byname) {
1684                 return -1;
1685         }
1686
1687         /*
1688          *      Create the table of attributes by value.  There MAY
1689          *      be attributes of the same value.  If there are, we
1690          *      pick the latest one.
1691          */
1692         attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
1693                                                     dict_attr_value_cmp,
1694                                                     fr_pool_free);
1695         if (!attributes_byvalue) {
1696                 return -1;
1697         }
1698
1699         values_byname = fr_hash_table_create(dict_value_name_hash,
1700                                                dict_value_name_cmp,
1701                                                fr_pool_free);
1702         if (!values_byname) {
1703                 return -1;
1704         }
1705
1706         values_byvalue = fr_hash_table_create(dict_value_value_hash,
1707                                                 dict_value_value_cmp,
1708                                                 fr_pool_free);
1709         if (!values_byvalue) {
1710                 return -1;
1711         }
1712
1713         value_fixup = NULL;     /* just to be safe. */
1714
1715         if (my_dict_init(dir, fn, NULL, 0) < 0)
1716                 return -1;
1717
1718         if (value_fixup) {
1719                 DICT_ATTR *a;
1720                 value_fixup_t *this, *next;
1721
1722                 for (this = value_fixup; this != NULL; this = next) {
1723                         next = this->next;
1724
1725                         a = dict_attrbyname(this->attrstr);
1726                         if (!a) {
1727                                 fr_strerror_printf(
1728                                         "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
1729                                         this->attrstr, this->dval->name);
1730                                 return -1; /* leak, but they should die... */
1731                         }
1732
1733                         this->dval->attr = a->attr;
1734
1735                         /*
1736                          *      Add the value into the dictionary.
1737                          */
1738                         if (!fr_hash_table_replace(values_byname,
1739                                                      this->dval)) {
1740                                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
1741                                 return -1;
1742                         }
1743
1744                         /*
1745                          *      Allow them to use the old name, but
1746                          *      prefer the new name when printing
1747                          *      values.
1748                          */
1749                         if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
1750                                 fr_hash_table_replace(values_byvalue,
1751                                                         this->dval);
1752                         }
1753                         free(this);
1754
1755                         /*
1756                          *      Just so we don't lose track of things.
1757                          */
1758                         value_fixup = next;
1759                 }
1760         }
1761
1762         /*
1763          *      Walk over all of the hash tables to ensure they're
1764          *      initialized.  We do this because the threads may perform
1765          *      lookups, and we don't want multi-threaded re-ordering
1766          *      of the table entries.  That would be bad.
1767          */
1768         fr_hash_table_walk(vendors_byname, null_callback, NULL);
1769         fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
1770
1771         fr_hash_table_walk(attributes_byname, null_callback, NULL);
1772         fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
1773
1774         fr_hash_table_walk(values_byvalue, null_callback, NULL);
1775         fr_hash_table_walk(values_byname, null_callback, NULL);
1776
1777         return 0;
1778 }
1779
1780 /*
1781  *      Get an attribute by its numerical value.
1782  */
1783 DICT_ATTR *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
1784 {
1785         DICT_ATTR dattr;
1786
1787         if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
1788
1789         dattr.attr = attr;
1790         dattr.vendor = vendor;
1791
1792         return fr_hash_table_finddata(attributes_byvalue, &dattr);
1793 }
1794
1795 /*
1796  *      Get an attribute by its name.
1797  */
1798 DICT_ATTR *dict_attrbyname(const char *name)
1799 {
1800         DICT_ATTR *da;
1801         uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
1802
1803         if (!name) return NULL;
1804
1805         da = (DICT_ATTR *) buffer;
1806         strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
1807
1808         return fr_hash_table_finddata(attributes_byname, da);
1809 }
1810
1811 /*
1812  *      Associate a value with an attribute and return it.
1813  */
1814 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
1815 {
1816         DICT_VALUE dval, *dv;
1817
1818         /*
1819          *      First, look up aliases.
1820          */
1821         dval.attr = attr;
1822         dval.vendor = vendor;
1823         dval.name[0] = '\0';
1824
1825         /*
1826          *      Look up the attribute alias target, and use
1827          *      the correct attribute number if found.
1828          */
1829         dv = fr_hash_table_finddata(values_byname, &dval);
1830         if (dv) dval.attr = dv->value;
1831
1832         dval.value = value;
1833
1834         return fr_hash_table_finddata(values_byvalue, &dval);
1835 }
1836
1837 /*
1838  *      Get a value by its name, keyed off of an attribute.
1839  */
1840 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, const char *name)
1841 {
1842         DICT_VALUE *my_dv, *dv;
1843         uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
1844
1845         if (!name) return NULL;
1846
1847         my_dv = (DICT_VALUE *) buffer;
1848         my_dv->attr = attr;
1849         my_dv->vendor = vendor;
1850         my_dv->name[0] = '\0';
1851
1852         /*
1853          *      Look up the attribute alias target, and use
1854          *      the correct attribute number if found.
1855          */
1856         dv = fr_hash_table_finddata(values_byname, my_dv);
1857         if (dv) my_dv->attr = dv->value;
1858
1859         strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
1860
1861         return fr_hash_table_finddata(values_byname, my_dv);
1862 }
1863
1864 /*
1865  *      Get the vendor PEC based on the vendor name
1866  *
1867  *      This is efficient only for small numbers of vendors.
1868  */
1869 int dict_vendorbyname(const char *name)
1870 {
1871         DICT_VENDOR *dv;
1872         uint32_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + 3)/4];
1873
1874         if (!name) return 0;
1875
1876         dv = (DICT_VENDOR *) buffer;
1877         strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
1878
1879         dv = fr_hash_table_finddata(vendors_byname, dv);
1880         if (!dv) return 0;
1881
1882         return dv->vendorpec;
1883 }
1884
1885 /*
1886  *      Return the vendor struct based on the PEC.
1887  */
1888 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
1889 {
1890         DICT_VENDOR dv;
1891
1892         dv.vendorpec = vendorpec;
1893
1894         return fr_hash_table_finddata(vendors_byvalue, &dv);
1895 }