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