The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
dict_unknown.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 /** Deal with 'unknown' attributes, creating ephemeral dictionary attributes for them
18  *
19  * @file src/lib/util/dict_unknown.c
20  *
21  * @copyright 2019 The FreeRADIUS server project
22  */
23 RCSID("$Id: 3565d579bb7c7962efd95c37dc41566959047daf $")
24 
25 #include <freeradius-devel/util/dict_priv.h>
26 
27 /** Converts an unknown to a known by adding it to the internal dictionaries.
28  *
29  * Does not free old #fr_dict_attr_t, that is left up to the caller.
30  *
31  * @param[in] dict of protocol context we're operating in.
32  * If NULL the internal dictionary will be used.
33  * @param[in] unknown attribute to add.
34  * @return
35  * - Existing #fr_dict_attr_t if unknown was found in a dictionary.
36  * - A new entry representing unknown.
37  */
39 {
40  fr_dict_attr_t const *da;
41  fr_dict_attr_t const *parent;
43 
44  if (unlikely(dict->read_only)) {
45  fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
46  return NULL;
47  }
48 
49 #ifdef STATIC_ANALYZER
50  if (!unknown->name || !unknown->parent) return NULL;
51 #endif
52 
53  da = fr_dict_attr_by_name(NULL, unknown->parent, unknown->name);
54  if (da) {
55  if (da->attr == unknown->attr) return da;
56 
57  fr_strerror_printf("Unknown attribute '%s' conflicts with existing attribute in context %s",
58  da->name, unknown->parent->name);
59  return da;
60  }
61 
62  /*
63  * Define the complete unknown hierarchy
64  */
65  if (unknown->parent && unknown->parent->flags.is_unknown) {
66  parent = fr_dict_unknown_add(dict, unknown->parent);
67  if (!parent) {
68  fr_strerror_printf_push("Failed adding parent \"%s\"", unknown->parent->name);
69  return NULL;
70  }
71  } else {
72  parent = unknown->parent;
73  }
74 
75  memcpy(&flags, &unknown->flags, sizeof(flags));
76  flags.is_unknown = 0;
77 
78  /*
79  * If this is a vendor, we skip most of the sanity
80  * checks and add it to the vendor hash, and add it
81  * as a child attribute to the Vendor-Specific
82  * container.
83  */
84  if (unknown->type == FR_TYPE_VENDOR) {
86 
87  if (dict_vendor_add(dict, unknown->name, unknown->attr) < 0) return NULL;
88 
89  n = dict_attr_alloc(dict->pool, parent, unknown->name, unknown->attr, unknown->type,
90  &(dict_attr_args_t){ .flags = &flags });
91  if (unlikely(!n)) return NULL;
92 
93  /*
94  * Setup parenting for the attribute
95  */
96  if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, unknown->parent), n) < 0) return NULL;
97 
98  return n;
99  }
100 
101  /*
102  * Look up the attribute by number. If it doesn't exist,
103  * add it both by name and by number. If it does exist,
104  * add it only by name.
105  */
106  da = fr_dict_attr_child_by_num(parent, unknown->attr);
107  if (da) {
108  fr_dict_attr_t *n;
109 
110  n = dict_attr_alloc(dict->pool, parent, unknown->name, unknown->attr, unknown->type,
111  &(dict_attr_args_t){ .flags = &flags });
112  if (!n) return NULL;
113 
114  /*
115  * Add the unknown by NAME. e.g. if the admin does "Attr-26", we want
116  * to return "Attr-26", and NOT "Vendor-Specific". The rest of the server
117  * is responsible for converting "Attr-26 = 0x..." to an actual attribute,
118  * if it so desires.
119  */
120  if (dict_attr_add_to_namespace(parent, n) < 0) {
121  talloc_free(n);
122  return NULL;
123  }
124 
125  return n;
126  }
127 
128  /*
129  * Add the attribute by both name and number.
130  *
131  * Fixme - Copy extensions?
132  */
133  if (fr_dict_attr_add(dict, parent, unknown->name, unknown->attr, unknown->type, &flags) < 0) return NULL;
134 
135  /*
136  * For paranoia, return it by name.
137  */
138  return fr_dict_attr_by_name(NULL, parent, unknown->name);
139 }
140 
141 /** Free dynamically allocated (unknown attributes)
142  *
143  * If the da was dynamically allocated it will be freed, else the function
144  * will return without doing anything.
145  *
146  * @param[in] da to free.
147  */
149 {
150  if (!da || !*da) return;
151 
152  /* Don't free real DAs */
153  if (!(*da)->flags.is_unknown) {
154  return;
155  }
156 
157  talloc_const_free(*da);
158 
159  *da = NULL;
160 }
161 
162 /** Allocate an unknown DA.
163  *
164  */
165 static fr_dict_attr_t *dict_unknown_alloc(TALLOC_CTX *ctx, fr_dict_attr_t const *da, fr_type_t type)
166 {
167  fr_dict_attr_t *n;
168  fr_dict_attr_t const *parent;
169  fr_dict_attr_flags_t flags = da->flags;
170 
171  fr_assert(!da->flags.is_root); /* cannot copy root attributes */
172 
173  /*
174  * Set the unknown flag, and copy only those other flags
175  * which we know to be correct.
176  */
177  flags.is_unknown = 1;
178  flags.is_raw = 1;
179  flags.array = 0;
180  flags.has_value = 0;
181  if (type != FR_TYPE_VENDOR) {
182  flags.length = 0; /* not fixed length */
183  } else {
184  flags.type_size = da->flags.type_size;
185  flags.length = da->flags.length;
186  }
187  flags.extra = 0;
188 
189  /*
190  * Allocate an attribute.
191  */
192  n = dict_attr_alloc_null(ctx);
193  if (!n) return NULL;
194 
195  /*
196  * We want to have parent / child relationships, AND to
197  * copy all unknown parents, AND to free the unknown
198  * parents when this 'da' is freed. We therefore talloc
199  * the parent from the 'da'.
200  */
201  if (da->parent && da->parent->flags.is_unknown) {
202  parent = fr_dict_unknown_copy(n, da->parent);
203  if (!parent) {
204  talloc_free(n);
205  return NULL;
206  }
207 
208  } else {
209  parent = da->parent;
210  }
211 
212  /*
213  * Initialize the rest of the fields.
214  */
215  dict_attr_init(&n, parent, da->name, da->attr, type, &(dict_attr_args_t){ .flags = &flags });
217  DA_VERIFY(n);
218 
219  return n;
220 }
221 
222 /** Copy a known or unknown attribute to produce an unknown attribute with the specified name
223  *
224  * Will copy the complete hierarchy down to the first known attribute.
225  */
227 {
228  fr_type_t type = da->type;
229 
230  /*
231  * VENDOR, etc. are logical containers, and can have
232  * unknown children, so they're left alone. All other
233  * base types are mangled to OCTETs.
234  *
235  * Note that we can't allocate an unknown STRUCT. If the
236  * structure is malformed, then it's just a sequence of
237  * OCTETS. Similarly, if a GROUP is malformed, then we
238  * have no idea what's inside of it, and we make it OCTETS.
239  */
240  switch (type) {
241  case FR_TYPE_VENDOR:
242  fr_assert(da->flags.type_size != 0);
243  break;
244 
245  case FR_TYPE_TLV:
246  case FR_TYPE_VSA:
247  break;
248 
249  default:
251  break;
252  }
253 
254  return dict_unknown_alloc(ctx, da, type);
255 }
256 
257 /** Build an unknown vendor, parented by a VSA attribute
258  *
259  * This allows us to complete the path back to the dictionary root in the case
260  * of unknown attributes with unknown vendors.
261  *
262  * @note Will return known vendors attributes where possible. Do not free directly,
263  * use #fr_dict_unknown_free.
264  *
265  * @param[in] ctx to allocate the vendor attribute in.
266  * @param[in] parent of the VSA attribute.
267  * @param[in] vendor id.
268  * @return
269  * - An fr_dict_attr_t on success.
270  * - NULL on failure.
271  */
273  fr_dict_attr_t const *parent, unsigned int vendor)
274 {
275  fr_dict_attr_flags_t flags = {
276  .is_unknown = 1,
277  .type_size = 1,
278  .length = 1,
279  .internal = parent->flags.internal,
280  };
281 
282  /*
283  * Vendor attributes can occur under VSA attribute.
284  */
285  switch (parent->type) {
286  case FR_TYPE_VSA:
287  if (!fr_cond_assert(!parent->flags.is_unknown)) return NULL;
288  return dict_attr_alloc(ctx, parent, NULL, vendor, FR_TYPE_VENDOR,
289  &(dict_attr_args_t){ .flags = &flags });
290 
291  case FR_TYPE_VENDOR:
292  if (!fr_cond_assert(!parent->flags.is_unknown)) return NULL;
293  fr_strerror_const("Unknown vendor cannot be parented by another vendor");
294  return NULL;
295 
296  default:
297  fr_strerror_printf("Unknown vendors can only be parented by a vsa, not a %s",
298  fr_type_to_str(parent->type));
299  return NULL;
300  }
301 }
302 
303 /** Initialise a fr_dict_attr_t from a number
304  *
305  * @param[in] ctx to allocate the attribute in.
306  * @param[in] parent of the unknown attribute (may also be unknown).
307  * @param[in] num of the unknown attribute.
308  * @return
309  * - An fr_dict_attr_t on success.
310  * - NULL on failure.
311  */
312 fr_dict_attr_t *fr_dict_unknown_tlv_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num)
313 {
314  fr_dict_attr_flags_t flags = {
315  .is_unknown = true,
316  .internal = parent->flags.internal,
317  };
318 
320  fr_strerror_printf("%s: Cannot allocate unknown tlv attribute (%u) with parent type %s",
321  __FUNCTION__,
322  num,
323  fr_type_to_str(parent->type));
324  return NULL;
325  }
326 
327  if (parent->depth >= FR_DICT_MAX_TLV_STACK) {
328  fr_strerror_const("Attribute depth is too large");
329  return NULL;
330  }
331 
332  return dict_attr_alloc(ctx, parent, NULL, num, FR_TYPE_TLV,
333  &(dict_attr_args_t){ .flags = &flags });
334 }
335 
336 /** Initialise a fr_dict_attr_t from a number
337  *
338  * @param[in] ctx to allocate the attribute in.
339  * @param[in] parent of the unknown attribute (may also be unknown).
340  * @param[in] num of the unknown attribute.
341  * @return
342  * - An fr_dict_attr_t on success.
343  * - NULL on failure.
344  */
345 fr_dict_attr_t *fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num)
346 {
347  fr_dict_attr_flags_t flags = {
348  .is_unknown = true,
349  .is_raw = true,
350  .internal = parent->flags.internal,
351  };
352 
354  fr_strerror_printf("%s: Cannot allocate unknown octets attribute (%u) with parent type %s",
355  __FUNCTION__,
356  num,
357  fr_type_to_str(parent->type));
358  return NULL;
359  }
360 
361  if (parent->depth >= FR_DICT_MAX_TLV_STACK) {
362  fr_strerror_const("Attribute depth is too large");
363  return NULL;
364  }
365 
366  return dict_attr_alloc(ctx, parent, NULL, num, FR_TYPE_OCTETS,
367  &(dict_attr_args_t){ .flags = &flags });
368 }
369 
370 /** Initialise an octets type attribute from a da
371  *
372  * @param[in] ctx to allocate the attribute in.
373  * @param[in] da of the unknown attribute.
374  * @return
375  * - 0 on success.
376  * - -1 on failure.
377  */
379 {
380  return dict_unknown_alloc(ctx, da, FR_TYPE_OCTETS);
381 }
382 
383 /** Create a fr_dict_attr_t from an ASCII attribute and value
384  *
385  * Where the attribute name is in the form:
386  * - %d
387  * - %d.%d.%d...
388  *
389  * @note If vendor != 0, an unknown vendor (may) also be created, parented by
390  * the correct VSA attribute. This is accessible via vp->parent,
391  * and will be use the unknown da as its talloc parent.
392  *
393  * @param[in] ctx to alloc new attribute in.
394  * @param[out] out Where to write the head of the chain unknown
395  * dictionary attributes.
396  * @param[in] parent Attribute to use as the root for resolving OIDs in.
397  * Usually the root of a protocol dictionary.
398  * @param[in] in of attribute.
399  * @return
400  * - The number of bytes parsed on success.
401  * - <= 0 on failure. Negative offset indicates parse error position.
402  */
404  fr_dict_attr_t const **out,
405  fr_dict_attr_t const *parent,
406  fr_sbuff_t *in)
407 {
408  fr_sbuff_t our_in = FR_SBUFF(in);
409  fr_dict_attr_t const *our_parent = parent;
410  fr_dict_attr_t *n = NULL;
411  fr_dict_attr_flags_t flags = {
412  .is_unknown = true,
413  .is_raw = true,
414  .type_size = parent->dict->root->flags.type_size,
415  .length = parent->dict->root->flags.length,
416  };
417 
418  *out = NULL;
419 
420  /*
421  * Allocate the final attribute first, so that any
422  * unknown parents can be freed when this da is freed.
423  *
424  * See fr_dict_unknown_afrom_da() for more details.
425  *
426  * Note also that we copy the input name, even if it is
427  * not normalized.
428  *
429  * While the name of this attribute is "Attr-#.#.#", one
430  * or more of the leading components may, in fact, be
431  * known.
432  */
433  n = dict_attr_alloc_null(ctx);
434 
435  /*
436  * Loop until there's no more component separators.
437  */
438  for (;;) {
439  uint32_t num;
441 
442  fr_sbuff_out(&sberr, &num, &our_in);
443  switch (sberr) {
444  case FR_SBUFF_PARSE_OK:
445  switch (our_parent->type) {
446  /*
447  * If the parent is a VSA, this component
448  * must specify a vendor.
449  */
450  case FR_TYPE_VSA:
451  {
452  fr_dict_attr_t *ni;
453 
454  if (fr_sbuff_next_if_char(&our_in, '.')) {
455  ni = fr_dict_unknown_vendor_afrom_num(n, our_parent, num);
456  if (!ni) {
457  error:
458  talloc_free(n);
459  FR_SBUFF_ERROR_RETURN(&our_in);
460  }
461  our_parent = ni;
462  continue;
463  }
464  if (dict_attr_init(&n, our_parent, NULL, num, FR_TYPE_VENDOR,
465  &(dict_attr_args_t){ .flags = &flags }) < 0) goto error;
466  }
467  break;
468 
469  /*
470  * If it's structural, this component must
471  * specify a TLV.
472  */
474  {
475  fr_dict_attr_t *ni;
476 
477  if (fr_sbuff_next_if_char(&our_in, '.')) {
478  ni = fr_dict_unknown_tlv_afrom_num(n, our_parent, num);
479  if (!ni) goto error;
480  our_parent = ni;
481  continue;
482  }
483  }
484  FALL_THROUGH;
485 
486  default:
487  /*
488  * Leaf type with more components
489  * is an error.
490  */
491  if (fr_sbuff_is_char(&our_in, '.')) {
492  fr_strerror_printf("Interior OID component cannot proceed a %s type",
493  fr_type_to_str(our_parent->type));
494  goto error;
495  }
496  if (dict_attr_init(&n, our_parent, NULL, num, FR_TYPE_OCTETS,
497  &(dict_attr_args_t){ .flags = &flags }) < 0) goto error;
498  break;
499  }
500  break;
501 
502  default:
503  {
504  fr_sbuff_marker_t c_start;
505 
506  fr_sbuff_marker(&c_start, &our_in);
508  fr_strerror_printf("Unknown attribute \"%.*s\" for parent \"%s\"",
509  (int)fr_sbuff_behind(&c_start), fr_sbuff_current(&c_start), our_parent->name);
510  goto error;
511  }
512  }
513  break;
514  }
515 
516  DA_VERIFY(n);
517 
518  *out = n;
519 
520  FR_SBUFF_SET_RETURN(in, &our_in);
521 }
522 
523 /** Fixup the parent of an unknown attribute using an equivalent known attribute
524  *
525  * This can be useful where an unknown attribute's ancestors are added to
526  * a dictionary but not the unknown attribute itself.
527  *
528  * @param[in] da to fixup.
529  * @param[in] parent to assign. If NULL, we will attempt to resolve
530  * the parent in the dictionary the current unknown
531  * attribute extends.
532  * @return
533  * - 0 on success.
534  * - -1 on failure.
535  */
537 {
538  fr_dict_attr_t const *da_u, *da_k;
539 
540  if (parent) {
541  /*
542  * Walk back up the hierarchy until we get to a known
543  * ancestor on the unknown side.
544  */
545  for (da_u = da->parent, da_k = parent;
546  da_k && da_u && da_u->flags.is_unknown;
547  da_u = da_u->parent, da_k = da_k->parent) {
548  if (unlikely(da_u->attr != da_k->attr)) {
549  fr_strerror_printf("Unknown parent number %u does not match "
550  "known parent number %u (%s)",
551  da_u->attr, da_k->attr, da_k->name);
552  return -1;
553  }
554 
555  if (unlikely(da_u->depth != da_k->depth)) {
556  fr_strerror_printf("Unknown parent depth %u does not match "
557  "known parent depth %u (%s)",
558  da_u->depth, da_k->depth, da_k->name);
559  return -1;
560  }
561  }
562  if ((da_k == NULL) != (da_u == NULL)) {
563  fr_strerror_printf("Truncated or over-extended hierarchy "
564  "for unknown attribute %u", da->attr);
565  return -1;
566  }
567  } else {
569  if (!parent) {
570  fr_strerror_printf("Failed resolving unknown attribute %u "
571  "in dictionary", da->attr);
572  return -1;
573  }
574  }
575 
576  da->parent = parent;
577 
578  return 0;
579 }
580 
581 /** Check to see if we can convert a nested TLV structure to known attributes
582  *
583  * @param[in] dict to search in.
584  * @param[in] da Nested tlv structure to convert.
585  * @return
586  * - NULL if we can't.
587  * - Known attribute if we can.
588  */
590 {
591  INTERNAL_IF_NULL(dict, NULL);
592 
593  if (!da->flags.is_unknown) return da; /* It's known */
594 
595  if (da->parent) {
596  fr_dict_attr_t const *parent;
597 
599  if (!parent) return NULL;
600 
601  return fr_dict_attr_child_by_num(parent, da->attr);
602  }
603 
604  if (dict->root == da) return dict->root;
605  return NULL;
606 }
int n
Definition: acutest.h:577
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 unlikely(_x)
Definition: build.h:378
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
unsigned int has_value
Has a value.
Definition: dict.h:92
static fr_dict_attr_t * fr_dict_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition: dict.h:428
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition: dict_util.c:2860
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
Definition: dict_util.c:45
unsigned int array
Pack multiples into 1 attr.
Definition: dict.h:88
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition: dict.h:109
#define DA_VERIFY(_x)
Definition: dict.h:66
unsigned int is_raw
This dictionary attribute was constructed from a known attribute to allow the user to assign octets v...
Definition: dict.h:79
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
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
uint8_t type_size
For TLV2 and root attributes.
Definition: dict.h:132
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:384
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
static fr_slen_t in
Definition: dict.h:645
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition: dict.h:364
uint8_t length
length of the attribute
Definition: dict.h:124
unsigned int is_unknown
This dictionary attribute is ephemeral and not part of the main dictionary.
Definition: dict.h:76
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
Values of the encryption flags.
Definition: merged_model.c:139
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
fr_dict_attr_t * dict_attr_alloc_null(TALLOC_CTX *ctx)
Allocate a partially completed attribute.
Definition: dict_util.c:657
#define INTERNAL_IF_NULL(_dict, _ret)
Set the internal dictionary if none was provided.
Definition: dict_priv.h:45
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
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
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
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
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
Optional arguments for initialising/allocating attributes.
Definition: dict_priv.h:167
fr_dict_attr_t * fr_dict_unknown_attr_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Initialise an octets type attribute from a da.
Definition: dict_unknown.c:378
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
fr_dict_attr_t * fr_dict_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Build an unknown vendor, parented by a VSA attribute.
Definition: dict_unknown.c:272
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num)
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
fr_dict_attr_t * fr_dict_unknown_tlv_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num)
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:312
int fr_dict_attr_unknown_parent_to_known(fr_dict_attr_t *da, fr_dict_attr_t const *parent)
Fixup the parent of an unknown attribute using an equivalent known attribute.
Definition: dict_unknown.c:536
fr_dict_attr_t const * fr_dict_unknown_add(fr_dict_t *dict, fr_dict_attr_t const *unknown)
Converts an unknown to a known by adding it to the internal dictionaries.
Definition: dict_unknown.c:38
fr_dict_attr_t * fr_dict_unknown_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Copy a known or unknown attribute to produce an unknown attribute with the specified name.
Definition: dict_unknown.c:226
fr_dict_attr_t const * fr_dict_attr_unknown_resolve(fr_dict_t const *dict, fr_dict_attr_t const *da)
Check to see if we can convert a nested TLV structure to known attributes.
Definition: dict_unknown.c:589
fr_slen_t fr_dict_unknown_afrom_oid_substr(TALLOC_CTX *ctx, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in)
Create a fr_dict_attr_t from an ASCII attribute and value.
Definition: dict_unknown.c:403
static fr_dict_attr_t * dict_unknown_alloc(TALLOC_CTX *ctx, fr_dict_attr_t const *da, fr_type_t type)
Allocate an unknown DA.
Definition: dict_unknown.c:165
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
ssize_t fr_slen_t
Definition: merged_model.c:35
fr_sbuff_parse_error_t
Definition: merged_model.c:45
@ FR_SBUFF_PARSE_OK
No error.
Definition: merged_model.c:46
static char const * name
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static UINT8_MAX+1], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition: sbuff.c:1736
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
#define fr_sbuff_current(_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_behind(_sbuff_or_marker)
fr_assert(0)
fr_aka_sim_id_type_t type
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:212
static fr_slen_t parent
Definition: pair.h:844
#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
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_STRUCTURAL_EXCEPT_VSA
Definition: types.h:294
#define fr_type_is_structural_except_vsa(_x)
Definition: types.h:370
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
static size_t char ** out
Definition: value.h:984