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