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