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