The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_util.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Multi-protocol AVP dictionary API
18 *
19 * @file src/lib/util/dict_util.c
20 *
21 * @copyright 2000,2006 The FreeRADIUS server project
22 * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: 2fdf90e92c61e56df0ccf64af8a14d13d6dc31ba $")
25
26#define _DICT_PRIVATE 1
27
28#include <freeradius-devel/util/atexit.h>
29#include <freeradius-devel/util/conf.h>
30#include <freeradius-devel/util/dict.h>
31#include <freeradius-devel/util/dict_ext_priv.h>
32#include <freeradius-devel/util/dict_fixup_priv.h>
33#include <freeradius-devel/util/proto.h>
34#include <freeradius-devel/util/rand.h>
35#include <freeradius-devel/util/syserror.h>
36
37#ifdef HAVE_SYS_STAT_H
38# include <sys/stat.h>
39#endif
40
41fr_dict_gctx_t *dict_gctx = NULL; //!< Top level structure containing global dictionary state.
42
43#define DICT_ATTR_ALLOWED_CHARS \
44 ['-'] = true, ['/'] = true, ['_'] = true, \
45 ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, \
46 ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, \
47 ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true, \
48 ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true, \
49 ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, \
50 ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, \
51 ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true, \
52 ['Z'] = true, \
53 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, \
54 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true, \
55 ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true, \
56 ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true, \
57 ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true, \
58 ['z'] = true
59
60/** Characters allowed in a single dictionary attribute name
61 *
62 */
66
67/** Characters allowed in a nested dictionary attribute name
68 *
69 */
74
75/** Characters allowed in enumeration value names
76 *
77 */
79 ['+'] = true, ['-'] = true, ['.'] = true, ['/'] = true, ['_'] = true,
80 ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
81 ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
82 ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
83 ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true,
84 ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true,
85 ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true,
86 ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true,
87 ['Z'] = true,
88 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
89 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
90 ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
91 ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
92 ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
93 ['z'] = true
94};
95
96/** Default protocol rules set for every dictionary
97 *
98 * This is usually overriden by the public symbol from the protocol library
99 * associated with the dictionary
100 * e.g. libfreeradius-dhcpv6.so -> libfreeradius_dhcpv6_dict_protocol.
101 */
103 .name = "default",
104 .default_type_size = 2,
105 .default_type_length = 2,
106};
107
108/*
109 * Create the hash of the name.
110 *
111 * We copy the hash function here because it's substantially faster.
112 */
113#define FNV_MAGIC_INIT (0x811c9dc5)
114#define FNV_MAGIC_PRIME (0x01000193)
115
116/** Apply a simple (case insensitive) hashing function to the name of an attribute, vendor or protocol
117 *
118 * @param[in] name of the attribute, vendor or protocol.
119 * @param[in] len length of the input string.
120 *
121 * @return the hashed derived from the name.
122 */
123static uint32_t dict_hash_name(char const *name, size_t len)
124{
126
127 char const *p = name, *q = name + len;
128
129 while (p < q) {
130 int c = *(unsigned char const *)p;
131 if (isalpha(c)) c = tolower(c);
132
133 /* coverity[overflow_const] */
135 hash ^= (uint32_t)(c & 0xff);
136 p++;
137 }
138
139 return hash;
140}
141
142/** Wrap name hash function for fr_dict_protocol_t
143 *
144 * @param[in] data fr_dict_attr_t to hash.
145 * @return the hash derived from the name of the attribute.
146 */
148{
149 char const *name;
150
151 name = ((fr_dict_t const *)data)->root->name;
152
153 return dict_hash_name(name, strlen(name));
154}
155
156/** Compare two protocol names
157 *
158 */
159static int8_t dict_protocol_name_cmp(void const *one, void const *two)
160{
161 fr_dict_t const *a = one;
162 fr_dict_t const *b = two;
163 int ret;
164
165 ret = strcasecmp(a->root->name, b->root->name);
166 return CMP(ret, 0);
167}
168
169/** Hash a protocol number
170 *
171 */
173{
174 return fr_hash(&(((fr_dict_t const *)data)->root->attr), sizeof(((fr_dict_t const *)data)->root->attr));
175}
176
177/** Compare two protocol numbers
178 *
179 */
180static int8_t dict_protocol_num_cmp(void const *one, void const *two)
181{
182 fr_dict_t const *a = one;
183 fr_dict_t const *b = two;
184
185 return CMP(a->root->attr, b->root->attr);
186}
187
188/** Wrap name hash function for fr_dict_attr_t
189 *
190 * @param data fr_dict_attr_t to hash.
191 * @return the hash derived from the name of the attribute.
192 */
194{
195 char const *name;
196
197 name = ((fr_dict_attr_t const *)data)->name;
198
199 return dict_hash_name(name, strlen(name));
200}
201
202/** Compare two attribute names
203 *
204 */
205static int8_t dict_attr_name_cmp(void const *one, void const *two)
206{
207 fr_dict_attr_t const *a = one, *b = two;
208 int ret;
209
210 ret = strcasecmp(a->name, b->name);
211 return CMP(ret, 0);
212}
213
214/** Compare two attributes by total order.
215 *
216 * This function is safe / ordered even when the attributes are in
217 * different dictionaries. This allows it to work for local
218 * variables, as those are in a different dictionary from the
219 * protocol ones.
220 *
221 * This function orders parents first, then their children.
222 */
224{
225 int8_t ret;
226
227 /*
228 * Order by parent first. If the parents are different,
229 * we order by parent numbers.
230 *
231 * If the attributes share the same parent at some point,
232 * then the deeper child is sorted later.
233 */
234 if (a->depth < b->depth) {
235 ret = fr_dict_attr_ordered_cmp(a, b->parent);
236 if (ret != 0) return ret;
237
238 return -1; /* order a before b */
239 }
240
241 if (a->depth > b->depth) {
242 ret = fr_dict_attr_ordered_cmp(a->parent, b);
243 if (ret != 0) return ret;
244
245 return +1; /* order b before a */
246 }
247
248 /*
249 * We're at the root (e.g. "RADIUS"). Compare by
250 * protocol number.
251 *
252 * Or, the parents are the same. We can then order by
253 * our (i.e. child) attribute number.
254 */
255 if ((a->depth == 0) || (a->parent == b->parent)) {
256 /*
257 * Order known attributes before unknown / raw ones.
258 */
259 ret = CMP((a->flags.is_unknown | a->flags.is_raw), (b->flags.is_unknown | b->flags.is_raw));
260 if (ret != 0) return ret;
261
262 return CMP(a->attr, b->attr);
263 }
264
265 /*
266 * The parents are different, we don't need to order by
267 * our attribute number. Instead, we order by the
268 * parent.
269 *
270 * Note that at this point, the call below will never
271 * return 0, because the parents are different.
272 */
273 return fr_dict_attr_ordered_cmp(a->parent, b->parent);
274}
275
276/** Wrap name hash function for fr_dict_vendor_t
277 *
278 * @param data fr_dict_vendor_t to hash.
279 * @return the hash derived from the name of the attribute.
280 */
282{
283 char const *name;
284
285 name = ((fr_dict_vendor_t const *)data)->name;
286
287 return dict_hash_name(name, strlen(name));
288}
289
290/** Compare two attribute names
291 *
292 */
293static int8_t dict_vendor_name_cmp(void const *one, void const *two)
294{
295 fr_dict_vendor_t const *a = one;
296 fr_dict_vendor_t const *b = two;
297 int ret;
298
299 ret = strcasecmp(a->name, b->name);
300 return CMP(ret, 0);
301}
302
303/** Hash a vendor number
304 *
305 */
307{
308 return fr_hash(&(((fr_dict_vendor_t const *)data)->pen),
309 sizeof(((fr_dict_vendor_t const *)data)->pen));
310}
311
312/** Compare two vendor numbers
313 *
314 */
315static int8_t dict_vendor_pen_cmp(void const *one, void const *two)
316{
317 fr_dict_vendor_t const *a = one;
318 fr_dict_vendor_t const *b = two;
319
320 return CMP(a->pen, b->pen);
321}
322
323/** Hash a enumeration name
324 *
325 */
327{
328 fr_dict_enum_value_t const *enumv = data;
329
330 return dict_hash_name((void const *)enumv->name, enumv->name_len);
331}
332
333/** Compare two dictionary attribute enum values
334 *
335 */
336static int8_t dict_enum_name_cmp(void const *one, void const *two)
337{
338 fr_dict_enum_value_t const *a = one;
339 fr_dict_enum_value_t const *b = two;
340 int ret;
341
342 ret = CMP(a->name_len, b->name_len);
343 if (ret != 0) return ret;
344
345 ret = strncasecmp(a->name, b->name, a->name_len);
346 return CMP(ret, 0);
347}
348
349/** Hash a dictionary enum value
350 *
351 */
353{
354 fr_dict_enum_value_t const *enumv = data;
355
356 return fr_value_box_hash(enumv->value);
357}
358
359/** Compare two dictionary enum values
360 *
361 */
362static int8_t dict_enum_value_cmp(void const *one, void const *two)
363{
364 fr_dict_enum_value_t const *a = one;
365 fr_dict_enum_value_t const *b = two;
366 int ret;
367
368 ret = fr_value_box_cmp(a->value, b->value); /* not yet int8_t! */
369 return CMP(ret, 0);
370}
371
372/** Resolve an alias attribute to the concrete attribute it points to
373 *
374 * @param[out] err where to write the error (if any).
375 * @param[in] da to resolve.
376 * @return
377 * - NULL on error.
378 * - The concrete attribute on success.
379 */
381{
382 fr_dict_attr_t const *ref;
383
384 if (!da->flags.is_alias) return da;
385
386 ref = fr_dict_attr_ref(da);
387 if (unlikely(!ref)) {
388 fr_strerror_printf("ALIAS attribute '%s' missing reference", da->name);
390 return NULL;
391 } else {
392 if (err) *err = FR_DICT_ATTR_OK;
393 }
394
395 return ref;
396}
397
398/** Set a dictionary attribute's name
399 *
400 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
401 *
402 * @param[in] da_p to set name for.
403 * @param[in] name to set. If NULL a name will be automatically generated.
404 */
405static inline CC_HINT(always_inline) int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
406{
408 size_t name_len;
409 char *name_start, *name_end;
410 fr_dict_attr_t *da = *da_p;
411
412 /*
413 * Generate a name if none is specified
414 */
415 if (!name) {
416 fr_sbuff_t unknown_name = FR_SBUFF_OUT(buffer, sizeof(buffer));
417
418
419 (void) fr_sbuff_in_sprintf(&unknown_name, "%u", da->attr);
420
421 name = fr_sbuff_buff(&unknown_name);
422 name_len = fr_sbuff_used(&unknown_name);
423 } else {
424 name_len = strlen(name);
425 }
426
427 /*
428 * Grow the structure to hold the name
429 *
430 * We add the name as an extension because it makes
431 * the code less complex, and means the name value
432 * is copied automatically when if the fr_dict_attr_t
433 * is copied.
434 *
435 * We do still need to fixup the da->name pointer
436 * though.
437 */
438 name_start = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_NAME, name_len + 1);
439 if (!name_start) return -1;
440
441 name_end = name_start + name_len;
442
443 memcpy(name_start, name, name_len);
444 *name_end = '\0';
445
446 (*da_p)->name = name_start;
447 (*da_p)->name_len = name_len;
448
449 return 0;
450}
451
452/** Add a child/nesting extension to an attribute
453 *
454 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
455 *
456 * @param[in] da_p to set a group reference for.
457 */
458static inline CC_HINT(always_inline) int dict_attr_children_init(fr_dict_attr_t **da_p)
459{
461
463 if (unlikely(!ext)) return -1;
464
465 return 0;
466}
467
468/** Cache the vendor pointer for an attribute
469 *
470 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
471 *
472 * @param[in] da_p to set a group reference for.
473 * @param[in] vendor to set.
474 */
475static inline CC_HINT(always_inline) int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
476{
478
480 if (unlikely(!ext)) return -1;
481
482 ext->vendor = vendor;
483
484 return 0;
485}
486
487/** Initialise a per-attribute enumeration table
488 *
489 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
490 *
491 * @param[in] da_p to set a group reference for.
492 */
493static inline CC_HINT(always_inline) int dict_attr_enumv_init(fr_dict_attr_t **da_p)
494{
496
498 if (unlikely(!ext)) return -1;
499
500 return 0;
501}
502
503/** Initialise a per-attribute namespace
504 *
505 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
506 *
507 * @param[in] da_p to set a group reference for.
508 */
509static inline CC_HINT(always_inline) int dict_attr_namespace_init(fr_dict_attr_t **da_p)
510{
512
514 if (unlikely(!ext)) return -1;
515
516 /*
517 * Create the table of attributes by name.
518 * There MAY NOT be multiple attributes of the same name.
519 *
520 * If the attribute already has extensions
521 * then we don't want to leak the old
522 * namespace hash table.
523 */
524 if (!ext->namespace) {
525 ext->namespace = fr_hash_table_talloc_alloc(*da_p, fr_dict_attr_t,
527 if (!ext->namespace) {
528 fr_strerror_printf("Failed allocating \"namespace\" table");
529 return -1;
530 }
531 }
532
533 return 0;
534}
535
536/** Initialise type specific fields within the dictionary attribute
537 *
538 * Call when the type of the attribute is known.
539 *
540 * @param[in,out] da_p to set the type for.
541 * @param[in] type to set.
542 * @return
543 * - 0 on success.
544 * - < 0 on error.
545 */
547{
548 if (unlikely(((*da_p)->type != FR_TYPE_NULL) &&
549 ((*da_p)->type != type))) {
550 fr_strerror_printf("Cannot set data type to '%s' - it is already set to '%s'",
551 fr_type_to_str(type), fr_type_to_str((*da_p)->type));
552 return -1;
553 }
554
555 if (unlikely((*da_p)->state.finalised == true)) {
556 fr_strerror_const("Can't perform type initialisation on finalised attribute");
557 return -1;
558 }
559
560 /*
561 * Structural types can have children
562 * so add the extension for them.
563 */
564 switch (type) {
566 /*
567 * Groups don't have children or namespaces. But
568 * they always have refs. Either to the root of
569 * the current dictionary, or to another dictionary,
570 * via its top-level TLV.
571 *
572 * Note that when multiple TLVs have the same
573 * children, the dictionary has to use "clone="
574 * instead of "ref=". That's because the
575 * children of the TLVs all require the correct
576 * parentage. Perhaps that can be changed when
577 * the encoders / decoders are updated. It would be good to just reference the DAs instead of cloning an entire subtree.
578 */
580 if (dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_REF) == NULL) return -1;
581 break;
582 }
583
584 if (dict_attr_children_init(da_p) < 0) return -1;
585 if (dict_attr_namespace_init(da_p) < 0) return -1; /* Needed for all TLV style attributes */
586
587 (*da_p)->last_child_attr = (1 << 24); /* High enough not to conflict with protocol numbers */
588 break;
589
590 /*
591 * Leaf types
592 */
593 default:
594 if (dict_attr_enumv_init(da_p) < 0) return -1;
595 break;
596 }
597
598 (*da_p)->flags.is_known_width |= fr_type_fixed_size[type];
599
600 /*
601 * Set default type-based flags
602 */
603 switch (type) {
604 case FR_TYPE_DATE:
606 (*da_p)->flags.length = 4;
607 (*da_p)->flags.flag_time_res = FR_TIME_RES_SEC;
608 break;
609
610
611 case FR_TYPE_OCTETS:
612 case FR_TYPE_STRING:
613 (*da_p)->flags.is_known_width = ((*da_p)->flags.length != 0);
614 break;
615
616 default:
617 break;
618 }
619
620 (*da_p)->type = type;
621
622 return 0;
623}
624
625/** Initialise fields which depend on a parent attribute
626 *
627 * @param[in,out] da_p to initialise.
628 * @param[in] parent of the attribute.
629 * @return
630 * - 0 on success.
631 * - < 0 on error.
632 */
634{
635 fr_dict_attr_t *da = *da_p;
636 fr_dict_t const *dict = parent->dict;
638
639 if (unlikely((*da_p)->type == FR_TYPE_NULL)) {
640 fr_strerror_const("Attribute type must be set before initialising parent. Use dict_attr_type_init() first");
641 return -1;
642 }
643
644 if (unlikely(da->parent != NULL)) {
645 fr_strerror_printf("Attempting to set parent for '%s' to '%s', but parent already set to '%s'",
646 da->name, parent->name, da->parent->name);
647 return -1;
648 }
649
650 if (unlikely((*da_p)->state.finalised == true)) {
651 fr_strerror_printf("Attempting to set parent for '%s' to '%s', but attribute already finalised",
652 da->name, parent->name);
653 return -1;
654 }
655
656 da->parent = parent;
657 da->dict = parent->dict;
658 da->depth = parent->depth + 1;
659 da->flags.internal |= parent->flags.internal;
660
661 /*
662 * Point to the vendor definition. Since ~90% of
663 * attributes are VSAs, caching this pointer will help.
664 */
665 if (da->type == FR_TYPE_VENDOR) {
666 da->flags.type_size = dict->root->flags.type_size;
667 da->flags.length = dict->root->flags.type_size;
668
669 if ((dict->root->attr == FR_DICT_PROTO_RADIUS) && (da->depth == 2)) {
670 fr_dict_vendor_t const *dv;
671
672 dv = fr_dict_vendor_by_num(dict, da->attr);
673 if (dv) {
674 da->flags.type_size = dv->type;
675 da->flags.length = dv->length;
676 }
677 }
678
679 } else if (da->type == FR_TYPE_TLV) {
680 da->flags.type_size = dict->root->flags.type_size;
681 da->flags.length = dict->root->flags.type_size;
682 }
683
684 if (parent->type == FR_TYPE_VENDOR) {
686 if (unlikely(!ext)) return -1;
687
688 ext->vendor = parent;
689
690 } else {
691 ext = dict_attr_ext_copy(da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
692 }
693
694 da = *da_p;
695
696 if (!ext || ((da->type != FR_TYPE_TLV) && (da->type != FR_TYPE_VENDOR))) return 0;
697
698 da->flags.type_size = ext->vendor->flags.type_size;
699 da->flags.length = ext->vendor->flags.type_size;
700
701 return 0;
702}
703
704/** Set the attribute number (if any)
705 *
706 * @param[in] da to set the attribute number for.
707 * @param[in] num to set.
708 */
709int dict_attr_num_init(fr_dict_attr_t *da, unsigned int num)
710{
711 if (da->state.attr_set) {
712 fr_strerror_const("Attribute number already set");
713 return -1;
714 }
715 da->attr = num;
716 da->state.attr_set = true;
717
718 return 0;
719}
720
721/** Set the attribute number (if any)
722 *
723 * @note Must have a parent set.
724 *
725 * @param[in] da to set the attribute number for.
726 */
728{
729 if (!da->parent) {
730 fr_strerror_const("Attribute must have parent set before automatically setting attribute number");
731 return -1;
732 }
733 return dict_attr_num_init(da, ++fr_dict_attr_unconst(da->parent)->last_child_attr);
734}
735
736/** Set where the dictionary attribute was defined
737 *
738 */
739void dict_attr_location_init(fr_dict_attr_t *da, char const *filename, int line)
740{
741 da->filename = filename;
742 da->line = line;
743}
744
745/** Set remaining fields in a dictionary attribute before insertion
746 *
747 * @param[in] da_p to finalise.
748 * @param[in] name of the attribute.
749 * @return
750 * - 0 on success.
751 * - < 0 on error.
752 */
753int dict_attr_finalise(fr_dict_attr_t **da_p, char const *name)
754{
755 fr_dict_attr_t *da;
756
757 /*
758 * Finalising the attribute allocates its
759 * automatic number if its a name only attribute.
760 */
761 da = *da_p;
762
763 /*
764 * Initialize the length field automatically if it's not been set already
765 */
766 if (!da->flags.length && fr_type_is_leaf(da->type) && !fr_type_is_variable_size(da->type)) {
767 fr_value_box_t box;
768
769 fr_value_box_init(&box, da->type, NULL, false);
770 da->flags.length = fr_value_box_network_length(&box);
771 }
772
773 switch(da->type) {
774 case FR_TYPE_STRUCT:
775 da->flags.is_known_width |= da->flags.array;
776 break;
777
778 case FR_TYPE_GROUP:
779 {
781 /*
782 * If it's a group attribute, the default
783 * reference goes to the root of the
784 * dictionary as that's where the default
785 * name/numberspace is.
786 *
787 * This may be updated by the caller.
788 */
790 if (unlikely(ext == NULL)) {
791 fr_strerror_const("Missing ref extension");
792 return -1;
793 }
794
795 /*
796 * For groups, if a ref wasn't provided then
797 * set it to the dictionary root.
798 */
799 if ((ext->type == FR_DICT_ATTR_REF_NONE) &&
801 return -1;
802 }
803 }
804 break;
805
806 default:
807 break;
808 }
809
810 /*
811 * Name is a separate talloc chunk. We allocate
812 * it last because we cache the pointer value.
813 */
814 if (dict_attr_name_set(da_p, name) < 0) return -1;
815
816 DA_VERIFY(*da_p);
817
818 (*da_p)->state.finalised = true;
819
820 return 0;
821}
822
823static inline CC_HINT(always_inline)
824int dict_attr_init_common(char const *filename, int line,
825 fr_dict_attr_t **da_p,
826 fr_dict_attr_t const *parent,
828{
829 dict_attr_location_init((*da_p), filename, line);
830
831 if (unlikely(dict_attr_type_init(da_p, type) < 0)) return -1;
832
833 if (args->flags) (*da_p)->flags = *args->flags;
834
835 if (parent && (dict_attr_parent_init(da_p, parent) < 0)) return -1;
836
837 if (args->ref && (dict_attr_ref_aset(da_p, args->ref, FR_DICT_ATTR_REF_ALIAS) < 0)) return -1;
838
839 /*
840 * Everything should be created correctly.
841 */
842 if (!(*da_p)->flags.internal && !(*da_p)->flags.is_alias &&
843 parent && ((parent->type == FR_TYPE_TLV) || (parent->type ==FR_TYPE_VENDOR))) {
844 if (!parent->flags.type_size) {
845 fr_strerror_printf("Parent %s has zero type_size", parent->name);
846 return -1;
847 }
848
849 if ((uint64_t) (*da_p)->attr >= ((uint64_t) 1 << (8 * parent->flags.type_size))) {
850 fr_strerror_printf("Child of parent %s has invalid attribute number %u for type_size %u",
851 parent->name, (*da_p)->attr, parent->flags.type_size);
852 return -1;
853 }
854 }
855
856 return 0;
857}
858
859/** Initialise fields in a dictionary attribute structure
860 *
861 * This function is a wrapper around the other initialisation functions.
862 *
863 * The reason for the separation, is that sometimes we're initialising a dictionary attribute
864 * by parsing an actual dictionary file, and other times we're copying attribute, or initialising
865 * them programatically.
866 *
867 * This function should only be used for the second case, where we have a complet attribute
868 * definition already.
869 *
870 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
871 *
872 * @param[in] filename file.
873 * @param[in] line number.
874 * @param[in] da_p to initialise.
875 * @param[in] parent of the attribute, if none, this attribute will
876 * be initialised as a dictionary root.
877 * @param[in] name of attribute. Pass NULL for auto-generated name.
878 * @param[in] attr number.
879 * @param[in] type of the attribute.
880 * @param[in] args optional initialisation arguments.
881 * @return
882 * - 0 on success.
883 * - <0 on error.
884 */
885int _dict_attr_init(char const *filename, int line,
886 fr_dict_attr_t **da_p,
887 fr_dict_attr_t const *parent,
888 char const *name, unsigned int attr,
890{
891 /*
892 * We initialize the number first, as doing that doesn't have any other side effects.
893 */
894 if (unlikely(dict_attr_num_init(*da_p, attr) < 0)) return -1;
895
896 /*
897 * This function then checks the number, for things like VSAs.
898 */
899 if (unlikely(dict_attr_init_common(filename, line, da_p, parent, type, args) < 0)) return -1;
900
901 if (unlikely(dict_attr_finalise(da_p, name) < 0)) return -1;
902
903 return 0;
904}
905
906/** Initialise fields in a dictionary attribute structure
907 *
908 * This function is a wrapper around the other initialisation functions.
909 *
910 * The reason for the separation, is that sometimes we're initialising a dictionary attribute
911 * by parsing an actual dictionary file, and other times we're copying attribute, or initialising
912 * them programatically.
913 *
914 * This function should only be used for the second case, where we have a complet attribute
915 * definition already.
916 *
917 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
918 *
919 * @param[in] filename file.
920 * @param[in] line number.
921 * @param[in] da_p to initialise.
922 * @param[in] parent of the attribute, if none, this attribute will
923 * be initialised as a dictionary root.
924 * @param[in] name of attribute. Pass NULL for auto-generated name.
925 * automatically generated.
926 * @param[in] type of the attribute.
927 * @param[in] args optional initialisation arguments.
928 * @return
929 * - 0 on success.
930 * - <0 on error.
931 */
932int _dict_attr_init_name_only(char const *filename, int line,
933 fr_dict_attr_t **da_p,
934 fr_dict_attr_t const *parent,
935 char const *name,
937{
938 if (unlikely(dict_attr_init_common(filename, line, da_p, parent, type, args) < 0)) return -1;
939
940 /*
941 * Automatically generate the attribute number when the attribut is added.
942 */
943 (*da_p)->flags.name_only = true;
944
945 if (unlikely(dict_attr_finalise(da_p, name) < 0)) return -1;
946
947 return 0;
948}
949
951{
953
954#if 0
955#ifdef WITH_VERIFY_PTR
956 /*
957 * Check that any attribute we reference is still valid
958 * when we're being freed.
959 */
960 fr_dict_attr_t const *ref = fr_dict_attr_ref(da);
961
962 if (ref) (void)talloc_get_type_abort_const(ref, fr_dict_attr_t);
963#endif
964#endif
965
967 if (ext) talloc_free(ext->value_by_name); /* Ensure this is freed before the enumvs */
968
969 return 0;
970}
971
972/** Allocate a partially completed attribute
973 *
974 * This is useful in some instances where we need to pre-allocate the attribute
975 * for talloc hierarchy reasons, but want to finish initialising it
976 * with #dict_attr_init later.
977 *
978 * @param[in] ctx to allocate attribute in.
979 * @param[in] proto protocol specific extensions.
980 * @return
981 * - A new, partially completed, fr_dict_attr_t on success.
982 * - NULL on failure (memory allocation error).
983 */
985{
986 fr_dict_attr_t *da;
987
988 /*
989 * Do not use talloc zero, the caller
990 * always initialises memory allocated
991 * here.
992 */
993 da = talloc_zero(ctx, fr_dict_attr_t);
994 if (unlikely(!da)) return NULL;
995
996 /*
997 * Allocate room for the protocol specific flags
998 */
999 if (proto->attr.flags.len > 0) {
1001 proto->attr.flags.len) == NULL)) {
1002 talloc_free(da);
1003 return NULL;
1004 }
1005 }
1006 talloc_set_destructor(da, _dict_attr_free);
1007
1008 return da;
1009}
1010
1011/** Allocate a dictionary root attribute on the heap
1012 *
1013 * @param[in] filename file.
1014 * @param[in] line number.
1015 * @param[in] ctx to allocate the attribute in.
1016 * @param[in] dict the attribute will be used in.
1017 * @param[in] name of the attribute. If NULL an OID string
1018 * will be created and set as the name.
1019 * @param[in] proto_number number. This should be
1020 * @param[in] args optional initialisation arguments.
1021 * @return
1022 * - A new fr_dict_attr_t on success.
1023 * - NULL on failure.
1024 */
1025fr_dict_attr_t *_dict_attr_alloc_root(char const *filename, int line,
1026 TALLOC_CTX *ctx,
1027 fr_dict_t const *dict,
1028 char const *name, int proto_number,
1029 dict_attr_args_t const *args)
1030{
1032
1033 n = dict_attr_alloc_null(ctx, dict->proto);
1034 if (unlikely(!n)) return NULL;
1035
1036 if (_dict_attr_init(filename, line, &n, NULL, name, proto_number, FR_TYPE_TLV, args) < 0) {
1037 talloc_free(n);
1038 return NULL;
1039 }
1040
1041 return n;
1042}
1043
1044/** Allocate a dictionary attribute on the heap
1045 *
1046 * @param[in] filename file.
1047 * @param[in] line number.
1048 * @param[in] ctx to allocate the attribute in.
1049 * @param[in] parent of the attribute.
1050 * @param[in] name of the attribute. If NULL an OID string
1051 * will be created and set as the name.
1052 * @param[in] attr number.
1053 * @param[in] type of the attribute.
1054 * @param[in] args optional initialisation arguments.
1055 * @return
1056 * - A new fr_dict_attr_t on success.
1057 * - NULL on failure.
1058 */
1059fr_dict_attr_t *_dict_attr_alloc(char const *filename, int line,
1060 TALLOC_CTX *ctx,
1061 fr_dict_attr_t const *parent,
1062 char const *name, int attr,
1064{
1066
1067 n = dict_attr_alloc_null(ctx, parent->dict->proto);
1068 if (unlikely(!n)) return NULL;
1069
1070 if (_dict_attr_init(filename, line, &n, parent, name, attr, type, args) < 0) {
1071 talloc_free(n);
1072 return NULL;
1073 }
1074
1075 return n;
1076}
1077
1078/** Copy a an existing attribute, possibly to a new location
1079 *
1080 * @param[in] ctx to allocate new attribute in.
1081 * @param[in] parent where to parent the copy from. If NULL, in->parent is used.
1082 * @param[in] in attribute to copy.
1083 * @param[in] name to assign to the attribute. If NULL, in->name is used.
1084 * @return
1085 * - A copy of the input fr_dict_attr_t on success.
1086 * - NULL on failure.
1087 */
1089 char const *name)
1090{
1092
1093 if (in->flags.has_fixup) {
1094 fr_strerror_printf("Cannot copy from %s - source attribute is waiting for additional definitions",
1095 in->name);
1096 return NULL;
1097 }
1098
1099 fr_assert(parent || name);
1100
1101 n = dict_attr_alloc(ctx, parent ? parent : in->parent, name ? name : in->name,
1102 in->attr, in->type, &(dict_attr_args_t){ .flags = &in->flags });
1103 if (unlikely(!n)) return NULL;
1104
1105 /*
1106 * This newly allocated attribute is not the target of a ref.
1107 */
1108 n->flags.is_ref_target = false;
1109
1110 if (dict_attr_ext_copy_all(&n, in) < 0) {
1111 error:
1112 talloc_free(n);
1113 return NULL;
1114 }
1115 DA_VERIFY(n);
1116
1117 if (fr_type_is_structural(in->type) && in->flags.has_alias) {
1118 if (dict_attr_acopy_aliases(n, in) < 0) goto error;
1119 }
1120
1121 return n;
1122}
1123
1125{
1126 if (!dst->flags.local) {
1127 fr_strerror_const("Cannot copy attributes to a non-local dictionary");
1128 return -1;
1129 }
1130
1131 if (src->flags.has_fixup) {
1132 fr_strerror_printf("Cannot copy from %s to %s - source attribute is waiting for additional definitions",
1133 src->name, dst->name);
1134 return -1;
1135 }
1136
1137 /*
1138 * Why not? @todo - check and fix
1139 */
1140 if (src->flags.local) {
1141 fr_strerror_const("Cannot copy a local attribute");
1142 return -1;
1143 }
1144
1145 return dict_attr_acopy_children(dst->dict, UNCONST(fr_dict_attr_t *, dst), src);
1146}
1147
1149 fr_dict_attr_t const *child)
1150{
1151 fr_dict_attr_t *copy;
1152
1153 copy = dict_attr_acopy(dict->pool, dst, child, child->name);
1154 if (!copy) return -1;
1155
1156 fr_assert(copy->parent == dst);
1157 copy->depth = copy->parent->depth + 1;
1158
1159 if (dict_attr_child_add(dst, copy) < 0) return -1;
1160
1161 if (dict_attr_add_to_namespace(dst, copy) < 0) return -1;
1162
1163 if (!dict_attr_children(child)) return 0;
1164
1165 if (dict_attr_acopy_children(dict, copy, child) < 0) return -1;
1166
1167 /*
1168 * Children of a UNION get an ALIAS added to the parent of the UNION. This allows the UNION
1169 * attribute to be omitted from parsing and printing.
1170 */
1171 if (src->type != FR_TYPE_UNION) return 0;
1172
1173 return dict_attr_alias_add(dst->parent, copy->name, copy, false);
1174}
1175
1176
1177/** Copy the children of an existing attribute
1178 *
1179 * @param[in] dict to allocate the children in
1180 * @param[in] dst where to copy the children to
1181 * @param[in] src where to copy the children from
1182 * @return
1183 * - 0 on success
1184 * - <0 on error
1185 */
1187{
1188 uint child_num;
1189 fr_dict_attr_t const *child = NULL, *src_key = NULL;
1190 fr_dict_attr_t *dst_key;
1191
1193 fr_assert(dst->type == src->type);
1195
1196 /*
1197 * For non-struct parents, we can copy their children in any order.
1198 */
1199 if (likely(src->type != FR_TYPE_STRUCT)) {
1200 for (child = fr_dict_attr_iterate_children(src, &child);
1201 child != NULL;
1202 child = fr_dict_attr_iterate_children(src, &child)) {
1203 if (dict_attr_acopy_child(dict, dst, src, child) < 0) return -1;
1204 }
1205
1206 return 0;
1207 }
1208
1209 /*
1210 * For structs, we copy the children in order. This allows "key" fields to be copied before
1211 * fields which depend on them.
1212 *
1213 * Note that due to the checks in the DEFINE and ATTRIBUTE parsers (but not the validate
1214 * routines), STRUCTs can only have children which are MEMBERs. And MEMBERs are allocated in
1215 * order.
1216 */
1217 for (child_num = 1, child = fr_dict_attr_child_by_num(src, child_num);
1218 child != NULL;
1219 child_num++, child = fr_dict_attr_child_by_num(src, child_num)) {
1220 /*
1221 * If the key field has enums, then delay copying the enums until after we've copied all
1222 * of the other children.
1223 *
1224 * For a UNION which is inside of a STRUCT, the UNION has a reference to the key field.
1225 * So the key field needs to be defined before we create the UNION.
1226 *
1227 * But the key field also has a set of ENUMs, each of which has a key ref to the UNION
1228 * member which is associated with that key value. This means that we have circular
1229 * dependencies.
1230 *
1231 * The loop is resolved by creating the key first, and allocating room for an ENUM
1232 * extension. This allows the UNION to reference the key. Once the UNION is created, we
1233 * go back and copy all of the ENUMs over. The ENUM copy routine will take care of
1234 * fixing up the refs.
1235 */
1236 if (unlikely(fr_dict_attr_is_key_field(child) && child->flags.has_value)) {
1237 src_key = child;
1238
1239 if (src_key->flags.has_fixup) {
1240 fr_strerror_printf("Cannot copy from %s - source attribute is waiting for additional definitions",
1241 src_key->name);
1242 return -1;
1243 }
1244
1245 dst_key = dict_attr_alloc(dict, dst, src_key->name,
1246 src_key->attr, src_key->type, &(dict_attr_args_t){ .flags = &src_key->flags });
1247 if (unlikely(!dst_key)) return -1;
1248
1249 if (!dict_attr_ext_alloc(&dst_key, FR_DICT_ATTR_EXT_ENUMV)) return -1;
1250
1251 fr_assert(dst_key->parent == dst);
1252 dst_key->depth = dst->depth + 1;
1253
1254 if (dict_attr_child_add(dst, dst_key) < 0) return -1;
1255
1256 if (dict_attr_add_to_namespace(dst, dst_key) < 0) return -1;
1257
1258 continue;
1259 }
1260
1261 if (dict_attr_acopy_child(dict, dst, src, child) < 0) return -1;
1262
1263 DA_VERIFY(child);
1264 }
1265
1266 DA_VERIFY(dst);
1267
1268 if (!src_key) return 0;
1269
1270 if (!dict_attr_ext_copy(&dst_key, src_key, FR_DICT_ATTR_EXT_ENUMV)) return -1;
1271
1272 return 0;
1273}
1274
1275/** Copy the VALUEs of an existing attribute, by casting them
1276 *
1277 * @param[in] dst where to cast the VALUEs to
1278 * @param[in] src where to cast the VALUEs from
1279 * @return
1280 * - 0 on success
1281 * - <0 on error
1282 */
1284{
1286
1287 fr_assert(!fr_type_is_non_leaf(dst->type));
1288 fr_assert(!fr_type_is_non_leaf(src->type));
1289
1292
1294 if (!ext) {
1295 fr_assert(0);
1296 return -1;
1297 }
1298
1299 if (!ext->name_by_value) {
1300 fr_strerror_printf("Reference enum %s does not have any VALUEs to copy", src->name);
1301 return -1;
1302 }
1303
1305
1306 return -1;
1307}
1308
1309
1310/** Copy aliases of an existing attribute to a new one.
1311 *
1312 * @param[in] dst where to copy the children to
1313 * @param[in] src where to copy the children from
1314 * @return
1315 * - 0 on success
1316 * - <0 on error
1317 */
1319{
1320 fr_hash_table_t *namespace;
1321 fr_hash_iter_t iter;
1322 fr_dict_attr_t const *da;
1323
1324 if (!src->flags.has_alias) return 0;
1325
1326 switch (src->type) {
1327 case FR_TYPE_TLV:
1328 case FR_TYPE_VENDOR:
1329 case FR_TYPE_VSA:
1330 break;
1331
1332 /*
1333 * Automatically added aliases are copied in dict_attr_acopy_child().
1334 */
1335 case FR_TYPE_STRUCT:
1336 return 0;
1337
1338 default:
1339 fr_strerror_printf("Cannot add ALIAS to parent attribute %s of data type '%s'", src->name, fr_type_to_str(src->type));
1340 return -1;
1341
1342 }
1343
1344 namespace = dict_attr_namespace(src);
1345 fr_assert(namespace != NULL);
1346
1347 for (da = fr_hash_table_iter_init(namespace, &iter);
1348 da != NULL;
1349 da = fr_hash_table_iter_next(namespace, &iter)) {
1350 if (!da->flags.is_alias) continue;
1351
1352#if 1
1353 fr_strerror_printf("Cannot clone ALIAS %s.%s to %s.%s", src->name, da->name, dst->name, da->name);
1354 return -1;
1355
1356#else
1357 fr_dict_attr_t const *parent, *ref;
1358 fr_dict_attr_t const *new_ref;
1359
1360 ref = fr_dict_attr_ref(da);
1361 fr_assert(ref != NULL);
1362
1363 /*
1364 * ALIASes are normally down the tree, to shorten sibling relationships.
1365 * e.g. Cisco-AVPAir -> Vendor-Specific.Cisco.AV-Pair.
1366 *
1367 * The question is to we want to allow aliases to create cross-tree links? I suspect
1368 * not.
1369 */
1370 parent = fr_dict_attr_common_parent(src, ref, true);
1371 if (!parent) {
1372 fr_strerror_printf("Cannot clone ALIAS %s.%s to %s.%s, the alias reference %s is outside of the shared tree",
1373 src->name, da->name, dst->name, da->name, ref->name);
1374 return -1;
1375 }
1376
1377 fr_assert(parent == src);
1378
1379 new_ref = fr_dict_attr_by_name(NULL, dst, da->name);
1380 fr_assert(new_ref == NULL);
1381
1382 /*
1383 * This function needs to walk back up from "ref" to "src", finding the intermediate DAs.
1384 * Once that's done, it needs to walk down from "dst" to create a new "ref".
1385 */
1386 new_ref = dict_alias_reref(dst, src, ref);
1387 fr_assert(new_ref != NULL);
1388
1389 if (dict_attr_alias_add(dst, da->name, new_ref, false) < 0) return -1;
1390#endif
1391 }
1392
1393 return 0;
1394}
1395
1396/** Add an alias to an existing attribute
1397 *
1398 */
1399int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref, bool from_public)
1400{
1401 fr_dict_attr_t const *da;
1402 fr_dict_attr_t *self;
1403 fr_hash_table_t *namespace;
1404
1405 switch (parent->type) {
1406 case FR_TYPE_STRUCT:
1407 /*
1408 * If we are a STRUCT, the reference an only be to children of a UNION.
1409 */
1410 fr_assert(ref->parent->type == FR_TYPE_UNION);
1411
1412 /*
1413 * And the UNION must be a MEMBER of the STRUCT.
1414 */
1415 fr_assert(ref->parent->parent == parent);
1416 break;
1417
1418 case FR_TYPE_TLV:
1419 case FR_TYPE_VENDOR:
1420 case FR_TYPE_VSA:
1421 case FR_TYPE_GROUP:
1422 break;
1423
1424 default:
1425 fr_strerror_printf("Cannot add ALIAS to parent attribute %s of data type '%s'",
1426 parent->name, fr_type_to_str(parent->type));
1427 return -1;
1428 }
1429
1430 if ((ref->type == FR_TYPE_UNION) || fr_dict_attr_is_key_field(ref)) {
1431 fr_strerror_printf("Cannot add ALIAS to target attribute %s of data type '%s'",
1432 ref->name, fr_type_to_str(ref->type));
1433 return -1;
1434 }
1435
1436 da = dict_attr_by_name(NULL, parent, alias);
1437 if (da) {
1438 fr_strerror_printf("ALIAS '%s' conflicts with another attribute in namespace %s",
1439 alias, parent->name);
1440 return -1;
1441 }
1442
1443 /*
1444 * ALIASes from the dictionaries, need to point to a child of the same parent. ALIASes cannot go
1445 * back up the tree.
1446 *
1447 * ALIASes added internally, they can break this restriction.
1448 *
1449 * This restriction is here to prevent people from creating loops of ALIASes.
1450 */
1451 if (from_public && !fr_dict_attr_common_parent(parent, ref, true)) {
1452 fr_strerror_printf("Invalid ALIAS to target attribute %s of data type '%s' - the attributes do not share a parent",
1453 ref->name, fr_type_to_str(ref->type));
1454 return -1;
1455 }
1456
1457 /*
1458 * Note that we do NOT call fr_dict_attr_add() here.
1459 *
1460 * When that function adds two equivalent attributes, the
1461 * second one is prioritized for printing. For ALIASes,
1462 * we want the pre-existing one to be prioritized.
1463 *
1464 * i.e. you can lookup the ALIAS by "name", but you
1465 * actually get returned "ref".
1466 */
1467 {
1468 fr_dict_attr_flags_t flags = ref->flags;
1469
1470 flags.is_alias = 1; /* These get followed automatically by public functions */
1471
1472 self = dict_attr_alloc(parent->dict->pool, parent, alias, ref->attr, FR_TYPE_VOID, (&(dict_attr_args_t){ .flags = &flags, .ref = ref }));
1473 if (unlikely(!self)) return -1;
1474 }
1475
1476 self->dict = parent->dict;
1477 UNCONST(fr_dict_attr_t *, parent)->flags.has_alias = true;
1478
1479 fr_assert(fr_dict_attr_ref(self) == ref);
1480
1481 namespace = dict_attr_namespace(parent);
1482 if (!namespace) {
1483 fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
1484 error:
1485 talloc_free(self);
1486 return -1;
1487 }
1488
1489 if (!fr_hash_table_insert(namespace, self)) {
1490 fr_strerror_const("Internal error storing attribute");
1491 goto error;
1492 }
1493
1494 return 0;
1495}
1496
1497/** Add a protocol to the global protocol table
1498 *
1499 * Inserts a protocol into the global protocol table. Uses the root attributes
1500 * of the dictionary for comparisons.
1501 *
1502 * @param[in] dict of protocol we're inserting.
1503 * @return
1504 * - 0 on success.
1505 * - -1 on failure.
1506 */
1508{
1509 if (!dict->root) return -1; /* Should always have root */
1510
1512 fr_dict_t *old_proto;
1513
1514 old_proto = fr_hash_table_find(dict_gctx->protocol_by_name, dict);
1515 if (!old_proto) {
1516 fr_strerror_printf("%s: Failed inserting protocol name %s", __FUNCTION__, dict->root->name);
1517 return -1;
1518 }
1519
1520 if ((strcmp(old_proto->root->name, dict->root->name) == 0) &&
1521 (old_proto->root->name == dict->root->name)) {
1522 fr_strerror_printf("%s: Duplicate protocol name %s", __FUNCTION__, dict->root->name);
1523 return -1;
1524 }
1525
1526 return 0;
1527 }
1528 dict->in_protocol_by_name = true;
1529
1531 fr_strerror_printf("%s: Duplicate protocol number %u", __FUNCTION__, dict->root->attr);
1532 return -1;
1533 }
1534 dict->in_protocol_by_num = true;
1535
1536 dict_dependent_add(dict, "global");
1537
1538 /*
1539 * Create and add sub-attributes which allow other
1540 * protocols to be encapsulated in the internal
1541 * namespace.
1542 */
1543 if (dict_gctx->internal && (dict != dict_gctx->internal)) {
1544 fr_dict_attr_t const *da;
1545 fr_dict_attr_flags_t flags = { 0 };
1546
1549
1551 if (!da) {
1553 dict->root->name, dict->root->attr, FR_TYPE_GROUP, &flags) < 0) {
1554 return -1;
1555 }
1556
1558 fr_assert(da != NULL);
1559 }
1560
1562 }
1563
1564 return 0;
1565}
1566
1567/** Add a vendor to the dictionary
1568 *
1569 * Inserts a vendor entry into the vendor hash table. This must be done before adding
1570 * attributes under a VSA.
1571 *
1572 * @param[in] dict of protocol context we're operating in.
1573 * If NULL the internal dictionary will be used.
1574 * @param[in] name of the vendor.
1575 * @param[in] num Vendor's Private Enterprise Number.
1576 * @return
1577 * - 0 on success.
1578 * - -1 on failure.
1579 */
1580int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
1581{
1582 size_t len;
1583 fr_dict_vendor_t *vendor;
1584
1585 INTERNAL_IF_NULL(dict, -1);
1586
1587 len = strlen(name);
1588 if (len >= FR_DICT_VENDOR_MAX_NAME_LEN) {
1589 fr_strerror_printf("%s: Vendor name too long", __FUNCTION__);
1590 return -1;
1591 }
1592
1593 vendor = talloc_zero(dict, fr_dict_vendor_t);
1594 if (!vendor) {
1595 oom:
1596 fr_strerror_const("Out of memory");
1597 return -1;
1598 }
1599
1600 vendor->name = talloc_strdup(vendor, name);
1601 if (!vendor->name) {
1602 talloc_free(vendor);
1603 goto oom;
1604 }
1605 vendor->pen = num;
1606 vendor->type = vendor->length = 1; /* defaults */
1607
1608 if (!fr_hash_table_insert(dict->vendors_by_name, vendor)) {
1609 fr_dict_vendor_t const *old_vendor;
1610
1611 old_vendor = fr_hash_table_find(dict->vendors_by_name, vendor);
1612 if (!old_vendor) {
1613 fr_strerror_printf("%s: Failed inserting vendor name %s", __FUNCTION__, name);
1614 return -1;
1615 }
1616 if ((strcmp(old_vendor->name, vendor->name) == 0) && (old_vendor->pen != vendor->pen)) {
1617 fr_strerror_printf("%s: Duplicate vendor name %s", __FUNCTION__, name);
1618 return -1;
1619 }
1620
1621 /*
1622 * Already inserted. Discard the duplicate entry.
1623 */
1624 talloc_free(vendor);
1625
1626 return 0;
1627 }
1628
1629 /*
1630 * Insert the SAME pointer (not free'd when this table is
1631 * deleted), into another table.
1632 *
1633 * We want this behaviour because we want OLD names for
1634 * the attributes to be read from the configuration
1635 * files, but when we're printing them, (and looking up
1636 * by value) we want to use the NEW name.
1637 */
1638 if (fr_hash_table_replace(NULL, dict->vendors_by_num, vendor) < 0) {
1639 fr_strerror_printf("%s: Failed inserting vendor %s", __FUNCTION__, name);
1640 return -1;
1641 }
1642
1643 return 0;
1644}
1645
1646/** See if a #fr_dict_attr_t can have children
1647 *
1648 * @param da the dictionary attribute to check.
1649 */
1651{
1652 switch (da->type) {
1653 case FR_TYPE_TLV:
1654 case FR_TYPE_VENDOR:
1655 case FR_TYPE_VSA:
1656 case FR_TYPE_STRUCT:
1657 case FR_TYPE_UNION:
1658 return true;
1659
1660 default:
1661 break;
1662 }
1663
1664 return false;
1665}
1666
1667/** Add a child to a parent.
1668 *
1669 * @param[in] parent we're adding a child to.
1670 * @param[in] child to add to parent.
1671 * @return
1672 * - 0 on success.
1673 * - -1 on failure (memory allocation error).
1674 */
1676{
1677 fr_dict_attr_t const * const *bin;
1678 fr_dict_attr_t **this;
1679 fr_dict_attr_t const **children;
1680
1681 /*
1682 * Setup fields in the child
1683 */
1684 fr_assert(child->parent == parent);
1685
1686 DA_VERIFY(child);
1687
1688 if (fr_dict_attr_ref(parent)) {
1689 fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
1691 return -1;
1692 }
1693
1695 fr_strerror_printf("Cannot add children to attribute '%s' of type %s",
1696 parent->name,
1697 fr_type_to_str(parent->type));
1698 return -1;
1699 }
1700
1701 if ((parent->type == FR_TYPE_VSA) && (child->type != FR_TYPE_VENDOR)) {
1702 fr_strerror_printf("Cannot add non-vendor children to attribute '%s' of type %s",
1703 parent->name,
1704 fr_type_to_str(parent->type));
1705 return -1;
1706 }
1707
1708 /*
1709 * The parent has children by name only, not by number. Don't even bother trying to track
1710 * numbers, except for VENDOR in root, and MEMBER of a struct.
1711 */
1712 if (!parent->flags.is_root && parent->flags.name_only &&
1713 (parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) {
1714 return 0;
1715 }
1716
1717 /*
1718 * We only allocate the pointer array *if* the parent has children.
1719 */
1720 children = dict_attr_children(parent);
1721 if (!children) {
1722 children = talloc_zero_array(parent, fr_dict_attr_t const *, UINT8_MAX + 1);
1723 if (!children) {
1724 fr_strerror_const("Out of memory");
1725 return -1;
1726 }
1727 if (dict_attr_children_set(parent, children) < 0) return -1;
1728 }
1729
1730 /*
1731 * Treat the array as a hash of 255 bins, with attributes
1732 * sorted into bins using num % 255.
1733 *
1734 * Although the various protocols may define numbers higher than 255:
1735 *
1736 * RADIUS/DHCPv4 - 1-255
1737 * Diameter/Internal - 1-4294967295
1738 * DHCPv6 - 1-65535
1739 *
1740 * In reality very few will ever use attribute numbers > 500, so for
1741 * the majority of lookups we get O(1) performance.
1742 *
1743 * Attributes are inserted into the bin in order of their attribute
1744 * numbers to allow slightly more efficient lookups.
1745 */
1746 for (bin = &children[child->attr & 0xff]; *bin; bin = &(*bin)->next) {
1747 /*
1748 * Workaround for vendors that overload the RFC space.
1749 * Structural attributes always take priority.
1750 */
1751 bool child_is_struct = fr_type_is_structural(child->type);
1752 bool bin_is_struct = fr_type_is_structural((*bin)->type);
1753
1754 if (child_is_struct && !bin_is_struct) break;
1755 if (fr_dict_vendor_num_by_da(child) <= fr_dict_vendor_num_by_da(*bin)) break; /* Prioritise RFC attributes */
1756 if (child->attr <= (*bin)->attr) break;
1757 }
1758
1759 memcpy(&this, &bin, sizeof(this));
1760 child->next = *this;
1761 *this = child;
1762
1763 return 0;
1764}
1765
1766/** Add an attribute to the name table for an attribute
1767 *
1768 * @param[in] parent containing the namespace to add this attribute to.
1769 * @param[in] da to add to the name lookup tables.
1770 * @return
1771 * - 0 on success.
1772 * - -1 on failure.
1773 */
1775{
1776 fr_hash_table_t *namespace;
1777
1778 namespace = dict_attr_namespace(parent);
1779 if (unlikely(!namespace)) {
1780 fr_strerror_printf("Parent \"%s\" has no namespace", parent->name);
1781 error:
1782 return -1;
1783 }
1784
1785 /*
1786 * Sanity check to stop children of vendors ending
1787 * up in the Vendor-Specific or root namespace.
1788 */
1789 if ((fr_dict_vendor_num_by_da(da) != 0) && (da->type != FR_TYPE_VENDOR) &&
1790 ((parent->type == FR_TYPE_VSA) || parent->flags.is_root)) {
1791 fr_strerror_printf("Cannot insert attribute '%s' of type %s into %s",
1792 da->name,
1793 fr_type_to_str(da->type),
1794 parent->name);
1795 goto error;
1796 }
1797
1798 /*
1799 * Insert the attribute, only if it's not a duplicate.
1800 */
1801 if (!fr_hash_table_insert(namespace, da)) {
1802 fr_dict_attr_t *a;
1803
1804 /*
1805 * Find the old name. If it's the same name and
1806 * but the parent, or number, or type are
1807 * different, that's an error.
1808 */
1809 a = fr_hash_table_find(namespace, da);
1810 if (a && (strcasecmp(a->name, da->name) == 0)) {
1811 if ((a->attr != da->attr) || (a->type != da->type) || (a->parent != da->parent)) {
1812 fr_strerror_printf("Duplicate attribute name '%s' in namespace '%s'. "
1813 "Originally defined %s[%d]",
1814 da->name, parent->name,
1815 a->filename, a->line);
1816 goto error;
1817 }
1818 }
1819
1820 /*
1821 * Otherwise the attribute has been redefined later
1822 * in the dictionary.
1823 *
1824 * The original fr_dict_attr_t remains in the
1825 * dictionary but entry in the name hash table is
1826 * updated to point to the new definition.
1827 */
1828 if (fr_hash_table_replace(NULL, namespace, da) < 0) {
1829 fr_strerror_const("Internal error storing attribute");
1830 goto error;
1831 }
1832 }
1833
1834 return 0;
1835}
1836
1837/** A variant of fr_dict_attr_t that allows a pre-allocated, populated fr_dict_attr_t to be added
1838 *
1839 */
1841{
1842 fr_dict_attr_t const *exists;
1843
1844 if (unlikely(da->dict->read_only)) {
1845 fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(da->dict)->name);
1846 return -1;
1847 }
1848
1849 if (unlikely(da->state.finalised == false)) {
1850 fr_strerror_const("Attribute has not been finalised");
1851 return -1;
1852 }
1853
1854 /*
1855 * Check that the definition is valid.
1856 */
1857 if (!dict_attr_valid(da)) return -1;
1858
1859 /*
1860 * Don't allow duplicate names
1861 *
1862 * Previously we allowed duplicate names, but only if the
1863 * attributes were compatible (we'd just ignore the operation).
1864 *
1865 * But as attribute parsing may have generated fixups, which
1866 * we'd now need to unpick, it's easier just to error out
1867 * and have the user fix the duplicate.
1868 */
1869 exists = fr_dict_attr_by_name(NULL, da->parent, da->name);
1870 if (exists) {
1871 fr_strerror_printf("Duplicate attribute name '%s' in namespace '%s'. "
1872 "Originally defined %s[%d]", da->name, da->parent->name,
1873 exists->filename, exists->line);
1874 return -1;
1875 }
1876
1877 /*
1878 * In some cases name_only attributes may have explicitly
1879 * assigned numbers. Ensure that there are no conflicts
1880 * between auto-assigned and explkicitly assigned.
1881 */
1882 if (da->flags.name_only) {
1883 if (da->state.attr_set) {
1885
1886 if (da->attr > da->parent->last_child_attr) {
1887 parent->last_child_attr = da->attr;
1888
1889 /*
1890 * If the attribute is outside of the bounds of
1891 * the type size, then it MUST be an internal
1892 * attribute. Set the flag in this attribute, so
1893 * that the encoder doesn't have to do complex
1894 * checks.
1895 */
1896 if ((da->attr >= (((uint64_t)1) << (8 * parent->flags.type_size)))) da->flags.internal = true;
1897 }
1898 } else if (unlikely(dict_attr_num_init_name_only(da)) < 0) {
1899 return -1;
1900 }
1901 }
1902
1903 /*
1904 * Attributes can also be indexed by number. Ensure that
1905 * all attributes of the same number have the same
1906 * properties.
1907 */
1908 exists = fr_dict_attr_child_by_num(da->parent, da->attr);
1909 if (exists) {
1910 fr_strerror_printf("Duplicate attribute number %u in namespace '%s'. "
1911 "Originally defined by '%s' at %s[%d]",
1912 da->attr, da->parent->name, exists->name, exists->filename, exists->line);
1913 return -1;
1914 }
1915
1916 /*
1917 * Add in by number
1918 */
1919 if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, da->parent), da) < 0) return -1;
1920
1921 /*
1922 * Add in by name
1923 */
1924 if (dict_attr_add_to_namespace(da->parent, da) < 0) return -1;
1925
1926#ifndef NDEBUG
1927 {
1928 fr_dict_attr_t const *found;
1929
1930 /*
1931 * Check if we added the attribute
1932 */
1933 found = dict_attr_child_by_num(da->parent, da->attr);
1934 if (!found) {
1935 fr_strerror_printf("FATAL - Failed to find attribute number %u we just added to namespace '%s'", da->attr, da->parent->name);
1936 return -1;
1937 }
1938
1939 if (!dict_attr_by_name(NULL, da->parent, da->name)) {
1940 fr_strerror_printf("FATAL - Failed to find attribute '%s' we just added to namespace '%s'", da->name, da->parent->name);
1941 return -1;
1942 }
1943 }
1944#endif
1945
1946 return 0;
1947}
1948
1949/** Add an attribute to the dictionary
1950 *
1951 * @param[in] dict of protocol context we're operating in.
1952 * If NULL the internal dictionary will be used.
1953 * @param[in] parent to add attribute under.
1954 * @param[in] name of the attribute.
1955 * @param[in] attr number.
1956 * @param[in] type of attribute.
1957 * @param[in] flags to set in the attribute.
1958 * @return
1959 * - 0 on success.
1960 * - -1 on failure.
1961 */
1963 char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags)
1964{
1965 fr_dict_attr_t *da;
1966
1967 if (fr_dict_attr_ref(parent)) {
1968 fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
1970 return -1;
1971 }
1972
1974 fr_strerror_printf("Cannot add children to attribute '%s' of type %s",
1975 parent->name,
1976 fr_type_to_str(parent->type));
1977 return -1;
1978 }
1979
1980 da = dict_attr_alloc_null(dict->pool, dict->proto);
1981 if (unlikely(!da)) return -1;
1982
1983 if (dict_attr_init(&da, parent, name,
1984 attr, type, &(dict_attr_args_t){ .flags = flags}) < 0) return -1;
1985
1987}
1988
1989/** Add an attribute to the dictionary
1990 *
1991 * @param[in] dict of protocol context we're operating in.
1992 * If NULL the internal dictionary will be used.
1993 * @param[in] parent to add attribute under.
1994 * @param[in] name of the attribute.
1995 * @param[in] type of attribute.
1996 * @param[in] flags to set in the attribute.
1997 * @return
1998 * - 0 on success.
1999 * - -1 on failure.
2000 */
2002 char const *name, fr_type_t type, fr_dict_attr_flags_t const *flags)
2003{
2004 fr_dict_attr_t *da;
2005
2006 da = dict_attr_alloc_null(dict->pool, dict->proto);
2007 if (unlikely(!da)) return -1;
2008
2009 if (dict_attr_init_name_only(&da, parent, name,type, &(dict_attr_args_t){ .flags = flags}) < 0) return -1;
2010
2012}
2013
2014
2016 fr_value_box_t const *value,
2017 bool coerce, bool takes_precedence,
2018 fr_dict_attr_t const *key_child_ref)
2019{
2020 size_t len;
2021 fr_dict_enum_value_t *enumv = NULL;
2022 fr_value_box_t *enum_value = NULL;
2024
2025 if (!da) {
2026 fr_strerror_printf("%s: Dictionary attribute not specified", __FUNCTION__);
2027 return -1;
2028 }
2029
2030 if (!*name) {
2031 fr_strerror_printf("%s: Empty names are not permitted", __FUNCTION__);
2032 return -1;
2033 }
2034
2035 len = strlen(name);
2036 if (len >= FR_DICT_ENUM_MAX_NAME_LEN) {
2037 fr_strerror_printf("VALUE name is too long");
2038 return -1;
2039 }
2040
2041 /*
2042 * If the parent isn't a key field, then we CANNOT add a child struct.
2043 */
2044 if (!fr_dict_attr_is_key_field(da) && key_child_ref) {
2045 fr_strerror_const("Child attributes cannot be defined for VALUEs which are not 'key' attributes");
2046 return -1;
2047 }
2048
2049 if (fr_type_is_structural(da->type) || (da->type == FR_TYPE_STRING)) {
2050 fr_strerror_printf("Enumeration names cannot be added for data type '%s'", fr_type_to_str(da->type));
2051 return -1;
2052 }
2053
2054 if (da->flags.is_alias) {
2055 fr_strerror_printf("Enumeration names cannot be added for ALIAS '%s'", da->name);
2056 return -1;
2057 }
2058
2060 if (!ext) {
2061 fr_strerror_printf("VALUE cannot be defined for %s", da->name);
2062 return -1;
2063 }
2064
2065 /*
2066 * Initialise enumv hash tables
2067 */
2068 if (!ext->value_by_name || !ext->name_by_value) {
2070 dict_enum_name_cmp, NULL);
2071 if (!ext->value_by_name) {
2072 fr_strerror_printf("Failed allocating \"value_by_name\" table");
2073 return -1;
2074 }
2075
2077 dict_enum_value_cmp, NULL);
2078 if (!ext->name_by_value) {
2079 fr_strerror_printf("Failed allocating \"name_by_value\" table");
2080 return -1;
2081 }
2082 }
2083
2084 /*
2085 * Allocate a structure to map between
2086 * the name and value.
2087 */
2088 enumv = talloc_zero_size(da, sizeof(fr_dict_enum_value_t));
2089 if (!enumv) {
2090 oom:
2091 fr_strerror_printf("%s: Out of memory", __FUNCTION__);
2092 return -1;
2093 }
2094 talloc_set_type(enumv, fr_dict_enum_value_t);
2095
2096 enumv->name = talloc_strdup(enumv, name);
2097 enumv->name_len = len;
2098
2099 if (key_child_ref) {
2101
2103 if (!ref) goto oom;
2104
2105 ref->da = key_child_ref;
2106 }
2107
2108 enum_value = fr_value_box_alloc(enumv, da->type, NULL);
2109 if (!enum_value) goto oom;
2110
2111 if (da->type != value->type) {
2112 if (!coerce) {
2113 fr_strerror_printf("Type mismatch between attribute (%s) and enum (%s)",
2114 fr_type_to_str(da->type),
2115 fr_type_to_str(value->type));
2116 return -1;
2117 }
2118
2119 if (fr_value_box_cast(enumv, enum_value, da->type, NULL, value) < 0) {
2120 fr_strerror_printf_push("Failed coercing enum type (%s) to attribute type (%s)",
2121 fr_type_to_str(value->type),
2122 fr_type_to_str(da->type));
2123
2124 return -1;
2125 }
2126 } else {
2127 if (unlikely(fr_value_box_copy(enum_value, enum_value, value) < 0)) {
2128 fr_strerror_printf_push("%s: Failed copying value into enum", __FUNCTION__);
2129 return -1;
2130 }
2131 }
2132
2133 enumv->value = enum_value;
2134
2135 /*
2136 * Add the value into the dictionary.
2137 */
2138 {
2139 fr_dict_attr_t *tmp;
2140 memcpy(&tmp, &enumv, sizeof(tmp));
2141
2142 if (!fr_hash_table_insert(ext->value_by_name, tmp)) {
2143 fr_dict_enum_value_t const *old;
2144
2145 /*
2146 * Suppress duplicates with the same
2147 * name and value. There are lots in
2148 * dictionary.ascend.
2149 */
2150 old = fr_dict_enum_by_name(da, name, -1);
2151 if (!fr_cond_assert(old)) return -1;
2152
2153 if (fr_value_box_cmp(old->value, enumv->value) == 0) {
2154 talloc_free(enumv);
2155 return 0;
2156 }
2157
2158 fr_strerror_printf("Duplicate VALUE name \"%s\" for Attribute '%s'. "
2159 "Old value was \"%pV\", new value was \"%pV\"", name, da->name,
2160 old->value, enumv->value);
2161 talloc_free(enumv);
2162 return -1;
2163 }
2164
2165 if (enumv->name_len > ext->max_name_len) ext->max_name_len = enumv->name_len;
2166 }
2167
2168 /*
2169 * There are multiple VALUE's, keyed by attribute, so we
2170 * take care of that here.
2171 */
2172 if (takes_precedence) {
2173 if (fr_hash_table_replace(NULL, ext->name_by_value, enumv) < 0) {
2174 fr_strerror_printf("%s: Failed inserting value %s", __FUNCTION__, name);
2175 return -1;
2176 }
2177 } else {
2178 (void) fr_hash_table_insert(ext->name_by_value, enumv);
2179 }
2180
2181 /*
2182 * Mark the attribute up as having an enumv
2183 */
2184 UNCONST(fr_dict_attr_t *, da)->flags.has_value = 1;
2185
2186 return 0;
2187}
2188
2189/** Add a value name
2190 *
2191 * Aliases are textual (string) names for a given value.
2192 *
2193 * Value names are not limited to integers, and may be added for any non-structural
2194 * attribute type.
2195 *
2196 * @param[in] da to add enumeration value to.
2197 * @param[in] name Name of value name.
2198 * @param[in] value to associate with name.
2199 * @param[in] coerce if the type of the value does not match the
2200 * type of the da, attempt to cast it to match
2201 * the type of the da. If this is false and there's
2202 * a type mismatch, we fail.
2203 * We also fail if the value cannot be coerced to
2204 * the attribute type.
2205 * @param[in] takes_precedence This name should take precedence over previous
2206 * names for the same value, when resolving value
2207 * to name.
2208 * @return
2209 * - 0 on success.
2210 * - -1 on failure.
2211 */
2213 fr_value_box_t const *value,
2214 bool coerce, bool takes_precedence)
2215{
2216 return dict_attr_enum_add_name(da, name, value, coerce, takes_precedence, NULL);
2217}
2218
2219/** Add an name to an integer attribute hashing the name for the integer value
2220 *
2221 * If the integer value conflicts with an existing name, it's incremented
2222 * until we find a free value.
2223 */
2225{
2226 fr_value_box_t v = {
2227 .type = da->type
2228 };
2229 fr_value_box_t s = {
2230 .type = da->type
2231 };
2232
2233 if (fr_dict_enum_by_name(da, name, -1)) return 0;
2234
2235 switch (da->type) {
2236 case FR_TYPE_INT8:
2237 v.vb_int8 = s.vb_int8 = fr_hash_string(name) & INT8_MAX;
2238 break;
2239
2240 case FR_TYPE_INT16:
2241 v.vb_int16 = s.vb_int16 = fr_hash_string(name) & INT16_MAX;
2242 break;
2243
2244 case FR_TYPE_INT32:
2245 v.vb_int32 = s.vb_int32 = fr_hash_string(name) & INT32_MAX;
2246 break;
2247
2248 case FR_TYPE_INT64:
2249 v.vb_int64 = s.vb_int64 = fr_hash_string(name) & INT64_MAX;
2250 break;
2251
2252 case FR_TYPE_UINT8:
2253 v.vb_uint8 = s.vb_uint8 = fr_hash_string(name) & UINT8_MAX;
2254 break;
2255
2256 case FR_TYPE_UINT16:
2257 v.vb_uint16 = s.vb_uint16 = fr_hash_string(name) & UINT16_MAX;
2258 break;
2259
2260 case FR_TYPE_UINT32:
2261 v.vb_uint32 = s.vb_uint32 = fr_hash_string(name) & UINT32_MAX;
2262 break;
2263
2264 case FR_TYPE_UINT64:
2265 v.vb_uint64 = s.vb_uint64 = fr_hash_string(name) & UINT64_MAX;
2266 break;
2267
2268 default:
2269 fr_strerror_printf("Attribute is wrong type for auto-numbering, expected numeric type, got %s",
2270 fr_type_to_str(da->type));
2271 return -1;
2272 }
2273
2274 /*
2275 * If there's no existing value, add an enum
2276 * with the hash value of the name.
2277 *
2278 * This helps with debugging as the values
2279 * are consistent.
2280 */
2281 if (!fr_dict_enum_by_value(da, &v)) {
2282 add:
2283 return fr_dict_enum_add_name(da, name, &v, false, false);
2284 }
2285
2286 for (;;) {
2288
2289 if (fr_value_box_cmp_op(T_OP_CMP_EQ, &v, &s) == 0) {
2290 fr_strerror_const("No free integer values for enumeration");
2291 return -1;
2292 }
2293
2294 if (!fr_dict_enum_by_value(da, &v)) goto add;
2295 }
2296 /* NEVER REACHED */
2297}
2298
2299/** Find a common ancestor that two TLV type attributes share
2300 *
2301 * @param[in] a first TLV attribute.
2302 * @param[in] b second TLV attribute.
2303 * @param[in] is_ancestor Enforce a->b relationship (a is parent or ancestor of b).
2304 * @return
2305 * - Common ancestor if one exists.
2306 * - NULL if no common ancestor exists.
2307 */
2309{
2310 unsigned int i;
2311 fr_dict_attr_t const *p_a, *p_b;
2312
2313 if (!a || !b) return NULL;
2314
2315 if (is_ancestor && (b->depth <= a->depth)) return NULL; /* fast_path */
2316
2317 /*
2318 * Find a common depth to work back from
2319 */
2320 if (a->depth > b->depth) {
2321 p_b = b;
2322 for (p_a = a, i = a->depth - b->depth; p_a && (i > 0); p_a = p_a->parent, i--);
2323 if (is_ancestor && (p_a != p_b)) return NULL;
2324 } else if (a->depth < b->depth) {
2325 p_a = a;
2326 for (p_b = b, i = b->depth - a->depth; p_b && (i > 0); p_b = p_b->parent, i--);
2327 if (is_ancestor && (p_a != p_b)) return NULL;
2328 } else {
2329 p_a = a;
2330 p_b = b;
2331 }
2332
2333 while (p_a && p_b) {
2334 if (p_a == p_b) return p_a;
2335
2336 p_a = p_a->parent;
2337 p_b = p_b->parent;
2338 }
2339
2340 return NULL;
2341}
2342
2343/** Process a single OID component
2344 *
2345 * @param[out] out Value of component.
2346 * @param[in] oid string to parse.
2347 * @return
2348 * - 0 on success.
2349 * - -1 on format error.
2350 */
2351int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
2352{
2353 char const *p = *oid;
2354 char *q;
2355 unsigned long num;
2356
2357 *out = 0;
2358
2359 num = strtoul(p, &q, 10);
2360 if ((p == q) || (num == ULONG_MAX)) {
2361 fr_strerror_printf("Invalid OID component \"%s\" (%lu)", p, num);
2362 return -1;
2363 }
2364
2365 switch (*q) {
2366 case '\0':
2367 case '.':
2368 *oid = q;
2369 *out = (unsigned int)num;
2370
2371 return 0;
2372
2373 default:
2374 fr_strerror_const("Unexpected text after OID component");
2375 *out = 0;
2376 return -1;
2377 }
2378}
2379
2380/** Get the leaf attribute of an OID string
2381 *
2382 * @note On error, vendor will be set (if present), parent will be the
2383 * maximum depth we managed to resolve to, and attr will be the child
2384 * we failed to resolve.
2385 *
2386 * @param[out] attr Number we parsed.
2387 * @param[in,out] parent attribute (or root of dictionary).
2388 * Will be updated to the parent directly beneath the leaf.
2389 * @param[in] oid string to parse.
2390 * @return
2391 * - > 0 on success (number of bytes parsed).
2392 * - <= 0 on parse error (negative offset of parse error).
2393 */
2394ssize_t fr_dict_attr_by_oid_legacy(fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
2395{
2396 char const *p = oid;
2397 unsigned int num = 0;
2398 ssize_t slen;
2399
2400 if (!*parent) return -1;
2401
2402 /*
2403 * It's a partial OID. Grab it, and skip to the next bit.
2404 */
2405 if (p[0] == '.') {
2406 p++;
2407 }
2408
2409 *attr = 0;
2410
2411 if (fr_dict_oid_component_legacy(&num, &p) < 0) return oid - p;
2412
2413 /*
2414 * Record progress even if we error out.
2415 *
2416 * Don't change this, you will break things.
2417 */
2418 *attr = num;
2419
2420 /*
2421 * Only a limited number of structural types can have children. Specifically, groups cannot.
2422 */
2424 fr_strerror_printf("Attribute %s (%u) cannot contain a child attribute. "
2425 "Error at sub OID \"%s\"", (*parent)->name, (*parent)->attr, oid);
2426 return 0; /* We parsed nothing */
2427 }
2428
2429 switch (p[0]) {
2430 /*
2431 * We've not hit the leaf yet, so the attribute must be
2432 * defined already.
2433 */
2434 case '.':
2435 {
2436 fr_dict_attr_t const *child;
2437 p++;
2438
2439 child = dict_attr_child_by_num(*parent, num);
2440 if (!child) {
2441 fr_strerror_printf("Unknown attribute '%u' in OID string \"%s\" for parent %s",
2442 num, oid, (*parent)->name);
2443 return 0; /* We parsed nothing */
2444 }
2445
2446 /*
2447 * Record progress even if we error out.
2448 *
2449 * Don't change this, you will break things.
2450 */
2451 *parent = child;
2452
2453 slen = fr_dict_attr_by_oid_legacy(parent, attr, p);
2454 if (slen <= 0) return slen - (p - oid);
2455 return slen + (p - oid);
2456 }
2457
2458 /*
2459 * Hit the leaf, this is the attribute we need to define.
2460 */
2461 case '\0':
2462 *attr = num;
2463 return p - oid;
2464
2465 default:
2466 fr_strerror_printf("Malformed OID string, got trailing garbage '%s'", p);
2467 return oid - p;
2468 }
2469}
2470
2471/** Parse an OID component, resolving it to a defined attribute
2472 *
2473 * @note Will leave the sbuff pointing at the component the error occurred at
2474 * so that the caller can attempt to process the component in another way.
2475 *
2476 * @param[out] err The parsing error that occurred.
2477 * @param[out] out The deepest attribute we resolved.
2478 * @param[in] parent Where to resolve relative attributes from.
2479 * @param[in] in string to parse.
2480 * @param[in] tt Terminal strings.
2481 * @return
2482 * - >0 the number of bytes consumed.
2483 * - <0 Parse error occurred here.
2484 */
2486 fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
2487 fr_sbuff_t *in, fr_sbuff_term_t const *tt)
2488{
2489 fr_sbuff_t our_in = FR_SBUFF(in);
2490 uint32_t num = 0;
2492 fr_dict_attr_t const *child;
2493
2494 if (err) *err = FR_DICT_ATTR_OK;
2495
2496 *out = NULL;
2497
2499 fr_strerror_printf("Attribute '%s' is type %s and cannot contain child attributes. "
2500 "Error at OID \"%.*s\"",
2501 parent->name,
2502 fr_type_to_str(parent->type),
2503 (int)fr_sbuff_remaining(&our_in),
2504 fr_sbuff_current(&our_in));
2506 FR_SBUFF_ERROR_RETURN(&our_in);
2507 }
2508
2509 if (fr_dict_attr_by_name_substr(err, &child, parent, &our_in, tt) > 0) goto done;
2510
2511 fr_sbuff_out(&sberr, &num, &our_in);
2512 switch (sberr) {
2513 /*
2514 * Lookup by number
2515 */
2516 case FR_SBUFF_PARSE_OK:
2517 if (!fr_sbuff_is_char(&our_in, '.') && !fr_sbuff_is_terminal(&our_in, tt)) {
2519 fr_strerror_printf("Invalid OID component (%s) \"%.*s\"",
2521 (int)fr_sbuff_remaining(&our_in), fr_sbuff_current(&our_in));
2522 goto fail;
2523 }
2524
2525 child = dict_attr_child_by_num(parent, num);
2526 if (!child) {
2527 fr_sbuff_set_to_start(&our_in);
2528 fr_strerror_printf("Failed resolving child %u in namespace '%s'",
2529 num, parent->name);
2531 FR_SBUFF_ERROR_RETURN(&our_in);
2532 }
2533
2534 if (err) *err = FR_DICT_ATTR_OK;
2535 break;
2536
2539
2540 fr_sbuff_set_to_start(&our_in);
2541
2542 {
2543 fr_sbuff_marker_t c_start;
2544
2545 fr_sbuff_marker(&c_start, &our_in);
2547 fr_strerror_printf("Invalid value \"%.*s\" - attribute numbers must be less than 2^32",
2548 (int)fr_sbuff_behind(&c_start), fr_sbuff_current(&c_start));
2549 }
2550 FR_SBUFF_ERROR_RETURN(&our_in);
2551
2552 default:
2553 fail:
2554 /*
2555 * Leave *err from the call to fr_dict_attr_by_name_substr().
2556 */
2557 fr_sbuff_set_to_start(&our_in);
2558 FR_SBUFF_ERROR_RETURN(&our_in);
2559 }
2560
2561done:
2562 child = dict_attr_alias(err, child);
2563 if (unlikely(!child)) FR_SBUFF_ERROR_RETURN(&our_in);
2564
2565 *out = child;
2566
2567 FR_SBUFF_SET_RETURN(in, &our_in);
2568}
2569
2570/** Resolve an attribute using an OID string
2571 *
2572 * @note Will leave the sbuff pointing at the component the error occurred at
2573 * so that the caller can attempt to process the component in another way.
2574 * An err pointer should be provided in order to determine if an error
2575 * occurred.
2576 *
2577 * @param[out] err The parsing error that occurred.
2578 * @param[out] out The deepest attribute we resolved.
2579 * @param[in] parent Where to resolve relative attributes from.
2580 * @param[in] in string to parse.
2581 * @param[in] tt Terminal strings.
2582 * @return The number of bytes of name consumed.
2583 */
2585 fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
2586 fr_sbuff_t *in, fr_sbuff_term_t const *tt)
2587{
2588 fr_sbuff_t our_in = FR_SBUFF(in);
2590 fr_dict_attr_t const *our_parent = parent;
2591
2592 fr_sbuff_marker(&m_c, &our_in);
2593
2594 /*
2595 * If the OID doesn't begin with '.' we
2596 * resolve it from the root.
2597 */
2598#if 0
2599 if (!fr_sbuff_next_if_char(&our_in, '.')) our_parent = fr_dict_root(fr_dict_by_da(parent));
2600#else
2601 (void) fr_sbuff_next_if_char(&our_in, '.');
2602#endif
2603 *out = NULL;
2604
2605 for (;;) {
2606 fr_dict_attr_t const *child;
2607
2608 if ((fr_dict_oid_component(err, &child, our_parent, &our_in, tt) < 0) || !child) {
2609 *out = our_parent;
2610 fr_sbuff_set(&our_in, &m_c); /* Reset to the start of the last component */
2611 break; /* Resolved as much as we can */
2612 }
2613
2614 our_parent = child;
2615 *out = child;
2616
2617 fr_sbuff_set(&m_c, &our_in);
2618 if (!fr_sbuff_next_if_char(&our_in, '.')) break;
2619 }
2620
2621 FR_SBUFF_SET_RETURN(in, &our_in);
2622}
2623
2624/** Resolve an attribute using an OID string
2625 *
2626 * @param[out] err The parsing error that occurred.
2627 * @param[in] parent Where to resolve relative attributes from.
2628 * @param[in] oid string to parse.
2629 * @return
2630 * - NULL if we couldn't resolve the attribute.
2631 * - The resolved attribute.
2632 */
2634{
2635 fr_sbuff_t sbuff = FR_SBUFF_IN(oid, strlen(oid));
2636 fr_dict_attr_t const *da;
2637
2638 if (fr_dict_attr_by_oid_substr(err, &da, parent, &sbuff, NULL) <= 0) return NULL;
2639 if (err && *err != FR_DICT_ATTR_OK) return NULL;
2640
2641 /*
2642 * If we didn't parse the entire string, then the parsing stopped at an unknown child.
2643 * e.g. Vendor-Specific.Cisco.Foo. In that case, the full attribute wasn't found.
2644 */
2645 if (fr_sbuff_remaining(&sbuff) > 0) {
2647 return NULL;
2648 }
2649
2650 return da;
2651}
2652
2653/** Return the root attribute of a dictionary
2654 *
2655 * @param dict to return root for.
2656 * @return the root attribute of the dictionary.
2657 *
2658 * @hidecallergraph
2659 */
2661{
2662 return dict->root;
2663}
2664
2666{
2667 return dict->read_only;
2668}
2669
2671{
2672 return dict->dl;
2673}
2674
2676 fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
2677{
2678 fr_dict_attr_t root;
2679
2680 fr_sbuff_t our_name;
2681 fr_dict_t *dict;
2682 fr_slen_t slen;
2683 char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
2684
2685 if (!dict_gctx || !name || !out) {
2686 if (err) *err = FR_DICT_ATTR_EINVAL;
2688 return 0;
2689 }
2690
2691 our_name = FR_SBUFF(name);
2692 memset(&root, 0, sizeof(root));
2693
2694 /*
2695 * Advance p until we get something that's not part of
2696 * the dictionary attribute name.
2697 */
2699 &our_name, SIZE_MAX,
2701 if (slen == 0) {
2702 fr_strerror_const("Zero length attribute name");
2704 FR_SBUFF_ERROR_RETURN(&our_name);
2705 }
2706 if (slen > FR_DICT_ATTR_MAX_NAME_LEN) {
2707 fr_strerror_const("Attribute name too long");
2709 FR_SBUFF_ERROR_RETURN(&our_name);
2710 }
2711
2712 /*
2713 * The remaining operations don't generate errors
2714 */
2715 if (err) *err = FR_DICT_ATTR_OK;
2716
2717 /*
2718 * If what we stopped at wasn't a '.', then there
2719 * can't be a protocol name in this string.
2720 */
2721 if (*(our_name.p) && (*(our_name.p) != '.')) {
2722 memcpy(out, &dict_def, sizeof(*out));
2723 return 0;
2724 }
2725
2726 root.name = buffer;
2727 dict = fr_hash_table_find(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
2728
2729 if (!dict) {
2730 if (strcasecmp(root.name, "internal") != 0) {
2731 fr_strerror_printf("Unknown protocol '%s'", root.name);
2732 memcpy(out, &dict_def, sizeof(*out));
2733 fr_sbuff_set_to_start(&our_name);
2734 FR_SBUFF_ERROR_RETURN(&our_name);
2735 }
2736
2737 dict = dict_gctx->internal;
2738 }
2739
2740 *out = dict;
2741
2742 FR_SBUFF_SET_RETURN(name, &our_name);
2743}
2744
2745/** Look up a protocol name embedded in another string
2746 *
2747 * @param[out] err Parsing error.
2748 * @param[out] out the resolve dictionary or NULL if the dictionary
2749 * couldn't be resolved.
2750 * @param[in] name string start.
2751 * @param[in] dict_def The dictionary to return if no dictionary qualifier was found.
2752 * @return
2753 * - 0 and *out != NULL. Couldn't find a dictionary qualifier, so returned dict_def.
2754 * - < 0 on error and (*out == NULL) (offset as negative integer)
2755 * - > 0 on success (number of bytes parsed).
2756 */
2761
2762/** Internal version of #fr_dict_by_protocol_name
2763 *
2764 * @note For internal use by the dictionary API only.
2765 *
2766 * @copybrief fr_dict_by_protocol_name
2767 */
2769{
2770 if (!dict_gctx || !name) return NULL;
2771
2773 &(fr_dict_t){ .root = &(fr_dict_attr_t){ .name = name } });
2774}
2775
2776/** Internal version of #fr_dict_by_protocol_num
2777 *
2778 * @note For internal use by the dictionary API only.
2779 *
2780 * @copybrief fr_dict_by_protocol_num
2781 */
2783{
2784 if (!dict_gctx) return NULL;
2785
2787 &(fr_dict_t) { .root = &(fr_dict_attr_t){ .attr = num } });
2788}
2789
2790/** Internal version of #fr_dict_by_da
2791 *
2792 * @note For internal use by the dictionary API only.
2793 *
2794 * @copybrief fr_dict_by_da
2795 */
2797{
2798#ifndef NDEBUG
2799 {
2800 fr_dict_attr_t const *da_p = da;
2801 fr_dict_t const *dict;
2802
2803 dict = da->dict;
2804 while (da_p->parent) {
2805 da_p = da_p->parent;
2806 fr_cond_assert_msg(da_p->dict == dict, "Inconsistent dict membership. "
2807 "Expected %s, got %s",
2808 !da_p->dict ? "(null)" : fr_dict_root(da_p->dict)->name,
2809 !dict ? "(null)" : fr_dict_root(dict)->name);
2810 DA_VERIFY(da_p);
2811 }
2812
2813 if (!da_p->flags.is_root) {
2814 fr_strerror_printf("%s: Attribute %s has not been inserted into a dictionary",
2815 __FUNCTION__, da->name);
2816 return NULL;
2817 }
2818 }
2819#endif
2820
2821 /*
2822 * Parent of the root attribute must
2823 * be the dictionary.
2824 */
2825 return talloc_get_type_abort(da->dict, fr_dict_t);
2826}
2827
2828/** Lookup a protocol by its name
2829 *
2830 * @note For internal use by the dictionary API only.
2831 *
2832 * @param[in] name of the protocol to locate.
2833 * @return
2834 * - Attribute matching name.
2835 * - NULL if no matching protocol could be found.
2836 */
2838{
2840}
2841
2842/** Lookup a protocol by its number
2843 *
2844 * Returns the #fr_dict_t belonging to the protocol with the specified number
2845 * if any have been registered.
2846 *
2847 * @param[in] num to search for.
2848 * @return dictionary representing the protocol (if it exists).
2849 */
2850fr_dict_t const *fr_dict_by_protocol_num(unsigned int num)
2851{
2852 return dict_by_protocol_num(num);
2853}
2854
2855/** Attempt to locate the protocol dictionary containing an attribute
2856 *
2857 * @note Unlike fr_dict_by_attr_name, doesn't search through all the dictionaries,
2858 * just uses the fr_dict_attr_t hierarchy and the talloc hierarchy to locate
2859 * the dictionary (much much faster and more scalable).
2860 *
2861 * @param[in] da To get the containing dictionary for.
2862 * @return
2863 * - The dictionary containing da.
2864 * - NULL.
2865 */
2867{
2868 return dict_by_da(da);
2869}
2870
2871/** See if two dictionaries have the same end parent
2872 *
2873 * @param[in] dict1 one dictionary
2874 * @param[in] dict2 two dictionary
2875 * @return
2876 * - true the dictionaries have the same end parent
2877 * - false the dictionaries do not have the same end parent.
2878 */
2879bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
2880{
2881 while (dict1->next) dict1 = dict1->next;
2882
2883 while (dict2->next) dict2 = dict2->next;
2884
2885 return (dict1 == dict2);
2886}
2887
2888/** Look up a vendor by one of its child attributes
2889 *
2890 * @param[in] da The vendor attribute.
2891 * @return
2892 * - The vendor.
2893 * - NULL if no vendor with that number was registered for this protocol.
2894 */
2896{
2897 fr_dict_t *dict;
2899
2901 if (!dv.pen) return NULL;
2902
2903 dict = dict_by_da(da);
2904
2905 return fr_hash_table_find(dict->vendors_by_num, &dv);
2906}
2907
2908/** Look up a vendor by its name
2909 *
2910 * @param[in] dict of protocol context we're operating in.
2911 * If NULL the internal dictionary will be used.
2912 * @param[in] name to search for.
2913 * @return
2914 * - The vendor.
2915 * - NULL if no vendor with that name was registered for this protocol.
2916 */
2918{
2919 fr_dict_vendor_t *found;
2920
2921 INTERNAL_IF_NULL(dict, NULL);
2922
2923 if (!name) return NULL;
2924
2925 found = fr_hash_table_find(dict->vendors_by_name, &(fr_dict_vendor_t) { .name = name });
2926 if (!found) return NULL;
2927
2928 return found;
2929}
2930
2931/** Look up a vendor by its PEN
2932 *
2933 * @param[in] dict of protocol context we're operating in.
2934 * If NULL the internal dictionary will be used.
2935 * @param[in] vendor_pen to search for.
2936 * @return
2937 * - The vendor.
2938 * - NULL if no vendor with that number was registered for this protocol.
2939 */
2941{
2942 INTERNAL_IF_NULL(dict, NULL);
2943
2944 return fr_hash_table_find(dict->vendors_by_num, &(fr_dict_vendor_t) { .pen = vendor_pen });
2945}
2946
2947/** Return vendor attribute for the specified dictionary and pen
2948 *
2949 * @param[in] vendor_root of the vendor root attribute. Could be 26 (for example) in RADIUS.
2950 * @param[in] vendor_pen to find.
2951 * @return
2952 * - NULL if vendor does not exist.
2953 * - A fr_dict_attr_t representing the vendor in the dictionary hierarchy.
2954 */
2956{
2957 fr_dict_attr_t const *vendor;
2958
2959 switch (vendor_root->type) {
2960 case FR_TYPE_VSA: /* Vendor specific attribute */
2961 break;
2962
2963 default:
2964 fr_strerror_printf("Wrong type for vendor root, expected '%s', got '%s'",
2966 fr_type_to_str(vendor_root->type));
2967 return NULL;
2968 }
2969
2970 vendor = dict_attr_child_by_num(vendor_root, vendor_pen);
2971 if (!vendor) {
2972 fr_strerror_printf("Vendor %u not defined", vendor_pen);
2973 return NULL;
2974 }
2975
2976 if (vendor->type != FR_TYPE_VENDOR) {
2977 fr_strerror_printf("Wrong type for vendor, expected '%s' got '%s'",
2978 fr_type_to_str(vendor->type),
2980 return NULL;
2981 }
2982
2983 return vendor;
2984}
2985
2986/** Callback function for resolving dictionary attributes
2987 *
2988 * @param[out] err Where to write error codes. Any error
2989 * other than FR_DICT_ATTR_NOTFOUND will
2990 * prevent resolution from continuing.
2991 * @param[out] out Where to write resolved DA.
2992 * @param[in] parent The dictionary root or other attribute to search from.
2993 * @param[in] in Contains the string to resolve.
2994 * @param[in] tt Terminal sequences to use to determine the portion
2995 * of in to search.
2996 * @return
2997 * - < 0 on failure.
2998 * - The number of bytes of name consumed on success.
2999 */
3001 fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
3002 fr_sbuff_t *in, fr_sbuff_term_t const *tt);
3003
3004/** Internal function for searching for attributes in multiple dictionaries
3005 *
3006 * @param[out] err Any errors that occurred searching.
3007 * @param[out] out The attribute we found.
3008 * @param[in] dict_def The default dictionary to search in.
3009 * @param[in] in string to resolve to an attribute.
3010 * @param[in] tt terminals that indicate the end of the string.
3011 * @param[in] internal Resolve the attribute in the internal dictionary.
3012 * @param[in] foreign Resolve attribute in a foreign dictionary,
3013 * i.e. one other than dict_def.
3014 * @param[in] func to use for resolution.
3015 * @return
3016 * - <=0 on error (the offset of the error).
3017 * - >0 on success.
3018 */
3019static inline CC_HINT(always_inline)
3021 fr_dict_t const *dict_def,
3022 fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3023 bool internal, bool foreign,
3025{
3027 fr_hash_iter_t iter;
3028 fr_dict_t *dict = NULL;
3029 fr_sbuff_t our_in = FR_SBUFF(in);
3030
3031 if (internal && !dict_gctx->internal) internal = false;
3032
3033 /*
3034 * Always going to fail...
3035 */
3036 if (unlikely(!internal && !foreign && !dict_def)) {
3037 if (err) *err = FR_DICT_ATTR_EINVAL;
3038 *out = NULL;
3039 return 0;
3040 }
3041
3042 /*
3043 * dict_def search in the specified dictionary
3044 */
3045 if (dict_def) {
3046 (void)func(&our_err, out, fr_dict_root(dict_def), &our_in, tt);
3047 switch (our_err) {
3048 case FR_DICT_ATTR_OK:
3049 FR_SBUFF_SET_RETURN(in, &our_in);
3050
3052 if (!internal && !foreign) goto error;
3053 break;
3054
3055 default:
3056 goto error;
3057 }
3058 }
3059
3060 /*
3061 * Next in the internal dictionary
3062 */
3063 if (internal) {
3064 (void)func(&our_err, out, fr_dict_root(dict_gctx->internal), &our_in, tt);
3065 switch (our_err) {
3066 case FR_DICT_ATTR_OK:
3067 FR_SBUFF_SET_RETURN(in, &our_in);
3068
3070 if (!foreign) goto error;
3071 break;
3072
3073 default:
3074 goto error;
3075 }
3076 }
3077
3078 /*
3079 * Now loop over the protocol dictionaries
3080 */
3082 dict;
3084 if (dict == dict_def) continue;
3085 if (dict == dict_gctx->internal) continue;
3086
3087 (void)func(&our_err, out, fr_dict_root(dict), &our_in, tt);
3088 switch (our_err) {
3089 case FR_DICT_ATTR_OK:
3090 FR_SBUFF_SET_RETURN(in, &our_in);
3091
3093 continue;
3094
3095 default:
3096 break;
3097 }
3098 }
3099
3100error:
3101 /*
3102 * Add a more helpful error message about
3103 * which dictionaries we tried to locate
3104 * the attribute in.
3105 */
3106 if (our_err == FR_DICT_ATTR_NOTFOUND) {
3107 fr_sbuff_marker_t start;
3108 char *list = NULL;
3109
3110#define DICT_NAME_APPEND(_in, _dict) \
3111do { \
3112 char *_n; \
3113 _n = talloc_strdup_append_buffer(_in, fr_dict_root(_dict)->name); \
3114 if (unlikely(!_n)) { \
3115 talloc_free(_in); \
3116 goto done; \
3117 } \
3118 _in = _n; \
3119 _n = talloc_strdup_append_buffer(_in, ", "); \
3120 if (unlikely(!_n)) { \
3121 talloc_free(_in); \
3122 goto done; \
3123 } \
3124 _in = _n; \
3125} while (0)
3126
3127 our_in = FR_SBUFF(in);
3128 fr_sbuff_marker(&start, &our_in);
3129
3130 list = talloc_strdup(NULL, "");
3131 if (unlikely(!list)) goto done;
3132
3133 if (dict_def) DICT_NAME_APPEND(list, dict_def);
3134 if (internal) DICT_NAME_APPEND(list, dict_gctx->internal);
3135
3136 if (foreign) {
3138 dict;
3140 if (dict == dict_def) continue;
3141 if (dict == dict_gctx->internal) continue;
3142
3143 if (internal) DICT_NAME_APPEND(list, dict);
3144 }
3145 }
3146
3147 fr_strerror_printf("Attribute '%pV' not found. Searched in: %pV",
3149 fr_sbuff_adv_until(&our_in, SIZE_MAX, tt, '\0')),
3150 fr_box_strvalue_len(list, talloc_array_length(list) - 3));
3151
3152 talloc_free(list);
3153 }
3154
3155done:
3156 if (err) *err = our_err;
3157 *out = NULL;
3158
3159 FR_SBUFF_ERROR_RETURN(&our_in);
3160}
3161
3162/** Internal function for searching for attributes in multiple dictionaries
3163 *
3164 * Unlike #dict_attr_search this function searches for a protocol name preceding
3165 * the attribute identifier.
3166 */
3167static inline CC_HINT(always_inline)
3169 fr_dict_t const *dict_def,
3170 fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3171 bool internal, bool foreign,
3173{
3174 fr_sbuff_t our_in = FR_SBUFF(in);
3175 fr_dict_attr_err_t our_err;
3176 fr_dict_t *initial;
3177 fr_slen_t slen;
3178
3179 /*
3180 * Check for dictionary prefix
3181 */
3182 slen = dict_by_protocol_substr(&our_err, &initial, &our_in, dict_def);
3183 if (our_err != FR_DICT_ATTR_OK) {
3184 error:
3185 if (err) *err = our_err;
3186 *out = NULL;
3187 FR_SBUFF_ERROR_RETURN(&our_in);
3188 }
3189
3190 /*
3191 * Has dictionary qualifier, can't fallback
3192 */
3193 if (slen > 0) {
3194 /*
3195 * Next thing SHOULD be a '.'
3196 */
3197 if (!fr_sbuff_next_if_char(&our_in, '.')) {
3199 *out = NULL;
3200 FR_SBUFF_ERROR_RETURN(&our_in);
3201 }
3202
3203 internal = foreign = false;
3204 }
3205
3206 if (dict_attr_search(&our_err, out, initial, &our_in, tt, internal, foreign, func) < 0) goto error;
3207 if (err) *err = FR_DICT_ATTR_OK;
3208
3209 FR_SBUFF_SET_RETURN(in, &our_in);
3210}
3211
3212/** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
3213 *
3214 * This function will search through all loaded dictionaries, or a subset of
3215 * loaded dictionaries, for a matching attribute in the top level namespace.
3216 *
3217 * This attribute may be qualified with `<protocol>.` to selection an attribute
3218 * in a specific case.
3219 *
3220 * @note If calling this function from the server any list or request qualifiers
3221 * should be stripped first.
3222 *
3223 * @param[out] err Why parsing failed. May be NULL.
3224 * @see fr_dict_attr_err_t
3225 * @param[out] out Dictionary found attribute.
3226 * @param[in] dict_def Default dictionary for non-qualified dictionaries.
3227 * @param[in] name Dictionary/Attribute name.
3228 * @param[in] tt Terminal strings.
3229 * @param[in] internal If true, fallback to the internal dictionary.
3230 * @param[in] foreign If true, fallback to foreign dictionaries.
3231 * @return
3232 * - < 0 on failure.
3233 * - The number of bytes of name consumed on success.
3234 */
3236 fr_dict_t const *dict_def,
3237 fr_sbuff_t *name, fr_sbuff_term_t const *tt,
3238 bool internal, bool foreign)
3239{
3240 return dict_attr_search_qualified(err, out, dict_def, name, tt,
3241 internal, foreign, fr_dict_attr_by_name_substr);
3242}
3243
3244/** Locate a #fr_dict_attr_t by its name in the top level namespace of a dictionary
3245 *
3246 * This function will search through all loaded dictionaries, or a subset of
3247 * loaded dictionaries, for a matching attribute in the top level namespace.
3248 *
3249 * @note If calling this function from the server any list or request qualifiers
3250 * should be stripped first.
3251 *
3252 * @param[out] err Why parsing failed. May be NULL.
3253 * @see fr_dict_attr_err_t
3254 * @param[out] out Dictionary found attribute.
3255 * @param[in] dict_def Default dictionary for non-qualified dictionaries.
3256 * @param[in] name Dictionary/Attribute name.
3257 * @param[in] tt Terminal strings.
3258 * @param[in] internal If true, fallback to the internal dictionary.
3259 * @param[in] foreign If true, fallback to foreign dictionaries.
3260 * @return
3261 * - < 0 on failure.
3262 * - The number of bytes of name consumed on success.
3263 */
3265 fr_dict_t const *dict_def,
3266 fr_sbuff_t *name, fr_sbuff_term_t const *tt,
3267 bool internal, bool foreign)
3268{
3269 return dict_attr_search_qualified(err, out, dict_def, name, tt,
3270 internal, foreign, fr_dict_attr_by_name_substr);
3271}
3272
3273/** Locate a qualified #fr_dict_attr_t by a dictionary qualified OID string
3274 *
3275 * This function will search through all loaded dictionaries, or a subset of
3276 * loaded dictionaries, for a matching attribute.
3277 *
3278 * @note If calling this function from the server any list or request qualifiers
3279 * should be stripped first.
3280 *
3281 * @note err should be checked to determine if a parse error occurred.
3282 *
3283 * @param[out] err Why parsing failed. May be NULL.
3284 * @see fr_dict_attr_err_t
3285 * @param[out] out Dictionary found attribute.
3286 * @param[in] dict_def Default dictionary for non-qualified dictionaries.
3287 * @param[in] in Dictionary/Attribute name.
3288 * @param[in] tt Terminal strings.
3289 * @param[in] internal If true, fallback to the internal dictionary.
3290 * @param[in] foreign If true, fallback to foreign dictionaries.
3291 * @return The number of bytes of name consumed.
3292 */
3294 fr_dict_t const *dict_def,
3295 fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3296 bool internal, bool foreign)
3297{
3298 return dict_attr_search_qualified(err, out, dict_def, in, tt,
3299 internal, foreign, fr_dict_attr_by_oid_substr);
3300}
3301
3302/** Locate a qualified #fr_dict_attr_t by a dictionary using a non-qualified OID string
3303 *
3304 * This function will search through all loaded dictionaries, or a subset of
3305 * loaded dictionaries, for a matching attribute.
3306 *
3307 * @note If calling this function from the server any list or request qualifiers
3308 * should be stripped first.
3309 *
3310 * @note err should be checked to determine if a parse error occurred.
3311 *
3312 * @param[out] err Why parsing failed. May be NULL.
3313 * @see fr_dict_attr_err_t
3314 * @param[out] out Dictionary found attribute.
3315 * @param[in] dict_def Default dictionary for non-qualified dictionaries.
3316 * @param[in] in Dictionary/Attribute name.
3317 * @param[in] tt Terminal strings.
3318 * @param[in] internal If true, fallback to the internal dictionary.
3319 * @param[in] foreign If true, fallback to foreign dictionaries.
3320 * @return The number of bytes of name consumed.
3321 */
3323 fr_dict_t const *dict_def,
3324 fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3325 bool internal, bool foreign)
3326{
3327 return dict_attr_search_qualified(err, out, dict_def, in, tt,
3328 internal, foreign, fr_dict_attr_by_oid_substr);
3329}
3330
3331/** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
3332 *
3333 * @param[out] err Why parsing failed. May be NULL.
3334 * @see fr_dict_attr_err_t.
3335 * @param[in] dict_def Default dictionary for non-qualified dictionaries.
3336 * @param[in] name Dictionary/Attribute name.
3337 * @param[in] internal If true, fallback to the internal dictionary.
3338 * @param[in] foreign If true, fallback to foreign dictionaries.
3339 * @return an #fr_dict_attr_err_t value.
3340 */
3342 char const *name,
3343 bool internal, bool foreign)
3344{
3345 ssize_t slen;
3346 fr_sbuff_t our_name;
3347 fr_dict_attr_t const *da;
3348 fr_dict_attr_err_t our_err;
3349
3350 fr_sbuff_init_in(&our_name, name, strlen(name));
3351
3352 slen = fr_dict_attr_search_by_qualified_oid_substr(&our_err, &da, dict_def, &our_name, NULL, internal, foreign);
3353 if (our_err != FR_DICT_ATTR_OK) {
3354 if (err) *err = our_err;
3355 return NULL;
3356 }
3357 if ((size_t)slen != fr_sbuff_len(&our_name)) {
3358 fr_strerror_printf("Trailing garbage after attr string \"%s\"", name);
3360 return NULL;
3361 }
3362
3363 return da;
3364}
3365
3366/** Look up a dictionary attribute by a name embedded in another string
3367 *
3368 * Find the first invalid attribute name char in the string pointed
3369 * to by name.
3370 *
3371 * Copy the characters between the start of the name string and the first
3372 * none #fr_dict_attr_allowed_chars char to a buffer and perform a dictionary lookup
3373 * using that value.
3374 *
3375 * If the attribute exists, advance the pointer pointed to by name
3376 * to the first none #fr_dict_attr_allowed_chars char, and return the DA.
3377 *
3378 * If the attribute does not exist, don't advance the pointer and return
3379 * NULL.
3380 *
3381 * @param[out] err Why parsing failed. May be NULL.
3382 * @see fr_dict_attr_err_t
3383 * @param[out] out Where to store the resolve attribute.
3384 * @param[in] parent containing the namespace to search in.
3385 * @param[in] name string start.
3386 * @param[in] tt Terminal sequences to use to determine the portion
3387 * of in to search.
3388 * @return
3389 * - <= 0 on failure.
3390 * - The number of bytes of name consumed on success.
3391 */
3394{
3395 fr_dict_attr_t const *da;
3396 size_t len;
3397 fr_dict_attr_t const *ref;
3398 char const *p;
3399 char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
3400 fr_sbuff_t our_name = FR_SBUFF(name);
3401 fr_hash_table_t *namespace;
3402
3403 *out = NULL;
3404
3405#ifdef STATIC_ANALYZER
3406 memset(buffer, 0, sizeof(buffer));
3407#endif
3408
3410 &our_name, SIZE_MAX,
3412 if (len == 0) {
3413 fr_strerror_const("Zero length attribute name");
3415 FR_SBUFF_ERROR_RETURN(&our_name);
3416 }
3417 if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
3418 fr_strerror_const("Attribute name too long");
3420 FR_SBUFF_ERROR_RETURN(&our_name);
3421 }
3422
3423 /*
3424 * Do a second pass, ensuring that the name has at least one alphanumeric character.
3425 */
3426 for (p = buffer; p < (buffer + len); p++) {
3427 if (sbuff_char_alpha_num[(uint8_t) *p]) break;
3428 }
3429
3430 if ((size_t) (p - buffer) == len) {
3431 fr_strerror_const("Invalid attribute name");
3433 FR_SBUFF_ERROR_RETURN(&our_name);
3434 }
3435
3436 ref = fr_dict_attr_ref(parent);
3437 if (ref) parent = ref;
3438
3439redo:
3440 namespace = dict_attr_namespace(parent);
3441 if (!namespace) {
3442 fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
3444 fr_sbuff_set_to_start(&our_name);
3445 FR_SBUFF_ERROR_RETURN(&our_name);
3446 }
3447
3448 da = fr_hash_table_find(namespace, &(fr_dict_attr_t){ .name = buffer });
3449 if (!da) {
3450 if (parent->flags.is_root) {
3451 fr_dict_t const *dict = fr_dict_by_da(parent);
3452
3453 if (dict->next) {
3454 parent = dict->next->root;
3455 goto redo;
3456 }
3457 }
3458
3460 fr_strerror_printf("Attribute '%s' not found in namespace '%s'", buffer, parent->name);
3461 fr_sbuff_set_to_start(&our_name);
3462 FR_SBUFF_ERROR_RETURN(&our_name);
3463 }
3464
3465 da = dict_attr_alias(err, da);
3466 if (unlikely(!da)) FR_SBUFF_ERROR_RETURN(&our_name);
3467
3468 *out = da;
3469 if (err) *err = FR_DICT_ATTR_OK;
3470
3471 FR_SBUFF_SET_RETURN(name, &our_name);
3472}
3473
3474/* Internal version of fr_dict_attr_by_name
3475 *
3476 */
3478{
3479 fr_hash_table_t *namespace;
3480 fr_dict_attr_t *da;
3481
3483
3484redo:
3485 namespace = dict_attr_namespace(parent);
3486 if (!namespace) {
3487 fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
3489 return NULL;
3490 }
3491
3492 da = fr_hash_table_find(namespace, &(fr_dict_attr_t) { .name = name });
3493 if (!da) {
3494 if (parent->flags.is_root) {
3495 fr_dict_t const *dict = fr_dict_by_da(parent);
3496
3497 if (dict->next) {
3498 parent = dict->next->root;
3499 goto redo;
3500 }
3501 }
3502
3504 fr_strerror_printf("Attribute '%s' not found in namespace '%s'", name, parent->name);
3505 return NULL;
3506 }
3507
3508 if (err) *err = FR_DICT_ATTR_OK;
3509
3510 return da;
3511}
3512
3513/** Locate a #fr_dict_attr_t by its name
3514 *
3515 * @param[out] err Why the lookup failed. May be NULL.
3516 * @see fr_dict_attr_err_t.
3517 * @param[in] parent containing the namespace we're searching in.
3518 * @param[in] name of the attribute to locate.
3519 * @return
3520 * - Attribute matching name.
3521 * - NULL if no matching attribute could be found.
3522 */
3524{
3525 fr_dict_attr_t const *da;
3526
3528
3530 if (!da) return NULL;
3531
3532 da = dict_attr_alias(err, da);
3533 if (unlikely(!da)) return NULL;
3534
3535 return da;
3536}
3537
3538/** Internal version of fr_dict_attr_child_by_num
3539 *
3540 */
3542{
3543 fr_dict_attr_t const *bin;
3544 fr_dict_attr_t const **children;
3545 fr_dict_attr_t const *ref;
3546
3548
3549 /*
3550 * Do any necessary dereferencing
3551 */
3552 ref = fr_dict_attr_ref(parent);
3553 if (ref) parent = ref;
3554
3555 children = dict_attr_children(parent);
3556 if (!children) return NULL;
3557
3558 /*
3559 * Child arrays may be trimmed back to save memory.
3560 * Check that so we don't SEGV.
3561 */
3562 if ((attr & 0xff) >= talloc_array_length(children)) return NULL;
3563
3564 bin = children[attr & 0xff];
3565 for (;;) {
3566 if (!bin) return NULL;
3567 if (bin->attr == attr) {
3569
3570 memcpy(&out, &bin, sizeof(bin));
3571
3572 return out;
3573 }
3574 bin = bin->next;
3575 }
3576
3577 return NULL;
3578}
3579
3580/** Check if a child attribute exists in a parent using an attribute number
3581 *
3582 * @param[in] parent to check for child in.
3583 * @param[in] attr number to look for.
3584 * @return
3585 * - The child attribute on success.
3586 * - NULL if the child attribute does not exist.
3587 */
3589{
3590 fr_dict_attr_t const *da;
3591
3592 da = dict_attr_child_by_num(parent, attr);
3593 if (!da) return NULL;
3594
3595 da = dict_attr_alias(NULL, da);
3596 if (unlikely(!da)) return NULL;
3597
3598 return da;
3599}
3600
3601/** Iterate over all enumeration values for an attribute
3602 *
3603 * @param[in] da to iterate over.
3604 * @param[in] iter to use for iteration.
3605 * @return
3606 * - First #fr_dict_enum_value_t in the attribute.
3607 * - NULL if no enumeration values exist.
3608 */
3610{
3612
3614 if (!ext) {
3615 fr_strerror_printf("%s has no enumeration values to iterate over", da->name);
3616 return NULL;
3617 }
3618
3619 return fr_hash_table_iter_init(ext->value_by_name, iter);
3620}
3621
3622/* Iterate over next enumeration value for an attribute
3623 *
3624 * @param[in] da to iterate over.
3625 * @param[in] iter to use for iteration.
3626 * @return
3627 * - Next #fr_dict_enum_value_t in the attribute.
3628 * - NULL if no more enumeration values exist.
3629 */
3631{
3634 if (!ext) {
3635 fr_strerror_printf("%s has no enumeration values to iterate over", da->name);
3636 return NULL;
3637 }
3638
3639 return fr_hash_table_iter_next(ext->value_by_name, iter);;
3640}
3641
3642/** Lookup the structure representing an enum value in a #fr_dict_attr_t
3643 *
3644 * @param[in] da to search in.
3645 * @param[in] value to search for.
3646 * @return
3647 * - Matching #fr_dict_enum_value_t.
3648 * - NULL if no matching #fr_dict_enum_value_t could be found.
3649 */
3651{
3653
3655 if (!ext) {
3656 fr_strerror_printf("VALUE cannot be defined for %s attributes",
3657 fr_type_to_str(da->type));
3658 return NULL;
3659 }
3660
3661 /*
3662 * No values associated with this attribute
3663 */
3664 if (!ext->name_by_value) return NULL;
3665
3666 /*
3667 * Could be NULL or an unknown attribute, in which case
3668 * we want to avoid the lookup gracefully...
3669 */
3670 if (value->type != da->type) return NULL;
3671
3672 return fr_hash_table_find(ext->name_by_value, &(fr_dict_enum_value_t){ .value = value });
3673}
3674
3675/** Lookup the name of an enum value in a #fr_dict_attr_t
3676 *
3677 * @param[in] da to search in.
3678 * @param[in] value number to search for.
3679 * @return
3680 * - Name of value.
3681 * - NULL if no matching value could be found.
3682 */
3684{
3685 fr_dict_enum_value_t const *dv;
3686
3687 dv = fr_dict_enum_by_value(da, value);
3688 if (!dv) return NULL;
3689
3690 return dv->name;
3691}
3692
3693/*
3694 * Get a value by its name, keyed off of an attribute.
3695 */
3697{
3699
3700 if (!name) return NULL;
3701
3703 if (!ext) {
3704 fr_strerror_printf("VALUE cannot be defined for %s attributes",
3705 fr_type_to_str(da->type));
3706 return NULL;
3707 }
3708
3709 /*
3710 * No values associated with this attribute
3711 */
3712 if (!ext->value_by_name) return NULL;
3713
3714 if (len < 0) len = strlen(name);
3715
3716 return fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = name, .name_len = len});
3717}
3718
3719/*
3720 * Get a value by its name, keyed off of an attribute, from an sbuff
3721 */
3723{
3725 fr_sbuff_t our_in = FR_SBUFF(in);
3726 fr_dict_enum_value_t *found = NULL;
3727 size_t found_len = 0;
3728 uint8_t *p;
3730
3731 /*
3732 * No values associated with this attribute, do nothing.
3733 */
3735 if (!ext || !ext->value_by_name) return 0;
3736
3737 /*
3738 * Loop until we exhaust all of the possibilities.
3739 */
3740 for (p = name; (size_t) (p - name) < ext->max_name_len; p++) {
3741 int len = (p - name) + 1;
3742 fr_dict_enum_value_t *enumv;
3743
3744 *p = fr_sbuff_char(&our_in, '\0');
3745 if (!fr_dict_enum_allowed_chars[*p]) {
3746 break;
3747 }
3748 fr_sbuff_next(&our_in);
3749
3750 enumv = fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = (char const *) name,
3751 .name_len = len});
3752
3753 /*
3754 * Return the LONGEST match, as there may be
3755 * overlaps. e.g. "Framed", and "Framed-User".
3756 */
3757 if (enumv) {
3758 found = enumv;
3759 found_len = len;
3760 }
3761 }
3762
3763 if (found) {
3764 *out = found;
3765 FR_SBUFF_SET_RETURN(in, found_len);
3766 }
3767
3768 return 0;
3769}
3770
3771/** Extract an enumeration name from a string
3772 *
3773 * This function defines the canonical format for an enumeration name.
3774 *
3775 * An enumeration name is made up of one or more fr_dict_attr_allowed_chars
3776 * with at least one character in the sequence not being a special character
3777 * i.e. [-+/_] or a number.
3778 *
3779 * This disambiguates enumeration identifiers from mathematical expressions.
3780 *
3781 * If we allowed enumeration names consisting of sequences of numbers separated
3782 * by special characters it would not be possible to determine if the special
3783 * character were an operator in a subexpression.
3784 *
3785 * For example take:
3786 *
3787 * &My-Enum-Attr == 01234-5678
3788 *
3789 * Without having access to the enumeration values of My-Enum-Attr (which we
3790 * might not have during tokenisation), we cannot tell if this is:
3791 *
3792 * (&My-Enum-Attr == 01234-5678)
3793 *
3794 * OR
3795 *
3796 * ((&My-Enum-Attr == 01234) - 5678)
3797 *
3798 * If an alpha character occurs anywhere in the string i.e:
3799 *
3800 * (&My-Enum-Attr == 01234-A5678)
3801 *
3802 * we know 01234-A5678 can't be a mathematical sub-expression because the
3803 * second potential operand can no longer be parsed as an integer constant.
3804 *
3805 * @param[out] out The name string we managed to extract.
3806 * May be NULL in which case only the length of the name
3807 * will be returned.
3808 * @param[out] err Type of parsing error which occurred. May be NULL.
3809 * @param[in] in The string containing the enum identifier.
3810 * @param[in] tt If non-null verify that a terminal sequence occurs
3811 * after the enumeration name.
3812 * @return
3813 * - <0 the offset at which the parse error occurred.
3814 * - >1 the number of bytes parsed.
3815 */
3817 fr_sbuff_t *in, fr_sbuff_term_t const *tt)
3818{
3819 fr_sbuff_t our_in = FR_SBUFF(in);
3820 bool seen_alpha = false;
3821
3822 while (fr_sbuff_is_in_charset(&our_in, fr_dict_enum_allowed_chars)) {
3823 if (fr_sbuff_is_alpha(&our_in)) seen_alpha = true;
3824 fr_sbuff_next(&our_in);
3825 }
3826
3827 if (!seen_alpha) {
3828 if (fr_sbuff_used(&our_in) == 0) {
3829 fr_strerror_const("VALUE name is empty");
3831 FR_SBUFF_ERROR_RETURN(&our_in);
3832 }
3833
3834 fr_strerror_const("VALUE name must contain at least one alpha character");
3836 fr_sbuff_set_to_start(&our_in); /* Marker should be at the start of the enum */
3837 FR_SBUFF_ERROR_RETURN(&our_in);
3838 }
3839
3840 /*
3841 * Check that the sequence is correctly terminated
3842 */
3843 if (tt && !fr_sbuff_is_terminal(&our_in, tt)) {
3844 fr_strerror_const("VALUE name has trailing text");
3846 FR_SBUFF_ERROR_RETURN(&our_in);
3847 }
3848
3849 if (out) return fr_sbuff_out_bstrncpy_exact(out, in, fr_sbuff_used(&our_in));
3850
3851 if (err) *err = FR_SBUFF_PARSE_OK;
3852
3853 FR_SBUFF_SET_RETURN(in, &our_in);
3854}
3855
3856int dict_dlopen(fr_dict_t *dict, char const *name)
3857{
3858 char *lib_name;
3859 char *sym_name;
3860 fr_dict_protocol_t *proto;
3861
3862 if (!name) return 0;
3863
3864 lib_name = talloc_typed_asprintf(NULL, "libfreeradius-%s", name);
3865 if (unlikely(lib_name == NULL)) {
3866 oom:
3867 fr_strerror_const("Out of memory");
3868 return -1;
3869 }
3870 talloc_bstr_tolower(lib_name);
3871
3872 dict->dl = dl_by_name(dict_gctx->dict_loader, lib_name, NULL, false);
3873 if (!dict->dl) {
3874 fr_strerror_printf_push("Failed loading dictionary validation library \"%s\"", lib_name);
3875 talloc_free(lib_name);
3876 return -1;
3877 }
3878 talloc_free(lib_name);
3879
3880 /*
3881 * The public symbol that contains per-protocol rules
3882 * and extensions.
3883 *
3884 * It ends up being easier to do this using dlsym to
3885 * resolve the symbol and not use the autoloader
3886 * callbacks as theoretically multiple dictionaries
3887 * could use the same protocol library, and then the
3888 * autoloader callback would only run for the first
3889 * dictionary which loaded the protocol.
3890 */
3891 sym_name = talloc_typed_asprintf(NULL, "libfreeradius_%s_dict_protocol", name);
3892 if (unlikely(sym_name == NULL)) {
3893 goto oom;
3894 }
3895 talloc_bstr_tolower(sym_name);
3896
3897 /*
3898 * De-hyphenate the symbol name
3899 */
3900 {
3901 char *p, *q;
3902
3903 for (p = sym_name, q = p + (talloc_strlen(sym_name)); p < q; p++) *p = *p == '-' ? '_' : *p;
3904 }
3905
3906 proto = dlsym(dict->dl->handle, sym_name);
3907 talloc_free(sym_name);
3908
3909 /*
3910 * Soft failure, not all protocol libraires provide
3911 * custom validation functions or flats.
3912 */
3913 if (!proto) return 0;
3914
3915 /*
3916 * Replace the default protocol with the custom one
3917 * if we have it...
3918 */
3919 dict->proto = proto;
3920
3921 return 0;
3922}
3923
3924/** Find a dependent in the tree of dependents
3925 *
3926 */
3927static int8_t _dict_dependent_cmp(void const *a, void const *b)
3928{
3929 fr_dict_dependent_t const *dep_a = a;
3930 fr_dict_dependent_t const *dep_b = b;
3931 int ret;
3932
3933 ret = strcmp(dep_a->dependent, dep_b->dependent);
3934 return CMP(ret, 0);
3935}
3936
3937/** Record a new dependency on a dictionary
3938 *
3939 * These are used to determine what is currently depending on a dictionary.
3940 *
3941 * @param[in] dict to record dependency on.
3942 * @param[in] dependent Either C src file, or another dictionary.
3943 * @return
3944 * - 0 on success.
3945 * - -1 on failure.
3946 */
3947int dict_dependent_add(fr_dict_t *dict, char const *dependent)
3948{
3949 fr_dict_dependent_t *found;
3950
3951 found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
3952 if (!found) {
3954
3955 new = talloc_zero(dict->dependents, fr_dict_dependent_t);
3956 if (unlikely(!new)) return -1;
3957
3958 /*
3959 * If the dependent is in a module that gets
3960 * unloaded, any strings in the text area also
3961 * get unloaded (including dependent locations).
3962 *
3963 * Strdup the string here so we don't get
3964 * random segfaults if a module forgets to unload
3965 * a dictionary.
3966 */
3967 new->dependent = talloc_strdup(new, dependent);
3968 fr_rb_insert(dict->dependents, new);
3969
3970 new->count = 1;
3971
3972 return 0;
3973 }
3974
3975 found->count++; /* Increase ref count */
3976
3977 return 0;
3978}
3979
3980/** Manually increase the reference count for a dictionary
3981 *
3982 * This is useful if a previously loaded dictionary needs to
3983 * be bound to the lifetime of an additional object.
3984 *
3985 * @param[in] dict to increase the reference count for.
3986 * @param[in] dependent requesting the loading of the dictionary.
3987 * @return
3988 * - 0 on success.
3989 * - -1 on error.
3990 */
3991int fr_dict_dependent_add(fr_dict_t const *dict, char const *dependent)
3992{
3993 fr_dict_t *m_dict = fr_dict_unconst(dict);
3994
3995 if (unlikely(!m_dict)) return -1;
3996
3997 return dict_dependent_add(m_dict, dependent);
3998}
3999
4000/** Decrement ref count for a dependent in a dictionary
4001 *
4002 * @param[in] dict to remove dependency from.
4003 * @param[in] dependent Either C src, or another dictionary dependent.
4004 * What depends on this dictionary.
4005 */
4006int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
4007{
4008 fr_dict_dependent_t *found;
4009
4010 found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
4011 if (!found) {
4012 fr_strerror_printf("Dependent \"%s\" not found in dictionary \"%s\"", dependent, dict->root->name);
4013 return -1;
4014 }
4015
4016 if (found->count == 0) {
4017 fr_strerror_printf("Zero ref count invalid for dependent \"%s\", dictionary \"%s\"",
4018 dependent, dict->root->name);
4019 return -1;
4020 }
4021
4022 if (--found->count == 0) {
4023 fr_rb_delete(dict->dependents, found);
4024 talloc_free(found);
4025 return 0;
4026 }
4027
4028 return 1;
4029}
4030
4031/** Check if a dictionary still has dependents
4032 *
4033 * @param[in] dict to check
4034 * @return
4035 * - true if there's still at least one dependent.
4036 * - false if there are no dependents.
4037 */
4039{
4040 return (fr_rb_num_elements(dict->dependents) > 0);
4041}
4042
4043#ifndef NDEBUG
4044static void dependent_debug(fr_dict_t *dict)
4045{
4048
4049 if (!dict_has_dependents(dict)) return;
4050
4051 fprintf(stderr, "DEPENDENTS FOR %s\n", dict->root->name);
4052
4053 for (dep = fr_rb_iter_init_inorder(dict->dependents, &iter);
4054 dep;
4055 dep = fr_rb_iter_next_inorder(dict->dependents, &iter)) {
4056 fprintf(stderr, "\t<- %s (%d)\n", dep->dependent, dep->count);
4057 }
4058}
4059#endif
4060
4061
4063{
4064 fr_dict_t **refd_list;
4065 unsigned int i;
4066
4067 if (!dict->autoref) return 0;
4068
4069 if (fr_hash_table_flatten(dict->autoref, (void ***)&refd_list, dict->autoref) < 0) {
4070 fr_strerror_const("failed flattening autoref hash table");
4071 return -1;
4072 }
4073
4074 /*
4075 * Free the dictionary. It will call proto->free() if there's nothing more to do.
4076 */
4077 for (i = 0; i < talloc_array_length(refd_list); i++) {
4078 if (fr_dict_free(&refd_list[i], dict->root->name) < 0) {
4079 fr_strerror_printf("failed freeing autoloaded protocol %s", refd_list[i]->root->name);
4080 return -1;
4081 }
4082 }
4083
4084 TALLOC_FREE(dict->autoref);
4085
4086 return 0;
4087}
4088
4089static int _dict_free(fr_dict_t *dict)
4090{
4091 /*
4092 * We don't necessarily control the order of freeing
4093 * children.
4094 */
4095 if (dict != dict->gctx->internal) {
4096 fr_dict_attr_t const *da;
4097
4098 if (dict->gctx->attr_protocol_encapsulation && dict->root) {
4099 da = fr_dict_attr_child_by_num(dict->gctx->attr_protocol_encapsulation, dict->root->attr);
4100 if (da && fr_dict_attr_ref(da)) dict_attr_ref_null(da);
4101 }
4102 }
4103
4104#ifdef STATIC_ANALYZER
4105 if (!dict->root) {
4106 fr_strerror_const("dict root is missing");
4107 return -1;
4108 }
4109#endif
4110
4111 /*
4112 * If we called init(), then call free()
4113 */
4114 if (dict->proto && dict->proto->free) {
4115 dict->proto->free();
4116 }
4117
4118 if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(dict->gctx->protocol_by_name, dict))) {
4119 fr_strerror_printf("Failed removing dictionary from protocol hash \"%s\"", dict->root->name);
4120 return -1;
4121 }
4122 dict->in_protocol_by_name = false;
4123
4124 if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(dict->gctx->protocol_by_num, dict))) {
4125 fr_strerror_printf("Failed removing dictionary from protocol number_hash \"%s\"", dict->root->name);
4126 return -1;
4127 }
4128 dict->in_protocol_by_num = false;
4129
4130 if (dict_has_dependents(dict)) {
4133
4134 fr_strerror_printf("Refusing to free dictionary \"%s\", still has dependents", dict->root->name);
4135
4136 for (dep = fr_rb_iter_init_inorder(dict->dependents, &iter);
4137 dep;
4138 dep = fr_rb_iter_next_inorder(dict->dependents, &iter)) {
4139 fr_strerror_printf_push("%s (%d)", dep->dependent, dep->count);
4140 }
4141
4142 return -1;
4143 }
4144
4145 /*
4146 * Free the hash tables with free functions first
4147 * so that the things the hash tables reference
4148 * are still there.
4149 */
4150 talloc_free(dict->vendors_by_name);
4151
4152 /*
4153 * Decrease the reference count on the validation
4154 * library we loaded.
4155 */
4156 dl_free(dict->dl);
4157
4158 if (dict == dict->gctx->internal) {
4159 dict->gctx->internal = NULL;
4160 dict->gctx->attr_protocol_encapsulation = NULL;
4161 }
4162
4163 return 0;
4164}
4165
4166/** Allocate a new dictionary
4167 *
4168 * @param[in] ctx to allocate dictionary in.
4169 * @return
4170 * - NULL on memory allocation error.
4171 */
4172fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
4173{
4174 fr_dict_t *dict;
4175
4176 if (!dict_gctx) {
4177 fr_strerror_const("Initialise global dictionary ctx with fr_dict_global_ctx_init()");
4178 return NULL;
4179 }
4180
4181 dict = talloc_zero(ctx, fr_dict_t);
4182 if (!dict) {
4183 fr_strerror_const("Failed allocating memory for dictionary");
4184 error:
4185 talloc_free(dict);
4186 return NULL;
4187 }
4188 dict->gctx = dict_gctx; /* Record which global context this was allocated in */
4189 talloc_set_destructor(dict, _dict_free);
4190
4191 /*
4192 * A list of all the files that constitute this dictionary
4193 */
4194 fr_dlist_talloc_init(&dict->filenames, fr_dict_filename_t, entry);
4195
4196 /*
4197 * Pre-Allocate pool memory for rapid startup
4198 * As that's the working memory required during
4199 * dictionary initialisation.
4200 */
4201 dict->pool = talloc_pool(dict, DICT_POOL_SIZE);
4202 if (!dict->pool) {
4203 fr_strerror_const("Failed allocating talloc pool for dictionary");
4204 goto error;
4205 }
4206
4207 /*
4208 * Create the table of vendor by name. There MAY NOT
4209 * be multiple vendors of the same name.
4210 */
4211 dict->vendors_by_name = fr_hash_table_alloc(dict, dict_vendor_name_hash, dict_vendor_name_cmp, NULL);
4212 if (!dict->vendors_by_name) {
4213 fr_strerror_printf("Failed allocating \"vendors_by_name\" table");
4214 goto error;
4215 }
4216 /*
4217 * Create the table of vendors by value. There MAY
4218 * be vendors of the same value. If there are, we
4219 * pick the latest one.
4220 */
4221 dict->vendors_by_num = fr_hash_table_alloc(dict, dict_vendor_pen_hash, dict_vendor_pen_cmp, NULL);
4222 if (!dict->vendors_by_num) {
4223 fr_strerror_printf("Failed allocating \"vendors_by_num\" table");
4224 goto error;
4225 }
4226
4227 /*
4228 * Inter-dictionary reference caching
4229 */
4231 if (!dict->autoref) {
4232 fr_strerror_printf("Failed allocating \"autoref\" table");
4233 goto error;
4234 }
4235
4236 /*
4237 * Who/what depends on this dictionary
4238 */
4239 dict->dependents = fr_rb_inline_alloc(dict, fr_dict_dependent_t, node, _dict_dependent_cmp, NULL);
4240
4241 /*
4242 * Set the default dictionary protocol, this can
4243 * be overriden by the protocol library.
4244 */
4245 dict->proto = &dict_proto_default;
4246
4247 return dict;
4248}
4249
4250/** Allocate a new local dictionary
4251 *
4252 * @param[in] parent parent dictionary and talloc ctx
4253 * @return
4254 * - NULL on memory allocation error.
4255 *
4256 * This dictionary cannot define vendors, or inter-dictionary
4257 * dependencies. However, we initialize the relevant fields just in
4258 * case. We should arguably just skip initializing those fields, and
4259 * just allow the server to crash if programmers do something stupid with it.
4260 */
4262{
4263 fr_dict_t *dict;
4264 fr_dict_attr_t *da;
4265
4266 fr_dict_attr_flags_t flags = {
4267 .is_root = true,
4268 .local = true,
4269 .internal = true,
4270 .type_size = parent->root->flags.type_size,
4271 .length = parent->root->flags.length,
4272 };
4273
4274 dict = dict_alloc(UNCONST(fr_dict_t *, parent));
4275 if (!dict) return NULL;
4276
4277 /*
4278 * Allocate the root attribute. This dictionary is
4279 * always protocol "local", and number "0".
4280 */
4281 da = dict_attr_alloc_root(dict->pool, parent, "local", 0,
4282 &(dict_attr_args_t){ .flags = &flags });
4283 if (unlikely(!da)) {
4284 talloc_free(dict);
4285 return NULL;
4286 }
4287
4288 da->last_child_attr = fr_dict_root(parent)->last_child_attr;
4289
4290 dict->root = da;
4291 dict->root->dict = dict;
4292 dict->next = parent;
4293
4294 DA_VERIFY(dict->root);
4295
4296 return dict;
4297}
4298
4299/** Decrement the reference count on a previously loaded dictionary
4300 *
4301 * @param[in] dict to free.
4302 * @param[in] dependent that originally allocated this dictionary.
4303 * @return
4304 * - 0 on success (dictionary freed).
4305 * - 1 if other things still depend on the dictionary.
4306 * - -1 on error (dependent doesn't exist)
4307 */
4308int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
4309{
4310 fr_dict_t **our_dict = UNCONST(fr_dict_t **, dict);
4311
4312 return fr_dict_free(our_dict, dependent);
4313}
4314
4315/** Decrement the reference count on a previously loaded dictionary
4316 *
4317 * @param[in] dict to free.
4318 * @param[in] dependent that originally allocated this dictionary.
4319 * @return
4320 * - 0 on success (dictionary freed).
4321 * - 1 if other things still depend on the dictionary.
4322 * - -1 on error (dependent doesn't exist)
4323 */
4324int fr_dict_free(fr_dict_t **dict, char const *dependent)
4325{
4326 if (!*dict) return 0;
4327
4328 switch (dict_dependent_remove(*dict, dependent)) {
4329 case 0: /* dependent has no more refs */
4330 if (!dict_has_dependents(*dict)) {
4331 talloc_free(*dict);
4332 return 0;
4333 }
4335
4336 case 1: /* dependent has more refs */
4337 return 1;
4338
4339 default: /* error */
4340 return -1;
4341 }
4342}
4343
4344/** Process a dict_attr_autoload element to load/verify a dictionary attribute
4345 *
4346 * @param[in] to_load attribute definition
4347 * @return
4348 * - 0 on success.
4349 * - -1 on failure.
4350 */
4352{
4353 fr_dict_enum_autoload_t const *p = to_load;
4354 fr_dict_enum_value_t const *enumv;
4355
4356 for (p = to_load; p->out; p++) {
4357 if (unlikely(!p->attr)) {
4358 fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing attribute pointer", p->name);
4359 return -1;
4360 }
4361
4362 if (unlikely(!*p->attr)) {
4363 fr_strerror_printf("Can't resolve value \"%s\", attribute not loaded", p->name);
4364 fr_strerror_printf_push("Check fr_dict_attr_autoload_t struct has "
4365 "an entry to load the attribute \"%s\" is located in, and that "
4366 "the fr_dict_autoload_attr_t symbol name is correct", p->name);
4367 return -1;
4368 }
4369
4370 enumv = fr_dict_enum_by_name(*(p->attr), p->name, -1);
4371 if (!enumv) {
4372 fr_strerror_printf("Value '%s' not found in \"%s\" attribute",
4373 p->name, (*(p->attr))->name);
4374 return -1;
4375 }
4376
4377 if (p->out) *(p->out) = enumv->value;
4378 }
4379
4380 return 0;
4381}
4382
4383/** Process a dict_attr_autoload element to load/verify a dictionary attribute
4384 *
4385 * @param[in] to_load attribute definition
4386 * @return
4387 * - 0 on success.
4388 * - -1 on failure.
4389 */
4391{
4392 fr_dict_attr_t const *da;
4393 fr_dict_attr_autoload_t const *p = to_load;
4394 fr_dict_attr_t const *root = NULL;
4395
4396 for (p = to_load; p->out; p++) {
4397 if (!p->dict) {
4398 fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing dictionary pointer", p->name);
4399 return -1;
4400 }
4401
4402 if (!*p->dict) {
4403 fr_strerror_printf("Autoloader autoloader can't resolve attribute \"%s\", dictionary not loaded", p->name);
4404 fr_strerror_printf_push("Check fr_dict_autoload_t struct has "
4405 "an entry to load the dictionary \"%s\" is located in, and that "
4406 "the fr_dict_autoload_t symbol name is correct", p->name);
4407 return -1;
4408 }
4409
4410 if (!root || (root->dict != *p->dict) || (p->name[0] != '.')) {
4411 root = (*p->dict)->root;
4412 }
4413
4414 if (p->name[0] == '.') {
4415 da = fr_dict_attr_by_oid(NULL, root, p->name + 1);
4416 if (!da) {
4417 fr_strerror_printf("Autoloader attribute \"%s\" not found in \"%s\" dictionary under attribute %s", p->name,
4418 *p->dict ? (*p->dict)->root->name : "internal", root->name);
4419 return -1;
4420 }
4421 } else {
4422 da = fr_dict_attr_by_oid(NULL, fr_dict_root(*p->dict), p->name);
4423 if (!da) {
4424 fr_strerror_printf("Autoloader attribute \"%s\" not found in \"%s\" dictionary", p->name,
4425 *p->dict ? (*p->dict)->root->name : "internal");
4426 return -1;
4427 }
4428
4429 if (fr_type_is_structural(da->type)) root = da;
4430 }
4431
4432 if (da->type != p->type) {
4433 fr_strerror_printf("Autoloader attribute \"%s\" should be type %s, but defined as type %s", da->name,
4434 fr_type_to_str(p->type),
4435 fr_type_to_str(da->type));
4436 return -1;
4437 }
4438
4439 DA_VERIFY(da);
4440
4441 if (p->out) *(p->out) = da;
4442 }
4443
4444 return 0;
4445}
4446
4447/** Process a dict_autoload element to load a protocol
4448 *
4449 * @param[in] to_load dictionary definition.
4450 * @param[in] dependent that is loading this dictionary.
4451 * @return
4452 * - 0 on success.
4453 * - -1 on failure.
4454 */
4455int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
4456{
4457 fr_dict_autoload_t const *p;
4458
4459 for (p = to_load; p->out; p++) {
4460 fr_dict_t *dict = NULL;
4461
4462 if (unlikely(!p->proto)) {
4463 fr_strerror_const("autoload missing parameter proto");
4464 return -1;
4465 }
4466
4467 /*
4468 * Load the internal dictionary
4469 */
4470 if (strcmp(p->proto, "freeradius") == 0) {
4471 if (fr_dict_internal_afrom_file(&dict, p->proto, dependent) < 0) return -1;
4472 } else {
4473 if (fr_dict_protocol_afrom_file(&dict, p->proto, p->base_dir, dependent) < 0) return -1;
4474 }
4475
4476 *(p->out) = dict;
4477 }
4478
4479 return 0;
4480}
4481
4482
4483/** Decrement the reference count on a previously loaded dictionary
4484 *
4485 * @param[in] to_free previously loaded dictionary to free.
4486 * @param[in] dependent that originally allocated this dictionary
4487 */
4488int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
4489{
4490 fr_dict_autoload_t const *p;
4491
4492 for (p = to_free; p->out; p++) {
4493 int ret;
4494
4495 if (!*p->out) continue;
4496 ret = fr_dict_const_free(p->out, dependent);
4497
4498 if (ret == 0) *p->out = NULL;
4499 if (ret < 0) return -1;
4500 }
4501
4502 return 0;
4503}
4504
4505/** Structure used to managed the lifetime of a dictionary
4506 *
4507 * This should only be used when dictionaries are being dynamically loaded during
4508 * compilation. It should not be used to load dictionaries at runtime, or if
4509 * modules need to load dictionaries (use static fr_dict_autoload_t defs).
4510
4511 */
4513 fr_dict_autoload_t load[2]; //!< Autoloader def.
4514 char const *dependent; //!< Dependent that loaded the dictionary.
4515};
4516
4517/** Talloc destructor to automatically free dictionaries
4518 *
4519 * @param[in] to_free dictionary autoloader definition describing the dictionary to free.
4520 */
4522{
4523 return _fr_dict_autofree(to_free->load, to_free->dependent);
4524}
4525
4526/** Autoload a dictionary and bind the lifetime to a talloc chunk
4527 *
4528 * Mainly useful for resolving "forward" references from unlang immediately.
4529 *
4530 * @note If the talloc chunk is freed it does not mean the dictionary will
4531 * be immediately freed. It will be freed when all other references
4532 * to the dictionary are gone.
4533 *
4534 * @param[in] ctx to bind the dictionary lifetime to.
4535 * @param[out] out pointer to the loaded dictionary.
4536 * @param[in] proto to load.
4537 * @param[in] dependent to register this reference to. Will be dupd.
4538 */
4539fr_dict_autoload_talloc_t *_fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent)
4540{
4541 fr_dict_autoload_talloc_t *dict_ref;
4542 int ret;
4543
4544 dict_ref = talloc(ctx, fr_dict_autoload_talloc_t);
4545 if (unlikely(dict_ref == NULL)) {
4546 oom:
4547 fr_strerror_const("Out of memory");
4548 return NULL;
4549 }
4550
4551 dict_ref->load[0] = (fr_dict_autoload_t){ .proto = proto, .out = out};
4553 dict_ref->dependent = talloc_strdup(dict_ref, dependent);
4554 if (unlikely(dict_ref->dependent == NULL)) {
4555 talloc_free(dict_ref);
4556 goto oom;
4557 }
4558
4559 ret = _fr_dict_autoload(dict_ref->load, dependent);
4560 if (ret < 0) {
4561 talloc_free(dict_ref);
4562 return NULL;
4563 }
4564
4565 return dict_ref;
4566}
4567
4568/** Callback to automatically resolve enum values
4569 *
4570 * @param[in] module being loaded.
4571 * @param[in] symbol An array of fr_dict_enum_autoload_t to load.
4572 * @param[in] user_ctx unused.
4573 * @return
4574 * - 0 on success.
4575 * - -1 on failure.
4576 */
4577int fr_dl_dict_enum_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4578{
4579 if (fr_dict_enum_autoload((fr_dict_enum_autoload_t *)symbol) < 0) return -1;
4580
4581 return 0;
4582}
4583
4584/** Callback to automatically resolve attributes and check the types are correct
4585 *
4586 * @param[in] module being loaded.
4587 * @param[in] symbol An array of fr_dict_attr_autoload_t to load.
4588 * @param[in] user_ctx unused.
4589 * @return
4590 * - 0 on success.
4591 * - -1 on failure.
4592 */
4593int fr_dl_dict_attr_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4594{
4595 if (fr_dict_attr_autoload((fr_dict_attr_autoload_t *)symbol) < 0) return -1;
4596
4597 return 0;
4598}
4599
4600/** Callback to automatically load dictionaries required by modules
4601 *
4602 * @param[in] module being loaded.
4603 * @param[in] symbol An array of fr_dict_autoload_t to load.
4604 * @param[in] user_ctx unused.
4605 * @return
4606 * - 0 on success.
4607 * - -1 on failure.
4608 */
4609int fr_dl_dict_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4610{
4611 if (fr_dict_autoload((fr_dict_autoload_t const *)symbol) < 0) return -1;
4612
4613 return 0;
4614}
4615
4616/** Callback to automatically free a dictionary when the module is unloaded
4617 *
4618 * @param[in] module being loaded.
4619 * @param[in] symbol An array of fr_dict_autoload_t to load.
4620 * @param[in] user_ctx unused.
4621 */
4622void fr_dl_dict_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4623{
4625}
4626
4627static int _dict_global_free_at_exit(void *uctx)
4628{
4629 return talloc_free(uctx);
4630}
4631
4633{
4634 fr_hash_iter_t iter;
4635 fr_dict_t *dict;
4636 bool still_loaded = false;
4637
4638 /*
4639 * Make sure this doesn't fire later and mess
4640 * things up...
4641 */
4643
4644 /*
4645 * Free up autorefs first, which will free up inter-dictionary dependencies.
4646 */
4647 for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
4648 dict;
4649 dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
4650 (void)talloc_get_type_abort(dict, fr_dict_t);
4651
4652 if (dict_autoref_free(dict) < 0) return -1;
4653 }
4654
4655 for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
4656 dict;
4657 dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
4658 (void)talloc_get_type_abort(dict, fr_dict_t);
4659 dict_dependent_remove(dict, "global"); /* remove our dependency */
4660
4661 if (talloc_free(dict) < 0) {
4662#ifndef NDEBUG
4663 FR_FAULT_LOG("gctx failed to free dictionary %s - %s", dict->root->name, fr_strerror());
4664#endif
4665 still_loaded = true;
4666 }
4667 }
4668
4669 /*
4670 * Free the internal dictionary as the last step, after all of the protocol dictionaries and
4671 * libraries have freed their references to it.
4672 */
4673 if (gctx->internal) {
4674 dict_dependent_remove(gctx->internal, "global"); /* remove our dependency */
4675
4676 if (talloc_free(gctx->internal) < 0) still_loaded = true;
4677 }
4678
4679 if (still_loaded) {
4680#ifndef NDEBUG
4681 fr_dict_gctx_debug(stderr, gctx);
4682#endif
4683 return -1;
4684 }
4685
4686 /*
4687 * Set this to NULL just in case the caller tries to use
4688 * dict_global_init() again.
4689 */
4690 if (gctx == dict_gctx) dict_gctx = NULL; /* In case the active context isn't this one */
4691
4692 return 0;
4693}
4694
4695/** Initialise the global protocol hashes
4696 *
4697 * @note Must be called before any other dictionary functions.
4698 *
4699 * @param[in] ctx to allocate global resources in.
4700 * @param[in] free_at_exit Install an at_exit handler to free the global ctx.
4701 * This is useful when dictionaries are held by other
4702 * libraries which free them using atexit handlers.
4703 * @param[in] dict_dir the default location for the dictionaries.
4704 * @return
4705 * - A pointer to the new global context on success.
4706 * - NULL on failure.
4707 */
4708fr_dict_gctx_t *fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
4709{
4710 fr_dict_gctx_t *new_ctx;
4711
4712 new_ctx = talloc_zero(ctx, fr_dict_gctx_t);
4713 if (!new_ctx) {
4714 fr_strerror_const("Out of Memory");
4715 return NULL;
4716 }
4717 new_ctx->perm_check = true; /* Check file permissions by default */
4718
4720 if (!new_ctx->protocol_by_name) {
4721 fr_strerror_const("Failed initializing protocol_by_name hash");
4722 error:
4723 talloc_free(new_ctx);
4724 return NULL;
4725 }
4726
4728 if (!new_ctx->protocol_by_num) {
4729 fr_strerror_const("Failed initializing protocol_by_num hash");
4730 goto error;
4731 }
4732
4733 new_ctx->dict_dir_default = talloc_strdup(new_ctx, dict_dir);
4734 if (!new_ctx->dict_dir_default) goto error;
4735
4736 new_ctx->dict_loader = dl_loader_init(new_ctx, NULL, false, false);
4737 if (!new_ctx->dict_loader) goto error;
4738
4739 new_ctx->free_at_exit = free_at_exit;
4740
4741 talloc_set_destructor(new_ctx, _dict_global_free);
4742
4743 if (!dict_gctx) dict_gctx = new_ctx; /* Set as the default */
4744
4745 if (free_at_exit) fr_atexit_global(_dict_global_free_at_exit, new_ctx);
4746
4747 return new_ctx;
4748}
4749
4750/** Set whether we check dictionary file permissions
4751 *
4752 * @param[in] gctx to alter.
4753 * @param[in] enable Whether we should check file permissions as they're loaded.
4754 */
4756{
4757 gctx->perm_check = enable;
4758}
4759
4760/** Set a new, active, global dictionary context
4761 *
4762 * @param[in] gctx To set.
4763 */
4765{
4766 memcpy(&dict_gctx, &gctx, sizeof(dict_gctx));
4767}
4768
4769/** Explicitly free all data associated with a global dictionary context
4770 *
4771 * @note You should *NOT* ignore the return code of this function.
4772 * You should use perror() or PERROR() to print out the reason
4773 * why freeing failed.
4774 *
4775 * @param[in] gctx To set.
4776 * @return
4777 * - 0 on success.
4778 * - -1 on failure.
4779 */
4781{
4782 if (dict_gctx == gctx) dict_gctx = NULL;
4783
4784 return talloc_const_free(gctx);
4785}
4786
4787/** Allow the default dict dir to be changed after initialisation
4788 *
4789 * @param[in] dict_dir New default dict dir to use.
4790 * @return
4791 * - 0 on success.
4792 * - -1 on failure.
4793 */
4794int fr_dict_global_ctx_dir_set(char const *dict_dir)
4795{
4796 if (!dict_gctx) return -1;
4797
4798 talloc_free(dict_gctx->dict_dir_default); /* Free previous value */
4800 if (!dict_gctx->dict_dir_default) return -1;
4801
4802 return 0;
4803}
4804
4805char const *fr_dict_global_ctx_dir(void)
4806{
4808}
4809
4810/** Mark all dictionaries and the global dictionary ctx as read only
4811 *
4812 * Any attempts to add new attributes will now fail.
4813 */
4815{
4816 fr_hash_iter_t iter;
4817 fr_dict_t *dict;
4818
4819 if (!dict_gctx) return;
4820
4821 /*
4822 * Set everything to read only
4823 */
4825 dict;
4828 dict->read_only = true;
4829 }
4830
4831 dict = dict_gctx->internal;
4833 dict->read_only = true;
4834 dict_gctx->read_only = true;
4835}
4836
4837/** Dump information about currently loaded dictionaries
4838 *
4839 * Intended to be called from a debugger
4840 */
4841void fr_dict_gctx_debug(FILE *fp, fr_dict_gctx_t const *gctx)
4842{
4843 fr_hash_iter_t dict_iter;
4844 fr_dict_t *dict;
4845 fr_rb_iter_inorder_t dep_iter;
4847
4848 if (gctx == NULL) gctx = dict_gctx;
4849
4850 if (!gctx) {
4851 fprintf(fp, "gctx not initialised\n");
4852 return;
4853 }
4854
4855 fprintf(fp, "gctx %p report\n", dict_gctx);
4856 for (dict = fr_hash_table_iter_init(gctx->protocol_by_num, &dict_iter);
4857 dict;
4858 dict = fr_hash_table_iter_next(gctx->protocol_by_num, &dict_iter)) {
4859 for (dep = fr_rb_iter_init_inorder(dict->dependents, &dep_iter);
4860 dep;
4861 dep = fr_rb_iter_next_inorder(dict->dependents, &dep_iter)) {
4862 fprintf(fp, "\t%s is referenced from %s count (%d)\n",
4863 dict->root->name, dep->dependent, dep->count);
4864 }
4865 }
4866
4867 if (gctx->internal) {
4868 for (dep = fr_rb_iter_init_inorder(gctx->internal->dependents, &dep_iter);
4869 dep;
4870 dep = fr_rb_iter_next_inorder(gctx->internal->dependents, &dep_iter)) {
4871 fprintf(fp, "\t%s is referenced from %s count (%d)\n",
4872 gctx->internal->root->name, dep->dependent, dep->count);
4873 }
4874 }
4875}
4876
4877/** Iterate protocols by name
4878 *
4879 */
4886
4893
4894
4895/** Coerce to non-const
4896 *
4897 */
4899{
4900 if (unlikely(dict->read_only)) {
4901 fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4902 return NULL;
4903 }
4904 return UNCONST(fr_dict_t *, dict);
4905}
4906
4907/** Coerce to non-const
4908 *
4909 */
4911{
4912 fr_dict_t *dict;
4913
4914 dict = dict_by_da(da);
4915 if (unlikely(dict->read_only)) {
4916 fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4917 return NULL;
4918 }
4919
4920 return UNCONST(fr_dict_attr_t *, da);
4921}
4922
4924{
4925 if (!dict_gctx) return NULL;
4926
4927 return dict_gctx->internal;
4928}
4929
4930/*
4931 * Check for the allowed characters.
4932 */
4934{
4935 char const *p = name, *end;
4936 bool unknown = false;
4937 bool alnum = false;
4938
4939 if (len < 0) len = strlen(name);
4940
4941 if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
4942 fr_strerror_const("Attribute name is too long");
4943 return -1;
4944 }
4945
4946 end = p + len;
4947
4948 /*
4949 * Unknown attributes can have '.' in their name.
4950 */
4951 if ((len > 5) && (memcmp(name, "Attr-", 5) == 0)) unknown = true;
4952
4953 while (p < end) {
4954 if ((*p == '.') && unknown) p++;
4955
4957 fr_strerror_printf("Invalid character '%pV' in attribute name \"%pV\"",
4959
4960 return -(p - name);
4961 }
4962
4963 alnum |= sbuff_char_alpha_num[(uint8_t)*p];
4964
4965 p++;
4966 }
4967
4968 if (!alnum) {
4969 fr_strerror_const("Invalid attribute name");
4970 return -1;
4971 }
4972
4973 return len;
4974}
4975
4977{
4978 char const *p = name, *end;
4979 bool alnum = false;
4980
4981 if (len < 0) len = strlen(name);
4982 end = p + len;
4983
4984 do {
4985 if (!fr_dict_attr_allowed_chars[(uint8_t)*p] && (*p != '.')) {
4986 fr_strerror_printf("Invalid character '%pV' in oid string \"%pV\"",
4988
4989 return -(p - name);
4990 }
4991
4992 alnum |= sbuff_char_alpha_num[(uint8_t)*p];
4993 p++;
4994 } while (p < end);
4995
4996 if (!alnum) return 0;
4997
4998 return len;
4999}
5000
5001/** Iterate over children of a DA.
5002 *
5003 * @param[in] parent the parent da to iterate over
5004 * @param[in,out] prev pointer to NULL to start, otherwise pointer to the previously returned child
5005 * @return
5006 * - NULL for end of iteration
5007 * - !NULL for a valid child. This child MUST be passed to the next loop.
5008 */
5010{
5011 fr_dict_attr_t const * const *bin;
5012 fr_dict_attr_t const **children;
5013 fr_dict_attr_t const *ref;
5014 size_t len, i, start;
5015
5016 ref = fr_dict_attr_ref(parent);
5017 if (ref) parent = ref;
5018
5019 children = dict_attr_children(parent);
5020 if (!children) return NULL;
5021
5022 if (!*prev) {
5023 start = 0;
5024
5025 } else if ((*prev)->next) {
5026 /*
5027 * There are more children in this bin, return
5028 * the next one.
5029 */
5030 return (*prev)->next;
5031
5032 } else {
5033 /*
5034 * Figure out which bin we were in. If it was
5035 * the last one, we're done.
5036 */
5037 start = (*prev)->attr & 0xff;
5038 if (start == 255) return NULL;
5039
5040 /*
5041 * Start at the next bin.
5042 */
5043 start++;
5044 }
5045
5046 /*
5047 * Look for a non-empty bin, and return the first child
5048 * from there.
5049 */
5050 len = talloc_array_length(children);
5051 for (i = start; i < len; i++) {
5052 bin = &children[i & 0xff];
5053
5054 if (*bin) return *bin;
5055 }
5056
5057 return NULL;
5058}
5059
5060/** Call the specified callback for da and then for all its children
5061 *
5062 */
5063static int dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
5064{
5065 size_t i, len;
5066 fr_dict_attr_t const **children;
5067
5068 children = dict_attr_children(da);
5069
5070 if (fr_dict_attr_ref(da) || !children) return callback(da, uctx);
5071
5072 len = talloc_array_length(children);
5073 for (i = 0; i < len; i++) {
5074 int ret;
5075 fr_dict_attr_t const *bin;
5076
5077 if (!children[i]) continue;
5078
5079 for (bin = children[i]; bin; bin = bin->next) {
5080 ret = dict_walk(bin, callback, uctx);
5081 if (ret < 0) return ret;
5082 }
5083 }
5084
5085 return 0;
5086}
5087
5088int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
5089{
5090 return dict_walk(da, callback, uctx);
5091}
5092
5093
5094void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
5095{
5096 int i;
5097 fr_dict_attr_t const *da_p;
5098
5100
5101 if ((!da->flags.is_root) && (da->depth == 0)) {
5102 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5103 "Is not root, but depth is 0",
5104 file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr);
5105 }
5106
5107 if (da->depth > FR_DICT_MAX_TLV_STACK) {
5108 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5109 "Indicated depth (%u) greater than TLV stack depth (%d)",
5110 file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr,
5111 da->depth, FR_DICT_MAX_TLV_STACK);
5112 }
5113
5114 for (da_p = da; da_p; da_p = da_p->next) {
5116 }
5117
5118 for (i = da->depth, da_p = da; i >= 0; i--, da_p = da_p->parent) {
5119 if (!da_p) {
5120 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5121 "Depth indicated there should be a parent, but parent is NULL",
5122 file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr);
5123 }
5124 if (i != (int)da_p->depth) {
5125 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5126 "Depth out of sequence, expected %i, got %u",
5127 file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr, i, da_p->depth);
5128 }
5129
5130 }
5131
5132 if ((i + 1) < 0) {
5133 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t top of hierarchy was not at depth 0",
5134 file, line);
5135 }
5136
5137 if (da->parent && (da->parent->type == FR_TYPE_VENDOR) && !fr_dict_attr_has_ext(da, FR_DICT_ATTR_EXT_VENDOR)) {
5138 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: VSA missing 'vendor' extension", file, line);
5139 }
5140
5141 switch (da->type) {
5142 case FR_TYPE_STRUCTURAL:
5143 {
5144 fr_hash_table_t *ht;
5145
5146 if (da->type == FR_TYPE_GROUP) break;
5147
5149 "CONSISTENCY CHECK FAILED %s[%d]: %s missing 'children' extension",
5150 file, line,
5151 fr_type_to_str(da->type));
5152
5154 "CONSISTENCY CHECK FAILED %s[%d]: %s missing 'namespace' extension",
5155 file, line,
5156 fr_type_to_str(da->type));
5157
5158 /*
5159 * Check the namespace hash table is ok
5160 */
5161 ht = dict_attr_namespace(da);
5162 if (unlikely(!ht)) break;
5164 }
5165 break;
5166
5167 default:
5168 break;
5169 }
5170}
5171
5172/** See if a structural da is allowed to contain another da
5173 *
5174 * We have some complex rules with different structural types,
5175 * different protocol dictionaries, references to other protocols,
5176 * etc.
5177 *
5178 * @param[in] parent The parent da, must be structural
5179 * @param[in] child The alleged child
5180 * @return
5181 * - false - the child is not allowed to be contained by the parent
5182 * - true - the child is allowed to be contained by the parent
5183 */
5185{
5186 /*
5187 * This is the common case: child is from the parent.
5188 */
5189 if (child->parent == parent) return true;
5190
5191 if (child->flags.is_raw) return true; /* let people do stupid things */
5192
5193 /*
5194 * Only structural types can have children.
5195 */
5196 if (!fr_type_structural[parent->type]) return false;
5197
5198 /*
5199 * An internal attribute can go into any other container.
5200 *
5201 * Any other attribute can go into an internal structural
5202 * attribute, because why not?
5203 */
5204 if (dict_gctx) {
5205 if (child->dict == dict_gctx->internal) return true;
5206
5207 if (parent->dict == dict_gctx->internal) return true;
5208 }
5209
5210 /*
5211 * Anything can go into internal groups.
5212 */
5213 if ((parent->type == FR_TYPE_GROUP) && parent->flags.internal) return true;
5214
5215 /*
5216 * Protocol attributes have to be in the same dictionary.
5217 *
5218 * Unless they're a cross-protocol grouping attribute.
5219 * In which case we check if the ref is the same.
5220 */
5221 if (child->dict != parent->dict) {
5222 fr_dict_attr_t const *ref;
5223
5224 ref = fr_dict_attr_ref(parent);
5225
5226 return (ref && (ref->dict == child->dict));
5227 }
5228
5229 /*
5230 * Key fields can have children, but everyone else thinks
5231 * that the struct is the parent. <sigh>
5232 */
5233 if ((parent->type == FR_TYPE_STRUCT) && child->parent->parent == parent) return true;
5234
5235 /*
5236 * We're in the same protocol dictionary, but the child
5237 * isn't directly from the parent. Therefore the only
5238 * type of same-protocol structure it can go into is a
5239 * group.
5240 */
5241 return (parent->type == FR_TYPE_GROUP);
5242}
5243
5244/** Return the protocol descriptor for the dictionary.
5245 *
5246 */
5248{
5249 return dict->proto;
5250}
5251
5252/*
5253 * Get the real protocol namespace behind a local one.
5254 */
5256{
5257 if (!da->flags.local) return da;
5258
5259 fr_assert(da->dict->root == da);
5260
5261 while (da->dict->next) {
5262 da = da->dict->next->root;
5263 }
5264
5265 return da;
5266}
5267
5268/*
5269 * Get the real protocol dictionary behind a local one.
5270 */
5272{
5273 while (dict->next) dict = dict->next;
5274
5275 return dict;
5276}
5277
5279{
5280 if ((*da_p)->type == FR_TYPE_GROUP) {
5282 return 0;
5283 }
5284
5285 (*da_p)->type = FR_TYPE_GROUP;
5286 (*da_p)->flags.type_size = 0;
5287 (*da_p)->flags.length = 0;
5288
5290
5291 return dict_attr_ref_aset(da_p, ref, FR_DICT_ATTR_REF_ALIAS);
5292}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
int n
Definition acutest.h:577
va_list args
Definition acutest.h:770
int const char int line
Definition acutest.h:702
unsigned int fr_atexit_global_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
Remove a specific global destructor (without executing it)
Definition atexit.c:248
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition atexit.h:58
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:512
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:183
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define FR_FAULT_LOG(_fmt,...)
Definition debug.h:50
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
size_t type
Length of type data.
Definition dict.h:272
size_t name_len
Allows for efficient name lookups when operating on partial buffers.
Definition dict.h:255
struct fr_dict_protocol_t::@124 attr
char const * name
of the attribute.
Definition dict.h:297
@ FR_DICT_ENUM_EXT_ATTR_REF
Reference to a child attribute associated with this key value.
Definition dict.h:238
char const * name
Vendor name.
Definition dict.h:274
fr_dict_attr_t const ** attr
The protocol dictionary the attribute should be resolved in.
Definition dict.h:282
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
Definition dict_util.c:2866
unsigned int is_root
Is root of a dictionary.
Definition dict.h:75
#define fr_dict_autofree(_to_free)
Definition dict.h:915
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition dict_util.c:2308
static fr_slen_t err
Definition dict.h:882
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3523
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
fr_value_box_t const ** out
Enumeration value.
Definition dict.h:281
fr_dict_t const ** dict
The protocol dictionary the attribute should be resolved in.
Definition dict.h:294
int(* fr_dict_walk_t)(fr_dict_attr_t const *da, void *uctx)
Definition dict.h:993
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DA_VERIFY(_x)
Definition dict.h:66
char const * name
of the attribute.
Definition dict.h:285
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:257
uint32_t pen
Private enterprise number.
Definition dict.h:270
fr_type_t type
of the attribute. Mismatch is a fatal error.
Definition dict.h:298
int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir, char const *dependent))
(Re)-initialize a protocol dictionary
size_t length
Length of length data.
Definition dict.h:273
char const * base_dir
Directory structure beneath share.
Definition dict.h:307
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:190
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:188
@ FR_DICT_ATTR_EXT_NAMESPACE
Attribute has its own namespace.
Definition dict.h:189
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:184
@ FR_DICT_ATTR_EXT_VENDOR
Cached vendor pointer.
Definition dict.h:187
@ FR_DICT_ATTR_EXT_NAME
Name of the attribute.
Definition dict.h:182
@ FR_DICT_ATTR_EXT_CHILDREN
Attribute has children.
Definition dict.h:183
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:517
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
Definition dict.h:317
@ FR_DICT_ATTR_OK
No error.
Definition dict.h:318
@ FR_DICT_ATTR_NOTFOUND
Attribute couldn't be found.
Definition dict.h:319
@ FR_DICT_ATTR_EINVAL
Invalid arguments.
Definition dict.h:329
@ FR_DICT_ATTR_NO_CHILDREN
Child lookup in attribute with no children.
Definition dict.h:328
@ FR_DICT_ATTR_PARSE_ERROR
Attribute string couldn't be parsed.
Definition dict.h:321
@ FR_DICT_ATTR_INTERNAL_ERROR
Internal error occurred.
Definition dict.h:322
#define FR_DICT_ENUM_MAX_NAME_LEN
Maximum length of a enum value.
Definition dict.h:499
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
char const * proto
The protocol dictionary name.
Definition dict.h:308
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:170
char const * name
Enum name.
Definition dict.h:254
static fr_slen_t in
Definition dict.h:882
char const * name
name of this protocol
Definition dict.h:456
#define FR_DICT_VENDOR_MAX_NAME_LEN
Maximum length of a vendor name.
Definition dict.h:500
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:501
unsigned int is_alias
This isn't a real attribute, it's a reference to to one.
Definition dict.h:85
fr_dict_attr_t const * da
the child structure referenced by this value of key
Definition dict.h:246
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Specifies a value which must be present for the module to function.
Definition dict.h:280
Enum extension - Sub-struct or union pointer.
Definition dict.h:245
Value of an enumerated attribute.
Definition dict.h:253
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:455
Private enterprise.
Definition dict.h:269
size_t max_name_len
maximum length of a name
Definition dict_ext.h:96
fr_dict_attr_t const * vendor
ancestor which has type FR_TYPE_VENDOR
Definition dict_ext.h:89
fr_dict_attr_ref_type_t type
The state of the reference.
Definition dict_ext.h:78
fr_hash_table_t * name_by_value
Lookup a name by value.
Definition dict_ext.h:98
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:121
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition dict_ext.h:97
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:148
static bool fr_dict_attr_has_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Return whether a da has a given extension or not.
Definition dict_ext.h:136
@ FR_DICT_ATTR_REF_ALIAS
The attribute is an alias for another attribute.
Definition dict_ext.h:59
@ FR_DICT_ATTR_REF_NONE
No ref set.
Definition dict_ext.h:58
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Definition dict_ext.h:176
Attribute extension - Holds children for an attribute.
Definition dict_ext.h:52
Attribute extension - Holds enumeration values.
Definition dict_ext.h:95
Attribute extension - Holds a hash table with the names of all children of this attribute.
Definition dict_ext.h:104
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:77
Attribute extension - Cached vendor pointer.
Definition dict_ext.h:88
static int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref, fr_dict_attr_ref_type_t type)
static int dict_attr_children_set(fr_dict_attr_t const *da, fr_dict_attr_t const **children)
static fr_hash_table_t * dict_attr_namespace(fr_dict_attr_t const *da)
Return the namespace hash table associated with the attribute.
static int dict_attr_ref_null(fr_dict_attr_t const *da)
static int dict_attr_ext_copy_all(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in)
Copy all attribute extensions from one attribute to another.
static void * dict_attr_ext_copy(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in, fr_dict_attr_ext_t ext)
Copy a single attribute extension from one attribute to another.
static fr_dict_attr_t const ** dict_attr_children(fr_dict_attr_t const *da)
static void * dict_attr_ext_alloc_size(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext, size_t ext_len)
Allocate an attribute extension of a particular size.
static void * dict_enum_ext_alloc(fr_dict_enum_value_t **enumv_p, fr_dict_enum_ext_t ext)
Allocate an enum extension.
static int dict_attr_ref_aset(fr_dict_attr_t **da_p, fr_dict_attr_t const *ref, fr_dict_attr_ref_type_t type)
static void * dict_attr_ext_alloc(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext)
Allocate an attribute extension.
void dict_hash_tables_finalise(fr_dict_t *dict)
Walk a dictionary finalising the hash tables in all attributes with a distinct namespace.
Definition dict_fixup.c:877
char * dict_dir_default
The default location for loading dictionaries if one wasn't provided.
Definition dict_priv.h:137
fr_hash_table_t * protocol_by_name
Hash containing names of all the registered protocols.
Definition dict_priv.h:142
#define dict_attr_alloc(_ctx, _parent, _name, _attr, _type, _args)
Definition dict_priv.h:256
#define INTERNAL_IF_NULL(_dict, _ret)
Set the internal dictionary if none was provided.
Definition dict_priv.h:45
fr_hash_table_t * protocol_by_num
Hash containing numbers of all the registered protocols.
Definition dict_priv.h:144
fr_dict_attr_t * root
Root attribute of this dictionary.
Definition dict_priv.h:109
#define DICT_POOL_SIZE
Definition dict_priv.h:37
dl_loader_t * dict_loader
for protocol validation
Definition dict_priv.h:140
#define dict_attr_init(_da_p, _parent, _name, _attr, _type, _args)
Full initialisation functions.
Definition dict_priv.h:232
char const * dependent
File holding the reference.
Definition dict_priv.h:62
bool dict_attr_valid(fr_dict_attr_t *da)
Validate a new attribute definition.
#define dict_attr_init_name_only(_da_p, _parent, _name, _type, _args)
Definition dict_priv.h:240
fr_dict_attr_t const * attr_protocol_encapsulation
Definition dict_priv.h:157
@ FR_DICT_PROTO_RADIUS
Definition dict_priv.h:161
int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref, bool from_public)
Add an alias to an existing attribute.
Definition dict_util.c:1399
fr_dict_t * internal
Magic internal dictionary.
Definition dict_priv.h:155
bool free_at_exit
This gctx will be freed on exit.
Definition dict_priv.h:130
#define dict_attr_alloc_root(_ctx, _dict, _name, _attr, _args)
Definition dict_priv.h:248
bool perm_check
Whether we should check dictionary file permissions as they're loaded.
Definition dict_priv.h:132
int count
How many references are held by this file.
Definition dict_priv.h:60
Optional arguments for initialising/allocating attributes.
Definition dict_priv.h:192
Entry recording dictionary reference holders by file.
Definition dict_priv.h:58
Entry in the filename list of files associated with this dictionary.
Definition dict_priv.h:69
Test enumeration values.
Definition dict_test.h:92
static fr_dict_protocol_t dict_proto_default
Default protocol rules set for every dictionary.
Definition dict_util.c:102
int fr_dl_dict_attr_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically resolve attributes and check the types are correct.
Definition dict_util.c:4593
fr_dict_t * fr_dict_global_ctx_iter_next(fr_dict_global_ctx_iter_t *iter)
Definition dict_util.c:4887
int fr_dict_attr_set_group(fr_dict_attr_t **da_p, fr_dict_attr_t const *ref)
Definition dict_util.c:5278
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool takes_precedence)
Add a value name.
Definition dict_util.c:2212
fr_slen_t fr_dict_attr_search_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a fr_dict_attr_t by its name in the top level namespace of a dictionary.
Definition dict_util.c:3264
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Definition dict_util.c:4708
int fr_dict_attr_add_initialised(fr_dict_attr_t *da)
A variant of fr_dict_attr_t that allows a pre-allocated, populated fr_dict_attr_t to be added.
Definition dict_util.c:1840
ssize_t fr_dict_valid_oid_str(char const *name, ssize_t len)
Definition dict_util.c:4976
int fr_dict_global_ctx_dir_set(char const *dict_dir)
Allow the default dict dir to be changed after initialisation.
Definition dict_util.c:4794
fr_slen_t fr_dict_enum_name_from_substr(fr_sbuff_t *out, fr_sbuff_parse_error_t *err, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Extract an enumeration name from a string.
Definition dict_util.c:3816
static int _dict_global_free_at_exit(void *uctx)
Definition dict_util.c:4627
static uint32_t dict_protocol_num_hash(void const *data)
Hash a protocol number.
Definition dict_util.c:172
static uint32_t dict_vendor_name_hash(void const *data)
Wrap name hash function for fr_dict_vendor_t.
Definition dict_util.c:281
#define DICT_NAME_APPEND(_in, _dict)
static int _dict_free(fr_dict_t *dict)
Definition dict_util.c:4089
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4898
static int dict_attr_init_common(char const *filename, int line, fr_dict_attr_t **da_p, fr_dict_attr_t const *parent, fr_type_t type, dict_attr_args_t const *args)
Definition dict_util.c:824
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
Definition dict_util.c:2866
int fr_dict_enum_autoload(fr_dict_enum_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4351
fr_dict_enum_value_t const * fr_dict_enum_iter_init(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
Iterate over all enumeration values for an attribute.
Definition dict_util.c:3609
int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4488
static int dict_autoref_free(fr_dict_t *dict)
Definition dict_util.c:4062
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition dict_util.c:5088
fr_slen_t dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
Definition dict_util.c:2675
fr_dict_attr_t const * fr_dict_unlocal(fr_dict_attr_t const *da)
Definition dict_util.c:5255
bool const fr_dict_attr_nested_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a nested dictionary attribute name.
Definition dict_util.c:70
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition dict_util.c:2308
static int dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Call the specified callback for da and then for all its children.
Definition dict_util.c:5063
bool const fr_dict_attr_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a single dictionary attribute name.
Definition dict_util.c:63
fr_dict_attr_t * dict_attr_alloc_null(TALLOC_CTX *ctx, fr_dict_protocol_t const *proto)
Allocate a partially completed attribute.
Definition dict_util.c:984
int dict_attr_type_init(fr_dict_attr_t **da_p, fr_type_t type)
Initialise type specific fields within the dictionary attribute.
Definition dict_util.c:546
int dict_attr_parent_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *parent)
Initialise fields which depend on a parent attribute.
Definition dict_util.c:633
static void dependent_debug(fr_dict_t *dict)
Definition dict_util.c:4044
fr_dict_t const * fr_dict_proto_dict(fr_dict_t const *dict)
Definition dict_util.c:5271
fr_dict_t * dict_alloc(TALLOC_CTX *ctx)
Allocate a new dictionary.
Definition dict_util.c:4172
static uint32_t dict_vendor_pen_hash(void const *data)
Hash a vendor number.
Definition dict_util.c:306
int8_t fr_dict_attr_ordered_cmp(fr_dict_attr_t const *a, fr_dict_attr_t const *b)
Compare two attributes by total order.
Definition dict_util.c:223
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition dict_util.c:5247
fr_dict_attr_t * _dict_attr_alloc_root(char const *filename, int line, TALLOC_CTX *ctx, fr_dict_t const *dict, char const *name, int proto_number, dict_attr_args_t const *args)
Allocate a dictionary root attribute on the heap.
Definition dict_util.c:1025
fr_dict_attr_t * _dict_attr_alloc(char const *filename, int line, TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *name, int attr, fr_type_t type, dict_attr_args_t const *args)
Allocate a dictionary attribute on the heap.
Definition dict_util.c:1059
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
Definition dict_util.c:1124
void fr_dl_dict_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically free a dictionary when the module is unloaded.
Definition dict_util.c:4622
fr_dict_autoload_talloc_t * _fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent)
Autoload a dictionary and bind the lifetime to a talloc chunk.
Definition dict_util.c:4539
bool const fr_dict_enum_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in enumeration value names.
Definition dict_util.c:78
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2879
static fr_slen_t dict_attr_search_qualified(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign, dict_attr_resolve_func_t func)
Internal function for searching for attributes in multiple dictionaries.
Definition dict_util.c:3168
bool dict_attr_can_have_children(fr_dict_attr_t const *da)
See if a fr_dict_attr_t can have children.
Definition dict_util.c:1650
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition dict_util.c:4910
static int8_t _dict_dependent_cmp(void const *a, void const *b)
Find a dependent in the tree of dependents.
Definition dict_util.c:3927
fr_slen_t fr_dict_attr_by_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Resolve an attribute using an OID string.
Definition dict_util.c:2584
void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
Definition dict_util.c:5094
#define FNV_MAGIC_PRIME
Definition dict_util.c:114
bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child)
See if a structural da is allowed to contain another da.
Definition dict_util.c:5184
void dict_attr_location_init(fr_dict_attr_t *da, char const *filename, int line)
Set where the dictionary attribute was defined.
Definition dict_util.c:739
fr_dict_t * dict_by_da(fr_dict_attr_t const *da)
Internal version of fr_dict_by_da.
Definition dict_util.c:2796
fr_dict_t * fr_dict_global_ctx_iter_init(fr_dict_global_ctx_iter_t *iter)
Iterate protocols by name.
Definition dict_util.c:4880
static int8_t dict_vendor_name_cmp(void const *one, void const *two)
Compare two attribute names.
Definition dict_util.c:293
fr_slen_t fr_dict_attr_search_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition dict_util.c:3235
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2660
fr_dict_attr_t const * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
Definition dict_util.c:2955
int dict_attr_add_to_namespace(fr_dict_attr_t const *parent, fr_dict_attr_t *da)
Add an attribute to the name table for an attribute.
Definition dict_util.c:1774
fr_dict_attr_t * dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Internal version of fr_dict_attr_child_by_num.
Definition dict_util.c:3541
void fr_dict_global_ctx_set(fr_dict_gctx_t const *gctx)
Set a new, active, global dictionary context.
Definition dict_util.c:4764
int fr_dl_dict_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically load dictionaries required by modules.
Definition dict_util.c:4609
static int8_t dict_attr_name_cmp(void const *one, void const *two)
Compare two attribute names.
Definition dict_util.c:205
static int8_t dict_vendor_pen_cmp(void const *one, void const *two)
Compare two vendor numbers.
Definition dict_util.c:315
static int8_t dict_enum_value_cmp(void const *one, void const *two)
Compare two dictionary enum values.
Definition dict_util.c:362
fr_dict_attr_t * dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
Definition dict_util.c:3477
static uint32_t dict_attr_name_hash(void const *data)
Wrap name hash function for fr_dict_attr_t.
Definition dict_util.c:193
static int _fr_dict_autoload_talloc_free(fr_dict_autoload_talloc_t const *to_free)
Talloc destructor to automatically free dictionaries.
Definition dict_util.c:4521
fr_dict_t * dict_by_protocol_num(unsigned int num)
Internal version of fr_dict_by_protocol_num.
Definition dict_util.c:2782
static int dict_attr_acopy_child(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src, fr_dict_attr_t const *child)
Definition dict_util.c:1148
fr_slen_t fr_dict_attr_search_by_qualified_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by a dictionary qualified OID string.
Definition dict_util.c:3293
dl_t * fr_dict_dl(fr_dict_t const *dict)
Definition dict_util.c:2670
static fr_slen_t dict_attr_search(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign, dict_attr_resolve_func_t func)
Internal function for searching for attributes in multiple dictionaries.
Definition dict_util.c:3020
char const * fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the name of an enum value in a fr_dict_attr_t.
Definition dict_util.c:3683
fr_dict_enum_value_t const * fr_dict_enum_iter_next(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
Definition dict_util.c:3630
int fr_dict_enum_add_name_next(fr_dict_attr_t *da, char const *name)
Add an name to an integer attribute hashing the name for the integer value.
Definition dict_util.c:2224
int dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child)
Add a child to a parent.
Definition dict_util.c:1675
static int dict_attr_children_init(fr_dict_attr_t **da_p)
Add a child/nesting extension to an attribute.
Definition dict_util.c:458
fr_dict_autoload_t load[2]
Autoloader def.
Definition dict_util.c:4513
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4324
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition dict_util.c:3650
int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
Decrement ref count for a dependent in a dictionary.
Definition dict_util.c:4006
int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
Process a single OID component.
Definition dict_util.c:2351
fr_slen_t fr_dict_enum_by_name_substr(fr_dict_enum_value_t **out, fr_dict_attr_t const *da, fr_sbuff_t *in)
Definition dict_util.c:3722
static int8_t dict_enum_name_cmp(void const *one, void const *two)
Compare two dictionary attribute enum values.
Definition dict_util.c:336
void fr_dict_global_ctx_perm_check(fr_dict_gctx_t *gctx, bool enable)
Set whether we check dictionary file permissions.
Definition dict_util.c:4755
void fr_dict_global_ctx_read_only(void)
Mark all dictionaries and the global dictionary ctx as read only.
Definition dict_util.c:4814
int _dict_attr_init_name_only(char const *filename, int line, fr_dict_attr_t **da_p, fr_dict_attr_t const *parent, char const *name, fr_type_t type, dict_attr_args_t const *args)
Initialise fields in a dictionary attribute structure.
Definition dict_util.c:932
fr_dict_attr_t const * fr_dict_attr_by_oid(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *oid)
Resolve an attribute using an OID string.
Definition dict_util.c:2633
int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
Add a vendor to the dictionary.
Definition dict_util.c:1580
static int _dict_global_free(fr_dict_gctx_t *gctx)
Definition dict_util.c:4632
static int8_t dict_protocol_name_cmp(void const *one, void const *two)
Compare two protocol names.
Definition dict_util.c:159
static int dict_attr_enumv_init(fr_dict_attr_t **da_p)
Initialise a per-attribute enumeration table.
Definition dict_util.c:493
int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4308
int fr_dl_dict_enum_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically resolve enum values.
Definition dict_util.c:4577
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4390
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4923
fr_slen_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
Look up a protocol name embedded in another string.
Definition dict_util.c:2757
int fr_dict_dependent_add(fr_dict_t const *dict, char const *dependent)
Manually increase the reference count for a dictionary.
Definition dict_util.c:3991
static int8_t dict_protocol_num_cmp(void const *one, void const *two)
Compare two protocol numbers.
Definition dict_util.c:180
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2837
static uint32_t dict_protocol_name_hash(void const *data)
Wrap name hash function for fr_dict_protocol_t.
Definition dict_util.c:147
int dict_attr_finalise(fr_dict_attr_t **da_p, char const *name)
Set remaining fields in a dictionary attribute before insertion.
Definition dict_util.c:753
bool fr_dict_is_read_only(fr_dict_t const *dict)
Definition dict_util.c:2665
static uint32_t dict_hash_name(char const *name, size_t len)
Apply a simple (case insensitive) hashing function to the name of an attribute, vendor or protocol.
Definition dict_util.c:123
int fr_dict_attr_add_name_only(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, fr_type_t type, fr_dict_attr_flags_t const *flags)
Add an attribute to the dictionary.
Definition dict_util.c:2001
#define FNV_MAGIC_INIT
Definition dict_util.c:113
int dict_attr_num_init(fr_dict_attr_t *da, unsigned int num)
Set the attribute number (if any)
Definition dict_util.c:709
static int dict_attr_namespace_init(fr_dict_attr_t **da_p)
Initialise a per-attribute namespace.
Definition dict_util.c:509
char const * fr_dict_global_ctx_dir(void)
Definition dict_util.c:4805
int dict_attr_num_init_name_only(fr_dict_attr_t *da)
Set the attribute number (if any)
Definition dict_util.c:727
static int _dict_attr_free(fr_dict_attr_t *da)
Definition dict_util.c:950
int fr_dict_global_ctx_free(fr_dict_gctx_t const *gctx)
Explicitly free all data associated with a global dictionary context.
Definition dict_util.c:4780
int dict_dlopen(fr_dict_t *dict, char const *name)
Definition dict_util.c:3856
fr_dict_t * dict_by_protocol_name(char const *name)
Internal version of fr_dict_by_protocol_name.
Definition dict_util.c:2768
int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy the children of an existing attribute.
Definition dict_util.c:1186
fr_dict_vendor_t const * fr_dict_vendor_by_name(fr_dict_t const *dict, char const *name)
Look up a vendor by its name.
Definition dict_util.c:2917
int dict_attr_acopy_aliases(UNUSED fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy aliases of an existing attribute to a new one.
Definition dict_util.c:1318
fr_slen_t(* dict_attr_resolve_func_t)(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Callback function for resolving dictionary attributes.
Definition dict_util.c:3000
void fr_dict_gctx_debug(FILE *fp, fr_dict_gctx_t const *gctx)
Dump information about currently loaded dictionaries.
Definition dict_util.c:4841
fr_dict_attr_t const * fr_dict_attr_iterate_children(fr_dict_attr_t const *parent, fr_dict_attr_t const **prev)
Iterate over children of a DA.
Definition dict_util.c:5009
int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool takes_precedence, fr_dict_attr_t const *key_child_ref)
Definition dict_util.c:2015
int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
Process a dict_autoload element to load a protocol.
Definition dict_util.c:4455
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
Look up a vendor by its PEN.
Definition dict_util.c:2940
int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref, bool from_public)
Add an alias to an existing attribute.
Definition dict_util.c:1399
fr_slen_t fr_dict_attr_search_by_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by a dictionary using a non-qualified OID string.
Definition dict_util.c:3322
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4933
#define DICT_ATTR_ALLOWED_CHARS
Definition dict_util.c:43
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition dict_util.c:4261
ssize_t fr_dict_attr_by_oid_legacy(fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
Get the leaf attribute of an OID string.
Definition dict_util.c:2394
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3523
fr_slen_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *name, UNUSED fr_sbuff_term_t const *tt)
Look up a dictionary attribute by a name embedded in another string.
Definition dict_util.c:3392
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3588
int dict_dependent_add(fr_dict_t *dict, char const *dependent)
Record a new dependency on a dictionary.
Definition dict_util.c:3947
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3696
static int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
Set a dictionary attribute's name.
Definition dict_util.c:405
fr_slen_t fr_dict_oid_component(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Parse an OID component, resolving it to a defined attribute.
Definition dict_util.c:2485
static int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
Cache the vendor pointer for an attribute.
Definition dict_util.c:475
static uint32_t dict_enum_name_hash(void const *data)
Hash a enumeration name.
Definition dict_util.c:326
int dict_protocol_add(fr_dict_t *dict)
Add a protocol to the global protocol table.
Definition dict_util.c:1507
static uint32_t dict_enum_value_hash(void const *data)
Hash a dictionary enum value.
Definition dict_util.c:352
fr_dict_attr_t const * fr_dict_attr_search_by_qualified_oid(fr_dict_attr_err_t *err, fr_dict_t const *dict_def, char const *name, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition dict_util.c:3341
bool dict_has_dependents(fr_dict_t *dict)
Check if a dictionary still has dependents.
Definition dict_util.c:4038
fr_dict_gctx_t * dict_gctx
Top level structure containing global dictionary state.
Definition dict_util.c:41
fr_dict_t const * fr_dict_by_protocol_num(unsigned int num)
Lookup a protocol by its number.
Definition dict_util.c:2850
int dict_attr_acopy_enumv(fr_dict_attr_t *dst, fr_dict_attr_t const *src)
Copy the VALUEs of an existing attribute, by casting them.
Definition dict_util.c:1283
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags)
Add an attribute to the dictionary.
Definition dict_util.c:1962
char const * dependent
Dependent that loaded the dictionary.
Definition dict_util.c:4514
static fr_dict_attr_t const * dict_attr_alias(fr_dict_attr_err_t *err, fr_dict_attr_t const *da)
Resolve an alias attribute to the concrete attribute it points to.
Definition dict_util.c:380
fr_dict_vendor_t const * fr_dict_vendor_by_da(fr_dict_attr_t const *da)
Look up a vendor by one of its child attributes.
Definition dict_util.c:2895
fr_dict_attr_t * dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, fr_dict_attr_t const *in, char const *name)
Copy a an existing attribute, possibly to a new location.
Definition dict_util.c:1088
int _dict_attr_init(char const *filename, int line, fr_dict_attr_t **da_p, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, dict_attr_args_t const *args)
Initialise fields in a dictionary attribute structure.
Definition dict_util.c:885
Structure used to managed the lifetime of a dictionary.
Definition dict_util.c:4512
dl_loader_t * dl_loader_init(TALLOC_CTX *ctx, void *uctx, bool uctx_free, bool defer_symbol_init)
Initialise structures needed by the dynamic linker.
Definition dl.c:900
int dl_free(dl_t const *dl)
"free" a dl handle, possibly actually freeing it, and unloading the library
Definition dl.c:693
dl_t * dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx_free)
Search for a dl's shared object in various locations.
Definition dl.c:470
Module handle.
Definition dl.h:57
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:257
void * fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Iterate over entries in a hash table.
Definition hash.c:649
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition hash.c:450
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:704
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:847
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
Definition hash.c:489
int fr_hash_table_flatten(TALLOC_CTX *ctx, void **out[], fr_hash_table_t *ht)
Copy all entries out of a hash table into an array.
Definition hash.c:721
uint32_t fr_hash_string(char const *p)
Definition hash.c:900
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
Definition hash.c:617
void fr_hash_table_verify(fr_hash_table_t *ht)
Check hash table is sane.
Definition hash.c:987
int fr_hash_table_replace(void **old, fr_hash_table_t *ht, void const *data)
Replace old data with new data, OR insert if there is no old.
Definition hash.c:551
uint32_t fr_hash_table_num_elements(fr_hash_table_t *ht)
Definition hash.c:633
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
Definition hash.h:61
#define fr_hash_table_talloc_alloc(_ctx, _type, _hash_node, _cmp_node, _free_node)
Definition hash.h:64
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(hp)
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
long int ssize_t
ssize_t fr_sbuff_out_bstrncpy_exact(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
size_t fr_sbuff_out_bstrncpy_allowed(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, bool const allowed[static SBUFF_CHAR_CLASS])
unsigned char uint8_t
ssize_t fr_slen_t
unsigned long int size_t
#define UINT8_MAX
fr_sbuff_parse_error_t
@ FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW
Integer type would overflow.
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
@ FR_SBUFF_PARSE_OK
No error.
@ FR_SBUFF_PARSE_ERROR_TRAILING
Trailing characters found.
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:35
int strcasecmp(char *s1, char *s2)
Definition missing.c:65
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool done
Definition radclient.c:80
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:269
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
static char const * name
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition sbuff.c:1825
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition sbuff.c:2200
bool const sbuff_char_alpha_num[SBUFF_CHAR_CLASS]
Definition sbuff.c:99
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition sbuff.c:1900
fr_table_num_ordered_t const sbuff_parse_error_table[]
Definition sbuff.c:43
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition sbuff.c:1612
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition sbuff.c:2136
#define fr_sbuff_set(_dst, _src)
#define SBUFF_CHAR_CLASS
Definition sbuff.h:203
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
#define fr_sbuff_is_alpha(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_len(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define fr_sbuff_behind(_sbuff_or_marker)
Set of terminal elements.
fr_aka_sim_id_type_t type
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:546
#define talloc_get_type_abort_const
Definition talloc.h:117
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:254
static void talloc_bstr_tolower(char *str)
Convert a talloced string to lowercase.
Definition talloc.h:157
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
@ FR_TIME_RES_SEC
Definition time.h:50
@ T_OP_CMP_EQ
Definition token.h:104
static fr_slen_t parent
Definition pair.h:858
#define add(_type, _out, _in)
Definition stats.c:187
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
bool const fr_type_fixed_size[FR_TYPE_MAX+1]
Definition types.c:189
bool const fr_type_structural[FR_TYPE_MAX+1]
Definition types.c:194
#define fr_type_is_non_leaf(_x)
Definition types.h:394
#define fr_type_is_variable_size(_x)
Definition types.h:388
#define fr_type_is_structural(_x)
Definition types.h:392
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:81
#define FR_TYPE_STRUCTURAL
Definition types.h:316
#define fr_type_is_leaf(_x)
Definition types.h:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
size_t fr_value_box_network_length(fr_value_box_t const *value)
Get the size of the value held by the fr_value_box_t.
Definition value.c:1409
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:7088
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3946
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:748
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4394
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
Definition value.c:993
void fr_value_box_increment(fr_value_box_t *vb)
Increment a boxed value.
Definition value.c:5255
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
static fr_slen_t data
Definition value.h:1340
#define fr_box_strvalue_len(_val, _len)
Definition value.h:309
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:610
static size_t char ** out
Definition value.h:1030