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