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