Add support for extended attributes: draft-dekok-radext-radius-extensions
[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
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/libradius.h>
27
28 #include        <ctype.h>
29
30 #ifdef HAVE_MALLOC_H
31 #include        <malloc.h>
32 #endif
33
34 #ifdef HAVE_SYS_STAT_H
35 #include        <sys/stat.h>
36 #endif
37
38 #define DICT_VALUE_MAX_NAME_LEN (128)
39 #define DICT_VENDOR_MAX_NAME_LEN (128)
40 #define DICT_ATTR_MAX_NAME_LEN (128)
41
42 static fr_hash_table_t *vendors_byname = NULL;
43 static fr_hash_table_t *vendors_byvalue = NULL;
44
45 static fr_hash_table_t *attributes_byname = NULL;
46 static fr_hash_table_t *attributes_byvalue = 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         char               *name;
60         time_t             mtime;
61 } dict_stat_t;
62
63 static char *stat_root_dir = NULL;
64 static char *stat_root_file = NULL;
65
66 static dict_stat_t *stat_head = NULL;
67 static dict_stat_t *stat_tail = NULL;
68
69 typedef struct value_fixup_t {
70         char            attrstr[DICT_ATTR_MAX_NAME_LEN];
71         DICT_VALUE      *dval;
72         struct value_fixup_t *next;
73 } value_fixup_t;
74
75
76 /*
77  *      So VALUEs in the dictionary can have forward references.
78  */
79 static value_fixup_t *value_fixup = NULL;
80
81 static const FR_NAME_NUMBER type_table[] = {
82         { "integer",    PW_TYPE_INTEGER },
83         { "string",     PW_TYPE_STRING },
84         { "ipaddr",     PW_TYPE_IPADDR },
85         { "date",       PW_TYPE_DATE },
86         { "abinary",    PW_TYPE_ABINARY },
87         { "octets",     PW_TYPE_OCTETS },
88         { "ifid",       PW_TYPE_IFID },
89         { "ipv6addr",   PW_TYPE_IPV6ADDR },
90         { "ipv6prefix", PW_TYPE_IPV6PREFIX },
91         { "byte",       PW_TYPE_BYTE },
92         { "short",      PW_TYPE_SHORT },
93         { "ether",      PW_TYPE_ETHERNET },
94         { "combo-ip",   PW_TYPE_COMBO_IP },
95         { "tlv",        PW_TYPE_TLV },
96         { "signed",     PW_TYPE_SIGNED },
97         { NULL, 0 }
98 };
99
100
101 /*
102  *      WiMAX craziness.
103  */
104 #define MAX_TLV_NEST (4)
105 /*
106  *      Bit packing:
107  *      8 bits of base VSA
108  *      8 bits for nested TLV 1
109  *      8 bits for nested TLV 2
110  *      5 bits for nested TLV 3
111  *      3 bits for nested TLV 4
112  */
113 const int fr_wimax_max_tlv = MAX_TLV_NEST;
114 const int fr_wimax_shift[MAX_TLV_NEST + 1] = {
115   0, 8, 16, 24, 29
116 };
117
118 const int fr_wimax_mask[MAX_TLV_NEST + 1] = {
119   0, 0xff, 0xff, 0x1f, 0x07
120 };
121
122
123 /*
124  *      Create the hash of the name.
125  *
126  *      We copy the hash function here because it's substantially faster.
127  */
128 #define FNV_MAGIC_INIT (0x811c9dc5)
129 #define FNV_MAGIC_PRIME (0x01000193)
130
131 static uint32_t dict_hashname(const char *name)
132 {
133         uint32_t hash = FNV_MAGIC_INIT;
134         const char *p;
135
136         for (p = name; *p != '\0'; p++) {
137                 int c = *(const unsigned char *) p;
138                 if (isalpha(c)) c = tolower(c);
139
140                 hash *= FNV_MAGIC_PRIME;
141                 hash ^= (uint32_t ) (c & 0xff);
142         }
143
144         return hash;
145 }
146
147
148 /*
149  *      Hash callback functions.
150  */
151 static uint32_t dict_attr_name_hash(const void *data)
152 {
153         return dict_hashname(((const DICT_ATTR *)data)->name);
154 }
155
156 static int dict_attr_name_cmp(const void *one, const void *two)
157 {
158         const DICT_ATTR *a = one;
159         const DICT_ATTR *b = two;
160
161         return strcasecmp(a->name, b->name);
162 }
163
164 static uint32_t dict_attr_value_hash(const void *data)
165 {
166         uint32_t hash;
167         const DICT_ATTR *attr = data;
168
169         hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
170         return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
171 }
172
173 static int dict_attr_value_cmp(const void *one, const void *two)
174 {
175         const DICT_ATTR *a = one;
176         const DICT_ATTR *b = two;
177
178         if (a->vendor < b->vendor) return -1;
179         if (a->vendor > b->vendor) return +1;
180
181         return a->attr - b->attr;
182 }
183
184 static uint32_t dict_vendor_name_hash(const void *data)
185 {
186         return dict_hashname(((const DICT_VENDOR *)data)->name);
187 }
188
189 static int dict_vendor_name_cmp(const void *one, const void *two)
190 {
191         const DICT_VENDOR *a = one;
192         const DICT_VENDOR *b = two;
193
194         return strcasecmp(a->name, b->name);
195 }
196
197 static uint32_t dict_vendor_value_hash(const void *data)
198 {
199         return fr_hash(&(((const DICT_VENDOR *)data)->vendorpec),
200                          sizeof(((const DICT_VENDOR *)data)->vendorpec));
201 }
202
203 static int dict_vendor_value_cmp(const void *one, const void *two)
204 {
205         const DICT_VENDOR *a = one;
206         const DICT_VENDOR *b = two;
207
208         return a->vendorpec - b->vendorpec;
209 }
210
211 static uint32_t dict_value_name_hash(const void *data)
212 {
213         uint32_t hash;
214         const DICT_VALUE *dval = data;
215
216         hash = dict_hashname(dval->name);
217         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
218         return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
219 }
220
221 static int dict_value_name_cmp(const void *one, const void *two)
222 {
223         int rcode;
224         const DICT_VALUE *a = one;
225         const DICT_VALUE *b = two;
226
227         rcode = a->attr - b->attr;
228         if (rcode != 0) return rcode;
229
230         rcode = a->vendor - b->vendor;
231         if (rcode != 0) return rcode;
232
233         return strcasecmp(a->name, b->name);
234 }
235
236 static uint32_t dict_value_value_hash(const void *data)
237 {
238         uint32_t hash;
239         const DICT_VALUE *dval = data;
240
241         hash = fr_hash(&dval->attr, sizeof(dval->attr));
242         hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
243         return fr_hash_update(&dval->value, sizeof(dval->value), hash);
244 }
245
246 static int dict_value_value_cmp(const void *one, const void *two)
247 {
248         int rcode;
249         const DICT_VALUE *a = one;
250         const DICT_VALUE *b = two;
251
252         if (a->vendor < b->vendor) return -1;
253         if (a->vendor > b->vendor) return +1;
254
255         rcode = a->attr - b->attr;
256         if (rcode != 0) return rcode;
257
258         return a->value - b->value;
259 }
260
261
262 /*
263  *      Free the list of stat buffers
264  */
265 static void dict_stat_free(void)
266 {
267         dict_stat_t *this, *next;
268
269         free(stat_root_dir);
270         stat_root_dir = NULL;
271         free(stat_root_file);
272         stat_root_file = NULL;
273
274         if (!stat_head) {
275                 stat_tail = NULL;
276                 return;
277         }
278
279         for (this = stat_head; this != NULL; this = next) {
280                 next = this->next;
281                 free(this->name);
282                 free(this);
283         }
284
285         stat_head = stat_tail = NULL;
286 }
287
288
289 /*
290  *      Add an entry to the list of stat buffers.
291  */
292 static void dict_stat_add(const char *name, const struct stat *stat_buf)
293 {
294         dict_stat_t *this;
295
296         this = malloc(sizeof(*this));
297         if (!this) return;
298         memset(this, 0, sizeof(*this));
299
300         this->name = strdup(name);
301         this->mtime = stat_buf->st_mtime;
302
303         if (!stat_head) {
304                 stat_head = stat_tail = this;
305         } else {
306                 stat_tail->next = this;
307                 stat_tail = this;
308         }
309 }
310
311
312 /*
313  *      See if any dictionaries have changed.  If not, don't
314  *      do anything.
315  */
316 static int dict_stat_check(const char *root_dir, const char *root_file)
317 {
318         struct stat buf;
319         dict_stat_t *this;
320
321         if (!stat_root_dir) return 0;
322         if (!stat_root_file) return 0;
323
324         if (strcmp(root_dir, stat_root_dir) != 0) return 0;
325         if (strcmp(root_file, stat_root_file) != 0) return 0;
326
327         if (!stat_head) return 0; /* changed, reload */
328
329         for (this = stat_head; this != NULL; this = this->next) {
330                 if (stat(this->name, &buf) < 0) return 0;
331
332                 if (buf.st_mtime != this->mtime) return 0;
333         }
334
335         return 1;
336 }
337
338 typedef struct fr_pool_t {
339         void    *page_end;
340         void    *free_ptr;
341         struct fr_pool_t *page_free;
342         struct fr_pool_t *page_next;
343 } fr_pool_t;
344
345 #define FR_POOL_SIZE (32768)
346 #define FR_ALLOC_ALIGN (8)
347
348 static fr_pool_t *dict_pool = NULL;
349
350 static fr_pool_t *fr_pool_create(void)
351 {
352         fr_pool_t *fp = malloc(FR_POOL_SIZE);
353
354         if (!fp) return NULL;
355
356         memset(fp, 0, FR_POOL_SIZE);
357
358         fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
359         fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
360         fp->page_free = fp;
361         fp->page_next = NULL;
362         return fp;
363 }
364
365 static void fr_pool_delete(fr_pool_t **pfp)
366 {
367         fr_pool_t *fp, *next;
368
369         if (!pfp || !*pfp) return;
370
371         for (fp = *pfp; fp != NULL; fp = next) {
372                 next = fp->page_next;
373                 free(fp);
374         }
375 }
376
377
378 static void *fr_pool_alloc(size_t size)
379 {
380         void *ptr;
381
382         if (size == 0) return NULL;
383
384         if (size > 256) return NULL; /* shouldn't happen */
385
386         if (!dict_pool) {
387                 dict_pool = fr_pool_create();
388                 if (!dict_pool) return NULL;
389         }
390
391         if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
392                 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
393         }
394
395         if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
396                 dict_pool->page_free->page_next = fr_pool_create();
397                 if (!dict_pool->page_free->page_next) return NULL;
398                 dict_pool->page_free = dict_pool->page_free->page_next;
399         }
400
401         ptr = dict_pool->page_free->free_ptr;
402         dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
403
404         return ptr;
405 }
406
407
408 static void fr_pool_free(UNUSED void *ptr)
409 {
410         /*
411          *      Place-holder for later code.
412          */
413 }
414
415 /*
416  *      Free the dictionary_attributes and dictionary_values lists.
417  */
418 void dict_free(void)
419 {
420         /*
421          *      Free the tables
422          */
423         fr_hash_table_free(vendors_byname);
424         fr_hash_table_free(vendors_byvalue);
425         vendors_byname = NULL;
426         vendors_byvalue = NULL;
427
428         fr_hash_table_free(attributes_byname);
429         fr_hash_table_free(attributes_byvalue);
430         attributes_byname = NULL;
431         attributes_byvalue = NULL;
432
433         fr_hash_table_free(values_byname);
434         fr_hash_table_free(values_byvalue);
435         values_byname = NULL;
436         values_byvalue = NULL;
437
438         memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
439
440         fr_pool_delete(&dict_pool);
441
442         dict_stat_free();
443 }
444
445
446 /*
447  *      Add vendor to the list.
448  */
449 int dict_addvendor(const char *name, int value)
450 {
451         size_t length;
452         DICT_VENDOR *dv;
453
454         if (value > FR_MAX_VENDOR) {
455                 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
456                 return -1;
457         }
458
459         if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
460                 fr_strerror_printf("dict_addvendor: vendor name too long");
461                 return -1;
462         }
463
464         if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
465                 fr_strerror_printf("dict_addvendor: out of memory");
466                 return -1;
467         }
468
469         strcpy(dv->name, name);
470         dv->vendorpec  = value;
471         dv->type = dv->length = 1; /* defaults */
472
473         if (!fr_hash_table_insert(vendors_byname, dv)) {
474                 DICT_VENDOR *old_dv;
475
476                 old_dv = fr_hash_table_finddata(vendors_byname, dv);
477                 if (!old_dv) {
478                         fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
479                         return -1;
480                 }
481                 if (old_dv->vendorpec != dv->vendorpec) {
482                         fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
483                         return -1;
484                 }
485
486                 /*
487                  *      Already inserted.  Discard the duplicate entry.
488                  */
489                 fr_pool_free(dv);
490                 return 0;
491         }
492
493         /*
494          *      Insert the SAME pointer (not free'd when this table is
495          *      deleted), into another table.
496          *
497          *      We want this behaviour because we want OLD names for
498          *      the attributes to be read from the configuration
499          *      files, but when we're printing them, (and looking up
500          *      by value) we want to use the NEW name.
501          */
502         if (!fr_hash_table_replace(vendors_byvalue, dv)) {
503                 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
504                            name);
505                 return -1;
506         }
507
508         return 0;
509 }
510
511 /*
512  *      Add an attribute to the dictionary.
513  */
514 int dict_addattr(const char *name, int attr, int vendor, int type,
515                  ATTR_FLAGS flags)
516 {
517         size_t namelen;
518         static int      max_attr = 0;
519         DICT_ATTR       *da;
520
521         namelen = strlen(name);
522         if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
523                 fr_strerror_printf("dict_addattr: attribute name too long");
524                 return -1;
525         }
526
527         /*
528          *      If the attr is '-1', that means use a pre-existing
529          *      one (if it already exists).  If one does NOT already exist,
530          *      then create a new attribute, with a non-conflicting value,
531          *      and use that.
532          */
533         if (attr == -1) {
534                 if (dict_attrbyname(name)) {
535                         return 0; /* exists, don't add it again */
536                 }
537
538                 attr = ++max_attr;
539
540         } else if (vendor == 0) {
541                 /*
542                  *  Update 'max_attr'
543                  */
544                 if (attr > max_attr) {
545                         max_attr = attr;
546                 }
547         }
548
549         /*
550          *      Additional checks for extended attributes.
551          */
552         if (flags.extended || flags.extended_flags) {
553                 if (vendor != 0) {
554                         fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" attribute format.");
555                         return -1;
556                 }
557                 vendor = VENDORPEC_EXTENDED;
558
559                 if ((attr < 256) && (type != PW_TYPE_OCTETS)) {
560                         fr_strerror_printf("dict_addattr: The base \"extended\" attribute definition MUST be of type \"octets\".");
561                         return -1;
562                 }
563
564                 if (flags.has_tag || flags.array || (flags.encrypt != FLAG_ENCRYPT_NONE)) {
565                         fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set.");
566                         return -1;
567                 }
568         }
569
570         if (attr < 0) {
571                 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
572                 return -1;
573         }
574
575         if (vendor && (vendor != VENDORPEC_EXTENDED)) {
576                 DICT_VENDOR *dv;
577                 static DICT_VENDOR *last_vendor = NULL;
578
579                 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
580                         fr_strerror_printf("TLV's cannot be encrypted");
581                         return -1;
582                 }
583
584                 if (flags.is_tlv && flags.has_tag) {
585                         fr_strerror_printf("Sub-TLV's cannot have a tag");
586                         return -1;
587                 }
588
589                 if (flags.has_tlv && flags.has_tag) {
590                         fr_strerror_printf("TLV's cannot have a tag");
591                         return -1;
592                 }
593
594                 /*
595                  *      Most ATTRIBUTEs are bunched together by
596                  *      VENDOR.  We can save a lot of lookups on
597                  *      dictionary initialization by caching the last
598                  *      vendor.
599                  */
600                 if (last_vendor && (vendor == last_vendor->vendorpec)) {
601                         dv = last_vendor;
602                 } else {
603                         dv = dict_vendorbyvalue(vendor);
604                         last_vendor = dv;
605                 }
606
607                 /*
608                  *      If the vendor isn't defined, die.
609                  */
610                 if (!dv) {
611                         fr_strerror_printf("dict_addattr: Unknown vendor %d",
612                                            vendor);
613                         return -1;
614                 }
615
616                 /*
617                  *      FIXME: Switch over dv->type, and limit things
618                  *      properly.
619                  */
620                 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
621                         fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
622                         return -1;
623                 } /* else 256..65535 are allowed */
624         }
625
626         /*
627          *      Create a new attribute for the list
628          */
629         if ((da = fr_pool_alloc(sizeof(*da) + namelen)) == NULL) {
630                 fr_strerror_printf("dict_addattr: out of memory");
631                 return -1;
632         }
633
634         memcpy(da->name, name, namelen);
635         da->name[namelen] = '\0';
636         da->attr = attr;
637         da->vendor = vendor;
638         da->type = type;
639         da->flags = flags;
640
641         /*
642          *      Insert the attribute, only if it's not a duplicate.
643          */
644         if (!fr_hash_table_insert(attributes_byname, da)) {
645                 DICT_ATTR       *a;
646
647                 /*
648                  *      If the attribute has identical number, then
649                  *      ignore the duplicate.
650                  */
651                 a = fr_hash_table_finddata(attributes_byname, da);
652                 if (a && (strcasecmp(a->name, da->name) == 0)) {
653                         if (a->attr != da->attr) {
654                                 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
655                                 fr_pool_free(da);
656                                 return -1;
657                         }
658
659                         /*
660                          *      Same name, same vendor, same attr,
661                          *      maybe the flags and/or type is
662                          *      different.  Let the new value
663                          *      over-ride the old one.
664                          */
665                 }
666
667
668                 fr_hash_table_delete(attributes_byvalue, a);
669
670                 if (!fr_hash_table_replace(attributes_byname, da)) {
671                         fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
672                         fr_pool_free(da);
673                         return -1;
674                 }
675         }
676
677         /*
678          *      Insert the SAME pointer (not free'd when this entry is
679          *      deleted), into another table.
680          *
681          *      We want this behaviour because we want OLD names for
682          *      the attributes to be read from the configuration
683          *      files, but when we're printing them, (and looking up
684          *      by value) we want to use the NEW name.
685          */
686         if (!fr_hash_table_replace(attributes_byvalue, da)) {
687                 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
688                 return -1;
689         }
690
691         if (!vendor && (attr > 0) && (attr < 256)) {
692                  dict_base_attrs[attr] = da;
693         }
694
695         return 0;
696 }
697
698
699 /*
700  *      Add a value for an attribute to the dictionary.
701  */
702 int dict_addvalue(const char *namestr, const char *attrstr, int value)
703 {
704         size_t          length;
705         DICT_ATTR       *dattr;
706         DICT_VALUE      *dval;
707
708         static DICT_ATTR *last_attr = NULL;
709
710         if (!*namestr) {
711                 fr_strerror_printf("dict_addvalue: empty names are not permitted");
712                 return -1;
713         }
714
715         if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
716                 fr_strerror_printf("dict_addvalue: value name too long");
717                 return -1;
718         }
719
720         if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
721                 fr_strerror_printf("dict_addvalue: out of memory");
722                 return -1;
723         }
724         memset(dval, 0, sizeof(*dval));
725
726         strcpy(dval->name, namestr);
727         dval->value = value;
728
729         /*
730          *      Most VALUEs are bunched together by ATTRIBUTE.  We can
731          *      save a lot of lookups on dictionary initialization by
732          *      caching the last attribute.
733          */
734         if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
735                 dattr = last_attr;
736         } else {
737                 dattr = dict_attrbyname(attrstr);
738                 last_attr = dattr;
739         }
740
741         /*
742          *      Remember which attribute is associated with this
743          *      value, if possible.
744          */
745         if (dattr) {
746                 if (dattr->flags.has_value_alias) {
747                         fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
748                         return -1;
749                 }
750
751                 dval->attr = dattr->attr;
752                 dval->vendor = dattr->vendor;
753
754                 /*
755                  *      Enforce valid values
756                  *
757                  *      Don't worry about fixups...
758                  */
759                 switch (dattr->type) {
760                         case PW_TYPE_BYTE:
761                                 if (value > 255) {
762                                         fr_pool_free(dval);
763                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
764                                         return -1;
765                                 }
766                                 break;
767                         case PW_TYPE_SHORT:
768                                 if (value > 65535) {
769                                         fr_pool_free(dval);
770                                         fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
771                                         return -1;
772                                 }
773                                 break;
774
775                                 /*
776                                  *      Allow octets for now, because
777                                  *      of dictionary.cablelabs
778                                  */
779                         case PW_TYPE_OCTETS:
780
781                         case PW_TYPE_INTEGER:
782                                 break;
783
784                         default:
785                                 fr_pool_free(dval);
786                                 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
787                                            fr_int2str(type_table, dattr->type, "?Unknown?"));
788                                 return -1;
789                 }
790
791                 dattr->flags.has_value = 1;
792         } else {
793                 value_fixup_t *fixup;
794
795                 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
796                 if (!fixup) {
797                         fr_pool_free(dval);
798                         fr_strerror_printf("dict_addvalue: out of memory");
799                         return -1;
800                 }
801                 memset(fixup, 0, sizeof(*fixup));
802
803                 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
804                 fixup->dval = dval;
805
806                 /*
807                  *      Insert to the head of the list.
808                  */
809                 fixup->next = value_fixup;
810                 value_fixup = fixup;
811
812                 return 0;
813         }
814
815         /*
816          *      Add the value into the dictionary.
817          */
818         if (!fr_hash_table_insert(values_byname, dval)) {
819                 if (dattr) {
820                         DICT_VALUE *old;
821
822                         /*
823                          *      Suppress duplicates with the same
824                          *      name and value.  There are lots in
825                          *      dictionary.ascend.
826                          */
827                         old = dict_valbyname(dattr->attr, dattr->vendor, namestr);
828                         if (old && (old->value == dval->value)) {
829                                 fr_pool_free(dval);
830                                 return 0;
831                         }
832                 }
833
834                 fr_pool_free(dval);
835                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
836                 return -1;
837         }
838
839         /*
840          *      There are multiple VALUE's, keyed by attribute, so we
841          *      take care of that here.
842          */
843         if (!fr_hash_table_replace(values_byvalue, dval)) {
844                 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
845                            namestr);
846                 return -1;
847         }
848
849         return 0;
850 }
851
852 static int sscanf_i(const char *str, int *pvalue)
853 {
854         int rcode = 0;
855         int base = 10;
856         static const char *tab = "0123456789";
857
858         if ((str[0] == '0') &&
859             ((str[1] == 'x') || (str[1] == 'X'))) {
860                 tab = "0123456789abcdef";
861                 base = 16;
862
863                 str += 2;
864         }
865
866         while (*str) {
867                 const char *c;
868
869                 c = memchr(tab, tolower((int) *str), base);
870                 if (!c) return 0;
871
872                 rcode *= base;
873                 rcode += (c - tab);
874                 str++;
875         }
876
877         *pvalue = rcode;
878         return 1;
879 }
880
881
882 /*
883  *      Process the ATTRIBUTE command
884  */
885 static int process_attribute(const char* fn, const int line,
886                              const int block_vendor, DICT_ATTR *block_tlv,
887                              int tlv_depth, char **argv, int argc)
888 {
889         int             vendor = 0;
890         int             value;
891         int             type;
892         int             length = 0;
893         ATTR_FLAGS      flags;
894         char            *p;
895
896         if ((argc < 3) || (argc > 4)) {
897                 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
898                         fn, line);
899                 return -1;
900         }
901
902         memset(&flags, 0, sizeof(flags));
903
904         /*
905          *      Look for extended attributes before doing anything else.
906          */
907         p = strchr(argv[1], '.');
908         if (p) *p = '\0';
909
910         /*
911          *      Validate all entries
912          */
913         if (!sscanf_i(argv[1], &value)) {
914                 fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
915                 return -1;
916         }
917
918         /*
919          *      Parse extended attributes.
920          */
921         if (p) {
922                 int sub;
923                 char *q;
924                 DICT_ATTR *da;
925
926                 *p = '.';       /* reset forlater printing */
927
928                 /*
929                  *      Does the parent attribute exist?
930                  */
931                 da = dict_attrbyvalue(value, VENDORPEC_EXTENDED);
932                 if (!da) {
933                         fr_strerror_printf("dict_init: %s[%d]: Entry refers to unknown attribute %d", fn, line, value);
934                         return -1;
935                 }
936
937                 /*
938                  *      241.1 means 241 is of type "extended".
939                  *      Otherwise, die.
940                  */
941                 if (!da->flags.extended && !da->flags.extended_flags) {
942                         fr_strerror_printf("dict_init: %s[%d]: Entry refers to a non-extended attribute %d", fn, line, value);
943                         return -1;
944                 }
945
946                 /*
947                  *      Look for sub-TLVs
948                  */
949                 q = strchr(p + 1, '.');
950                 if (q) *q = '\0';
951
952                 /*
953                  *      Parse error.
954                  */
955                 if (!sscanf_i(p + 1, &sub)) {
956                         fr_strerror_printf("dict_init: %s[%d]: Parse error in value \"%s\"", fn, line, argv[1]);
957                         return -1;
958                 }
959
960                 /*
961                  *      Value is out of bounds.
962                  */
963                 if ((sub == 0) || (sub > 255)) {
964                         fr_strerror_printf("dict_init: %s[%d]: Entry has value out of range 0..255: %d", fn, line, sub);
965                         return -1;
966                 }
967
968                 value |= (sub << fr_wimax_shift[1]);
969
970                 /*
971                  *      If this is defining the contents of a TLV,
972                  *      look for the parent, and check it.
973                  */
974                 if (q) {
975                         DICT_ATTR *tlv;
976
977                         tlv = dict_attrbyvalue(value, VENDORPEC_EXTENDED);
978                         if (!tlv || !tlv->flags.has_tlv ||
979                             (!tlv->flags.extended && !tlv->flags.extended_flags)) {
980                                 fr_strerror_printf("dict_init: %s[%d]: Entry refers to Attribute \"%s\", which is not an extended attribute TLV", fn, line, argv[1]);
981                                 return -1;
982
983                         }
984
985                         flags.is_tlv = 1;
986                         
987                         /*
988                          *      Parse error.
989                          */
990                         if (!sscanf_i(q + 1, &sub)) {
991                                 fr_strerror_printf("dict_init: %s[%d]: Parse error in value \"%s\"", fn, line, argv[1]);
992                                 return -1;
993                         }
994
995                         /*
996                          *      Value is out of bounds.
997                          */
998                         if ((sub == 0) || (sub > 255)) {
999                                 fr_strerror_printf("dict_init: %s[%d]: Entry has value out of range 0..255: %d", fn, line, sub);
1000                                 return -1;
1001                         }
1002
1003                         value |= (sub << fr_wimax_shift[2]);
1004                 }
1005
1006                 /*
1007                  *      Set which type of attribute this is.
1008                  */
1009                 flags.extended = da->flags.extended;
1010                 flags.extended_flags = da->flags.extended_flags;
1011         }
1012
1013         if (strncmp(argv[2], "octets[", 7) != 0) {
1014                 /*
1015                  *      find the type of the attribute.
1016                  */
1017                 type = fr_str2int(type_table, argv[2], -1);
1018                 if (type < 0) {
1019                         fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
1020                                            fn, line, argv[2]);
1021                         return -1;
1022                 }
1023         } else {
1024                 type = PW_TYPE_OCTETS;
1025                 
1026                 p = strchr(argv[2] + 7, ']');
1027                 if (!p) {
1028                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
1029                         return -1;
1030                 }
1031
1032                 *p = 0;
1033
1034                 if (!sscanf_i(argv[1], &length)) {
1035                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1036                         return -1;
1037                 }
1038
1039                 if ((length == 0) || (length > 253)) {
1040                         fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1041                         return -1;
1042                 }
1043         }
1044
1045         /*
1046          *      Only look up the vendor if the string
1047          *      is non-empty.
1048          */
1049         if (argc < 4) {
1050                 /*
1051                  *      Force "length" for data types of fixed length;
1052                  */
1053                 switch (type) {
1054                 case PW_TYPE_BYTE:
1055                         length = 1;
1056                         break;
1057
1058                 case PW_TYPE_SHORT:
1059                         length = 2;
1060                         break;
1061
1062                 case PW_TYPE_DATE:
1063                 case PW_TYPE_IPADDR:
1064                 case PW_TYPE_INTEGER:
1065                 case PW_TYPE_SIGNED:
1066                         length = 4;
1067                         break;
1068
1069                 case PW_TYPE_ETHERNET:
1070                         length = 6;
1071                         break;
1072
1073                 case PW_TYPE_IFID:
1074                         length = 8;
1075                         break;
1076
1077                 case PW_TYPE_IPV6ADDR:
1078                         length = 16;
1079                         break;
1080
1081                 default:
1082                         break;
1083                 }
1084
1085                 flags.length = length;
1086
1087         } else {                /* argc == 4: we have options */
1088                 char *key, *next, *last;
1089
1090                 if (length != 0) {
1091                         fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line);
1092                         return -1;
1093                 }
1094
1095                 key = argv[3];
1096                 do {
1097                         next = strchr(key, ',');
1098                         if (next) *(next++) = '\0';
1099
1100                         if (strcmp(key, "has_tag") == 0 ||
1101                             strcmp(key, "has_tag=1") == 0) {
1102                                 /* Boolean flag, means this is a
1103                                    tagged attribute */
1104                                 flags.has_tag = 1;
1105                                 
1106                         } else if (strncmp(key, "encrypt=", 8) == 0) {
1107                                 /* Encryption method, defaults to 0 (none).
1108                                    Currently valid is just type 2,
1109                                    Tunnel-Password style, which can only
1110                                    be applied to strings. */
1111                                 flags.encrypt = strtol(key + 8, &last, 0);
1112                                 if (*last) {
1113                                         fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
1114                                                     fn, line, key);
1115                                         return -1;
1116                                 }
1117                                 
1118                         } else if (strncmp(key, "array", 6) == 0) {
1119                                 flags.array = 1;
1120                                 
1121                                 switch (type) {
1122                                         case PW_TYPE_IPADDR:
1123                                         case PW_TYPE_BYTE:
1124                                         case PW_TYPE_SHORT:
1125                                         case PW_TYPE_INTEGER:
1126                                         case PW_TYPE_DATE:
1127                                                 break;
1128
1129                                         default:
1130                                                 fr_strerror_printf( "dict_init: %s[%d] Only IP addresses can have the \"array\" flag set.",
1131                                                             fn, line);
1132                                                 return -1;
1133                                 }
1134
1135                                 /*
1136                                  *      The only thing is the vendor name,
1137                                  *      and it's a known name: allow it.
1138                                  */
1139                         } else if ((key == argv[3]) && !next && !block_vendor &&
1140                                    ((vendor = dict_vendorbyname(key)) !=0)) {
1141                                 break;
1142
1143                         } else if (strncmp(key, "extended-flags", 15) == 0) {
1144                                 if (flags.extended) {
1145                                         fr_strerror_printf( "dict_init: %s[%d] You cannot set two  \"extended\" flags.",
1146                                                             fn, line);
1147                                         return -1;
1148                                 }
1149
1150                                 flags.extended_flags = 1;
1151
1152                         } else if (strncmp(key, "extended", 9) == 0) {
1153                                 if (flags.extended_flags) {
1154                                         fr_strerror_printf( "dict_init: %s[%d] You cannot set two  \"extended\" flags.",
1155                                                             fn, line);
1156                                         return -1;
1157                                 }
1158                                 flags.extended = 1;
1159
1160                         } else {
1161                                 fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
1162                                             fn, line, key);
1163                                 return -1;
1164                         }
1165
1166                         key = next;
1167                         if (key && !*key) break;
1168                 } while (key);
1169         }
1170
1171         if (block_vendor) vendor = block_vendor;
1172
1173         /*
1174          *      Special checks for tags, they make our life much more
1175          *      difficult.
1176          */
1177         if (flags.has_tag) {
1178                 /*
1179                  *      Only string, octets, and integer can be tagged.
1180                  */
1181                 switch (type) {
1182                 case PW_TYPE_STRING:
1183                 case PW_TYPE_INTEGER:
1184                         break;
1185
1186                 default:
1187                         fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
1188                                    fn, line,
1189                                    fr_int2str(type_table, type, "?Unknown?"));
1190                         return -1;
1191                 }
1192         }
1193
1194         if (type == PW_TYPE_TLV) {
1195                 flags.has_tlv = 1;
1196         }
1197
1198         if (block_tlv) {
1199                 /*
1200                  *      TLV's can be only one octet.
1201                  */
1202           if ((value <= 0) || ((value & ~fr_wimax_mask[tlv_depth]) != 0)) {
1203                         fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1204                                     fn, line);
1205                         return -1;
1206                 }
1207
1208                 /*
1209                  *      
1210                  */
1211                 value <<= fr_wimax_shift[tlv_depth];
1212                 value |= block_tlv->attr;
1213                 flags.is_tlv = 1;
1214         }
1215
1216         /*
1217          *      Add it in.
1218          */
1219         if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1220                 char buffer[256];
1221
1222                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1223
1224                 fr_strerror_printf("dict_init: %s[%d]: %s",
1225                                    fn, line, buffer);
1226                 return -1;
1227         }
1228
1229         return 0;
1230 }
1231
1232
1233 /*
1234  *      Process the VALUE command
1235  */
1236 static int process_value(const char* fn, const int line, char **argv,
1237                          int argc)
1238 {
1239         int     value;
1240
1241         if (argc != 3) {
1242                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1243                         fn, line);
1244                 return -1;
1245         }
1246         /*
1247          *      For Compatibility, skip "Server-Config"
1248          */
1249         if (strcasecmp(argv[0], "Server-Config") == 0)
1250                 return 0;
1251
1252         /*
1253          *      Validate all entries
1254          */
1255         if (!sscanf_i(argv[2], &value)) {
1256                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1257                         fn, line);
1258                 return -1;
1259         }
1260
1261         if (dict_addvalue(argv[1], argv[0], value) < 0) {
1262                 char buffer[256];
1263
1264                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1265
1266                 fr_strerror_printf("dict_init: %s[%d]: %s",
1267                                    fn, line, buffer);
1268                 return -1;
1269         }
1270
1271         return 0;
1272 }
1273
1274
1275 /*
1276  *      Process the VALUE-ALIAS command
1277  *
1278  *      This allows VALUE mappings to be shared among multiple
1279  *      attributes.
1280  */
1281 static int process_value_alias(const char* fn, const int line, char **argv,
1282                                int argc)
1283 {
1284         DICT_ATTR *my_da, *da;
1285         DICT_VALUE *dval;
1286
1287         if (argc != 2) {
1288                 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1289                         fn, line);
1290                 return -1;
1291         }
1292
1293         my_da = dict_attrbyname(argv[0]);
1294         if (!my_da) {
1295                 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1296                            fn, line, argv[1]);
1297                 return -1;
1298         }
1299
1300         if (my_da->flags.has_value) {
1301                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE",
1302                            fn, line, argv[0]);
1303                 return -1;
1304         }
1305
1306         if (my_da->flags.has_value_alias) {
1307                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
1308                            fn, line, argv[0]);
1309                 return -1;
1310         }
1311
1312         da = dict_attrbyname(argv[1]);
1313         if (!da) {
1314                 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
1315                            fn, line, argv[1]);
1316                 return -1;
1317         }
1318
1319         if (!da->flags.has_value) {
1320                 fr_strerror_printf("dict_init: %s[%d]: VALUE-ALIAS cannot refer to ATTRIBUTE %s: It has no values",
1321                            fn, line, argv[1]);
1322                 return -1;
1323         }
1324
1325         if (da->flags.has_value_alias) {
1326                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
1327                            fn, line, argv[1]);
1328                 return -1;
1329         }
1330
1331         if (my_da->type != da->type) {
1332                 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
1333                            fn, line);
1334                 return -1;
1335         }
1336
1337         if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
1338                 fr_strerror_printf("dict_addvalue: out of memory");
1339                 return -1;
1340         }
1341
1342         dval->name[0] = '\0';   /* empty name */
1343         dval->attr = my_da->attr;
1344         dval->vendor = my_da->vendor;
1345         dval->value = da->attr;
1346
1347         if (!fr_hash_table_insert(values_byname, dval)) {
1348                 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
1349                            fn, line);
1350                 fr_pool_free(dval);
1351                 return -1;
1352         }
1353
1354         return 0;
1355 }
1356
1357
1358 /*
1359  *      Process the VENDOR command
1360  */
1361 static int process_vendor(const char* fn, const int line, char **argv,
1362                           int argc)
1363 {
1364         int     value;
1365         int     continuation = 0;
1366         const   char *format = NULL;
1367
1368         if ((argc < 2) || (argc > 3)) {
1369                 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
1370                             fn, line);
1371                 return -1;
1372         }
1373
1374         /*
1375          *       Validate all entries
1376          */
1377         if (!isdigit((int) argv[1][0])) {
1378                 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1379                         fn, line);
1380                 return -1;
1381         }
1382         value = atoi(argv[1]);
1383
1384         /* Create a new VENDOR entry for the list */
1385         if (dict_addvendor(argv[0], value) < 0) {
1386                 char buffer[256];
1387
1388                 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1389
1390                 fr_strerror_printf("dict_init: %s[%d]: %s",
1391                            fn, line, buffer);
1392                 return -1;
1393         }
1394
1395         /*
1396          *      Look for a format statement
1397          */
1398         if (argc == 3) {
1399                 format = argv[2];
1400
1401         } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
1402                 format = "format=4,0";
1403
1404         } else if (value == VENDORPEC_LUCENT) {
1405                 format = "format=2,1";
1406
1407         } else if (value == VENDORPEC_STARENT) {
1408                 format = "format=2,2";
1409
1410         } /* else no fixups to do */
1411
1412         if (format) {
1413                 int type, length;
1414                 const char *p;
1415                 DICT_VENDOR *dv;
1416
1417                 if (strncasecmp(format, "format=", 7) != 0) {
1418                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected \"format=\", got \"%s\"",
1419                                    fn, line, format);
1420                         return -1;
1421                 }
1422
1423                 p = format + 7;
1424                 if ((strlen(p) < 3) ||
1425                     !isdigit((int) p[0]) ||
1426                     (p[1] != ',') ||
1427                     !isdigit((int) p[2]) ||
1428                     (p[3] && (p[3] != ','))) {
1429                         fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1430                                    fn, line, p);
1431                         return -1;
1432                 }
1433
1434                 type = (int) (p[0] - '0');
1435                 length = (int) (p[2] - '0');
1436
1437                 if (p[3] == ',') {
1438                         if ((p[4] != 'c') ||
1439                             (p[5] != '\0')) {
1440                                 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR.  Expected text like \"1,1\", got \"%s\"",
1441                                            fn, line, p);
1442                                 return -1;
1443                         }
1444                         continuation = 1;
1445
1446                         if ((value != VENDORPEC_WIMAX) ||
1447                             (type != 1) || (length != 1)) {
1448                                 fr_strerror_printf("dict_init: %s[%d]: Only WiMAX VSAs can have continuations",
1449                                            fn, line);
1450                                 return -1;
1451                         }
1452                 }
1453
1454                 dv = dict_vendorbyvalue(value);
1455                 if (!dv) {
1456                         fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
1457                                    fn, line);
1458                         return -1;
1459                 }
1460
1461                 if ((type != 1) && (type != 2) && (type != 4)) {
1462                         fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
1463                                    fn, line, type);
1464                         return -1;
1465                 }
1466
1467                 if ((length != 0) && (length != 1) && (length != 2)) {
1468                         fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
1469                                    fn, line, length);
1470                         return -1;
1471                 }
1472
1473                 dv->type = type;
1474                 dv->length = length;
1475                 dv->flags = continuation;
1476         }
1477
1478         return 0;
1479 }
1480
1481 /*
1482  *      String split routine.  Splits an input string IN PLACE
1483  *      into pieces, based on spaces.
1484  */
1485 static int str2argv(char *str, char **argv, int max_argc)
1486 {
1487         int argc = 0;
1488
1489         while (*str) {
1490                 if (argc >= max_argc) break;
1491
1492                 /*
1493                  *      Chop out comments early.
1494                  */
1495                 if (*str == '#') {
1496                         *str = '\0';
1497                         break;
1498                 }
1499
1500                 while ((*str == ' ') ||
1501                        (*str == '\t') ||
1502                        (*str == '\r') ||
1503                        (*str == '\n')) *(str++) = '\0';
1504
1505                 if (!*str) break;
1506
1507                 argv[argc] = str;
1508                 argc++;
1509
1510                 while (*str &&
1511                        (*str != ' ') &&
1512                        (*str != '\t') &&
1513                        (*str != '\r') &&
1514                        (*str != '\n')) str++;
1515         }
1516
1517         return argc;
1518 }
1519
1520 #define MAX_ARGV (16)
1521
1522 /*
1523  *      Initialize the dictionary.
1524  */
1525 static int my_dict_init(const char *dir, const char *fn,
1526                         const char *src_file, int src_line)
1527 {
1528         FILE    *fp;
1529         char    dirtmp[256];
1530         char    buf[256];
1531         char    *p;
1532         int     line = 0;
1533         int     vendor;
1534         int     block_vendor;
1535         struct stat statbuf;
1536         char    *argv[MAX_ARGV];
1537         int     argc;
1538         DICT_ATTR *da, *block_tlv[MAX_TLV_NEST + 1];
1539         int     which_block_tlv = 0;
1540
1541         block_tlv[0] = NULL;
1542         block_tlv[1] = NULL;
1543         block_tlv[2] = NULL;
1544
1545         if (strlen(fn) >= sizeof(dirtmp) / 2 ||
1546             strlen(dir) >= sizeof(dirtmp) / 2) {
1547                 fr_strerror_printf("dict_init: filename name too long");
1548                 return -1;
1549         }
1550
1551         /*
1552          *      First see if fn is relative to dir. If so, create
1553          *      new filename. If not, remember the absolute dir.
1554          */
1555         if ((p = strrchr(fn, FR_DIR_SEP)) != NULL) {
1556                 strcpy(dirtmp, fn);
1557                 dirtmp[p - fn] = 0;
1558                 dir = dirtmp;
1559         } else if (dir && dir[0] && strcmp(dir, ".") != 0) {
1560                 snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn);
1561                 fn = dirtmp;
1562         }
1563
1564         if ((fp = fopen(fn, "r")) == NULL) {
1565                 if (!src_file) {
1566                         fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
1567                                    fn, strerror(errno));
1568                 } else {
1569                         fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
1570                                    src_file, src_line, fn, strerror(errno));
1571                 }
1572                 return -1;
1573         }
1574
1575         stat(fn, &statbuf); /* fopen() guarantees this will succeed */
1576         if (!S_ISREG(statbuf.st_mode)) {
1577                 fclose(fp);
1578                 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
1579                            fn);
1580                 return -1;
1581         }
1582
1583         /*
1584          *      Globally writable dictionaries means that users can control
1585          *      the server configuration with little difficulty.
1586          */
1587 #ifdef S_IWOTH
1588         if ((statbuf.st_mode & S_IWOTH) != 0) {
1589                 fclose(fp);
1590                 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable.  Refusing to start due to insecure configuration.",
1591                            fn);
1592                 return -1;
1593         }
1594 #endif
1595
1596         dict_stat_add(fn, &statbuf);
1597
1598         /*
1599          *      Seed the random pool with data.
1600          */
1601         fr_rand_seed(&statbuf, sizeof(statbuf));
1602
1603         block_vendor = 0;
1604
1605         while (fgets(buf, sizeof(buf), fp) != NULL) {
1606                 line++;
1607                 if (buf[0] == '#' || buf[0] == 0 ||
1608                     buf[0] == '\n' || buf[0] == '\r')
1609                         continue;
1610
1611                 /*
1612                  *  Comment characters should NOT be appearing anywhere but
1613                  *  as start of a comment;
1614                  */
1615                 p = strchr(buf, '#');
1616                 if (p) *p = '\0';
1617
1618                 argc = str2argv(buf, argv, MAX_ARGV);
1619                 if (argc == 0) continue;
1620
1621                 if (argc == 1) {
1622                         fr_strerror_printf( "dict_init: %s[%d] invalid entry",
1623                                     fn, line);
1624                         fclose(fp);
1625                         return -1;
1626                 }
1627
1628                 /*
1629                  *      Process VALUE lines.
1630                  */
1631                 if (strcasecmp(argv[0], "VALUE") == 0) {
1632                         if (process_value(fn, line,
1633                                           argv + 1, argc - 1) == -1) {
1634                                 fclose(fp);
1635                                 return -1;
1636                         }
1637                         continue;
1638                 }
1639
1640                 /*
1641                  *      Perhaps this is an attribute.
1642                  */
1643                 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
1644                         if (process_attribute(fn, line, block_vendor,
1645                                               block_tlv[which_block_tlv],
1646                                               which_block_tlv,
1647                                               argv + 1, argc - 1) == -1) {
1648                                 fclose(fp);
1649                                 return -1;
1650                         }
1651                         continue;
1652                 }
1653
1654                 /*
1655                  *      See if we need to import another dictionary.
1656                  */
1657                 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
1658                         if (my_dict_init(dir, argv[1], fn, line) < 0) {
1659                                 fclose(fp);
1660                                 return -1;
1661                         }
1662                         continue;
1663                 } /* $INCLUDE */
1664
1665                 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
1666                         if (process_value_alias(fn, line,
1667                                                 argv + 1, argc - 1) == -1) {
1668                                 fclose(fp);
1669                                 return -1;
1670                         }
1671                         continue;
1672                 }
1673
1674                 /*
1675                  *      Process VENDOR lines.
1676                  */
1677                 if (strcasecmp(argv[0], "VENDOR") == 0) {
1678                         if (process_vendor(fn, line,
1679                                            argv + 1, argc - 1) == -1) {
1680                                 fclose(fp);
1681                                 return -1;
1682                         }
1683                         continue;
1684                 }
1685
1686                 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
1687                         if (argc != 2) {
1688                                 fr_strerror_printf(
1689                                 "dict_init: %s[%d] invalid BEGIN-TLV entry",
1690                                         fn, line);
1691                                 fclose(fp);
1692                                 return -1;
1693                         }
1694
1695                         da = dict_attrbyname(argv[1]);
1696                         if (!da) {
1697                                 fr_strerror_printf(
1698                                         "dict_init: %s[%d]: unknown attribute %s",
1699                                         fn, line, argv[1]);
1700                                 fclose(fp);
1701                                 return -1;
1702                         }
1703
1704                         if (da->type != PW_TYPE_TLV) {
1705                                 fr_strerror_printf(
1706                                         "dict_init: %s[%d]: attribute %s is not of type tlv",
1707                                         fn, line, argv[1]);
1708                                 fclose(fp);
1709                                 return -1;
1710                         }
1711
1712                         if (which_block_tlv >= MAX_TLV_NEST) {
1713                                 fr_strerror_printf(
1714                                         "dict_init: %s[%d]: TLVs are nested too deep",
1715                                         fn, line);
1716                                 fclose(fp);
1717                                 return -1;
1718                         }
1719
1720
1721                         block_tlv[++which_block_tlv] = da;
1722                         continue;
1723                 } /* BEGIN-TLV */
1724
1725                 if (strcasecmp(argv[0], "END-TLV") == 0) {
1726                         if (argc != 2) {
1727                                 fr_strerror_printf(
1728                                 "dict_init: %s[%d] invalid END-TLV entry",
1729                                         fn, line);
1730                                 fclose(fp);
1731                                 return -1;
1732                         }
1733
1734                         da = dict_attrbyname(argv[1]);
1735                         if (!da) {
1736                                 fr_strerror_printf(
1737                                         "dict_init: %s[%d]: unknown attribute %s",
1738                                         fn, line, argv[1]);
1739                                 fclose(fp);
1740                                 return -1;
1741                         }
1742
1743                         if (da != block_tlv[which_block_tlv]) {
1744                                 fr_strerror_printf(
1745                                         "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
1746                                         fn, line, argv[1]);
1747                                 fclose(fp);
1748                                 return -1;
1749                         }
1750                         block_tlv[which_block_tlv--] = NULL;
1751                         continue;
1752                 } /* END-VENDOR */
1753
1754                 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
1755                         if (argc != 2) {
1756                                 fr_strerror_printf(
1757                                 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
1758                                         fn, line);
1759                                 fclose(fp);
1760                                 return -1;
1761                         }
1762
1763                         vendor = dict_vendorbyname(argv[1]);
1764                         if (!vendor) {
1765                                 fr_strerror_printf(
1766                                         "dict_init: %s[%d]: unknown vendor %s",
1767                                         fn, line, argv[1]);
1768                                 fclose(fp);
1769                                 return -1;
1770                         }
1771                         block_vendor = vendor;
1772                         continue;
1773                 } /* BEGIN-VENDOR */
1774
1775                 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
1776                         if (argc != 2) {
1777                                 fr_strerror_printf(
1778                                 "dict_init: %s[%d] invalid END-VENDOR entry",
1779                                         fn, line);
1780                                 fclose(fp);
1781                                 return -1;
1782                         }
1783
1784                         vendor = dict_vendorbyname(argv[1]);
1785                         if (!vendor) {
1786                                 fr_strerror_printf(
1787                                         "dict_init: %s[%d]: unknown vendor %s",
1788                                         fn, line, argv[1]);
1789                                 fclose(fp);
1790                                 return -1;
1791                         }
1792
1793                         if (vendor != block_vendor) {
1794                                 fr_strerror_printf(
1795                                         "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
1796                                         fn, line, argv[1]);
1797                                 fclose(fp);
1798                                 return -1;
1799                         }
1800                         block_vendor = 0;
1801                         continue;
1802                 } /* END-VENDOR */
1803
1804                 /*
1805                  *      Any other string: We don't recognize it.
1806                  */
1807                 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
1808                            fn, line, argv[0]);
1809                 fclose(fp);
1810                 return -1;
1811         }
1812         fclose(fp);
1813         return 0;
1814 }
1815
1816
1817 /*
1818  *      Empty callback for hash table initialization.
1819  */
1820 static int null_callback(void *ctx, void *data)
1821 {
1822         ctx = ctx;              /* -Wunused */
1823         data = data;            /* -Wunused */
1824
1825         return 0;
1826 }
1827
1828
1829 /*
1830  *      Initialize the directory, then fix the attr member of
1831  *      all attributes.
1832  */
1833 int dict_init(const char *dir, const char *fn)
1834 {
1835         /*
1836          *      Check if we need to change anything.  If not, don't do
1837          *      anything.
1838          */
1839         if (dict_stat_check(dir, fn)) {
1840                 return 0;
1841         }
1842
1843         /*
1844          *      Free the dictionaries, and the stat cache.
1845          */
1846         dict_free();
1847         stat_root_dir = strdup(dir);
1848         stat_root_file = strdup(fn);
1849
1850         /*
1851          *      Create the table of vendor by name.   There MAY NOT
1852          *      be multiple vendors of the same name.
1853          *
1854          *      Each vendor is malloc'd, so the free function is free.
1855          */
1856         vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
1857                                                 dict_vendor_name_cmp,
1858                                                 fr_pool_free);
1859         if (!vendors_byname) {
1860                 return -1;
1861         }
1862
1863         /*
1864          *      Create the table of vendors by value.  There MAY
1865          *      be vendors of the same value.  If there are, we
1866          *      pick the latest one.
1867          */
1868         vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
1869                                                  dict_vendor_value_cmp,
1870                                                  fr_pool_free);
1871         if (!vendors_byvalue) {
1872                 return -1;
1873         }
1874
1875         /*
1876          *      Create the table of attributes by name.   There MAY NOT
1877          *      be multiple attributes of the same name.
1878          *
1879          *      Each attribute is malloc'd, so the free function is free.
1880          */
1881         attributes_byname = fr_hash_table_create(dict_attr_name_hash,
1882                                                    dict_attr_name_cmp,
1883                                                    fr_pool_free);
1884         if (!attributes_byname) {
1885                 return -1;
1886         }
1887
1888         /*
1889          *      Create the table of attributes by value.  There MAY
1890          *      be attributes of the same value.  If there are, we
1891          *      pick the latest one.
1892          */
1893         attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
1894                                                     dict_attr_value_cmp,
1895                                                     fr_pool_free);
1896         if (!attributes_byvalue) {
1897                 return -1;
1898         }
1899
1900         values_byname = fr_hash_table_create(dict_value_name_hash,
1901                                                dict_value_name_cmp,
1902                                                fr_pool_free);
1903         if (!values_byname) {
1904                 return -1;
1905         }
1906
1907         values_byvalue = fr_hash_table_create(dict_value_value_hash,
1908                                                 dict_value_value_cmp,
1909                                                 fr_pool_free);
1910         if (!values_byvalue) {
1911                 return -1;
1912         }
1913
1914         value_fixup = NULL;     /* just to be safe. */
1915
1916         if (my_dict_init(dir, fn, NULL, 0) < 0)
1917                 return -1;
1918
1919         if (value_fixup) {
1920                 DICT_ATTR *a;
1921                 value_fixup_t *this, *next;
1922
1923                 for (this = value_fixup; this != NULL; this = next) {
1924                         next = this->next;
1925
1926                         a = dict_attrbyname(this->attrstr);
1927                         if (!a) {
1928                                 fr_strerror_printf(
1929                                         "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
1930                                         this->attrstr, this->dval->name);
1931                                 return -1; /* leak, but they should die... */
1932                         }
1933
1934                         this->dval->attr = a->attr;
1935
1936                         /*
1937                          *      Add the value into the dictionary.
1938                          */
1939                         if (!fr_hash_table_replace(values_byname,
1940                                                      this->dval)) {
1941                                 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
1942                                 return -1;
1943                         }
1944
1945                         /*
1946                          *      Allow them to use the old name, but
1947                          *      prefer the new name when printing
1948                          *      values.
1949                          */
1950                         if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
1951                                 fr_hash_table_replace(values_byvalue,
1952                                                         this->dval);
1953                         }
1954                         free(this);
1955
1956                         /*
1957                          *      Just so we don't lose track of things.
1958                          */
1959                         value_fixup = next;
1960                 }
1961         }
1962
1963         /*
1964          *      Walk over all of the hash tables to ensure they're
1965          *      initialized.  We do this because the threads may perform
1966          *      lookups, and we don't want multi-threaded re-ordering
1967          *      of the table entries.  That would be bad.
1968          */
1969         fr_hash_table_walk(vendors_byname, null_callback, NULL);
1970         fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
1971
1972         fr_hash_table_walk(attributes_byname, null_callback, NULL);
1973         fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
1974
1975         fr_hash_table_walk(values_byvalue, null_callback, NULL);
1976         fr_hash_table_walk(values_byname, null_callback, NULL);
1977
1978         return 0;
1979 }
1980
1981 /*
1982  *      Get an attribute by its numerical value.
1983  */
1984 DICT_ATTR *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
1985 {
1986         DICT_ATTR dattr;
1987
1988         if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
1989
1990         dattr.attr = attr;
1991         dattr.vendor = vendor;
1992
1993         return fr_hash_table_finddata(attributes_byvalue, &dattr);
1994 }
1995
1996 /*
1997  *      Get an attribute by its name.
1998  */
1999 DICT_ATTR *dict_attrbyname(const char *name)
2000 {
2001         DICT_ATTR *da;
2002         uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
2003
2004         if (!name) return NULL;
2005
2006         da = (DICT_ATTR *) buffer;
2007         strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
2008
2009         return fr_hash_table_finddata(attributes_byname, da);
2010 }
2011
2012 /*
2013  *      Associate a value with an attribute and return it.
2014  */
2015 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
2016 {
2017         DICT_VALUE dval, *dv;
2018
2019         /*
2020          *      First, look up aliases.
2021          */
2022         dval.attr = attr;
2023         dval.vendor = vendor;
2024         dval.name[0] = '\0';
2025
2026         /*
2027          *      Look up the attribute alias target, and use
2028          *      the correct attribute number if found.
2029          */
2030         dv = fr_hash_table_finddata(values_byname, &dval);
2031         if (dv) dval.attr = dv->value;
2032
2033         dval.value = value;
2034
2035         return fr_hash_table_finddata(values_byvalue, &dval);
2036 }
2037
2038 /*
2039  *      Get a value by its name, keyed off of an attribute.
2040  */
2041 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, const char *name)
2042 {
2043         DICT_VALUE *my_dv, *dv;
2044         uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
2045
2046         if (!name) return NULL;
2047
2048         my_dv = (DICT_VALUE *) buffer;
2049         my_dv->attr = attr;
2050         my_dv->vendor = vendor;
2051         my_dv->name[0] = '\0';
2052
2053         /*
2054          *      Look up the attribute alias target, and use
2055          *      the correct attribute number if found.
2056          */
2057         dv = fr_hash_table_finddata(values_byname, my_dv);
2058         if (dv) my_dv->attr = dv->value;
2059
2060         strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
2061
2062         return fr_hash_table_finddata(values_byname, my_dv);
2063 }
2064
2065 /*
2066  *      Get the vendor PEC based on the vendor name
2067  *
2068  *      This is efficient only for small numbers of vendors.
2069  */
2070 int dict_vendorbyname(const char *name)
2071 {
2072         DICT_VENDOR *dv;
2073         uint32_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + 3)/4];
2074
2075         if (!name) return 0;
2076
2077         dv = (DICT_VENDOR *) buffer;
2078         strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
2079
2080         dv = fr_hash_table_finddata(vendors_byname, dv);
2081         if (!dv) return 0;
2082
2083         return dv->vendorpec;
2084 }
2085
2086 /*
2087  *      Return the vendor struct based on the PEC.
2088  */
2089 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
2090 {
2091         DICT_VENDOR dv;
2092
2093         dv.vendorpec = vendorpec;
2094
2095         return fr_hash_table_finddata(vendors_byvalue, &dv);
2096 }