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