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