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