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