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