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