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