Add function to create unknown attributes from text strings
[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 #define DICT_ATTR_SIZE sizeof(DICT_ATTR) + DICT_ATTR_MAX_NAME_LEN
48
49 static fr_hash_table_t *vendors_byname = NULL;
50 static fr_hash_table_t *vendors_byvalue = NULL;
51
52 static fr_hash_table_t *attributes_byname = NULL;
53 static fr_hash_table_t *attributes_byvalue = NULL;
54
55 static fr_hash_table_t *attributes_combo = NULL;
56
57 static fr_hash_table_t *values_byvalue = NULL;
58 static fr_hash_table_t *values_byname = NULL;
59
60 static DICT_ATTR *dict_base_attrs[256];
61
62 /*
63  *      For faster HUP's, we cache the stat information for
64  *      files we've $INCLUDEd
65  */
66 typedef struct dict_stat_t {
67         struct dict_stat_t *next;
68         char               *name;
69         time_t             mtime;
70 } dict_stat_t;
71
72 static char *stat_root_dir = NULL;
73 static char *stat_root_file = NULL;
74
75 static dict_stat_t *stat_head = NULL;
76 static dict_stat_t *stat_tail = NULL;
77
78 typedef struct value_fixup_t {
79         char            attrstr[DICT_ATTR_MAX_NAME_LEN];
80         DICT_VALUE      *dval;
81         struct value_fixup_t *next;
82 } value_fixup_t;
83
84
85 /*
86  *      So VALUEs in the dictionary can have forward references.
87  */
88 static value_fixup_t *value_fixup = NULL;
89
90 const FR_NAME_NUMBER dict_attr_types[] = {
91         { "integer",    PW_TYPE_INTEGER },
92         { "string",     PW_TYPE_STRING },
93         { "ipaddr",     PW_TYPE_IPADDR },
94         { "date",       PW_TYPE_DATE },
95         { "abinary",    PW_TYPE_ABINARY },
96         { "octets",     PW_TYPE_OCTETS },
97         { "ifid",       PW_TYPE_IFID },
98         { "ipv6addr",   PW_TYPE_IPV6ADDR },
99         { "ipv6prefix", PW_TYPE_IPV6PREFIX },
100         { "byte",       PW_TYPE_BYTE },
101         { "short",      PW_TYPE_SHORT },
102         { "ether",      PW_TYPE_ETHERNET },
103         { "combo-ip",   PW_TYPE_COMBO_IP },
104         { "tlv",        PW_TYPE_TLV },
105         { "signed",     PW_TYPE_SIGNED },
106         { "extended",   PW_TYPE_EXTENDED },
107         { "long-extended",      PW_TYPE_LONG_EXTENDED },
108         { "evs",        PW_TYPE_EVS },
109         { "uint8",      PW_TYPE_BYTE },
110         { "uint16",     PW_TYPE_SHORT },
111         { "uint32",     PW_TYPE_INTEGER },
112         { "int32",      PW_TYPE_SIGNED },
113         { "integer64",  PW_TYPE_INTEGER64 },
114         { "uint64",     PW_TYPE_INTEGER64 },
115         { "ipv4prefix", PW_TYPE_IPV4PREFIX },
116         { NULL, 0 }
117 };
118
119
120 /*
121  *      For packing multiple TLV numbers into one 32-bit integer.  The
122  *      first 3 bytes are just the 8-bit number.  The next two are
123  *      more limited.  We only allow 31 attributes nested 3 layers
124  *      deep, and only 7 nested 4 layers deep.  This should be
125  *      sufficient for most purposes.
126  *
127  *      For TLVs and extended attributes, we packet the base attribute
128  *      number into the upper 8 bits of the "vendor" field.
129  *
130  *      e.g.    OID             attribute       vendor
131  *              241.1           1               (241 << 8)
132  *              241.26.9.1      1               (241 << 8) | (9)
133  *              241.1.2         1 | (2 << 8)    (241 << 8)
134  */
135 #define MAX_TLV_NEST (4)
136 /*
137  *      Bit packing:
138  *      8 bits of base attribute
139  *      8 bits for nested TLV 1
140  *      8 bits for nested TLV 2
141  *      5 bits for nested TLV 3
142  *      3 bits for nested TLV 4
143  */
144 const int fr_attr_max_tlv = MAX_TLV_NEST;
145 const int fr_attr_shift[MAX_TLV_NEST + 1] = {
146   0, 8, 16, 24, 29
147 };
148
149 const int fr_attr_mask[MAX_TLV_NEST + 1] = {
150   0xff, 0xff, 0xff, 0x1f, 0x07
151 };
152
153
154 /*
155  *      Create the hash of the name.
156  *
157  *      We copy the hash function here because it's substantially faster.
158  */
159 #define FNV_MAGIC_INIT (0x811c9dc5)
160 #define FNV_MAGIC_PRIME (0x01000193)
161
162 static uint32_t dict_hashname(const char *name)
163 {
164         uint32_t hash = FNV_MAGIC_INIT;
165         const char *p;
166
167         for (p = name; *p != '\0'; p++) {
168                 int c = *(const unsigned char *) p;
169                 if (isalpha(c)) c = tolower(c);
170
171                 hash *= FNV_MAGIC_PRIME;
172                 hash ^= (uint32_t ) (c & 0xff);
173         }
174
175         return hash;
176 }
177
178
179 /*
180  *      Hash callback functions.
181  */
182 static uint32_t dict_attr_name_hash(const void *data)
183 {
184         return dict_hashname(((const DICT_ATTR *)data)->name);
185 }
186
187 static int dict_attr_name_cmp(const void *one, const void *two)
188 {
189         const DICT_ATTR *a = one;
190         const DICT_ATTR *b = two;
191
192         return strcasecmp(a->name, b->name);
193 }
194
195 static uint32_t dict_attr_value_hash(const void *data)
196 {
197         uint32_t hash;
198         const DICT_ATTR *attr = data;
199
200         hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
201         return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
202 }
203
204 static int dict_attr_value_cmp(const void *one, const void *two)
205 {
206         const DICT_ATTR *a = one;
207         const DICT_ATTR *b = two;
208
209         if (a->vendor < b->vendor) return -1;
210         if (a->vendor > b->vendor) return +1;
211
212         return a->attr - b->attr;
213 }
214
215 static uint32_t dict_attr_combo_hash(const void *data)
216 {
217         uint32_t hash;
218         const DICT_ATTR *attr = data;
219
220         hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
221         hash = fr_hash_update(&attr->type, sizeof(attr->type), hash);
222         return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
223 }
224
225 static int dict_attr_combo_cmp(const void *one, const void *two)
226 {
227         const DICT_ATTR *a = one;
228         const DICT_ATTR *b = two;
229
230         if (a->type < b->type) return -1;
231         if (a->type > b->type) return +1;
232
233         if (a->vendor < b->vendor) return -1;
234         if (a->vendor > b->vendor) return +1;
235
236         return a->attr - b->attr;
237 }
238
239 static uint32_t dict_vendor_name_hash(const void *data)
240 {
241         return dict_hashname(((const DICT_VENDOR *)data)->name);
242 }
243
244 static int dict_vendor_name_cmp(const void *one, const void *two)
245 {
246         const DICT_VENDOR *a = one;
247         const DICT_VENDOR *b = two;
248
249         return strcasecmp(a->name, b->name);
250 }
251
252 static uint32_t dict_vendor_value_hash(const void *data)
253 {
254         return fr_hash(&(((const DICT_VENDOR *)data)->vendorpec),
255                          sizeof(((const DICT_VENDOR *)data)->vendorpec));
256 }
257
258 static int dict_vendor_value_cmp(const void *one, const void *two)
259 {
260         const DICT_VENDOR *a = one;
261         const DICT_VENDOR *b = two;
262
263         return a->vendorpec - b->vendorpec;
264 }
265
266 static uint32_t dict_value_name_hash(const void *data)
267 {
268         uint32_t hash;
269         const DICT_VALUE *dval = data;
270
271         hash = dict_hashname(dval->name);
272         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
273         return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
274 }
275
276 static int dict_value_name_cmp(const void *one, const void *two)
277 {
278         int rcode;
279         const DICT_VALUE *a = one;
280         const DICT_VALUE *b = two;
281
282         rcode = a->attr - b->attr;
283         if (rcode != 0) return rcode;
284
285         rcode = a->vendor - b->vendor;
286         if (rcode != 0) return rcode;
287
288         return strcasecmp(a->name, b->name);
289 }
290
291 static uint32_t dict_value_value_hash(const void *data)
292 {
293         uint32_t hash;
294         const DICT_VALUE *dval = data;
295
296         hash = fr_hash(&dval->attr, sizeof(dval->attr));
297         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
298         return fr_hash_update(&dval->value, sizeof(dval->value), hash);
299 }
300
301 static int dict_value_value_cmp(const void *one, const void *two)
302 {
303         int rcode;
304         const DICT_VALUE *a = one;
305         const DICT_VALUE *b = two;
306
307         if (a->vendor < b->vendor) return -1;
308         if (a->vendor > b->vendor) return +1;
309
310         rcode = a->attr - b->attr;
311         if (rcode != 0) return rcode;
312
313         return a->value - b->value;
314 }
315
316
317 /*
318  *      Free the list of stat buffers
319  */
320 static void dict_stat_free(void)
321 {
322         dict_stat_t *this, *next;
323
324         free(stat_root_dir);
325         stat_root_dir = NULL;
326         free(stat_root_file);
327         stat_root_file = NULL;
328
329         if (!stat_head) {
330                 stat_tail = NULL;
331                 return;
332         }
333
334         for (this = stat_head; this != NULL; this = next) {
335                 next = this->next;
336                 free(this->name);
337                 free(this);
338         }
339
340         stat_head = stat_tail = NULL;
341 }
342
343
344 /*
345  *      Add an entry to the list of stat buffers.
346  */
347 static void dict_stat_add(const char *name, const struct stat *stat_buf)
348 {
349         dict_stat_t *this;
350
351         this = malloc(sizeof(*this));
352         if (!this) return;
353         memset(this, 0, sizeof(*this));
354
355         this->name = strdup(name);
356         this->mtime = stat_buf->st_mtime;
357
358         if (!stat_head) {
359                 stat_head = stat_tail = this;
360         } else {
361                 stat_tail->next = this;
362                 stat_tail = this;
363         }
364 }
365
366
367 /*
368  *      See if any dictionaries have changed.  If not, don't
369  *      do anything.
370  */
371 static int dict_stat_check(const char *root_dir, const char *root_file)
372 {
373         struct stat buf;
374         dict_stat_t *this;
375
376         if (!stat_root_dir) return 0;
377         if (!stat_root_file) return 0;
378
379         if (strcmp(root_dir, stat_root_dir) != 0) return 0;
380         if (strcmp(root_file, stat_root_file) != 0) return 0;
381
382         if (!stat_head) return 0; /* changed, reload */
383
384         for (this = stat_head; this != NULL; this = this->next) {
385                 if (stat(this->name, &buf) < 0) return 0;
386
387                 if (buf.st_mtime != this->mtime) return 0;
388         }
389
390         return 1;
391 }
392
393 typedef struct fr_pool_t {
394         void    *page_end;
395         void    *free_ptr;
396         struct fr_pool_t *page_free;
397         struct fr_pool_t *page_next;
398 } fr_pool_t;
399
400 #define FR_POOL_SIZE (32768)
401 #define FR_ALLOC_ALIGN (8)
402
403 static fr_pool_t *dict_pool = NULL;
404
405 static fr_pool_t *fr_pool_create(void)
406 {
407         fr_pool_t *fp = malloc(FR_POOL_SIZE);
408
409         if (!fp) return NULL;
410
411         memset(fp, 0, FR_POOL_SIZE);
412
413         fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
414         fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
415         fp->page_free = fp;
416         fp->page_next = NULL;
417         return fp;
418 }
419
420 static void fr_pool_delete(fr_pool_t **pfp)
421 {
422         fr_pool_t *fp, *next;
423
424         if (!pfp || !*pfp) return;
425
426         for (fp = *pfp; fp != NULL; fp = next) {
427                 next = fp->page_next;
428                 fp->page_next = NULL;
429                 free(fp);
430         }
431         *pfp = NULL;
432 }
433
434
435 static void *fr_pool_alloc(size_t size)
436 {
437         void *ptr;
438
439         if (size == 0) return NULL;
440
441         if (size > 256) return NULL; /* shouldn't happen */
442
443         if (!dict_pool) {
444                 dict_pool = fr_pool_create();
445                 if (!dict_pool) return NULL;
446         }
447
448         if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
449                 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
450         }
451
452         if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
453                 dict_pool->page_free->page_next = fr_pool_create();
454                 if (!dict_pool->page_free->page_next) return NULL;
455                 dict_pool->page_free = dict_pool->page_free->page_next;
456         }
457
458         ptr = dict_pool->page_free->free_ptr;
459         dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
460
461         return ptr;
462 }
463
464
465 static void fr_pool_free(UNUSED void *ptr)
466 {
467         /*
468          *      Place-holder for later code.
469          */
470 }
471
472 /*
473  *      Free the dictionary_attributes and dictionary_values lists.
474  */
475 void dict_free(void)
476 {
477         /*
478          *      Free the tables
479          */
480         fr_hash_table_free(vendors_byname);
481         fr_hash_table_free(vendors_byvalue);
482         vendors_byname = NULL;
483         vendors_byvalue = NULL;
484
485         fr_hash_table_free(attributes_byname);
486         fr_hash_table_free(attributes_byvalue);
487         fr_hash_table_free(attributes_combo);
488         attributes_byname = NULL;
489         attributes_byvalue = NULL;
490         attributes_combo = NULL;
491
492         fr_hash_table_free(values_byname);
493         fr_hash_table_free(values_byvalue);
494         values_byname = NULL;
495         values_byvalue = NULL;
496
497         memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
498
499         fr_pool_delete(&dict_pool);
500
501         dict_stat_free();
502 }
503
504 /*
505  *      Add vendor to the list.
506  */
507 int dict_addvendor(const char *name, unsigned int value)
508 {
509         size_t length;
510         DICT_VENDOR *dv;
511
512         if (value >= FR_MAX_VENDOR) {
513                 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
514                 return -1;
515         }
516
517         if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
518                 fr_strerror_printf("dict_addvendor: vendor name too long");
519                 return -1;
520         }
521
522         if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
523                 fr_strerror_printf("dict_addvendor: out of memory");
524                 return -1;
525         }
526
527         strcpy(dv->name, name);
528         dv->vendorpec  = value;
529         dv->type = dv->length = 1; /* defaults */
530
531         if (!fr_hash_table_insert(vendors_byname, dv)) {
532                 DICT_VENDOR *old_dv;
533
534                 old_dv = fr_hash_table_finddata(vendors_byname, dv);
535                 if (!old_dv) {
536                         fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
537                         return -1;
538                 }
539                 if (old_dv->vendorpec != dv->vendorpec) {
540                         fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
541                         return -1;
542                 }
543
544                 /*
545                  *      Already inserted.  Discard the duplicate entry.
546                  */
547                 fr_pool_free(dv);
548                 return 0;
549         }
550
551         /*
552          *      Insert the SAME pointer (not free'd when this table is
553          *      deleted), into another table.
554          *
555          *      We want this behaviour because we want OLD names for
556          *      the attributes to be read from the configuration
557          *      files, but when we're printing them, (and looking up
558          *      by value) we want to use the NEW name.
559          */
560         if (!fr_hash_table_replace(vendors_byvalue, dv)) {
561                 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
562                            name);
563                 return -1;
564         }
565
566         return 0;
567 }
568
569 /*
570  *      Add an attribute to the dictionary.
571  */
572 int dict_addattr(const char *name, int attr, unsigned int vendor, int type,
573                  ATTR_FLAGS flags)
574 {
575         size_t namelen;
576         static int      max_attr = 0;
577         const char      *p;
578         DICT_ATTR       *da;
579
580         namelen = strlen(name);
581         if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
582                 fr_strerror_printf("dict_addattr: attribute name too long");
583                 return -1;
584         }
585
586         for (p = name; *p != '\0'; p++) {
587                 if (*p < ' ') {
588                         fr_strerror_printf("dict_addattr: attribute name cannot contain control characters");
589                         return -1;
590                 }
591
592                 if ((*p == '"') || (*p == '\\')) {
593                         fr_strerror_printf("dict_addattr: attribute name cannot contain quotation or backslash");
594                         return -1;
595                 }
596
597                 if ((*p == '<') || (*p == '>') || (*p == '&')) {
598                         fr_strerror_printf("dict_addattr: attribute name cannot contain XML control characters");
599                         return -1;
600                 }
601         }
602
603         if (flags.has_tag &&
604             !((type == PW_TYPE_INTEGER) || (type == PW_TYPE_STRING))) {
605                 fr_strerror_printf("dict_addattr: Only 'integer' and 'string' attributes can have tags");
606                 return -1;
607         }
608
609
610         /*
611          *      If the attr is '-1', that means use a pre-existing
612          *      one (if it already exists).  If one does NOT already exist,
613          *      then create a new attribute, with a non-conflicting value,
614          *      and use that.
615          */
616         if (attr == -1) {
617                 if (dict_attrbyname(name)) {
618                         return 0; /* exists, don't add it again */
619                 }
620
621                 attr = ++max_attr;
622
623         } else if (vendor == 0) {
624                 /*
625                  *  Update 'max_attr'
626                  */
627                 if (attr > max_attr) {
628                         max_attr = attr;
629                 }
630         }
631
632         /*
633          *      Additional checks for extended attributes.
634          */
635         if (flags.extended || flags.long_extended || flags.evs) {
636                 if (vendor && (vendor < FR_MAX_VENDOR)) {
637                         fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats.");
638                         return -1;
639                 }
640                 if (flags.has_tag
641 #ifdef WITH_DHCP
642                     || flags.array
643 #endif
644                     || (flags.encrypt != FLAG_ENCRYPT_NONE)) {
645                         fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set.");
646                         return -1;
647                 }
648         }
649
650         if (flags.evs) {
651                 if (!(flags.extended || flags.long_extended)) {
652                         fr_strerror_printf("dict_addattr: Attributes of type \"evs\" MUST have a parent of type \"extended\"");
653                         return -1;
654                 }
655
656                 /* VSAs cannot be of format EVS */
657                 if ((vendor & (FR_MAX_VENDOR - 1)) != 0) {
658                         fr_strerror_printf("dict_addattr: Attribute of type \"evs\" fails internal sanity check");
659                         return -1;
660                 }
661         }
662                 
663         if (attr < 0) {
664                 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
665                 return -1;
666         }
667
668         if (flags.has_tlv && flags.length) {
669                 fr_strerror_printf("TLVs cannot have a fixed length");
670                 return -1;
671         }
672
673         if ((vendor & (FR_MAX_VENDOR -1)) != 0) {
674                 DICT_VENDOR *dv;
675                 static DICT_VENDOR *last_vendor = NULL;
676
677                 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
678                         fr_strerror_printf("TLV's cannot be encrypted");
679                         return -1;
680                 }
681
682                 if (flags.is_tlv && flags.has_tag) {
683                         fr_strerror_printf("Sub-TLV's cannot have a tag");
684                         return -1;
685                 }
686
687                 if (flags.has_tlv && flags.has_tag) {
688                         fr_strerror_printf("TLV's cannot have a tag");
689                         return -1;
690                 }
691
692                 /*
693                  *      Most ATTRIBUTEs are bunched together by
694                  *      VENDOR.  We can save a lot of lookups on
695                  *      dictionary initialization by caching the last
696                  *      vendor.
697                  */
698                 if (last_vendor &&
699                     ((vendor & (FR_MAX_VENDOR - 1)) == last_vendor->vendorpec)) {
700                         dv = last_vendor;
701                 } else {
702                         /*
703                          *      Ignore the high byte (sigh)
704                          */
705                         dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
706                         last_vendor = dv;
707                 }
708
709                 /*
710                  *      If the vendor isn't defined, die.
711                  */
712                 if (!dv) {
713                         fr_strerror_printf("dict_addattr: Unknown vendor %u",
714                                            vendor & (FR_MAX_VENDOR - 1));
715                         return -1;
716                 }
717
718                 /*
719                  *      FIXME: Switch over dv->type, and limit things
720                  *      properly.
721                  */
722                 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
723                         fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
724                         return -1;
725                 } /* else 256..65535 are allowed */
726
727                 /*
728                  *      If the attribute is in the standard space, AND
729                  *      has a sub-type (e.g. 241.1 or 255.3), then its
730                  *      number is placed into the upper 8 bits of the
731                  *      vendor field.
732                  *
733                  *      This also happens for the new VSAs.
734                  *
735                  *      If we find it, then set the various flags
736                  *      based on what we see.
737                  */
738                 if (vendor >= FR_MAX_VENDOR) {
739                         unsigned int parent;
740
741                         parent = (vendor / FR_MAX_VENDOR) & 0xff;
742
743                         da = dict_attrbyvalue(parent, 0);
744                         if (!da) {
745                                 fr_strerror_printf("dict_addattr: ATTRIBUTE refers to unknown parent attribute %u.", parent);
746                                 return -1;
747                         }
748
749                         /*
750                          *      These flags are inhereited inherited
751                          *      from the parent.
752                          */
753                         flags.extended = da->flags.extended;
754                         flags.long_extended = da->flags.long_extended;
755
756                         /*
757                          *      Non-extended attributes can't have VSAs.
758                          */
759                         if (!flags.extended &&
760                             ((vendor & (FR_MAX_VENDOR - 1)) != 0)) {
761                                 fr_strerror_printf("dict_addattr: ATTRIBUTE cannot be a VSA");
762                                 return -1;
763                         }
764
765                         if ((vendor & (FR_MAX_VENDOR - 1)) != 0) {
766                                 flags.evs = 1;
767                         }
768                 }
769
770                 /*
771                  *      <sigh> Alvarion, being *again* a horribly
772                  *      broken vendor, has re-used the WiMAX format in
773                  *      their proprietary vendor space.  This re-use
774                  *      means that there are *multiple* conflicting
775                  *      Alvarion dictionaries.
776                  */
777                 flags.wimax = dv->flags;
778         }
779
780         /*
781          *      Create a new attribute for the list
782          */
783         if ((da = fr_pool_alloc(sizeof(*da) + namelen)) == NULL) {
784         oom:
785                 fr_strerror_printf("dict_addattr: out of memory");
786                 return -1;
787         }
788
789         memcpy(da->name, name, namelen);
790         da->name[namelen] = '\0';
791         da->attr = attr;
792         da->vendor = vendor;
793         da->type = type;
794         da->flags = flags;
795
796         /*
797          *      Insert the attribute, only if it's not a duplicate.
798          */
799         if (!fr_hash_table_insert(attributes_byname, da)) {
800                 DICT_ATTR       *a;
801
802                 /*
803                  *      If the attribute has identical number, then
804                  *      ignore the duplicate.
805                  */
806                 a = fr_hash_table_finddata(attributes_byname, da);
807                 if (a && (strcasecmp(a->name, da->name) == 0)) {
808                         if (a->attr != da->attr) {
809                                 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
810                                 fr_pool_free(da);
811                                 return -1;
812                         }
813
814                         /*
815                          *      Same name, same vendor, same attr,
816                          *      maybe the flags and/or type is
817                          *      different.  Let the new value
818                          *      over-ride the old one.
819                          */
820                 }
821
822
823                 fr_hash_table_delete(attributes_byvalue, a);
824
825                 if (!fr_hash_table_replace(attributes_byname, da)) {
826                         fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
827                         fr_pool_free(da);
828                         return -1;
829                 }
830         }
831
832         /*
833          *      Insert the SAME pointer (not free'd when this entry is
834          *      deleted), into another table.
835          *
836          *      We want this behaviour because we want OLD names for
837          *      the attributes to be read from the configuration
838          *      files, but when we're printing them, (and looking up
839          *      by value) we want to use the NEW name.
840          */
841         if (!fr_hash_table_replace(attributes_byvalue, da)) {
842                 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
843                 return -1;
844         }
845
846         /*
847          *      Hacks for combo-IP
848          */
849         if (da->type == PW_TYPE_COMBO_IP) {
850                 DICT_ATTR *v4, *v6;
851
852                 v4 = malloc(sizeof(*v4));
853                 if (!v4) goto oom;
854
855                 v6 = malloc(sizeof(*v6));
856                 if (!v6) {
857                         free(v4);
858                         goto oom;
859                 }
860
861                 memcpy(v4, da, sizeof(*v4));
862                 v4->type = PW_TYPE_IPADDR;
863
864                 memcpy(v6, da, sizeof(*v6));
865                 v6->type = PW_TYPE_IPV6ADDR;
866
867                 if (fr_hash_table_insert(attributes_combo, v4)) {
868                         fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
869                         free(v4);
870                         free(v6);
871                         return -1;
872                 }
873
874                 if (fr_hash_table_insert(attributes_combo, v6)) {
875                         fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
876                         free(v6);
877                         return -1;
878                 }
879         }
880
881         if (!vendor && (attr > 0) && (attr < 256)) {
882                  dict_base_attrs[attr] = da;
883         }
884
885         return 0;
886 }
887
888
889 /*
890  *      Add a value for an attribute to the dictionary.
891  */
892 int dict_addvalue(const char *namestr, const char *attrstr, int value)
893 {
894         size_t          length;
895         DICT_ATTR       *dattr;
896         DICT_VALUE      *dval;
897
898         static DICT_ATTR *last_attr = NULL;
899
900         if (!*namestr) {
901                 fr_strerror_printf("dict_addvalue: empty names are not permitted");
902                 return -1;
903         }
904
905         if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
906                 fr_strerror_printf("dict_addvalue: value name too long");
907                 return -1;
908         }
909
910         if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
911                 fr_strerror_printf("dict_addvalue: out of memory");
912                 return -1;
913         }
914         memset(dval, 0, sizeof(*dval));
915
916         strcpy(dval->name, namestr);
917         dval->value = value;
918
919         /*
920          *      Most VALUEs are bunched together by ATTRIBUTE.  We can
921          *      save a lot of lookups on dictionary initialization by
922          *      caching the last attribute.
923          */
924         if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
925                 dattr = last_attr;
926         } else {
927                 dattr = dict_attrbyname(attrstr);
928                 last_attr = dattr;
929         }
930
931         /*
932          *      Remember which attribute is associated with this
933          *      value, if possible.
934          */
935         if (dattr) {
936                 if (dattr->flags.has_value_alias) {
937                         fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
938                         return -1;
939                 }
940
941                 dval->attr = dattr->attr;
942                 dval->vendor = dattr->vendor;
943
944                 /*
945                  *      Enforce valid values
946                  *
947                  *      Don't worry about fixups...
948                  */
949                 switch (dattr->type) {
950                         case PW_TYPE_BYTE:
951                                 if (value > 255) {
952                                         fr_pool_free(dval);
953                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
954                                         return -1;
955                                 }
956                                 break;
957                         case PW_TYPE_SHORT:
958                                 if (value > 65535) {
959                                         fr_pool_free(dval);
960                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
961                                         return -1;
962                                 }
963                                 break;
964
965                                 /*
966                                  *      Allow octets for now, because
967                                  *      of dictionary.cablelabs
968                                  */
969                         case PW_TYPE_OCTETS:
970
971                         case PW_TYPE_INTEGER:
972                                 break;
973
974                         case PW_TYPE_INTEGER64:
975                         default:
976                                 fr_pool_free(dval);
977                                 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
978                                            fr_int2str(dict_attr_types, dattr->type, "?Unknown?"));
979                                 return -1;
980                 }
981
982                 dattr->flags.has_value = 1;
983         } else {
984                 value_fixup_t *fixup;
985
986                 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
987                 if (!fixup) {
988                         fr_pool_free(dval);
989                         fr_strerror_printf("dict_addvalue: out of memory");
990                         return -1;
991                 }
992                 memset(fixup, 0, sizeof(*fixup));
993
994                 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
995                 fixup->dval = dval;
996
997                 /*
998                  *      Insert to the head of the list.
999                  */
1000                 fixup->next = value_fixup;
1001                 value_fixup = fixup;
1002
1003                 return 0;
1004         }
1005
1006         /*
1007          *      Add the value into the dictionary.
1008          */
1009         if (!fr_hash_table_insert(values_byname, dval)) {
1010                 if (dattr) {
1011                         DICT_VALUE *old;
1012
1013                         /*
1014                          *      Suppress duplicates with the same
1015                          *      name and value.  There are lots in
1016                          *      dictionary.ascend.
1017                          */
1018                         old = dict_valbyname(dattr->attr, dattr->vendor, namestr);
1019                         if (old && (old->value == dval->value)) {
1020                                 fr_pool_free(dval);
1021                                 return 0;
1022                         }
1023                 }
1024
1025                 fr_pool_free(dval);
1026                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
1027                 return -1;
1028         }
1029
1030         /*
1031          *      There are multiple VALUE's, keyed by attribute, so we
1032          *      take care of that here.
1033          */
1034         if (!fr_hash_table_replace(values_byvalue, dval)) {
1035                 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
1036                            namestr);
1037                 return -1;
1038         }
1039
1040         return 0;
1041 }
1042
1043 static int sscanf_i(const char *str, unsigned int *pvalue)
1044 {
1045         int rcode = 0;
1046         int base = 10;
1047         static const char *tab = "0123456789";
1048
1049         if ((str[0] == '0') &&
1050             ((str[1] == 'x') || (str[1] == 'X'))) {
1051                 tab = "0123456789abcdef";
1052                 base = 16;
1053
1054                 str += 2;
1055         }
1056
1057         while (*str) {
1058                 const char *c;
1059
1060                 if (*str == '.') break;
1061
1062                 c = memchr(tab, tolower((int) *str), base);
1063                 if (!c) return 0;
1064
1065                 rcode *= base;
1066                 rcode += (c - tab);
1067                 str++;
1068         }
1069
1070         *pvalue = rcode;
1071         return 1;
1072 }
1073
1074
1075 /*
1076  *      Get the OID based on various pieces of information.
1077  *
1078  *      Remember, the packing format is weird.
1079  *
1080  *      00VID   000000AA        normal VSA for vendor VID
1081  *      00VID   AABBCCDD        normal VSAs with TLVs
1082  *      EE000   000000AA        extended attr (241.1)
1083  *      EE000   AABBCCDD        extended attr with TLVs
1084  *      EEVID   000000AA        EVS with vendor VID, attr AAA
1085  *      EEVID   AABBCCDD        EVS with TLVs
1086  *
1087  *      <whew>!  Are we crazy, or what?
1088  */
1089 int dict_str2oid(const char *ptr, unsigned int *pvalue, unsigned int *pvendor,
1090                  int tlv_depth)
1091 {
1092         const char *p;
1093         unsigned int value;
1094         DICT_ATTR *da;
1095
1096         if (tlv_depth > fr_attr_max_tlv) {
1097                 fr_strerror_printf("Too many sub-attributes");
1098                 return -1;
1099         }
1100
1101         /*
1102          *      If *pvalue is set, check if the attribute exists.
1103          *      Otherwise, check that the vendor exists.
1104          */
1105         if (*pvalue) {
1106                 da = dict_attrbyvalue(*pvalue, *pvendor);
1107                 if (!da) {
1108                         fr_strerror_printf("Parent attribute is undefined.");
1109                         return -1;
1110                 }
1111                 
1112                 if (!da->flags.has_tlv && !da->flags.extended) {
1113                         fr_strerror_printf("Parent attribute %s cannot have sub-attributes",
1114                                            da->name);
1115                         return -1;
1116                 }
1117
1118         } else if ((*pvendor & (FR_MAX_VENDOR - 1)) != 0) {
1119                 if (!dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1))) {
1120                         fr_strerror_printf("Unknown vendor %u",
1121                                            *pvendor & (FR_MAX_VENDOR - 1));
1122                         return -1;
1123                 }
1124         }
1125
1126         p = strchr(ptr, '.');
1127
1128         /*
1129          *      Look for 26.VID.x.y
1130          *
1131          *      If we find it, re-write the parameters, and recurse.
1132          */
1133         if (!*pvendor && (tlv_depth == 0) && (*pvalue == PW_VENDOR_SPECIFIC)) {
1134                 const DICT_VENDOR *dv;
1135
1136                 if (!p) {
1137                         fr_strerror_printf("VSA needs to have sub-attribute");
1138                         return -1;
1139                 }
1140
1141                 if (!sscanf_i(ptr, pvendor)) {
1142                         fr_strerror_printf("Invalid number in attribute");
1143                         return -1;
1144                 }
1145
1146                 if (*pvendor >= FR_MAX_VENDOR) {
1147                         fr_strerror_printf("Cannot handle vendor ID larger than 2^24");
1148                         
1149                         return -1;
1150                 }
1151
1152                 dv = dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1));
1153                 if (!dv) {
1154                         fr_strerror_printf("Unknown vendor \"%u\" ",
1155                                            *pvendor  & (FR_MAX_VENDOR - 1));
1156                         return -1;
1157                 }
1158
1159                 /*
1160                  *      Start off with (attr=0, vendor=VID), and
1161                  *      recurse.  This causes the various checks above
1162                  *      to be done.
1163                  */
1164                 *pvalue = 0;
1165                 return dict_str2oid(p + 1, pvalue, pvendor, 0);
1166         }
1167
1168         if (!sscanf_i(ptr, &value)) {
1169                 fr_strerror_printf("Invalid number in attribute");
1170                 return -1;
1171         }
1172
1173         if (!*pvendor && (tlv_depth == 1) &&
1174             (da->flags.has_tlv || da->flags.extended)) {
1175
1176
1177                 *pvendor = *pvalue * FR_MAX_VENDOR;
1178                 *pvalue = value;
1179
1180                 if (!p) return 0;
1181                 return dict_str2oid(p + 1, pvalue, pvendor, 1);
1182         }
1183
1184         /*
1185          *      And pack the data according to the scheme described in
1186          *      the comments at the start of this function.
1187          */
1188         if (*pvalue) {
1189                 *pvalue |= (value & fr_attr_mask[tlv_depth]) << fr_attr_shift[tlv_depth];
1190         } else {
1191                 *pvalue = value;
1192         }
1193
1194         if (p) {
1195                 return dict_str2oid(p + 1, pvalue, pvendor, tlv_depth + 1);
1196         }
1197
1198         return tlv_depth;
1199 }
1200
1201 /*
1202  *      Bamboo skewers under the fingernails in 5, 4, 3, 2, ...
1203  */
1204 static DICT_ATTR *dict_parent(unsigned int attr, unsigned int vendor)
1205 {
1206         if (vendor < FR_MAX_VENDOR) {
1207                 return dict_attrbyvalue(attr & 0xff, vendor);
1208         }
1209
1210         if (attr < 256) {
1211                 return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0);
1212         }
1213
1214         return dict_attrbyvalue(attr & 0xff, vendor);
1215 }
1216
1217
1218 /*
1219  *      Process the ATTRIBUTE command
1220  */
1221 static int process_attribute(const char* fn, const int line,
1222                              unsigned int block_vendor, DICT_ATTR *block_tlv,
1223                              int tlv_depth, char **argv, int argc)
1224 {
1225         int             oid = 0;
1226         unsigned int    vendor = 0;
1227         unsigned int    value;
1228         int             type;
1229         unsigned int    length = 0;
1230         ATTR_FLAGS      flags;
1231         char            *p;
1232
1233         if ((argc < 3) || (argc > 4)) {
1234                 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
1235                         fn, line);
1236                 return -1;
1237         }
1238
1239         /*
1240          *      Dictionaries need to have real names, not shitty ones.
1241          */
1242         if (strncmp(argv[1], "Attr-", 5) == 0) {
1243                 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
1244                                    fn, line);
1245                 return -1;
1246         }
1247
1248         memset(&flags, 0, sizeof(flags));
1249
1250         /*
1251          *      Look for OIDs before doing anything else.
1252          */
1253         p = strchr(argv[1], '.');
1254         if (p) oid = 1;
1255
1256         /*
1257          *      Validate all entries
1258          */
1259         if (!sscanf_i(argv[1], &value)) {
1260                 fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
1261                 return -1;
1262         }
1263
1264         if (oid) {
1265                 DICT_ATTR *da;
1266
1267                 vendor = block_vendor;
1268
1269                 /*
1270                  *      Parse the rest of the OID.
1271                  */
1272                 if (dict_str2oid(p + 1, &value, &vendor, tlv_depth + 1) < 0) {
1273                         char buffer[256];
1274
1275                         strlcpy(buffer, fr_strerror(), sizeof(buffer));
1276                         
1277                         fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
1278                         return -1;
1279                 }
1280                 block_vendor = vendor;
1281
1282                 /*
1283                  *      Set the flags based on the parents flags.
1284                  */
1285                 da = dict_parent(value, vendor);
1286                 if (!da) {
1287                         fr_strerror_printf("dict_init: %s[%d]: Parent attribute is undefined.", fn, line);
1288                         return -1;
1289                 }
1290
1291                 flags.extended = da->flags.extended;
1292                 flags.long_extended = da->flags.long_extended;
1293                 flags.evs = da->flags.evs;
1294                 if (da->flags.has_tlv) flags.is_tlv = 1;
1295         }
1296
1297         if (strncmp(argv[2], "octets[", 7) != 0) {
1298                 /*
1299                  *      find the type of the attribute.
1300                  */
1301                 type = fr_str2int(dict_attr_types, argv[2], -1);
1302                 if (type < 0) {
1303                         fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
1304                                            fn, line, argv[2]);
1305                         return -1;
1306                 }
1307
1308         } else {
1309                 type = PW_TYPE_OCTETS;
1310                 
1311                 p = strchr(argv[2] + 7, ']');
1312                 if (!p) {
1313                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
1314                         return -1;
1315                 }
1316
1317                 *p = 0;
1318
1319                 if (!sscanf_i(argv[1], &length)) {
1320                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1321                         return -1;
1322                 }
1323
1324                 if ((length == 0) || (length > 253)) {
1325                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1326                         return -1;
1327                 }
1328         }
1329
1330         /*
1331          *      Only look up the vendor if the string
1332          *      is non-empty.
1333          */
1334         if (argc < 4) {
1335                 /*
1336                  *      Force "length" for data types of fixed length;
1337                  */
1338                 switch (type) {
1339                 case PW_TYPE_BYTE:
1340                         length = 1;
1341                         break;
1342
1343                 case PW_TYPE_SHORT:
1344                         length = 2;
1345                         break;
1346
1347                 case PW_TYPE_DATE:
1348                 case PW_TYPE_IPADDR:
1349                 case PW_TYPE_INTEGER:
1350                 case PW_TYPE_SIGNED:
1351                         length = 4;
1352                         break;
1353
1354                 case PW_TYPE_INTEGER64:
1355                         length = 8;
1356                         break;
1357
1358                 case PW_TYPE_ETHERNET:
1359                         length = 6;
1360                         break;
1361
1362                 case PW_TYPE_IFID:
1363                         length = 8;
1364                         break;
1365
1366                 case PW_TYPE_IPV6ADDR:
1367                         length = 16;
1368                         break;
1369
1370                 case PW_TYPE_EXTENDED:
1371                         if ((vendor != 0) || (value < 241)) {
1372                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"extended\" MUST be RFC attributes with value >= 241.", fn, line);
1373                                 return -1;
1374                         }
1375                         type = PW_TYPE_OCTETS;
1376                         flags.extended = 1;
1377                         break;
1378
1379                 case PW_TYPE_LONG_EXTENDED:
1380                         if ((vendor != 0) || (value < 241)) {
1381                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"long-extended\" MUST be RFC attributes with value >= 241.", fn, line);
1382                                 return -1;
1383                         }
1384                         type = PW_TYPE_OCTETS;
1385                         flags.extended = 1;
1386                         flags.long_extended = 1;
1387                         break;
1388
1389                 case PW_TYPE_EVS:
1390                         type = PW_TYPE_OCTETS;
1391                         flags.extended = 1;
1392                         flags.evs = 1;
1393                         if (value != PW_VENDOR_SPECIFIC) {
1394                                 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"evs\" MUST have attribute code 26.", fn, line);
1395                                 return -1;
1396                         }
1397                         break;
1398
1399                 default:
1400                         break;
1401                 }
1402
1403                 flags.length = length;
1404
1405         } else {                /* argc == 4: we have options */
1406                 char *key, *next, *last;
1407
1408                 /*
1409                  *      Keep it real.
1410                  */
1411                 if (flags.extended) {
1412                         fr_strerror_printf("dict_init: %s[%d]: Extended attributes cannot use flags", fn, line);
1413                         return -1;
1414                 }
1415
1416                 if (length != 0) {
1417                         fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line);
1418                         return -1;
1419                 }
1420
1421                 key = argv[3];
1422                 do {
1423                         next = strchr(key, ',');
1424                         if (next) *(next++) = '\0';
1425
1426                         if (strcmp(key, "has_tag") == 0 ||
1427                             strcmp(key, "has_tag=1") == 0) {
1428                                 /* Boolean flag, means this is a
1429                                    tagged attribute */
1430                                 flags.has_tag = 1;
1431                                 
1432                         } else if (strncmp(key, "encrypt=", 8) == 0) {
1433                                 /* Encryption method, defaults to 0 (none).
1434                                    Currently valid is just type 2,
1435                                    Tunnel-Password style, which can only
1436                                    be applied to strings. */
1437                                 flags.encrypt = strtol(key + 8, &last, 0);
1438                                 if (*last) {
1439                                         fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
1440                                                     fn, line, key);
1441                                         return -1;
1442                                 }
1443
1444                                 if ((flags.encrypt == FLAG_ENCRYPT_ASCEND_SECRET) &&
1445                                     (type != PW_TYPE_STRING)) {
1446                                         fr_strerror_printf( "dict_init: %s[%d] Only \"string\" types can have the \"encrypt=3\" flag set.",
1447                                                             fn, line);
1448                                         return -1;
1449                                 }
1450                                 
1451                         } else if (strncmp(key, "array", 6) == 0) {
1452                                 flags.array = 1;
1453                                 
1454                                 switch (type) {
1455                                         case PW_TYPE_IPADDR:
1456                                         case PW_TYPE_BYTE:
1457                                         case PW_TYPE_SHORT:
1458                                         case PW_TYPE_INTEGER:
1459                                         case PW_TYPE_DATE:
1460                                                 break;
1461
1462                                         default:
1463                                                 fr_strerror_printf( "dict_init: %s[%d] Only IP addresses can have the \"array\" flag set.",
1464                                                             fn, line);
1465                                                 return -1;
1466                                 }
1467
1468                                 /*
1469                                  *      The only thing is the vendor name,
1470                                  *      and it's a known name: allow it.
1471                                  */
1472                         } else if ((key == argv[3]) && !next) {
1473                                 if (oid) {
1474                                         fr_strerror_printf( "dict_init: %s[%d] New-style attributes cannot use a vendor flag.",
1475                                                             fn, line);
1476                                         return -1;
1477                                 }
1478
1479                                 if (block_vendor) {
1480                                         fr_strerror_printf( "dict_init: %s[%d] Vendor flag inside of \"BEGIN-VENDOR\" is not allowed.",
1481                                                             fn, line);
1482                                         return -1;
1483                                 }
1484
1485                                 vendor = dict_vendorbyname(key);
1486                                 if (!vendor) goto unknown;
1487                                 break;
1488
1489                         } else {
1490                         unknown:
1491                                 fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
1492                                             fn, line, key);
1493                                 return -1;
1494                         }
1495
1496                         key = next;
1497                         if (key && !*key) break;
1498                 } while (key);
1499         }
1500
1501         if (block_vendor) vendor = block_vendor;
1502
1503         /*
1504          *      Special checks for tags, they make our life much more
1505          *      difficult.
1506          */
1507         if (flags.has_tag) {
1508                 /*
1509                  *      Only string, octets, and integer can be tagged.
1510                  */
1511                 switch (type) {
1512                 case PW_TYPE_STRING:
1513                 case PW_TYPE_INTEGER:
1514                         break;
1515
1516                 default:
1517                         fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
1518                                    fn, line,
1519                                    fr_int2str(dict_attr_types, type, "?Unknown?"));
1520                         return -1;
1521                 }
1522         }
1523
1524         if (type == PW_TYPE_TLV) {
1525                 if (vendor && (vendor < FR_MAX_VENDOR)
1526 #ifdef WITH_DHCP
1527                     && (vendor != DHCP_MAGIC_VENDOR)
1528 #endif
1529                         ) {
1530                         DICT_VENDOR *dv;
1531
1532                         dv = dict_vendorbyvalue(vendor);
1533                         if (!dv || (dv->type != 1) || (dv->length != 1)) {
1534                                 fr_strerror_printf("dict_init: %s[%d]: Type \"tlv\" can only be for \"format=1,1\".",
1535                                                    fn, line);
1536                                 return -1;
1537                         }
1538
1539                 }
1540                 flags.has_tlv = 1;
1541         }
1542         
1543         if (block_tlv) {
1544                 /*
1545                  *      TLV's can be only one octet.
1546                  */
1547                 if ((value == 0) || ((value & ~fr_attr_mask[tlv_depth]) != 0)) {
1548                         fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1549                                             fn, line);
1550                         return -1;
1551                 }
1552
1553                 /*
1554                  *      
1555                  */
1556                 value <<= fr_attr_shift[tlv_depth];
1557                 value |= block_tlv->attr;
1558                 flags.is_tlv = 1;
1559         }
1560
1561 #ifdef WITH_DICTIONARY_WARNINGS
1562         /*
1563          *      Hack to help us discover which vendors have illegal
1564          *      attributes.
1565          */
1566         if (!vendor && (value < 256) &&
1567             !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
1568                 fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
1569                         argv[0], fn);
1570         }
1571 #endif
1572
1573         /*
1574          *      Add it in.
1575          */
1576         if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1577                 char buffer[256];
1578
1579                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1580
1581                 fr_strerror_printf("dict_init: %s[%d]: %s",
1582                                    fn, line, buffer);
1583                 return -1;
1584         }
1585
1586         return 0;
1587 }
1588
1589
1590 /*
1591  *      Process the VALUE command
1592  */
1593 static int process_value(const char* fn, const int line, char **argv,
1594                          int argc)
1595 {
1596         unsigned int    value;
1597
1598         if (argc != 3) {
1599                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1600                         fn, line);
1601                 return -1;
1602         }
1603         /*
1604          *      For Compatibility, skip "Server-Config"
1605          */
1606         if (strcasecmp(argv[0], "Server-Config") == 0)
1607                 return 0;
1608
1609         /*
1610          *      Validate all entries
1611          */
1612         if (!sscanf_i(argv[2], &value)) {
1613                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1614                         fn, line);
1615                 return -1;
1616         }
1617
1618         if (dict_addvalue(argv[1], argv[0], value) < 0) {
1619                 char buffer[256];
1620
1621                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1622
1623                 fr_strerror_printf("dict_init: %s[%d]: %s",
1624                                    fn, line, buffer);
1625                 return -1;
1626         }
1627
1628         return 0;
1629 }
1630
1631
1632 /*
1633  *      Process the VALUE-ALIAS command
1634  *
1635  *      This allows VALUE mappings to be shared among multiple
1636  *      attributes.
1637  */
1638 static int process_value_alias(const char* fn, const int line, char **argv,
1639                                int argc)
1640 {
1641         DICT_ATTR *my_da, *da;
1642         DICT_VALUE *dval;
1643
1644         if (argc != 2) {
1645                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1646                         fn, line);
1647                 return -1;
1648         }
1649
1650         my_da = dict_attrbyname(argv[0]);
1651         if (!my_da) {
1652                 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1653                            fn, line, argv[1]);
1654                 return -1;
1655         }
1656
1657         if (my_da->flags.has_value) {
1658                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE",
1659                            fn, line, argv[0]);
1660                 return -1;
1661         }
1662
1663         if (my_da->flags.has_value_alias) {
1664                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
1665                            fn, line, argv[0]);
1666                 return -1;
1667         }
1668
1669         da = dict_attrbyname(argv[1]);
1670         if (!da) {
1671                 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
1672                            fn, line, argv[1]);
1673                 return -1;
1674         }
1675
1676         if (!da->flags.has_value) {
1677                 fr_strerror_printf("dict_init: %s[%d]: VALUE-ALIAS cannot refer to ATTRIBUTE %s: It has no values",
1678                            fn, line, argv[1]);
1679                 return -1;
1680         }
1681
1682         if (da->flags.has_value_alias) {
1683                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
1684                            fn, line, argv[1]);
1685                 return -1;
1686         }
1687
1688         if (my_da->type != da->type) {
1689                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
1690                            fn, line);
1691                 return -1;
1692         }
1693
1694         if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
1695                 fr_strerror_printf("dict_addvalue: out of memory");
1696                 return -1;
1697         }
1698
1699         dval->name[0] = '\0';   /* empty name */
1700         dval->attr = my_da->attr;
1701         dval->vendor = my_da->vendor;
1702         dval->value = da->attr;
1703
1704         if (!fr_hash_table_insert(values_byname, dval)) {
1705                 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
1706                            fn, line);
1707                 fr_pool_free(dval);
1708                 return -1;
1709         }
1710
1711         return 0;
1712 }
1713
1714
1715 /*
1716  *      Process the VENDOR command
1717  */
1718 static int process_vendor(const char* fn, const int line, char **argv,
1719                           int argc)
1720 {
1721         int     value;
1722         int     continuation = 0;
1723         const   char *format = NULL;
1724
1725         if ((argc < 2) || (argc > 3)) {
1726                 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
1727                             fn, line);
1728                 return -1;
1729         }
1730
1731         /*
1732          *       Validate all entries
1733          */
1734         if (!isdigit((int) argv[1][0])) {
1735                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1736                         fn, line);
1737                 return -1;
1738         }
1739         value = atoi(argv[1]);
1740
1741         /* Create a new VENDOR entry for the list */
1742         if (dict_addvendor(argv[0], value) < 0) {
1743                 char buffer[256];
1744
1745                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1746
1747                 fr_strerror_printf("dict_init: %s[%d]: %s",
1748                            fn, line, buffer);
1749                 return -1;
1750         }
1751
1752         /*
1753          *      Look for a format statement
1754          */
1755         if (argc == 3) {
1756                 format = argv[2];
1757
1758         } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
1759                 format = "format=4,0";
1760
1761         } else if (value == VENDORPEC_LUCENT) {
1762                 format = "format=2,1";
1763
1764         } else if (value == VENDORPEC_STARENT) {
1765                 format = "format=2,2";
1766
1767         } /* else no fixups to do */
1768
1769         if (format) {
1770                 int type, length;
1771                 const char *p;
1772                 DICT_VENDOR *dv;
1773
1774                 if (strncasecmp(format, "format=", 7) != 0) {
1775                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
1776                                    fn, line, format);
1777                         return -1;
1778                 }
1779
1780                 p = format + 7;
1781                 if ((strlen(p) < 3) ||
1782                     !isdigit((int) p[0]) ||
1783                     (p[1] != ',') ||
1784                     !isdigit((int) p[2]) ||
1785                     (p[3] && (p[3] != ','))) {
1786                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1787                                    fn, line, p);
1788                         return -1;
1789                 }
1790
1791                 type = (int) (p[0] - '0');
1792                 length = (int) (p[2] - '0');
1793
1794                 if (p[3] == ',') {
1795                         if (!p[4]) {
1796                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1797                                    fn, line, p);
1798                                 return -1;
1799                         }
1800
1801                         if ((p[4] != 'c') ||
1802                             (p[5] != '\0')) {
1803                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1804                                            fn, line, p);
1805                                 return -1;
1806                         }
1807                         continuation = 1;
1808
1809                         if ((value != VENDORPEC_WIMAX) ||
1810                             (type != 1) || (length != 1)) {
1811                                 fr_strerror_printf("dict_init: %s[%d]: Only WiMAX VSAs can have continuations",
1812                                            fn, line);
1813                                 return -1;
1814                         }
1815                 }
1816
1817                 dv = dict_vendorbyvalue(value);
1818                 if (!dv) {
1819                         fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
1820                                    fn, line);
1821                         return -1;
1822                 }
1823
1824                 if ((type != 1) && (type != 2) && (type != 4)) {
1825                         fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
1826                                    fn, line, type);
1827                         return -1;
1828                 }
1829
1830                 if ((length != 0) && (length != 1) && (length != 2)) {
1831                         fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
1832                                    fn, line, length);
1833                         return -1;
1834                 }
1835
1836                 dv->type = type;
1837                 dv->length = length;
1838                 dv->flags = continuation;
1839         }
1840
1841         return 0;
1842 }
1843
1844 /*
1845  *      String split routine.  Splits an input string IN PLACE
1846  *      into pieces, based on spaces.
1847  */
1848 int str2argv(char *str, char **argv, int max_argc)
1849 {
1850         int argc = 0;
1851
1852         while (*str) {
1853                 if (argc >= max_argc) break;
1854
1855                 /*
1856                  *      Chop out comments early.
1857                  */
1858                 if (*str == '#') {
1859                         *str = '\0';
1860                         break;
1861                 }
1862
1863                 while ((*str == ' ') ||
1864                        (*str == '\t') ||
1865                        (*str == '\r') ||
1866                        (*str == '\n')) *(str++) = '\0';
1867
1868                 if (!*str) break;
1869
1870                 argv[argc] = str;
1871                 argc++;
1872
1873                 while (*str &&
1874                        (*str != ' ') &&
1875                        (*str != '\t') &&
1876                        (*str != '\r') &&
1877                        (*str != '\n')) str++;
1878         }
1879
1880         return argc;
1881 }
1882
1883 #define MAX_ARGV (16)
1884
1885 /*
1886  *      Initialize the dictionary.
1887  */
1888 static int my_dict_init(const char *dir, const char *fn,
1889                         const char *src_file, int src_line)
1890 {
1891         FILE    *fp;
1892         char    dirtmp[256];
1893         char    buf[256];
1894         char    *p;
1895         int     line = 0;
1896         unsigned int    vendor;
1897         unsigned int    block_vendor;
1898         struct stat statbuf;
1899         char    *argv[MAX_ARGV];
1900         int     argc;
1901         DICT_ATTR *da, *block_tlv[MAX_TLV_NEST + 1];
1902         int     which_block_tlv = 0;
1903
1904         block_tlv[0] = NULL;
1905         block_tlv[1] = NULL;
1906         block_tlv[2] = NULL;
1907         block_tlv[3] = NULL;
1908
1909         if (strlen(fn) >= sizeof(dirtmp) / 2 ||
1910             strlen(dir) >= sizeof(dirtmp) / 2) {
1911                 fr_strerror_printf("dict_init: filename name too long");
1912                 return -1;
1913         }
1914
1915         /*
1916          *      First see if fn is relative to dir. If so, create
1917          *      new filename. If not, remember the absolute dir.
1918          */
1919         if ((p = strrchr(fn, FR_DIR_SEP)) != NULL) {
1920                 strcpy(dirtmp, fn);
1921                 dirtmp[p - fn] = 0;
1922                 dir = dirtmp;
1923         } else if (dir && dir[0] && strcmp(dir, ".") != 0) {
1924                 snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn);
1925                 fn = dirtmp;
1926         }
1927
1928         if ((fp = fopen(fn, "r")) == NULL) {
1929                 if (!src_file) {
1930                         fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
1931                                    fn, strerror(errno));
1932                 } else {
1933                         fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
1934                                    src_file, src_line, fn, strerror(errno));
1935                 }
1936                 return -2;
1937         }
1938
1939         stat(fn, &statbuf); /* fopen() guarantees this will succeed */
1940         if (!S_ISREG(statbuf.st_mode)) {
1941                 fclose(fp);
1942                 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
1943                            fn);
1944                 return -1;
1945         }
1946
1947         /*
1948          *      Globally writable dictionaries means that users can control
1949          *      the server configuration with little difficulty.
1950          */
1951 #ifdef S_IWOTH
1952         if ((statbuf.st_mode & S_IWOTH) != 0) {
1953                 fclose(fp);
1954                 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable.  Refusing to start due to insecure configuration.",
1955                            fn);
1956                 return -1;
1957         }
1958 #endif
1959
1960         dict_stat_add(fn, &statbuf);
1961
1962         /*
1963          *      Seed the random pool with data.
1964          */
1965         fr_rand_seed(&statbuf, sizeof(statbuf));
1966
1967         block_vendor = 0;
1968
1969         while (fgets(buf, sizeof(buf), fp) != NULL) {
1970                 line++;
1971                 if (buf[0] == '#' || buf[0] == 0 ||
1972                     buf[0] == '\n' || buf[0] == '\r')
1973                         continue;
1974
1975                 /*
1976                  *  Comment characters should NOT be appearing anywhere but
1977                  *  as start of a comment;
1978                  */
1979                 p = strchr(buf, '#');
1980                 if (p) *p = '\0';
1981
1982                 argc = str2argv(buf, argv, MAX_ARGV);
1983                 if (argc == 0) continue;
1984
1985                 if (argc == 1) {
1986                         fr_strerror_printf( "dict_init: %s[%d] invalid entry",
1987                                     fn, line);
1988                         fclose(fp);
1989                         return -1;
1990                 }
1991
1992                 /*
1993                  *      Process VALUE lines.
1994                  */
1995                 if (strcasecmp(argv[0], "VALUE") == 0) {
1996                         if (process_value(fn, line,
1997                                           argv + 1, argc - 1) == -1) {
1998                                 fclose(fp);
1999                                 return -1;
2000                         }
2001                         continue;
2002                 }
2003
2004                 /*
2005                  *      Perhaps this is an attribute.
2006                  */
2007                 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
2008                         if (process_attribute(fn, line, block_vendor,
2009                                               block_tlv[which_block_tlv],
2010                                               which_block_tlv,
2011                                               argv + 1, argc - 1) == -1) {
2012                                 fclose(fp);
2013                                 return -1;
2014                         }
2015                         continue;
2016                 }
2017
2018                 /*
2019                  *      See if we need to import another dictionary.
2020                  */
2021                 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
2022                         if (my_dict_init(dir, argv[1], fn, line) < 0) {
2023                                 fclose(fp);
2024                                 return -1;
2025                         }
2026                         continue;
2027                 } /* $INCLUDE */
2028
2029                 /*
2030                  *      Optionally include a dictionary
2031                  */
2032                 if (strcasecmp(argv[0], "$INCLUDE-") == 0) {
2033                         int rcode = my_dict_init(dir, argv[1], fn, line);
2034
2035                         if (rcode == -2) continue;
2036
2037                         if (rcode < 0) {
2038                                 fclose(fp);
2039                                 return -1;
2040                         }
2041                         continue;
2042                 } /* $INCLUDE- */
2043
2044                 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
2045                         if (process_value_alias(fn, line,
2046                                                 argv + 1, argc - 1) == -1) {
2047                                 fclose(fp);
2048                                 return -1;
2049                         }
2050                         continue;
2051                 }
2052
2053                 /*
2054                  *      Process VENDOR lines.
2055                  */
2056                 if (strcasecmp(argv[0], "VENDOR") == 0) {
2057                         if (process_vendor(fn, line,
2058                                            argv + 1, argc - 1) == -1) {
2059                                 fclose(fp);
2060                                 return -1;
2061                         }
2062                         continue;
2063                 }
2064
2065                 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
2066                         if (argc != 2) {
2067                                 fr_strerror_printf(
2068                                 "dict_init: %s[%d] invalid BEGIN-TLV entry",
2069                                         fn, line);
2070                                 fclose(fp);
2071                                 return -1;
2072                         }
2073
2074                         da = dict_attrbyname(argv[1]);
2075                         if (!da) {
2076                                 fr_strerror_printf(
2077                                         "dict_init: %s[%d]: unknown attribute %s",
2078                                         fn, line, argv[1]);
2079                                 fclose(fp);
2080                                 return -1;
2081                         }
2082
2083                         if (da->type != PW_TYPE_TLV) {
2084                                 fr_strerror_printf(
2085                                         "dict_init: %s[%d]: attribute %s is not of type tlv",
2086                                         fn, line, argv[1]);
2087                                 fclose(fp);
2088                                 return -1;
2089                         }
2090
2091                         if (which_block_tlv >= MAX_TLV_NEST) {
2092                                 fr_strerror_printf(
2093                                         "dict_init: %s[%d]: TLVs are nested too deep",
2094                                         fn, line);
2095                                 fclose(fp);
2096                                 return -1;
2097                         }
2098
2099
2100                         block_tlv[++which_block_tlv] = da;
2101                         continue;
2102                 } /* BEGIN-TLV */
2103
2104                 if (strcasecmp(argv[0], "END-TLV") == 0) {
2105                         if (argc != 2) {
2106                                 fr_strerror_printf(
2107                                 "dict_init: %s[%d] invalid END-TLV entry",
2108                                         fn, line);
2109                                 fclose(fp);
2110                                 return -1;
2111                         }
2112
2113                         da = dict_attrbyname(argv[1]);
2114                         if (!da) {
2115                                 fr_strerror_printf(
2116                                         "dict_init: %s[%d]: unknown attribute %s",
2117                                         fn, line, argv[1]);
2118                                 fclose(fp);
2119                                 return -1;
2120                         }
2121
2122                         if (da != block_tlv[which_block_tlv]) {
2123                                 fr_strerror_printf(
2124                                         "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
2125                                         fn, line, argv[1]);
2126                                 fclose(fp);
2127                                 return -1;
2128                         }
2129                         block_tlv[which_block_tlv--] = NULL;
2130                         continue;
2131                 } /* END-VENDOR */
2132
2133                 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
2134                         if (argc < 2) {
2135                                 fr_strerror_printf(
2136                                 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
2137                                         fn, line);
2138                                 fclose(fp);
2139                                 return -1;
2140                         }
2141
2142                         vendor = dict_vendorbyname(argv[1]);
2143                         if (!vendor) {
2144                                 fr_strerror_printf(
2145                                         "dict_init: %s[%d]: unknown vendor %s",
2146                                         fn, line, argv[1]);
2147                                 fclose(fp);
2148                                 return -1;
2149                         }
2150
2151                         block_vendor = vendor;
2152
2153                         /*
2154                          *      Check for extended attr VSAs
2155                          *
2156                          *      BEGIN-VENDOR foo format=Foo-Encapsulation-Attr
2157                          */
2158                         if (argc > 2) {
2159                                 if (strncmp(argv[2], "format=", 7) != 0) {
2160                                         fr_strerror_printf(
2161                                                 "dict_init: %s[%d]: Invalid format %s",
2162                                                 fn, line, argv[2]);
2163                                         fclose(fp);
2164                                         return -1;
2165                                 }
2166                                 
2167                                 p = argv[2] + 7;
2168                                 da = dict_attrbyname(p);
2169                                 if (!da) {
2170                                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR: unknown attribute \"%s\"",
2171                                                            fn, line, p);
2172                                         fclose(fp);
2173                                         return -1;
2174                                 }
2175
2176                                 if (!da->flags.evs) {
2177                                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR.  Attribute \"%s\" is not of \"evs\" data type",
2178                                                            fn, line, p);
2179                                         fclose(fp);
2180                                         return -1;
2181                                 }
2182                                 
2183                                 /*
2184                                  *      Pack the encapsulating
2185                                  *      attribute into the upper 8
2186                                  *      bits of the vendor ID
2187                                  */
2188                                 block_vendor |= (da->attr & fr_attr_mask[0]) * FR_MAX_VENDOR;
2189                         }
2190
2191                         continue;
2192                 } /* BEGIN-VENDOR */
2193
2194                 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
2195                         if (argc != 2) {
2196                                 fr_strerror_printf(
2197                                 "dict_init: %s[%d] invalid END-VENDOR entry",
2198                                         fn, line);
2199                                 fclose(fp);
2200                                 return -1;
2201                         }
2202
2203                         vendor = dict_vendorbyname(argv[1]);
2204                         if (!vendor) {
2205                                 fr_strerror_printf(
2206                                         "dict_init: %s[%d]: unknown vendor %s",
2207                                         fn, line, argv[1]);
2208                                 fclose(fp);
2209                                 return -1;
2210                         }
2211
2212                         if (vendor != (block_vendor & (FR_MAX_VENDOR - 1))) {
2213                                 fr_strerror_printf(
2214                                         "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
2215                                         fn, line, argv[1]);
2216                                 fclose(fp);
2217                                 return -1;
2218                         }
2219                         block_vendor = 0;
2220                         continue;
2221                 } /* END-VENDOR */
2222
2223                 /*
2224                  *      Any other string: We don't recognize it.
2225                  */
2226                 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
2227                            fn, line, argv[0]);
2228                 fclose(fp);
2229                 return -1;
2230         }
2231         fclose(fp);
2232         return 0;
2233 }
2234
2235
2236 /*
2237  *      Empty callback for hash table initialization.
2238  */
2239 static int null_callback(void *ctx, void *data)
2240 {
2241         ctx = ctx;              /* -Wunused */
2242         data = data;            /* -Wunused */
2243
2244         return 0;
2245 }
2246
2247
2248 /*
2249  *      Initialize the directory, then fix the attr member of
2250  *      all attributes.
2251  */
2252 int dict_init(const char *dir, const char *fn)
2253 {
2254         /*
2255          *      Check if we need to change anything.  If not, don't do
2256          *      anything.
2257          */
2258         if (dict_stat_check(dir, fn)) {
2259                 return 0;
2260         }
2261
2262         /*
2263          *      Free the dictionaries, and the stat cache.
2264          */
2265         dict_free();
2266         stat_root_dir = strdup(dir);
2267         stat_root_file = strdup(fn);
2268
2269         /*
2270          *      Create the table of vendor by name.   There MAY NOT
2271          *      be multiple vendors of the same name.
2272          *
2273          *      Each vendor is malloc'd, so the free function is free.
2274          */
2275         vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
2276                                                 dict_vendor_name_cmp,
2277                                                 fr_pool_free);
2278         if (!vendors_byname) {
2279                 return -1;
2280         }
2281
2282         /*
2283          *      Create the table of vendors by value.  There MAY
2284          *      be vendors of the same value.  If there are, we
2285          *      pick the latest one.
2286          */
2287         vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
2288                                                  dict_vendor_value_cmp,
2289                                                  fr_pool_free);
2290         if (!vendors_byvalue) {
2291                 return -1;
2292         }
2293
2294         /*
2295          *      Create the table of attributes by name.   There MAY NOT
2296          *      be multiple attributes of the same name.
2297          *
2298          *      Each attribute is malloc'd, so the free function is free.
2299          */
2300         attributes_byname = fr_hash_table_create(dict_attr_name_hash,
2301                                                    dict_attr_name_cmp,
2302                                                    fr_pool_free);
2303         if (!attributes_byname) {
2304                 return -1;
2305         }
2306
2307         /*
2308          *      Create the table of attributes by value.  There MAY
2309          *      be attributes of the same value.  If there are, we
2310          *      pick the latest one.
2311          */
2312         attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
2313                                                     dict_attr_value_cmp,
2314                                                     fr_pool_free);
2315         if (!attributes_byvalue) {
2316                 return -1;
2317         }
2318
2319         /*
2320          *      Horrible hacks for combo-IP.
2321          */
2322         attributes_combo = fr_hash_table_create(dict_attr_combo_hash,
2323                                                 dict_attr_combo_cmp,
2324                                                 fr_pool_free);
2325         if (!attributes_combo) {
2326                 return -1;
2327         }
2328
2329         values_byname = fr_hash_table_create(dict_value_name_hash,
2330                                                dict_value_name_cmp,
2331                                                fr_pool_free);
2332         if (!values_byname) {
2333                 return -1;
2334         }
2335
2336         values_byvalue = fr_hash_table_create(dict_value_value_hash,
2337                                                 dict_value_value_cmp,
2338                                                 fr_pool_free);
2339         if (!values_byvalue) {
2340                 return -1;
2341         }
2342
2343         value_fixup = NULL;     /* just to be safe. */
2344
2345         if (my_dict_init(dir, fn, NULL, 0) < 0)
2346                 return -1;
2347
2348         if (value_fixup) {
2349                 DICT_ATTR *a;
2350                 value_fixup_t *this, *next;
2351
2352                 for (this = value_fixup; this != NULL; this = next) {
2353                         next = this->next;
2354
2355                         a = dict_attrbyname(this->attrstr);
2356                         if (!a) {
2357                                 fr_strerror_printf(
2358                                         "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
2359                                         this->attrstr, this->dval->name);
2360                                 return -1; /* leak, but they should die... */
2361                         }
2362
2363                         this->dval->attr = a->attr;
2364
2365                         /*
2366                          *      Add the value into the dictionary.
2367                          */
2368                         if (!fr_hash_table_replace(values_byname,
2369                                                      this->dval)) {
2370                                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
2371                                 return -1;
2372                         }
2373
2374                         /*
2375                          *      Allow them to use the old name, but
2376                          *      prefer the new name when printing
2377                          *      values.
2378                          */
2379                         if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
2380                                 fr_hash_table_replace(values_byvalue,
2381                                                         this->dval);
2382                         }
2383                         free(this);
2384
2385                         /*
2386                          *      Just so we don't lose track of things.
2387                          */
2388                         value_fixup = next;
2389                 }
2390         }
2391
2392         /*
2393          *      Walk over all of the hash tables to ensure they're
2394          *      initialized.  We do this because the threads may perform
2395          *      lookups, and we don't want multi-threaded re-ordering
2396          *      of the table entries.  That would be bad.
2397          */
2398         fr_hash_table_walk(vendors_byname, null_callback, NULL);
2399         fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
2400
2401         fr_hash_table_walk(attributes_byname, null_callback, NULL);
2402         fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
2403
2404         fr_hash_table_walk(values_byvalue, null_callback, NULL);
2405         fr_hash_table_walk(values_byname, null_callback, NULL);
2406
2407         return 0;
2408 }
2409
2410 static size_t print_attr_oid(char *buffer, size_t size, unsigned int attr,
2411                              int dv_type)
2412 {
2413         int nest;
2414         size_t outlen;
2415         size_t len;
2416
2417         switch (dv_type) {
2418         case 4:
2419                 return snprintf(buffer, size, "%u", attr);
2420
2421         case 2:
2422                 return snprintf(buffer, size, "%u", attr & 0xffff);
2423
2424         default:
2425         case 1:
2426                 len = snprintf(buffer, size, "%u", attr & 0xff);
2427                 break;
2428         }
2429
2430         if ((attr >> 8) == 0) return len;
2431
2432         outlen = len;
2433         buffer += len;
2434         size -= len;
2435
2436         for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
2437                 if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
2438
2439                 len = snprintf(buffer, size, ".%u",
2440                                (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
2441
2442                 outlen = len;
2443                 buffer += len;
2444                 size -= len;
2445         }
2446
2447         return outlen;
2448 }
2449
2450 /** Free dynamically allocated (unknown attributes)
2451  * 
2452  * If the da was dynamically allocated it will be freed, else the function
2453  * will return without doing anything.
2454  *
2455  * @param da to free.
2456  */
2457 void dict_attr_free(const DICT_ATTR *da)
2458 {
2459         DICT_ATTR *tmp;
2460         
2461         /* Don't free real DAs */
2462         if (!da->flags.is_unknown) {
2463                 return;
2464         }
2465         
2466         memcpy(&tmp, &da, sizeof(tmp));
2467         free(tmp);      
2468 }
2469
2470 /** Copies a dictionary attr
2471  *
2472  * If the attr is dynamically allocated (unknown attribute), then it will be
2473  * copied to a new attr.
2474  *
2475  * If the attr is known, a pointer to the da will be returned.
2476  *
2477  * @param da to copy.
2478  * @param return a copy of the da.
2479  */
2480 const DICT_ATTR *dict_attr_copy(const DICT_ATTR *da)
2481 {
2482         DICT_ATTR *copy;
2483         
2484         if (!da->flags.is_unknown) {
2485                 return da;
2486         }
2487         
2488         copy = malloc(DICT_ATTR_SIZE);
2489         if (!copy) {
2490                 fr_strerror_printf("Out of memory");
2491                 return NULL;
2492         }
2493         
2494         memcpy(copy, da, DICT_ATTR_SIZE);
2495         
2496         return copy;
2497 }
2498
2499
2500 /** Allocs an dictionary attr for unknown attributes
2501  *
2502  * Allocates a dict attr for an unknown attribute/vendor/type
2503  * without adding it to dictionary pools/hashes.
2504  *
2505  * @note Must be freed with dict_attr_free if not used as part of a valuepair.
2506  *
2507  * @param[in] attr number.
2508  * @param[in] vendor number.
2509  * @return new dictionary attribute.
2510  */
2511 const DICT_ATTR *dict_attrunknown(unsigned int attr, unsigned int vendor)
2512 {
2513         DICT_ATTR *da;
2514         char *p;
2515         int dv_type = 1;
2516         size_t len = 0;
2517         size_t bufsize = DICT_ATTR_MAX_NAME_LEN;
2518         
2519         da = malloc(DICT_ATTR_SIZE);
2520         if (!da) {
2521                 fr_strerror_printf("Out of memory");
2522                 return NULL;
2523         }
2524         memset(da, 0, DICT_ATTR_SIZE);
2525         
2526         da->attr = attr;
2527         da->vendor = vendor;
2528         da->type = PW_TYPE_OCTETS;
2529         da->flags.is_unknown = TRUE;
2530         
2531         p = da->name;
2532         
2533         len = snprintf(p, bufsize, "Attr-");
2534         p += len;
2535         bufsize -= len;
2536
2537         if (vendor > FR_MAX_VENDOR) {
2538                 len = snprintf(p, bufsize, "%u.", vendor / FR_MAX_VENDOR);
2539                 p += len;
2540                 bufsize -= len;
2541                 vendor &= (FR_MAX_VENDOR) - 1;
2542         }
2543
2544         if (vendor) {
2545                 DICT_VENDOR *dv;
2546
2547                 /*
2548                  *      dv_type is the length of the vendor's type field
2549                  *      RFC 2865 never defined a mandatory length, so
2550                  *      different vendors have different length type fields.
2551                  */
2552                 dv = dict_vendorbyvalue(vendor);
2553                 if (dv) {
2554                         dv_type = dv->type;
2555                 }
2556                 len = snprintf(p, bufsize, "26.%u.", vendor);
2557                 
2558                 p += len;
2559                 bufsize -= len;
2560         }
2561
2562         p += print_attr_oid(p, bufsize , attr, dv_type);
2563         
2564         return da;
2565 }
2566
2567 /** Create a DICT_ATTR from an ASCII attribute and value
2568  *
2569  * Where the attribute name is in the form:
2570  *  - Attr-%d
2571  *  - Attr-%d.%d.%d...
2572  *  - Vendor-%d-Attr-%d
2573  *  - VendorName-Attr-%d
2574  *
2575  * @todo should check attr/vendor against dictionary and return the real da.
2576  *
2577  * @param attribute name to parse.
2578  * @return new da or NULL on error.
2579  */
2580 const DICT_ATTR *dict_attrunknownbyname(const char *attribute)
2581 {
2582         unsigned int    attr, vendor = 0;
2583         unsigned int    dv_type = 1;    /* The type of vendor field */
2584
2585         const char      *p = attribute;
2586         char            *q;
2587         
2588         DICT_VENDOR     *dv;
2589         DICT_ATTR       *da;
2590
2591         /*
2592          *      Pull off vendor prefix first.
2593          */
2594         if (strncasecmp(p, "Attr-", 5) != 0) {
2595                 if (strncasecmp(p, "Vendor-", 7) == 0) {
2596                         vendor = (int) strtol(p + 7, &q, 10);
2597                         if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
2598                                 fr_strerror_printf("Invalid vendor value in "
2599                                                    "attribute name \"%s\"", 
2600                                                    attribute);
2601                                 return NULL;
2602                         }
2603
2604                         p = q;
2605
2606                 /* must be vendor name */
2607                 } else {
2608                         char buffer[256];
2609
2610                         q = strchr(p, '-');
2611
2612                         if (!q) {
2613                                 fr_strerror_printf("Invalid vendor name in "
2614                                                    "attribute name \"%s\"",
2615                                                    attribute);
2616                                 return NULL;
2617                         }
2618
2619                         if ((size_t) (q - p) >= sizeof(buffer)) {
2620                                 fr_strerror_printf("Vendor name too long "
2621                                                    "in attribute name \"%s\"",
2622                                                    attribute);
2623                                 return NULL;
2624                         }
2625
2626                         memcpy(buffer, p, (q - p));
2627                         buffer[q - p] = '\0';
2628
2629                         vendor = dict_vendorbyname(buffer);
2630                         if (!vendor) {
2631                                 fr_strerror_printf("Unknown vendor name in "
2632                                                    "attribute name \"%s\"",
2633                                                    attribute);
2634                                 return NULL;
2635                         }
2636
2637                         p = q;
2638                 }
2639
2640                 if (*p != '-') {
2641                         fr_strerror_printf("Invalid text following vendor "
2642                                            "definition in attribute name "
2643                                            "\"%s\"", attribute);
2644                         return NULL;
2645                 }
2646                 p++;
2647         }
2648         
2649         /*
2650          *      Attr-%d
2651          */
2652         if (strncasecmp(p, "Attr-", 5) != 0) {
2653                 fr_strerror_printf("Invalid format in attribute name \"%s\"",
2654                                    attribute);
2655                 return NULL;
2656         }
2657
2658         attr = strtol(p + 5, &q, 10);
2659
2660         /*
2661          *      Invalid attribute.
2662          */
2663         if (attr == 0) {
2664                 fr_strerror_printf("Invalid value in attribute name \"%s\"",
2665                                    attribute);
2666                 return NULL;
2667         }
2668
2669         p = q;
2670         
2671         /*
2672          *      Vendor-%d-Attr-%d
2673          *      VendorName-Attr-%d
2674          *      Attr-%d
2675          *      Attr-%d.
2676          *
2677          *      Anything else is invalid.
2678          */
2679         if (((vendor != 0) && (*p != '\0')) ||
2680             ((vendor == 0) && *p && (*p != '.'))) {
2681         invalid:
2682                 fr_strerror_printf("Invalid OID");
2683                 return NULL;
2684         }
2685         
2686         /*
2687          *      Look for OIDs.  Require the "Attr-26.Vendor-Id.type"
2688          *      format, and disallow "Vendor-%d-Attr-%d" and
2689          *      "VendorName-Attr-%d"
2690          *
2691          *      This section parses the Vendor-Id portion of
2692          *      Attr-%d.%d.  where the first number is 26, *or* an
2693          *      extended attribute of the "evs" data type.
2694          */
2695         if (*p == '.') {
2696                 da = dict_attrbyvalue(attr, 0);
2697                 if (!da) {
2698                         fr_strerror_printf("Cannot parse attributes without "
2699                                            "dictionaries");
2700                         return NULL;
2701                 }               
2702                 
2703                 if ((attr != PW_VENDOR_SPECIFIC) &&
2704                     !(da->flags.extended || da->flags.long_extended)) {
2705                         fr_strerror_printf("Standard attributes cannot use "
2706                                            "OIDs");
2707                         return NULL;
2708                 }
2709
2710                 if ((attr == PW_VENDOR_SPECIFIC) || da->flags.evs) {
2711                         vendor = strtol(p + 1, &q, 10);
2712                         if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
2713                                 fr_strerror_printf("Invalid vendor");
2714                                 return NULL;
2715                         }
2716
2717                         if (*q != '.') goto invalid;
2718
2719                         p = q;
2720
2721                         if (da->flags.evs) {
2722                                 vendor |= attr * FR_MAX_VENDOR;
2723                         }
2724                         attr = 0;
2725                 } /* else the second number is a TLV number */
2726         }
2727
2728         /*
2729          *      Get the expected maximum size of the attribute.
2730          */
2731         if (vendor) {
2732                 dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
2733                 if (dv) {
2734                         dv_type = dv->type;
2735                         if (dv_type > 3) dv_type = 3; /* hack */
2736                 }
2737         }
2738         
2739         /*
2740          *      Parse the next number.  It could be a Vendor-Type
2741          *      of 1..2^24, or it could be a TLV.
2742          */
2743         if (*p == '.') {
2744                 attr = strtol(p + 1, &q, 10);
2745                 if (attr == 0) {
2746                         fr_strerror_printf("Invalid attribute number");
2747                         return NULL;
2748                 }
2749
2750                 if (*q) {
2751                         if (*q != '.') {
2752                                 goto invalid;
2753                         }
2754                         
2755                         if (dv_type != 1) {
2756                                 goto invalid;
2757                         }
2758                 }
2759
2760                 p = q;
2761         }
2762
2763         /*
2764          *      Enforce a maximum value on the attribute number.
2765          */
2766         if (attr >= (unsigned) (1 << (dv_type << 3))) goto invalid;
2767
2768         if (*p == '.') {
2769                 if (dict_str2oid(p + 1, &attr, &vendor, 1) < 0) {
2770                         return NULL;
2771                 }
2772         }
2773
2774         return dict_attrunknown(attr, vendor);
2775 }
2776
2777 /*
2778  *      Get an attribute by its numerical value.
2779  */
2780 DICT_ATTR *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
2781 {
2782         DICT_ATTR dattr;
2783
2784         if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
2785
2786         dattr.attr = attr;
2787         dattr.vendor = vendor;
2788
2789         return fr_hash_table_finddata(attributes_byvalue, &dattr);
2790 }
2791
2792
2793 /**
2794  * @brief Get an attribute by its numerical value. and data type
2795  *
2796  *      Used only for COMBO_IP
2797  *
2798  * @return The attribute, or NULL if not found
2799  */
2800 DICT_ATTR *dict_attrbytype(unsigned int attr, unsigned int vendor,
2801                            PW_TYPE type)
2802 {
2803         DICT_ATTR dattr;
2804
2805         dattr.attr = attr;
2806         dattr.vendor = vendor;
2807         dattr.type = type;
2808
2809         return fr_hash_table_finddata(attributes_combo, &dattr);
2810 }
2811
2812
2813 /*
2814  *      Get an attribute by it's numerical value, and the parent
2815  */
2816 DICT_ATTR *dict_attrbyparent(const DICT_ATTR *parent, unsigned int attr)
2817 {
2818         DICT_ATTR dattr;
2819
2820         if (!parent) return NULL;
2821
2822         /*
2823          *      Only TLVs can have children
2824          */
2825         if (!parent->flags.has_tlv) return NULL;
2826
2827         /*
2828          *      Bootstrap by starting off with the parents values.
2829          */
2830         dattr.attr = parent->attr;
2831         dattr.vendor = parent->vendor;
2832
2833         /*
2834          *      Do various butchery to insert the "attr" value.
2835          *
2836          *      00VID   000000AA        normal VSA for vendor VID
2837          *      00VID   DDCCBBAA        normal VSAs with TLVs
2838          *      EE000   000000AA        extended attr (241.1)
2839          *      EE000   DDCCBBAA        extended attr with TLVs
2840          *      EEVID   000000AA        EVS with vendor VID, attr AAA
2841          *      EEVID   DDCCBBAA        EVS with TLVs
2842          */
2843         if (!dattr.vendor) {
2844                 dattr.vendor = parent->attr * FR_MAX_VENDOR;
2845                 dattr.attr = attr;
2846
2847         } else {
2848                 int i;
2849
2850                 /*
2851                  *      Trying to nest too deep.  It's an error
2852                  */
2853                 if (parent->attr & (fr_attr_mask[MAX_TLV_NEST] << fr_attr_shift[MAX_TLV_NEST])) {
2854                         return NULL;
2855                 }
2856
2857                 for (i = MAX_TLV_NEST - 1; i >= 0; i--) {
2858                         if ((parent->attr & (fr_attr_mask[i] << fr_attr_shift[i]))) {
2859                                 dattr.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
2860                                 goto find;
2861                         }
2862                 }
2863
2864                 return NULL;
2865         }
2866
2867 find:
2868         return fr_hash_table_finddata(attributes_byvalue, &dattr);
2869 }
2870
2871
2872 /*
2873  *      Get an attribute by its name.
2874  */
2875 DICT_ATTR *dict_attrbyname(const char *name)
2876 {
2877         DICT_ATTR *da;
2878         uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
2879
2880         if (!name) return NULL;
2881
2882         da = (DICT_ATTR *) buffer;
2883         strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
2884
2885         return fr_hash_table_finddata(attributes_byname, da);
2886 }
2887
2888 /*
2889  *      Associate a value with an attribute and return it.
2890  */
2891 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
2892 {
2893         DICT_VALUE dval, *dv;
2894
2895         /*
2896          *      First, look up aliases.
2897          */
2898         dval.attr = attr;
2899         dval.vendor = vendor;
2900         dval.name[0] = '\0';
2901
2902         /*
2903          *      Look up the attribute alias target, and use
2904          *      the correct attribute number if found.
2905          */
2906         dv = fr_hash_table_finddata(values_byname, &dval);
2907         if (dv) dval.attr = dv->value;
2908
2909         dval.value = value;
2910
2911         return fr_hash_table_finddata(values_byvalue, &dval);
2912 }
2913
2914 /*
2915  *      Associate a value with an attribute and return it.
2916  */
2917 const char *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value)
2918 {
2919         DICT_VALUE *dv;
2920
2921         dv = dict_valbyattr(attr, vendor, value);
2922         if (!dv) return "";
2923
2924         return dv->name;
2925 }
2926
2927 /*
2928  *      Get a value by its name, keyed off of an attribute.
2929  */
2930 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, const char *name)
2931 {
2932         DICT_VALUE *my_dv, *dv;
2933         uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
2934
2935         if (!name) return NULL;
2936
2937         my_dv = (DICT_VALUE *) buffer;
2938         my_dv->attr = attr;
2939         my_dv->vendor = vendor;
2940         my_dv->name[0] = '\0';
2941
2942         /*
2943          *      Look up the attribute alias target, and use
2944          *      the correct attribute number if found.
2945          */
2946         dv = fr_hash_table_finddata(values_byname, my_dv);
2947         if (dv) my_dv->attr = dv->value;
2948
2949         strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
2950
2951         return fr_hash_table_finddata(values_byname, my_dv);
2952 }
2953
2954 /*
2955  *      Get the vendor PEC based on the vendor name
2956  *
2957  *      This is efficient only for small numbers of vendors.
2958  */
2959 int dict_vendorbyname(const char *name)
2960 {
2961         DICT_VENDOR *dv;
2962         uint32_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + 3)/4];
2963
2964         if (!name) return 0;
2965
2966         dv = (DICT_VENDOR *) buffer;
2967         strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
2968
2969         dv = fr_hash_table_finddata(vendors_byname, dv);
2970         if (!dv) return 0;
2971
2972         return dv->vendorpec;
2973 }
2974
2975 /*
2976  *      Return the vendor struct based on the PEC.
2977  */
2978 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
2979 {
2980         DICT_VENDOR dv;
2981
2982         dv.vendorpec = vendorpec;
2983
2984         return fr_hash_table_finddata(vendors_byvalue, &dv);
2985 }