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