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