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