Add IPv4prefix data type for RFC 6572
[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 #ifdef WITH_DHCP
29 #include        <freeradius-devel/dhcp.h>
30 #endif
31
32 #include        <ctype.h>
33
34 #ifdef HAVE_MALLOC_H
35 #include        <malloc.h>
36 #endif
37
38 #ifdef HAVE_SYS_STAT_H
39 #include        <sys/stat.h>
40 #endif
41
42
43 #define DICT_VALUE_MAX_NAME_LEN (128)
44 #define DICT_VENDOR_MAX_NAME_LEN (128)
45 #define DICT_ATTR_MAX_NAME_LEN (128)
46
47 static fr_hash_table_t *vendors_byname = NULL;
48 static fr_hash_table_t *vendors_byvalue = NULL;
49
50 static fr_hash_table_t *attributes_byname = NULL;
51 static fr_hash_table_t *attributes_byvalue = NULL;
52
53 static fr_hash_table_t *values_byvalue = NULL;
54 static fr_hash_table_t *values_byname = NULL;
55
56 static DICT_ATTR *dict_base_attrs[256];
57
58 /*
59  *      For faster HUP's, we cache the stat information for
60  *      files we've $INCLUDEd
61  */
62 typedef struct dict_stat_t {
63         struct dict_stat_t *next;
64         char               *name;
65         time_t             mtime;
66 } dict_stat_t;
67
68 static char *stat_root_dir = NULL;
69 static char *stat_root_file = NULL;
70
71 static dict_stat_t *stat_head = NULL;
72 static dict_stat_t *stat_tail = NULL;
73
74 typedef struct value_fixup_t {
75         char            attrstr[DICT_ATTR_MAX_NAME_LEN];
76         DICT_VALUE      *dval;
77         struct value_fixup_t *next;
78 } value_fixup_t;
79
80
81 /*
82  *      So VALUEs in the dictionary can have forward references.
83  */
84 static value_fixup_t *value_fixup = NULL;
85
86 const FR_NAME_NUMBER dict_attr_types[] = {
87         { "integer",    PW_TYPE_INTEGER },
88         { "string",     PW_TYPE_STRING },
89         { "ipaddr",     PW_TYPE_IPADDR },
90         { "date",       PW_TYPE_DATE },
91         { "abinary",    PW_TYPE_ABINARY },
92         { "octets",     PW_TYPE_OCTETS },
93         { "ifid",       PW_TYPE_IFID },
94         { "ipv6addr",   PW_TYPE_IPV6ADDR },
95         { "ipv6prefix", PW_TYPE_IPV6PREFIX },
96         { "byte",       PW_TYPE_BYTE },
97         { "short",      PW_TYPE_SHORT },
98         { "ether",      PW_TYPE_ETHERNET },
99         { "combo-ip",   PW_TYPE_COMBO_IP },
100         { "tlv",        PW_TYPE_TLV },
101         { "signed",     PW_TYPE_SIGNED },
102         { "extended",   PW_TYPE_EXTENDED },
103         { "long-extended",      PW_TYPE_LONG_EXTENDED },
104         { "evs",        PW_TYPE_EVS },
105         { "uint8",      PW_TYPE_BYTE },
106         { "uint16",     PW_TYPE_SHORT },
107         { "uint32",     PW_TYPE_INTEGER },
108         { "int32",      PW_TYPE_SIGNED },
109         { "integer64",  PW_TYPE_INTEGER64 },
110         { "uint64",     PW_TYPE_INTEGER64 },
111         { "ipv4prefix", PW_TYPE_IPV4PREFIX },
112         { NULL, 0 }
113 };
114
115
116 /*
117  *      WiMAX craziness.
118  */
119 #define MAX_TLV_NEST (4)
120 /*
121  *      Bit packing:
122  *      8 bits of base VSA
123  *      8 bits for nested TLV 1
124  *      8 bits for nested TLV 2
125  *      5 bits for nested TLV 3
126  *      3 bits for nested TLV 4
127  */
128 const int fr_attr_max_tlv = MAX_TLV_NEST;
129 const int fr_attr_shift[MAX_TLV_NEST + 1] = {
130   0, 8, 16, 24, 29
131 };
132
133 const int fr_attr_mask[MAX_TLV_NEST + 1] = {
134   0xff, 0xff, 0xff, 0x1f, 0x07
135 };
136
137
138 /*
139  *      Create the hash of the name.
140  *
141  *      We copy the hash function here because it's substantially faster.
142  */
143 #define FNV_MAGIC_INIT (0x811c9dc5)
144 #define FNV_MAGIC_PRIME (0x01000193)
145
146 static uint32_t dict_hashname(const char *name)
147 {
148         uint32_t hash = FNV_MAGIC_INIT;
149         const char *p;
150
151         for (p = name; *p != '\0'; p++) {
152                 int c = *(const unsigned char *) p;
153                 if (isalpha(c)) c = tolower(c);
154
155                 hash *= FNV_MAGIC_PRIME;
156                 hash ^= (uint32_t ) (c & 0xff);
157         }
158
159         return hash;
160 }
161
162
163 /*
164  *      Hash callback functions.
165  */
166 static uint32_t dict_attr_name_hash(const void *data)
167 {
168         return dict_hashname(((const DICT_ATTR *)data)->name);
169 }
170
171 static int dict_attr_name_cmp(const void *one, const void *two)
172 {
173         const DICT_ATTR *a = one;
174         const DICT_ATTR *b = two;
175
176         return strcasecmp(a->name, b->name);
177 }
178
179 static uint32_t dict_attr_value_hash(const void *data)
180 {
181         uint32_t hash;
182         const DICT_ATTR *attr = data;
183
184         hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
185         return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
186 }
187
188 static int dict_attr_value_cmp(const void *one, const void *two)
189 {
190         const DICT_ATTR *a = one;
191         const DICT_ATTR *b = two;
192
193         if (a->vendor < b->vendor) return -1;
194         if (a->vendor > b->vendor) return +1;
195
196         return a->attr - b->attr;
197 }
198
199 static uint32_t dict_vendor_name_hash(const void *data)
200 {
201         return dict_hashname(((const DICT_VENDOR *)data)->name);
202 }
203
204 static int dict_vendor_name_cmp(const void *one, const void *two)
205 {
206         const DICT_VENDOR *a = one;
207         const DICT_VENDOR *b = two;
208
209         return strcasecmp(a->name, b->name);
210 }
211
212 static uint32_t dict_vendor_value_hash(const void *data)
213 {
214         return fr_hash(&(((const DICT_VENDOR *)data)->vendorpec),
215                          sizeof(((const DICT_VENDOR *)data)->vendorpec));
216 }
217
218 static int dict_vendor_value_cmp(const void *one, const void *two)
219 {
220         const DICT_VENDOR *a = one;
221         const DICT_VENDOR *b = two;
222
223         return a->vendorpec - b->vendorpec;
224 }
225
226 static uint32_t dict_value_name_hash(const void *data)
227 {
228         uint32_t hash;
229         const DICT_VALUE *dval = data;
230
231         hash = dict_hashname(dval->name);
232         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
233         return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
234 }
235
236 static int dict_value_name_cmp(const void *one, const void *two)
237 {
238         int rcode;
239         const DICT_VALUE *a = one;
240         const DICT_VALUE *b = two;
241
242         rcode = a->attr - b->attr;
243         if (rcode != 0) return rcode;
244
245         rcode = a->vendor - b->vendor;
246         if (rcode != 0) return rcode;
247
248         return strcasecmp(a->name, b->name);
249 }
250
251 static uint32_t dict_value_value_hash(const void *data)
252 {
253         uint32_t hash;
254         const DICT_VALUE *dval = data;
255
256         hash = fr_hash(&dval->attr, sizeof(dval->attr));
257         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
258         return fr_hash_update(&dval->value, sizeof(dval->value), hash);
259 }
260
261 static int dict_value_value_cmp(const void *one, const void *two)
262 {
263         int rcode;
264         const DICT_VALUE *a = one;
265         const DICT_VALUE *b = two;
266
267         if (a->vendor < b->vendor) return -1;
268         if (a->vendor > b->vendor) return +1;
269
270         rcode = a->attr - b->attr;
271         if (rcode != 0) return rcode;
272
273         return a->value - b->value;
274 }
275
276
277 /*
278  *      Free the list of stat buffers
279  */
280 static void dict_stat_free(void)
281 {
282         dict_stat_t *this, *next;
283
284         free(stat_root_dir);
285         stat_root_dir = NULL;
286         free(stat_root_file);
287         stat_root_file = NULL;
288
289         if (!stat_head) {
290                 stat_tail = NULL;
291                 return;
292         }
293
294         for (this = stat_head; this != NULL; this = next) {
295                 next = this->next;
296                 free(this->name);
297                 free(this);
298         }
299
300         stat_head = stat_tail = NULL;
301 }
302
303
304 /*
305  *      Add an entry to the list of stat buffers.
306  */
307 static void dict_stat_add(const char *name, const struct stat *stat_buf)
308 {
309         dict_stat_t *this;
310
311         this = malloc(sizeof(*this));
312         if (!this) return;
313         memset(this, 0, sizeof(*this));
314
315         this->name = strdup(name);
316         this->mtime = stat_buf->st_mtime;
317
318         if (!stat_head) {
319                 stat_head = stat_tail = this;
320         } else {
321                 stat_tail->next = this;
322                 stat_tail = this;
323         }
324 }
325
326
327 /*
328  *      See if any dictionaries have changed.  If not, don't
329  *      do anything.
330  */
331 static int dict_stat_check(const char *root_dir, const char *root_file)
332 {
333         struct stat buf;
334         dict_stat_t *this;
335
336         if (!stat_root_dir) return 0;
337         if (!stat_root_file) return 0;
338
339         if (strcmp(root_dir, stat_root_dir) != 0) return 0;
340         if (strcmp(root_file, stat_root_file) != 0) return 0;
341
342         if (!stat_head) return 0; /* changed, reload */
343
344         for (this = stat_head; this != NULL; this = this->next) {
345                 if (stat(this->name, &buf) < 0) return 0;
346
347                 if (buf.st_mtime != this->mtime) return 0;
348         }
349
350         return 1;
351 }
352
353 typedef struct fr_pool_t {
354         void    *page_end;
355         void    *free_ptr;
356         struct fr_pool_t *page_free;
357         struct fr_pool_t *page_next;
358 } fr_pool_t;
359
360 #define FR_POOL_SIZE (32768)
361 #define FR_ALLOC_ALIGN (8)
362
363 static fr_pool_t *dict_pool = NULL;
364
365 static fr_pool_t *fr_pool_create(void)
366 {
367         fr_pool_t *fp = malloc(FR_POOL_SIZE);
368
369         if (!fp) return NULL;
370
371         memset(fp, 0, FR_POOL_SIZE);
372
373         fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
374         fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
375         fp->page_free = fp;
376         fp->page_next = NULL;
377         return fp;
378 }
379
380 static void fr_pool_delete(fr_pool_t **pfp)
381 {
382         fr_pool_t *fp, *next;
383
384         if (!pfp || !*pfp) return;
385
386         for (fp = *pfp; fp != NULL; fp = next) {
387                 next = fp->page_next;
388                 fp->page_next = NULL;
389                 free(fp);
390         }
391         *pfp = NULL;
392 }
393
394
395 static void *fr_pool_alloc(size_t size)
396 {
397         void *ptr;
398
399         if (size == 0) return NULL;
400
401         if (size > 256) return NULL; /* shouldn't happen */
402
403         if (!dict_pool) {
404                 dict_pool = fr_pool_create();
405                 if (!dict_pool) return NULL;
406         }
407
408         if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
409                 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
410         }
411
412         if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
413                 dict_pool->page_free->page_next = fr_pool_create();
414                 if (!dict_pool->page_free->page_next) return NULL;
415                 dict_pool->page_free = dict_pool->page_free->page_next;
416         }
417
418         ptr = dict_pool->page_free->free_ptr;
419         dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
420
421         return ptr;
422 }
423
424
425 static void fr_pool_free(UNUSED void *ptr)
426 {
427         /*
428          *      Place-holder for later code.
429          */
430 }
431
432 /*
433  *      Free the dictionary_attributes and dictionary_values lists.
434  */
435 void dict_free(void)
436 {
437         /*
438          *      Free the tables
439          */
440         fr_hash_table_free(vendors_byname);
441         fr_hash_table_free(vendors_byvalue);
442         vendors_byname = NULL;
443         vendors_byvalue = NULL;
444
445         fr_hash_table_free(attributes_byname);
446         fr_hash_table_free(attributes_byvalue);
447         attributes_byname = NULL;
448         attributes_byvalue = NULL;
449
450         fr_hash_table_free(values_byname);
451         fr_hash_table_free(values_byvalue);
452         values_byname = NULL;
453         values_byvalue = NULL;
454
455         memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
456
457         fr_pool_delete(&dict_pool);
458
459         dict_stat_free();
460 }
461
462
463 /*
464  *      Add vendor to the list.
465  */
466 int dict_addvendor(const char *name, unsigned int value)
467 {
468         size_t length;
469         DICT_VENDOR *dv;
470
471         if (value > FR_MAX_VENDOR) {
472                 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
473                 return -1;
474         }
475
476         if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
477                 fr_strerror_printf("dict_addvendor: vendor name too long");
478                 return -1;
479         }
480
481         if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
482                 fr_strerror_printf("dict_addvendor: out of memory");
483                 return -1;
484         }
485
486         strcpy(dv->name, name);
487         dv->vendorpec  = value;
488         dv->type = dv->length = 1; /* defaults */
489
490         if (!fr_hash_table_insert(vendors_byname, dv)) {
491                 DICT_VENDOR *old_dv;
492
493                 old_dv = fr_hash_table_finddata(vendors_byname, dv);
494                 if (!old_dv) {
495                         fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
496                         return -1;
497                 }
498                 if (old_dv->vendorpec != dv->vendorpec) {
499                         fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
500                         return -1;
501                 }
502
503                 /*
504                  *      Already inserted.  Discard the duplicate entry.
505                  */
506                 fr_pool_free(dv);
507                 return 0;
508         }
509
510         /*
511          *      Insert the SAME pointer (not free'd when this table is
512          *      deleted), into another table.
513          *
514          *      We want this behaviour because we want OLD names for
515          *      the attributes to be read from the configuration
516          *      files, but when we're printing them, (and looking up
517          *      by value) we want to use the NEW name.
518          */
519         if (!fr_hash_table_replace(vendors_byvalue, dv)) {
520                 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
521                            name);
522                 return -1;
523         }
524
525         return 0;
526 }
527
528 /*
529  *      Add an attribute to the dictionary.
530  */
531 int dict_addattr(const char *name, int attr, unsigned int vendor, int type,
532                  ATTR_FLAGS flags)
533 {
534         size_t namelen;
535         static int      max_attr = 0;
536         const char      *p;
537         DICT_ATTR       *da;
538
539         namelen = strlen(name);
540         if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
541                 fr_strerror_printf("dict_addattr: attribute name too long");
542                 return -1;
543         }
544
545         for (p = name; *p != '\0'; p++) {
546                 if (*p < ' ') {
547                         fr_strerror_printf("dict_addattr: attribute name cannot contain control characters");
548                         return -1;
549                 }
550
551                 if ((*p == '"') || (*p == '\\')) {
552                         fr_strerror_printf("dict_addattr: attribute name cannot contain quotation or backslash");
553                         return -1;
554                 }
555
556                 if ((*p == '<') || (*p == '>') || (*p == '&')) {
557                         fr_strerror_printf("dict_addattr: attribute name cannot contain XML control characters");
558                         return -1;
559                 }
560         }
561
562         if (flags.has_tag &&
563             !((type == PW_TYPE_INTEGER) || (type == PW_TYPE_STRING))) {
564                 fr_strerror_printf("dict_addattr: Only 'integer' and 'string' attributes can have tags");
565                 return -1;
566         }
567
568
569         /*
570          *      If the attr is '-1', that means use a pre-existing
571          *      one (if it already exists).  If one does NOT already exist,
572          *      then create a new attribute, with a non-conflicting value,
573          *      and use that.
574          */
575         if (attr == -1) {
576                 if (dict_attrbyname(name)) {
577                         return 0; /* exists, don't add it again */
578                 }
579
580                 attr = ++max_attr;
581
582         } else if (vendor == 0) {
583                 /*
584                  *  Update 'max_attr'
585                  */
586                 if (attr > max_attr) {
587                         max_attr = attr;
588                 }
589         }
590
591         /*
592          *      Additional checks for extended attributes.
593          */
594         if (flags.extended || flags.long_extended || flags.evs) {
595                 if (vendor && (vendor < FR_MAX_VENDOR)) {
596                         fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats.");
597                         return -1;
598                 }
599                 if (!vendor) vendor = VENDORPEC_EXTENDED;
600
601                 if (flags.has_tag
602 #ifdef WITH_DHCP
603                     || flags.array
604 #endif
605                     || (flags.encrypt != FLAG_ENCRYPT_NONE)) {
606                         fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set.");
607                         return -1;
608                 }
609         }
610
611         if (flags.evs) {
612                 if (!(flags.extended || flags.long_extended)) {
613                         fr_strerror_printf("dict_addattr: Attributes of type \"evs\" MUST have a parent of type \"extended\"");
614                         return -1;
615                 }
616
617                 if (vendor <= FR_MAX_VENDOR) {
618                         fr_strerror_printf("dict_addattr: Attribute of type \"evs\" fails internal sanity check");
619                         return -1;
620                 }
621         }
622                 
623         if (attr < 0) {
624                 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
625                 return -1;
626         }
627
628         if (flags.has_tlv && flags.length) {
629                 fr_strerror_printf("TLVs cannot have a fixed length");
630                 return -1;
631         }
632
633         if (vendor && (vendor != VENDORPEC_EXTENDED)) {
634                 DICT_VENDOR *dv;
635                 static DICT_VENDOR *last_vendor = NULL;
636
637                 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
638                         fr_strerror_printf("TLV's cannot be encrypted");
639                         return -1;
640                 }
641
642                 if (flags.is_tlv && flags.has_tag) {
643                         fr_strerror_printf("Sub-TLV's cannot have a tag");
644                         return -1;
645                 }
646
647                 if (flags.has_tlv && flags.has_tag) {
648                         fr_strerror_printf("TLV's cannot have a tag");
649                         return -1;
650                 }
651
652                 /*
653                  *      Most ATTRIBUTEs are bunched together by
654                  *      VENDOR.  We can save a lot of lookups on
655                  *      dictionary initialization by caching the last
656                  *      vendor.
657                  */
658                 if (last_vendor &&
659                     ((vendor & (FR_MAX_VENDOR - 1)) == last_vendor->vendorpec)) {
660                         dv = last_vendor;
661                 } else {
662                         /*
663                          *      Ignore the high byte (sigh)
664                          */
665                         dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
666                         last_vendor = dv;
667                 }
668
669                 /*
670                  *      If the vendor isn't defined, die.
671                  */
672                 if (!dv) {
673                         fr_strerror_printf("dict_addattr: Unknown vendor %u",
674                                            vendor);
675                         return -1;
676                 }
677
678                 /*
679                  *      FIXME: Switch over dv->type, and limit things
680                  *      properly.
681                  */
682                 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
683                         fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
684                         return -1;
685                 } /* else 256..65535 are allowed */
686
687                 /*
688                  *      Set the extended flags as appropriate.
689                  */
690                 if (vendor > FR_MAX_VENDOR) {
691                         unsigned int myattr;
692
693                         myattr = (vendor >> 24) & 0xff;
694                         myattr |= PW_VENDOR_SPECIFIC << 8;
695
696                         da = dict_attrbyvalue(myattr, VENDORPEC_EXTENDED);
697                         if (!da) {
698                                 fr_strerror_printf("dict_addattr: ATTRIBUTE refers to unknown \"evs\" type.");
699                                 return -1;
700                         }
701                         flags.extended = da->flags.extended;
702                         flags.long_extended = da->flags.long_extended;
703                         flags.evs = da->flags.evs;
704                 }
705
706                 /*
707                  *      <sigh> Alvarion, being *again* a horribly
708                  *      broken vendor, has re-used the WiMAX format in
709                  *      their proprietary vendor space.  This re-use
710                  *      means that there are *multiple* conflicting
711                  *      Alvarion dictionaries.
712                  */
713                 flags.wimax = dv->flags;
714         }
715
716         /*
717          *      Create a new attribute for the list
718          */
719         if ((da = fr_pool_alloc(sizeof(*da) + namelen)) == NULL) {
720                 fr_strerror_printf("dict_addattr: out of memory");
721                 return -1;
722         }
723
724         memcpy(da->name, name, namelen);
725         da->name[namelen] = '\0';
726         da->attr = attr;
727         da->vendor = vendor;
728         da->type = type;
729         da->flags = flags;
730
731         /*
732          *      Insert the attribute, only if it's not a duplicate.
733          */
734         if (!fr_hash_table_insert(attributes_byname, da)) {
735                 DICT_ATTR       *a;
736
737                 /*
738                  *      If the attribute has identical number, then
739                  *      ignore the duplicate.
740                  */
741                 a = fr_hash_table_finddata(attributes_byname, da);
742                 if (a && (strcasecmp(a->name, da->name) == 0)) {
743                         if (a->attr != da->attr) {
744                                 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
745                                 fr_pool_free(da);
746                                 return -1;
747                         }
748
749                         /*
750                          *      Same name, same vendor, same attr,
751                          *      maybe the flags and/or type is
752                          *      different.  Let the new value
753                          *      over-ride the old one.
754                          */
755                 }
756
757
758                 fr_hash_table_delete(attributes_byvalue, a);
759
760                 if (!fr_hash_table_replace(attributes_byname, da)) {
761                         fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
762                         fr_pool_free(da);
763                         return -1;
764                 }
765         }
766
767         /*
768          *      Insert the SAME pointer (not free'd when this entry is
769          *      deleted), into another table.
770          *
771          *      We want this behaviour because we want OLD names for
772          *      the attributes to be read from the configuration
773          *      files, but when we're printing them, (and looking up
774          *      by value) we want to use the NEW name.
775          */
776         if (!fr_hash_table_replace(attributes_byvalue, da)) {
777                 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
778                 return -1;
779         }
780
781         if (!vendor && (attr > 0) && (attr < 256)) {
782                  dict_base_attrs[attr] = da;
783         }
784
785         return 0;
786 }
787
788
789 /*
790  *      Add a value for an attribute to the dictionary.
791  */
792 int dict_addvalue(const char *namestr, const char *attrstr, int value)
793 {
794         size_t          length;
795         DICT_ATTR       *dattr;
796         DICT_VALUE      *dval;
797
798         static DICT_ATTR *last_attr = NULL;
799
800         if (!*namestr) {
801                 fr_strerror_printf("dict_addvalue: empty names are not permitted");
802                 return -1;
803         }
804
805         if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
806                 fr_strerror_printf("dict_addvalue: value name too long");
807                 return -1;
808         }
809
810         if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
811                 fr_strerror_printf("dict_addvalue: out of memory");
812                 return -1;
813         }
814         memset(dval, 0, sizeof(*dval));
815
816         strcpy(dval->name, namestr);
817         dval->value = value;
818
819         /*
820          *      Most VALUEs are bunched together by ATTRIBUTE.  We can
821          *      save a lot of lookups on dictionary initialization by
822          *      caching the last attribute.
823          */
824         if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
825                 dattr = last_attr;
826         } else {
827                 dattr = dict_attrbyname(attrstr);
828                 last_attr = dattr;
829         }
830
831         /*
832          *      Remember which attribute is associated with this
833          *      value, if possible.
834          */
835         if (dattr) {
836                 if (dattr->flags.has_value_alias) {
837                         fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
838                         return -1;
839                 }
840
841                 dval->attr = dattr->attr;
842                 dval->vendor = dattr->vendor;
843
844                 /*
845                  *      Enforce valid values
846                  *
847                  *      Don't worry about fixups...
848                  */
849                 switch (dattr->type) {
850                         case PW_TYPE_BYTE:
851                                 if (value > 255) {
852                                         fr_pool_free(dval);
853                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
854                                         return -1;
855                                 }
856                                 break;
857                         case PW_TYPE_SHORT:
858                                 if (value > 65535) {
859                                         fr_pool_free(dval);
860                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
861                                         return -1;
862                                 }
863                                 break;
864
865                                 /*
866                                  *      Allow octets for now, because
867                                  *      of dictionary.cablelabs
868                                  */
869                         case PW_TYPE_OCTETS:
870
871                         case PW_TYPE_INTEGER:
872                                 break;
873
874                         case PW_TYPE_INTEGER64:
875                         default:
876                                 fr_pool_free(dval);
877                                 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
878                                            fr_int2str(dict_attr_types, dattr->type, "?Unknown?"));
879                                 return -1;
880                 }
881
882                 dattr->flags.has_value = 1;
883         } else {
884                 value_fixup_t *fixup;
885
886                 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
887                 if (!fixup) {
888                         fr_pool_free(dval);
889                         fr_strerror_printf("dict_addvalue: out of memory");
890                         return -1;
891                 }
892                 memset(fixup, 0, sizeof(*fixup));
893
894                 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
895                 fixup->dval = dval;
896
897                 /*
898                  *      Insert to the head of the list.
899                  */
900                 fixup->next = value_fixup;
901                 value_fixup = fixup;
902
903                 return 0;
904         }
905
906         /*
907          *      Add the value into the dictionary.
908          */
909         if (!fr_hash_table_insert(values_byname, dval)) {
910                 if (dattr) {
911                         DICT_VALUE *old;
912
913                         /*
914                          *      Suppress duplicates with the same
915                          *      name and value.  There are lots in
916                          *      dictionary.ascend.
917                          */
918                         old = dict_valbyname(dattr->attr, dattr->vendor, namestr);
919                         if (old && (old->value == dval->value)) {
920                                 fr_pool_free(dval);
921                                 return 0;
922                         }
923                 }
924
925                 fr_pool_free(dval);
926                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
927                 return -1;
928         }
929
930         /*
931          *      There are multiple VALUE's, keyed by attribute, so we
932          *      take care of that here.
933          */
934         if (!fr_hash_table_replace(values_byvalue, dval)) {
935                 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
936                            namestr);
937                 return -1;
938         }
939
940         return 0;
941 }
942
943 static int sscanf_i(const char *str, unsigned int *pvalue)
944 {
945         int rcode = 0;
946         int base = 10;
947         static const char *tab = "0123456789";
948
949         if ((str[0] == '0') &&
950             ((str[1] == 'x') || (str[1] == 'X'))) {
951                 tab = "0123456789abcdef";
952                 base = 16;
953
954                 str += 2;
955         }
956
957         while (*str) {
958                 const char *c;
959
960                 if (*str == '.') break;
961
962                 c = memchr(tab, tolower((int) *str), base);
963                 if (!c) return 0;
964
965                 rcode *= base;
966                 rcode += (c - tab);
967                 str++;
968         }
969
970         *pvalue = rcode;
971         return 1;
972 }
973
974
975 int dict_str2oid(const char *ptr, unsigned int *pvalue, int vendor, int tlv_depth)
976 {
977         const char *p;
978         unsigned int value;
979         DICT_ATTR *da;
980
981         if (tlv_depth > fr_attr_max_tlv) {
982                 fr_strerror_printf("Attribute has too long OID");
983                 return 0;
984         }
985
986         if (*pvalue) {
987                 if (vendor) {
988                         da = dict_attrbyvalue(*pvalue, vendor);
989                 } else {
990                         da = dict_attrbyvalue(*pvalue, VENDORPEC_EXTENDED);
991                 }
992                 if (!da) {
993                         fr_strerror_printf("Parent attribute is undefined.");
994                         return 0;
995                 }
996         
997                 if (!(da->flags.has_tlv || da->flags.extended || da->flags.long_extended)) {
998                         fr_strerror_printf("Parent attribute %s cannot have sub-tlvs",
999                                            da->name);
1000                         return 0;
1001                 }
1002         }
1003
1004         p = strchr(ptr, '.');
1005
1006         if (!sscanf_i(ptr, &value)) {
1007                 fr_strerror_printf("Failed parsing attribute identifier %s",
1008                                    ptr);
1009                 return 0;
1010         }
1011
1012         if (*pvalue) {
1013                 *pvalue |= (value & fr_attr_mask[tlv_depth]) << fr_attr_shift[tlv_depth];
1014         } else {
1015                 *pvalue = value;
1016         }
1017
1018         if (p) {
1019                 return dict_str2oid(p + 1, pvalue, vendor, tlv_depth + 1);
1020         }
1021
1022         return tlv_depth;
1023 }
1024
1025
1026 /*
1027  *      Process the ATTRIBUTE command
1028  */
1029 static int process_attribute(const char* fn, const int line,
1030                              const unsigned int block_vendor, DICT_ATTR *block_tlv,
1031                              int tlv_depth, char **argv, int argc)
1032 {
1033         int             oid = 0;
1034         unsigned int    vendor = 0;
1035         unsigned int    value;
1036         int             type;
1037         unsigned int    length = 0;
1038         ATTR_FLAGS      flags;
1039         char            *p;
1040
1041         if ((argc < 3) || (argc > 4)) {
1042                 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
1043                         fn, line);
1044                 return -1;
1045         }
1046
1047         if (strncmp(argv[1], "Attr-", 5) == 0) {
1048                 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
1049                                    fn, line);
1050                 return -1;
1051         }
1052
1053         memset(&flags, 0, sizeof(flags));
1054
1055         /*
1056          *      Look for extended attributes before doing anything else.
1057          */
1058         p = strchr(argv[1], '.');
1059         if (p) {
1060                 *p = '\0';
1061                 oid = 1;
1062         }
1063
1064         /*
1065          *      Validate all entries
1066          */
1067         if (!sscanf_i(argv[1], &value)) {
1068                 fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
1069                 return -1;
1070         }
1071
1072         if (!p) {
1073                 if (value > (1 << 24)) {
1074                         fr_strerror_printf("dict_init: %s[%d]: Attribute number is too large", fn, line);
1075                         return -1;
1076                 }
1077
1078                 
1079                 /*
1080                  *      Parse NUM.NUM.NUM.NUM
1081                  */
1082         } else {
1083                 int my_depth;
1084                 DICT_ATTR *da;
1085
1086                 *p = '.';       /* reset for later printing */
1087
1088                 if (block_vendor) {
1089                         da = dict_attrbyvalue(value, block_vendor);
1090                 } else if (value == PW_VENDOR_SPECIFIC) {
1091                         char *q;
1092                         const DICT_VENDOR *dv;
1093
1094                         p++;
1095                         q = strchr(p, '.');
1096                         if (!q) {
1097                         invalid:
1098                                 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier", fn, line);
1099                                 return -1;
1100                         }
1101                         *q = '\0';
1102
1103                         if (!sscanf_i(p, &vendor)) {
1104                                 *q = '.';
1105                                 goto invalid;
1106                         }
1107                         *(q++) = '.';
1108                         p = q;
1109                         dv = dict_vendorbyvalue(vendor);
1110                         if (!dv) {
1111                                 fr_strerror_printf("dict_init: %s[%d]: Unknown vendor \"%u\" in attribute identifier", fn, line, vendor);
1112                                 return -1;
1113                         }
1114
1115                         argv[1] = p;
1116                         return process_attribute(fn, line, vendor, NULL, 0,
1117                                                  argv, argc);
1118                 } else {
1119                         da = dict_attrbyvalue(value, VENDORPEC_EXTENDED);
1120                 }
1121                 if (!da) {
1122                         fr_strerror_printf("dict_init: %s[%d]: Entry refers to unknown attribute %d", fn, line, value);
1123                         return -1;
1124                 }
1125
1126                 /*
1127                  *      241.1 means 241 is of type "extended".
1128                  *      Otherwise, die.
1129                  */
1130                 if (!(da->flags.has_tlv || da->flags.extended || da->flags.long_extended)) {
1131                         fr_strerror_printf("dict_init: %s[%d]: Parent attribute %s cannot contain sub-attributes", fn, line, da->name);
1132                         return -1;
1133                 }
1134
1135                 my_depth = dict_str2oid(p + 1, &value, block_vendor, tlv_depth + 1);
1136                 if (!my_depth) {
1137                         char buffer[256];
1138
1139                         strlcpy(buffer, fr_strerror(), sizeof(buffer));
1140                         
1141                         fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
1142                         return -1;
1143                 }
1144
1145                 /*
1146                  *      Look up the REAL parent TLV.
1147                  */
1148                 if (my_depth > 1) {
1149                         unsigned int parent = value;
1150
1151                         parent &= ~(fr_attr_mask[my_depth] << fr_attr_shift[my_depth]);
1152
1153                         da = dict_attrbyvalue(parent, da->vendor);
1154                         if (!da) {
1155                                 fr_strerror_printf("dict_init: %s[%d]: Parent attribute is undefined.", fn, line);
1156                                 return -1;
1157                         }
1158                 }
1159                 
1160                 /*
1161                  *      Set which type of attribute this is.
1162                  */
1163                 flags.extended = da->flags.extended;
1164                 flags.long_extended = da->flags.long_extended;
1165                 flags.evs = da->flags.evs;
1166                 if (da->flags.has_tlv) flags.is_tlv = 1;
1167         }
1168
1169         if (strncmp(argv[2], "octets[", 7) != 0) {
1170                 /*
1171                  *      find the type of the attribute.
1172                  */
1173                 type = fr_str2int(dict_attr_types, argv[2], -1);
1174                 if (type < 0) {
1175                         fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
1176                                            fn, line, argv[2]);
1177                         return -1;
1178                 }
1179
1180         } else {
1181                 type = PW_TYPE_OCTETS;
1182                 
1183                 p = strchr(argv[2] + 7, ']');
1184                 if (!p) {
1185                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
1186                         return -1;
1187                 }
1188
1189                 *p = 0;
1190
1191                 if (!sscanf_i(argv[1], &length)) {
1192                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1193                         return -1;
1194                 }
1195
1196                 if ((length == 0) || (length > 253)) {
1197                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1198                         return -1;
1199                 }
1200         }
1201
1202         /*
1203          *      Only look up the vendor if the string
1204          *      is non-empty.
1205          */
1206         if (argc < 4) {
1207                 /*
1208                  *      Force "length" for data types of fixed length;
1209                  */
1210                 switch (type) {
1211                 case PW_TYPE_BYTE:
1212                         length = 1;
1213                         break;
1214
1215                 case PW_TYPE_SHORT:
1216                         length = 2;
1217                         break;
1218
1219                 case PW_TYPE_DATE:
1220                 case PW_TYPE_IPADDR:
1221                 case PW_TYPE_INTEGER:
1222                 case PW_TYPE_SIGNED:
1223                         length = 4;
1224                         break;
1225
1226                 case PW_TYPE_INTEGER64:
1227                         length = 8;
1228                         break;
1229
1230                 case PW_TYPE_ETHERNET:
1231                         length = 6;
1232                         break;
1233
1234                 case PW_TYPE_IFID:
1235                         length = 8;
1236                         break;
1237
1238                 case PW_TYPE_IPV6ADDR:
1239                         length = 16;
1240                         break;
1241
1242                 case PW_TYPE_EXTENDED:
1243                         if ((vendor != 0) || (value < 241)) {
1244                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"extended\" MUST be RFC attributes with value >= 241.", fn, line);
1245                                 return -1;
1246                         }
1247                         type = PW_TYPE_OCTETS;
1248                         flags.extended = 1;
1249                         break;
1250
1251                 case PW_TYPE_LONG_EXTENDED:
1252                         if ((vendor != 0) || (value < 241)) {
1253                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"long-extended\" MUST be RFC attributes with value >= 241.", fn, line);
1254                                 return -1;
1255                         }
1256                         type = PW_TYPE_OCTETS;
1257                         flags.long_extended = 1;
1258                         break;
1259
1260                 case PW_TYPE_EVS:
1261                         type = PW_TYPE_OCTETS;
1262                         flags.evs = 1;
1263                         if (((value >> fr_attr_shift[1]) & fr_attr_mask[1]) != PW_VENDOR_SPECIFIC) {
1264                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"evs\" MUST have attribute code 26.", fn, line);
1265                                 return -1;
1266                         }
1267                         break;
1268
1269                 default:
1270                         break;
1271                 }
1272
1273                 flags.length = length;
1274
1275         } else {                /* argc == 4: we have options */
1276                 char *key, *next, *last;
1277
1278                 /*
1279                  *      Keep it real.
1280                  */
1281                 if (flags.extended || flags.long_extended || flags.evs) {
1282                         fr_strerror_printf("dict_init: %s[%d]: Extended attributes cannot use flags", fn, line);
1283                         return -1;
1284                 }
1285
1286                 if (length != 0) {
1287                         fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line);
1288                         return -1;
1289                 }
1290
1291                 key = argv[3];
1292                 do {
1293                         next = strchr(key, ',');
1294                         if (next) *(next++) = '\0';
1295
1296                         if (strcmp(key, "has_tag") == 0 ||
1297                             strcmp(key, "has_tag=1") == 0) {
1298                                 /* Boolean flag, means this is a
1299                                    tagged attribute */
1300                                 flags.has_tag = 1;
1301                                 
1302                         } else if (strncmp(key, "encrypt=", 8) == 0) {
1303                                 /* Encryption method, defaults to 0 (none).
1304                                    Currently valid is just type 2,
1305                                    Tunnel-Password style, which can only
1306                                    be applied to strings. */
1307                                 flags.encrypt = strtol(key + 8, &last, 0);
1308                                 if (*last) {
1309                                         fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
1310                                                     fn, line, key);
1311                                         return -1;
1312                                 }
1313
1314                                 if ((flags.encrypt == FLAG_ENCRYPT_ASCEND_SECRET) &&
1315                                     (type != PW_TYPE_STRING)) {
1316                                         fr_strerror_printf( "dict_init: %s[%d] Only \"string\" types can have the \"encrypt=3\" flag set.",
1317                                                             fn, line);
1318                                         return -1;
1319                                 }
1320                                 
1321                         } else if (strncmp(key, "array", 6) == 0) {
1322                                 flags.array = 1;
1323                                 
1324                                 switch (type) {
1325                                         case PW_TYPE_IPADDR:
1326                                         case PW_TYPE_BYTE:
1327                                         case PW_TYPE_SHORT:
1328                                         case PW_TYPE_INTEGER:
1329                                         case PW_TYPE_DATE:
1330                                                 break;
1331
1332                                         default:
1333                                                 fr_strerror_printf( "dict_init: %s[%d] Only IP addresses can have the \"array\" flag set.",
1334                                                             fn, line);
1335                                                 return -1;
1336                                 }
1337
1338                                 /*
1339                                  *      The only thing is the vendor name,
1340                                  *      and it's a known name: allow it.
1341                                  */
1342                         } else if ((key == argv[3]) && !next) {
1343                                 if (oid) {
1344                                         fr_strerror_printf( "dict_init: %s[%d] New-style attributes cannot use a vendor flag.",
1345                                                             fn, line);
1346                                         return -1;
1347                                 }
1348
1349                                 if (block_vendor) {
1350                                         fr_strerror_printf( "dict_init: %s[%d] Vendor flag inside of \"BEGIN-VENDOR\" is not allowed.",
1351                                                             fn, line);
1352                                         return -1;
1353                                 }
1354
1355                                 vendor = dict_vendorbyname(key);
1356                                 if (!vendor) goto unknown;
1357                                 break;
1358
1359                         } else {
1360                         unknown:
1361                                 fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
1362                                             fn, line, key);
1363                                 return -1;
1364                         }
1365
1366                         key = next;
1367                         if (key && !*key) break;
1368                 } while (key);
1369         }
1370
1371         if (block_vendor) vendor = block_vendor;
1372
1373         /*
1374          *      Special checks for tags, they make our life much more
1375          *      difficult.
1376          */
1377         if (flags.has_tag) {
1378                 /*
1379                  *      Only string, octets, and integer can be tagged.
1380                  */
1381                 switch (type) {
1382                 case PW_TYPE_STRING:
1383                 case PW_TYPE_INTEGER:
1384                         break;
1385
1386                 default:
1387                         fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
1388                                    fn, line,
1389                                    fr_int2str(dict_attr_types, type, "?Unknown?"));
1390                         return -1;
1391                 }
1392         }
1393
1394         if (type == PW_TYPE_TLV) {
1395                 if (vendor && (vendor < FR_MAX_VENDOR)
1396 #ifdef WITH_DHCP
1397                     && (vendor != DHCP_MAGIC_VENDOR)
1398 #endif
1399                         ) {
1400                         DICT_VENDOR *dv;
1401
1402                         dv = dict_vendorbyvalue(vendor);
1403                         if (!dv || (dv->type != 1) || (dv->length != 1)) {
1404                                 fr_strerror_printf("dict_init: %s[%d]: Type \"tlv\" can only be for \"format=1,1\".",
1405                                                    fn, line);
1406                                 return -1;
1407                         }
1408
1409                 }
1410                 flags.has_tlv = 1;
1411         }
1412         
1413         if (block_tlv) {
1414                 /*
1415                  *      TLV's can be only one octet.
1416                  */
1417                 if ((value == 0) || ((value & ~fr_attr_mask[tlv_depth]) != 0)) {
1418                         fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1419                                             fn, line);
1420                         return -1;
1421                 }
1422
1423                 /*
1424                  *      
1425                  */
1426                 value <<= fr_attr_shift[tlv_depth];
1427                 value |= block_tlv->attr;
1428                 flags.is_tlv = 1;
1429         }
1430
1431 #ifdef WITH_DICTIONARY_WARNINGS
1432         /*
1433          *      Hack to help us discover which vendors have illegal
1434          *      attributes.
1435          */
1436         if (!vendor && (value < 256) &&
1437             !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
1438                 fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
1439                         argv[0], fn);
1440         }
1441 #endif
1442
1443         /*
1444          *      Add it in.
1445          */
1446         if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1447                 char buffer[256];
1448
1449                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1450
1451                 fr_strerror_printf("dict_init: %s[%d]: %s",
1452                                    fn, line, buffer);
1453                 return -1;
1454         }
1455
1456         return 0;
1457 }
1458
1459
1460 /*
1461  *      Process the VALUE command
1462  */
1463 static int process_value(const char* fn, const int line, char **argv,
1464                          int argc)
1465 {
1466         unsigned int    value;
1467
1468         if (argc != 3) {
1469                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1470                         fn, line);
1471                 return -1;
1472         }
1473         /*
1474          *      For Compatibility, skip "Server-Config"
1475          */
1476         if (strcasecmp(argv[0], "Server-Config") == 0)
1477                 return 0;
1478
1479         /*
1480          *      Validate all entries
1481          */
1482         if (!sscanf_i(argv[2], &value)) {
1483                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1484                         fn, line);
1485                 return -1;
1486         }
1487
1488         if (dict_addvalue(argv[1], argv[0], value) < 0) {
1489                 char buffer[256];
1490
1491                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1492
1493                 fr_strerror_printf("dict_init: %s[%d]: %s",
1494                                    fn, line, buffer);
1495                 return -1;
1496         }
1497
1498         return 0;
1499 }
1500
1501
1502 /*
1503  *      Process the VALUE-ALIAS command
1504  *
1505  *      This allows VALUE mappings to be shared among multiple
1506  *      attributes.
1507  */
1508 static int process_value_alias(const char* fn, const int line, char **argv,
1509                                int argc)
1510 {
1511         DICT_ATTR *my_da, *da;
1512         DICT_VALUE *dval;
1513
1514         if (argc != 2) {
1515                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1516                         fn, line);
1517                 return -1;
1518         }
1519
1520         my_da = dict_attrbyname(argv[0]);
1521         if (!my_da) {
1522                 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1523                            fn, line, argv[1]);
1524                 return -1;
1525         }
1526
1527         if (my_da->flags.has_value) {
1528                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE",
1529                            fn, line, argv[0]);
1530                 return -1;
1531         }
1532
1533         if (my_da->flags.has_value_alias) {
1534                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
1535                            fn, line, argv[0]);
1536                 return -1;
1537         }
1538
1539         da = dict_attrbyname(argv[1]);
1540         if (!da) {
1541                 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
1542                            fn, line, argv[1]);
1543                 return -1;
1544         }
1545
1546         if (!da->flags.has_value) {
1547                 fr_strerror_printf("dict_init: %s[%d]: VALUE-ALIAS cannot refer to ATTRIBUTE %s: It has no values",
1548                            fn, line, argv[1]);
1549                 return -1;
1550         }
1551
1552         if (da->flags.has_value_alias) {
1553                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
1554                            fn, line, argv[1]);
1555                 return -1;
1556         }
1557
1558         if (my_da->type != da->type) {
1559                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
1560                            fn, line);
1561                 return -1;
1562         }
1563
1564         if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
1565                 fr_strerror_printf("dict_addvalue: out of memory");
1566                 return -1;
1567         }
1568
1569         dval->name[0] = '\0';   /* empty name */
1570         dval->attr = my_da->attr;
1571         dval->vendor = my_da->vendor;
1572         dval->value = da->attr;
1573
1574         if (!fr_hash_table_insert(values_byname, dval)) {
1575                 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
1576                            fn, line);
1577                 fr_pool_free(dval);
1578                 return -1;
1579         }
1580
1581         return 0;
1582 }
1583
1584
1585 /*
1586  *      Process the VENDOR command
1587  */
1588 static int process_vendor(const char* fn, const int line, char **argv,
1589                           int argc)
1590 {
1591         int     value;
1592         int     continuation = 0;
1593         const   char *format = NULL;
1594
1595         if ((argc < 2) || (argc > 3)) {
1596                 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
1597                             fn, line);
1598                 return -1;
1599         }
1600
1601         /*
1602          *       Validate all entries
1603          */
1604         if (!isdigit((int) argv[1][0])) {
1605                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1606                         fn, line);
1607                 return -1;
1608         }
1609         value = atoi(argv[1]);
1610
1611         /* Create a new VENDOR entry for the list */
1612         if (dict_addvendor(argv[0], value) < 0) {
1613                 char buffer[256];
1614
1615                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1616
1617                 fr_strerror_printf("dict_init: %s[%d]: %s",
1618                            fn, line, buffer);
1619                 return -1;
1620         }
1621
1622         /*
1623          *      Look for a format statement
1624          */
1625         if (argc == 3) {
1626                 format = argv[2];
1627
1628         } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
1629                 format = "format=4,0";
1630
1631         } else if (value == VENDORPEC_LUCENT) {
1632                 format = "format=2,1";
1633
1634         } else if (value == VENDORPEC_STARENT) {
1635                 format = "format=2,2";
1636
1637         } /* else no fixups to do */
1638
1639         if (format) {
1640                 int type, length;
1641                 const char *p;
1642                 DICT_VENDOR *dv;
1643
1644                 if (strncasecmp(format, "format=", 7) != 0) {
1645                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
1646                                    fn, line, format);
1647                         return -1;
1648                 }
1649
1650                 p = format + 7;
1651                 if ((strlen(p) < 3) ||
1652                     !isdigit((int) p[0]) ||
1653                     (p[1] != ',') ||
1654                     !isdigit((int) p[2]) ||
1655                     (p[3] && (p[3] != ','))) {
1656                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1657                                    fn, line, p);
1658                         return -1;
1659                 }
1660
1661                 type = (int) (p[0] - '0');
1662                 length = (int) (p[2] - '0');
1663
1664                 if (p[3] == ',') {
1665                         if (!p[4]) {
1666                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1667                                    fn, line, p);
1668                                 return -1;
1669                         }
1670
1671                         if ((p[4] != 'c') ||
1672                             (p[5] != '\0')) {
1673                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1674                                            fn, line, p);
1675                                 return -1;
1676                         }
1677                         continuation = 1;
1678
1679                         if ((value != VENDORPEC_WIMAX) ||
1680                             (type != 1) || (length != 1)) {
1681                                 fr_strerror_printf("dict_init: %s[%d]: Only WiMAX VSAs can have continuations",
1682                                            fn, line);
1683                                 return -1;
1684                         }
1685                 }
1686
1687                 dv = dict_vendorbyvalue(value);
1688                 if (!dv) {
1689                         fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
1690                                    fn, line);
1691                         return -1;
1692                 }
1693
1694                 if ((type != 1) && (type != 2) && (type != 4)) {
1695                         fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
1696                                    fn, line, type);
1697                         return -1;
1698                 }
1699
1700                 if ((length != 0) && (length != 1) && (length != 2)) {
1701                         fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
1702                                    fn, line, length);
1703                         return -1;
1704                 }
1705
1706                 dv->type = type;
1707                 dv->length = length;
1708                 dv->flags = continuation;
1709         }
1710
1711         return 0;
1712 }
1713
1714 /*
1715  *      String split routine.  Splits an input string IN PLACE
1716  *      into pieces, based on spaces.
1717  */
1718 int str2argv(char *str, char **argv, int max_argc)
1719 {
1720         int argc = 0;
1721
1722         while (*str) {
1723                 if (argc >= max_argc) break;
1724
1725                 /*
1726                  *      Chop out comments early.
1727                  */
1728                 if (*str == '#') {
1729                         *str = '\0';
1730                         break;
1731                 }
1732
1733                 while ((*str == ' ') ||
1734                        (*str == '\t') ||
1735                        (*str == '\r') ||
1736                        (*str == '\n')) *(str++) = '\0';
1737
1738                 if (!*str) break;
1739
1740                 argv[argc] = str;
1741                 argc++;
1742
1743                 while (*str &&
1744                        (*str != ' ') &&
1745                        (*str != '\t') &&
1746                        (*str != '\r') &&
1747                        (*str != '\n')) str++;
1748         }
1749
1750         return argc;
1751 }
1752
1753 #define MAX_ARGV (16)
1754
1755 /*
1756  *      Initialize the dictionary.
1757  */
1758 static int my_dict_init(const char *dir, const char *fn,
1759                         const char *src_file, int src_line)
1760 {
1761         FILE    *fp;
1762         char    dirtmp[256];
1763         char    buf[256];
1764         char    *p;
1765         int     line = 0;
1766         unsigned int    vendor;
1767         unsigned int    block_vendor;
1768         struct stat statbuf;
1769         char    *argv[MAX_ARGV];
1770         int     argc;
1771         DICT_ATTR *da, *block_tlv[MAX_TLV_NEST + 1];
1772         int     which_block_tlv = 0;
1773
1774         block_tlv[0] = NULL;
1775         block_tlv[1] = NULL;
1776         block_tlv[2] = NULL;
1777         block_tlv[3] = NULL;
1778
1779         if (strlen(fn) >= sizeof(dirtmp) / 2 ||
1780             strlen(dir) >= sizeof(dirtmp) / 2) {
1781                 fr_strerror_printf("dict_init: filename name too long");
1782                 return -1;
1783         }
1784
1785         /*
1786          *      First see if fn is relative to dir. If so, create
1787          *      new filename. If not, remember the absolute dir.
1788          */
1789         if ((p = strrchr(fn, FR_DIR_SEP)) != NULL) {
1790                 strcpy(dirtmp, fn);
1791                 dirtmp[p - fn] = 0;
1792                 dir = dirtmp;
1793         } else if (dir && dir[0] && strcmp(dir, ".") != 0) {
1794                 snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn);
1795                 fn = dirtmp;
1796         }
1797
1798         if ((fp = fopen(fn, "r")) == NULL) {
1799                 if (!src_file) {
1800                         fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
1801                                    fn, strerror(errno));
1802                 } else {
1803                         fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
1804                                    src_file, src_line, fn, strerror(errno));
1805                 }
1806                 return -2;
1807         }
1808
1809         stat(fn, &statbuf); /* fopen() guarantees this will succeed */
1810         if (!S_ISREG(statbuf.st_mode)) {
1811                 fclose(fp);
1812                 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
1813                            fn);
1814                 return -1;
1815         }
1816
1817         /*
1818          *      Globally writable dictionaries means that users can control
1819          *      the server configuration with little difficulty.
1820          */
1821 #ifdef S_IWOTH
1822         if ((statbuf.st_mode & S_IWOTH) != 0) {
1823                 fclose(fp);
1824                 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable.  Refusing to start due to insecure configuration.",
1825                            fn);
1826                 return -1;
1827         }
1828 #endif
1829
1830         dict_stat_add(fn, &statbuf);
1831
1832         /*
1833          *      Seed the random pool with data.
1834          */
1835         fr_rand_seed(&statbuf, sizeof(statbuf));
1836
1837         block_vendor = 0;
1838
1839         while (fgets(buf, sizeof(buf), fp) != NULL) {
1840                 line++;
1841                 if (buf[0] == '#' || buf[0] == 0 ||
1842                     buf[0] == '\n' || buf[0] == '\r')
1843                         continue;
1844
1845                 /*
1846                  *  Comment characters should NOT be appearing anywhere but
1847                  *  as start of a comment;
1848                  */
1849                 p = strchr(buf, '#');
1850                 if (p) *p = '\0';
1851
1852                 argc = str2argv(buf, argv, MAX_ARGV);
1853                 if (argc == 0) continue;
1854
1855                 if (argc == 1) {
1856                         fr_strerror_printf( "dict_init: %s[%d] invalid entry",
1857                                     fn, line);
1858                         fclose(fp);
1859                         return -1;
1860                 }
1861
1862                 /*
1863                  *      Process VALUE lines.
1864                  */
1865                 if (strcasecmp(argv[0], "VALUE") == 0) {
1866                         if (process_value(fn, line,
1867                                           argv + 1, argc - 1) == -1) {
1868                                 fclose(fp);
1869                                 return -1;
1870                         }
1871                         continue;
1872                 }
1873
1874                 /*
1875                  *      Perhaps this is an attribute.
1876                  */
1877                 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
1878                         if (process_attribute(fn, line, block_vendor,
1879                                               block_tlv[which_block_tlv],
1880                                               which_block_tlv,
1881                                               argv + 1, argc - 1) == -1) {
1882                                 fclose(fp);
1883                                 return -1;
1884                         }
1885                         continue;
1886                 }
1887
1888                 /*
1889                  *      See if we need to import another dictionary.
1890                  */
1891                 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
1892                         if (my_dict_init(dir, argv[1], fn, line) < 0) {
1893                                 fclose(fp);
1894                                 return -1;
1895                         }
1896                         continue;
1897                 } /* $INCLUDE */
1898
1899                 /*
1900                  *      Optionally include a dictionary
1901                  */
1902                 if (strcasecmp(argv[0], "$INCLUDE-") == 0) {
1903                         int rcode = my_dict_init(dir, argv[1], fn, line);
1904
1905                         if (rcode == -2) continue;
1906
1907                         if (rcode < 0) {
1908                                 fclose(fp);
1909                                 return -1;
1910                         }
1911                         continue;
1912                 } /* $INCLUDE- */
1913
1914                 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
1915                         if (process_value_alias(fn, line,
1916                                                 argv + 1, argc - 1) == -1) {
1917                                 fclose(fp);
1918                                 return -1;
1919                         }
1920                         continue;
1921                 }
1922
1923                 /*
1924                  *      Process VENDOR lines.
1925                  */
1926                 if (strcasecmp(argv[0], "VENDOR") == 0) {
1927                         if (process_vendor(fn, line,
1928                                            argv + 1, argc - 1) == -1) {
1929                                 fclose(fp);
1930                                 return -1;
1931                         }
1932                         continue;
1933                 }
1934
1935                 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
1936                         if (argc != 2) {
1937                                 fr_strerror_printf(
1938                                 "dict_init: %s[%d] invalid BEGIN-TLV entry",
1939                                         fn, line);
1940                                 fclose(fp);
1941                                 return -1;
1942                         }
1943
1944                         da = dict_attrbyname(argv[1]);
1945                         if (!da) {
1946                                 fr_strerror_printf(
1947                                         "dict_init: %s[%d]: unknown attribute %s",
1948                                         fn, line, argv[1]);
1949                                 fclose(fp);
1950                                 return -1;
1951                         }
1952
1953                         if (da->type != PW_TYPE_TLV) {
1954                                 fr_strerror_printf(
1955                                         "dict_init: %s[%d]: attribute %s is not of type tlv",
1956                                         fn, line, argv[1]);
1957                                 fclose(fp);
1958                                 return -1;
1959                         }
1960
1961                         if (which_block_tlv >= MAX_TLV_NEST) {
1962                                 fr_strerror_printf(
1963                                         "dict_init: %s[%d]: TLVs are nested too deep",
1964                                         fn, line);
1965                                 fclose(fp);
1966                                 return -1;
1967                         }
1968
1969
1970                         block_tlv[++which_block_tlv] = da;
1971                         continue;
1972                 } /* BEGIN-TLV */
1973
1974                 if (strcasecmp(argv[0], "END-TLV") == 0) {
1975                         if (argc != 2) {
1976                                 fr_strerror_printf(
1977                                 "dict_init: %s[%d] invalid END-TLV entry",
1978                                         fn, line);
1979                                 fclose(fp);
1980                                 return -1;
1981                         }
1982
1983                         da = dict_attrbyname(argv[1]);
1984                         if (!da) {
1985                                 fr_strerror_printf(
1986                                         "dict_init: %s[%d]: unknown attribute %s",
1987                                         fn, line, argv[1]);
1988                                 fclose(fp);
1989                                 return -1;
1990                         }
1991
1992                         if (da != block_tlv[which_block_tlv]) {
1993                                 fr_strerror_printf(
1994                                         "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
1995                                         fn, line, argv[1]);
1996                                 fclose(fp);
1997                                 return -1;
1998                         }
1999                         block_tlv[which_block_tlv--] = NULL;
2000                         continue;
2001                 } /* END-VENDOR */
2002
2003                 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
2004                         if (argc < 2) {
2005                                 fr_strerror_printf(
2006                                 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
2007                                         fn, line);
2008                                 fclose(fp);
2009                                 return -1;
2010                         }
2011
2012                         vendor = dict_vendorbyname(argv[1]);
2013                         if (!vendor) {
2014                                 fr_strerror_printf(
2015                                         "dict_init: %s[%d]: unknown vendor %s",
2016                                         fn, line, argv[1]);
2017                                 fclose(fp);
2018                                 return -1;
2019                         }
2020
2021                         block_vendor = vendor;
2022
2023                         /*
2024                          *      Check for extended attr VSAs
2025                          */
2026                         if (argc > 2) {
2027                                 if (strncmp(argv[2], "format=", 7) != 0) {
2028                                         fr_strerror_printf(
2029                                                 "dict_init: %s[%d]: Invalid format %s",
2030                                                 fn, line, argv[2]);
2031                                         fclose(fp);
2032                                         return -1;
2033                                 }
2034                                 
2035                                 p = argv[2] + 7;
2036                                 da = dict_attrbyname(p);
2037                                 if (!da) {
2038                                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR: unknown attribute \"%s\"",
2039                                                            fn, line, p);
2040                                         fclose(fp);
2041                                         return -1;
2042                                 }
2043
2044                                 if (!da->flags.evs) {
2045                                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR.  Attribute \"%s\" is not of \"evs\" data type",
2046                                                            fn, line, p);
2047                                         fclose(fp);
2048                                         return -1;
2049                                 }
2050                                 
2051                                 /*
2052                                  *      Pack the encapsulating attribute
2053                                  *      into the vendor Id.  This attribute
2054                                  *      MUST be >= 241.
2055                                  */
2056                                 block_vendor |= (da->attr & fr_attr_mask[1]) * FR_MAX_VENDOR;
2057                         }
2058
2059                         continue;
2060                 } /* BEGIN-VENDOR */
2061
2062                 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
2063                         if (argc != 2) {
2064                                 fr_strerror_printf(
2065                                 "dict_init: %s[%d] invalid END-VENDOR entry",
2066                                         fn, line);
2067                                 fclose(fp);
2068                                 return -1;
2069                         }
2070
2071                         vendor = dict_vendorbyname(argv[1]);
2072                         if (!vendor) {
2073                                 fr_strerror_printf(
2074                                         "dict_init: %s[%d]: unknown vendor %s",
2075                                         fn, line, argv[1]);
2076                                 fclose(fp);
2077                                 return -1;
2078                         }
2079
2080                         if (vendor != (block_vendor & (FR_MAX_VENDOR - 1))) {
2081                                 fr_strerror_printf(
2082                                         "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
2083                                         fn, line, argv[1]);
2084                                 fclose(fp);
2085                                 return -1;
2086                         }
2087                         block_vendor = 0;
2088                         continue;
2089                 } /* END-VENDOR */
2090
2091                 /*
2092                  *      Any other string: We don't recognize it.
2093                  */
2094                 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
2095                            fn, line, argv[0]);
2096                 fclose(fp);
2097                 return -1;
2098         }
2099         fclose(fp);
2100         return 0;
2101 }
2102
2103
2104 /*
2105  *      Empty callback for hash table initialization.
2106  */
2107 static int null_callback(void *ctx, void *data)
2108 {
2109         ctx = ctx;              /* -Wunused */
2110         data = data;            /* -Wunused */
2111
2112         return 0;
2113 }
2114
2115
2116 /*
2117  *      Initialize the directory, then fix the attr member of
2118  *      all attributes.
2119  */
2120 int dict_init(const char *dir, const char *fn)
2121 {
2122         /*
2123          *      Check if we need to change anything.  If not, don't do
2124          *      anything.
2125          */
2126         if (dict_stat_check(dir, fn)) {
2127                 return 0;
2128         }
2129
2130         /*
2131          *      Free the dictionaries, and the stat cache.
2132          */
2133         dict_free();
2134         stat_root_dir = strdup(dir);
2135         stat_root_file = strdup(fn);
2136
2137         /*
2138          *      Create the table of vendor by name.   There MAY NOT
2139          *      be multiple vendors of the same name.
2140          *
2141          *      Each vendor is malloc'd, so the free function is free.
2142          */
2143         vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
2144                                                 dict_vendor_name_cmp,
2145                                                 fr_pool_free);
2146         if (!vendors_byname) {
2147                 return -1;
2148         }
2149
2150         /*
2151          *      Create the table of vendors by value.  There MAY
2152          *      be vendors of the same value.  If there are, we
2153          *      pick the latest one.
2154          */
2155         vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
2156                                                  dict_vendor_value_cmp,
2157                                                  fr_pool_free);
2158         if (!vendors_byvalue) {
2159                 return -1;
2160         }
2161
2162         /*
2163          *      Create the table of attributes by name.   There MAY NOT
2164          *      be multiple attributes of the same name.
2165          *
2166          *      Each attribute is malloc'd, so the free function is free.
2167          */
2168         attributes_byname = fr_hash_table_create(dict_attr_name_hash,
2169                                                    dict_attr_name_cmp,
2170                                                    fr_pool_free);
2171         if (!attributes_byname) {
2172                 return -1;
2173         }
2174
2175         /*
2176          *      Create the table of attributes by value.  There MAY
2177          *      be attributes of the same value.  If there are, we
2178          *      pick the latest one.
2179          */
2180         attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
2181                                                     dict_attr_value_cmp,
2182                                                     fr_pool_free);
2183         if (!attributes_byvalue) {
2184                 return -1;
2185         }
2186
2187         values_byname = fr_hash_table_create(dict_value_name_hash,
2188                                                dict_value_name_cmp,
2189                                                fr_pool_free);
2190         if (!values_byname) {
2191                 return -1;
2192         }
2193
2194         values_byvalue = fr_hash_table_create(dict_value_value_hash,
2195                                                 dict_value_value_cmp,
2196                                                 fr_pool_free);
2197         if (!values_byvalue) {
2198                 return -1;
2199         }
2200
2201         value_fixup = NULL;     /* just to be safe. */
2202
2203         if (my_dict_init(dir, fn, NULL, 0) < 0)
2204                 return -1;
2205
2206         if (value_fixup) {
2207                 DICT_ATTR *a;
2208                 value_fixup_t *this, *next;
2209
2210                 for (this = value_fixup; this != NULL; this = next) {
2211                         next = this->next;
2212
2213                         a = dict_attrbyname(this->attrstr);
2214                         if (!a) {
2215                                 fr_strerror_printf(
2216                                         "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
2217                                         this->attrstr, this->dval->name);
2218                                 return -1; /* leak, but they should die... */
2219                         }
2220
2221                         this->dval->attr = a->attr;
2222
2223                         /*
2224                          *      Add the value into the dictionary.
2225                          */
2226                         if (!fr_hash_table_replace(values_byname,
2227                                                      this->dval)) {
2228                                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
2229                                 return -1;
2230                         }
2231
2232                         /*
2233                          *      Allow them to use the old name, but
2234                          *      prefer the new name when printing
2235                          *      values.
2236                          */
2237                         if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
2238                                 fr_hash_table_replace(values_byvalue,
2239                                                         this->dval);
2240                         }
2241                         free(this);
2242
2243                         /*
2244                          *      Just so we don't lose track of things.
2245                          */
2246                         value_fixup = next;
2247                 }
2248         }
2249
2250         /*
2251          *      Walk over all of the hash tables to ensure they're
2252          *      initialized.  We do this because the threads may perform
2253          *      lookups, and we don't want multi-threaded re-ordering
2254          *      of the table entries.  That would be bad.
2255          */
2256         fr_hash_table_walk(vendors_byname, null_callback, NULL);
2257         fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
2258
2259         fr_hash_table_walk(attributes_byname, null_callback, NULL);
2260         fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
2261
2262         fr_hash_table_walk(values_byvalue, null_callback, NULL);
2263         fr_hash_table_walk(values_byname, null_callback, NULL);
2264
2265         return 0;
2266 }
2267
2268 /*
2269  *      Get an attribute by its numerical value.
2270  */
2271 DICT_ATTR *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
2272 {
2273         DICT_ATTR dattr;
2274
2275         if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
2276
2277         dattr.attr = attr;
2278         dattr.vendor = vendor;
2279
2280         return fr_hash_table_finddata(attributes_byvalue, &dattr);
2281 }
2282
2283 /*
2284  *      Get an attribute by its name.
2285  */
2286 DICT_ATTR *dict_attrbyname(const char *name)
2287 {
2288         DICT_ATTR *da;
2289         uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
2290
2291         if (!name) return NULL;
2292
2293         da = (DICT_ATTR *) buffer;
2294         strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
2295
2296         return fr_hash_table_finddata(attributes_byname, da);
2297 }
2298
2299 /*
2300  *      Associate a value with an attribute and return it.
2301  */
2302 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
2303 {
2304         DICT_VALUE dval, *dv;
2305
2306         /*
2307          *      First, look up aliases.
2308          */
2309         dval.attr = attr;
2310         dval.vendor = vendor;
2311         dval.name[0] = '\0';
2312
2313         /*
2314          *      Look up the attribute alias target, and use
2315          *      the correct attribute number if found.
2316          */
2317         dv = fr_hash_table_finddata(values_byname, &dval);
2318         if (dv) dval.attr = dv->value;
2319
2320         dval.value = value;
2321
2322         return fr_hash_table_finddata(values_byvalue, &dval);
2323 }
2324
2325 /*
2326  *      Associate a value with an attribute and return it.
2327  */
2328 const char *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value)
2329 {
2330         DICT_VALUE *dv;
2331
2332         dv = dict_valbyattr(attr, vendor, value);
2333         if (!dv) return "";
2334
2335         return dv->name;
2336 }
2337
2338 /*
2339  *      Get a value by its name, keyed off of an attribute.
2340  */
2341 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, const char *name)
2342 {
2343         DICT_VALUE *my_dv, *dv;
2344         uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
2345
2346         if (!name) return NULL;
2347
2348         my_dv = (DICT_VALUE *) buffer;
2349         my_dv->attr = attr;
2350         my_dv->vendor = vendor;
2351         my_dv->name[0] = '\0';
2352
2353         /*
2354          *      Look up the attribute alias target, and use
2355          *      the correct attribute number if found.
2356          */
2357         dv = fr_hash_table_finddata(values_byname, my_dv);
2358         if (dv) my_dv->attr = dv->value;
2359
2360         strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
2361
2362         return fr_hash_table_finddata(values_byname, my_dv);
2363 }
2364
2365 /*
2366  *      Get the vendor PEC based on the vendor name
2367  *
2368  *      This is efficient only for small numbers of vendors.
2369  */
2370 int dict_vendorbyname(const char *name)
2371 {
2372         DICT_VENDOR *dv;
2373         uint32_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + 3)/4];
2374
2375         if (!name) return 0;
2376
2377         dv = (DICT_VENDOR *) buffer;
2378         strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
2379
2380         dv = fr_hash_table_finddata(vendors_byname, dv);
2381         if (!dv) return 0;
2382
2383         return dv->vendorpec;
2384 }
2385
2386 /*
2387  *      Return the vendor struct based on the PEC.
2388  */
2389 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
2390 {
2391         DICT_VENDOR dv;
2392
2393         dv.vendorpec = vendorpec;
2394
2395         return fr_hash_table_finddata(vendors_byvalue, &dv);
2396 }