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