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