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