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