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