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