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