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