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