The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
23RCSID("$Id: 06124fe02b3d45e7e2f7a4508bda0b11c07dbe4f $")
24
25#include <freeradius-devel/util/dict_priv.h>
26
28{
29 flags->is_unknown = true;
30
31 if (parent->flags.local) {
32 fr_strerror_printf("Cannot create 'raw' attribute of data type '%s' which is a local variable",
34 return -1;
35 }
36
37 if (parent->flags.internal) {
38 fr_strerror_printf("Cannot create 'raw' attribute of data type '%s' which is 'internal'",
40 return -1;
41 }
42
43 if ((parent->type == FR_TYPE_UNION) && (type != FR_TYPE_OCTETS)) {
44 fr_strerror_printf("Cannot create 'raw' attribute of data type '%s' which has parent data type 'union'",
46 return -1;
47 }
48
49 if (parent->depth >= FR_DICT_MAX_TLV_STACK) {
50 fr_strerror_const("Attribute depth is too large");
51 return -1;
52 }
53
54 /*
55 * If we are leveraging an existing attribute, then do some additional checks.
56 */
57 if (da) {
58 if (da->flags.internal) {
59 fr_strerror_printf("Cannot create unknown attribute from internal attribute %s", da->name);
60 return -1;
61 }
62
63 /*
64 * @todo - do we actually care about this?
65 *
66 * If we fix the unknown allocations to always use the raw number as the name, then it
67 * should be fine to change the data types.
68 */
69 if (type != FR_TYPE_OCTETS) {
70 if (da->type != type) {
71 fr_strerror_printf("Cannot allocate unknown attribute (%s) which changes data type from '%s' to '%s'",
72 da->name,
73 fr_type_to_str(da->type),
75 return -1;
76 }
77 }
78 }
79
80 /*
81 * Ensure that raw members of a structure have the correct length.
82 */
83 if (parent->type == FR_TYPE_STRUCT) {
84 if (!da) {
85 fr_strerror_printf("Cannot create 'raw' attribute of data type '%s' which has parent data type 'struct'",
87 return -1;
88 }
89
90 if (fr_type_is_leaf(da->type)) {
91 if (fr_type_is_structural(type)) goto cannot_change_type;
92
93 fr_assert(da->flags.is_known_width);
94
95 flags->is_known_width = true;
96 flags->length = da->flags.length;
97
98 } else if (da->type != type) {
99 cannot_change_type:
100 /*
101 * @todo - why not? So long as the size is the same...
102 */
103 fr_strerror_printf("Cannot create 'raw' attribute in 'struct' which changes data type from '%s' to '%s'",
105 return -1;
106 }
107 }
108
109 return 0;
110}
111
112/** Converts an unknown to a known by adding it to the internal dictionaries.
113 *
114 * Does not free old #fr_dict_attr_t, that is left up to the caller.
115 *
116 * @param[in] dict of protocol context we're operating in.
117 * If NULL the internal dictionary will be used.
118 * @param[in] unknown attribute to add.
119 * @return
120 * - Existing #fr_dict_attr_t if unknown was found in a dictionary.
121 * - A new entry representing unknown.
122 */
124{
125 fr_dict_attr_t const *da;
126 fr_dict_attr_t const *parent;
128
129 if (unlikely(dict->read_only)) {
130 fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
131 return NULL;
132 }
133
134#ifdef STATIC_ANALYZER
135 if (!unknown->name || !unknown->parent) return NULL;
136#endif
137
138 da = fr_dict_attr_by_name(NULL, unknown->parent, unknown->name);
139 if (da) {
140 if (da->attr == unknown->attr) return da;
141
142 fr_strerror_printf("Unknown attribute '%s' conflicts with existing attribute in namespace '%s'",
143 da->name, unknown->parent->name);
144 return da;
145 }
146
147 /*
148 * Define the complete unknown hierarchy
149 */
150 if (unknown->parent && unknown->parent->flags.is_unknown) {
151 parent = fr_dict_attr_unknown_add(dict, unknown->parent);
152 if (!parent) {
153 fr_strerror_printf_push("Failed adding parent \"%s\"", unknown->parent->name);
154 return NULL;
155 }
156 } else {
157 parent = unknown->parent;
158 }
159
160 memcpy(&flags, &unknown->flags, sizeof(flags));
161 flags.is_unknown = 0;
162
163 /*
164 * If this is a vendor, we skip most of the sanity
165 * checks and add it to the vendor hash, and add it
166 * as a child attribute to the Vendor-Specific
167 * container.
168 */
169 if (unknown->type == FR_TYPE_VENDOR) {
171
172 if (dict_vendor_add(dict, unknown->name, unknown->attr) < 0) return NULL;
173
174 n = dict_attr_alloc(dict->pool, parent, unknown->name, unknown->attr, unknown->type,
175 &(dict_attr_args_t){ .flags = &flags });
176 if (unlikely(!n)) return NULL;
177
178 /*
179 * Setup parenting for the attribute
180 */
181 if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, unknown->parent), n) < 0) return NULL;
182
183 return n;
184 }
185
186 /*
187 * Look up the attribute by number. If it doesn't exist,
188 * add it both by name and by number. If it does exist,
189 * add it only by name.
190 */
191 da = fr_dict_attr_child_by_num(parent, unknown->attr);
192 if (da) {
194
195 n = dict_attr_alloc(dict->pool, parent, unknown->name, unknown->attr, unknown->type,
196 &(dict_attr_args_t){ .flags = &flags });
197 if (!n) return NULL;
198
199 /*
200 * Add the unknown by NAME. e.g. if the admin does "Attr-26", we want
201 * to return "Attr-26", and NOT "Vendor-Specific". The rest of the server
202 * is responsible for converting "Attr-26 = 0x..." to an actual attribute,
203 * if it so desires.
204 */
206 talloc_free(n);
207 return NULL;
208 }
209
210 return n;
211 }
212
213 /*
214 * Add the attribute by both name and number.
215 *
216 * Fixme - Copy extensions?
217 */
218 if (fr_dict_attr_add(dict, parent, unknown->name, unknown->attr, unknown->type, &flags) < 0) return NULL;
219
220 /*
221 * For paranoia, return it by name.
222 */
223 return fr_dict_attr_by_name(NULL, parent, unknown->name);
224}
225
226/** Free dynamically allocated (unknown attributes)
227 *
228 * If the da was dynamically allocated it will be freed, else the function
229 * will return without doing anything.
230 *
231 * @param[in] da to free.
232 */
234{
235 if (!da || !*da) return;
236
237 /* Don't free real DAs */
238 if (!(*da)->flags.is_unknown) {
239 return;
240 }
241
243
244 *da = NULL;
245}
246
247/** Allocate an unknown DA.
248 *
249 */
251{
253 fr_dict_attr_t const *parent;
254 fr_dict_attr_flags_t flags = {};
255
256 fr_assert(!da->flags.is_root); /* cannot copy root attributes */
257 fr_assert(da->parent);
258
259 switch (type) {
260 case FR_TYPE_LEAF:
261 case FR_TYPE_GROUP:
262 case FR_TYPE_TLV:
263 case FR_TYPE_VSA:
264 case FR_TYPE_VENDOR:
265 break;
266
267 default:
268 fr_strerror_printf("Invalid data type '%s' for unknown attribute", fr_type_to_str(type));
269 return NULL;
270 }
271
272 switch (da->type) {
273 case FR_TYPE_LEAF:
275 break;
276
277 default:
278 fr_strerror_printf("Cannot create unknown attribute from data type '%s'", fr_type_to_str(da->type));
279 return NULL;
280 }
281
282 if (dict_attr_unknown_init(da->parent, da, type, &flags)) return NULL;
283
284 /*
285 * Set the unknown flags. Note that we don't copy any other flags, as they are all likely to be wrong.
286 */
287 flags.is_raw = 1;
288
289 /*
290 * Allocate an attribute.
291 */
292 n = dict_attr_alloc_null(ctx, da->dict->proto);
293 if (!n) return NULL;
294
295 /*
296 * We want to have parent / child relationships, AND to
297 * copy all unknown parents, AND to free the unknown
298 * parents when this 'da' is freed. We therefore talloc
299 * the parent from the 'da'.
300 */
301 if (da->parent->flags.is_unknown) {
302 parent = fr_dict_attr_unknown_copy(n, da->parent);
303 if (!parent) {
304 error:
305 talloc_free(n);
306 return NULL;
307 }
308
309 } else {
310 parent = da->parent;
311 }
312
313 /*
314 * Initialize the rest of the fields.
315 */
316 if (dict_attr_init(&n, parent, da->name, da->attr, type, &(dict_attr_args_t){ .flags = &flags }) < 0) {
317 goto error;
318 }
319
320 /*
321 * Copy protocol-specific extents, and hope to heck that the protocol encoder knows what it's doing.
322 */
325 goto error;
326 }
327
328 /*
329 * Do NOT copy extents. The name and da_stack extents are already defined. We do NOT copy
330 * existing children, references, keys, enumv, etc. If the unknown attribute is a group, it's
331 * ref is already set to the root, or to a copy of the input DA. If the unknown attribute is a
332 * TLV, then it cannot have known children. If an unknown attribute is a leaf, then it cannot
333 * have known enums.
334 */
335
336 DA_VERIFY(n);
337
338 return n;
339}
340
341/** Copy a known or unknown attribute to produce an unknown attribute with the specified name
342 *
343 * Will copy the complete hierarchy down to the first known attribute.
344 */
346{
347 fr_type_t type = da->type;
348
349 /*
350 * VENDOR, etc. are logical containers, and can have
351 * unknown children, so they're left alone. All other
352 * base types are mangled to OCTETs.
353 *
354 * Note that we can't allocate an unknown STRUCT. If the
355 * structure is malformed, then it's just a sequence of
356 * OCTETS. Similarly, if a GROUP is malformed, then we
357 * have no idea what's inside of it, and we make it OCTETS.
358 */
359 if (!da->flags.is_unknown) switch (type) {
360 case FR_TYPE_VENDOR:
361 fr_assert(da->flags.type_size != 0);
362 break;
363
364 case FR_TYPE_TLV:
365 case FR_TYPE_VSA:
366 break;
367
368 default:
370 break;
371 }
372
373 return fr_dict_attr_unknown_alloc(ctx, da, type);
374}
375
376/** Initialise a fr_dict_attr_t from a number and a data type
377 *
378 * @param[in] ctx to allocate the attribute in.
379 * @param[in] parent of the unknown attribute (may also be unknown).
380 * @param[in] num of the unknown attribute.
381 * @param[in] type data type
382 * @param[in] raw is it raw, i.e. _bad_ value, versus unknown?
383 * @return
384 * - An fr_dict_attr_t on success.
385 * - NULL on failure.
386 */
388{
389 fr_dict_attr_flags_t flags = {
390 .is_raw = raw,
391 };
392 fr_dict_attr_t const *da = NULL;
393
394 if (parent->flags.internal) {
395 fr_strerror_printf("Cannot create 'raw' attribute from internal parent '%s' of data type '%s'",
396 parent->name, fr_type_to_str(parent->type));
397 return NULL;
398 }
399
400 if (((parent->type == FR_TYPE_TLV) || (parent->type == FR_TYPE_VENDOR))) {
401 if ((uint64_t) num >= ((uint64_t) 1 << (8 * parent->flags.type_size))) {
402 fr_strerror_printf("Invalid attribute number '%u' - it must be no more than %u bits in size",
403 num, 8 * parent->flags.type_size);
404 return NULL;
405 }
406 }
407
408 switch (type) {
409 default:
410 fr_strerror_printf("Cannot allocate unknown attribute '%u' - invalid data type '%s'",
411 num, fr_type_to_str(type));
412 return NULL;
413
414 case FR_TYPE_VENDOR:
415 if (parent->type != FR_TYPE_VSA) goto fail;
416
417 if (parent->flags.is_unknown) goto fail;
418 break;
419
420 case FR_TYPE_LEAF:
421 case FR_TYPE_TLV:
422 case FR_TYPE_VSA:
424 fail:
425 fr_strerror_printf("Cannot allocate unknown attribute '%u' data type '%s' with parent %s data type '%s'",
426 num, fr_type_to_str(type),
427 parent->name, fr_type_to_str(parent->type));
428 return NULL;
429 }
430
431 /*
432 * We can convert anything to 'octets'.
433 */
434 if (type == FR_TYPE_OCTETS) break;
435
436 /*
437 * But we shouldn't be able to create a raw attribute which is a _different_ type than an
438 * existing one.
439 */
441 break;
442 }
443
444 if (dict_attr_unknown_init(parent, da, type, &flags)) return NULL;
445
446 return dict_attr_alloc(ctx, parent, NULL, num, type,
447 &(dict_attr_args_t){ .flags = &flags });
448}
449
450/** Create a fr_dict_attr_t from an ASCII attribute and value
451 *
452 * Where the attribute name is in the form:
453 * - %d
454 * - %d.%d.%d...
455 *
456 * @note If vendor != 0, an unknown vendor (may) also be created, parented by
457 * the correct VSA attribute. This is accessible via vp->parent,
458 * and will be use the unknown da as its talloc parent.
459 *
460 * @param[in] ctx to alloc new attribute in.
461 * @param[out] out Where to write the head of the chain unknown
462 * dictionary attributes.
463 * @param[in] parent Attribute to use as the root for resolving OIDs in.
464 * Usually the root of a protocol dictionary.
465 * @param[in] in OID string to parse
466 * @param[in] type data type of the unknown attribute
467 * @return
468 * - The number of bytes parsed on success.
469 * - <= 0 on failure. Negative offset indicates parse error position.
470 */
472 fr_dict_attr_t const **out,
473 fr_dict_attr_t const *parent,
475{
476 fr_sbuff_t our_in = FR_SBUFF(in);
477 fr_dict_attr_t const *our_parent = parent;
478 fr_dict_attr_t *n = NULL;
479 int depth;
480 fr_dict_attr_flags_t flags = { .is_raw = true, };
481
482 *out = NULL;
483
484 /*
485 * Allocate the final attribute first, so that any
486 * unknown parents can be freed when this da is freed.
487 *
488 * See fr_dict_attr_unknown_afrom_da() for more details.
489 *
490 * Note also that we copy the input name, even if it is
491 * not normalized.
492 *
493 * While the name of this attribute is "Attr-#.#.#", one
494 * or more of the leading components may, in fact, be
495 * known.
496 */
497 n = dict_attr_alloc_null(ctx, parent->dict->proto);
498
499 /*
500 * Loop until there's no more component separators.
501 */
502 for (depth = 0; depth < FR_DICT_MAX_TLV_STACK; depth++) {
503 uint32_t num;
505
506 /*
507 * Cannot create attributes that are too deeply nested.
508 */
509 if ((depth + parent->depth) >= FR_DICT_MAX_TLV_STACK) {
510 fr_strerror_printf("Attribute depth (%u) is too large", depth + parent->depth);
511 goto error;
512 }
513
514 fr_sbuff_out(&sberr, &num, &our_in);
515 switch (sberr) {
517 switch (our_parent->type) {
518 /*
519 * If the parent is a VSA, this component
520 * must specify a vendor.
521 */
522 case FR_TYPE_VSA:
523 {
524 fr_dict_attr_t *ni;
525
526 if (fr_sbuff_next_if_char(&our_in, '.')) {
527 ni = fr_dict_attr_unknown_vendor_afrom_num(n, our_parent, num);
528 if (!ni) {
529 error:
530 talloc_free(n);
531 FR_SBUFF_ERROR_RETURN(&our_in);
532 }
533 our_parent = ni;
534 continue;
535 }
536 if (dict_attr_init(&n, our_parent, NULL, num, FR_TYPE_VENDOR,
537 &(dict_attr_args_t){ .flags = &flags }) < 0) goto error;
538 }
539 break;
540
541 /*
542 * If it's structural, this component must
543 * specify a TLV.
544 */
546 {
547 fr_dict_attr_t *ni;
548
549 if (fr_sbuff_next_if_char(&our_in, '.')) {
550 ni = fr_dict_attr_unknown_typed_afrom_num(n, our_parent, num, FR_TYPE_TLV);
551 if (!ni) goto error;
552 our_parent = ni;
553 continue;
554 }
555 }
557
558 default:
559 /*
560 * Leaf type with more components
561 * is an error.
562 */
563 if (fr_sbuff_is_char(&our_in, '.')) {
564 fr_strerror_printf("Interior OID component cannot proceed a %s type",
565 fr_type_to_str(our_parent->type));
566 goto error;
567 }
568
569 if (dict_attr_unknown_init(our_parent, NULL, type, &flags)) goto error;
570
571 if (dict_attr_init(&n, our_parent, NULL, num, type,
572 &(dict_attr_args_t){ .flags = &flags }) < 0) goto error;
573 break;
574 }
575 break;
576
578 {
579 fr_sbuff_marker_t c_start;
580
581 fr_sbuff_marker(&c_start, &our_in);
583 fr_strerror_printf("Invalid value \"%.*s\" - attribute numbers must be less than 2^32",
584 (int)fr_sbuff_behind(&c_start), fr_sbuff_current(&c_start));
585 goto error;
586 }
587
588 default:
589 {
590 size_t len;
591 fr_sbuff_marker_t c_start;
592
593 fr_sbuff_marker(&c_start, &our_in);
595
596 /*
597 * If we saw no valid characters at the start, it's a bad attribute name.
598 *
599 * If we saw valid characters but didn't parse them into an attribute name, it's
600 * a bad attribute name.
601 *
602 * Otherwise we parsed at least one attribute, and then ran out of valid
603 * attribute characters to parse. The result must be OK.
604 *
605 * This check is here really only because there's a lot of code which parses
606 * attributes, but does not properly set either the buffer size to be _just_ the
607 * attribute name, OR the set of terminal characters. This means that the
608 * attribute parsing code can't error out if there are invalid characters after a
609 * valid attribute name. Instead, the caller has to check the return code.
610 */
611 if (((depth == 0) && (len == 0)) || ((depth > 0) && (len > 0))) {
612 fr_strerror_printf("Unknown attribute \"%.*s\" for parent \"%s\"",
613 (int)fr_sbuff_behind(&c_start), fr_sbuff_current(&c_start), our_parent->name);
614 goto error;
615 }
616 }
617 }
618 break;
619 }
620
621 DA_VERIFY(n);
622
623 *out = n;
624
625 FR_SBUFF_SET_RETURN(in, &our_in);
626}
627
628/** Fixup the parent of an unknown attribute using an equivalent known attribute
629 *
630 * This can be useful where an unknown attribute's ancestors are added to
631 * a dictionary but not the unknown attribute itself.
632 *
633 * @param[in] da to fixup.
634 * @param[in] parent to assign. If NULL, we will attempt to resolve
635 * the parent in the dictionary the current unknown
636 * attribute extends.
637 * @return
638 * - 0 on success.
639 * - -1 on failure.
640 */
642{
643 fr_dict_attr_t const *da_u, *da_k;
644
645 if (parent) {
646 /*
647 * Walk back up the hierarchy until we get to a known
648 * ancestor on the unknown side.
649 */
650 for (da_u = da->parent, da_k = parent;
651 da_k && da_u && da_u->flags.is_unknown;
652 da_u = da_u->parent, da_k = da_k->parent) {
653 if (unlikely(da_u->attr != da_k->attr)) {
654 fr_strerror_printf("Unknown parent number %u does not match "
655 "known parent number %u (%s)",
656 da_u->attr, da_k->attr, da_k->name);
657 return -1;
658 }
659
660 if (unlikely(da_u->depth != da_k->depth)) {
661 fr_strerror_printf("Unknown parent depth %u does not match "
662 "known parent depth %u (%s)",
663 da_u->depth, da_k->depth, da_k->name);
664 return -1;
665 }
666 }
667 if ((da_k == NULL) != (da_u == NULL)) {
668 fr_strerror_printf("Truncated or over-extended hierarchy "
669 "for unknown attribute %u", da->attr);
670 return -1;
671 }
672 } else {
674 if (!parent) {
675 fr_strerror_printf("Failed resolving unknown attribute %u "
676 "in dictionary", da->attr);
677 return -1;
678 }
679 }
680
681 da->parent = fr_dict_attr_unconst(parent);
682
683 return 0;
684}
685
686/** Check to see if we can convert a nested TLV structure to known attributes
687 *
688 * @param[in] dict to search in.
689 * @param[in] da Nested tlv structure to convert.
690 * @return
691 * - NULL if we can't.
692 * - Known attribute if we can.
693 */
695{
696 INTERNAL_IF_NULL(dict, NULL);
697
698 if (!da->flags.is_unknown) return da; /* It's known */
699
700 if (da->parent) {
701 fr_dict_attr_t const *parent;
702
703 parent = fr_dict_attr_unknown_resolve(dict, da->parent);
704 if (!parent) return NULL;
705
706 return fr_dict_attr_child_by_num(parent, da->attr);
707 }
708
709 if (dict->root == da) return dict->root;
710 return NULL;
711}
int n
Definition acutest.h:579
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
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:2875
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition dict.h:606
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters allowed in a single dictionary attribute name.
Definition dict_util.c:64
static fr_dict_attr_t * fr_dict_attr_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition dict.h:586
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:3532
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition dict_util.c:4909
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
#define DA_VERIFY(_x)
Definition dict.h:68
unsigned int is_raw
This dictionary attribute was constructed from a known attribute to allow the user to assign octets v...
Definition dict.h:82
uint16_t length
length of the attribute
Definition dict.h:155
@ FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC
Protocol specific extensions.
Definition dict.h:192
unsigned int is_known_width
is treated as if it has a known width for structs
Definition dict.h:94
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:519
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags))
Add an attribute to the dictionary.
Definition dict_util.c:1969
static fr_dict_attr_t * fr_dict_attr_unknown_typed_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num, fr_type_t type)
Definition dict.h:598
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:3597
static fr_slen_t in
Definition dict.h:884
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:503
unsigned int is_unknown
This dictionary attribute is ephemeral and not part of the main dictionary.
Definition dict.h:79
Values of the encryption flags.
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:121
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.
#define dict_attr_alloc(_ctx, _parent, _name, _attr, _type, _args)
Definition dict_priv.h:255
#define INTERNAL_IF_NULL(_dict, _ret)
Set the internal dictionary if none was provided.
Definition dict_priv.h:45
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:1781
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:1682
int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
Add a vendor to the dictionary.
Definition dict_util.c:1587
#define dict_attr_init(_da_p, _parent, _name, _attr, _type, _args)
Full initialisation functions.
Definition dict_priv.h:231
fr_dict_attr_t * dict_attr_alloc_null(TALLOC_CTX *ctx, fr_dict_protocol_t const *dict)
Partial initialisation functions.
Definition dict_util.c:994
Optional arguments for initialising/allocating attributes.
Definition dict_priv.h:191
fr_slen_t fr_dict_attr_unknown_afrom_oid_substr(TALLOC_CTX *ctx, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_type_t type)
Create a fr_dict_attr_t from an ASCII attribute and value.
fr_dict_attr_t * fr_dict_attr_unknown_alloc(TALLOC_CTX *ctx, fr_dict_attr_t const *da, fr_type_t type)
Allocate an unknown DA.
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.
fr_dict_attr_t * fr_dict_attr_unknown_typed_afrom_num_raw(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num, fr_type_t type, bool raw)
Initialise a fr_dict_attr_t from a number and a data type.
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.
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
fr_dict_attr_t const * fr_dict_attr_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.
fr_dict_attr_t * fr_dict_attr_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.
static int dict_attr_unknown_init(fr_dict_attr_t const *parent, UNUSED fr_dict_attr_t const *da, fr_type_t type, fr_dict_attr_flags_t *flags)
talloc_free(reap)
fr_type_t
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
ssize_t fr_slen_t
fr_sbuff_parse_error_t
@ FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW
Integer type would overflow.
@ FR_SBUFF_PARSE_OK
No error.
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
#define fr_assert(_expr)
Definition rad_assert.h:38
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:1805
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:2116
#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_SET_RETURN(_dst, _src)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_behind(_sbuff_or_marker)
fr_aka_sim_id_type_t type
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:229
static fr_slen_t parent
Definition pair.h:857
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_structural(_x)
Definition types.h:393
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:82
#define FR_TYPE_STRUCTURAL_EXCEPT_VSA
Definition types.h:315
#define fr_type_is_structural_except_vsa(_x)
Definition types.h:392
#define FR_TYPE_STRUCTURAL
Definition types.h:317
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define FR_TYPE_LEAF
Definition types.h:318
static size_t char ** out
Definition value.h:1023