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