The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
dict_util.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Multi-protocol AVP dictionary API
18  *
19  * @file src/lib/util/dict_util.c
20  *
21  * @copyright 2000,2006 The FreeRADIUS server project
22  */
23 RCSID("$Id: be45c6c79b638a31de8dc2b9a2fe27043983bc87 $")
24 
25 #define _DICT_PRIVATE 1
26 
27 #include <freeradius-devel/util/atexit.h>
28 #include <freeradius-devel/util/conf.h>
29 #include <freeradius-devel/util/dict.h>
30 #include <freeradius-devel/util/dict_fixup_priv.h>
31 #include <freeradius-devel/util/proto.h>
32 #include <freeradius-devel/util/rand.h>
33 #include <freeradius-devel/util/sbuff.h>
34 #include <freeradius-devel/util/syserror.h>
35 
36 #ifdef HAVE_SYS_STAT_H
37 # include <sys/stat.h>
38 #endif
39 
40 fr_dict_gctx_t *dict_gctx = NULL; //!< Top level structure containing global dictionary state.
41 
42 /** Characters allowed in dictionary names
43  *
44  */
46  ['-'] = true, ['/'] = true, ['_'] = true,
47  ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
48  ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
49  ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
50  ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true,
51  ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true,
52  ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true,
53  ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true,
54  ['Z'] = true,
55  ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
56  ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
57  ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
58  ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
59  ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
60  ['z'] = true
61 };
62 
63 /** Characters allowed in enumeration value names
64  *
65  */
67  ['+'] = true, ['-'] = true, ['.'] = true, ['/'] = true, ['_'] = true,
68  ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
69  ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
70  ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
71  ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true,
72  ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true,
73  ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true,
74  ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true,
75  ['Z'] = true,
76  ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
77  ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
78  ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
79  ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
80  ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
81  ['z'] = true
82 };
83 
84 /*
85  * Create the hash of the name.
86  *
87  * We copy the hash function here because it's substantially faster.
88  */
89 #define FNV_MAGIC_INIT (0x811c9dc5)
90 #define FNV_MAGIC_PRIME (0x01000193)
91 
92 static void hash_pool_free(void *to_free)
93 {
94  talloc_free(to_free);
95 }
96 
97 /** Apply a simple (case insensitive) hashing function to the name of an attribute, vendor or protocol
98  *
99  * @param[in] name of the attribute, vendor or protocol.
100  * @param[in] len length of the input string.
101  *
102  * @return the hashed derived from the name.
103  */
104 static uint32_t dict_hash_name(char const *name, size_t len)
105 {
107 
108  char const *p = name, *q = name + len;
109 
110  while (p < q) {
111  int c = *(unsigned char const *)p;
112  if (isalpha(c)) c = tolower(c);
113 
115  hash ^= (uint32_t)(c & 0xff);
116  p++;
117  }
118 
119  return hash;
120 }
121 
122 /** Wrap name hash function for fr_dict_protocol_t
123  *
124  * @param[in] data fr_dict_attr_t to hash.
125  * @return the hash derived from the name of the attribute.
126  */
128 {
129  char const *name;
130 
131  name = ((fr_dict_t const *)data)->root->name;
132 
133  return dict_hash_name(name, strlen(name));
134 }
135 
136 /** Compare two protocol names
137  *
138  */
139 static int8_t dict_protocol_name_cmp(void const *one, void const *two)
140 {
141  fr_dict_t const *a = one;
142  fr_dict_t const *b = two;
143  int ret;
144 
145  ret = strcasecmp(a->root->name, b->root->name);
146  return CMP(ret, 0);
147 }
148 
149 /** Hash a protocol number
150  *
151  */
153 {
154  return fr_hash(&(((fr_dict_t const *)data)->root->attr), sizeof(((fr_dict_t const *)data)->root->attr));
155 }
156 
157 /** Compare two protocol numbers
158  *
159  */
160 static int8_t dict_protocol_num_cmp(void const *one, void const *two)
161 {
162  fr_dict_t const *a = one;
163  fr_dict_t const *b = two;
164 
165  return CMP(a->root->attr, b->root->attr);
166 }
167 
168 /** Wrap name hash function for fr_dict_attr_t
169  *
170  * @param data fr_dict_attr_t to hash.
171  * @return the hash derived from the name of the attribute.
172  */
173 static uint32_t dict_attr_name_hash(void const *data)
174 {
175  char const *name;
176 
177  name = ((fr_dict_attr_t const *)data)->name;
178 
179  return dict_hash_name(name, strlen(name));
180 }
181 
182 /** Compare two attribute names
183  *
184  */
185 static int8_t dict_attr_name_cmp(void const *one, void const *two)
186 {
187  fr_dict_attr_t const *a = one, *b = two;
188  int ret;
189 
190  ret = strcasecmp(a->name, b->name);
191  return CMP(ret, 0);
192 }
193 
194 /** Wrap name hash function for fr_dict_vendor_t
195  *
196  * @param data fr_dict_vendor_t to hash.
197  * @return the hash derived from the name of the attribute.
198  */
200 {
201  char const *name;
202 
203  name = ((fr_dict_vendor_t const *)data)->name;
204 
205  return dict_hash_name(name, strlen(name));
206 }
207 
208 /** Compare two attribute names
209  *
210  */
211 static int8_t dict_vendor_name_cmp(void const *one, void const *two)
212 {
213  fr_dict_vendor_t const *a = one;
214  fr_dict_vendor_t const *b = two;
215  int ret;
216 
217  ret = strcasecmp(a->name, b->name);
218  return CMP(ret, 0);
219 }
220 
221 /** Hash a vendor number
222  *
223  */
224 static uint32_t dict_vendor_pen_hash(void const *data)
225 {
226  return fr_hash(&(((fr_dict_vendor_t const *)data)->pen),
227  sizeof(((fr_dict_vendor_t const *)data)->pen));
228 }
229 
230 /** Compare two vendor numbers
231  *
232  */
233 static int8_t dict_vendor_pen_cmp(void const *one, void const *two)
234 {
235  fr_dict_vendor_t const *a = one;
236  fr_dict_vendor_t const *b = two;
237 
238  return CMP(a->pen, b->pen);
239 }
240 
241 /** Hash a enumeration name
242  *
243  */
244 static uint32_t dict_enum_name_hash(void const *data)
245 {
246  fr_dict_enum_value_t const *enumv = data;
247 
248  return dict_hash_name((void const *)enumv->name, enumv->name_len);
249 }
250 
251 /** Compare two dictionary attribute enum values
252  *
253  */
254 static int8_t dict_enum_name_cmp(void const *one, void const *two)
255 {
256  fr_dict_enum_value_t const *a = one;
257  fr_dict_enum_value_t const *b = two;
258  size_t len;
259  int ret;
260 
261  if (a->name_len >= b->name_len) {
262  len = a->name_len;
263  } else {
264  len = b->name_len;
265  }
266 
267  ret = strncasecmp(a->name, b->name, len);
268  return CMP(ret, 0);
269 }
270 
271 /** Hash a dictionary enum value
272  *
273  */
274 static uint32_t dict_enum_value_hash(void const *data)
275 {
276  fr_dict_enum_value_t const *enumv = data;
277 
278  return fr_value_box_hash(enumv->value);
279 }
280 
281 /** Compare two dictionary enum values
282  *
283  */
284 static int8_t dict_enum_value_cmp(void const *one, void const *two)
285 {
286  fr_dict_enum_value_t const *a = one;
287  fr_dict_enum_value_t const *b = two;
288  int ret;
289 
290  ret = fr_value_box_cmp(a->value, b->value); /* not yet int8_t! */
291  return CMP(ret, 0);
292 }
293 
294 /** Resolve an alias attribute to the concrete attribute it points to
295  *
296  * @param[out] err where to write the error (if any).
297  * @param[in] da to resolve.
298  * @return
299  * - NULL on error.
300  * - The concrete attribute on success.
301  */
303 {
304  fr_dict_attr_t const *ref;
305 
306  if (!da->flags.is_alias) return da;
307 
308  ref = fr_dict_attr_ref(da);
309  if (unlikely(!ref)) {
310  fr_strerror_printf("ALIAS attribute '%s' missing reference", da->name);
312  return NULL;
313  } else {
314  if (err) *err = FR_DICT_ATTR_OK;
315  }
316 
317  return ref;
318 }
319 
320 /** Set a dictionary attribute's name
321  *
322  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
323  *
324  * @param[in] da_p to set name for.
325  * @param[in] name to set. If NULL a name will be automatically generated.
326  */
327 static inline CC_HINT(always_inline) int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
328 {
330  size_t name_len;
331  char *name_start, *name_end;
332  fr_dict_attr_t *da = *da_p;
333 
334  /*
335  * Generate a name if none is specified
336  */
337  if (!name) {
338  fr_sbuff_t unknown_name = FR_SBUFF_OUT(buffer, sizeof(buffer));
339 
340 
341  (void) fr_sbuff_in_sprintf(&unknown_name, "%u", da->attr);
342 
343  name = fr_sbuff_buff(&unknown_name);
344  name_len = fr_sbuff_used(&unknown_name);
345  } else {
346  name_len = strlen(name);
347  }
348 
349  /*
350  * Grow the structure to hold the name
351  *
352  * We add the name as an extension because it makes
353  * the code less complex, and means the name value
354  * is copied automatically when if the fr_dict_attr_t
355  * is copied.
356  *
357  * We do still need to fixup the da->name pointer
358  * though.
359  */
360  name_start = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_NAME, name_len + 1);
361  if (!name_start) return -1;
362 
363  name_end = name_start + name_len;
364 
365  memcpy(name_start, name, name_len);
366  *name_end = '\0';
367 
368  (*da_p)->name = name_start;
369  (*da_p)->name_len = name_len;
370 
371  return 0;
372 }
373 
374 /** Add a child/nesting extension to an attribute
375  *
376  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
377  *
378  * @param[in] da_p to set a group reference for.
379  */
380 static inline CC_HINT(always_inline) int dict_attr_children_init(fr_dict_attr_t **da_p)
381 {
383 
385  if (unlikely(!ext)) return -1;
386 
387  return 0;
388 }
389 
390 /** Set a reference for a grouping attribute or an alias attribute
391  *
392  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
393  *
394  * @param[in] da_p to set reference for.
395  * @param[in] ref The attribute referred to by this attribute.
396  */
397 static inline CC_HINT(always_inline) int dict_attr_ref_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *ref)
398 {
400 
402  if (unlikely(!ext)) return -1;
403 
404  ext->ref = ref;
405 
406  return 0;
407 }
408 
409 /** Cache the vendor pointer for an attribute
410  *
411  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
412  *
413  * @param[in] da_p to set a group reference for.
414  * @param[in] vendor to set.
415  */
416 static inline CC_HINT(always_inline) int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
417 {
419 
421  if (unlikely(!ext)) return -1;
422 
423  ext->vendor = vendor;
424 
425  return 0;
426 }
427 
428 /** Initialise an attribute's da stack from its parent
429  *
430  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
431  *
432  * @param[in] da_p to populate the da_stack for.
433  */
434 static inline CC_HINT(always_inline) int dict_attr_da_stack_set(fr_dict_attr_t **da_p)
435 {
436  fr_dict_attr_ext_da_stack_t *ext, *p_ext;
437  fr_dict_attr_t *da = *da_p;
438  fr_dict_attr_t const *parent = da->parent;
439 
440  if (!parent) return 1;
441  if (da->depth > FR_DICT_DA_STACK_CACHE_MAX) return 1;
442  if (fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_DA_STACK)) return 1;
443 
445  if (!p_ext) return 1;
446 
447  ext = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_DA_STACK, sizeof(ext->da_stack[0]) * (da->depth + 1));
448  if (unlikely(!ext)) return -1;
449 
450  memcpy(ext->da_stack, p_ext->da_stack, sizeof(ext->da_stack[0]) * parent->depth);
451 
452  /*
453  * Always set the last stack entry to ourselves.
454  */
455  ext->da_stack[da->depth] = da;
456 
457  return 0;
458 }
459 
460 /** Initialise a per-attribute enumeration table
461  *
462  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
463  *
464  * @param[in] da_p to set a group reference for.
465  */
466 static inline CC_HINT(always_inline) int dict_attr_enumv_init(fr_dict_attr_t **da_p)
467 {
469 
471  if (unlikely(!ext)) return -1;
472 
473  return 0;
474 }
475 
476 /** Initialise a per-attribute namespace
477  *
478  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
479  *
480  * @param[in] da_p to set a group reference for.
481  */
482 static inline CC_HINT(always_inline) int dict_attr_namespace_init(fr_dict_attr_t **da_p)
483 {
485 
487  if (unlikely(!ext)) return -1;
488 
489  /*
490  * Create the table of attributes by name.
491  * There MAY NOT be multiple attributes of the same name.
492  *
493  * If the attribute already has extensions
494  * then we don't want to leak the old
495  * namespace hash table.
496  */
497  if (!ext->namespace) {
498  ext->namespace = fr_hash_table_talloc_alloc(*da_p, fr_dict_attr_t,
500  if (!ext->namespace) {
501  fr_strerror_printf("Failed allocating \"namespace\" table");
502  return -1;
503  }
504  }
505 
506  return 0;
507 }
508 
509 /** Initialise fields in a dictionary attribute structure
510  *
511  * @note This function can only be used _before_ the attribute is inserted into the dictionary.
512  *
513  * @param[in] da_p to initialise.
514  * @param[in] parent of the attribute, if none, should be
515  * the dictionary root.
516  * @param[in] name of attribute. Pass NULL for auto-generated name.
517  * @param[in] attr number.
518  * @param[in] type of the attribute.
519  * @param[in] args optional initialisation arguments.
520  */
522  fr_dict_attr_t const *parent,
523  char const *name, int attr,
525 {
527 
528  if (!args) args = &default_args;
529 
530  **da_p = (fr_dict_attr_t) {
531  .attr = attr,
532  .last_child_attr = (1 << 24),
533  .type = type,
534  .flags = *args->flags,
535  .parent = parent,
536  };
537 
538  /*
539  * Record the parent
540  */
541  if (parent) {
542  (*da_p)->dict = parent->dict;
543  (*da_p)->depth = parent->depth + 1;
544 
545  /*
546  * Point to the vendor definition. Since ~90% of
547  * attributes are VSAs, caching this pointer will help.
548  */
549  if (parent->type == FR_TYPE_VENDOR) {
550  if (dict_attr_vendor_set(da_p, parent) < 0) return -1;
551  } else {
552  dict_attr_ext_copy(da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
553  }
554  } else {
555  (*da_p)->depth = 0;
556  }
557 
558  /*
559  * Cache the da_stack so we don't need
560  * to generate it at runtime.
561  */
563 
564  /*
565  * Structural types can have children
566  * so add the extension for them.
567  */
568  switch (type) {
569  case FR_TYPE_STRUCTURAL:
570  structural:
571  /*
572  * Groups don't have children or namespaces. But
573  * they always have refs. Either to the root of
574  * the current dictionary, or to another dictionary,
575  * via its top-level TLV.
576  *
577  * Note that when multiple TLVs have the same
578  * children, the dictionary has to use "clone="
579  * instead of "ref=". That's because the
580  * children of the TLVs all require the correct
581  * parentage. Perhaps that can be changed when
582  * the encoders / decoders are updated. It would be good to just reference the DAs instead of cloning an entire subtree.
583  */
584  if (type == FR_TYPE_GROUP) {
585  if (dict_attr_ref_init(da_p, NULL) < 0) return -1;
586  break;
587  }
588 
589  if (dict_attr_children_init(da_p) < 0) return -1;
590  if (dict_attr_namespace_init(da_p) < 0) return -1; /* Needed for all TLV style attributes */
591  break;
592 
593  /*
594  * Keying types *sigh*
595  */
596  case FR_TYPE_UINT8: /* Hopefully temporary until unions are done properly */
597  case FR_TYPE_UINT16: /* Same here */
598  if (dict_attr_enumv_init(da_p) < 0) return -1;
599  goto structural;
600 
601  /*
602  * Leaf types
603  */
604  default:
605  if (dict_attr_enumv_init(da_p) < 0) return -1;
606  break;
607  }
608 
609  /*
610  * This attribute is just a reference to another.
611  */
612  if (args->ref) if (dict_attr_ref_init(da_p, args->ref) < 0) return -1;
613 
614  /*
615  * Name is a separate talloc chunk. We allocate
616  * it last because we cache the pointer value.
617  */
618  if (dict_attr_name_set(da_p, name) < 0) return -1;
619 
620  DA_VERIFY(*da_p);
621 
622  return 0;
623 }
624 
626 {
628 
629 #if 0
630 #ifdef WITH_VERIFY_PTR
631  /*
632  * Check that any attribute we reference is still valid
633  * when we're being freed.
634  */
635  fr_dict_attr_t const *ref = fr_dict_attr_ref(da);
636 
637  if (ref) (void)talloc_get_type_abort_const(ref, fr_dict_attr_t);
638 #endif
639 #endif
640 
642  if (ext) talloc_free(ext->value_by_name); /* Ensure this is freed before the enumvs */
643 
644  return 0;
645 }
646 /** Allocate a partially completed attribute
647  *
648  * This is useful in some instances where we need to pre-allocate the attribute
649  * for talloc hierarchy reasons, but want to finish initialising it
650  * with #dict_attr_init later.
651  *
652  * @param[in] ctx to allocate attribute in.
653  * @return
654  * - A new, partially completed, fr_dict_attr_t on success.
655  * - NULL on failure (memory allocation error).
656  */
658 {
659  fr_dict_attr_t *da;
660 
661  /*
662  * Do not use talloc zero, the caller
663  * always initialises memory allocated
664  * here.
665  */
666  da = talloc(ctx, fr_dict_attr_t);
667  if (unlikely(!da)) return NULL;
668 
669  /*
670  * On error paths in the caller, the
671  * caller may free the attribute
672  * allocated here without initialising
673  * the ext array, which is then
674  * accessed in the destructor.
675  */
676  memset(da->ext, 0, sizeof(da->ext));
677 
678  talloc_set_destructor(da, _dict_attr_free);
679 
680  return da;
681 }
682 
683 /** Allocate a dictionary attribute on the heap
684  *
685  * @param[in] ctx to allocate the attribute in.
686  * @param[in] parent of the attribute, if none, should be
687  * the dictionary root.
688  * @param[in] name of the attribute. If NULL an OID string
689  * will be created and set as the name.
690  * @param[in] attr number.
691  * @param[in] type of the attribute.
692  * @param[in] args optional initialisation arguments.
693  * @return
694  * - A new fr_dict_attr_t on success.
695  * - NULL on failure.
696  */
698  fr_dict_attr_t const *parent,
699  char const *name, int attr,
701 {
702  fr_dict_attr_t *n;
703 
704  n = dict_attr_alloc_null(ctx);
705  if (unlikely(!n)) return NULL;
706 
707  if (dict_attr_init(&n, parent, name, attr, type, args) < 0) {
708  talloc_free(n);
709  return NULL;
710  }
711 
712  return n;
713 }
714 
715 /** Copy a an existing attribute
716  *
717  * @param[in] ctx to allocate new attribute in.
718  * @param[in] in attribute to copy.
719  * @param[in] new_name to assign to the attribute.
720  * If NULL the existing name will be used.
721  * @return
722  * - A copy of the input fr_dict_attr_t on success.
723  * - NULL on failure.
724  */
725 fr_dict_attr_t *dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in, char const *new_name)
726 {
727  fr_dict_attr_t *n;
728 
729  n = dict_attr_alloc(ctx, in->parent, new_name ? new_name : in->name,
730  in->attr, in->type, &(dict_attr_args_t){ .flags = &in->flags });
731  if (unlikely(!n)) return NULL;
732 
733  if (dict_attr_ext_copy_all(&n, in) < 0) {
734  talloc_free(n);
735  return NULL;
736  }
737  DA_VERIFY(n);
738 
739  return n;
740 }
741 
742 /** Copy the children of an existing attribute
743  *
744  * @param[in] dict to allocate the children in
745  * @param[in] dst where to copy the children to
746  * @param[in] src where to copy the children from
747  * @return
748  * - 0 on success
749  * - <0 on error
750  */
752 {
753  fr_dict_attr_t const *child = NULL;
754  fr_dict_attr_t *copy;
756 
758  fr_assert(dst->type == src->type);
760 
761  for (child = fr_dict_attr_iterate_children(src, &child);
762  child != NULL;
763  child = fr_dict_attr_iterate_children(src, &child)) {
764  copy = dict_attr_acopy(dict->pool, child, NULL);
765  if (!copy) {
766  fr_strerror_printf("Failed cloning child %s", child->name);
767  return -1;
768  }
769 
770  copy->parent = dst;
771 
772  if (dict_attr_child_add(dst, copy) < 0) return -1;
773 
774  if (dict_attr_add_to_namespace(dst, copy) < 0) return -1;
775 
776  if (!dict_attr_children(child)) continue;
777 
778  if (dict_attr_acopy_children(dict, copy, child) < 0) return -1;
779  }
780 
781  /*
782  * Copy VALUEs, too.
783  */
785  if (ext && ext->name_by_value) {
786  int cloned;
787 
788  cloned = dict_attr_acopy_enumv(dst, src);
789  if (cloned < 0) return -1;
790  }
791 
792  return 0;
793 }
794 
795 /** Copy the VALUEs of an existing attribute, by casting them
796  *
797  * @param[in] dst where to cast the VALUEs to
798  * @param[in] src where to cast the VALUEs from
799  * @return
800  * - 0 on success (but copied no values)
801  * - 1 on success (but copied at least one value)
802  * - <0 on error
803  */
805 {
806  fr_dict_enum_value_t const *enumv;
808  fr_hash_iter_t iter;
809  int copied = 0;
810 
811  fr_assert(!fr_type_is_non_leaf(dst->type));
812  fr_assert(!fr_type_is_non_leaf(src->type));
813 
816 
818  if (!ext) {
819  fr_assert(0);
820  return -1;
821  }
822 
823  if (!ext->name_by_value) {
824  fr_strerror_printf("Reference enum %s does not have any VALUEs to copy", src->name);
825  return -1;
826  }
827 
828  /*
829  * Loop over the VALUEs, adding names from the old
830  * attribute to the new one.
831  *
832  * If a value can't be cast, then just ignore it.
833  */
834  for (enumv = fr_hash_table_iter_init(ext->name_by_value, &iter);
835  enumv;
836  enumv = fr_hash_table_iter_next(ext->name_by_value, &iter)) {
837  if (dict_attr_enum_add_name(dst, enumv->name, enumv->value, true,
838  false, NULL) < 0) {
839  continue;
840  }
841 
842  copied++;
843  }
844 
845  return copied;
846 }
847 
848 /** Add a protocol to the global protocol table
849  *
850  * Inserts a protocol into the global protocol table. Uses the root attributes
851  * of the dictionary for comparisons.
852  *
853  * @param[in] dict of protocol we're inserting.
854  * @return
855  * - 0 on success.
856  * - -1 on failure.
857  */
859 {
860  if (!dict->root) return -1; /* Should always have root */
861 
863  fr_dict_t *old_proto;
864 
866  if (!old_proto) {
867  fr_strerror_printf("%s: Failed inserting protocol name %s", __FUNCTION__, dict->root->name);
868  return -1;
869  }
870 
871  if ((strcmp(old_proto->root->name, dict->root->name) == 0) &&
872  (old_proto->root->name == dict->root->name)) {
873  fr_strerror_printf("%s: Duplicate protocol name %s", __FUNCTION__, dict->root->name);
874  return -1;
875  }
876 
877  return 0;
878  }
879  dict->in_protocol_by_name = true;
880 
882  fr_strerror_printf("%s: Duplicate protocol number %i", __FUNCTION__, dict->root->attr);
883  return -1;
884  }
885  dict->in_protocol_by_num = true;
886 
887  dict_dependent_add(dict, "global");
888 
889  /*
890  * Create and add sub-attributes which allow other
891  * protocols to be encapsulated in the internal
892  * namespace.
893  */
894  if (dict_gctx->internal && (dict != dict_gctx->internal)) {
895  fr_dict_attr_t const *da;
896  fr_dict_attr_flags_t flags = { 0 };
897 
900 
902  if (!da) {
903  if (fr_dict_attr_add(dict_gctx->internal, dict_gctx->attr_protocol_encapsulation, dict->root->name, dict->root->attr, FR_TYPE_GROUP, &flags) < 0) {
904  return -1;
905  }
906 
908  fr_assert(da != NULL);
909  }
910 
911  dict_attr_ref_set(da, dict->root);
912  }
913 
914  return 0;
915 }
916 
917 /** Add a vendor to the dictionary
918  *
919  * Inserts a vendor entry into the vendor hash table. This must be done before adding
920  * attributes under a VSA.
921  *
922  * @param[in] dict of protocol context we're operating in.
923  * If NULL the internal dictionary will be used.
924  * @param[in] name of the vendor.
925  * @param[in] num Vendor's Private Enterprise Number.
926  * @return
927  * - 0 on success.
928  * - -1 on failure.
929  */
930 int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
931 {
932  size_t len;
933  fr_dict_vendor_t *vendor;
934 
935  INTERNAL_IF_NULL(dict, -1);
936 
937  len = strlen(name);
938  if (len >= FR_DICT_VENDOR_MAX_NAME_LEN) {
939  fr_strerror_printf("%s: Vendor name too long", __FUNCTION__);
940  return -1;
941  }
942 
943  vendor = talloc_zero(dict, fr_dict_vendor_t);
944  if (!vendor) {
945  oom:
946  fr_strerror_const("Out of memory");
947  return -1;
948  }
949 
950  vendor->name = talloc_typed_strdup(vendor, name);
951  if (!vendor->name) {
952  talloc_free(vendor);
953  goto oom;
954  }
955  vendor->pen = num;
956  vendor->type = vendor->length = 1; /* defaults */
957 
958  if (!fr_hash_table_insert(dict->vendors_by_name, vendor)) {
959  fr_dict_vendor_t const *old_vendor;
960 
961  old_vendor = fr_hash_table_find(dict->vendors_by_name, vendor);
962  if (!old_vendor) {
963  fr_strerror_printf("%s: Failed inserting vendor name %s", __FUNCTION__, name);
964  return -1;
965  }
966  if ((strcmp(old_vendor->name, vendor->name) == 0) && (old_vendor->pen != vendor->pen)) {
967  fr_strerror_printf("%s: Duplicate vendor name %s", __FUNCTION__, name);
968  return -1;
969  }
970 
971  /*
972  * Already inserted. Discard the duplicate entry.
973  */
974  talloc_free(vendor);
975 
976  return 0;
977  }
978 
979  /*
980  * Insert the SAME pointer (not free'd when this table is
981  * deleted), into another table.
982  *
983  * We want this behaviour because we want OLD names for
984  * the attributes to be read from the configuration
985  * files, but when we're printing them, (and looking up
986  * by value) we want to use the NEW name.
987  */
988  if (fr_hash_table_replace(NULL, dict->vendors_by_num, vendor) < 0) {
989  fr_strerror_printf("%s: Failed inserting vendor %s", __FUNCTION__, name);
990  return -1;
991  }
992 
993  return 0;
994 }
995 
996 /** See if a #fr_dict_attr_t can have children
997  *
998  * The check for children is complicated by the need for "int" types
999  * to have children, when they are `key` fields in a `struct`. This
1000  * situation occurs when a struct has multiple sub-structures, which
1001  * are selected based on a `key` field.
1002  *
1003  * There is no other place for the sub-structures to go. In the
1004  * future, we may extend the functionality of the `key` field, by
1005  * allowing non-integer data types. That would require storing keys
1006  * as #fr_dict_enum_value_t, and then placing the child (i.e. sub)
1007  * structures there. But that would involve adding children to
1008  * enums, which is currently not supported.
1009  *
1010  * @param da the dictionary attribute to check.
1011  */
1013 {
1014  switch (da->type) {
1015  case FR_TYPE_TLV:
1016  case FR_TYPE_VENDOR:
1017  case FR_TYPE_VSA:
1018  case FR_TYPE_STRUCT:
1019  return true;
1020 
1021  case FR_TYPE_UINT8:
1022  case FR_TYPE_UINT16:
1023  case FR_TYPE_UINT32:
1024  /*
1025  * Children are allowed here, but ONLY if this
1026  * attribute is a key field.
1027  */
1028  if (da->parent && (da->parent->type == FR_TYPE_STRUCT) && fr_dict_attr_is_key_field(da)) return true;
1029  break;
1030 
1031  default:
1032  break;
1033  }
1034 
1035  return false;
1036 }
1037 
1038 /** Add a child to a parent.
1039  *
1040  * @param[in] parent we're adding a child to.
1041  * @param[in] child to add to parent.
1042  * @return
1043  * - 0 on success.
1044  * - -1 on failure (memory allocation error).
1045  */
1047 {
1048  fr_dict_attr_t const * const *bin;
1049  fr_dict_attr_t **this;
1050  fr_dict_attr_t const **children;
1051 
1052  /*
1053  * Setup fields in the child
1054  */
1055  fr_assert(child->parent == parent);
1056 
1057  DA_VERIFY(child);
1058 
1059  if (fr_dict_attr_ref(parent)) {
1060  fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
1061  parent->name, fr_dict_attr_ref(parent)->name);
1062  return -1;
1063  }
1064 
1066  fr_strerror_printf("Cannot add children to attribute '%s' of type %s",
1067  parent->name,
1068  fr_type_to_str(parent->type));
1069  return -1;
1070  }
1071 
1072  if ((parent->type == FR_TYPE_VSA) && (child->type != FR_TYPE_VENDOR)) {
1073  fr_strerror_printf("Cannot add non-vendor children to attribute '%s' of type %s",
1074  parent->name,
1075  fr_type_to_str(parent->type));
1076  return -1;
1077  }
1078 
1079  /*
1080  * The parent has children by name only, not by number. Don't even bother trying to track
1081  * numbers, except for VENDOR in root, and MEMBER of a struct.
1082  */
1083  if (!parent->flags.is_root && parent->flags.name_only &&
1084  (parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) {
1085  return 0;
1086  }
1087 
1088  /*
1089  * We only allocate the pointer array *if* the parent has children.
1090  */
1091  children = dict_attr_children(parent);
1092  if (!children) {
1093  children = talloc_zero_array(parent, fr_dict_attr_t const *, UINT8_MAX + 1);
1094  if (!children) {
1095  fr_strerror_const("Out of memory");
1096  return -1;
1097  }
1098  if (dict_attr_children_set(parent, children) < 0) return -1;
1099  }
1100 
1101  /*
1102  * Treat the array as a hash of 255 bins, with attributes
1103  * sorted into bins using num % 255.
1104  *
1105  * Although the various protocols may define numbers higher than 255:
1106  *
1107  * RADIUS/DHCPv4 - 1-255
1108  * Diameter/Internal - 1-4294967295
1109  * DHCPv6 - 1-65535
1110  *
1111  * In reality very few will ever use attribute numbers > 500, so for
1112  * the majority of lookups we get O(1) performance.
1113  *
1114  * Attributes are inserted into the bin in order of their attribute
1115  * numbers to allow slightly more efficient lookups.
1116  */
1117  for (bin = &children[child->attr & 0xff]; *bin; bin = &(*bin)->next) {
1118  /*
1119  * Workaround for vendors that overload the RFC space.
1120  * Structural attributes always take priority.
1121  */
1122  bool child_is_struct = fr_type_is_structural(child->type);
1123  bool bin_is_struct = fr_type_is_structural((*bin)->type);
1124 
1125  if (child_is_struct && !bin_is_struct) break;
1126  if (fr_dict_vendor_num_by_da(child) <= fr_dict_vendor_num_by_da(*bin)) break; /* Prioritise RFC attributes */
1127  if (child->attr <= (*bin)->attr) break;
1128  }
1129 
1130  memcpy(&this, &bin, sizeof(this));
1131  child->next = *this;
1132  *this = child;
1133 
1134  return 0;
1135 }
1136 
1137 /** Add an attribute to the name table for an attribute
1138  *
1139  * @param[in] parent containing the namespace to add this attribute to.
1140  * @param[in] da to add to the name lookup tables.
1141  * @return
1142  * - 0 on success.
1143  * - -1 on failure.
1144  */
1146 {
1147  fr_hash_table_t *namespace;
1148 
1149  namespace = dict_attr_namespace(parent);
1150  if (unlikely(!namespace)) {
1151  fr_strerror_printf("Parent \"%s\" has no namespace", parent->name);
1152  error:
1153  return -1;
1154  }
1155 
1156  /*
1157  * Sanity check to stop children of vendors ending
1158  * up in the Vendor-Specific or root namespace.
1159  */
1160  if ((fr_dict_vendor_num_by_da(da) != 0) && (da->type != FR_TYPE_VENDOR) &&
1161  ((parent->type == FR_TYPE_VSA) || parent->flags.is_root)) {
1162  fr_strerror_printf("Cannot insert attribute '%s' of type %s into %s",
1163  da->name,
1164  fr_type_to_str(da->type),
1165  parent->name);
1166  goto error;
1167  }
1168 
1169  /*
1170  * Insert the attribute, only if it's not a duplicate.
1171  */
1172  if (!fr_hash_table_insert(namespace, da)) {
1173  fr_dict_attr_t *a;
1174 
1175  /*
1176  * Find the old name. If it's the same name and
1177  * but the parent, or number, or type are
1178  * different, that's an error.
1179  */
1180  a = fr_hash_table_find(namespace, da);
1181  if (a && (strcasecmp(a->name, da->name) == 0)) {
1182  if ((a->attr != da->attr) || (a->type != da->type) || (a->parent != da->parent)) {
1183  fr_strerror_printf("Duplicate attribute name \"%s\"", da->name);
1184  goto error;
1185  }
1186  }
1187 
1188  /*
1189  * Otherwise the attribute has been redefined later
1190  * in the dictionary.
1191  *
1192  * The original fr_dict_attr_t remains in the
1193  * dictionary but entry in the name hash table is
1194  * updated to point to the new definition.
1195  */
1196  if (fr_hash_table_replace(NULL, namespace, da) < 0) {
1197  fr_strerror_const("Internal error storing attribute");
1198  goto error;
1199  }
1200  }
1201 
1202  return 0;
1203 }
1204 
1206 {
1207  if (old->parent != parent) {
1208  fr_strerror_printf_push("Cannot add duplicate attribute \"%s\" with different parent (old %s, new %s)",
1209  n->name, old->parent->name, parent->name);
1210  return -1;
1211  }
1212 
1213  if (old->attr != n->attr) {
1214  fr_strerror_printf_push("Cannot add duplicate attribute name \"%s\" with different number (old %u, new %d)",
1215  n->name, old->attr, n->attr);
1216  return -1;
1217  }
1218 
1219  if (old->type != n->type) {
1220  fr_strerror_printf_push("Cannot add duplicate attribute with different type "
1221  "(old attribute \"%s\" has type %s, new attribute \"%s\" has type %s)",
1222  old->name,
1223  fr_type_to_str(old->type),
1224  n->name,
1225  fr_type_to_str(n->type));
1226  return -1;
1227  }
1228 
1229  return 0;
1230 }
1231 
1232 /** Add an attribute to the dictionary
1233  *
1234  * @param[in] dict of protocol context we're operating in.
1235  * If NULL the internal dictionary will be used.
1236  * @param[in] parent to add attribute under.
1237  * @param[in] name of the attribute.
1238  * @param[in] attr number.
1239  * @param[in] type of attribute.
1240  * @param[in] flags to set in the attribute.
1241  * @return
1242  * - 0 on success.
1243  * - -1 on failure.
1244  */
1246  char const *name, int attr, fr_type_t type, fr_dict_attr_flags_t const *flags)
1247 {
1248  fr_dict_attr_t *n;
1249  fr_dict_attr_t const *old;
1250  fr_dict_attr_flags_t our_flags = *flags;
1251  bool self_allocated = false;
1252 #ifndef NDEBUG
1253  fr_dict_attr_t const *da;
1254 #endif
1255 
1256  if (unlikely(dict->read_only)) {
1257  fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
1258  return -1;
1259  }
1260 
1261  self_allocated = (attr < 0);
1262 
1263  /*
1264  * Check that the definition is valid.
1265  */
1266  if (!dict_attr_fields_valid(dict, parent, name, &attr, type, &our_flags)) return -1;
1267 
1268  n = dict_attr_alloc(dict->pool, parent, name, attr, type, &(dict_attr_args_t){ .flags = &our_flags});
1269  if (!n) return -1;
1270 
1271 #define FLAGS_EQUAL(_x) (old->flags._x == flags->_x)
1272 
1273  old = fr_dict_attr_by_name(NULL, parent, name);
1274  if (old) {
1275  /*
1276  * Don't bother inserting exact duplicates.
1277  */
1278  if ((old->parent == parent) && (old->type == type) &&
1279  FLAGS_EQUAL(array) && FLAGS_EQUAL(subtype) &&
1280  ((old->attr == (unsigned int) attr) || self_allocated)) {
1281  return 0;
1282  }
1283 
1284  /*
1285  * We have the same name, but different
1286  * properties. That's an error.
1287  */
1288  if (dict_attr_compatible(parent, old, n) < 0) goto error;
1289 
1290  /*
1291  * We have the same name, and same (enough)
1292  * properties. Discard the duplicate.
1293  */
1294  talloc_free(n);
1295  return 0;
1296  }
1297 
1298  /*
1299  * Attributes can also be indexed by number. Ensure that
1300  * all attributes of the same number have the same
1301  * properties.
1302  */
1303  old = fr_dict_attr_child_by_num(parent, n->attr);
1304  if (old && (dict_attr_compatible(parent, old, n) < 0)) goto error;
1305 
1306  if (dict_attr_add_to_namespace(parent, n) < 0) {
1307  error:
1308  talloc_free(n);
1309  return -1;
1310  }
1311 
1312  /*
1313  * Add in by number
1314  */
1315  if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, parent), n) < 0) goto error;
1316 
1317 #ifndef NDEBUG
1318  /*
1319  * Check if we added the attribute
1320  */
1321  da = dict_attr_child_by_num(parent, n->attr);
1322  if (!da) {
1323  fr_strerror_printf("FATAL - Failed to find attribute number %u we just added to parent %s.", n->attr, parent->name);
1324  return -1;
1325  }
1326 
1327  if (!dict_attr_by_name(NULL, parent, n->name)) {
1328  fr_strerror_printf("FATAL - Failed to find attribute '%s' we just added to parent %s.", n->name, parent->name);
1329  return -1;
1330  }
1331 #endif
1332 
1333  /*
1334  * If it's a group attribute, the default
1335  * reference goes to the root of the
1336  * dictionary as that's where the default
1337  * name/numberspace is.
1338  *
1339  * This may be updated by the caller.
1340  */
1342 
1343  return 0;
1344 }
1345 
1347  fr_value_box_t const *value,
1348  bool coerce, bool takes_precedence,
1349  fr_dict_attr_t const *child_struct)
1350 {
1351  size_t len;
1352  fr_dict_enum_value_t *enumv = NULL;
1353  fr_value_box_t *enum_value = NULL;
1355 
1356  if (!da) {
1357  fr_strerror_printf("%s: Dictionary attribute not specified", __FUNCTION__);
1358  return -1;
1359  }
1360 
1361  if (!*name) {
1362  fr_strerror_printf("%s: Empty names are not permitted", __FUNCTION__);
1363  return -1;
1364  }
1365 
1366  len = strlen(name);
1367  if (len >= FR_DICT_ENUM_MAX_NAME_LEN) {
1368  fr_strerror_printf("VALUE name is too long");
1369  return -1;
1370  }
1371 
1372  /*
1373  * If the parent isn't a key field, then we CANNOT add a child struct.
1374  */
1375  if (!fr_dict_attr_is_key_field(da) && child_struct) {
1376  fr_strerror_const("Child structures cannot be defined for VALUEs which are not for 'key' attributes");
1377  return -1;
1378  }
1379 
1380  if (fr_type_is_structural(da->type) || (da->type == FR_TYPE_STRING)) {
1381  fr_strerror_printf("Enumeration names cannot be added for data type '%s'", fr_type_to_str(da->type));
1382  return -1;
1383  }
1384 
1385  if (da->flags.is_alias) {
1386  fr_strerror_printf("Enumeration names cannot be added for ALIAS '%s'", da->name);
1387  return -1;
1388  }
1389 
1391  if (!ext) {
1392  fr_strerror_printf("VALUE cannot be defined for %s", da->name);
1393  return -1;
1394  }
1395 
1396  /*
1397  * Initialise enumv hash tables
1398  */
1399  if (!ext->value_by_name || !ext->name_by_value) {
1402  if (!ext->value_by_name) {
1403  fr_strerror_printf("Failed allocating \"value_by_name\" table");
1404  return -1;
1405  }
1406 
1408  dict_enum_value_cmp, NULL);
1409  if (!ext->name_by_value) {
1410  fr_strerror_printf("Failed allocating \"name_by_value\" table");
1411  return -1;
1412  }
1413  }
1414 
1415  /*
1416  * Allocate a structure to map between
1417  * the name and value.
1418  */
1419  enumv = talloc_zero_size(da, sizeof(fr_dict_enum_value_t) + sizeof(enumv->child_struct[0]) * fr_dict_attr_is_key_field(da));
1420  if (!enumv) {
1421  oom:
1422  fr_strerror_printf("%s: Out of memory", __FUNCTION__);
1423  return -1;
1424  }
1425  talloc_set_type(enumv, fr_dict_enum_value_t);
1426 
1427  enumv->name = talloc_typed_strdup(enumv, name);
1428  enumv->name_len = len;
1429 
1430  if (child_struct) enumv->child_struct[0] = child_struct;
1431  enum_value = fr_value_box_alloc(enumv, da->type, NULL);
1432  if (!enum_value) goto oom;
1433 
1434  if (da->type != value->type) {
1435  if (!coerce) {
1436  fr_strerror_printf("Type mismatch between attribute (%s) and enum (%s)",
1437  fr_type_to_str(da->type),
1438  fr_type_to_str(value->type));
1439  return -1;
1440  }
1441 
1442  if (fr_value_box_cast(enumv, enum_value, da->type, NULL, value) < 0) {
1443  fr_strerror_printf_push("Failed coercing enum type (%s) to attribute type (%s)",
1444  fr_type_to_str(value->type),
1445  fr_type_to_str(da->type));
1446 
1447  return -1;
1448  }
1449  } else {
1450  if (fr_value_box_copy(enum_value, enum_value, value) < 0) {
1451  fr_strerror_printf_push("%s: Failed copying value into enum", __FUNCTION__);
1452  return -1;
1453  }
1454  }
1455 
1456  enumv->value = enum_value;
1457 
1458  /*
1459  * Add the value into the dictionary.
1460  */
1461  {
1462  fr_dict_attr_t *tmp;
1463  memcpy(&tmp, &enumv, sizeof(tmp));
1464 
1465  if (!fr_hash_table_insert(ext->value_by_name, tmp)) {
1466  fr_dict_enum_value_t *old;
1467 
1468  /*
1469  * Suppress duplicates with the same
1470  * name and value. There are lots in
1471  * dictionary.ascend.
1472  */
1473  old = fr_dict_enum_by_name(da, name, -1);
1474  if (!fr_cond_assert(old)) return -1;
1475 
1476  if (fr_value_box_cmp(old->value, enumv->value) == 0) {
1477  talloc_free(enumv);
1478  return 0;
1479  }
1480 
1481  fr_strerror_printf("Duplicate VALUE name \"%s\" for Attribute '%s'. "
1482  "Old value was \"%pV\", new value was \"%pV\"", name, da->name,
1483  old->value, enumv->value);
1484  talloc_free(enumv);
1485  return -1;
1486  }
1487 
1488  if (enumv->name_len > ext->max_name_len) ext->max_name_len = enumv->name_len;
1489  }
1490 
1491  /*
1492  * There are multiple VALUE's, keyed by attribute, so we
1493  * take care of that here.
1494  */
1495  if (takes_precedence) {
1496  if (fr_hash_table_replace(NULL, ext->name_by_value, enumv) < 0) {
1497  fr_strerror_printf("%s: Failed inserting value %s", __FUNCTION__, name);
1498  return -1;
1499  }
1500  } else {
1501  (void) fr_hash_table_insert(ext->name_by_value, enumv);
1502  }
1503 
1504  /*
1505  * Mark the attribute up as having an enumv
1506  */
1507  UNCONST(fr_dict_attr_t *, da)->flags.has_value = 1;
1508 
1509  return 0;
1510 }
1511 
1512 /** Add a value name
1513  *
1514  * Aliases are textual (string) names for a given value.
1515  *
1516  * Value names are not limited to integers, and may be added for any non-structural
1517  * attribute type.
1518  *
1519  * @param[in] da to add enumeration value to.
1520  * @param[in] name Name of value name.
1521  * @param[in] value to associate with name.
1522  * @param[in] coerce if the type of the value does not match the
1523  * type of the da, attempt to cast it to match
1524  * the type of the da. If this is false and there's
1525  * a type mismatch, we fail.
1526  * We also fail if the value cannot be coerced to
1527  * the attribute type.
1528  * @param[in] takes_precedence This name should take precedence over previous
1529  * names for the same value, when resolving value
1530  * to name.
1531  * @return
1532  * - 0 on success.
1533  * - -1 on failure.
1534  */
1536  fr_value_box_t const *value,
1537  bool coerce, bool takes_precedence)
1538 {
1539  return dict_attr_enum_add_name(da, name, value, coerce, takes_precedence, NULL);
1540 }
1541 
1542 /** Add an name to an integer attribute hashing the name for the integer value
1543  *
1544  * If the integer value conflicts with an existing name, it's incremented
1545  * until we find a free value.
1546  */
1548 {
1549  fr_value_box_t v = {
1550  .type = da->type
1551  };
1552  fr_value_box_t s = {
1553  .type = da->type
1554  };
1555 
1556  if (fr_dict_enum_by_name(da, name, -1)) return 0;
1557 
1558  switch (da->type) {
1559  case FR_TYPE_INT8:
1560  v.vb_int8 = s.vb_int8 = fr_hash_string(name) & INT8_MAX;
1561  break;
1562 
1563  case FR_TYPE_INT16:
1564  v.vb_int16 = s.vb_int16 = fr_hash_string(name) & INT16_MAX;
1565  break;
1566 
1567  case FR_TYPE_INT32:
1568  v.vb_int32 = s.vb_int32 = fr_hash_string(name) & INT32_MAX;
1569  break;
1570 
1571  case FR_TYPE_INT64:
1572  v.vb_int64 = s.vb_int64 = fr_hash_string(name) & INT64_MAX;
1573  break;
1574 
1575  case FR_TYPE_UINT8:
1576  v.vb_uint8 = s.vb_uint8 = fr_hash_string(name) & UINT8_MAX;
1577  break;
1578 
1579  case FR_TYPE_UINT16:
1580  v.vb_uint16 = s.vb_uint16 = fr_hash_string(name) & UINT16_MAX;
1581  break;
1582 
1583  case FR_TYPE_UINT32:
1584  v.vb_uint32 = s.vb_uint32 = fr_hash_string(name) & UINT32_MAX;
1585  break;
1586 
1587  case FR_TYPE_UINT64:
1588  v.vb_uint64 = s.vb_uint64 = fr_hash_string(name) & UINT64_MAX;
1589  break;
1590 
1591  default:
1592  fr_strerror_printf("Attribute is wrong type for auto-numbering, expected numeric type, got %s",
1593  fr_type_to_str(da->type));
1594  return -1;
1595  }
1596 
1597  /*
1598  * If there's no existing value, add an enum
1599  * with the hash value of the name.
1600  *
1601  * This helps with debugging as the values
1602  * are consistent.
1603  */
1604  if (!fr_dict_enum_by_value(da, &v)) {
1605  add:
1606  return fr_dict_enum_add_name(da, name, &v, false, false);
1607  }
1608 
1609  for (;;) {
1611 
1612  if (fr_value_box_cmp_op(T_OP_CMP_EQ, &v, &s) == 0) {
1613  fr_strerror_const("No free integer values for enumeration");
1614  return -1;
1615  }
1616 
1617  if (!fr_dict_enum_by_value(da, &v)) goto add;
1618  }
1619  /* NEVER REACHED */
1620 }
1621 
1622 /** Find a common ancestor that two TLV type attributes share
1623  *
1624  * @param[in] a first TLV attribute.
1625  * @param[in] b second TLV attribute.
1626  * @param[in] is_ancestor Enforce a->b relationship (a is parent or ancestor of b).
1627  * @return
1628  * - Common ancestor if one exists.
1629  * - NULL if no common ancestor exists.
1630  */
1631 fr_dict_attr_t const *fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
1632 {
1633  unsigned int i;
1634  fr_dict_attr_t const *p_a, *p_b;
1635 
1636  if (!a || !b) return NULL;
1637 
1638  if (is_ancestor && (b->depth <= a->depth)) return NULL; /* fast_path */
1639 
1640  /*
1641  * Find a common depth to work back from
1642  */
1643  if (a->depth > b->depth) {
1644  p_b = b;
1645  for (p_a = a, i = a->depth - b->depth; p_a && (i > 0); p_a = p_a->parent, i--);
1646  if (is_ancestor && (p_a != p_b)) return NULL;
1647  } else if (a->depth < b->depth) {
1648  p_a = a;
1649  for (p_b = b, i = b->depth - a->depth; p_b && (i > 0); p_b = p_b->parent, i--);
1650  if (is_ancestor && (p_a != p_b)) return NULL;
1651  } else {
1652  p_a = a;
1653  p_b = b;
1654  }
1655 
1656  while (p_a && p_b) {
1657  if (p_a == p_b) return p_a;
1658 
1659  p_a = p_a->parent;
1660  p_b = p_b->parent;
1661  }
1662 
1663  return NULL;
1664 }
1665 
1666 /** Process a single OID component
1667  *
1668  * @param[out] out Value of component.
1669  * @param[in] oid string to parse.
1670  * @return
1671  * - 0 on success.
1672  * - -1 on format error.
1673  */
1674 int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
1675 {
1676  char const *p = *oid;
1677  char *q;
1678  unsigned long num;
1679 
1680  *out = 0;
1681 
1682  num = strtoul(p, &q, 10);
1683  if ((p == q) || (num == ULONG_MAX)) {
1684  fr_strerror_printf("Invalid OID component \"%s\" (%lu)", p, num);
1685  return -1;
1686  }
1687 
1688  switch (*q) {
1689  case '\0':
1690  case '.':
1691  *oid = q;
1692  *out = (unsigned int)num;
1693 
1694  return 0;
1695 
1696  default:
1697  fr_strerror_const("Unexpected text after OID component");
1698  *out = 0;
1699  return -1;
1700  }
1701 }
1702 
1703 /** Get the leaf attribute of an OID string
1704  *
1705  * @note On error, vendor will be set (if present), parent will be the
1706  * maximum depth we managed to resolve to, and attr will be the child
1707  * we failed to resolve.
1708  *
1709  * @param[in] dict of protocol context we're operating in.
1710  * If NULL the internal dictionary will be used.
1711  * @param[out] attr Number we parsed.
1712  * @param[in,out] parent attribute (or root of dictionary).
1713  * Will be updated to the parent directly beneath the leaf.
1714  * @param[in] oid string to parse.
1715  * @return
1716  * - > 0 on success (number of bytes parsed).
1717  * - <= 0 on parse error (negative offset of parse error).
1718  */
1719 ssize_t fr_dict_attr_by_oid_legacy(fr_dict_t const *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
1720 {
1721  char const *p = oid;
1722  unsigned int num = 0;
1723  ssize_t slen;
1724 
1725  if (!*parent) return -1;
1726 
1727  /*
1728  * It's a partial OID. Grab it, and skip to the next bit.
1729  */
1730  if (p[0] == '.') {
1731  p++;
1732  }
1733 
1734  *attr = 0;
1735 
1736  if (fr_dict_oid_component_legacy(&num, &p) < 0) return oid - p;
1737 
1738  /*
1739  * Record progress even if we error out.
1740  *
1741  * Don't change this, you will break things.
1742  */
1743  *attr = num;
1744 
1745  switch ((*parent)->type) {
1746  case FR_TYPE_STRUCTURAL:
1747  break;
1748 
1749  default:
1750  if (dict_attr_can_have_children(*parent)) break;
1751  fr_strerror_printf("Attribute %s (%i) is not a TLV, so cannot contain a child attribute. "
1752  "Error at sub OID \"%s\"", (*parent)->name, (*parent)->attr, oid);
1753  return 0; /* We parsed nothing */
1754  }
1755 
1756  /*
1757  * If it's not a vendor type, it must be between 0..8*type_size
1758  *
1759  * @fixme: find the TLV parent, and check it's size
1760  */
1761  if (((*parent)->type != FR_TYPE_VENDOR) && ((*parent)->type != FR_TYPE_VSA) && !(*parent)->flags.is_root &&
1762  (num > UINT8_MAX)) {
1763  fr_strerror_const("TLV attributes must be between 0..255 inclusive");
1764  return 0;
1765  }
1766 
1767  switch (p[0]) {
1768  /*
1769  * We've not hit the leaf yet, so the attribute must be
1770  * defined already.
1771  */
1772  case '.':
1773  {
1774  fr_dict_attr_t const *child;
1775  p++;
1776 
1777  child = dict_attr_child_by_num(*parent, num);
1778  if (!child) {
1779  fr_strerror_printf("Unknown attribute '%i' in OID string \"%s\" for parent %s",
1780  num, oid, (*parent)->name);
1781  return 0; /* We parsed nothing */
1782  }
1783 
1784  /*
1785  * Record progress even if we error out.
1786  *
1787  * Don't change this, you will break things.
1788  */
1789  *parent = child;
1790 
1791  slen = fr_dict_attr_by_oid_legacy(dict, parent, attr, p);
1792  if (slen <= 0) return slen - (p - oid);
1793  return slen + (p - oid);
1794  }
1795 
1796  /*
1797  * Hit the leaf, this is the attribute we need to define.
1798  */
1799  case '\0':
1800  *attr = num;
1801  return p - oid;
1802 
1803  default:
1804  fr_strerror_printf("Malformed OID string, got trailing garbage '%s'", p);
1805  return oid - p;
1806  }
1807 }
1808 
1809 /** Parse an OID component, resolving it to a defined attribute
1810  *
1811  * @note Will leave the sbuff pointing at the component the error occurred at
1812  * so that the caller can attempt to process the component in another way.
1813  *
1814  * @param[out] err The parsing error that occurred.
1815  * @param[out] out The deepest attribute we resolved.
1816  * @param[in] parent Where to resolve relative attributes from.
1817  * @param[in] in string to parse.
1818  * @param[in] tt Terminal strings.
1819  * @return
1820  * - >0 the number of bytes consumed.
1821  * - <0 Parse error occurred here.
1822  */
1824  fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
1825  fr_sbuff_t *in, fr_sbuff_term_t const *tt)
1826 {
1827  fr_sbuff_t our_in = FR_SBUFF(in);
1828  uint32_t num = 0;
1829  fr_sbuff_parse_error_t sberr;
1830  fr_dict_attr_t const *child;
1831 
1832  if (err) *err = FR_DICT_ATTR_OK;
1833 
1834  *out = NULL;
1835 
1836  switch (parent->type) {
1837  case FR_TYPE_STRUCTURAL:
1838  break;
1839 
1840  default:
1841  if (dict_attr_can_have_children(parent)) break;
1842  fr_strerror_printf("Attribute '%s' is type %s and cannot contain child attributes. "
1843  "Error at OID \"%.*s\"",
1844  parent->name,
1845  fr_type_to_str(parent->type),
1846  (int)fr_sbuff_remaining(&our_in),
1847  fr_sbuff_current(&our_in));
1849  FR_SBUFF_ERROR_RETURN(&our_in);
1850  }
1851 
1852  fr_sbuff_out(&sberr, &num, &our_in);
1853  switch (sberr) {
1854  /*
1855  * Lookup by number
1856  */
1857  case FR_SBUFF_PARSE_OK:
1858  if (!fr_sbuff_is_char(&our_in, '.') && !fr_sbuff_is_terminal(&our_in, tt)) {
1859  fr_sbuff_set_to_start(&our_in);
1860  goto oid_str;
1861  }
1862 
1863  child = dict_attr_child_by_num(parent, num);
1864  if (!child) {
1865  fr_strerror_printf("Failed resolving child %u in context %s",
1866  num, parent->name);
1867  if (err) *err = FR_DICT_ATTR_NOTFOUND;
1868  FR_SBUFF_ERROR_RETURN(&our_in);
1869  }
1870  break;
1871 
1872  /*
1873  * Lookup by name
1874  */
1877  {
1878  fr_dict_attr_err_t our_err;
1879  oid_str:
1880  if (fr_dict_attr_by_name_substr(&our_err, &child, parent, &our_in, tt) < 0) {
1881  fr_strerror_printf("Failed resolving \"%.*s\" in context %s",
1882  (int)fr_sbuff_remaining(&our_in),
1883  fr_sbuff_current(&our_in),
1884  parent->name);
1885  if (err) *err = our_err;
1886  FR_SBUFF_ERROR_RETURN(&our_in);
1887  }
1888  }
1889  break;
1890 
1891  default:
1892  fr_strerror_printf("Invalid OID component (%s) \"%.*s\"",
1893  fr_table_str_by_value(sbuff_parse_error_table, sberr, "<INVALID>"),
1894  (int)fr_sbuff_remaining(&our_in), fr_sbuff_current(&our_in));
1896  FR_SBUFF_ERROR_RETURN(&our_in);
1897  }
1898 
1899  child = dict_attr_alias(err, child);
1900  if (unlikely(!child)) FR_SBUFF_ERROR_RETURN(&our_in);
1901 
1902  *out = child;
1903 
1904  FR_SBUFF_SET_RETURN(in, &our_in);
1905 }
1906 
1907 /** Resolve an attribute using an OID string
1908  *
1909  * @note Will leave the sbuff pointing at the component the error occurred at
1910  * so that the caller can attempt to process the component in another way.
1911  * An err pointer should be provided in order to determine if an error
1912  * occurred.
1913  *
1914  * @param[out] err The parsing error that occurred.
1915  * @param[out] out The deepest attribute we resolved.
1916  * @param[in] parent Where to resolve relative attributes from.
1917  * @param[in] in string to parse.
1918  * @param[in] tt Terminal strings.
1919  * @return The number of bytes of name consumed.
1920  */
1922  fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
1923  fr_sbuff_t *in, fr_sbuff_term_t const *tt)
1924 {
1925  fr_sbuff_t our_in = FR_SBUFF(in);
1926  fr_sbuff_marker_t m_c;
1927  fr_dict_attr_t const *our_parent = parent;
1928 
1929  fr_sbuff_marker(&m_c, &our_in);
1930 
1931  /*
1932  * If the OID doesn't begin with '.' we
1933  * resolve it from the root.
1934  */
1935 #if 0
1936  if (!fr_sbuff_next_if_char(&our_in, '.')) our_parent = fr_dict_root(fr_dict_by_da(parent));
1937 #else
1938  (void) fr_sbuff_next_if_char(&our_in, '.');
1939 #endif
1940  *out = NULL;
1941 
1942  for (;;) {
1943  fr_dict_attr_t const *child;
1944 
1945  if ((fr_dict_oid_component(err, &child, our_parent, &our_in, tt) < 0) || !child) {
1946  *out = our_parent;
1947  fr_sbuff_set(&our_in, &m_c); /* Reset to the start of the last component */
1948  break; /* Resolved as much as we can */
1949  }
1950 
1951  our_parent = child;
1952  *out = child;
1953 
1954  fr_sbuff_set(&m_c, &our_in);
1955  if (!fr_sbuff_next_if_char(&our_in, '.')) break;
1956  }
1957 
1958  FR_SBUFF_SET_RETURN(in, &our_in);
1959 }
1960 
1961 /** Resolve an attribute using an OID string
1962  *
1963  * @param[out] err The parsing error that occurred.
1964  * @param[in] parent Where to resolve relative attributes from.
1965  * @param[in] oid string to parse.
1966  * @return
1967  * - NULL if we couldn't resolve the attribute.
1968  * - The resolved attribute.
1969  */
1971 {
1972  fr_sbuff_t sbuff = FR_SBUFF_IN(oid, strlen(oid));
1973  fr_dict_attr_t const *da;
1974 
1975  if (fr_dict_attr_by_oid_substr(err, &da, parent, &sbuff, NULL) <= 0) return NULL;
1976  if (err && *err != FR_DICT_ATTR_OK) return NULL;
1977 
1978  /*
1979  * If we didn't parse the entire string, then the parsing stopped at an unknown child.
1980  * e.g. Vendor-Specific.Cisco.Foo. In that case, the full attribute wasn't found.
1981  */
1982  if (fr_sbuff_remaining(&sbuff) > 0) {
1983  if (err) *err = FR_DICT_ATTR_NOTFOUND;
1984  return NULL;
1985  }
1986 
1987  return da;
1988 }
1989 
1990 /** Return the root attribute of a dictionary
1991  *
1992  * @param dict to return root for.
1993  * @return the root attribute of the dictionary.
1994  *
1995  * @hidecallergraph
1996  */
1998 {
1999  return dict->root;
2000 }
2001 
2003 {
2004  return dict->read_only;
2005 }
2006 
2008 {
2009  return dict->dl;
2010 }
2011 
2013  fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
2014 {
2015  fr_dict_attr_t root;
2016 
2017  fr_sbuff_t our_name;
2018  fr_dict_t *dict;
2019  fr_slen_t slen;
2020  char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
2021 
2022  if (!dict_gctx || !name || !out) {
2023  if (err) *err = FR_DICT_ATTR_EINVAL;
2025  return 0;
2026  }
2027 
2028  our_name = FR_SBUFF(name);
2029  memset(&root, 0, sizeof(root));
2030 
2031  /*
2032  * Advance p until we get something that's not part of
2033  * the dictionary attribute name.
2034  */
2036  &our_name, SIZE_MAX,
2038  if (slen == 0) {
2039  fr_strerror_const("Zero length attribute name");
2041  FR_SBUFF_ERROR_RETURN(&our_name);
2042  }
2043  if (slen > FR_DICT_ATTR_MAX_NAME_LEN) {
2044  fr_strerror_const("Attribute name too long");
2046  FR_SBUFF_ERROR_RETURN(&our_name);
2047  }
2048 
2049  /*
2050  * The remaining operations don't generate errors
2051  */
2052  if (err) *err = FR_DICT_ATTR_OK;
2053 
2054  /*
2055  * If what we stopped at wasn't a '.', then there
2056  * can't be a protocol name in this string.
2057  */
2058  if (*(our_name.p) && (*(our_name.p) != '.')) {
2059  memcpy(out, &dict_def, sizeof(*out));
2060  return 0;
2061  }
2062 
2063  root.name = buffer;
2064  dict = fr_hash_table_find(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
2065 
2066  if (!dict) {
2067  if (strcasecmp(root.name, "internal") != 0) {
2068  fr_strerror_printf("Unknown protocol '%s'", root.name);
2069  memcpy(out, &dict_def, sizeof(*out));
2070  fr_sbuff_set_to_start(&our_name);
2071  FR_SBUFF_ERROR_RETURN(&our_name);
2072  }
2073 
2074  dict = dict_gctx->internal;
2075  }
2076 
2077  *out = dict;
2078 
2079  FR_SBUFF_SET_RETURN(name, &our_name);
2080 }
2081 
2082 /** Look up a protocol name embedded in another string
2083  *
2084  * @param[out] err Parsing error.
2085  * @param[out] out the resolve dictionary or NULL if the dictionary
2086  * couldn't be resolved.
2087  * @param[in] name string start.
2088  * @param[in] dict_def The dictionary to return if no dictionary qualifier was found.
2089  * @return
2090  * - 0 and *out != NULL. Couldn't find a dictionary qualifier, so returned dict_def.
2091  * - < 0 on error and (*out == NULL) (offset as negative integer)
2092  * - > 0 on success (number of bytes parsed).
2093  */
2095 {
2096  return dict_by_protocol_substr(err, UNCONST(fr_dict_t **, out), name, dict_def);
2097 }
2098 
2099 /** Internal version of #fr_dict_by_protocol_name
2100  *
2101  * @note For internal use by the dictionary API only.
2102  *
2103  * @copybrief fr_dict_by_protocol_name
2104  */
2106 {
2107  if (!dict_gctx || !name) return NULL;
2108 
2110  &(fr_dict_t){ .root = &(fr_dict_attr_t){ .name = name } });
2111 }
2112 
2113 /** Internal version of #fr_dict_by_protocol_num
2114  *
2115  * @note For internal use by the dictionary API only.
2116  *
2117  * @copybrief fr_dict_by_protocol_num
2118  */
2120 {
2121  if (!dict_gctx) return NULL;
2122 
2124  &(fr_dict_t) { .root = &(fr_dict_attr_t){ .attr = num } });
2125 }
2126 
2127 /** Internal version of #fr_dict_by_da
2128  *
2129  * @note For internal use by the dictionary API only.
2130  *
2131  * @copybrief fr_dict_by_da
2132  */
2134 {
2135 #ifndef NDEBUG
2136  {
2137  fr_dict_attr_t const *da_p = da;
2138  fr_dict_t const *dict;
2139 
2140  dict = da->dict;
2141  while (da_p->parent) {
2142  da_p = da_p->parent;
2143  fr_cond_assert_msg(da_p->dict == dict, "Inconsistent dict membership. "
2144  "Expected %s, got %s",
2145  !da_p->dict ? "(null)" : fr_dict_root(da_p->dict)->name,
2146  !dict ? "(null)" : fr_dict_root(dict)->name);
2147  DA_VERIFY(da_p);
2148  }
2149 
2150  if (!da_p->flags.is_root) {
2151  fr_strerror_printf("%s: Attribute %s has not been inserted into a dictionary",
2152  __FUNCTION__, da->name);
2153  return NULL;
2154  }
2155  }
2156 #endif
2157 
2158  /*
2159  * Parent of the root attribute must
2160  * be the dictionary.
2161  */
2162  return talloc_get_type_abort(da->dict, fr_dict_t);
2163 }
2164 
2165 /** Lookup a protocol by its name
2166  *
2167  * @note For internal use by the dictionary API only.
2168  *
2169  * @param[in] name of the protocol to locate.
2170  * @return
2171  * - Attribute matching name.
2172  * - NULL if no matching protocol could be found.
2173  */
2175 {
2176  return dict_by_protocol_name(name);
2177 }
2178 
2179 /** Lookup a protocol by its number
2180  *
2181  * Returns the #fr_dict_t belonging to the protocol with the specified number
2182  * if any have been registered.
2183  *
2184  * @param[in] num to search for.
2185  * @return dictionary representing the protocol (if it exists).
2186  */
2187 fr_dict_t const *fr_dict_by_protocol_num(unsigned int num)
2188 {
2189  return dict_by_protocol_num(num);
2190 }
2191 
2192 /** Attempt to locate the protocol dictionary containing an attribute
2193  *
2194  * @note Unlike fr_dict_by_attr_name, doesn't search through all the dictionaries,
2195  * just uses the fr_dict_attr_t hierarchy and the talloc hierarchy to locate
2196  * the dictionary (much much faster and more scalable).
2197  *
2198  * @param[in] da To get the containing dictionary for.
2199  * @return
2200  * - The dictionary containing da.
2201  * - NULL.
2202  */
2204 {
2205  return dict_by_da(da);
2206 }
2207 
2208 /** See if two dictionaries have the same end parent
2209  *
2210  * @param[in] dict1 one dictionary
2211  * @param[in] dict2 two dictionary
2212  * @return
2213  * - true the dictionaries have the same end parent
2214  * - false the dictionaries do not have the same end parent.
2215  */
2216 bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
2217 {
2218  while (dict1->next) dict1 = dict1->next;
2219 
2220  while (dict2->next) dict2 = dict2->next;
2221 
2222  return (dict1 == dict2);
2223 }
2224 
2225 /** Look up a vendor by one of its child attributes
2226  *
2227  * @param[in] da The vendor attribute.
2228  * @return
2229  * - The vendor.
2230  * - NULL if no vendor with that number was registered for this protocol.
2231  */
2233 {
2234  fr_dict_t *dict;
2235  fr_dict_vendor_t dv;
2236 
2237  dv.pen = fr_dict_vendor_num_by_da(da);
2238  if (!dv.pen) return NULL;
2239 
2240  dict = dict_by_da(da);
2241 
2242  return fr_hash_table_find(dict->vendors_by_num, &dv);
2243 }
2244 
2245 /** Look up a vendor by its name
2246  *
2247  * @param[in] dict of protocol context we're operating in.
2248  * If NULL the internal dictionary will be used.
2249  * @param[in] name to search for.
2250  * @return
2251  * - The vendor.
2252  * - NULL if no vendor with that name was registered for this protocol.
2253  */
2255 {
2256  fr_dict_vendor_t *found;
2257 
2258  INTERNAL_IF_NULL(dict, NULL);
2259 
2260  if (!name) return 0;
2261 
2262  found = fr_hash_table_find(dict->vendors_by_name, &(fr_dict_vendor_t) { .name = name });
2263  if (!found) return 0;
2264 
2265  return found;
2266 }
2267 
2268 /** Look up a vendor by its PEN
2269  *
2270  * @param[in] dict of protocol context we're operating in.
2271  * If NULL the internal dictionary will be used.
2272  * @param[in] vendor_pen to search for.
2273  * @return
2274  * - The vendor.
2275  * - NULL if no vendor with that number was registered for this protocol.
2276  */
2278 {
2279  INTERNAL_IF_NULL(dict, NULL);
2280 
2281  return fr_hash_table_find(dict->vendors_by_num, &(fr_dict_vendor_t) { .pen = vendor_pen });
2282 }
2283 
2284 /** Return vendor attribute for the specified dictionary and pen
2285  *
2286  * @param[in] vendor_root of the vendor root attribute. Could be 26 (for example) in RADIUS.
2287  * @param[in] vendor_pen to find.
2288  * @return
2289  * - NULL if vendor does not exist.
2290  * - A fr_dict_attr_t representing the vendor in the dictionary hierarchy.
2291  */
2292 fr_dict_attr_t const *fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
2293 {
2294  fr_dict_attr_t const *vendor;
2295 
2296  switch (vendor_root->type) {
2297  case FR_TYPE_VSA: /* Vendor specific attribute */
2298  break;
2299 
2300  default:
2301  fr_strerror_printf("Wrong type for vendor root, expected '%s', got '%s'",
2303  fr_type_to_str(vendor_root->type));
2304  return NULL;
2305  }
2306 
2307  vendor = dict_attr_child_by_num(vendor_root, vendor_pen);
2308  if (!vendor) {
2309  fr_strerror_printf("Vendor %i not defined", vendor_pen);
2310  return NULL;
2311  }
2312 
2313  if (vendor->type != FR_TYPE_VENDOR) {
2314  fr_strerror_printf("Wrong type for vendor, expected '%s' got '%s'",
2315  fr_type_to_str(vendor->type),
2317  return NULL;
2318  }
2319 
2320  return vendor;
2321 }
2322 
2323 /** Callback function for resolving dictionary attributes
2324  *
2325  * @param[out] err Where to write error codes. Any error
2326  * other than FR_DICT_ATTR_NOTFOUND will
2327  * prevent resolution from continuing.
2328  * @param[out] out Where to write resolved DA.
2329  * @param[in] parent The dictionary root or other attribute to search from.
2330  * @param[in] in Contains the string to resolve.
2331  * @param[in] tt Terminal sequences to use to determine the portion
2332  * of in to search.
2333  * @return
2334  * - < 0 on failure.
2335  * - The number of bytes of name consumed on success.
2336  */
2338  fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
2339  fr_sbuff_t *in, fr_sbuff_term_t const *tt);
2340 
2341 /** Internal function for searching for attributes in multiple dictionaries
2342  *
2343  * @param[out] err Any errors that occurred searching.
2344  * @param[out] out The attribute we found.
2345  * @param[in] dict_def The default dictionary to search in.
2346  * @param[in] in string to resolve to an attribute.
2347  * @param[in] tt terminals that indicate the end of the string.
2348  * @param[in] internal Resolve the attribute in the internal dictionary.
2349  * @param[in] foreign Resolve attribute in a foreign dictionary,
2350  * i.e. one other than dict_def.
2351  * @param[in] func to use for resolution.
2352  * @return
2353  * - <=0 on error (the offset of the error).
2354  * - >0 on success.
2355  */
2356 static inline CC_HINT(always_inline)
2358  fr_dict_t const *dict_def,
2359  fr_sbuff_t *in, fr_sbuff_term_t const *tt,
2360  bool internal, bool foreign,
2362 {
2364  fr_hash_iter_t iter;
2365  fr_dict_t *dict = NULL;
2366  fr_sbuff_t our_in = FR_SBUFF(in);
2367 
2368  if (internal && !dict_gctx->internal) internal = false;
2369 
2370  /*
2371  * Always going to fail...
2372  */
2373  if (unlikely(!internal && !foreign && !dict_def)) {
2374  if (err) *err = FR_DICT_ATTR_EINVAL;
2375  *out = NULL;
2376  return 0;
2377  }
2378 
2379  /*
2380  * dict_def search in the specified dictionary
2381  */
2382  if (dict_def) {
2383  (void)func(&our_err, out, fr_dict_root(dict_def), &our_in, tt);
2384  switch (our_err) {
2385  case FR_DICT_ATTR_OK:
2386  FR_SBUFF_SET_RETURN(in, &our_in);
2387 
2388  case FR_DICT_ATTR_NOTFOUND:
2389  if (!internal && !foreign) goto error;
2390  break;
2391 
2392  default:
2393  goto error;
2394  }
2395  }
2396 
2397  /*
2398  * Next in the internal dictionary
2399  */
2400  if (internal) {
2401  (void)func(&our_err, out, fr_dict_root(dict_gctx->internal), &our_in, tt);
2402  switch (our_err) {
2403  case FR_DICT_ATTR_OK:
2404  FR_SBUFF_SET_RETURN(in, &our_in);
2405 
2406  case FR_DICT_ATTR_NOTFOUND:
2407  if (!foreign) goto error;
2408  break;
2409 
2410  default:
2411  goto error;
2412  }
2413  }
2414 
2415  /*
2416  * Now loop over the protocol dictionaries
2417  */
2419  dict;
2421  if (dict == dict_def) continue;
2422  if (dict == dict_gctx->internal) continue;
2423 
2424  (void)func(&our_err, out, fr_dict_root(dict), &our_in, tt);
2425  switch (our_err) {
2426  case FR_DICT_ATTR_OK:
2427  FR_SBUFF_SET_RETURN(in, &our_in);
2428 
2429  case FR_DICT_ATTR_NOTFOUND:
2430  continue;
2431 
2432  default:
2433  break;
2434  }
2435  }
2436 
2437 error:
2438  /*
2439  * Add a more helpful error message about
2440  * which dictionaries we tried to locate
2441  * the attribute in.
2442  */
2443  if (our_err == FR_DICT_ATTR_NOTFOUND) {
2444  fr_sbuff_marker_t start;
2445  char *list = NULL;
2446 
2447 #define DICT_NAME_APPEND(_in, _dict) \
2448 do { \
2449  char *_n; \
2450  _n = talloc_strdup_append_buffer(_in, fr_dict_root(_dict)->name); \
2451  if (unlikely(!_n)) { \
2452  talloc_free(_in); \
2453  goto done; \
2454  } \
2455  _in = _n; \
2456  _n = talloc_strdup_append_buffer(_in, ", "); \
2457  if (unlikely(!_n)) { \
2458  talloc_free(_in); \
2459  goto done; \
2460  } \
2461  _in = _n; \
2462 } while (0)
2463 
2464  our_in = FR_SBUFF(in);
2465  fr_sbuff_marker(&start, &our_in);
2466 
2467  list = talloc_strdup(NULL, "");
2468  if (unlikely(!list)) goto done;
2469 
2470  if (dict_def) DICT_NAME_APPEND(list, dict_def);
2471  if (internal) DICT_NAME_APPEND(list, dict_gctx->internal);
2472 
2473  if (foreign) {
2475  dict;
2477  if (dict == dict_def) continue;
2478  if (dict == dict_gctx->internal) continue;
2479 
2480  if (internal) DICT_NAME_APPEND(list, dict);
2481  }
2482  }
2483 
2484  fr_strerror_printf("Attribute '%pV' not found. Searched in: %pV",
2486  fr_sbuff_adv_until(&our_in, SIZE_MAX, tt, '\0')),
2487  fr_box_strvalue_len(list, talloc_array_length(list) - 3));
2488 
2489  talloc_free(list);
2490  }
2491 
2492 done:
2493  if (err) *err = our_err;
2494  *out = NULL;
2495 
2496  FR_SBUFF_ERROR_RETURN(&our_in);
2497 }
2498 
2499 /** Internal function for searching for attributes in multiple dictionaries
2500  *
2501  * Unlike #dict_attr_search this function searches for a protocol name preceding
2502  * the attribute identifier.
2503  */
2504 static inline CC_HINT(always_inline)
2506  fr_dict_t const *dict_def,
2507  fr_sbuff_t *in, fr_sbuff_term_t const *tt,
2508  bool internal, bool foreign,
2510 {
2511  fr_sbuff_t our_in = FR_SBUFF(in);
2512  fr_dict_attr_err_t our_err;
2513  fr_dict_t *initial;
2514  fr_slen_t slen;
2515 
2516  /*
2517  * Check for dictionary prefix
2518  */
2519  slen = dict_by_protocol_substr(&our_err, &initial, &our_in, dict_def);
2520  if (our_err != FR_DICT_ATTR_OK) {
2521  error:
2522  if (err) *err = our_err;
2523  *out = NULL;
2524  FR_SBUFF_ERROR_RETURN(&our_in);
2525  }
2526 
2527  /*
2528  * Has dictionary qualifier, can't fallback
2529  */
2530  if (slen > 0) {
2531  /*
2532  * Next thing SHOULD be a '.'
2533  */
2534  if (!fr_sbuff_next_if_char(&our_in, '.')) {
2536  *out = NULL;
2537  FR_SBUFF_ERROR_RETURN(&our_in);
2538  }
2539 
2540  internal = foreign = false;
2541  }
2542 
2543  if (dict_attr_search(&our_err, out, initial, &our_in, tt, internal, foreign, func) < 0) goto error;
2544  if (err) *err = FR_DICT_ATTR_OK;
2545 
2546  FR_SBUFF_SET_RETURN(in, &our_in);
2547 }
2548 
2549 /** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
2550  *
2551  * This function will search through all loaded dictionaries, or a subset of
2552  * loaded dictionaries, for a matching attribute in the top level namespace.
2553  *
2554  * This attribute may be qualified with `<protocol>.` to selection an attribute
2555  * in a specific case.
2556  *
2557  * @note If calling this function from the server any list or request qualifiers
2558  * should be stripped first.
2559  *
2560  * @param[out] err Why parsing failed. May be NULL.
2561  * @see fr_dict_attr_err_t
2562  * @param[out] out Dictionary found attribute.
2563  * @param[in] dict_def Default dictionary for non-qualified dictionaries.
2564  * @param[in] name Dictionary/Attribute name.
2565  * @param[in] tt Terminal strings.
2566  * @param[in] internal If true, fallback to the internal dictionary.
2567  * @param[in] foreign If true, fallback to foreign dictionaries.
2568  * @return
2569  * - < 0 on failure.
2570  * - The number of bytes of name consumed on success.
2571  */
2573  fr_dict_t const *dict_def,
2574  fr_sbuff_t *name, fr_sbuff_term_t const *tt,
2575  bool internal, bool foreign)
2576 {
2577  return dict_attr_search_qualified(err, out, dict_def, name, tt,
2578  internal, foreign, fr_dict_attr_by_name_substr);
2579 }
2580 
2581 /** Locate a #fr_dict_attr_t by its name in the top level namespace of a dictionary
2582  *
2583  * This function will search through all loaded dictionaries, or a subset of
2584  * loaded dictionaries, for a matching attribute in the top level namespace.
2585  *
2586  * @note If calling this function from the server any list or request qualifiers
2587  * should be stripped first.
2588  *
2589  * @param[out] err Why parsing failed. May be NULL.
2590  * @see fr_dict_attr_err_t
2591  * @param[out] out Dictionary found attribute.
2592  * @param[in] dict_def Default dictionary for non-qualified dictionaries.
2593  * @param[in] name Dictionary/Attribute name.
2594  * @param[in] tt Terminal strings.
2595  * @param[in] internal If true, fallback to the internal dictionary.
2596  * @param[in] foreign If true, fallback to foreign dictionaries.
2597  * @return
2598  * - < 0 on failure.
2599  * - The number of bytes of name consumed on success.
2600  */
2602  fr_dict_t const *dict_def,
2603  fr_sbuff_t *name, fr_sbuff_term_t const *tt,
2604  bool internal, bool foreign)
2605 {
2606  return dict_attr_search_qualified(err, out, dict_def, name, tt,
2607  internal, foreign, fr_dict_attr_by_name_substr);
2608 }
2609 
2610 /** Locate a qualified #fr_dict_attr_t by a dictionary qualified OID string
2611  *
2612  * This function will search through all loaded dictionaries, or a subset of
2613  * loaded dictionaries, for a matching attribute.
2614  *
2615  * @note If calling this function from the server any list or request qualifiers
2616  * should be stripped first.
2617  *
2618  * @note err should be checked to determine if a parse error occurred.
2619  *
2620  * @param[out] err Why parsing failed. May be NULL.
2621  * @see fr_dict_attr_err_t
2622  * @param[out] out Dictionary found attribute.
2623  * @param[in] dict_def Default dictionary for non-qualified dictionaries.
2624  * @param[in] in Dictionary/Attribute name.
2625  * @param[in] tt Terminal strings.
2626  * @param[in] internal If true, fallback to the internal dictionary.
2627  * @param[in] foreign If true, fallback to foreign dictionaries.
2628  * @return The number of bytes of name consumed.
2629  */
2631  fr_dict_t const *dict_def,
2632  fr_sbuff_t *in, fr_sbuff_term_t const *tt,
2633  bool internal, bool foreign)
2634 {
2635  return dict_attr_search_qualified(err, out, dict_def, in, tt,
2636  internal, foreign, fr_dict_attr_by_oid_substr);
2637 }
2638 
2639 /** Locate a qualified #fr_dict_attr_t by a dictionary using a non-qualified OID string
2640  *
2641  * This function will search through all loaded dictionaries, or a subset of
2642  * loaded dictionaries, for a matching attribute.
2643  *
2644  * @note If calling this function from the server any list or request qualifiers
2645  * should be stripped first.
2646  *
2647  * @note err should be checked to determine if a parse error occurred.
2648  *
2649  * @param[out] err Why parsing failed. May be NULL.
2650  * @see fr_dict_attr_err_t
2651  * @param[out] out Dictionary found attribute.
2652  * @param[in] dict_def Default dictionary for non-qualified dictionaries.
2653  * @param[in] in Dictionary/Attribute name.
2654  * @param[in] tt Terminal strings.
2655  * @param[in] internal If true, fallback to the internal dictionary.
2656  * @param[in] foreign If true, fallback to foreign dictionaries.
2657  * @return The number of bytes of name consumed.
2658  */
2660  fr_dict_t const *dict_def,
2661  fr_sbuff_t *in, fr_sbuff_term_t const *tt,
2662  bool internal, bool foreign)
2663 {
2664  return dict_attr_search_qualified(err, out, dict_def, in, tt,
2665  internal, foreign, fr_dict_attr_by_oid_substr);
2666 }
2667 
2668 /** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
2669  *
2670  * @param[out] err Why parsing failed. May be NULL.
2671  * @see fr_dict_attr_err_t.
2672  * @param[in] dict_def Default dictionary for non-qualified dictionaries.
2673  * @param[in] name Dictionary/Attribute name.
2674  * @param[in] internal If true, fallback to the internal dictionary.
2675  * @param[in] foreign If true, fallback to foreign dictionaries.
2676  * @return an #fr_dict_attr_err_t value.
2677  */
2679  char const *name,
2680  bool internal, bool foreign)
2681 {
2682  ssize_t slen;
2683  fr_sbuff_t our_name;
2684  fr_dict_attr_t const *da;
2685  fr_dict_attr_err_t our_err;
2686 
2687  fr_sbuff_init_in(&our_name, name, strlen(name));
2688 
2689  slen = fr_dict_attr_search_by_qualified_oid_substr(&our_err, &da, dict_def, &our_name, NULL, internal, foreign);
2690  if (our_err != FR_DICT_ATTR_OK) {
2691  if (err) *err = our_err;
2692  return NULL;
2693  }
2694  if ((size_t)slen != fr_sbuff_len(&our_name)) {
2695  fr_strerror_printf("Trailing garbage after attr string \"%s\"", name);
2697  return NULL;
2698  }
2699 
2700  return da;
2701 }
2702 
2703 /** Look up a dictionary attribute by a name embedded in another string
2704  *
2705  * Find the first invalid attribute name char in the string pointed
2706  * to by name.
2707  *
2708  * Copy the characters between the start of the name string and the first
2709  * none #fr_dict_attr_allowed_chars char to a buffer and perform a dictionary lookup
2710  * using that value.
2711  *
2712  * If the attribute exists, advance the pointer pointed to by name
2713  * to the first none #fr_dict_attr_allowed_chars char, and return the DA.
2714  *
2715  * If the attribute does not exist, don't advance the pointer and return
2716  * NULL.
2717  *
2718  * @param[out] err Why parsing failed. May be NULL.
2719  * @see fr_dict_attr_err_t
2720  * @param[out] out Where to store the resolve attribute.
2721  * @param[in] parent containing the namespace to search in.
2722  * @param[in] name string start.
2723  * @param[in] tt Terminal sequences to use to determine the portion
2724  * of in to search.
2725  * @return
2726  * - <= 0 on failure.
2727  * - The number of bytes of name consumed on success.
2728  */
2731 {
2732  fr_dict_attr_t const *da;
2733  size_t len;
2734  fr_dict_attr_t const *ref;
2735  char const *p;
2736  char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1]; /* +1 \0 +1 for "too long" */
2737  fr_sbuff_t our_name = FR_SBUFF(name);
2738  fr_hash_table_t *namespace;
2739 
2740  *out = NULL;
2741 
2742 #ifdef STATIC_ANALYZER
2743  memset(buffer, 0, sizeof(buffer));
2744 #endif
2745 
2747  &our_name, SIZE_MAX,
2749  if (len == 0) {
2750  fr_strerror_const("Zero length attribute name");
2752  FR_SBUFF_ERROR_RETURN(&our_name);
2753  }
2754  if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
2755  fr_strerror_const("Attribute name too long");
2757  FR_SBUFF_ERROR_RETURN(&our_name);
2758  }
2759 
2760  /*
2761  * Do a second pass, ensuring that the name has at least one alphanumeric character.
2762  */
2763  for (p = buffer; p < (buffer + len); p++) {
2764  if (sbuff_char_alpha_num[(uint8_t) *p]) break;
2765  }
2766 
2767  if ((size_t) (p - buffer) == len) {
2768  fr_strerror_const("Invalid attribute name");
2770  FR_SBUFF_ERROR_RETURN(&our_name);
2771  }
2772 
2773  ref = fr_dict_attr_ref(parent);
2774  if (ref) parent = ref;
2775 
2776 redo:
2777  namespace = dict_attr_namespace(parent);
2778  if (!namespace) {
2779  fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
2781  fr_sbuff_set_to_start(&our_name);
2782  FR_SBUFF_ERROR_RETURN(&our_name);
2783  }
2784 
2785  da = fr_hash_table_find(namespace, &(fr_dict_attr_t){ .name = buffer });
2786  if (!da) {
2787  if (parent->flags.is_root) {
2788  fr_dict_t const *dict = fr_dict_by_da(parent);
2789 
2790  if (dict->next) {
2791  parent = dict->next->root;
2792  goto redo;
2793  }
2794  }
2795 
2796  if (err) *err = FR_DICT_ATTR_NOTFOUND;
2797  fr_strerror_printf("Attribute '%s' not found in namespace '%s'", buffer, parent->name);
2798  fr_sbuff_set_to_start(&our_name);
2799  FR_SBUFF_ERROR_RETURN(&our_name);
2800  }
2801 
2802  da = dict_attr_alias(err, da);
2803  if (unlikely(!da)) FR_SBUFF_ERROR_RETURN(&our_name);
2804 
2805  *out = da;
2806  if (err) *err = FR_DICT_ATTR_OK;
2807 
2808  FR_SBUFF_SET_RETURN(name, &our_name);
2809 }
2810 
2811 /* Internal version of fr_dict_attr_by_name
2812  *
2813  */
2815 {
2816  fr_hash_table_t *namespace;
2817  fr_dict_attr_t *da;
2818 
2819  DA_VERIFY(parent);
2820 
2821 redo:
2822  namespace = dict_attr_namespace(parent);
2823  if (!namespace) {
2824  fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
2826  return NULL;
2827  }
2828 
2829  da = fr_hash_table_find(namespace, &(fr_dict_attr_t) { .name = name });
2830  if (!da) {
2831  if (parent->flags.is_root) {
2832  fr_dict_t const *dict = fr_dict_by_da(parent);
2833 
2834  if (dict->next) {
2835  parent = dict->next->root;
2836  goto redo;
2837  }
2838  }
2839 
2840  if (err) *err = FR_DICT_ATTR_NOTFOUND;
2841  fr_strerror_printf("Attribute '%s' not found in namespace '%s'", name, parent->name);
2842  return NULL;
2843  }
2844 
2845  if (err) *err = FR_DICT_ATTR_OK;
2846 
2847  return da;
2848 }
2849 
2850 /** Locate a #fr_dict_attr_t by its name
2851  *
2852  * @param[out] err Why the lookup failed. May be NULL.
2853  * @see fr_dict_attr_err_t.
2854  * @param[in] parent containing the namespace we're searching in.
2855  * @param[in] name of the attribute to locate.
2856  * @return
2857  * - Attribute matching name.
2858  * - NULL if no matching attribute could be found.
2859  */
2861 {
2862  fr_dict_attr_t const *da;
2863 
2864  DA_VERIFY(parent);
2865 
2866  da = dict_attr_by_name(err, parent, name);
2867  if (!da) return NULL;
2868 
2869  da = dict_attr_alias(err, da);
2870  if (unlikely(!da)) return NULL;
2871 
2872  return da;
2873 }
2874 
2875 /** Internal version of fr_dict_attr_child_by_num
2876  *
2877  */
2879 {
2880  fr_dict_attr_t const *bin;
2881  fr_dict_attr_t const **children;
2882  fr_dict_attr_t const *ref;
2883 
2884  DA_VERIFY(parent);
2885 
2886  /*
2887  * Do any necessary dereferencing
2888  */
2889  ref = fr_dict_attr_ref(parent);
2890  if (ref) parent = ref;
2891 
2892  children = dict_attr_children(parent);
2893  if (!children) return NULL;
2894 
2895  /*
2896  * Child arrays may be trimmed back to save memory.
2897  * Check that so we don't SEGV.
2898  */
2899  if ((attr & 0xff) > talloc_array_length(children)) return NULL;
2900 
2901  bin = children[attr & 0xff];
2902  for (;;) {
2903  if (!bin) return NULL;
2904  if (bin->attr == attr) {
2906 
2907  memcpy(&out, &bin, sizeof(bin));
2908 
2909  return out;
2910  }
2911  bin = bin->next;
2912  }
2913 
2914  return NULL;
2915 }
2916 
2917 /** Check if a child attribute exists in a parent using an attribute number
2918  *
2919  * @param[in] parent to check for child in.
2920  * @param[in] attr number to look for.
2921  * @return
2922  * - The child attribute on success.
2923  * - NULL if the child attribute does not exist.
2924  */
2926 {
2927  fr_dict_attr_t const *da;
2928 
2929  da = dict_attr_child_by_num(parent, attr);
2930  if (!da) return NULL;
2931 
2932  da = dict_attr_alias(NULL, da);
2933  if (unlikely(!da)) return NULL;
2934 
2935  return da;
2936 }
2937 
2938 /** Lookup the structure representing an enum value in a #fr_dict_attr_t
2939  *
2940  * @param[in] da to search in.
2941  * @param[in] value to search for.
2942  * @return
2943  * - Matching #fr_dict_enum_value_t.
2944  * - NULL if no matching #fr_dict_enum_value_t could be found.
2945  */
2947 {
2949 
2951  if (!ext) {
2952  fr_strerror_printf("VALUE cannot be defined for %s attributes",
2953  fr_type_to_str(da->type));
2954  return NULL;
2955  }
2956 
2957  /*
2958  * No values associated with this attribute
2959  */
2960  if (!ext->name_by_value) return NULL;
2961 
2962  /*
2963  * Could be NULL or an unknown attribute, in which case
2964  * we want to avoid the lookup gracefully...
2965  */
2966  if (value->type != da->type) return NULL;
2967 
2968  return fr_hash_table_find(ext->name_by_value, &(fr_dict_enum_value_t){ .value = value });
2969 }
2970 
2971 /** Lookup the name of an enum value in a #fr_dict_attr_t
2972  *
2973  * @param[in] da to search in.
2974  * @param[in] value number to search for.
2975  * @return
2976  * - Name of value.
2977  * - NULL if no matching value could be found.
2978  */
2980 {
2982 
2983  dv = fr_dict_enum_by_value(da, value);
2984  if (!dv) return NULL;
2985 
2986  return dv->name;
2987 }
2988 
2989 /*
2990  * Get a value by its name, keyed off of an attribute.
2991  */
2993 {
2995 
2996  if (!name) return NULL;
2997 
2999  if (!ext) {
3000  fr_strerror_printf("VALUE cannot be defined for %s attributes",
3001  fr_type_to_str(da->type));
3002  return NULL;
3003  }
3004 
3005  /*
3006  * No values associated with this attribute
3007  */
3008  if (!ext->value_by_name) return NULL;
3009 
3010  if (len < 0) len = strlen(name);
3011 
3012  return fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = name, .name_len = len});
3013 }
3014 
3015 /*
3016  * Get a value by its name, keyed off of an attribute, from an sbuff
3017  */
3019 {
3021  fr_sbuff_t our_in = FR_SBUFF(in);
3022  fr_dict_enum_value_t *found = NULL;
3023  size_t found_len = 0;
3024  uint8_t *p;
3026 
3027  /*
3028  * No values associated with this attribute, do nothing.
3029  */
3031  if (!ext || !ext->value_by_name) return 0;
3032 
3033  /*
3034  * Loop until we exhaust all of the possibilities.
3035  */
3036  for (p = name; (size_t) (p - name) < ext->max_name_len; p++) {
3037  int len = (p - name) + 1;
3038  fr_dict_enum_value_t *enumv;
3039 
3040  *p = fr_sbuff_char(&our_in, '\0');
3041  if (!fr_dict_enum_allowed_chars[*p]) {
3042  break;
3043  }
3044  fr_sbuff_next(&our_in);
3045 
3046  enumv = fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = (char const *) name,
3047  .name_len = len});
3048 
3049  /*
3050  * Return the LONGEST match, as there may be
3051  * overlaps. e.g. "Framed", and "Framed-User".
3052  */
3053  if (enumv) {
3054  found = enumv;
3055  found_len = len;
3056  }
3057  }
3058 
3059  if (found) {
3060  *out = found;
3061  FR_SBUFF_SET_RETURN(in, found_len);
3062  }
3063 
3064  return 0;
3065 }
3066 
3067 /** Extract an enumeration name from a string
3068  *
3069  * This function defines the canonical format for an enumeration name.
3070  *
3071  * An enumeration name is made up of one or more fr_dict_attr_allowed_chars
3072  * with at least one character in the sequence not being a special character
3073  * i.e. [-+/_] or a number.
3074  *
3075  * This disambiguates enumeration identifiers from mathematical expressions.
3076  *
3077  * If we allowed enumeration names consisting of sequences of numbers separated
3078  * by special characters it would not be possible to determine if the special
3079  * character were an operator in a subexpression.
3080  *
3081  * For example take:
3082  *
3083  * &My-Enum-Attr == 01234-5678
3084  *
3085  * Without having access to the enumeration values of My-Enum-Attr (which we
3086  * might not have during tokenisation), we cannot tell if this is:
3087  *
3088  * (&My-Enum-Attr == 01234-5678)
3089  *
3090  * OR
3091  *
3092  * ((&My-Enum-Attr == 01234) - 5678)
3093  *
3094  * If an alpha character occurs anywhere in the string i.e:
3095  *
3096  * (&My-Enum-Attr == 01234-A5678)
3097  *
3098  * we know 01234-A5678 can't be a mathematical sub-expression because the
3099  * second potential operand can no longer be parsed as an integer constant.
3100  *
3101  * @param[out] out The name string we managed to extract.
3102  * May be NULL in which case only the length of the name
3103  * will be returned.
3104  * @param[out] err Type of parsing error which occurred. May be NULL.
3105  * @param[in] in The string containing the enum identifier.
3106  * @param[in] tt If non-null verify that a terminal sequence occurs
3107  * after the enumeration name.
3108  * @return
3109  * - <0 the offset at which the parse error occurred.
3110  * - >1 the number of bytes parsed.
3111  */
3113  fr_sbuff_t *in, fr_sbuff_term_t const *tt)
3114 {
3115  fr_sbuff_t our_in = FR_SBUFF(in);
3116  bool seen_alpha = false;
3117 
3118  while (fr_sbuff_is_in_charset(&our_in, fr_dict_enum_allowed_chars)) {
3119  if (fr_sbuff_is_alpha(&our_in)) seen_alpha = true;
3120  fr_sbuff_next(&our_in);
3121  }
3122 
3123  if (!seen_alpha) {
3124  if (fr_sbuff_used(&our_in) == 0) {
3125  fr_strerror_const("VALUE name is empty");
3127  FR_SBUFF_ERROR_RETURN(&our_in);
3128  }
3129 
3130  fr_strerror_const("VALUE name must contain at least one alpha character");
3132  fr_sbuff_set_to_start(&our_in); /* Marker should be at the start of the enum */
3133  FR_SBUFF_ERROR_RETURN(&our_in);
3134  }
3135 
3136  /*
3137  * Check that the sequence is correctly terminated
3138  */
3139  if (tt && !fr_sbuff_is_terminal(&our_in, tt)) {
3140  fr_strerror_const("VALUE name has trailing text");
3142  FR_SBUFF_ERROR_RETURN(&our_in);
3143  }
3144 
3145  if (out) return fr_sbuff_out_bstrncpy_exact(out, in, fr_sbuff_used(&our_in));
3146 
3147  if (err) *err = FR_SBUFF_PARSE_OK;
3148 
3149  FR_SBUFF_SET_RETURN(in, &our_in);
3150 }
3151 
3152 int dict_dlopen(fr_dict_t *dict, char const *name)
3153 {
3154  char *module_name;
3155  char *p, *q;
3156 
3157  if (!name) return 0;
3158 
3159  module_name = talloc_typed_asprintf(NULL, "libfreeradius-%s", name);
3160  for (p = module_name, q = p + talloc_array_length(p) - 1; p < q; p++) *p = tolower((uint8_t) *p);
3161 
3162  /*
3163  * Pass in dict as the uctx so that we can get at it in
3164  * any callbacks.
3165  *
3166  * Not all dictionaries have validation functions. It's
3167  * a soft error if they don't exist.
3168  */
3169  dict->dl = dl_by_name(dict_gctx->dict_loader, module_name, dict, false);
3170  if (!dict->dl) {
3171  fr_strerror_printf_push("Failed loading dictionary validation library \"%s\"", module_name);
3172  talloc_free(module_name);
3173  return -1;
3174  }
3175 
3176  talloc_free(module_name);
3177  return 0;
3178 }
3179 
3180 /** Find a dependent in the tree of dependents
3181  *
3182  */
3183 static int8_t _dict_dependent_cmp(void const *a, void const *b)
3184 {
3185  fr_dict_dependent_t const *dep_a = a;
3186  fr_dict_dependent_t const *dep_b = b;
3187  int ret;
3188 
3189  ret = strcmp(dep_a->dependent, dep_b->dependent);
3190  return CMP(ret, 0);
3191 }
3192 
3193 /** Record a new dependency on a dictionary
3194  *
3195  * These are used to determine what is currently depending on a dictionary.
3196  *
3197  * @param[in] dict to record dependency on.
3198  * @param[in] dependent Either C src file, or another dictionary.
3199  * @return
3200  * - 0 on success.
3201  * - -1 on failure.
3202  */
3203 int dict_dependent_add(fr_dict_t *dict, char const *dependent)
3204 {
3205  fr_dict_dependent_t *found;
3206 
3207  found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
3208  if (!found) {
3209  fr_dict_dependent_t *new;
3210 
3211  new = talloc_zero(dict->dependents, fr_dict_dependent_t);
3212  if (unlikely(!new)) return -1;
3213 
3214  /*
3215  * If the dependent is in a module that gets
3216  * unloaded, any strings in the text area also
3217  * get unloaded (including dependent locations).
3218  *
3219  * Strdup the string here so we don't get
3220  * random segfaults if a module forgets to unload
3221  * a dictionary.
3222  */
3223  new->dependent = talloc_typed_strdup(new, dependent);
3224  fr_rb_insert(dict->dependents, new);
3225 
3226  new->count = 1;
3227 
3228  return 0;
3229  }
3230 
3231  found->count++; /* Increase ref count */
3232 
3233  return 0;
3234 }
3235 
3236 /** Manually increase the reference count for a dictionary
3237  *
3238  * This is useful if a previously loaded dictionary needs to
3239  * be bound to the lifetime of an additional object.
3240  *
3241  * @param[in] dict to increase the reference count for.
3242  * @param[in] dependent requesting the loading of the dictionary.
3243  * @return
3244  * - 0 on success.
3245  * - -1 on error.
3246  */
3247 int fr_dict_dependent_add(fr_dict_t const *dict, char const *dependent)
3248 {
3249  fr_dict_t *m_dict = fr_dict_unconst(dict);
3250 
3251  if (unlikely(!m_dict)) return -1;
3252 
3253  return dict_dependent_add(m_dict, dependent);
3254 }
3255 
3256 /** Decrement ref count for a dependent in a dictionary
3257  *
3258  * @param[in] dict to remove dependency from.
3259  * @param[in] dependent Either C src, or another dictionary dependent.
3260  * What depends on this dictionary.
3261  */
3262 int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
3263 {
3264  fr_dict_dependent_t *found;
3265 
3266  found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
3267  if (!found) {
3268  fr_strerror_printf("Dependent \"%s\" not found in dictionary \"%s\"", dependent, dict->root->name);
3269  return -1;
3270  }
3271 
3272  if (found->count == 0) {
3273  fr_strerror_printf("Zero ref count invalid for dependent \"%s\", dictionary \"%s\"",
3274  dependent, dict->root->name);
3275  return -1;
3276  }
3277 
3278  if (--found->count == 0) {
3279  fr_rb_delete(dict->dependents, found);
3280  talloc_free(found);
3281  return 0;
3282  }
3283 
3284  return 1;
3285 }
3286 
3287 /** Check if a dictionary still has dependents
3288  *
3289  * @param[in] dict to check
3290  * @return
3291  * - true if there's still at least one dependent.
3292  * - false if there are no dependents.
3293  */
3295 {
3296  return (fr_rb_num_elements(dict->dependents) > 0);
3297 }
3298 
3299 #ifndef NDEBUG
3301 {
3302  fr_rb_iter_inorder_t iter;
3303  fr_dict_dependent_t *dep;
3304 
3305  if (!dict_has_dependents(dict)) return;
3306 
3307  fprintf(stderr, "DEPENDENTS FOR %s\n", dict->root->name);
3308 
3309  for (dep = fr_rb_iter_init_inorder(&iter, dict->dependents);
3310  dep;
3311  dep = fr_rb_iter_next_inorder(&iter)) {
3312  fprintf(stderr, "\t<- %s (%u)\n", dep->dependent, dep->count);
3313  }
3314 }
3315 #endif
3316 
3317 
3319 {
3320  fr_dict_t **refd_list;
3321  unsigned int i;
3322 
3323  if (!dict->autoref) return 0;
3324 
3325  if (fr_hash_table_flatten(dict->autoref, (void ***)&refd_list, dict->autoref) < 0) {
3326  fr_strerror_const("failed flattening autoref hash table");
3327  return -1;
3328  }
3329 
3330  /*
3331  * Free the dictionary. It will call proto->free() if there's nothing more to do.
3332  */
3333  for (i = 0; i < talloc_array_length(refd_list); i++) {
3334  if (fr_dict_free(&refd_list[i], dict->root->name) < 0) {
3335  fr_strerror_printf("failed freeing autoloaded protocol %s", refd_list[i]->root->name);
3336  return -1;
3337  }
3338  }
3339 
3340  TALLOC_FREE(dict->autoref);
3341 
3342  return 0;
3343 }
3344 
3346 {
3347  /*
3348  * We don't necessarily control the order of freeing
3349  * children.
3350  */
3351  if (dict != dict->gctx->internal) {
3352  fr_dict_attr_t const *da;
3353 
3354  if (dict->gctx->attr_protocol_encapsulation && dict->root) {
3355  da = fr_dict_attr_child_by_num(dict->gctx->attr_protocol_encapsulation, dict->root->attr);
3356  if (da && fr_dict_attr_ref(da)) dict_attr_ref_set(da, NULL);
3357  }
3358  }
3359 
3360 #ifdef STATIC_ANALYZER
3361  if (!dict->root) {
3362  fr_strerror_const("dict root is missing");
3363  return -1;
3364  }
3365 #endif
3366 
3367  /*
3368  * If we called init(), then call free()
3369  */
3370  if (dict->proto && dict->proto->free) {
3371  dict->proto->free();
3372  }
3373 
3374  if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(dict->gctx->protocol_by_name, dict))) {
3375  fr_strerror_printf("Failed removing dictionary from protocol hash \"%s\"", dict->root->name);
3376  return -1;
3377  }
3378  dict->in_protocol_by_name = false;
3379 
3380  if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(dict->gctx->protocol_by_num, dict))) {
3381  fr_strerror_printf("Failed removing dictionary from protocol number_hash \"%s\"", dict->root->name);
3382  return -1;
3383  }
3384  dict->in_protocol_by_num = false;
3385 
3386  if (dict_has_dependents(dict)) {
3387  fr_rb_iter_inorder_t iter;
3388  fr_dict_dependent_t *dep;
3389 
3390  fr_strerror_printf("Refusing to free dictionary \"%s\", still has dependents", dict->root->name);
3391 
3392  for (dep = fr_rb_iter_init_inorder(&iter, dict->dependents);
3393  dep;
3394  dep = fr_rb_iter_next_inorder(&iter)) {
3395  fr_strerror_printf_push("%s (%u)", dep->dependent, dep->count);
3396  }
3397 
3398  return -1;
3399  }
3400 
3401  /*
3402  * Free the hash tables with free functions first
3403  * so that the things the hash tables reference
3404  * are still there.
3405  */
3406  talloc_free(dict->vendors_by_name);
3407 
3408  /*
3409  * Decrease the reference count on the validation
3410  * library we loaded.
3411  */
3412  dl_free(dict->dl);
3413 
3414  if (dict == dict->gctx->internal) {
3415  dict->gctx->internal = NULL;
3416  dict->gctx->attr_protocol_encapsulation = NULL;
3417  }
3418 
3419  return 0;
3420 }
3421 
3422 /** Allocate a new dictionary
3423  *
3424  * @param[in] ctx to allocate dictionary in.
3425  * @return
3426  * - NULL on memory allocation error.
3427  */
3428 fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
3429 {
3430  fr_dict_t *dict;
3431 
3432  if (!dict_gctx) {
3433  fr_strerror_const("Initialise global dictionary ctx with fr_dict_global_ctx_init()");
3434  return NULL;
3435  }
3436 
3437  dict = talloc_zero(ctx, fr_dict_t);
3438  if (!dict) {
3439  fr_strerror_const("Failed allocating memory for dictionary");
3440  error:
3441  talloc_free(dict);
3442  return NULL;
3443  }
3444  dict->gctx = dict_gctx; /* Record which global context this was allocated in */
3445  talloc_set_destructor(dict, _dict_free);
3446 
3447  /*
3448  * Pre-Allocate pool memory for rapid startup
3449  * As that's the working memory required during
3450  * dictionary initialisation.
3451  */
3452  dict->pool = talloc_pool(dict, DICT_POOL_SIZE);
3453  if (!dict->pool) {
3454  fr_strerror_const("Failed allocating talloc pool for dictionary");
3455  goto error;
3456  }
3457 
3458  /*
3459  * Create the table of vendor by name. There MAY NOT
3460  * be multiple vendors of the same name.
3461  */
3463  if (!dict->vendors_by_name) {
3464  fr_strerror_printf("Failed allocating \"vendors_by_name\" table");
3465  goto error;
3466  }
3467  /*
3468  * Create the table of vendors by value. There MAY
3469  * be vendors of the same value. If there are, we
3470  * pick the latest one.
3471  */
3473  if (!dict->vendors_by_num) {
3474  fr_strerror_printf("Failed allocating \"vendors_by_num\" table");
3475  goto error;
3476  }
3477 
3478  /*
3479  * Inter-dictionary reference caching
3480  */
3482  if (!dict->autoref) {
3483  fr_strerror_printf("Failed allocating \"autoref\" table");
3484  goto error;
3485  }
3486 
3487  /*
3488  * Who/what depends on this dictionary
3489  */
3491 
3492  /*
3493  * Set default type size and length.
3494  */
3495  dict->default_type_size = 1;
3496  dict->default_type_length = 1;
3497 
3498  return dict;
3499 }
3500 
3501 /** Allocate a new local dictionary
3502  *
3503  * @param[in] parent parent dictionary and talloc ctx
3504  * @return
3505  * - NULL on memory allocation error.
3506  *
3507  * This dictionary cannot define vendors, or inter-dictionary
3508  * dependencies. However, we initialize the relevant fields just in
3509  * case. We should arguably just skip initializing those fields, and
3510  * just allow the server to crash if programmers do something stupid with it.
3511  */
3513 {
3514  fr_dict_t *dict;
3515  fr_dict_attr_t *da;
3516 
3517  fr_dict_attr_flags_t flags = {
3518  .is_root = true,
3519  .local = true,
3520  .type_size = 2,
3521  .length = 2
3522  };
3523 
3524 
3526  if (!dict) return NULL;
3527 
3528  /*
3529  * Allow for 64k local attributes.
3530  */
3531  dict->default_type_size = 2;
3532  dict->default_type_length = 2;
3533 
3534  /*
3535  * Allocate the root attribute. This dictionary is
3536  * always protocol "local", and number "0".
3537  */
3538  da = dict_attr_alloc(dict->pool, NULL, "local", 0, FR_TYPE_TLV,
3539  &(dict_attr_args_t){ .flags = &flags });
3540  if (unlikely(!da)) {
3541  talloc_free(dict);
3542  return NULL;
3543  }
3544 
3545  da->last_child_attr = fr_dict_root(parent)->last_child_attr;
3546 
3547  dict->root = da;
3548  dict->root->dict = dict;
3549  dict->next = parent;
3550 
3551  DA_VERIFY(dict->root);
3552 
3553  return dict;
3554 }
3555 
3556 /** Decrement the reference count on a previously loaded dictionary
3557  *
3558  * @param[in] dict to free.
3559  * @param[in] dependent that originally allocated this dictionary.
3560  * @return
3561  * - 0 on success (dictionary freed).
3562  * - 1 if other things still depend on the dictionary.
3563  * - -1 on error (dependent doesn't exist)
3564  */
3565 int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
3566 {
3567  fr_dict_t **our_dict = UNCONST(fr_dict_t **, dict);
3568 
3569  return fr_dict_free(our_dict, dependent);
3570 }
3571 
3572 /** Decrement the reference count on a previously loaded dictionary
3573  *
3574  * @param[in] dict to free.
3575  * @param[in] dependent that originally allocated this dictionary.
3576  * @return
3577  * - 0 on success (dictionary freed).
3578  * - 1 if other things still depend on the dictionary.
3579  * - -1 on error (dependent doesn't exist)
3580  */
3581 int fr_dict_free(fr_dict_t **dict, char const *dependent)
3582 {
3583  if (!*dict) return 0;
3584 
3585  switch (dict_dependent_remove(*dict, dependent)) {
3586  case 0: /* dependent has no more refs */
3587  if (!dict_has_dependents(*dict)) {
3588  talloc_free(*dict);
3589  return 0;
3590  }
3591  FALL_THROUGH;
3592 
3593  case 1: /* dependent has more refs */
3594  return 1;
3595 
3596  default: /* error */
3597  return -1;
3598  }
3599 }
3600 
3601 /** Process a dict_attr_autoload element to load/verify a dictionary attribute
3602  *
3603  * @param[in] to_load attribute definition
3604  * @return
3605  * - 0 on success.
3606  * - -1 on failure.
3607  */
3609 {
3610  fr_dict_enum_autoload_t const *p = to_load;
3611  fr_dict_enum_value_t const *enumv;
3612 
3613  for (p = to_load; p->out; p++) {
3614  if (unlikely(!p->attr)) {
3615  fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing attribute pointer", p->name);
3616  return -1;
3617  }
3618 
3619  if (unlikely(!*p->attr)) {
3620  fr_strerror_printf("Can't resolve value \"%s\", attribute not loaded", p->name);
3621  fr_strerror_printf_push("Check fr_dict_attr_autoload_t struct has "
3622  "an entry to load the attribute \"%s\" is located in, and that "
3623  "the fr_dict_autoload_attr_t symbol name is correct", p->name);
3624  return -1;
3625  }
3626 
3627  enumv = fr_dict_enum_by_name(*(p->attr), p->name, -1);
3628  if (!enumv) {
3629  fr_strerror_printf("Value '%s' not found in \"%s\" attribute",
3630  p->name, (*(p->attr))->name);
3631  return -1;
3632  }
3633 
3634  if (p->out) *(p->out) = enumv->value;
3635  }
3636 
3637  return 0;
3638 }
3639 
3640 /** Process a dict_attr_autoload element to load/verify a dictionary attribute
3641  *
3642  * @param[in] to_load attribute definition
3643  * @return
3644  * - 0 on success.
3645  * - -1 on failure.
3646  */
3648 {
3649  fr_dict_attr_t const *da;
3650  fr_dict_attr_autoload_t const *p = to_load;
3651 
3652  for (p = to_load; p->out; p++) {
3653  if (!p->dict) {
3654  fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing dictionary pointer", p->name);
3655  return -1;
3656  }
3657 
3658  if (!*p->dict) {
3659  fr_strerror_printf("Autoloader autoloader can't resolve attribute \"%s\", dictionary not loaded", p->name);
3660  fr_strerror_printf_push("Check fr_dict_autoload_t struct has "
3661  "an entry to load the dictionary \"%s\" is located in, and that "
3662  "the fr_dict_autoload_t symbol name is correct", p->name);
3663  return -1;
3664  }
3665 
3666  da = fr_dict_attr_by_oid(NULL, fr_dict_root(*p->dict), p->name);
3667  if (!da) {
3668  fr_strerror_printf("Autoloader attribute \"%s\" not found in \"%s\" dictionary", p->name,
3669  *p->dict ? (*p->dict)->root->name : "internal");
3670  return -1;
3671  }
3672 
3673  if (da->type != p->type) {
3674  fr_strerror_printf("Autoloader attribute \"%s\" should be type %s, but defined as type %s", da->name,
3675  fr_type_to_str(p->type),
3676  fr_type_to_str(da->type));
3677  return -1;
3678  }
3679 
3680  DA_VERIFY(da);
3681 
3682  if (p->out) *(p->out) = da;
3683  }
3684 
3685  return 0;
3686 }
3687 
3688 /** Process a dict_autoload element to load a protocol
3689  *
3690  * @param[in] to_load dictionary definition.
3691  * @param[in] dependent that is loading this dictionary.
3692  * @return
3693  * - 0 on success.
3694  * - -1 on failure.
3695  */
3696 int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
3697 {
3698  fr_dict_autoload_t const *p;
3699 
3700  for (p = to_load; p->out; p++) {
3701  fr_dict_t *dict = NULL;
3702 
3703  if (unlikely(!p->proto)) {
3704  fr_strerror_const("autoload missing parameter proto");
3705  return -1;
3706  }
3707 
3708  /*
3709  * Load the internal dictionary
3710  */
3711  if (strcmp(p->proto, "freeradius") == 0) {
3712  if (fr_dict_internal_afrom_file(&dict, p->proto, dependent) < 0) return -1;
3713  } else {
3714  if (fr_dict_protocol_afrom_file(&dict, p->proto, p->base_dir, dependent) < 0) return -1;
3715  }
3716 
3717  *(p->out) = dict;
3718  }
3719 
3720  return 0;
3721 }
3722 
3723 
3724 /** Decrement the reference count on a previously loaded dictionary
3725  *
3726  * @param[in] to_free previously loaded dictionary to free.
3727  * @param[in] dependent that originally allocated this dictionary
3728  */
3729 int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
3730 {
3731  fr_dict_autoload_t const *p;
3732 
3733  for (p = to_free; p->out; p++) {
3734  int ret;
3735 
3736  if (!*p->out) continue;
3737  ret = fr_dict_const_free(p->out, dependent);
3738 
3739  if (ret == 0) *p->out = NULL;
3740  if (ret < 0) return -1;
3741  }
3742 
3743  return 0;
3744 }
3745 
3746 /** Structure used to managed the lifetime of a dictionary
3747  *
3748  * This should only be used when dictionaries are being dynamically loaded during
3749  * compilation. It should not be used to load dictionaries at runtime, or if
3750  * modules need to load dictionaries (use static fr_dict_autoload_t defs).
3751 
3752  */
3754  fr_dict_autoload_t load[2]; //!< Autoloader def.
3755  char const *dependent; //!< Dependent that loaded the dictionary.
3756 };
3757 
3758 /** Talloc destructor to automatically free dictionaries
3759  *
3760  * @param[in] to_free dictionary autoloader definition describing the dictionary to free.
3761  */
3763 {
3764  return _fr_dict_autofree(to_free->load, to_free->dependent);
3765 }
3766 
3767 /** Autoload a dictionary and bind the lifetime to a talloc chunk
3768  *
3769  * Mainly useful for resolving "forward" references from unlang immediately.
3770  *
3771  * @note If the talloc chunk is freed it does not mean the dictionary will
3772  * be immediately freed. It will be freed when all other references
3773  * to the dictionary are gone.
3774  *
3775  * @param[in] ctx to bind the dictionary lifetime to.
3776  * @param[out] out pointer to the loaded dictionary.
3777  * @param[in] proto to load.
3778  * @param[in] dependent to register this reference to. Will be dupd.
3779  */
3780 fr_dict_autoload_talloc_t *_fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent)
3781 {
3782  fr_dict_autoload_talloc_t *dict_ref;
3783  int ret;
3784 
3785  dict_ref = talloc(ctx, fr_dict_autoload_talloc_t);
3786  if (unlikely(dict_ref == NULL)) {
3787  oom:
3788  fr_strerror_const("Out of memory");
3789  return NULL;
3790  }
3791 
3792  dict_ref->load[0] = (fr_dict_autoload_t){ .proto = proto, .out = out};
3793  dict_ref->load[1] = (fr_dict_autoload_t){ NULL };
3794  dict_ref->dependent = talloc_strdup(dict_ref, dependent);
3795  if (unlikely(dict_ref->dependent == NULL)) {
3796  talloc_free(dict_ref);
3797  goto oom;
3798  }
3799 
3800  ret = _fr_dict_autoload(dict_ref->load, dependent);
3801  if (ret < 0) {
3802  talloc_free(dict_ref);
3803  return NULL;
3804  }
3805 
3806  return dict_ref;
3807 }
3808 
3809 /** Callback to automatically resolve enum values
3810  *
3811  * @param[in] module being loaded.
3812  * @param[in] symbol An array of fr_dict_enum_autoload_t to load.
3813  * @param[in] user_ctx unused.
3814  * @return
3815  * - 0 on success.
3816  * - -1 on failure.
3817  */
3818 int fr_dl_dict_enum_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
3819 {
3820  if (fr_dict_enum_autoload((fr_dict_enum_autoload_t *)symbol) < 0) return -1;
3821 
3822  return 0;
3823 }
3824 
3825 /** Callback to automatically resolve attributes and check the types are correct
3826  *
3827  * @param[in] module being loaded.
3828  * @param[in] symbol An array of fr_dict_attr_autoload_t to load.
3829  * @param[in] user_ctx unused.
3830  * @return
3831  * - 0 on success.
3832  * - -1 on failure.
3833  */
3834 int fr_dl_dict_attr_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
3835 {
3836  if (fr_dict_attr_autoload((fr_dict_attr_autoload_t *)symbol) < 0) return -1;
3837 
3838  return 0;
3839 }
3840 
3841 /** Callback to automatically load dictionaries required by modules
3842  *
3843  * @param[in] module being loaded.
3844  * @param[in] symbol An array of fr_dict_autoload_t to load.
3845  * @param[in] user_ctx unused.
3846  * @return
3847  * - 0 on success.
3848  * - -1 on failure.
3849  */
3850 int fr_dl_dict_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
3851 {
3852  if (fr_dict_autoload((fr_dict_autoload_t const *)symbol) < 0) return -1;
3853 
3854  return 0;
3855 }
3856 
3857 /** Callback to automatically free a dictionary when the module is unloaded
3858  *
3859  * @param[in] module being loaded.
3860  * @param[in] symbol An array of fr_dict_autoload_t to load.
3861  * @param[in] user_ctx unused.
3862  */
3863 void fr_dl_dict_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
3864 {
3865  fr_dict_autofree(((fr_dict_autoload_t *)symbol));
3866 }
3867 
3868 /** Callback to automatically load validation routines for dictionaries.
3869  *
3870  * @param[in] dl the library we just loaded
3871  * @param[in] symbol pointer to a fr_dict_protocol_t table
3872  * @param[in] user_ctx the global context which we don't need
3873  * @return
3874  * - 0 on success.
3875  * - -1 on failure.
3876  */
3877 static int _dict_validation_onload(dl_t const *dl, void *symbol, UNUSED void *user_ctx)
3878 {
3879  fr_dict_t *dict = talloc_get_type_abort(dl->uctx, fr_dict_t);
3880  fr_dict_protocol_t const *proto = symbol;
3881 
3882 
3883  /*
3884  * Set the protocol-specific callbacks.
3885  */
3886  dict->proto = proto;
3887 
3888  /*
3889  * @todo - just use dict->proto->foo, once we get the
3890  * rest of the code cleaned up.
3891  */
3892 #undef COPY
3893 #define COPY(_x) dict->_x = proto->_x
3894  COPY(default_type_size);
3895  COPY(default_type_length);
3897  COPY(subtype_table_len);
3898  COPY(attr_valid);
3899 
3900  return 0;
3901 }
3902 
3903 static int _dict_global_free_at_exit(void *uctx)
3904 {
3905  return talloc_free(uctx);
3906 }
3907 
3909 {
3910  fr_hash_iter_t iter;
3911  fr_dict_t *dict;
3912  bool still_loaded = false;
3913 
3914  /*
3915  * Make sure this doesn't fire later and mess
3916  * things up...
3917  */
3919 
3920  /*
3921  * Free up autorefs first, which will free up inter-dictionary dependencies.
3922  */
3923  for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
3924  dict;
3925  dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
3926  (void)talloc_get_type_abort(dict, fr_dict_t);
3927 
3928  if (dict_autoref_free(dict) < 0) return -1;
3929  }
3930 
3931  for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
3932  dict;
3933  dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
3934  (void)talloc_get_type_abort(dict, fr_dict_t);
3935  dict_dependent_remove(dict, "global"); /* remove our dependency */
3936 
3937  if (talloc_free(dict) < 0) {
3938 #ifndef NDEBUG
3939  FR_FAULT_LOG("gctx failed to free dictionary %s - %s", dict->root->name, fr_strerror());
3940 #endif
3941  still_loaded = true;
3942  }
3943  }
3944 
3945  /*
3946  * Free the internal dictionary as the last step, after all of the protocol dictionaries and
3947  * libraries have freed their references to it.
3948  */
3949  if (gctx->internal) {
3950  dict_dependent_remove(gctx->internal, "global"); /* remove our dependency */
3951 
3952  if (talloc_free(gctx->internal) < 0) still_loaded = true;
3953  }
3954 
3955  if (still_loaded) {
3956 #ifndef NDEBUG
3958 #endif
3959  return -1;
3960  }
3961 
3962  /*
3963  * Set this to NULL just in case the caller tries to use
3964  * dict_global_init() again.
3965  */
3966  if (gctx == dict_gctx) dict_gctx = NULL; /* In case the active context isn't this one */
3967 
3968  return 0;
3969 }
3970 
3971 /** Initialise the global protocol hashes
3972  *
3973  * @note Must be called before any other dictionary functions.
3974  *
3975  * @param[in] ctx to allocate global resources in.
3976  * @param[in] free_at_exit Install an at_exit handler to free the global ctx.
3977  * This is useful when dictionaries are held by other
3978  * libraries which free them using atexit handlers.
3979  * @param[in] dict_dir the default location for the dictionaries.
3980  * @return
3981  * - A pointer to the new global context on success.
3982  * - NULL on failure.
3983  */
3984 fr_dict_gctx_t *fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
3985 {
3986  fr_dict_gctx_t *new_ctx;
3987 
3988  if (!dict_dir) {
3989  fr_strerror_const("No dictionary location provided");
3990  return NULL;
3991  }
3992 
3993  new_ctx = talloc_zero(ctx, fr_dict_gctx_t);
3994  if (!new_ctx) {
3995  fr_strerror_const("Out of Memory");
3996  return NULL;
3997  }
3998  new_ctx->perm_check = true; /* Check file permissions by default */
3999 
4001  if (!new_ctx->protocol_by_name) {
4002  fr_strerror_const("Failed initializing protocol_by_name hash");
4003  error:
4004  talloc_free(new_ctx);
4005  return NULL;
4006  }
4007 
4009  if (!new_ctx->protocol_by_num) {
4010  fr_strerror_const("Failed initializing protocol_by_num hash");
4011  goto error;
4012  }
4013 
4014  new_ctx->dict_dir_default = talloc_strdup(new_ctx, dict_dir);
4015  if (!new_ctx->dict_dir_default) goto error;
4016 
4017  new_ctx->dict_loader = dl_loader_init(new_ctx, NULL, false, false);
4018  if (!new_ctx->dict_loader) goto error;
4019 
4020  if (dl_symbol_init_cb_register(new_ctx->dict_loader, 0, "dict_protocol",
4021  _dict_validation_onload, NULL) < 0) goto error;
4022  new_ctx->free_at_exit = free_at_exit;
4023 
4024  talloc_set_destructor(new_ctx, _dict_global_free);
4025 
4026  if (!dict_gctx) dict_gctx = new_ctx; /* Set as the default */
4027 
4028  if (free_at_exit) fr_atexit_global(_dict_global_free_at_exit, new_ctx);
4029 
4030  return new_ctx;
4031 }
4032 
4033 /** Set whether we check dictionary file permissions
4034  *
4035  * @param[in] gctx to alter.
4036  * @param[in] enable Whether we should check file permissions as they're loaded.
4037  */
4039 {
4040  gctx->perm_check = enable;
4041 }
4042 
4043 /** Set a new, active, global dictionary context
4044  *
4045  * @param[in] gctx To set.
4046  */
4048 {
4049  memcpy(&dict_gctx, &gctx, sizeof(dict_gctx));
4050 }
4051 
4052 /** Explicitly free all data associated with a global dictionary context
4053  *
4054  * @note You should *NOT* ignore the return code of this function.
4055  * You should use perror() or PERROR() to print out the reason
4056  * why freeing failed.
4057  *
4058  * @param[in] gctx To set.
4059  * @return
4060  * - 0 on success.
4061  * - -1 on failure.
4062  */
4064 {
4065  if (dict_gctx == gctx) dict_gctx = NULL;
4066 
4067  return talloc_const_free(gctx);
4068 }
4069 
4070 /** Allow the default dict dir to be changed after initialisation
4071  *
4072  * @param[in] dict_dir New default dict dir to use.
4073  * @return
4074  * - 0 on success.
4075  * - -1 on failure.
4076  */
4077 int fr_dict_global_ctx_dir_set(char const *dict_dir)
4078 {
4079  if (!dict_gctx) return -1;
4080 
4081  talloc_free(dict_gctx->dict_dir_default); /* Free previous value */
4082  dict_gctx->dict_dir_default = talloc_strdup(dict_gctx, dict_dir);
4083  if (!dict_gctx->dict_dir_default) return -1;
4084 
4085  return 0;
4086 }
4087 
4088 char const *fr_dict_global_ctx_dir(void)
4089 {
4090  return dict_gctx->dict_dir_default;
4091 }
4092 
4093 /** Mark all dictionaries and the global dictionary ctx as read only
4094  *
4095  * Any attempts to add new attributes will now fail.
4096  */
4098 {
4099  fr_hash_iter_t iter;
4100  fr_dict_t *dict;
4101 
4102  if (!dict_gctx) return;
4103 
4104  /*
4105  * Set everything to read only
4106  */
4108  dict;
4111  dict->read_only = true;
4112  }
4113 
4114  dict = dict_gctx->internal;
4116  dict->read_only = true;
4117  dict_gctx->read_only = true;
4118 }
4119 
4120 /** Dump information about currently loaded dictionaries
4121  *
4122  * Intended to be called from a debugger
4123  */
4125 {
4126  fr_hash_iter_t dict_iter;
4127  fr_dict_t *dict;
4128  fr_rb_iter_inorder_t dep_iter;
4129  fr_dict_dependent_t *dep;
4130 
4131  if (gctx == NULL) gctx = dict_gctx;
4132 
4133  if (!gctx) {
4134  FR_FAULT_LOG("gctx not initialised");
4135  return;
4136  }
4137 
4138  FR_FAULT_LOG("gctx %p report", dict_gctx);
4139  for (dict = fr_hash_table_iter_init(gctx->protocol_by_num, &dict_iter);
4140  dict;
4141  dict = fr_hash_table_iter_next(gctx->protocol_by_num, &dict_iter)) {
4142  for (dep = fr_rb_iter_init_inorder(&dep_iter, dict->dependents);
4143  dep;
4144  dep = fr_rb_iter_next_inorder(&dep_iter)) {
4145  FR_FAULT_LOG("\t%s is referenced from %s count (%u)", dict->root->name, dep->dependent, dep->count);
4146  }
4147  }
4148 
4149  if (gctx->internal) {
4150  for (dep = fr_rb_iter_init_inorder(&dep_iter, gctx->internal->dependents);
4151  dep;
4152  dep = fr_rb_iter_next_inorder(&dep_iter)) {
4153  FR_FAULT_LOG("\t%s is referenced from %s count (%u)", gctx->internal->root->name, dep->dependent, dep->count);
4154  }
4155  }
4156 }
4157 
4158 /** Iterate protocols by name
4159  *
4160  */
4162 {
4163  if (!dict_gctx) return NULL;
4164 
4166 }
4167 
4169 {
4170  if (!dict_gctx) return NULL;
4171 
4173 }
4174 
4175 
4176 /** Coerce to non-const
4177  *
4178  */
4180 {
4181  if (unlikely(dict->read_only)) {
4182  fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4183  return NULL;
4184  }
4185  return UNCONST(fr_dict_t *, dict);
4186 }
4187 
4188 /** Coerce to non-const
4189  *
4190  */
4192 {
4193  fr_dict_t *dict;
4194 
4195  dict = dict_by_da(da);
4196  if (unlikely(dict->read_only)) {
4197  fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4198  return NULL;
4199  }
4200 
4201  return UNCONST(fr_dict_attr_t *, da);
4202 }
4203 
4205 {
4206  if (!dict_gctx) return NULL;
4207 
4208  return dict_gctx->internal;
4209 }
4210 
4211 /*
4212  * Check for the allowed characters.
4213  */
4215 {
4216  char const *p = name, *end;
4217  bool unknown = false;
4218  bool alnum = false;
4219 
4220  if (len < 0) len = strlen(name);
4221 
4222  if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
4223  fr_strerror_const("Attribute name is too long");
4224  return -1;
4225  }
4226 
4227  end = p + len;
4228 
4229  /*
4230  * Unknown attributes can have '.' in their name.
4231  */
4232  if ((len > 5) && (memcmp(name, "Attr-", 5) == 0)) unknown = true;
4233 
4234  while (p < end) {
4235  if ((*p == '.') && unknown) p++;
4236 
4237  if (!fr_dict_attr_allowed_chars[(uint8_t)*p]) {
4238  fr_strerror_printf("Invalid character '%pV' in attribute name \"%pV\"",
4240 
4241  return -(p - name);
4242  }
4243 
4244  alnum |= sbuff_char_alpha_num[(uint8_t)*p];
4245 
4246  p++;
4247  }
4248 
4249  if (!alnum) {
4250  fr_strerror_const("Invalid attribute name");
4251  return -1;
4252  }
4253 
4254  return len;
4255 }
4256 
4258 {
4259  char const *p = name, *end;
4260  bool alnum = false;
4261 
4262  if (len < 0) len = strlen(name);
4263  end = p + len;
4264 
4265  do {
4266  if (!fr_dict_attr_allowed_chars[(uint8_t)*p] && (*p != '.')) {
4267  fr_strerror_printf("Invalid character '%pV' in oid string \"%pV\"",
4269 
4270  return -(p - name);
4271  }
4272 
4273  alnum |= sbuff_char_alpha_num[(uint8_t)*p];
4274  p++;
4275  } while (p < end);
4276 
4277  if (!alnum) return 0;
4278 
4279  return len;
4280 }
4281 
4282 /** Iterate over children of a DA.
4283  *
4284  * @param[in] parent the parent da to iterate over
4285  * @param[in,out] prev pointer to NULL to start, otherwise pointer to the previously returned child
4286  * @return
4287  * - NULL for end of iteration
4288  * - !NULL for a valid child. This child MUST be passed to the next loop.
4289  */
4291 {
4292  fr_dict_attr_t const * const *bin;
4293  fr_dict_attr_t const **children;
4294  fr_dict_attr_t const *ref;
4295  size_t len, i, start;
4296 
4297  if (!parent || !prev) return NULL;
4298 
4299  ref = fr_dict_attr_ref(parent);
4300  if (ref) parent = ref;
4301 
4302  children = dict_attr_children(parent);
4303  if (!children) return NULL;
4304 
4305  if (!*prev) {
4306  start = 0;
4307 
4308  } else if ((*prev)->next) {
4309  /*
4310  * There are more children in this bin, return
4311  * the next one.
4312  */
4313  return (*prev)->next;
4314 
4315  } else {
4316  /*
4317  * Figure out which bin we were in. If it was
4318  * the last one, we're done.
4319  */
4320  start = (*prev)->attr & 0xff;
4321  if (start == 255) return NULL;
4322 
4323  /*
4324  * Start at the next bin.
4325  */
4326  start++;
4327  }
4328 
4329  /*
4330  * Look for a non-empty bin, and return the first child
4331  * from there.
4332  */
4333  len = talloc_array_length(children);
4334  for (i = start; i < len; i++) {
4335  bin = &children[i & 0xff];
4336 
4337  if (*bin) return *bin;
4338  }
4339 
4340  return NULL;
4341 }
4342 
4343 /** Call the specified callback for da and then for all its children
4344  *
4345  */
4346 static int dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
4347 {
4348  size_t i, len;
4349  fr_dict_attr_t const **children;
4350 
4351  children = dict_attr_children(da);
4352 
4353  if (fr_dict_attr_ref(da) || !children) return callback(da, uctx);
4354 
4355  len = talloc_array_length(children);
4356  for (i = 0; i < len; i++) {
4357  int ret;
4358  fr_dict_attr_t const *bin;
4359 
4360  if (!children[i]) continue;
4361 
4362  for (bin = children[i]; bin; bin = bin->next) {
4363  ret = dict_walk(bin, callback, uctx);
4364  if (ret < 0) return ret;
4365  }
4366  }
4367 
4368  return 0;
4369 }
4370 
4371 int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
4372 {
4373  return dict_walk(da, callback, uctx);
4374 }
4375 
4376 
4377 void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
4378 {
4379  int i;
4380  fr_dict_attr_t const *da_p;
4381 
4382  if (!da) fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_dict_attr_t pointer was NULL", file, line);
4383 
4385 
4386  if ((!da->flags.is_root) && (da->depth == 0)) {
4387  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_dict_attr_t %s vendor: %i, attr %i: "
4388  "Is not root, but depth is 0",
4389  file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr);
4390  }
4391 
4392  if (da->depth > FR_DICT_MAX_TLV_STACK) {
4393  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_dict_attr_t %s vendor: %i, attr %i: "
4394  "Indicated depth (%u) greater than TLV stack depth (%u)",
4395  file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr,
4396  da->depth, FR_DICT_MAX_TLV_STACK);
4397  }
4398 
4399  for (da_p = da; da_p; da_p = da_p->next) {
4401  }
4402 
4403  for (i = da->depth, da_p = da; (i >= 0) && da; i--, da_p = da_p->parent) {
4404  if (i != (int)da_p->depth) {
4405  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_dict_attr_t %s vendor: %i, attr %i: "
4406  "Depth out of sequence, expected %i, got %u",
4407  file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr, i, da_p->depth);
4408  }
4409 
4410  }
4411 
4412  if ((i + 1) < 0) {
4413  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_dict_attr_t top of hierarchy was not at depth 0",
4414  file, line);
4415  }
4416 
4417  if (da->parent && (da->parent->type == FR_TYPE_VENDOR) && !fr_dict_attr_has_ext(da, FR_DICT_ATTR_EXT_VENDOR)) {
4418  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: VSA missing 'vendor' extension", file, line);
4419  }
4420 
4421  switch (da->type) {
4422  case FR_TYPE_STRUCTURAL:
4423  {
4424  fr_hash_table_t *ht;
4425 
4426  if (da->type == FR_TYPE_GROUP) break;
4427 
4429  "CONSISTENCY CHECK FAILED %s[%u]: %s missing 'children' extension",
4430  file, line,
4431  fr_type_to_str(da->type));
4432 
4434  "CONSISTENCY CHECK FAILED %s[%u]: %s missing 'namespace' extension",
4435  file, line,
4436  fr_type_to_str(da->type));
4437 
4438  /*
4439  * Check the namespace hash table is ok
4440  */
4441  ht = dict_attr_namespace(da);
4442  if (unlikely(!ht)) break;
4444  }
4445  break;
4446 
4447  default:
4448  break;
4449  }
4450 }
4451 
4452 /** See if a structural da is allowed to contain another da
4453  *
4454  * We have some complex rules with different structural types,
4455  * different protocol dictionaries, references to other protocols,
4456  * etc.
4457  *
4458  * @param[in] parent The parent da, must be structural
4459  * @param[in] child The alleged child
4460  * @return
4461  * - false - the child is not allowed to be contained by the parent
4462  * - true - the child is allowed to be contained by the parent
4463  */
4465 {
4466  /*
4467  * This is the common case: child is from the parent.
4468  */
4469  if (child->parent == parent) return true;
4470 
4471  if (child->flags.is_raw) return true; /* let people do stupid things */
4472 
4473  /*
4474  * Child is a STRUCT which has a parent key field. The
4475  * child pair nesting, though, is in the grandparent.
4476  */
4477  if (fr_dict_attr_is_key_field(child->parent)) {
4478  fr_assert(child->parent->parent == parent);
4479 
4480  return (child->parent->parent == parent);
4481  }
4482 
4483  /*
4484  * Only structural types or key fields can have children.
4485  */
4486  if (!fr_type_structural[parent->type]) return false;
4487 
4488  /*
4489  * An internal attribute can go into any other container.
4490  *
4491  * Any other attribute can go into an internal structural
4492  * attribute, because why not?
4493  */
4494  if (dict_gctx) {
4495  if (child->dict == dict_gctx->internal) return true;
4496 
4497  if (parent->dict == dict_gctx->internal) return true;
4498  }
4499 
4500  /*
4501  * Anything can go into internal groups.
4502  */
4503  if ((parent->type == FR_TYPE_GROUP) && parent->flags.internal) return true;
4504 
4505  /*
4506  * Protocol attributes have to be in the same dictionary.
4507  *
4508  * Unless they're a cross-protocol grouping attribute.
4509  * In which case we check if the ref is the same.
4510  */
4511  if (child->dict != parent->dict) {
4512  fr_dict_attr_t const *ref;
4513 
4514  ref = fr_dict_attr_ref(parent);
4515 
4516  return (ref && (ref->dict == child->dict));
4517  }
4518 
4519  /*
4520  * Key fields can have children, but everyone else thinks
4521  * that the struct is the parent. <sigh>
4522  */
4523  if ((parent->type == FR_TYPE_STRUCT) && child->parent->parent == parent) return true;
4524 
4525  /*
4526  * We're in the same protocol dictionary, but the child
4527  * isn't directly from the parent. Therefore the only
4528  * type of same-protocol structure it can go into is a
4529  * group.
4530  */
4531  return (parent->type == FR_TYPE_GROUP);
4532 }
4533 
4534 /** Return the protocol descriptor for the dictionary.
4535  *
4536  */
4538 {
4539  return dict->proto;
4540 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
int n
Definition: acutest.h:577
va_list args
Definition: acutest.h:770
int const char int line
Definition: acutest.h:702
unsigned int fr_atexit_global_disarm(bool uctx_scope, fr_atexit_t func, void const *uctx)
Remove a specific global destructor (without executing it)
Definition: atexit.c:229
#define fr_atexit_global(_func, _uctx)
Add a free function to the global free list.
Definition: atexit.h:59
static dl_t * dl
Definition: fuzzer.c:42
static fr_dict_t * dict
Definition: fuzzer.c:46
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:189
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:208
#define FR_FAULT_LOG(_fmt,...)
Definition: debug.h:49
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:154
size_t type
Length of type data.
Definition: dict.h:230
size_t name_len
Allows for efficient name lookups when operating on partial buffers.
Definition: dict.h:211
char const * name
of the attribute.
Definition: dict.h:255
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name, char const *dependent)
(Re-)Initialize the special internal dictionary
char const * name
Vendor name.
Definition: dict.h:232
fr_dict_attr_t const ** attr
The protocol dictionary the attribute should be resolved in.
Definition: dict.h:240
unsigned int is_root
Is root of a dictionary.
Definition: dict.h:74
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
static fr_slen_t err
Definition: dict.h:645
fr_value_box_t const ** out
Enumeration value.
Definition: dict.h:239
fr_dict_t const ** dict
The protocol dictionary the attribute should be resolved in.
Definition: dict.h:252
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
int(* fr_dict_walk_t)(fr_dict_attr_t const *da, void *uctx)
Definition: dict.h:749
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
#define DA_VERIFY(_x)
Definition: dict.h:66
char const * name
of the attribute.
Definition: dict.h:243
fr_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:213
uint32_t pen
Private enterprise number.
Definition: dict.h:228
fr_type_t type
of the attribute. Mismatch is a fatal error.
Definition: dict.h:256
#define FR_DICT_DA_STACK_CACHE_MAX
Maximum level of da stack caching.
Definition: dict.h:372
size_t length
Length of length data.
Definition: dict.h:231
char const * base_dir
Directory structure beneath share.
Definition: dict.h:265
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition: dict.h:166
@ FR_DICT_ATTR_EXT_NAMESPACE
Attribute has its own namespace.
Definition: dict.h:167
@ FR_DICT_ATTR_EXT_DA_STACK
Cached da stack.
Definition: dict.h:165
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition: dict.h:162
@ FR_DICT_ATTR_EXT_VENDOR
Cached vendor pointer.
Definition: dict.h:164
@ FR_DICT_ATTR_EXT_NAME
Name of the attribute.
Definition: dict.h:160
@ FR_DICT_ATTR_EXT_CHILDREN
Attribute has children.
Definition: dict.h:161
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:384
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
Definition: dict.h:272
@ FR_DICT_ATTR_OK
No error.
Definition: dict.h:273
@ FR_DICT_ATTR_NOTFOUND
Attribute couldn't be found.
Definition: dict.h:274
@ FR_DICT_ATTR_EINVAL
Invalid arguments.
Definition: dict.h:284
@ FR_DICT_ATTR_NO_CHILDREN
Child lookup in attribute with no children.
Definition: dict.h:283
@ FR_DICT_ATTR_PARSE_ERROR
Attribute string couldn't be parsed.
Definition: dict.h:276
@ FR_DICT_ATTR_INTERNAL_ERROR
Internal error occurred.
Definition: dict.h:277
#define FR_DICT_ENUM_MAX_NAME_LEN
Maximum length of a enum value.
Definition: dict.h:362
char const * proto
The protocol dictionary name.
Definition: dict.h:266
#define fr_dict_attr_is_key_field(_da)
Definition: dict.h:149
char const * name
Enum name.
Definition: dict.h:210
static fr_slen_t in
Definition: dict.h:645
#define FR_DICT_VENDOR_MAX_NAME_LEN
Maximum length of a vendor name.
Definition: dict.h:363
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition: dict.h:364
struct dict_attr_s fr_dict_attr_t
Definition: dict.h:46
fr_dict_attr_t const * child_struct[]
for key fields
Definition: dict.h:217
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Values of the encryption flags.
Definition: merged_model.c:139
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Specifies a value which must be present for the module to function.
Definition: dict.h:238
Value of an enumerated attribute.
Definition: dict.h:209
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:341
Private enterprise.
Definition: dict.h:227
size_t max_name_len
maximum length of a name
Definition: dict_ext.h:88
fr_dict_attr_t const * vendor
ancestor which has type FR_TYPE_VENDOR
Definition: dict_ext.h:68
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition: dict_ext.h:120
fr_hash_table_t * name_by_value
Lookup a name by value.
Definition: dict_ext.h:90
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:164
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition: dict_ext.h:89
fr_dict_attr_t const * da_stack[]
Stack of dictionary attributes.
Definition: dict_ext.h:81
static bool fr_dict_attr_has_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Return whether a da has a given extension or not.
Definition: dict_ext.h:135
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Definition: dict_ext.h:182
fr_dict_attr_t const * ref
reference, only for FR_TYPE_GROUP
Definition: dict_ext.h:61
Attribute extension - Holds children for an attribute.
Definition: dict_ext.h:52
Attribute extension - Stack of dictionary attributes that describe the path back to the root of the d...
Definition: dict_ext.h:74
Attribute extension - Holds enumeration values.
Definition: dict_ext.h:87
Attribute extension - Holds a hash table with the names of all children of this attribute.
Definition: dict_ext.h:96
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition: dict_ext.h:60
Attribute extension - Cached vendor pointer.
Definition: dict_ext.h:67
static int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref)
static int dict_attr_children_set(fr_dict_attr_t const *da, fr_dict_attr_t const **children)
static void * dict_attr_ext_alloc_size(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext, size_t ext_len)
Allocate an attribute extension of a particular size.
Definition: dict_ext_priv.h:42
static void * dict_attr_ext_alloc(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext)
Allocate an attribute extension.
Definition: dict_ext_priv.h:55
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_ext_copy_all(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in)
Copy all attribute extensions from one attribute to another.
Definition: dict_ext_priv.h:89
static void * dict_attr_ext_copy(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in, fr_dict_attr_ext_t ext)
Copy a single attribute extension from one attribute to another.
Definition: dict_ext_priv.h:76
static fr_dict_attr_t const ** dict_attr_children(fr_dict_attr_t const *da)
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:674
char * dict_dir_default
The default location for loading dictionaries if one wasn't provided.
Definition: dict_priv.h:127
fr_hash_table_t * protocol_by_name
Hash containing names of all the registered protocols.
Definition: dict_priv.h:132
#define INTERNAL_IF_NULL(_dict, _ret)
Set the internal dictionary if none was provided.
Definition: dict_priv.h:45
fr_hash_table_t * protocol_by_num
Hash containing numbers of all the registered protocols.
Definition: dict_priv.h:134
#define DICT_POOL_SIZE
Definition: dict_priv.h:37
dl_loader_t * dict_loader
for protocol validation
Definition: dict_priv.h:130
char const * dependent
File holding the reference.
Definition: dict_priv.h:62
fr_dict_attr_t const * attr_protocol_encapsulation
Definition: dict_priv.h:147
fr_dict_t * internal
Magic internal dictionary.
Definition: dict_priv.h:145
bool free_at_exit
This gctx will be freed on exit.
Definition: dict_priv.h:120
bool perm_check
Whether we should check dictionary file permissions as they're loaded.
Definition: dict_priv.h:122
int count
How many references are held by this file.
Definition: dict_priv.h:60
bool dict_attr_fields_valid(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, int *attr, fr_type_t type, fr_dict_attr_flags_t *flags)
Validate a new attribute definition.
Optional arguments for initialising/allocating attributes.
Definition: dict_priv.h:167
Entry recording dictionary reference holders by file.
Definition: dict_priv.h:58
Test enumeration values.
Definition: dict_test.h:92
int fr_dl_dict_attr_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically resolve attributes and check the types are correct.
Definition: dict_util.c:3834
fr_dict_t * fr_dict_global_ctx_iter_init(fr_dict_global_ctx_iter_t *iter)
Iterate protocols by name.
Definition: dict_util.c:4161
void fr_dict_global_ctx_debug(fr_dict_gctx_t const *gctx)
Dump information about currently loaded dictionaries.
Definition: dict_util.c:4124
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool takes_precedence)
Add a value name.
Definition: dict_util.c:1535
dl_t * fr_dict_dl(fr_dict_t const *dict)
Definition: dict_util.c:2007
fr_slen_t fr_dict_attr_search_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a fr_dict_attr_t by its name in the top level namespace of a dictionary.
Definition: dict_util.c:2601
char const * fr_dict_global_ctx_dir(void)
Definition: dict_util.c:4088
ssize_t fr_dict_attr_by_oid_legacy(fr_dict_t const *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
Get the leaf attribute of an OID string.
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:1970
#define FLAGS_EQUAL(_x)
ssize_t fr_dict_valid_oid_str(char const *name, ssize_t len)
Definition: dict_util.c:4257
int fr_dict_global_ctx_dir_set(char const *dict_dir)
Allow the default dict dir to be changed after initialisation.
Definition: dict_util.c:4077
fr_slen_t fr_dict_enum_name_from_substr(fr_sbuff_t *out, fr_sbuff_parse_error_t *err, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Extract an enumeration name from a string.
Definition: dict_util.c:3112
static int _dict_global_free_at_exit(void *uctx)
Definition: dict_util.c:3903
static uint32_t dict_protocol_num_hash(void const *data)
Hash a protocol number.
Definition: dict_util.c:152
static uint32_t dict_vendor_name_hash(void const *data)
Wrap name hash function for fr_dict_vendor_t.
Definition: dict_util.c:199
#define DICT_NAME_APPEND(_in, _dict)
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition: dict_util.c:4191
static int _dict_free(fr_dict_t *dict)
Definition: dict_util.c:3345
fr_dict_vendor_t const * fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
Look up a vendor by its PEN.
Definition: dict_util.c:2277
int fr_dict_enum_autoload(fr_dict_enum_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3608
int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:3729
fr_dict_t * dict_by_da(fr_dict_attr_t const *da)
Internal version of fr_dict_by_da.
Definition: dict_util.c:2133
static int dict_autoref_free(fr_dict_t *dict)
Definition: dict_util.c:3318
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition: dict_util.c:4371
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:2012
static int dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Call the specified callback for da and then for all its children.
Definition: dict_util.c:4346
fr_dict_t * fr_dict_protocol_alloc(fr_dict_t const *parent)
Allocate a new local dictionary.
Definition: dict_util.c:3512
static void dependent_debug(fr_dict_t *dict)
Definition: dict_util.c:3300
static uint32_t dict_vendor_pen_hash(void const *data)
Hash a vendor number.
Definition: dict_util.c:224
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters allowed in dictionary names.
Definition: dict_util.c:45
static int _dict_validation_onload(dl_t const *dl, void *symbol, UNUSED void *user_ctx)
Callback to automatically load validation routines for dictionaries.
Definition: dict_util.c:3877
fr_dict_attr_t * dict_attr_alloc_null(TALLOC_CTX *ctx)
Allocate a partially completed attribute.
Definition: dict_util.c:657
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:725
void fr_dl_dict_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically free a dictionary when the module is unloaded.
Definition: dict_util.c:3863
static int dict_attr_da_stack_set(fr_dict_attr_t **da_p)
Initialise an attribute's da stack from its parent.
Definition: dict_util.c:434
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition: dict_util.c:2216
static int dict_attr_compatible(fr_dict_attr_t const *parent, fr_dict_attr_t const *old, fr_dict_attr_t const *n)
Definition: dict_util.c:1205
static fr_slen_t dict_attr_search_qualified(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign, dict_attr_resolve_func_t func)
Internal function for searching for attributes in multiple dictionaries.
Definition: dict_util.c:2505
bool dict_attr_can_have_children(fr_dict_attr_t const *da)
See if a fr_dict_attr_t can have children.
Definition: dict_util.c:1012
static int8_t _dict_dependent_cmp(void const *a, void const *b)
Find a dependent in the tree of dependents.
Definition: dict_util.c:3183
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition: dict_util.c:1631
int dict_attr_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *parent, char const *name, int attr, fr_type_t type, dict_attr_args_t const *args)
Initialise fields in a dictionary attribute structure.
Definition: dict_util.c:521
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:1921
fr_dict_attr_t const * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
Definition: dict_util.c:2292
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, int attr, fr_type_t type, fr_dict_attr_flags_t const *flags)
Add an attribute to the dictionary.
Definition: dict_util.c:1245
void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
Definition: dict_util.c:4377
#define FNV_MAGIC_PRIME
Definition: dict_util.c:90
#define COPY(_x)
bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child)
See if a structural da is allowed to contain another da.
Definition: dict_util.c:4464
fr_dict_t const * fr_dict_by_protocol_num(unsigned int num)
Lookup a protocol by its number.
Definition: dict_util.c:2187
fr_dict_t * dict_by_protocol_num(unsigned int num)
Internal version of fr_dict_by_protocol_num.
Definition: dict_util.c:2119
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition: dict_util.c:2174
fr_dict_attr_t const * fr_dict_attr_iterate_children(fr_dict_attr_t const *parent, fr_dict_attr_t const **prev)
Iterate over children of a DA.
Definition: dict_util.c:4290
fr_dict_enum_value_t * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict_util.c:2946
static int8_t dict_vendor_name_cmp(void const *one, void const *two)
Compare two attribute names.
Definition: dict_util.c:211
fr_slen_t fr_dict_attr_search_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *name, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition: dict_util.c:2572
int dict_attr_add_to_namespace(fr_dict_attr_t const *parent, fr_dict_attr_t *da)
Add an attribute to the name table for an attribute.
Definition: dict_util.c:1145
void fr_dict_global_ctx_set(fr_dict_gctx_t const *gctx)
Set a new, active, global dictionary context.
Definition: dict_util.c:4047
int fr_dl_dict_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically load dictionaries required by modules.
Definition: dict_util.c:3850
static int8_t dict_attr_name_cmp(void const *one, void const *two)
Compare two attribute names.
Definition: dict_util.c:185
static int8_t dict_vendor_pen_cmp(void const *one, void const *two)
Compare two vendor numbers.
Definition: dict_util.c:233
static int8_t dict_enum_value_cmp(void const *one, void const *two)
Compare two dictionary enum values.
Definition: dict_util.c:284
static void hash_pool_free(void *to_free)
Definition: dict_util.c:92
static uint32_t dict_attr_name_hash(void const *data)
Wrap name hash function for fr_dict_attr_t.
Definition: dict_util.c:173
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
bool const fr_dict_enum_allowed_chars[UINT8_MAX+1]
Characters allowed in enumeration value names.
Definition: dict_util.c:66
static int _fr_dict_autoload_talloc_free(fr_dict_autoload_talloc_t const *to_free)
Talloc destructor to automatically free dictionaries.
Definition: dict_util.c:3762
fr_slen_t fr_dict_attr_search_by_qualified_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by a dictionary qualified OID string.
Definition: dict_util.c:2630
static fr_slen_t dict_attr_search(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign, dict_attr_resolve_func_t func)
Internal function for searching for attributes in multiple dictionaries.
Definition: dict_util.c:2357
fr_dict_t * dict_by_protocol_name(char const *name)
Internal version of fr_dict_by_protocol_name.
Definition: dict_util.c:2105
int fr_dict_enum_add_name_next(fr_dict_attr_t *da, char const *name)
Add an name to an integer attribute hashing the name for the integer value.
Definition: dict_util.c:1547
int dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child)
Add a child to a parent.
Definition: dict_util.c:1046
static int dict_attr_children_init(fr_dict_attr_t **da_p)
Add a child/nesting extension to an attribute.
Definition: dict_util.c:380
fr_dict_autoload_t load[2]
Autoloader def.
Definition: dict_util.c:3754
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:3581
int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
Decrement ref count for a dependent in a dictionary.
Definition: dict_util.c:3262
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:2203
int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
Process a single OID component.
Definition: dict_util.c:1674
fr_slen_t fr_dict_enum_by_name_substr(fr_dict_enum_value_t **out, fr_dict_attr_t const *da, fr_sbuff_t *in)
Definition: dict_util.c:3018
static int8_t dict_enum_name_cmp(void const *one, void const *two)
Compare two dictionary attribute enum values.
Definition: dict_util.c:254
void fr_dict_global_ctx_perm_check(fr_dict_gctx_t *gctx, bool enable)
Set whether we check dictionary file permissions.
Definition: dict_util.c:4038
void fr_dict_global_ctx_read_only(void)
Mark all dictionaries and the global dictionary ctx as read only.
Definition: dict_util.c:4097
fr_dict_t * dict_alloc(TALLOC_CTX *ctx)
Allocate a new dictionary.
Definition: dict_util.c:3428
int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
Add a vendor to the dictionary.
Definition: dict_util.c:930
static int _dict_global_free(fr_dict_gctx_t *gctx)
Definition: dict_util.c:3908
static int8_t dict_protocol_name_cmp(void const *one, void const *two)
Compare two protocol names.
Definition: dict_util.c:139
static int dict_attr_enumv_init(fr_dict_attr_t **da_p)
Initialise a per-attribute enumeration table.
Definition: dict_util.c:466
int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:3565
int fr_dl_dict_enum_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
Callback to automatically resolve enum values.
Definition: dict_util.c:3818
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3647
fr_slen_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
Look up a protocol name embedded in another string.
Definition: dict_util.c:2094
int fr_dict_dependent_add(fr_dict_t const *dict, char const *dependent)
Manually increase the reference count for a dictionary.
Definition: dict_util.c:3247
static int8_t dict_protocol_num_cmp(void const *one, void const *two)
Compare two protocol numbers.
Definition: dict_util.c:160
static uint32_t dict_protocol_name_hash(void const *data)
Wrap name hash function for fr_dict_protocol_t.
Definition: dict_util.c:127
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:2878
bool fr_dict_is_read_only(fr_dict_t const *dict)
Definition: dict_util.c:2002
static uint32_t dict_hash_name(char const *name, size_t len)
Apply a simple (case insensitive) hashing function to the name of an attribute, vendor or protocol.
Definition: dict_util.c:104
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition: dict_util.c:2992
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
#define FNV_MAGIC_INIT
Definition: dict_util.c:89
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition: dict_util.c:4179
static int dict_attr_namespace_init(fr_dict_attr_t **da_p)
Initialise a per-attribute namespace.
Definition: dict_util.c:482
fr_dict_autoload_talloc_t * _fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent)
Autoload a dictionary and bind the lifetime to a talloc chunk.
Definition: dict_util.c:3780
static int _dict_attr_free(fr_dict_attr_t *da)
Definition: dict_util.c:625
int fr_dict_global_ctx_free(fr_dict_gctx_t const *gctx)
Explicitly free all data associated with a global dictionary context.
Definition: dict_util.c:4063
int dict_dlopen(fr_dict_t *dict, char const *name)
Definition: dict_util.c:3152
fr_dict_vendor_t const * fr_dict_vendor_by_da(fr_dict_attr_t const *da)
Look up a vendor by one of its child attributes.
Definition: dict_util.c:2232
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:751
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
Locate a fr_dict_attr_t by its name.
Definition: dict_util.c:2860
fr_slen_t(* dict_attr_resolve_func_t)(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Callback function for resolving dictionary attributes.
Definition: dict_util.c:2337
static fr_dict_attr_t const * dict_attr_alias(fr_dict_attr_err_t *err, fr_dict_attr_t const *da)
Resolve an alias attribute to the concrete attribute it points to.
Definition: dict_util.c:302
fr_dict_t * fr_dict_global_ctx_iter_next(fr_dict_global_ctx_iter_t *iter)
Definition: dict_util.c:4168
int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
Process a dict_autoload element to load a protocol.
Definition: dict_util.c:3696
int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool takes_precedence, fr_dict_attr_t const *child_struct)
Definition: dict_util.c:1346
fr_slen_t fr_dict_attr_search_by_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_t const *dict_def, fr_sbuff_t *in, fr_sbuff_term_t const *tt, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by a dictionary using a non-qualified OID string.
Definition: dict_util.c:2659
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition: dict_util.c:4214
fr_slen_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *name, UNUSED fr_sbuff_term_t const *tt)
Look up a dictionary attribute by a name embedded in another string.
Definition: dict_util.c:2729
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
int dict_dependent_add(fr_dict_t *dict, char const *dependent)
Record a new dependency on a dictionary.
Definition: dict_util.c:3203
fr_dict_attr_t * dict_attr_alloc(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *name, int attr, fr_type_t type, dict_attr_args_t const *args)
Allocate a dictionary attribute on the heap.
Definition: dict_util.c:697
fr_dict_vendor_t const * fr_dict_vendor_by_name(fr_dict_t const *dict, char const *name)
Look up a vendor by its name.
Definition: dict_util.c:2254
static int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
Set a dictionary attribute's name.
Definition: dict_util.c:327
fr_slen_t fr_dict_oid_component(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Parse an OID component, resolving it to a defined attribute.
Definition: dict_util.c:1823
fr_dict_protocol_t const * fr_dict_protocol(fr_dict_t const *dict)
Return the protocol descriptor for the dictionary.
Definition: dict_util.c:4537
static int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
Cache the vendor pointer for an attribute.
Definition: dict_util.c:416
static uint32_t dict_enum_name_hash(void const *data)
Hash a enumeration name.
Definition: dict_util.c:244
int dict_protocol_add(fr_dict_t *dict)
Add a protocol to the global protocol table.
Definition: dict_util.c:858
static uint32_t dict_enum_value_hash(void const *data)
Hash a dictionary enum value.
Definition: dict_util.c:274
bool dict_has_dependents(fr_dict_t *dict)
Check if a dictionary still has dependents.
Definition: dict_util.c:3294
fr_dict_gctx_t * dict_gctx
Top level structure containing global dictionary state.
Definition: dict_util.c:40
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:804
char const * dependent
Dependent that loaded the dictionary.
Definition: dict_util.c:3755
char const * fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the name of an enum value in a fr_dict_attr_t.
Definition: dict_util.c:2979
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Definition: dict_util.c:3984
static int dict_attr_ref_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *ref)
Set a reference for a grouping attribute or an alias attribute.
Definition: dict_util.c:397
fr_dict_attr_t * dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
Definition: dict_util.c:2814
fr_dict_attr_t const * fr_dict_attr_search_by_qualified_oid(fr_dict_attr_err_t *err, fr_dict_t const *dict_def, char const *name, bool internal, bool foreign)
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
Definition: dict_util.c:2678
Structure used to managed the lifetime of a dictionary.
Definition: dict_util.c:3753
dl_loader_t * dl_loader_init(TALLOC_CTX *ctx, void *uctx, bool uctx_free, bool defer_symbol_init)
Initialise structures needed by the dynamic linker.
Definition: dl.c:885
dl_t * dl_by_name(dl_loader_t *dl_loader, char const *name, void *uctx, bool uctx_free)
Search for a dl's shared object in various locations.
Definition: dl.c:470
int dl_symbol_init_cb_register(dl_loader_t *dl_loader, unsigned int priority, char const *symbol, dl_onload_t func, void *uctx)
Register a callback to execute when a dl with a particular symbol is first loaded.
Definition: dl.c:321
int dl_free(dl_t const *dl)
"free" a dl handle, possibly actually freeing it, and unloading the library
Definition: dl.c:678
void * uctx
API client's opaque data.
Definition: dl.h:65
Module handle.
Definition: dl.h:58
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition: hash.c:672
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:620
void * fr_hash_table_find(fr_hash_table_t *ht, void const *data)
Find data in a hash table.
Definition: hash.c:428
uint32_t fr_hash(void const *data, size_t size)
Definition: hash.c:806
bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
Insert data into a hash table.
Definition: hash.c:466
int fr_hash_table_flatten(TALLOC_CTX *ctx, void **out[], fr_hash_table_t *ht)
Copy all entries out of a hash table into an array.
Definition: hash.c:689
uint32_t fr_hash_string(char const *p)
Definition: hash.c:859
bool fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
Remove and free data (if a free function was specified)
Definition: hash.c:589
void fr_hash_table_verify(fr_hash_table_t *ht)
Check hash table is sane.
Definition: hash.c:889
int fr_hash_table_replace(void **old, fr_hash_table_t *ht, void const *data)
Replace old data with new data, OR insert if there is no old.
Definition: hash.c:525
#define fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node)
Definition: hash.h:58
#define fr_hash_table_talloc_alloc(_ctx, _type, _hash_node, _cmp_node, _free_node)
Definition: hash.h:61
Stores the state of the current iteration operation.
Definition: hash.h:41
static fr_table_num_ordered_t const subtype_table[]
Definition: base.c:296
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_INT64
64 Bit signed integer.
Definition: merged_model.c:106
@ FR_TYPE_INT16
16 Bit signed integer.
Definition: merged_model.c:104
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
ssize_t fr_sbuff_out_bstrncpy_exact(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Definition: merged_model.c:142
char * p
Definition: merged_model.c:38
unsigned char uint8_t
Definition: merged_model.c:30
ssize_t fr_slen_t
Definition: merged_model.c:35
unsigned long int size_t
Definition: merged_model.c:25
#define UINT8_MAX
Definition: merged_model.c:32
fr_sbuff_parse_error_t
Definition: merged_model.c:45
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
Definition: merged_model.c:47
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
Definition: merged_model.c:50
@ FR_SBUFF_PARSE_OK
No error.
Definition: merged_model.c:46
@ FR_SBUFF_PARSE_ERROR_TRAILING
Trailing characters found.
Definition: merged_model.c:49
size_t fr_sbuff_out_bstrncpy_allowed(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, bool const allowed[static UINT8_MAX+1])
Definition: merged_model.c:151
static size_t array[MY_ARRAY_SIZE]
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:36
int strcasecmp(char *s1, char *s2)
Definition: missing.c:66
static bool attr_valid(UNUSED fr_dict_t *dict, UNUSED fr_dict_attr_t const *parent, UNUSED char const *name, UNUSED int attr, fr_type_t type, fr_dict_attr_flags_t *flags)
Definition: base.c:689
static bool done
Definition: radclient.c:80
static char const * proto(int id, int porttype)
Definition: radwho.c:85
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition: rb.c:775
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition: rb.c:844
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition: rb.c:736
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition: rb.c:818
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition: rb.c:576
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition: rb.h:271
Iterator structure for in-order traversal of an rbtree.
Definition: rb.h:321
static request_init_args_t default_args
Definition: request.c:30
static unsigned int hash(char const *username, unsigned int tablesize)
Definition: rlm_passwd.c:132
static char const * name
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
Definition: sbuff.c:2111
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition: sbuff.c:1811
fr_table_num_ordered_t const sbuff_parse_error_table[]
Definition: sbuff.c:35
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
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:2047
bool const sbuff_char_alpha_num[UINT8_MAX+1]
Definition: sbuff.c:87
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
#define fr_sbuff_is_alpha(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_len(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
Set of terminal elements.
Definition: merged_model.c:161
fr_assert(0)
fr_aka_sim_id_type_t type
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition: talloc.c:333
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
#define talloc_get_type_abort_const
Definition: talloc.h:270
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:212
@ T_OP_CMP_EQ
Definition: token.h:106
static fr_slen_t parent
Definition: pair.h:844
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
bool const fr_type_structural[FR_TYPE_MAX+1]
Definition: types.c:183
#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
#define fr_type_is_structural(_x)
Definition: types.h:371
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition: value.c:6077
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition: value.c:3301
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:640
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3689
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
Definition: value.c:884
void fr_value_box_increment(fr_value_box_t *vb)
Increment a boxed value.
Definition: value.c:4597
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static fr_slen_t data
Definition: value.h:1259
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279
static size_t char ** out
Definition: value.h:984