The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_fixup.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/** Code to apply fctx and finalisation steps to a dictionary
18 *
19 * @file src/lib/util/dict_fixup.c
20 *
21 * @copyright 2020 The FreeRADIUS server project
22 * @copyright 2020,2024 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23 */
24RCSID("$Id: b96dfda1d29e50a1c8556b4f11a72dea276f3da8 $")
25
26#include <freeradius-devel/util/dict.h>
27#include <freeradius-devel/util/file.h>
28#include <freeradius-devel/util/sbuff.h>
29#include <freeradius-devel/util/strerror.h>
30#include <freeradius-devel/util/types.h>
31#include <freeradius-devel/util/talloc.h>
32#include <freeradius-devel/util/value.h>
33
34#include "dict_fixup_priv.h"
35
36/** Common fields for every fixup structure
37 *
38 */
39typedef struct {
40 fr_dlist_t entry; //!< Entry in linked list of fctx.
42
43/** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
44 *
45 */
46typedef struct {
47 dict_fixup_common_t common; //!< Common fields.
48
49 char *filename; //!< where the line being fixed up.
50 int line; //!< ditto.
51
52 char *alias; //!< we need to create.
53 fr_dict_attr_t *alias_parent; //!< Where to add the alias.
54
55 char *ref; //!< what the alias references.
56 fr_dict_attr_t *ref_parent; //!< Parent attribute to resolve the 'attribute' string in.
58
59/** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
60 *
61 */
62typedef struct {
63 dict_fixup_common_t common; //!< Common fields.
64
65 char *filename; //!< where the line being fixed up.
66 int line; //!< ditto.
67
68 char *attribute; //!< we couldn't find (and will need to resolve later).
69 char *name; //!< Raw enum name.
70 char *value; //!< Raw enum value. We can't do anything with this until
71 //!< we know the attribute type, which we only find out later.
72
73 fr_dict_attr_t const *parent; //!< Parent attribute to resolve the 'attribute' string in.
75
76/** Resolve a group reference
77 *
78 */
79typedef struct {
80 dict_fixup_common_t common; //!< Common fields.
81
82 fr_dict_attr_t *da; //!< FR_TYPE_GROUP to fix
83 char *ref; //!< the reference name
85
86/** Clone operation from one tree node to another
87 *
88 */
89typedef struct {
90 dict_fixup_common_t common; //!< Common fields.
91
92 fr_dict_attr_t *da; //!< to populate with cloned information.
93 char *ref; //!< the target attribute to clone
95
96/** Run fixup callbacks for a VSA
97 *
98 */
99typedef struct {
100 dict_fixup_common_t common; //!< Common fields.
101
102 fr_dict_attr_t *da; //!< FR_TYPE_VSA to fix
104
105/** Dictionary attribute namespaces need their hash tables finalised
106 *
107 */
108typedef struct {
109 dict_fixup_common_t common; //!< Common fields.
110
111 fr_hash_table_t *hash; //!< We need to finalise.
113
114/** Initialise common fields in fixup struct, and add it to a fixup list
115 *
116 * @param[in] fixup_list to add fixup to.
117 * @param[in] common common header to populate.
118 * @return
119 * - 0 on success.
120 * - -1 on out of memory.
121 */
122static inline CC_HINT(always_inline) int dict_fixup_common(fr_dlist_head_t *fixup_list, dict_fixup_common_t *common)
123{
124 fr_dlist_insert_tail(fixup_list, common);
125
126 return 0;
127}
128
129/** Resolve a ref= or copy= value to a dictionary */
130
131/** Resolve a reference string to a dictionary attribute
132 *
133 * @param[in] rel Relative attribute to resolve from.
134 * @param[in] ref Reference string.
135 * @param[in] absolute_root If true, and there is no '.' prefix, searching will begin from
136 * the root of the dictionary, else we pretend there was a '.' and
137 * search from rel.
138 */
139fr_dict_attr_t const *dict_protocol_reference(fr_dict_attr_t const *rel, char const *ref, bool absolute_root)
140{
141 fr_dict_t *dict = fr_dict_unconst(rel->dict);
142 fr_dict_attr_t const *da = rel, *found;
143 ssize_t slen;
144 fr_sbuff_t sbuff = FR_SBUFF_IN(ref, strlen(ref));
145
146 /*
147 * Are we resolving a foreign reference?
148 */
149 if (fr_sbuff_next_if_char(&sbuff, '@')) {
150 char proto_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
151 fr_sbuff_t proto_name_sbuff = FR_SBUFF_OUT(proto_name, sizeof(proto_name));
152
153 slen = dict_by_protocol_substr(NULL, &dict, &sbuff, NULL);
154 /* Need to load it... */
155 if (slen <= 0) {
156 /* Quiet coverity */
157 fr_sbuff_terminate(&proto_name_sbuff);
158
159 /* Fixme, probably want to limit allowed chars */
160 if (fr_sbuff_out_bstrncpy_until(&proto_name_sbuff, &sbuff, SIZE_MAX,
161 &FR_SBUFF_TERMS(L(""), L(".")), NULL) <= 0) {
162 invalid_name:
163 fr_strerror_const("Invalid protocol name");
164 return NULL;
165 }
166
167 /*
168 * The filenames are lowercase. The names in the dictionaries are case-insensitive. So
169 * we mash the name to all lowercase.
170 */
171 fr_tolower(proto_name);
172
173 /*
174 * Catch this early, so people don't do stupid things
175 * like put slashes in the references and then claim
176 * it's a security issue.
177 */
178 if (fr_dict_valid_oid_str(proto_name, -1) < 0) goto invalid_name;
179
180 /*
181 * Load the new dictionary, and mark it as loaded from our dictionary.
182 */
183 if (fr_dict_protocol_afrom_file(&dict, proto_name, NULL, (rel->dict)->root->name) < 0) {
184 return NULL;
185 }
186
187 if (!fr_hash_table_insert((rel->dict)->autoref, dict)) {
188 fr_strerror_const("Failed inserting into internal autoref table");
189 return NULL;
190 }
191 }
192
193 /*
194 * Didn't stop at an attribute ref... we're done
195 */
196 if (!fr_sbuff_next_if_char(&sbuff, '.')) {
197 return dict->root;
198 }
199
200 da = dict->root;
201 }
202
203 /*
204 * First '.' makes it reletive, subsequent ones traverse up the tree.
205 *
206 * No '.' means use the root.
207 */
208 if (fr_sbuff_next_if_char(&sbuff, '.')) {
209 while (fr_sbuff_next_if_char(&sbuff, '.')) {
210 if (!da->parent) {
211 fr_strerror_const("Reference attempted to navigate above dictionary root");
212 return NULL;
213 }
214 da = da->parent;
215 }
216 } else {
217 da = absolute_root ? dict->root : rel;
218 }
219
220 /*
221 * Look up the attribute.
222 */
223 if (fr_dict_attr_by_oid_substr(NULL, &found, da, &sbuff, NULL) <= 0) return NULL;
224
225 return found;
226}
227
228/** Add an enumeration value to an attribute which has not yet been defined
229 *
230 * @param[in] fctx Holds current dictionary parsing information.
231 * @param[in] filename this fixup relates to.
232 * @param[in] line this fixup relates to.
233 * @param[in] attr The OID string pointing to the attribute
234 * to add the enumeration value to.
235 * @param[in] attr_len The length of the attr string.
236 * @param[in] name The name of the enumv.
237 * @param[in] name_len Length of the name string.
238 * @param[in] value Value string. This is kept as a string until we know
239 * what type we want to transform it into.
240 * @param[in] value_len Length of the value string.
241 * @param[in] parent of this attribute.
242 * @return
243 * - 0 on success.
244 * - -1 on out of memory.
245 */
246int dict_fixup_enumv_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line,
247 char const *attr, size_t attr_len,
248 char const *name, size_t name_len,
249 char const *value, size_t value_len,
250 fr_dict_attr_t const *parent)
251{
252 dict_fixup_enumv_t *fixup;
253
254 fixup = talloc(fctx->pool, dict_fixup_enumv_t);
255 if (!fixup) {
256 oom:
257 fr_strerror_const("Out of memory");
258 return -1;
259 }
260 *fixup = (dict_fixup_enumv_t) {
261 .attribute = talloc_bstrndup(fixup, attr, attr_len),
262 .name = talloc_bstrndup(fixup, name, name_len),
263 .value = talloc_bstrndup(fixup, value, value_len),
264 .parent = parent
265 };
266 if (!fixup->attribute || !fixup->name || !fixup->value) goto oom;
267
268 fixup->filename = talloc_strdup(fixup, filename);
269 if (!fixup->filename) goto oom;
270 fixup->line = line;
271
272 return dict_fixup_common(&fctx->enumv, &fixup->common);
273}
274
275/** Add a previously defined enumeration value to an existing attribute
276 *
277 * @param[in] fctx Holds current dictionary parsing information.
278 * @param[in] fixup Hash table to fill.
279 * @return
280 * - 0 on success.
281 * - -1 on failure.
282 */
283static inline CC_HINT(always_inline) int dict_fixup_enumv_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_enumv_t *fixup)
284{
285 fr_dict_attr_t *da;
288 int ret;
289 fr_dict_attr_t const *da_const;
290
291 da_const = fr_dict_attr_by_oid(NULL, fixup->parent, fixup->attribute);
292 if (!da_const) {
293 fr_strerror_printf_push("Failed resolving ATTRIBUTE referenced by VALUE '%s' at %s[%d]",
294 fixup->name, fr_cwd_strip(fixup->filename), fixup->line);
295 return -1;
296 }
297 da = fr_dict_attr_unconst(da_const);
298 type = da->type;
299
300 if (fr_value_box_from_str(fixup, &value, type, NULL,
301 fixup->value, talloc_array_length(fixup->value) - 1,
302 NULL, false) < 0) {
303 fr_strerror_printf_push("Invalid VALUE '%pV' for attribute '%s' at %s[%d]",
305 da->name,
306 fr_cwd_strip(fixup->filename), fixup->line);
307 return -1;
308 }
309
310 ret = fr_dict_enum_add_name(da, fixup->name, &value, false, false);
312
313 if (ret < 0) return -1;
314
315 return 0;
316}
317
318/** Resolve a group reference
319 *
320 * This is required as the reference may point to another dictionary which
321 * hasn't been loaded yet.
322 *
323 * @param[in] fctx Holds current dictionary parsing information.
324 * @param[in] da The group dictionary attribute.
325 * @param[in] ref OID string representing what the group references.
326 * @return
327 * - 0 on success.
328 * - -1 on out of memory.
329 */
331{
332 dict_fixup_group_t *fixup;
333
334 fixup = talloc(fctx->pool, dict_fixup_group_t);
335 if (!fixup) {
336 fr_strerror_const("Out of memory");
337 return -1;
338 }
339 *fixup = (dict_fixup_group_t) {
340 .da = da,
341 .ref = talloc_strdup(fixup, ref),
342 };
343
344 return dict_fixup_common(&fctx->group, &fixup->common);
345}
346
347/** Resolve a group reference
348 *
349 * @param[in] fctx Holds current dictionary parsing information.
350 * @param[in] fixup Hash table to fill.
351 * @return
352 * - 0 on success.
353 * - -1 on failure.
354 */
355static inline CC_HINT(always_inline) int dict_fixup_group_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_group_t *fixup)
356{
357 fr_dict_attr_t const *da;
358
359 da = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
360 if (!da) {
361 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
362 fr_cwd_strip(fixup->da->filename), fixup->da->line);
363 return -1;
364 }
365
366 if (da->type != FR_TYPE_TLV) {
367 fr_strerror_printf("References MUST be to attributes of type 'tlv' at %s[%d]",
368 fr_cwd_strip(fixup->da->filename), fixup->da->line);
369 return -1;
370 }
371
372 if (fr_dict_attr_ref(da)) {
373 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which also has 'ref=...' at %s[%d]",
374 fr_cwd_strip(fixup->da->filename), fixup->da->line);
375 return -1;
376 }
377 if (unlikely(dict_attr_ref_resolve(fixup->da, da) < 0)) return -1;
378
379 return 0;
380}
381
382/** Clone one area of a tree into another
383 *
384 * These must be processed later to ensure that we've finished building an
385 * attribute by the time it has been cloned.
386 *
387 * @param[in] fctx Holds current dictionary parsing information.
388 * @param[in] da The group dictionary attribute.
389 * @param[in] ref OID string representing what the group references..
390 * @return
391 * - 0 on success.
392 * - -1 on out of memory.
393 */
395{
396 dict_fixup_clone_t *fixup;
397
398 /*
399 * Delay type checks until we've loaded all of the
400 * dictionaries. This means that errors are produced
401 * later, but that shouldn't matter for the default
402 * dictionaries. They're supposed to work.
403 */
404 fixup = talloc(fctx->pool, dict_fixup_clone_t);
405 if (!fixup) {
406 fr_strerror_const("Out of memory");
407 return -1;
408 }
409 *fixup = (dict_fixup_clone_t) {
410 .da = da,
411 .ref = talloc_typed_strdup(fixup, ref)
412 };
413
414 return dict_fixup_common(&fctx->clone, &fixup->common);
415}
416
417/** Clone a dictionary attribute from a ref
418 *
419 * @param[in] dst_p will either be inserted directly, with fields from the clone, or will be
420 * cloned, and then inserted. In this case the original dst da will be freed
421 * and the new cloned attribute will be written back to dst_p.
422 * @param[in] src to clone.
423 * @return
424 * - 0 on success.
425 * - -1 on failure.
426 */
428{
429 fr_dict_attr_t *dst = *dst_p;
430 fr_dict_t *dict = fr_dict_unconst(dst->dict);
431 fr_dict_attr_t *cloned;
432
433 if (src->dict->proto != dst->dict->proto) {
434 fr_strerror_printf("Incompatible protocols. Referenced '%s', referencing '%s'. Defined at %s[%d]",
435 src->dict->proto->name, dst->dict->proto->name, dst->filename, dst->line);
436 return -1;
437 }
438
439 /*
440 * The referenced DA is higher than the one we're
441 * creating. Ensure it's not a parent.
442 */
443 if (src->depth < dst->depth) {
444 fr_dict_attr_t const *parent;
445
446 for (parent = dst->parent; !parent->flags.is_root; parent = parent->parent) {
447 if (parent == src) {
448 fr_strerror_printf("References MUST NOT refer to a parent attribute %s at %s[%d]",
449 parent->name, fr_cwd_strip(dst->filename), dst->line);
450 return -1;
451 }
452 }
453 }
454
455 if (fr_dict_attr_ref(src)) {
456 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which itself has a 'ref=...' at %s[%d]",
457 fr_cwd_strip(dst->filename), dst->line);
458 return -1;
459 }
460
461 /*
462 * If the attributes are of different types, then we have
463 * to _manually_ clone the values. This means looping
464 * over the ref da, and _casting_ the values to the new
465 * data type. If the cast succeeds, we add the value.
466 * Otherwise we don't
467 *
468 * We do this if the source type is a leaf node, AND the
469 * types are different, or the destination has no
470 * children.
471 */
472 if (!fr_type_is_non_leaf(dst->type) &&
473 ((src->type != dst->type) || !dict_attr_children(src))) {
474 int copied;
475
476 /*
477 * Only TLV and STRUCT types can be the source or destination of clones.
478 *
479 * Leaf types can be cloned, even if they're
480 * different types. But only if they don't have
481 * children (i.e. key fields).
482 */
483 if (fr_type_is_non_leaf(src->type) || fr_type_is_non_leaf(dst->type) ||
485 fr_strerror_printf("Reference MUST be to a simple data type of type '%s' at %s[%d]",
486 fr_type_to_str(dst->type),
487 fr_cwd_strip(dst->filename), dst->line);
488 return -1;
489 }
490
491 /*
492 * We copy all of the VALUEs over from the source
493 * da by hand, by casting them.
494 *
495 * We have to do this work manually because we
496 * can't call dict_attr_acopy(), as that function
497 * copies the VALUE with the *source* data type,
498 * where we need the *destination* data type.
499 */
500 copied = dict_attr_acopy_enumv(dst, src);
501 if (copied < 0) return -1;
502
503 if (!copied) {
504 fr_strerror_printf("Reference copied no VALUEs from type type '%s' at %s[%d]",
505 fr_type_to_str(dst->type),
506 fr_cwd_strip(dst->filename), dst->line);
507 return -1;
508 }
509
510 return 0;
511 }
512
513 /*
514 * Can't clone KEY fields directly, you MUST clone the parent struct.
515 */
517 fr_strerror_printf("Invalid reference from '%s' to %s", dst->name, src->name);
518 return -1;
519 }
520
521 /*
522 * Copy the source attribute, but with a
523 * new name and a new attribute number.
524 */
525 cloned = dict_attr_acopy(dict->pool, src, dst->name);
526 if (!cloned) {
527 fr_strerror_printf("Failed copying attribute '%s' to %s", src->name, dst->name);
528 return -1;
529 }
530
531 cloned->attr = dst->attr;
532 cloned->parent = dst->parent; /* we need to re-parent this attribute */
533 cloned->depth = cloned->parent->depth + 1;
534
535 /*
536 * Copy any pre-existing children over.
537 */
538 if (dict_attr_children(dst)) {
539 if (dict_attr_acopy_children(dict, cloned, dst) < 0) {
540 fr_strerror_printf("Failed populating attribute '%s' with children of %s", src->name, dst->name);
541 return -1;
542 }
543 }
544
545 /*
546 * Copy children of the DA we're cloning.
547 */
548 if (dict_attr_children(src)) {
549 if (dict_attr_acopy_children(dict, cloned, src) < 0) {
550 fr_strerror_printf("Failed populating attribute '%s' with children of %s", src->name, dst->name);
551 return -1;
552 }
553 }
554
555 if (fr_dict_attr_add_initialised(cloned) < 0) {
556 talloc_free(cloned);
557 return -1;
558 }
559
560 /*
561 * Free the original and pass back our new cloned attribute
562 */
563 talloc_free(dst);
564 *dst_p = cloned;
565
566 return 0;
567}
568
569/** Clone one are of a tree into another
570 *
571 * @param[in] fctx Holds current dictionary parsing information.
572 * @param[in] fixup Containing source/destination of the clone.
573 * @return
574 * - 0 on success.
575 * - -1 on failure.
576 */
577static inline CC_HINT(always_inline) int dict_fixup_clone_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
578{
579 fr_dict_attr_t const *src;
580
581 src = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
582 if (!src) {
583 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
584 fr_cwd_strip(fixup->da->filename), fixup->da->line);
585 return -1;
586 }
587
588 return dict_fixup_clone(&fixup->da, src);
589}
590
591/** Clone enumeration values from one attribute to another
592 *
593 * These must be processed later to ensure that we've finished building an
594 * attribute by the time it has been cloned.
595 *
596 * @param[in] fctx Holds current dictionary parsing information.
597 * @param[in] da The group dictionary attribute.
598 * @param[in] ref OID string representing what the group references..
599 * @return
600 * - 0 on success.
601 * - -1 on out of memory.
602 */
604{
605 dict_fixup_clone_t *fixup;
606
607 /*
608 * Delay type checks until we've loaded all of the
609 * dictionaries. This means that errors are produced
610 * later, but that shouldn't matter for the default
611 * dictionaries. They're supposed to work.
612 */
613 fixup = talloc(fctx->pool, dict_fixup_clone_t);
614 if (!fixup) {
615 fr_strerror_const("Out of memory");
616 return -1;
617 }
618 *fixup = (dict_fixup_clone_t) {
619 .da = da,
620 .ref = talloc_typed_strdup(fixup, ref)
621 };
622
623 return dict_fixup_common(&fctx->clone, &fixup->common);
624}
625
626/** Clone one are of a tree into another
627 *
628 * @param[in] fctx Holds current dictionary parsing information.
629 * @param[in] fixup Containing source/destination of the clone.
630 * @return
631 * - 0 on success.
632 * - -1 on failure.
633 */
634static inline CC_HINT(always_inline) int dict_fixup_clone_enum_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
635{
636 fr_dict_attr_t const *src;
637 int copied;
638
639 src = dict_protocol_reference(fixup->da->parent, fixup->ref, true);
640 if (!src) {
641 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
642 fr_cwd_strip(fixup->da->filename), fixup->da->line);
643 return -1;
644 }
645
646 if (src->dict->proto != fixup->da->dict->proto) {
647 fr_strerror_printf("Incompatible protocols. Referenced '%s', referencing '%s'. Defined at %s[%d]",
648 src->dict->proto->name, fixup->da->dict->proto->name, fixup->da->filename, fixup->da->line);
649 return -1;
650 }
651
652 if (fr_dict_attr_ref(src)) {
653 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which itself has a 'ref=...' at %s[%d]",
654 fr_cwd_strip(fixup->da->filename), fixup->da->line);
655 return -1;
656 }
657
658 if (!fr_type_is_non_leaf(fixup->da->type)) {
659 fr_strerror_printf("enum copy can only be applied to leaf types, not %s", fr_type_to_str(fixup->da->type));
660 return -1;
661 }
662
663 if (src->type != fixup->da->type) {
664 fr_strerror_printf("enum copy type mismatch. src '%s', dst '%s'",
665 fr_type_to_str(src->type), fr_type_to_str(fixup->da->type));
666 return -1;
667 }
668
669 /*
670 * We copy all of the VALUEs over from the source
671 * da by hand, by casting them.
672 *
673 * We have to do this work manually because we
674 * can't call dict_attr_acopy(), as that function
675 * copies the VALUE with the *source* data type,
676 * where we need the *destination* data type.
677 */
678 copied = dict_attr_acopy_enumv(fixup->da, src);
679 if (copied < 0) return -1;
680
681 if (!copied) {
682 fr_strerror_printf("Reference copied no VALUEs from type type '%s' at %s[%d]",
683 fr_type_to_str(fixup->da->type),
684 fr_cwd_strip(fixup->da->filename), fixup->da->line);
685 return -1;
686 }
687
688 return 0;
689}
690
691/** Push a fixup for a VSA.
692 *
693 * This is required so that we can define VENDORs for all VSAs, even
694 * if the dictionary doesn't contain VENDOR children for that VSA.
695 * This fixup means that we can define VENDORs elsewhere, and then
696 * use them in all VSA definitions. It means that we don't have to
697 * do these lookups at run-time.
698 *
699 * @param[in] fctx Holds current dictionary parsing information.
700 * @param[in] da The group dictionary attribute.
701 * @return
702 * - 0 on success.
703 * - -1 on out of memory.
704 */
706{
707 dict_fixup_vsa_t *fixup;
708
709 fixup = talloc(fctx->pool, dict_fixup_vsa_t);
710 if (!fixup) {
711 fr_strerror_const("Out of memory");
712 return -1;
713 }
714 *fixup = (dict_fixup_vsa_t) {
715 .da = da,
716 };
717
718 return dict_fixup_common(&fctx->vsa, &fixup->common);
719}
720
721/** Run VSA fixups
722 *
723 * @param[in] fctx Holds current dictionary parsing information.
724 * @param[in] fixup entry for fixup
725 * @return
726 * - 0 on success.
727 * - -1 on failure.
728 */
729static inline CC_HINT(always_inline) int dict_fixup_vsa_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_vsa_t *fixup)
730{
732 fr_dict_t *dict = fr_dict_unconst(fr_dict_by_da(fixup->da));
733 fr_hash_iter_t iter;
734
735 if (!dict->vendors_by_num) return 0;
736
737 for (dv = fr_hash_table_iter_init(dict->vendors_by_num, &iter);
738 dv;
739 dv = fr_hash_table_iter_next(dict->vendors_by_num, &iter)) {
740 if (dict_attr_child_by_num(fixup->da, dv->pen)) continue;
741
742 if (fr_dict_attr_add(dict, fixup->da, dv->name, dv->pen, FR_TYPE_VENDOR, NULL) < 0) return -1;
743 }
744
745 return 0;
746}
747
748
749/** Resolve a group reference
750 *
751 * This is required as the reference may point to another dictionary which
752 * hasn't been loaded yet.
753 *
754 * @param[in] fctx Holds current dictionary parsing information.
755 * @param[in] filename this fixup relates to.
756 * @param[in] line this fixup relates to.
757 * @param[in] alias_parent where to add the alias.
758 * @param[in] alias alias to add.
759 * @param[in] ref_parent attribute that should contain the reference.
760 * @param[in] ref OID string representing what the group references.
761 * @return
762 * - 0 on success.
763 * - -1 on out of memory.
764 */
765int dict_fixup_alias_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line,
766 fr_dict_attr_t *alias_parent, char const *alias,
767 fr_dict_attr_t *ref_parent, char const *ref)
768{
769 dict_fixup_alias_t *fixup;
770
771 fixup = talloc(fctx->pool, dict_fixup_alias_t);
772 if (!fixup) {
773 oom:
774 fr_strerror_const("Out of memory");
775 return -1;
776 }
777 *fixup = (dict_fixup_alias_t) {
778 .alias = talloc_typed_strdup(fixup, alias),
779 .alias_parent = alias_parent,
780 .ref = talloc_typed_strdup(fixup, ref),
781 .ref_parent = ref_parent
782 };
783
784 fixup->filename = talloc_strdup(fixup, filename);
785 if (!fixup->filename) goto oom;
786 fixup->line = line;
787
788 return dict_fixup_common(&fctx->alias, &fixup->common);
789}
790
791static inline CC_HINT(always_inline) int dict_fixup_alias_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_alias_t *fixup)
792{
793 fr_dict_attr_t const *da;
794
795 /*
796 * The <ref> can be a name.
797 */
798 da = fr_dict_attr_by_oid(NULL, fixup->ref_parent, fixup->ref);
799 if (!da) {
800 fr_strerror_printf("Attribute '%s' aliased by '%s' doesn't exist in namespace '%s', at %s[%d]",
801 fixup->ref, fixup->alias, fixup->ref_parent->name, fixup->filename, fixup->line);
802 return -1;
803 }
804
805 return dict_attr_alias_add(fixup->alias_parent, fixup->alias, da);
806}
807
808/** Initialise a fixup ctx
809 *
810 * @param[in] ctx to allocate the fixup pool in.
811 * @param[in] fctx to initialise.
812 * @return
813 * - 0 on success.
814 * - -1 on failure.
815 */
816int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
817{
818 if (fctx->pool) return 0;
819
820 fr_dlist_talloc_init(&fctx->enumv, dict_fixup_enumv_t, common.entry);
821 fr_dlist_talloc_init(&fctx->group, dict_fixup_group_t, common.entry);
822 fr_dlist_talloc_init(&fctx->clone, dict_fixup_clone_t, common.entry);
823 fr_dlist_talloc_init(&fctx->vsa, dict_fixup_vsa_t, common.entry);
824 fr_dlist_talloc_init(&fctx->alias, dict_fixup_alias_t, common.entry);
825
826 fctx->pool = talloc_pool(ctx, DICT_FIXUP_POOL_SIZE);
827 if (!fctx->pool) return -1;
828
829 return 0;
830}
831
832/** Apply all outstanding fixes to a set of dictionaries
833 *
834 */
836{
837
838#define APPLY_FIXUP(_fctx, _list, _func, _type) \
839do { \
840 _type *_fixup; \
841 while ((_fixup = fr_dlist_head(&(_fctx)->_list))) { \
842 if (_func(_fctx, _fixup) < 0) return -1; \
843 fr_dlist_remove(&(_fctx)->_list, _fixup); \
844 talloc_free(_fixup); \
845 } \
846} while (0)
847
848 /*
849 * Apply all the fctx in order
850 *
851
852 * - Enumerations first as they have no dependencies
853 * - Group references next, as group attributes may be cloned.
854 * - Clones last as all other references and additions should
855 * be applied before cloning.
856 * - Clone enum clones the enumeration values from a dedicated
857 * enum, or another attribute with enumerations.
858 * - VSAs
859 * - Aliases last as all attributes need to be defined.
860 */
867
868 TALLOC_FREE(fctx->pool);
869
870 return 0;
871}
872
873/** Fixup all hash tables in the dictionary so they're suitable for threaded access
874 *
875 */
876static int _dict_attr_fixup_hash_tables(fr_dict_attr_t const *da, UNUSED void *uctx)
877{
878 {
880
882 if (ext) {
885 }
886 }
887
888 {
890
893 }
894
895 return 0;
896}
897
898/** Walk a dictionary finalising the hash tables in all attributes with a distinct namespace
899 *
900 * @param[in] dict to finalise namespaces for.
901 */
903{
905
906 (void)_dict_attr_fixup_hash_tables(root, NULL);
907
909
910 /*
911 * Walk over all of the hash tables to ensure they're
912 * initialized. We do this because the threads may perform
913 * lookups, and we don't want multi-threaded re-ordering
914 * of the table entries. That would be bad.
915 */
916 fr_hash_table_fill(dict->vendors_by_name);
917 fr_hash_table_fill(dict->vendors_by_num);
918}
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
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:1087
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:1590
ssize_t fr_dict_valid_oid_str(char const *name, ssize_t len)
Definition dict_util.c:4663
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace)
Add a value name.
Definition dict_util.c:1941
char const * name
Vendor name.
Definition dict.h:250
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4585
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:2606
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition dict_util.c:4777
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition dict_util.c:4597
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:2324
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
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
uint32_t pen
Private enterprise number.
Definition dict.h:246
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:169
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:1712
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:2373
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:153
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:475
Private enterprise.
Definition dict.h:245
fr_hash_table_t * name_by_value
Lookup a name by value.
Definition dict_ext.h:110
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:140
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition dict_ext.h:109
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:184
Attribute extension - Holds enumeration values.
Definition dict_ext.h:107
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_resolve(fr_dict_attr_t const *da, fr_dict_attr_t const *ref)
static fr_dict_attr_t const ** dict_attr_children(fr_dict_attr_t const *da)
fr_dict_attr_t * da
FR_TYPE_GROUP to fix.
Definition dict_fixup.c:82
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:63
int dict_fixup_apply(dict_fixup_ctx_t *fctx)
Apply all outstanding fixes to a set of dictionaries.
Definition dict_fixup.c:835
char * ref
the target attribute to clone
Definition dict_fixup.c:93
char * attribute
we couldn't find (and will need to resolve later).
Definition dict_fixup.c:68
static int dict_fixup_clone_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
Clone one are of a tree into another.
Definition dict_fixup.c:577
char * value
Raw enum value.
Definition dict_fixup.c:70
char * alias
we need to create.
Definition dict_fixup.c:52
char * ref
what the alias references.
Definition dict_fixup.c:55
static int dict_fixup_common(fr_dlist_head_t *fixup_list, dict_fixup_common_t *common)
Initialise common fields in fixup struct, and add it to a fixup list.
Definition dict_fixup.c:122
char * filename
where the line being fixed up.
Definition dict_fixup.c:65
int dict_fixup_enumv_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line, char const *attr, size_t attr_len, char const *name, size_t name_len, char const *value, size_t value_len, fr_dict_attr_t const *parent)
Add an enumeration value to an attribute which has not yet been defined.
Definition dict_fixup.c:246
int dict_fixup_alias_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line, fr_dict_attr_t *alias_parent, char const *alias, fr_dict_attr_t *ref_parent, char const *ref)
Resolve a group reference.
Definition dict_fixup.c:765
int dict_fixup_clone_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Clone one area of a tree into another.
Definition dict_fixup.c:394
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:100
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:80
static int dict_fixup_clone_enum_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
Clone one are of a tree into another.
Definition dict_fixup.c:634
int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
Initialise a fixup ctx.
Definition dict_fixup.c:816
int dict_fixup_clone_enum_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Clone enumeration values from one attribute to another.
Definition dict_fixup.c:603
static int dict_fixup_vsa_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_vsa_t *fixup)
Run VSA fixups.
Definition dict_fixup.c:729
fr_dict_attr_t * alias_parent
Where to add the alias.
Definition dict_fixup.c:53
fr_dict_attr_t const * dict_protocol_reference(fr_dict_attr_t const *rel, char const *ref, bool absolute_root)
Resolve a ref= or copy= value to a dictionary.
Definition dict_fixup.c:139
fr_dlist_t entry
Entry in linked list of fctx.
Definition dict_fixup.c:40
fr_dict_attr_t const * parent
Parent attribute to resolve the 'attribute' string in.
Definition dict_fixup.c:73
static int _dict_attr_fixup_hash_tables(fr_dict_attr_t const *da, UNUSED void *uctx)
Fixup all hash tables in the dictionary so they're suitable for threaded access.
Definition dict_fixup.c:876
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:109
char * filename
where the line being fixed up.
Definition dict_fixup.c:49
fr_hash_table_t * hash
We need to finalise.
Definition dict_fixup.c:111
int dict_fixup_vsa_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da)
Push a fixup for a VSA.
Definition dict_fixup.c:705
int dict_fixup_clone(fr_dict_attr_t **dst_p, fr_dict_attr_t const *src)
Clone a dictionary attribute from a ref.
Definition dict_fixup.c:427
static int dict_fixup_group_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_group_t *fixup)
Resolve a group reference.
Definition dict_fixup.c:355
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:47
int dict_fixup_group_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Resolve a group reference.
Definition dict_fixup.c:330
char * ref
the reference name
Definition dict_fixup.c:83
static int dict_fixup_enumv_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_enumv_t *fixup)
Add a previously defined enumeration value to an existing attribute.
Definition dict_fixup.c:283
#define APPLY_FIXUP(_fctx, _list, _func, _type)
fr_dict_attr_t * ref_parent
Parent attribute to resolve the 'attribute' string in.
Definition dict_fixup.c:56
char * name
Raw enum name.
Definition dict_fixup.c:69
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:902
fr_dict_attr_t * da
FR_TYPE_VSA to fix.
Definition dict_fixup.c:102
static int dict_fixup_alias_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_alias_t *fixup)
Definition dict_fixup.c:791
fr_dict_attr_t * da
to populate with cloned information.
Definition dict_fixup.c:92
dict_fixup_common_t common
Common fields.
Definition dict_fixup.c:90
Add an enumeration value to an attribute that wasn't defined at the time the value was parsed.
Definition dict_fixup.c:46
Clone operation from one tree node to another.
Definition dict_fixup.c:89
Common fields for every fixup structure.
Definition dict_fixup.c:39
Add an enumeration value to an attribute that wasn't defined at the time the value was parsed.
Definition dict_fixup.c:62
Resolve a group reference.
Definition dict_fixup.c:79
Dictionary attribute namespaces need their hash tables finalised.
Definition dict_fixup.c:108
Run fixup callbacks for a VSA.
Definition dict_fixup.c:99
Functions to finalise and fixup dictionaries.
fr_dlist_head_t alias
Aliases that can't be resolved immediately.
fr_dlist_head_t group
Group references to resolve.
fr_dlist_head_t clone
Clone operation to apply.
fr_dlist_head_t vsa
VSAs to add vendors for.
fr_dlist_head_t enumv
Raw enumeration values to add.
TALLOC_CTX * pool
Temporary pool for fixups, reduces holes.
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:2415
#define DICT_FIXUP_POOL_SIZE
Definition dict_priv.h:38
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:3281
fr_dict_attr_t * dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in, char const *new_name)
Copy a an existing attribute.
Definition dict_util.c:1017
int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref)
Add an alias to an existing attribute.
Definition dict_util.c:1174
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:1145
Test enumeration values.
Definition dict_test.h:92
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:275
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
char const * fr_cwd_strip(char const *filename)
Intended to be used in logging functions to make output more readable.
Definition file.c:384
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:626
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:678
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
Definition hash.c:468
void fr_hash_table_fill(fr_hash_table_t *ht)
Ensure all buckets are filled.
Definition hash.c:719
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(reap)
fr_type_t
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
long int ssize_t
size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
char * fr_tolower(char *str)
Definition misc.c:225
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
static char const * name
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:2088
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:192
#define FR_SBUFF_OUT(_start, _len_or_end)
fr_aka_sim_id_type_t type
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:564
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:445
static fr_slen_t parent
Definition pair.h:851
#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
#define fr_type_is_non_leaf(_x)
Definition types.h:373
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition value.c:5315
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3723
#define fr_box_strvalue_buffer(_val)
Definition value.h:289
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:488