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