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: f2650137ccd10c5ec8c9fd0e94d674bac41fef00 $")
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 reference string to a dictionary attribute
130 *
131 * @param[out] da_p Where the attribute will be stored
132 * @param[in] rel Relative attribute to resolve from.
133 * @param[in] ref Reference string.
134 * @return
135 * - <0 on error
136 * - 0 on parse OK, but *da_p is NULL;
137 * - 1 for parse OK, and *da_p is !NULL
138 */
139int dict_protocol_reference(fr_dict_attr_t const **da_p, fr_dict_attr_t const *rel, char const *ref)
140{
141 fr_dict_t *dict = fr_dict_unconst(rel->dict);
142 fr_dict_attr_t const *da = rel;
143 ssize_t slen;
144 fr_sbuff_t sbuff = FR_SBUFF_IN(ref, strlen(ref));
145
146 *da_p = NULL;
147
148 /*
149 * Are we resolving a foreign reference?
150 */
151 if (fr_sbuff_next_if_char(&sbuff, '@')) {
152 char proto_name[FR_DICT_ATTR_MAX_NAME_LEN + 1];
153 fr_sbuff_t proto_name_sbuff = FR_SBUFF_OUT(proto_name, sizeof(proto_name));
154
155 /*
156 * @.foo is "foo from the current root".
157 *
158 * This is a bit clearer than "foo".
159 */
160 if (fr_sbuff_next_if_char(&sbuff, '.')) {
161 if (fr_sbuff_is_char(&sbuff, '.')) goto above_root;
162
163 da = rel->dict->root;
164 goto more;
165 }
166
167 slen = dict_by_protocol_substr(NULL, &dict, &sbuff, NULL);
168 /* Need to load it... */
169 if (slen <= 0) {
170 /* Quiet coverity */
171 fr_sbuff_terminate(&proto_name_sbuff);
172
173 /* Fixme, probably want to limit allowed chars */
174 if (fr_sbuff_out_bstrncpy_until(&proto_name_sbuff, &sbuff, SIZE_MAX,
175 &FR_SBUFF_TERMS(L(""), L(".")), NULL) <= 0) {
176 invalid_name:
177 fr_strerror_const("Invalid protocol name");
178 return -1;
179 }
180
181 /*
182 * The filenames are lowercase. The names in the dictionaries are case-insensitive. So
183 * we mash the name to all lowercase.
184 */
185 fr_tolower(proto_name);
186
187 /*
188 * Catch this early, so people don't do stupid things
189 * like put slashes in the references and then claim
190 * it's a security issue.
191 */
192 if (fr_dict_valid_oid_str(proto_name, -1) < 0) goto invalid_name;
193
194 /*
195 * Load the new dictionary, and mark it as loaded from our dictionary.
196 */
197 if (fr_dict_protocol_afrom_file(&dict, proto_name, NULL, (rel->dict)->root->name) < 0) {
198 return -1;
199 }
200
201 if (!fr_hash_table_insert((rel->dict)->autoref, dict)) {
202 fr_strerror_const("Failed inserting into internal autoref table");
203 return -1;
204 }
205 }
206
207 /*
208 * Didn't stop at an attribute ref... we're done
209 */
210 if (fr_sbuff_eof(&sbuff)) {
211 *da_p = dict->root;
212 return 1;
213 }
214
215 da = dict->root;
216 }
217
218 if (!fr_sbuff_next_if_char(&sbuff, '.')) {
219 fr_strerror_printf("Attribute %s has reference '%s' which does not begin with '.' or '@'",
220 rel->name, ref);
221 return -1;
222 }
223
224 /*
225 * First '.' makes it reletive, subsequent ones traverse up the tree.
226 *
227 * No '.' means use the root.
228 */
229 while (fr_sbuff_next_if_char(&sbuff, '.')) {
230 if (!da->parent) {
231 above_root:
232 fr_strerror_const("Reference attempted to navigate above dictionary root");
233 return -1;
234 }
235 da = da->parent;
236 }
237
238 /*
239 * Look up the attribute. Note that this call will
240 * update *da_p with a partial reference if it exists.
241 */
242more:
243 slen = fr_dict_attr_by_oid_substr(NULL, da_p, da, &sbuff, NULL);
244 if (slen < 0) return -1;
245
246 if (slen == 0) {
247 *da_p = NULL;
248 return 0;
249 }
250
251 return 1;
252}
253
254/** Add an enumeration value to an attribute which has not yet been defined
255 *
256 * @param[in] fctx Holds current dictionary parsing information.
257 * @param[in] filename this fixup relates to.
258 * @param[in] line this fixup relates to.
259 * @param[in] attr The OID string pointing to the attribute
260 * to add the enumeration value to.
261 * @param[in] attr_len The length of the attr string.
262 * @param[in] name The name of the enumv.
263 * @param[in] name_len Length of the name string.
264 * @param[in] value Value string. This is kept as a string until we know
265 * what type we want to transform it into.
266 * @param[in] value_len Length of the value string.
267 * @param[in] parent of this attribute.
268 * @return
269 * - 0 on success.
270 * - -1 on out of memory.
271 */
272int dict_fixup_enumv_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line,
273 char const *attr, size_t attr_len,
274 char const *name, size_t name_len,
275 char const *value, size_t value_len,
276 fr_dict_attr_t const *parent)
277{
278 dict_fixup_enumv_t *fixup;
279
280 fixup = talloc(fctx->pool, dict_fixup_enumv_t);
281 if (!fixup) {
282 oom:
283 fr_strerror_const("Out of memory");
284 return -1;
285 }
286 *fixup = (dict_fixup_enumv_t) {
287 .attribute = talloc_bstrndup(fixup, attr, attr_len),
288 .name = talloc_bstrndup(fixup, name, name_len),
289 .value = talloc_bstrndup(fixup, value, value_len),
290 .parent = parent
291 };
292 if (!fixup->attribute || !fixup->name || !fixup->value) goto oom;
293
294 fixup->filename = talloc_strdup(fixup, filename);
295 if (!fixup->filename) goto oom;
296 fixup->line = line;
297
298 return dict_fixup_common(&fctx->enumv, &fixup->common);
299}
300
301/** Add a previously defined enumeration value to an existing attribute
302 *
303 * @param[in] fctx Holds current dictionary parsing information.
304 * @param[in] fixup Hash table to fill.
305 * @return
306 * - 0 on success.
307 * - -1 on failure.
308 */
309static inline CC_HINT(always_inline) int dict_fixup_enumv_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_enumv_t *fixup)
310{
311 fr_dict_attr_t *da;
314 int ret;
315 fr_dict_attr_t const *da_const;
316
317 da_const = fr_dict_attr_by_oid(NULL, fixup->parent, fixup->attribute);
318 if (!da_const) {
319 fr_strerror_printf_push("Failed resolving ATTRIBUTE referenced by VALUE '%s' at %s[%d]",
320 fixup->name, fr_cwd_strip(fixup->filename), fixup->line);
321 return -1;
322 }
323 da = fr_dict_attr_unconst(da_const);
324 type = da->type;
325
326 if (fr_value_box_from_str(fixup, &value, type, NULL,
327 fixup->value, talloc_array_length(fixup->value) - 1,
328 NULL) < 0) {
329 fr_strerror_printf_push("Invalid VALUE '%pV' for attribute '%s' at %s[%d]",
331 da->name,
332 fr_cwd_strip(fixup->filename), fixup->line);
333 return -1;
334 }
335
336 ret = fr_dict_enum_add_name(da, fixup->name, &value, false, false);
338 da->flags.has_fixup = false;
339
340 return ret;
341}
342
343/** Resolve a group reference
344 *
345 * This is required as the reference may point to another dictionary which
346 * hasn't been loaded yet.
347 *
348 * @param[in] fctx Holds current dictionary parsing information.
349 * @param[in] da The group dictionary attribute.
350 * @param[in] ref OID string representing what the group references.
351 * @return
352 * - 0 on success.
353 * - -1 on out of memory.
354 */
356{
357 dict_fixup_group_t *fixup;
358
359 fixup = talloc(fctx->pool, dict_fixup_group_t);
360 if (!fixup) {
361 fr_strerror_const("Out of memory");
362 return -1;
363 }
364 *fixup = (dict_fixup_group_t) {
365 .da = da,
366 .ref = talloc_strdup(fixup, ref),
367 };
368
369 da->flags.has_fixup = true;
370
371 return dict_fixup_common(&fctx->group, &fixup->common);
372}
373
374/** Resolve a group reference
375 *
376 * @param[in] fctx Holds current dictionary parsing information.
377 * @param[in] fixup Hash table to fill.
378 * @return
379 * - 0 on success.
380 * - -1 on failure.
381 */
382static inline CC_HINT(always_inline) int dict_fixup_group_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_group_t *fixup)
383{
384 fr_dict_attr_t const *da;
385
386 (void) dict_protocol_reference(&da, fixup->da->parent, fixup->ref);
387 if (!da) {
388 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
389 fr_cwd_strip(fixup->da->filename), fixup->da->line);
390 return -1;
391 }
392
393 if (da->type != FR_TYPE_TLV) {
394 fr_strerror_printf("References MUST be to attributes of type 'tlv' at %s[%d]",
395 fr_cwd_strip(fixup->da->filename), fixup->da->line);
396 return -1;
397 }
398
399 if (fr_dict_attr_ref(da)) {
400 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which also has 'ref=...' at %s[%d]",
401 fr_cwd_strip(fixup->da->filename), fixup->da->line);
402 return -1;
403 }
404
405 fixup->da->flags.has_fixup = false;
406
407 return dict_attr_ref_resolve(fixup->da, da);
408}
409
410/** Clone one area of a tree into another
411 *
412 * These must be processed later to ensure that we've finished building an
413 * attribute by the time it has been cloned.
414 *
415 * @param[in] fctx Holds current dictionary parsing information.
416 * @param[in] da The group dictionary attribute.
417 * @param[in] ref OID string representing what the group references..
418 * @return
419 * - 0 on success.
420 * - -1 on out of memory.
421 */
423{
424 dict_fixup_clone_t *fixup;
425
426 /*
427 * Delay type checks until we've loaded all of the
428 * dictionaries. This means that errors are produced
429 * later, but that shouldn't matter for the default
430 * dictionaries. They're supposed to work.
431 */
432 fixup = talloc(fctx->pool, dict_fixup_clone_t);
433 if (!fixup) {
434 fr_strerror_const("Out of memory");
435 return -1;
436 }
437 *fixup = (dict_fixup_clone_t) {
438 .da = da,
439 .ref = talloc_typed_strdup(fixup, ref)
440 };
441
442 return dict_fixup_common(&fctx->clone, &fixup->common);
443}
444
445/** Clone a dictionary attribute from a ref
446 *
447 * @param[in] dst_p will either be inserted directly, with fields from the clone, or will be
448 * cloned, and then inserted. In this case the original dst da will be freed
449 * and the new cloned attribute will be written back to dst_p.
450 * @param[in] src to clone.
451 * @return
452 * - 0 on success.
453 * - -1 on failure.
454 */
456{
457 fr_dict_attr_t *dst = *dst_p;
458 fr_dict_t *dict = fr_dict_unconst(dst->dict);
459 fr_dict_attr_t *cloned;
460
461 if (src->dict->proto != dst->dict->proto) {
462 fr_strerror_printf("Incompatible protocols. Referenced '%s', referencing '%s'. Defined at %s[%d]",
463 src->dict->proto->name, dst->dict->proto->name, dst->filename, dst->line);
464 return -1;
465 }
466
467 /*
468 * The referenced DA is higher than the one we're
469 * creating. Ensure it's not a parent.
470 */
471 if (src->depth < dst->depth) {
472 fr_dict_attr_t const *parent;
473
474 for (parent = dst->parent; !parent->flags.is_root; parent = parent->parent) {
475 if (parent == src) {
476 fr_strerror_printf("References MUST NOT refer to a parent attribute %s at %s[%d]",
477 parent->name, fr_cwd_strip(dst->filename), dst->line);
478 return -1;
479 }
480 }
481 }
482
483 if (fr_dict_attr_ref(src)) {
484 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which itself has a 'ref=...' at %s[%d]",
485 fr_cwd_strip(dst->filename), dst->line);
486 return -1;
487 }
488
489 /*
490 * If the attributes are of different types, then we have
491 * to _manually_ clone the values. This means looping
492 * over the ref da, and _casting_ the values to the new
493 * data type. If the cast succeeds, we add the value.
494 * Otherwise we don't
495 *
496 * We do this if the source type is a leaf node, AND the
497 * types are different, or the destination has no
498 * children.
499 */
500 if (!fr_type_is_non_leaf(dst->type) &&
501 ((src->type != dst->type) || !dict_attr_children(src))) {
502 int copied;
503
504 /*
505 * Only TLV and STRUCT types can be the source or destination of clones.
506 *
507 * Leaf types can be cloned, even if they're
508 * different types. But only if they don't have
509 * children (i.e. key fields).
510 */
511 if (fr_type_is_non_leaf(src->type) || fr_type_is_non_leaf(dst->type) ||
513 fr_strerror_printf("Reference MUST be to a simple data type of type '%s' at %s[%d]",
514 fr_type_to_str(dst->type),
515 fr_cwd_strip(dst->filename), dst->line);
516 return -1;
517 }
518
519 /*
520 * We copy all of the VALUEs over from the source
521 * da by hand, by casting them.
522 *
523 * We have to do this work manually because we
524 * can't call dict_attr_acopy(), as that function
525 * copies the VALUE with the *source* data type,
526 * where we need the *destination* data type.
527 */
528 copied = dict_attr_acopy_enumv(dst, src);
529 if (copied < 0) return -1;
530
531 if (!copied) {
532 fr_strerror_printf("Reference copied no VALUEs from type type '%s' at %s[%d]",
533 fr_type_to_str(dst->type),
534 fr_cwd_strip(dst->filename), dst->line);
535 return -1;
536 }
537
538 return 0;
539 }
540
541 /*
542 * Can't clone KEY fields directly, you MUST clone the parent struct.
543 */
545 fr_strerror_printf("Invalid reference from '%s' to %s", dst->name, src->name);
546 return -1;
547 }
548
549 /*
550 * Copy the source attribute, but with a
551 * new name and a new attribute number.
552 */
553 cloned = dict_attr_acopy(dict->pool, src, dst->name);
554 if (!cloned) {
555 fr_strerror_printf("Failed copying attribute '%s' to %s", src->name, dst->name);
556 return -1;
557 }
558
559 cloned->attr = dst->attr;
560 cloned->parent = dst->parent; /* we need to re-parent this attribute */
561 cloned->depth = cloned->parent->depth + 1;
562
563 /*
564 * Copy any pre-existing children over.
565 */
566 if (dict_attr_children(dst)) {
567 if (dict_attr_acopy_children(dict, cloned, dst) < 0) {
568 fr_strerror_printf("Failed populating attribute '%s' with children of %s - %s", src->name, dst->name, fr_strerror());
569 return -1;
570 }
571 }
572
573 /*
574 * Copy children of the DA we're cloning.
575 */
576 if (dict_attr_children(src)) {
577 if (dict_attr_acopy_children(dict, cloned, src) < 0) {
578 fr_strerror_printf("Failed populating attribute '%s' with children of %s - %s", src->name, dst->name, fr_strerror());
579 return -1;
580 }
581 }
582
583 if (fr_dict_attr_add_initialised(cloned) < 0) {
584 talloc_free(cloned);
585 return -1;
586 }
587
588 /*
589 * Free the original and pass back our new cloned attribute
590 */
591 talloc_free(dst);
592 *dst_p = cloned;
593
594 return 0;
595}
596
597/** Clone one are of a tree into another
598 *
599 * @param[in] fctx Holds current dictionary parsing information.
600 * @param[in] fixup Containing source/destination of the clone.
601 * @return
602 * - 0 on success.
603 * - -1 on failure.
604 */
605static inline CC_HINT(always_inline) int dict_fixup_clone_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
606{
607 fr_dict_attr_t const *src;
608
609 (void) dict_protocol_reference(&src, fixup->da->parent, fixup->ref);
610 if (!src) {
611 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
612 fr_cwd_strip(fixup->da->filename), fixup->da->line);
613 return -1;
614 }
615
616 fixup->da->flags.has_fixup = false;
617 return dict_fixup_clone(&fixup->da, src);
618}
619
620/** Clone enumeration values from one attribute to another
621 *
622 * These must be processed later to ensure that we've finished building an
623 * attribute by the time it has been cloned.
624 *
625 * @param[in] fctx Holds current dictionary parsing information.
626 * @param[in] da The group dictionary attribute.
627 * @param[in] ref OID string representing what the group references..
628 * @return
629 * - 0 on success.
630 * - -1 on out of memory.
631 */
633{
634 dict_fixup_clone_t *fixup;
635
636 /*
637 * Delay type checks until we've loaded all of the
638 * dictionaries. This means that errors are produced
639 * later, but that shouldn't matter for the default
640 * dictionaries. They're supposed to work.
641 */
642 fixup = talloc(fctx->pool, dict_fixup_clone_t);
643 if (!fixup) {
644 fr_strerror_const("Out of memory");
645 return -1;
646 }
647 *fixup = (dict_fixup_clone_t) {
648 .da = da,
649 .ref = talloc_typed_strdup(fixup, ref)
650 };
651
652 return dict_fixup_common(&fctx->clone, &fixup->common);
653}
654
655/** Clone one are of a tree into another
656 *
657 * @param[in] fctx Holds current dictionary parsing information.
658 * @param[in] fixup Containing source/destination of the clone.
659 * @return
660 * - 0 on success.
661 * - -1 on failure.
662 */
663static inline CC_HINT(always_inline) int dict_fixup_clone_enum_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_clone_t *fixup)
664{
665 fr_dict_attr_t const *src;
666 int copied;
667
668 (void) dict_protocol_reference(&src, fixup->da->parent, fixup->ref);
669 if (!src) {
670 fr_strerror_printf_push("Failed resolving reference for attribute at %s[%d]",
671 fr_cwd_strip(fixup->da->filename), fixup->da->line);
672 return -1;
673 }
674
675 if (src->dict->proto != fixup->da->dict->proto) {
676 fr_strerror_printf("Incompatible protocols. Referenced '%s', referencing '%s'. Defined at %s[%d]",
677 src->dict->proto->name, fixup->da->dict->proto->name, fixup->da->filename, fixup->da->line);
678 return -1;
679 }
680
681 if (fr_dict_attr_ref(src)) {
682 fr_strerror_printf("References MUST NOT refer to an ATTRIBUTE which itself has a 'ref=...' at %s[%d]",
683 fr_cwd_strip(fixup->da->filename), fixup->da->line);
684 return -1;
685 }
686
687 if (!fr_type_is_non_leaf(fixup->da->type)) {
688 fr_strerror_printf("enum copy can only be applied to leaf types, not %s", fr_type_to_str(fixup->da->type));
689 return -1;
690 }
691
692 if (src->type != fixup->da->type) {
693 fr_strerror_printf("enum copy type mismatch. src '%s', dst '%s'",
694 fr_type_to_str(src->type), fr_type_to_str(fixup->da->type));
695 return -1;
696 }
697
698 /*
699 * We copy all of the VALUEs over from the source
700 * da by hand, by casting them.
701 *
702 * We have to do this work manually because we
703 * can't call dict_attr_acopy(), as that function
704 * copies the VALUE with the *source* data type,
705 * where we need the *destination* data type.
706 */
707 copied = dict_attr_acopy_enumv(fixup->da, src);
708 if (copied < 0) return -1;
709
710 if (!copied) {
711 fr_strerror_printf("Reference copied no VALUEs from type type '%s' at %s[%d]",
712 fr_type_to_str(fixup->da->type),
713 fr_cwd_strip(fixup->da->filename), fixup->da->line);
714 return -1;
715 }
716
717 fixup->da->flags.has_fixup = false;
718 return 0;
719}
720
721/** Push a fixup for a VSA.
722 *
723 * This is required so that we can define VENDORs for all VSAs, even
724 * if the dictionary doesn't contain VENDOR children for that VSA.
725 * This fixup means that we can define VENDORs elsewhere, and then
726 * use them in all VSA definitions. It means that we don't have to
727 * do these lookups at run-time.
728 *
729 * @param[in] fctx Holds current dictionary parsing information.
730 * @param[in] da The group dictionary attribute.
731 * @return
732 * - 0 on success.
733 * - -1 on out of memory.
734 */
736{
737 dict_fixup_vsa_t *fixup;
738
739 fixup = talloc(fctx->pool, dict_fixup_vsa_t);
740 if (!fixup) {
741 fr_strerror_const("Out of memory");
742 return -1;
743 }
744 *fixup = (dict_fixup_vsa_t) {
745 .da = da,
746 };
747
748 return dict_fixup_common(&fctx->vsa, &fixup->common);
749}
750
751/** Run VSA fixups
752 *
753 * @param[in] fctx Holds current dictionary parsing information.
754 * @param[in] fixup entry for fixup
755 * @return
756 * - 0 on success.
757 * - -1 on failure.
758 */
759static inline CC_HINT(always_inline) int dict_fixup_vsa_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_vsa_t *fixup)
760{
762 fr_dict_t *dict = fr_dict_unconst(fr_dict_by_da(fixup->da));
763 fr_hash_iter_t iter;
764
765 if (!dict->vendors_by_num) return 0;
766
767 for (dv = fr_hash_table_iter_init(dict->vendors_by_num, &iter);
768 dv;
769 dv = fr_hash_table_iter_next(dict->vendors_by_num, &iter)) {
770 if (dict_attr_child_by_num(fixup->da, dv->pen)) continue;
771
772 if (fr_dict_attr_add(dict, fixup->da, dv->name, dv->pen, FR_TYPE_VENDOR, NULL) < 0) return -1;
773 }
774
775 fixup->da->flags.has_fixup = false;
776 return 0;
777}
778
779
780/** Resolve a group reference
781 *
782 * This is required as the reference may point to another dictionary which
783 * hasn't been loaded yet.
784 *
785 * @param[in] fctx Holds current dictionary parsing information.
786 * @param[in] filename this fixup relates to.
787 * @param[in] line this fixup relates to.
788 * @param[in] alias_parent where to add the alias.
789 * @param[in] alias alias to add.
790 * @param[in] ref_parent attribute that should contain the reference.
791 * @param[in] ref OID string representing what the group references.
792 * @return
793 * - 0 on success.
794 * - -1 on out of memory.
795 */
796int dict_fixup_alias_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line,
797 fr_dict_attr_t *alias_parent, char const *alias,
798 fr_dict_attr_t *ref_parent, char const *ref)
799{
800 dict_fixup_alias_t *fixup;
801
802 fixup = talloc(fctx->pool, dict_fixup_alias_t);
803 if (!fixup) {
804 oom:
805 fr_strerror_const("Out of memory");
806 return -1;
807 }
808 *fixup = (dict_fixup_alias_t) {
809 .alias = talloc_typed_strdup(fixup, alias),
810 .alias_parent = alias_parent,
811 .ref = talloc_typed_strdup(fixup, ref),
812 .ref_parent = ref_parent
813 };
814
815 fixup->filename = talloc_strdup(fixup, filename);
816 if (!fixup->filename) goto oom;
817 fixup->line = line;
818
819 return dict_fixup_common(&fctx->alias, &fixup->common);
820}
821
822static inline CC_HINT(always_inline) int dict_fixup_alias_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_alias_t *fixup)
823{
824 fr_dict_attr_t const *da;
825
826 /*
827 * The <ref> can be a name.
828 */
829 da = fr_dict_attr_by_oid(NULL, fixup->ref_parent, fixup->ref);
830 if (!da) {
831 fr_strerror_printf("Attribute '%s' aliased by '%s' doesn't exist in namespace '%s', at %s[%d]",
832 fixup->ref, fixup->alias, fixup->ref_parent->name, fixup->filename, fixup->line);
833 return -1;
834 }
835
836 fr_dict_attr_unconst(da)->flags.has_fixup = false;
837 return dict_attr_alias_add(fixup->alias_parent, fixup->alias, da);
838}
839
840/** Initialise a fixup ctx
841 *
842 * @param[in] ctx to allocate the fixup pool in.
843 * @param[in] fctx to initialise.
844 * @return
845 * - 0 on success.
846 * - -1 on failure.
847 */
848int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
849{
850 if (fctx->pool) return 0;
851
852 fr_dlist_talloc_init(&fctx->enumv, dict_fixup_enumv_t, common.entry);
853 fr_dlist_talloc_init(&fctx->group, dict_fixup_group_t, common.entry);
854 fr_dlist_talloc_init(&fctx->clone, dict_fixup_clone_t, common.entry);
855 fr_dlist_talloc_init(&fctx->vsa, dict_fixup_vsa_t, common.entry);
856 fr_dlist_talloc_init(&fctx->alias, dict_fixup_alias_t, common.entry);
857
858 fctx->pool = talloc_pool(ctx, DICT_FIXUP_POOL_SIZE);
859 if (!fctx->pool) return -1;
860
861 return 0;
862}
863
864/** Apply all outstanding fixes to a set of dictionaries
865 *
866 */
868{
869
870#define APPLY_FIXUP(_fctx, _list, _func, _type) \
871do { \
872 _type *_fixup; \
873 while ((_fixup = fr_dlist_head(&(_fctx)->_list))) { \
874 if (_func(_fctx, _fixup) < 0) return -1; \
875 fr_dlist_remove(&(_fctx)->_list, _fixup); \
876 talloc_free(_fixup); \
877 } \
878} while (0)
879
880 /*
881 * Apply all the fctx in order
882 *
883
884 * - Enumerations first as they have no dependencies
885 * - Group references next, as group attributes may be cloned.
886 * - Clones last as all other references and additions should
887 * be applied before cloning.
888 * - Clone enum clones the enumeration values from a dedicated
889 * enum, or another attribute with enumerations.
890 * - VSAs
891 * - Aliases last as all attributes need to be defined.
892 */
899
900 TALLOC_FREE(fctx->pool);
901
902 return 0;
903}
904
905/** Fixup all hash tables in the dictionary so they're suitable for threaded access
906 *
907 */
908static int _dict_attr_fixup_hash_tables(fr_dict_attr_t const *da, UNUSED void *uctx)
909{
910 {
912
914 if (ext) {
917 }
918 }
919
920 {
922
925 }
926
927 return 0;
928}
929
930/** Walk a dictionary finalising the hash tables in all attributes with a distinct namespace
931 *
932 * @param[in] dict to finalise namespaces for.
933 */
935{
937
938 (void)_dict_attr_fixup_hash_tables(root, NULL);
939
941
942 /*
943 * Walk over all of the hash tables to ensure they're
944 * initialized. We do this because the threads may perform
945 * lookups, and we don't want multi-threaded re-ordering
946 * of the table entries. That would be bad.
947 */
948 fr_hash_table_fill(dict->vendors_by_name);
949 fr_hash_table_fill(dict->vendors_by_num);
950}
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:317
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:1109
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:1597
ssize_t fr_dict_valid_oid_str(char const *name, ssize_t len)
Definition dict_util.c:4670
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:1948
char const * name
Vendor name.
Definition dict.h:254
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4592
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:2613
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition dict_util.c:4784
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition dict_util.c:4604
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:2331
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:2407
uint32_t pen
Private enterprise number.
Definition dict.h:250
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:173
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:1719
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:2380
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:157
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:478
Private enterprise.
Definition dict.h:249
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:867
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:605
char * value
Raw enum value.
Definition dict_fixup.c:70
int dict_protocol_reference(fr_dict_attr_t const **da_p, fr_dict_attr_t const *rel, char const *ref)
Resolve a reference string to a dictionary attribute.
Definition dict_fixup.c:139
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:272
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:796
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:422
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:663
int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
Initialise a fixup ctx.
Definition dict_fixup.c:848
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:632
static int dict_fixup_vsa_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_vsa_t *fixup)
Run VSA fixups.
Definition dict_fixup.c:759
fr_dict_attr_t * alias_parent
Where to add the alias.
Definition dict_fixup.c:53
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:908
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:735
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:455
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:382
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:355
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:309
#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:934
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:822
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:2422
#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:3288
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:1021
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:1181
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:1152
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_is_char(_sbuff_or_marker, _c)
#define fr_sbuff_eof(_x)
#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:845
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
#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)
Definition value.c:5246
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3742
#define fr_box_strvalue_buffer(_val)
Definition value.h:300
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:499