2 * dict.c Routines to read the dictionary file.
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.
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.
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
20 * Copyright 2000,2006 The FreeRADIUS server project
24 #include <freeradius-devel/libradius.h>
27 #include <freeradius-devel/dhcp.h>
36 #ifdef HAVE_SYS_STAT_H
41 #define DICT_VALUE_MAX_NAME_LEN (128)
42 #define DICT_VENDOR_MAX_NAME_LEN (128)
43 #define DICT_ATTR_MAX_NAME_LEN (128)
45 #define DICT_ATTR_SIZE sizeof(DICT_ATTR) + DICT_ATTR_MAX_NAME_LEN
47 static fr_hash_table_t *vendors_byname = NULL;
48 static fr_hash_table_t *vendors_byvalue = NULL;
50 static fr_hash_table_t *attributes_byname = NULL;
51 static fr_hash_table_t *attributes_byvalue = NULL;
53 static fr_hash_table_t *attributes_combo = NULL;
55 static fr_hash_table_t *values_byvalue = NULL;
56 static fr_hash_table_t *values_byname = NULL;
58 static DICT_ATTR *dict_base_attrs[256];
61 * For faster HUP's, we cache the stat information for
62 * files we've $INCLUDEd
64 typedef struct dict_stat_t {
65 struct dict_stat_t *next;
69 static dict_stat_t *stat_head = NULL;
70 static dict_stat_t *stat_tail = NULL;
72 typedef struct value_fixup_t {
73 char attrstr[DICT_ATTR_MAX_NAME_LEN];
75 struct value_fixup_t *next;
80 * So VALUEs in the dictionary can have forward references.
82 static value_fixup_t *value_fixup = NULL;
84 const FR_NAME_NUMBER dict_attr_types[] = {
85 { "integer", PW_TYPE_INTEGER },
86 { "string", PW_TYPE_STRING },
87 { "ipaddr", PW_TYPE_IPV4_ADDR },
88 { "date", PW_TYPE_DATE },
89 { "abinary", PW_TYPE_ABINARY },
90 { "octets", PW_TYPE_OCTETS },
91 { "ifid", PW_TYPE_IFID },
92 { "ipv6addr", PW_TYPE_IPV6_ADDR },
93 { "ipv6prefix", PW_TYPE_IPV6_PREFIX },
94 { "byte", PW_TYPE_BYTE },
95 { "short", PW_TYPE_SHORT },
96 { "ether", PW_TYPE_ETHERNET },
97 { "combo-ip", PW_TYPE_IP_ADDR },
98 { "tlv", PW_TYPE_TLV },
99 { "signed", PW_TYPE_SIGNED },
100 { "extended", PW_TYPE_EXTENDED },
101 { "long-extended", PW_TYPE_LONG_EXTENDED },
102 { "evs", PW_TYPE_EVS },
103 { "uint8", PW_TYPE_BYTE },
104 { "uint16", PW_TYPE_SHORT },
105 { "uint32", PW_TYPE_INTEGER },
106 { "int32", PW_TYPE_SIGNED },
107 { "integer64", PW_TYPE_INTEGER64 },
108 { "uint64", PW_TYPE_INTEGER64 },
109 { "ipv4prefix", PW_TYPE_IPV4_PREFIX },
110 { "cidr", PW_TYPE_IPV4_PREFIX },
111 { "vsa", PW_TYPE_VSA },
116 * Map data types to min / max data sizes.
118 const size_t dict_attr_sizes[PW_TYPE_MAX][2] = {
119 [PW_TYPE_INVALID] = { ~0, 0 },
120 [PW_TYPE_STRING] = { 0, ~0 },
121 [PW_TYPE_INTEGER] = {4, 4 },
122 [PW_TYPE_IPV4_ADDR] = {4, 4},
123 [PW_TYPE_DATE] = {4, 4},
124 [PW_TYPE_ABINARY] = {32, ~0},
125 [PW_TYPE_OCTETS] = {0, ~0},
126 [PW_TYPE_IFID] = {8, 8},
127 [PW_TYPE_IPV6_ADDR] = { 16, 16},
128 [PW_TYPE_IPV6_PREFIX] = {2, 18},
129 [PW_TYPE_BYTE] = {1, 1},
130 [PW_TYPE_SHORT] = {2, 2},
131 [PW_TYPE_ETHERNET] = {6, 6},
132 [PW_TYPE_SIGNED] = {4, 4},
133 [PW_TYPE_IP_ADDR] = {4, 16},
134 [PW_TYPE_TLV] = {2, ~0},
135 [PW_TYPE_EXTENDED] = {2, ~0},
136 [PW_TYPE_LONG_EXTENDED] = {3, ~0},
137 [PW_TYPE_EVS] = {6, ~0},
138 [PW_TYPE_INTEGER64] = {8, 8},
139 [PW_TYPE_IPV4_PREFIX] = {6, 6},
140 [PW_TYPE_VSA] = {4, ~0}
144 * For packing multiple TLV numbers into one 32-bit integer. The
145 * first 3 bytes are just the 8-bit number. The next two are
146 * more limited. We only allow 31 attributes nested 3 layers
147 * deep, and only 7 nested 4 layers deep. This should be
148 * sufficient for most purposes.
150 * For TLVs and extended attributes, we packet the base attribute
151 * number into the upper 8 bits of the "vendor" field.
153 * e.g. OID attribute vendor
154 * 241.1 1 (241 << 24)
155 * 241.26.9.1 1 (241 << 24) | (9)
156 * 241.1.2 1 | (2 << 8) (241 << 24)
158 #define MAX_TLV_NEST (4)
161 * 8 bits of base attribute
162 * 8 bits for nested TLV 1
163 * 8 bits for nested TLV 2
164 * 5 bits for nested TLV 3
165 * 3 bits for nested TLV 4
167 const int fr_attr_max_tlv = MAX_TLV_NEST;
168 const int fr_attr_shift[MAX_TLV_NEST + 1] = {
172 const int fr_attr_mask[MAX_TLV_NEST + 1] = {
173 0xff, 0xff, 0xff, 0x1f, 0x07
178 * Create the hash of the name.
180 * We copy the hash function here because it's substantially faster.
182 #define FNV_MAGIC_INIT (0x811c9dc5)
183 #define FNV_MAGIC_PRIME (0x01000193)
185 static uint32_t dict_hashname(char const *name)
187 uint32_t hash = FNV_MAGIC_INIT;
190 for (p = name; *p != '\0'; p++) {
191 int c = *(unsigned char const *) p;
192 if (isalpha(c)) c = tolower(c);
194 hash *= FNV_MAGIC_PRIME;
195 hash ^= (uint32_t ) (c & 0xff);
203 * Hash callback functions.
205 static uint32_t dict_attr_name_hash(void const *data)
207 return dict_hashname(((DICT_ATTR const *)data)->name);
210 static int dict_attr_name_cmp(void const *one, void const *two)
212 DICT_ATTR const *a = one;
213 DICT_ATTR const *b = two;
215 return strcasecmp(a->name, b->name);
218 static uint32_t dict_attr_value_hash(void const *data)
221 DICT_ATTR const *attr = data;
223 hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
224 return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
227 static int dict_attr_value_cmp(void const *one, void const *two)
229 DICT_ATTR const *a = one;
230 DICT_ATTR const *b = two;
232 if (a->vendor < b->vendor) return -1;
233 if (a->vendor > b->vendor) return +1;
235 return a->attr - b->attr;
238 static uint32_t dict_attr_combo_hash(void const *data)
241 DICT_ATTR const *attr = data;
243 hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
244 hash = fr_hash_update(&attr->type, sizeof(attr->type), hash);
245 return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
248 static int dict_attr_combo_cmp(void const *one, void const *two)
250 DICT_ATTR const *a = one;
251 DICT_ATTR const *b = two;
253 if (a->type < b->type) return -1;
254 if (a->type > b->type) return +1;
256 if (a->vendor < b->vendor) return -1;
257 if (a->vendor > b->vendor) return +1;
259 return a->attr - b->attr;
262 static uint32_t dict_vendor_name_hash(void const *data)
264 return dict_hashname(((DICT_VENDOR const *)data)->name);
267 static int dict_vendor_name_cmp(void const *one, void const *two)
269 DICT_VENDOR const *a = one;
270 DICT_VENDOR const *b = two;
272 return strcasecmp(a->name, b->name);
275 static uint32_t dict_vendor_value_hash(void const *data)
277 return fr_hash(&(((DICT_VENDOR const *)data)->vendorpec),
278 sizeof(((DICT_VENDOR const *)data)->vendorpec));
281 static int dict_vendor_value_cmp(void const *one, void const *two)
283 DICT_VENDOR const *a = one;
284 DICT_VENDOR const *b = two;
286 return a->vendorpec - b->vendorpec;
289 static uint32_t dict_value_name_hash(void const *data)
292 DICT_VALUE const *dval = data;
294 hash = dict_hashname(dval->name);
295 hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
296 return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
299 static int dict_value_name_cmp(void const *one, void const *two)
302 DICT_VALUE const *a = one;
303 DICT_VALUE const *b = two;
305 rcode = a->attr - b->attr;
306 if (rcode != 0) return rcode;
308 rcode = a->vendor - b->vendor;
309 if (rcode != 0) return rcode;
311 return strcasecmp(a->name, b->name);
314 static uint32_t dict_value_value_hash(void const *data)
317 DICT_VALUE const *dval = data;
319 hash = fr_hash(&dval->attr, sizeof(dval->attr));
320 hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
321 return fr_hash_update(&dval->value, sizeof(dval->value), hash);
324 static int dict_value_value_cmp(void const *one, void const *two)
327 DICT_VALUE const *a = one;
328 DICT_VALUE const *b = two;
330 if (a->vendor < b->vendor) return -1;
331 if (a->vendor > b->vendor) return +1;
333 rcode = a->attr - b->attr;
334 if (rcode != 0) return rcode;
336 return a->value - b->value;
341 * Free the list of stat buffers
343 static void dict_stat_free(void)
345 dict_stat_t *this, *next;
352 for (this = stat_head; this != NULL; this = next) {
357 stat_head = stat_tail = NULL;
362 * Add an entry to the list of stat buffers.
364 static void dict_stat_add(struct stat const *stat_buf)
368 this = malloc(sizeof(*this));
370 memset(this, 0, sizeof(*this));
372 memcpy(&(this->stat_buf), stat_buf, sizeof(this->stat_buf));
375 stat_head = stat_tail = this;
377 stat_tail->next = this;
384 * See if any dictionaries have changed. If not, don't
387 static int dict_stat_check(char const *dir, char const *file)
389 struct stat stat_buf;
394 * Nothing cached, all files are new.
396 if (!stat_head) return 0;
401 snprintf(buffer, sizeof(buffer), "%s/%s", dir, file);
402 if (stat(buffer, &stat_buf) < 0) return 0;
405 * Find the cache entry.
406 * FIXME: use a hash table.
407 * FIXME: check dependencies, via children.
408 * if A loads B and B changes, we probably want
409 * to reload B at the minimum.
411 for (this = stat_head; this != NULL; this = this->next) {
412 if (this->stat_buf.st_dev != stat_buf.st_dev) continue;
413 if (this->stat_buf.st_ino != stat_buf.st_ino) continue;
416 * The file has changed. Re-read it.
418 if (this->stat_buf.st_mtime < stat_buf.st_mtime) return 0;
421 * The file is the same. Ignore it.
432 typedef struct fr_pool_t {
435 struct fr_pool_t *page_free;
436 struct fr_pool_t *page_next;
439 #define FR_POOL_SIZE (32768)
440 #define FR_ALLOC_ALIGN (8)
442 static fr_pool_t *dict_pool = NULL;
444 static fr_pool_t *fr_pool_create(void)
446 fr_pool_t *fp = malloc(FR_POOL_SIZE);
448 if (!fp) return NULL;
450 memset(fp, 0, FR_POOL_SIZE);
452 fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
453 fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
455 fp->page_next = NULL;
459 static void fr_pool_delete(fr_pool_t **pfp)
461 fr_pool_t *fp, *next;
463 if (!pfp || !*pfp) return;
465 for (fp = *pfp; fp != NULL; fp = next) {
466 next = fp->page_next;
467 fp->page_next = NULL;
474 static void *fr_pool_alloc(size_t size)
478 if (size == 0) return NULL;
480 if (size > 256) return NULL; /* shouldn't happen */
483 dict_pool = fr_pool_create();
484 if (!dict_pool) return NULL;
487 if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
488 size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
491 if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
492 dict_pool->page_free->page_next = fr_pool_create();
493 if (!dict_pool->page_free->page_next) return NULL;
494 dict_pool->page_free = dict_pool->page_free->page_next;
497 ptr = dict_pool->page_free->free_ptr;
498 dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
504 static void fr_pool_free(UNUSED void *ptr)
507 * Place-holder for later code.
512 * Free the dictionary_attributes and dictionary_values lists.
519 fr_hash_table_free(vendors_byname);
520 fr_hash_table_free(vendors_byvalue);
521 vendors_byname = NULL;
522 vendors_byvalue = NULL;
524 fr_hash_table_free(attributes_byname);
525 fr_hash_table_free(attributes_byvalue);
526 fr_hash_table_free(attributes_combo);
527 attributes_byname = NULL;
528 attributes_byvalue = NULL;
529 attributes_combo = NULL;
531 fr_hash_table_free(values_byname);
532 fr_hash_table_free(values_byvalue);
533 values_byname = NULL;
534 values_byvalue = NULL;
536 memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
538 fr_pool_delete(&dict_pool);
544 * Add vendor to the list.
546 int dict_addvendor(char const *name, unsigned int value)
551 if (value >= FR_MAX_VENDOR) {
552 fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
556 if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
557 fr_strerror_printf("dict_addvendor: vendor name too long");
561 if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
562 fr_strerror_printf("dict_addvendor: out of memory");
566 strcpy(dv->name, name);
567 dv->vendorpec = value;
568 dv->type = dv->length = 1; /* defaults */
570 if (!fr_hash_table_insert(vendors_byname, dv)) {
573 old_dv = fr_hash_table_finddata(vendors_byname, dv);
575 fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
578 if (old_dv->vendorpec != dv->vendorpec) {
579 fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
584 * Already inserted. Discard the duplicate entry.
591 * Insert the SAME pointer (not free'd when this table is
592 * deleted), into another table.
594 * We want this behaviour because we want OLD names for
595 * the attributes to be read from the configuration
596 * files, but when we're printing them, (and looking up
597 * by value) we want to use the NEW name.
599 if (!fr_hash_table_replace(vendors_byvalue, dv)) {
600 fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
612 const int dict_attr_allowed_chars[256] = {
613 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
615 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
616 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
617 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
618 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
619 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
620 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
623 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
624 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
625 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
626 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
627 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
628 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
633 * Add an attribute to the dictionary.
635 int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type,
639 static int max_attr = 0;
644 namelen = strlen(name);
645 if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
646 fr_strerror_printf("dict_addattr: attribute name too long");
650 for (p = (uint8_t const *) name; *p != '\0'; p++) {
651 if (!dict_attr_allowed_chars[*p]) {
652 fr_strerror_printf("dict_addattr: Invalid character '%c' in attribute name", *p);
658 !((type == PW_TYPE_INTEGER) || (type == PW_TYPE_STRING))) {
659 fr_strerror_printf("dict_addattr: Only 'integer' and 'string' attributes can have tags");
665 * If the attr is '-1', that means use a pre-existing
666 * one (if it already exists). If one does NOT already exist,
667 * then create a new attribute, with a non-conflicting value,
671 if (dict_attrbyname(name)) {
672 return 0; /* exists, don't add it again */
677 } else if (vendor == 0) {
681 if (attr > max_attr) {
687 * Additional checks for extended attributes.
689 if (flags.extended || flags.long_extended || flags.evs) {
690 if (vendor && (vendor < FR_MAX_VENDOR)) {
691 fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats");
698 || (flags.encrypt != FLAG_ENCRYPT_NONE)) {
699 fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set");
705 if (!(flags.extended || flags.long_extended)) {
706 fr_strerror_printf("dict_addattr: Attributes of type \"evs\" MUST have a parent of type \"extended\"");
710 /* VSAs cannot be of format EVS */
711 if ((vendor & (FR_MAX_VENDOR - 1)) != 0) {
712 fr_strerror_printf("dict_addattr: Attribute of type \"evs\" fails internal sanity check");
718 * Allow for generic pointers
727 flags.is_pointer = true;
732 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
736 if (flags.has_tlv && flags.length) {
737 fr_strerror_printf("TLVs cannot have a fixed length");
741 if (vendor && flags.concat) {
742 fr_strerror_printf("VSAs cannot have the \"concat\" flag set");
746 if (flags.concat && (type != PW_TYPE_OCTETS)) {
747 fr_strerror_printf("The \"concat\" flag can only be set for attributes of type \"octets\"");
751 if (flags.concat && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
752 flags.length || flags.evs || flags.extended || flags.long_extended ||
753 (flags.encrypt != FLAG_ENCRYPT_NONE))) {
754 fr_strerror_printf("The \"concat\" flag cannot be used with any other flag");
758 if ((vendor & (FR_MAX_VENDOR -1)) != 0) {
760 static DICT_VENDOR *last_vendor = NULL;
762 if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
763 fr_strerror_printf("TLV's cannot be encrypted");
767 if (flags.is_tlv && flags.has_tag) {
768 fr_strerror_printf("Sub-TLV's cannot have a tag");
772 if (flags.has_tlv && flags.has_tag) {
773 fr_strerror_printf("TLV's cannot have a tag");
778 * Most ATTRIBUTEs are bunched together by
779 * VENDOR. We can save a lot of lookups on
780 * dictionary initialization by caching the last
784 ((vendor & (FR_MAX_VENDOR - 1)) == last_vendor->vendorpec)) {
788 * Ignore the high byte (sigh)
790 dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
795 * If the vendor isn't defined, die.
798 fr_strerror_printf("dict_addattr: Unknown vendor %u",
799 vendor & (FR_MAX_VENDOR - 1));
804 * FIXME: Switch over dv->type, and limit things
807 if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
808 fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255)");
810 } /* else 256..65535 are allowed */
813 * If the attribute is in the standard space, AND
814 * has a sub-type (e.g. 241.1 or 255.3), then its
815 * number is placed into the upper 8 bits of the
818 * This also happens for the new VSAs.
820 * If we find it, then set the various flags
821 * based on what we see.
823 if (vendor >= FR_MAX_VENDOR) {
826 parent = (vendor / FR_MAX_VENDOR) & 0xff;
828 da = dict_attrbyvalue(parent, 0);
830 fr_strerror_printf("dict_addattr: ATTRIBUTE refers to unknown parent attribute %u.", parent);
835 * These flags are inherited from the
838 flags.extended = da->flags.extended;
839 flags.long_extended = da->flags.long_extended;
842 * Non-extended attributes can't have VSAs.
844 if (!flags.extended &&
845 ((vendor & (FR_MAX_VENDOR - 1)) != 0)) {
846 fr_strerror_printf("dict_addattr: ATTRIBUTE cannot be a VSA");
850 if ((vendor & (FR_MAX_VENDOR - 1)) != 0) {
856 * <sigh> Alvarion, being *again* a horribly
857 * broken vendor, has re-used the WiMAX format in
858 * their proprietary vendor space. This re-use
859 * means that there are *multiple* conflicting
860 * Alvarion dictionaries.
862 flags.wimax = dv->flags;
866 * Create a new attribute for the list
868 if ((n = fr_pool_alloc(sizeof(*n) + namelen)) == NULL) {
870 fr_strerror_printf("dict_addattr: out of memory");
874 memcpy(n->name, name, namelen);
875 n->name[namelen] = '\0';
882 * Insert the attribute, only if it's not a duplicate.
884 if (!fr_hash_table_insert(attributes_byname, n)) {
888 * If the attribute has identical number, then
889 * ignore the duplicate.
891 a = fr_hash_table_finddata(attributes_byname, n);
892 if (a && (strcasecmp(a->name, n->name) == 0)) {
893 if (a->attr != n->attr) {
894 fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
900 * Same name, same vendor, same attr,
901 * maybe the flags and/or type is
902 * different. Let the new value
903 * over-ride the old one.
908 fr_hash_table_delete(attributes_byvalue, a);
910 if (!fr_hash_table_replace(attributes_byname, n)) {
911 fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
918 * Insert the SAME pointer (not free'd when this entry is
919 * deleted), into another table.
921 * We want this behaviour because we want OLD names for
922 * the attributes to be read from the configuration
923 * files, but when we're printing them, (and looking up
924 * by value) we want to use the NEW name.
926 if (!fr_hash_table_replace(attributes_byvalue, n)) {
927 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
934 if (n->type == PW_TYPE_IP_ADDR) {
937 v4 = fr_pool_alloc(sizeof(*v4));
940 v6 = fr_pool_alloc(sizeof(*v6));
943 memcpy(v4, n, sizeof(*v4));
944 v4->type = PW_TYPE_IPV4_ADDR;
946 memcpy(v6, n, sizeof(*v6));
947 v6->type = PW_TYPE_IPV6_ADDR;
948 if (!fr_hash_table_replace(attributes_combo, v4)) {
949 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv4", name);
953 if (!fr_hash_table_replace(attributes_combo, v6)) {
954 fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv6", name);
959 if (!vendor && (attr > 0) && (attr < 256)) {
960 dict_base_attrs[attr] = n;
968 * Add a value for an attribute to the dictionary.
970 int dict_addvalue(char const *namestr, char const *attrstr, int value)
976 static DICT_ATTR const *last_attr = NULL;
979 fr_strerror_printf("dict_addvalue: empty names are not permitted");
983 if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
984 fr_strerror_printf("dict_addvalue: value name too long");
988 if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
989 fr_strerror_printf("dict_addvalue: out of memory");
992 memset(dval, 0, sizeof(*dval));
994 strcpy(dval->name, namestr);
998 * Most VALUEs are bunched together by ATTRIBUTE. We can
999 * save a lot of lookups on dictionary initialization by
1000 * caching the last attribute.
1002 if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
1005 da = dict_attrbyname(attrstr);
1010 * Remember which attribute is associated with this
1011 * value, if possible.
1014 if (da->flags.has_value_alias) {
1015 fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
1019 dval->attr = da->attr;
1020 dval->vendor = da->vendor;
1023 * Enforce valid values
1025 * Don't worry about fixups...
1031 fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
1036 if (value > 65535) {
1038 fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
1044 * Allow octets for now, because
1045 * of dictionary.cablelabs
1047 case PW_TYPE_OCTETS:
1049 case PW_TYPE_INTEGER:
1052 case PW_TYPE_INTEGER64:
1055 fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
1056 fr_int2str(dict_attr_types, da->type, "?Unknown?"));
1060 value_fixup_t *fixup;
1062 fixup = (value_fixup_t *) malloc(sizeof(*fixup));
1065 fr_strerror_printf("dict_addvalue: out of memory");
1068 memset(fixup, 0, sizeof(*fixup));
1070 strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
1074 * Insert to the head of the list.
1076 fixup->next = value_fixup;
1077 value_fixup = fixup;
1083 * Add the value into the dictionary.
1087 memcpy(&tmp, &dval, sizeof(tmp));
1089 if (!fr_hash_table_insert(values_byname, tmp)) {
1094 * Suppress duplicates with the same
1095 * name and value. There are lots in
1096 * dictionary.ascend.
1098 old = dict_valbyname(da->attr, da->vendor, namestr);
1099 if (old && (old->value == dval->value)) {
1106 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
1112 * There are multiple VALUE's, keyed by attribute, so we
1113 * take care of that here.
1115 if (!fr_hash_table_replace(values_byvalue, dval)) {
1116 fr_strerror_printf("dict_addvalue: Failed inserting value %s",
1124 static int sscanf_i(char const *str, unsigned int *pvalue)
1128 static char const *tab = "0123456789";
1130 if ((str[0] == '0') &&
1131 ((str[1] == 'x') || (str[1] == 'X'))) {
1132 tab = "0123456789abcdef";
1141 if (*str == '.') break;
1143 c = memchr(tab, tolower((int) *str), base);
1157 * Get the OID based on various pieces of information.
1159 * Remember, the packing format is weird.
1161 * 00VID 000000AA normal VSA for vendor VID
1162 * 00VID AABBCCDD normal VSAs with TLVs
1163 * EE000 000000AA extended attr (241.1)
1164 * EE000 AABBCCDD extended attr with TLVs
1165 * EEVID 000000AA EVS with vendor VID, attr AAA
1166 * EEVID AABBCCDD EVS with TLVs
1168 * <whew>! Are we crazy, or what?
1170 int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor,
1175 DICT_ATTR const *da = NULL;
1177 if (tlv_depth > fr_attr_max_tlv) {
1178 fr_strerror_printf("Too many sub-attributes");
1183 * If *pvalue is set, check if the attribute exists.
1184 * Otherwise, check that the vendor exists.
1187 da = dict_attrbyvalue(*pvalue, *pvendor);
1189 fr_strerror_printf("Parent attribute is undefined");
1193 if (!da->flags.has_tlv && !da->flags.extended) {
1194 fr_strerror_printf("Parent attribute %s cannot have sub-attributes",
1199 } else if ((*pvendor & (FR_MAX_VENDOR - 1)) != 0) {
1200 if (!dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1))) {
1201 fr_strerror_printf("Unknown vendor %u",
1202 *pvendor & (FR_MAX_VENDOR - 1));
1207 p = strchr(ptr, '.');
1210 * Look for 26.VID.x.y
1212 * If we find it, re-write the parameters, and recurse.
1214 if (!*pvendor && (tlv_depth == 0) && (*pvalue == PW_VENDOR_SPECIFIC)) {
1215 DICT_VENDOR const *dv;
1218 fr_strerror_printf("VSA needs to have sub-attribute");
1222 if (!sscanf_i(ptr, pvendor)) {
1223 fr_strerror_printf("Invalid number in attribute");
1227 if (*pvendor >= FR_MAX_VENDOR) {
1228 fr_strerror_printf("Cannot handle vendor ID larger than 2^24");
1233 dv = dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1));
1235 fr_strerror_printf("Unknown vendor \"%u\" ",
1236 *pvendor & (FR_MAX_VENDOR - 1));
1241 * Start off with (attr=0, vendor=VID), and
1242 * recurse. This causes the various checks above
1246 return dict_str2oid(p + 1, pvalue, pvendor, 0);
1249 if (!sscanf_i(ptr, &value)) {
1250 fr_strerror_printf("Invalid number in attribute");
1254 if (!*pvendor && (tlv_depth == 1) && da &&
1255 (da->flags.has_tlv || da->flags.extended)) {
1258 *pvendor = *pvalue * FR_MAX_VENDOR;
1262 return dict_str2oid(p + 1, pvalue, pvendor, 1);
1266 * And pack the data according to the scheme described in
1267 * the comments at the start of this function.
1270 *pvalue |= (value & fr_attr_mask[tlv_depth]) << fr_attr_shift[tlv_depth];
1276 return dict_str2oid(p + 1, pvalue, pvendor, tlv_depth + 1);
1283 * Bamboo skewers under the fingernails in 5, 4, 3, 2, ...
1285 static DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor)
1287 if (vendor < FR_MAX_VENDOR) {
1288 return dict_attrbyvalue(attr & 0xff, vendor);
1292 return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0);
1295 return dict_attrbyvalue(attr & 0xff, vendor);
1300 * Process the ATTRIBUTE command
1302 static int process_attribute(char const* fn, int const line,
1303 unsigned int block_vendor,
1304 DICT_ATTR const *block_tlv, int tlv_depth,
1305 char **argv, int argc)
1308 unsigned int vendor = 0;
1311 unsigned int length = 0;
1315 if ((argc < 3) || (argc > 4)) {
1316 fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
1322 * Dictionaries need to have real names, not shitty ones.
1324 if (strncmp(argv[1], "Attr-", 5) == 0) {
1325 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
1330 memset(&flags, 0, sizeof(flags));
1333 * Look for OIDs before doing anything else.
1335 p = strchr(argv[1], '.');
1339 * Validate all entries
1341 if (!sscanf_i(argv[1], &value)) {
1342 fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
1347 DICT_ATTR const *da;
1349 vendor = block_vendor;
1352 * Parse the rest of the OID.
1354 if (dict_str2oid(p + 1, &value, &vendor, tlv_depth + 1) < 0) {
1357 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1359 fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
1362 block_vendor = vendor;
1365 * Set the flags based on the parents flags.
1367 da = dict_parent(value, vendor);
1369 fr_strerror_printf("dict_init: %s[%d]: Parent attribute is undefined.", fn, line);
1373 flags.extended = da->flags.extended;
1374 flags.long_extended = da->flags.long_extended;
1375 flags.evs = da->flags.evs;
1376 if (da->flags.has_tlv) flags.is_tlv = 1;
1379 if (strncmp(argv[2], "octets[", 7) != 0) {
1381 * find the type of the attribute.
1383 type = fr_str2int(dict_attr_types, argv[2], -1);
1385 fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
1391 type = PW_TYPE_OCTETS;
1393 p = strchr(argv[2] + 7, ']');
1395 fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
1401 if (!sscanf_i(argv[1], &length)) {
1402 fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1406 if ((length == 0) || (length > 253)) {
1407 fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
1413 * Only look up the vendor if the string
1418 * Force "length" for data types of fixed length;
1430 case PW_TYPE_IPV4_ADDR:
1431 case PW_TYPE_INTEGER:
1432 case PW_TYPE_SIGNED:
1436 case PW_TYPE_INTEGER64:
1440 case PW_TYPE_ETHERNET:
1448 case PW_TYPE_IPV6_ADDR:
1452 case PW_TYPE_EXTENDED:
1453 if ((vendor != 0) || (value < 241)) {
1454 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"extended\" MUST be RFC attributes with value >= 241.", fn, line);
1460 case PW_TYPE_LONG_EXTENDED:
1461 if ((vendor != 0) || (value < 241)) {
1462 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"long-extended\" MUST be RFC attributes with value >= 241.", fn, line);
1466 flags.long_extended = 1;
1472 if (value != PW_VENDOR_SPECIFIC) {
1473 fr_strerror_printf("dict_init: %s[%d]: Attributes of type \"evs\" MUST have attribute code 26.", fn, line);
1482 flags.length = length;
1484 } else { /* argc == 4: we have options */
1485 char *key, *next, *last;
1490 if (flags.extended) {
1491 fr_strerror_printf("dict_init: %s[%d]: Extended attributes cannot use flags", fn, line);
1496 fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line);
1502 next = strchr(key, ',');
1503 if (next) *(next++) = '\0';
1505 if (strcmp(key, "has_tag") == 0 ||
1506 strcmp(key, "has_tag=1") == 0) {
1507 /* Boolean flag, means this is a
1511 } else if (strncmp(key, "encrypt=", 8) == 0) {
1512 /* Encryption method, defaults to 0 (none).
1513 Currently valid is just type 2,
1514 Tunnel-Password style, which can only
1515 be applied to strings. */
1516 flags.encrypt = strtol(key + 8, &last, 0);
1518 fr_strerror_printf( "dict_init: %s[%d] invalid option %s",
1523 if ((flags.encrypt == FLAG_ENCRYPT_ASCEND_SECRET) &&
1524 (type != PW_TYPE_STRING)) {
1525 fr_strerror_printf( "dict_init: %s[%d] Only \"string\" types can have the \"encrypt=3\" flag set.",
1530 } else if (strncmp(key, "array", 6) == 0) {
1534 case PW_TYPE_IPV4_ADDR:
1535 case PW_TYPE_IPV6_ADDR:
1538 case PW_TYPE_INTEGER:
1540 case PW_TYPE_STRING:
1544 fr_strerror_printf( "dict_init: %s[%d] \"%s\" type cannot have the "
1545 "\"array\" flag set",
1547 fr_int2str(dict_attr_types, type, "<UNKNOWN>"));
1551 } else if (strncmp(key, "concat", 6) == 0) {
1554 if (type != PW_TYPE_OCTETS) {
1555 fr_strerror_printf( "dict_init: %s[%d] Only \"octets\" type can have the \"concat\" flag set.",
1561 * The only thing is the vendor name,
1562 * and it's a known name: allow it.
1564 } else if ((key == argv[3]) && !next) {
1566 fr_strerror_printf( "dict_init: %s[%d] New-style attributes cannot use a vendor flag.",
1572 fr_strerror_printf( "dict_init: %s[%d] Vendor flag inside of \"BEGIN-VENDOR\" is not allowed.",
1577 vendor = dict_vendorbyname(key);
1578 if (!vendor) goto unknown;
1583 fr_strerror_printf( "dict_init: %s[%d]: unknown option \"%s\"",
1589 if (key && !*key) break;
1593 if (block_vendor) vendor = block_vendor;
1596 * Special checks for tags, they make our life much more
1599 if (flags.has_tag) {
1601 * Only string, octets, and integer can be tagged.
1604 case PW_TYPE_STRING:
1605 case PW_TYPE_INTEGER:
1609 fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
1611 fr_int2str(dict_attr_types, type, "?Unknown?"));
1616 if (type == PW_TYPE_TLV) {
1617 if (vendor && (vendor < FR_MAX_VENDOR)
1619 && (vendor != DHCP_MAGIC_VENDOR)
1624 dv = dict_vendorbyvalue(vendor);
1625 if (!dv || (dv->type != 1) || (dv->length != 1)) {
1626 fr_strerror_printf("dict_init: %s[%d]: Type \"tlv\" can only be for \"format=1,1\".",
1637 * TLV's can be only one octet.
1639 if ((value == 0) || ((value & ~fr_attr_mask[tlv_depth]) != 0)) {
1640 fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
1648 value <<= fr_attr_shift[tlv_depth];
1649 value |= block_tlv->attr;
1653 #ifdef WITH_DICTIONARY_WARNINGS
1655 * Hack to help us discover which vendors have illegal
1658 if (!vendor && (value < 256) &&
1659 !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
1660 fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
1668 if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
1671 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1673 fr_strerror_printf("dict_init: %s[%d]: %s",
1683 * Process the VALUE command
1685 static int process_value(char const* fn, int const line, char **argv,
1691 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
1696 * For Compatibility, skip "Server-Config"
1698 if (strcasecmp(argv[0], "Server-Config") == 0)
1702 * Validate all entries
1704 if (!sscanf_i(argv[2], &value)) {
1705 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1710 if (dict_addvalue(argv[1], argv[0], value) < 0) {
1713 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1715 fr_strerror_printf("dict_init: %s[%d]: %s",
1725 * Process the VALUE-ALIAS command
1727 * This allows VALUE mappings to be shared among multiple
1730 static int process_value_alias(char const* fn, int const line, char **argv,
1733 DICT_ATTR const *my_da, *da;
1737 fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
1742 my_da = dict_attrbyname(argv[0]);
1744 fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
1749 if (my_da->flags.has_value_alias) {
1750 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
1755 da = dict_attrbyname(argv[1]);
1757 fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
1762 if (da->flags.has_value_alias) {
1763 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
1768 if (my_da->type != da->type) {
1769 fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
1774 if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
1775 fr_strerror_printf("dict_addvalue: out of memory");
1779 dval->name[0] = '\0'; /* empty name */
1780 dval->attr = my_da->attr;
1781 dval->vendor = my_da->vendor;
1782 dval->value = da->attr;
1784 if (!fr_hash_table_insert(values_byname, dval)) {
1785 fr_strerror_printf("dict_init: %s[%d]: Error create alias",
1796 * Process the VENDOR command
1798 static int process_vendor(char const* fn, int const line, char **argv,
1802 bool continuation = false;
1803 char const *format = NULL;
1805 if ((argc < 2) || (argc > 3)) {
1806 fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
1812 * Validate all entries
1814 if (!isdigit((int) argv[1][0])) {
1815 fr_strerror_printf("dict_init: %s[%d]: invalid value",
1819 value = atoi(argv[1]);
1821 /* Create a new VENDOR entry for the list */
1822 if (dict_addvendor(argv[0], value) < 0) {
1825 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1827 fr_strerror_printf("dict_init: %s[%d]: %s",
1833 * Look for a format statement
1838 } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
1839 format = "format=4,0";
1841 } else if (value == VENDORPEC_LUCENT) {
1842 format = "format=2,1";
1844 } else if (value == VENDORPEC_STARENT) {
1845 format = "format=2,2";
1847 } /* else no fixups to do */
1854 if (strncasecmp(format, "format=", 7) != 0) {
1855 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected \"format=\", got \"%s\"",
1861 if ((strlen(p) < 3) ||
1862 !isdigit((int) p[0]) ||
1864 !isdigit((int) p[2]) ||
1865 (p[3] && (p[3] != ','))) {
1866 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
1871 type = (int) (p[0] - '0');
1872 length = (int) (p[2] - '0');
1876 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
1881 if ((p[4] != 'c') ||
1883 fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
1887 continuation = true;
1889 if ((value != VENDORPEC_WIMAX) ||
1890 (type != 1) || (length != 1)) {
1891 fr_strerror_printf("dict_init: %s[%d]: Only WiMAX VSAs can have continuations",
1897 dv = dict_vendorbyvalue(value);
1899 fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
1904 if ((type != 1) && (type != 2) && (type != 4)) {
1905 fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
1910 if ((length != 0) && (length != 1) && (length != 2)) {
1911 fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
1917 dv->length = length;
1918 dv->flags = continuation;
1925 * String split routine. Splits an input string IN PLACE
1926 * into pieces, based on spaces.
1928 int str2argv(char *str, char **argv, int max_argc)
1933 if (argc >= max_argc) break;
1936 * Chop out comments early.
1943 while ((*str == ' ') ||
1946 (*str == '\n')) *(str++) = '\0';
1957 (*str != '\n')) str++;
1963 static int my_dict_init(char const *parent, char const *filename,
1964 char const *src_file, int src_line);
1966 int dict_read(char const *dir, char const *filename)
1968 if (!attributes_byname) {
1969 fr_strerror_printf("Must call dict_init() before dict_read()");
1973 return my_dict_init(dir, filename, NULL, 0);
1977 #define MAX_ARGV (16)
1980 * Initialize the dictionary.
1982 static int my_dict_init(char const *parent, char const *filename,
1983 char const *src_file, int src_line)
1986 char dir[256], fn[256];
1990 unsigned int vendor;
1991 unsigned int block_vendor;
1992 struct stat statbuf;
1993 char *argv[MAX_ARGV];
1995 DICT_ATTR const *da, *block_tlv[MAX_TLV_NEST + 1];
1996 int which_block_tlv = 0;
1998 block_tlv[0] = NULL;
1999 block_tlv[1] = NULL;
2000 block_tlv[2] = NULL;
2001 block_tlv[3] = NULL;
2003 if ((strlen(parent) + 3 + strlen(filename)) > sizeof(dir)) {
2004 fr_strerror_printf("dict_init: filename name too long");
2009 * If it's an absolute dir, forget the parent dir,
2010 * and remember the new one.
2012 * If it's a relative dir, tack on the current filename
2013 * to the parent dir. And use that.
2015 if (!FR_DIR_IS_RELATIVE(filename)) {
2016 strlcpy(dir, filename, sizeof(dir));
2017 p = strrchr(dir, FR_DIR_SEP);
2021 strlcat(dir, "/", sizeof(dir));
2024 strlcpy(fn, filename, sizeof(fn));
2026 strlcpy(dir, parent, sizeof(dir));
2027 p = strrchr(dir, FR_DIR_SEP);
2029 if (p[1]) strlcat(dir, "/", sizeof(dir));
2031 strlcat(dir, "/", sizeof(dir));
2033 strlcat(dir, filename, sizeof(dir));
2034 p = strrchr(dir, FR_DIR_SEP);
2038 strlcat(dir, "/", sizeof(dir));
2041 p = strrchr(filename, FR_DIR_SEP);
2043 snprintf(fn, sizeof(fn), "%s%s", dir, p);
2045 snprintf(fn, sizeof(fn), "%s%s", dir, filename);
2051 * Check if we've loaded this file before. If so, ignore it.
2053 p = strrchr(fn, FR_DIR_SEP);
2056 if (dict_stat_check(fn, p + 1)) {
2063 if ((fp = fopen(fn, "r")) == NULL) {
2065 fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
2066 fn, fr_syserror(errno));
2068 fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
2069 src_file, src_line, fn, fr_syserror(errno));
2074 stat(fn, &statbuf); /* fopen() guarantees this will succeed */
2075 if (!S_ISREG(statbuf.st_mode)) {
2077 fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
2083 * Globally writable dictionaries means that users can control
2084 * the server configuration with little difficulty.
2087 if ((statbuf.st_mode & S_IWOTH) != 0) {
2089 fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable. Refusing to start due to insecure configuration.",
2095 dict_stat_add(&statbuf);
2098 * Seed the random pool with data.
2100 fr_rand_seed(&statbuf, sizeof(statbuf));
2104 while (fgets(buf, sizeof(buf), fp) != NULL) {
2106 if (buf[0] == '#' || buf[0] == 0 ||
2107 buf[0] == '\n' || buf[0] == '\r')
2111 * Comment characters should NOT be appearing anywhere but
2112 * as start of a comment;
2114 p = strchr(buf, '#');
2117 argc = str2argv(buf, argv, MAX_ARGV);
2118 if (argc == 0) continue;
2121 fr_strerror_printf( "dict_init: %s[%d] invalid entry",
2128 * Process VALUE lines.
2130 if (strcasecmp(argv[0], "VALUE") == 0) {
2131 if (process_value(fn, line,
2132 argv + 1, argc - 1) == -1) {
2140 * Perhaps this is an attribute.
2142 if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
2143 if (process_attribute(fn, line, block_vendor,
2144 block_tlv[which_block_tlv],
2146 argv + 1, argc - 1) == -1) {
2154 * See if we need to import another dictionary.
2156 if (strcasecmp(argv[0], "$INCLUDE") == 0) {
2157 if (my_dict_init(dir, argv[1], fn, line) < 0) {
2165 * Optionally include a dictionary
2167 if (strcasecmp(argv[0], "$INCLUDE-") == 0) {
2168 int rcode = my_dict_init(dir, argv[1], fn, line);
2170 if (rcode == -2) continue;
2179 if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
2180 if (process_value_alias(fn, line,
2181 argv + 1, argc - 1) == -1) {
2189 * Process VENDOR lines.
2191 if (strcasecmp(argv[0], "VENDOR") == 0) {
2192 if (process_vendor(fn, line,
2193 argv + 1, argc - 1) == -1) {
2200 if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
2203 "dict_init: %s[%d] invalid BEGIN-TLV entry",
2209 da = dict_attrbyname(argv[1]);
2212 "dict_init: %s[%d]: unknown attribute %s",
2218 if (da->type != PW_TYPE_TLV) {
2220 "dict_init: %s[%d]: attribute %s is not of type tlv",
2226 if (which_block_tlv >= MAX_TLV_NEST) {
2228 "dict_init: %s[%d]: TLVs are nested too deep",
2235 block_tlv[++which_block_tlv] = da;
2239 if (strcasecmp(argv[0], "END-TLV") == 0) {
2242 "dict_init: %s[%d] invalid END-TLV entry",
2248 da = dict_attrbyname(argv[1]);
2251 "dict_init: %s[%d]: unknown attribute %s",
2257 if (da != block_tlv[which_block_tlv]) {
2259 "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
2264 block_tlv[which_block_tlv--] = NULL;
2268 if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
2271 "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
2277 vendor = dict_vendorbyname(argv[1]);
2280 "dict_init: %s[%d]: unknown vendor %s",
2286 block_vendor = vendor;
2289 * Check for extended attr VSAs
2291 * BEGIN-VENDOR foo format=Foo-Encapsulation-Attr
2294 if (strncmp(argv[2], "format=", 7) != 0) {
2296 "dict_init: %s[%d]: Invalid format %s",
2303 da = dict_attrbyname(p);
2305 fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR: unknown attribute \"%s\"",
2311 if (!da->flags.evs) {
2312 fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR. Attribute \"%s\" is not of \"evs\" data type",
2319 * Pack the encapsulating
2320 * attribute into the upper 8
2321 * bits of the vendor ID
2323 block_vendor |= (da->attr & fr_attr_mask[0]) * FR_MAX_VENDOR;
2327 } /* BEGIN-VENDOR */
2329 if (strcasecmp(argv[0], "END-VENDOR") == 0) {
2332 "dict_init: %s[%d] invalid END-VENDOR entry",
2338 vendor = dict_vendorbyname(argv[1]);
2341 "dict_init: %s[%d]: unknown vendor %s",
2347 if (vendor != (block_vendor & (FR_MAX_VENDOR - 1))) {
2349 "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
2359 * Any other string: We don't recognize it.
2361 fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
2372 * Empty callback for hash table initialization.
2374 static int null_callback(UNUSED void *ctx, UNUSED void *data)
2381 * Initialize the directory, then fix the attr member of
2384 int dict_init(char const *dir, char const *fn)
2387 * Check if we need to change anything. If not, don't do
2390 if (dict_stat_check(dir, fn)) {
2395 * Free the dictionaries, and the stat cache.
2400 * Create the table of vendor by name. There MAY NOT
2401 * be multiple vendors of the same name.
2403 * Each vendor is malloc'd, so the free function is free.
2405 vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
2406 dict_vendor_name_cmp,
2408 if (!vendors_byname) {
2413 * Create the table of vendors by value. There MAY
2414 * be vendors of the same value. If there are, we
2415 * pick the latest one.
2417 vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
2418 dict_vendor_value_cmp,
2420 if (!vendors_byvalue) {
2425 * Create the table of attributes by name. There MAY NOT
2426 * be multiple attributes of the same name.
2428 * Each attribute is malloc'd, so the free function is free.
2430 attributes_byname = fr_hash_table_create(dict_attr_name_hash,
2433 if (!attributes_byname) {
2438 * Create the table of attributes by value. There MAY
2439 * be attributes of the same value. If there are, we
2440 * pick the latest one.
2442 attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
2443 dict_attr_value_cmp,
2445 if (!attributes_byvalue) {
2450 * Horrible hacks for combo-IP.
2452 attributes_combo = fr_hash_table_create(dict_attr_combo_hash,
2453 dict_attr_combo_cmp,
2455 if (!attributes_combo) {
2459 values_byname = fr_hash_table_create(dict_value_name_hash,
2460 dict_value_name_cmp,
2462 if (!values_byname) {
2466 values_byvalue = fr_hash_table_create(dict_value_value_hash,
2467 dict_value_value_cmp,
2469 if (!values_byvalue) {
2473 value_fixup = NULL; /* just to be safe. */
2475 if (my_dict_init(dir, fn, NULL, 0) < 0)
2480 value_fixup_t *this, *next;
2482 for (this = value_fixup; this != NULL; this = next) {
2485 a = dict_attrbyname(this->attrstr);
2488 "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
2489 this->attrstr, this->dval->name);
2490 return -1; /* leak, but they should die... */
2493 this->dval->attr = a->attr;
2496 * Add the value into the dictionary.
2498 if (!fr_hash_table_replace(values_byname,
2500 fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
2505 * Allow them to use the old name, but
2506 * prefer the new name when printing
2509 if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
2510 fr_hash_table_replace(values_byvalue,
2516 * Just so we don't lose track of things.
2523 * Walk over all of the hash tables to ensure they're
2524 * initialized. We do this because the threads may perform
2525 * lookups, and we don't want multi-threaded re-ordering
2526 * of the table entries. That would be bad.
2528 fr_hash_table_walk(vendors_byname, null_callback, NULL);
2529 fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
2531 fr_hash_table_walk(attributes_byname, null_callback, NULL);
2532 fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
2534 fr_hash_table_walk(values_byvalue, null_callback, NULL);
2535 fr_hash_table_walk(values_byname, null_callback, NULL);
2540 static size_t print_attr_oid(char *buffer, size_t size, unsigned int attr,
2549 return snprintf(buffer, size, "%u", attr);
2552 return snprintf(buffer, size, "%u", attr & 0xffff);
2556 len = snprintf(buffer, size, "%u", attr & 0xff);
2560 if ((attr >> 8) == 0) return len;
2566 for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
2567 if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
2569 len = snprintf(buffer, size, ".%u",
2570 (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
2580 /** Free dynamically allocated (unknown attributes)
2582 * If the da was dynamically allocated it will be freed, else the function
2583 * will return without doing anything.
2585 * @param da to free.
2587 void dict_attr_free(DICT_ATTR const **da)
2591 if (!da || !*da) return;
2593 /* Don't free real DAs */
2594 if (!(*da)->flags.is_unknown) {
2598 memcpy(&tmp, &da, sizeof(*tmp));
2604 /** Copies a dictionary attr
2606 * If the attr is dynamically allocated (unknown attribute), then it will be
2607 * copied to a new attr.
2609 * If the attr is known, a pointer to the da will be returned.
2611 * @param da to copy.
2612 * @param vp_free if true, da will be freed at the same time as the
2613 * VALUE_PAIR which contains it.
2614 * @return return a copy of the da.
2616 DICT_ATTR const *dict_attr_copy(DICT_ATTR const *da, int vp_free)
2620 if (!da) return NULL;
2622 if (!da->flags.is_unknown) {
2626 copy = malloc(DICT_ATTR_SIZE);
2628 fr_strerror_printf("Out of memory");
2632 memcpy(copy, da, DICT_ATTR_SIZE);
2633 copy->flags.vp_free = (vp_free != 0);
2639 /** Allocs an dictionary attr for unknown attributes
2641 * Allocates a dict attr for an unknown attribute/vendor/type
2642 * without adding it to dictionary pools/hashes.
2644 * @note Must be freed with dict_attr_free if not used as part of a valuepair.
2646 * @param[in] attr number.
2647 * @param[in] vendor number.
2648 * @param[in] vp_free if > 0 DICT_ATTR will be freed on VALUE_PAIR free.
2649 * @return new dictionary attribute.
2651 DICT_ATTR const *dict_attrunknown(unsigned int attr, unsigned int vendor,
2658 size_t bufsize = DICT_ATTR_MAX_NAME_LEN;
2660 da = malloc(DICT_ATTR_SIZE);
2662 fr_strerror_printf("Out of memory");
2665 memset(da, 0, DICT_ATTR_SIZE);
2668 da->vendor = vendor;
2669 da->type = PW_TYPE_OCTETS;
2670 da->flags.is_unknown = true;
2671 da->flags.vp_free = (vp_free != 0);
2674 * Unknown attributes of the "WiMAX" vendor get marked up
2675 * as being for WiMAX.
2677 if (vendor == VENDORPEC_WIMAX) {
2678 da->flags.wimax = 1;
2683 len = snprintf(p, bufsize, "Attr-");
2687 if (vendor > FR_MAX_VENDOR) {
2688 len = snprintf(p, bufsize, "%u.", vendor / FR_MAX_VENDOR);
2691 vendor &= (FR_MAX_VENDOR) - 1;
2698 * dv_type is the length of the vendor's type field
2699 * RFC 2865 never defined a mandatory length, so
2700 * different vendors have different length type fields.
2702 dv = dict_vendorbyvalue(vendor);
2706 len = snprintf(p, bufsize, "26.%u.", vendor);
2712 print_attr_oid(p, bufsize , attr, dv_type);
2717 /** Create a DICT_ATTR from an ASCII attribute and value
2719 * Where the attribute name is in the form:
2721 * - Attr-%d.%d.%d...
2722 * - Vendor-%d-Attr-%d
2723 * - VendorName-Attr-%d
2725 * @todo should check attr/vendor against dictionary and return the real da.
2727 * @param[in] attribute name.
2728 * @param[in] vp_free if > 0 DICT_ATTR will be freed on VALUE_PAIR free.
2729 * @return new da or NULL on error.
2731 DICT_ATTR const *dict_attrunknownbyname(char const *attribute, int vp_free)
2733 unsigned int attr, vendor = 0;
2734 unsigned int dv_type = 1; /* The type of vendor field */
2736 char const *p = attribute;
2740 DICT_ATTR const *da;
2743 * Pull off vendor prefix first.
2745 if (strncasecmp(p, "Attr-", 5) != 0) {
2746 if (strncasecmp(p, "Vendor-", 7) == 0) {
2747 vendor = (int) strtol(p + 7, &q, 10);
2748 if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
2749 fr_strerror_printf("Invalid vendor value in "
2750 "attribute name \"%s\"",
2757 /* must be vendor name */
2764 fr_strerror_printf("Invalid vendor name in "
2765 "attribute name \"%s\"",
2770 if ((size_t) (q - p) >= sizeof(buffer)) {
2771 fr_strerror_printf("Vendor name too long "
2772 "in attribute name \"%s\"",
2777 memcpy(buffer, p, (q - p));
2778 buffer[q - p] = '\0';
2780 vendor = dict_vendorbyname(buffer);
2782 fr_strerror_printf("Unknown attribute \"%s\"",
2791 fr_strerror_printf("Invalid text following vendor "
2792 "definition in attribute name "
2793 "\"%s\"", attribute);
2802 if (strncasecmp(p, "Attr-", 5) != 0) {
2803 fr_strerror_printf("Unknown attribute \"%s\"",
2808 attr = strtol(p + 5, &q, 10);
2811 * Invalid attribute.
2814 fr_strerror_printf("Invalid value in attribute name \"%s\"",
2823 * VendorName-Attr-%d
2827 * Anything else is invalid.
2829 if (((vendor != 0) && (*p != '\0')) ||
2830 ((vendor == 0) && *p && (*p != '.'))) {
2832 fr_strerror_printf("Invalid OID");
2837 * Look for OIDs. Require the "Attr-26.Vendor-Id.type"
2838 * format, and disallow "Vendor-%d-Attr-%d" and
2839 * "VendorName-Attr-%d"
2841 * This section parses the Vendor-Id portion of
2842 * Attr-%d.%d. where the first number is 26, *or* an
2843 * extended attribute of the "evs" data type.
2846 da = dict_attrbyvalue(attr, 0);
2848 fr_strerror_printf("Cannot parse attributes without "
2853 if ((attr != PW_VENDOR_SPECIFIC) &&
2854 !(da->flags.extended || da->flags.long_extended)) {
2855 fr_strerror_printf("Standard attributes cannot use "
2860 if ((attr == PW_VENDOR_SPECIFIC) || da->flags.evs) {
2861 vendor = strtol(p + 1, &q, 10);
2862 if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
2863 fr_strerror_printf("Invalid vendor");
2867 if (*q != '.') goto invalid;
2871 if (da->flags.evs) {
2872 vendor |= attr * FR_MAX_VENDOR;
2875 } /* else the second number is a TLV number */
2879 * Get the expected maximum size of the attribute.
2882 dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
2885 if (dv_type > 3) dv_type = 3; /* hack */
2890 * Parse the next number. It could be a Vendor-Type
2891 * of 1..2^24, or it could be a TLV.
2894 attr = strtol(p + 1, &q, 10);
2896 fr_strerror_printf("Invalid attribute number");
2914 * Enforce a maximum value on the attribute number.
2916 if (attr >= (unsigned) (1 << (dv_type << 3))) goto invalid;
2919 if (dict_str2oid(p + 1, &attr, &vendor, 1) < 0) {
2924 return dict_attrunknown(attr, vendor, vp_free);
2928 * Get an attribute by its numerical value.
2930 DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
2934 if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
2939 return fr_hash_table_finddata(attributes_byvalue, &da);
2944 * @brief Get an attribute by its numerical value. and data type
2946 * Used only for COMBO_IP
2948 * @return The attribute, or NULL if not found
2950 DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
2959 return fr_hash_table_finddata(attributes_combo, &da);
2963 * @brief Using a parent and attr/vendor, find a child attr/vendor
2965 int dict_attr_child(DICT_ATTR const *parent,
2966 unsigned int *pattr, unsigned int *pvendor)
2968 unsigned int attr, vendor;
2971 if (!parent || !pattr || !pvendor) return false;
2977 * Only some types can have children
2979 switch (parent->type) {
2980 default: return false;
2985 case PW_TYPE_EXTENDED:
2986 case PW_TYPE_LONG_EXTENDED:
2990 if ((vendor == 0) && (parent->vendor != 0)) return false;
2993 * Bootstrap by starting off with the parents values.
2995 da.attr = parent->attr;
2996 da.vendor = parent->vendor;
2999 * Do various butchery to insert the "attr" value.
3001 * 00VID 000000AA normal VSA for vendor VID
3002 * 00VID DDCCBBAA normal VSAs with TLVs
3003 * EE000 000000AA extended attr (241.1)
3004 * EE000 DDCCBBAA extended attr with TLVs
3005 * EEVID 000000AA EVS with vendor VID, attr AAA
3006 * EEVID DDCCBBAA EVS with TLVs
3009 da.vendor = parent->attr * FR_MAX_VENDOR;
3010 da.vendor |= vendor;
3017 * Trying to nest too deep. It's an error
3019 if (parent->attr & (fr_attr_mask[MAX_TLV_NEST] << fr_attr_shift[MAX_TLV_NEST])) {
3023 for (i = MAX_TLV_NEST - 1; i >= 0; i--) {
3024 if ((parent->attr & (fr_attr_mask[i] << fr_attr_shift[i]))) {
3025 da.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
3035 fprintf(stderr, "LOOKING FOR %08x %08x + %08x %08x --> %08x %08x\n",
3036 parent->vendor, parent->attr, attr, vendor,
3037 da.vendor, da.attr);
3041 *pvendor = da.vendor;
3046 * Get an attribute by it's numerical value, and the parent
3048 DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr, unsigned int vendor)
3050 unsigned int my_attr, my_vendor;
3056 if (!dict_attr_child(parent, &my_attr, &my_vendor)) return NULL;
3059 da.vendor = my_vendor;
3061 return fr_hash_table_finddata(attributes_byvalue, &da);
3066 * Get an attribute by its name.
3068 DICT_ATTR const *dict_attrbyname(char const *name)
3071 uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
3073 if (!name) return NULL;
3075 da = (DICT_ATTR *) buffer;
3076 strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
3078 return fr_hash_table_finddata(attributes_byname, da);
3082 * Get an attribute by its name, where the name might have a tag
3083 * or something else after it.
3085 DICT_ATTR const *dict_attrbytagged_name(char const *name)
3089 uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
3091 if (!name) return NULL;
3093 da = (DICT_ATTR *) buffer;
3094 strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
3097 * The name might have a tag or array reference. That
3098 * isn't properly part of the name, and can be ignored on
3101 for (p = &da->name[0]; *p; p++) {
3113 return fr_hash_table_finddata(attributes_byname, da);
3117 * Associate a value with an attribute and return it.
3119 DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
3121 DICT_VALUE dval, *dv;
3124 * First, look up aliases.
3127 dval.vendor = vendor;
3128 dval.name[0] = '\0';
3131 * Look up the attribute alias target, and use
3132 * the correct attribute number if found.
3134 dv = fr_hash_table_finddata(values_byname, &dval);
3135 if (dv) dval.attr = dv->value;
3139 return fr_hash_table_finddata(values_byvalue, &dval);
3143 * Associate a value with an attribute and return it.
3145 char const *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value)
3149 dv = dict_valbyattr(attr, vendor, value);
3156 * Get a value by its name, keyed off of an attribute.
3158 DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, char const *name)
3160 DICT_VALUE *my_dv, *dv;
3161 uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
3163 if (!name) return NULL;
3165 my_dv = (DICT_VALUE *) buffer;
3167 my_dv->vendor = vendor;
3168 my_dv->name[0] = '\0';
3171 * Look up the attribute alias target, and use
3172 * the correct attribute number if found.
3174 dv = fr_hash_table_finddata(values_byname, my_dv);
3175 if (dv) my_dv->attr = dv->value;
3177 strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
3179 return fr_hash_table_finddata(values_byname, my_dv);
3183 * Get the vendor PEC based on the vendor name
3185 * This is efficient only for small numbers of vendors.
3187 int dict_vendorbyname(char const *name)
3190 size_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + sizeof(size_t) - 1) / sizeof(size_t)];
3192 if (!name) return 0;
3194 dv = (DICT_VENDOR *) buffer;
3195 strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
3197 dv = fr_hash_table_finddata(vendors_byname, dv);
3200 return dv->vendorpec;
3204 * Return the vendor struct based on the PEC.
3206 DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
3210 dv.vendorpec = vendorpec;
3212 return fr_hash_table_finddata(vendors_byvalue, &dv);