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