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