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