The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_tokenize.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/** Parse dictionary files
18 *
19 * @file src/lib/util/dict_tokenize.c
20 *
21 * @copyright 2019 The FreeRADIUS server project
22 * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24RCSID("$Id: 62708d6e458892c3e9d2ec0205a377b1db612c9a $")
25
26#include <freeradius-devel/radius/defs.h>
27#include <freeradius-devel/util/conf.h>
28#include <freeradius-devel/util/dict_fixup_priv.h>
29#include <freeradius-devel/util/file.h>
30#include <freeradius-devel/util/rand.h>
31#include <freeradius-devel/util/syserror.h>
32
33#include <sys/stat.h>
34
35/** Maximum number of arguments
36 *
37 * For any one keyword, this is the maxiumum number of arguments that can be passed.
38 */
39#define DICT_MAX_ARGV (8)
40
41/** Maximum stack size
42 *
43 * This is the maximum number of nested BEGIN and $INCLUDE statements.
44 */
45#define DICT_MAX_STACK (32)
46
47/** This represents explicit BEGIN/END frames pushed onto the stack
48 *
49 * These are flags to allow multiple nesting types to be passed to the search function.
50 */
51DIAG_OFF(attributes)
52typedef enum CC_HINT(flag_enum) {
53 NEST_NONE = 0x00,
54 NEST_ROOT = 0x01,
57 NEST_ATTRIBUTE = 0x08
59DIAG_ON(attributes)
60
62 { L("ATTRIBUTE"), NEST_ATTRIBUTE },
63 { L("NONE"), NEST_NONE },
64 { L("PROTOCOL"), NEST_PROTOCOL },
65 { L("ROOT"), NEST_ROOT },
66 { L("VENDOR"), NEST_VENDOR }
67};
69
70/** Parser context for dict_from_file
71 *
72 * Allows vendor and TLV context to persist across $INCLUDEs
73 */
74typedef struct {
75 fr_dict_t *dict; //!< The dictionary before the current BEGIN-PROTOCOL block.
76 char *filename; //!< name of the file we're reading
77 int line; //!< line number of this file
78 fr_dict_attr_t const *da; //!< the da we care about
79 dict_nest_t nest; //!< for manual vs automatic begin / end things
80 int member_num; //!< structure member numbers
81 fr_dict_attr_t const *struct_is_closed; //!< no more members are allowed
82 ssize_t struct_size; //!< size of the struct.
84
86 fr_dict_t *dict; //!< Protocol dictionary we're inserting attributes into.
87
88 dict_tokenize_frame_t stack[DICT_MAX_STACK]; //!< stack of attributes to track
89 int stack_depth; //!< points to the last used stack frame
90
91 fr_dict_attr_t *value_attr; //!< Cache of last attribute to speed up value processing.
92 fr_dict_attr_t const *relative_attr; //!< for ".82" instead of "1.2.3.82". only for parents of type "tlv"
94};
95
97 char const *dir_name, char const *filename,
98 char const *src_file, int src_line);
99
100#define CURRENT_FRAME(_dctx) (&(_dctx)->stack[(_dctx)->stack_depth])
101#define CURRENT_DA(_dctx) (CURRENT_FRAME(_dctx)->da)
102#define CURRENT_FILENAME(_dctx) (CURRENT_FRAME(_dctx)->filename)
103#define CURRENT_LINE(_dctx) (CURRENT_FRAME(_dctx)->line)
104
105#define ASSERT_CURRENT_NEST(_dctx, _nest) fr_assert_msg(CURRENT_FRAME(_dctx)->nest == (_nest), "Expected frame type %s, got %s", \
106 fr_table_str_by_value(dict_nest_table, (_nest), "<INVALID>"), fr_table_str_by_value(dict_nest_table, CURRENT_FRAME(_dctx)->nest, "<INVALID>"))
107
109{
110 int i;
111
112 for (i = 0; i <= dctx->stack_depth; i++) {
113 FR_FAULT_LOG("[%d]: %s %s (%s): %s[%d]",
114 i,
115 fr_table_str_by_value(dict_nest_table, dctx->stack[i].nest, "<INVALID>"),
116 dctx->stack[i].da->name,
117 fr_type_to_str(dctx->stack[i].da->type),
118 dctx->stack[i].filename, dctx->stack[i].line);
119 }
120}
121
123{
124 int i;
125
126 for (i = dctx->stack_depth; i >= 0; i--) {
127 if (dctx->stack[i].nest & nest) return &dctx->stack[i];
128 }
129
130 return NULL;
131}
132
134{
135 if ((dctx->stack_depth + 1) >= DICT_MAX_STACK) {
136 fr_strerror_const_push("Attribute definitions are nested too deep.");
137 return -1;
138 }
139
140 fr_assert(da != NULL);
141
142 dctx->stack[++dctx->stack_depth] = (dict_tokenize_frame_t){
143 .dict = dctx->stack[dctx->stack_depth - 1].dict,
144 .da = da,
145 .filename = dctx->stack[dctx->stack_depth - 1].filename,
146 .line = dctx->stack[dctx->stack_depth - 1].line,
147 .nest = nest
148 };
149
150 return 0;
151}
152
153/** Either updates the da in the current stack frame if 'nest' matches, or pushes a new frame of type 'nest'
154 *
155 * @param[in] dctx Stack to push to.
156 * @param[in] da Attribute to push.
157 * @param[in] nest Frame type to push.
158 * @return
159 * - 0 on success.
160 * - -1 on failure.
161 */
162static int CC_HINT(nonnull)
164{
165 if (dctx->stack[++dctx->stack_depth].nest == nest) {
166 dctx->stack[dctx->stack_depth].filename = dctx->stack[dctx->stack_depth - 1].filename;
167 dctx->stack[dctx->stack_depth].da = da;
168 return 0;
169 }
170
171 return dict_dctx_push(dctx, da, nest);
172}
173
174
175/** Pop the current stack frame
176 *
177 * @param[in] dctx Stack to pop from.
178 * @return
179 * - Pointer to the current stack frame.
180 * - NULL, if we're already at the root.
181 */
183{
184 if (dctx->stack_depth == 0) return NULL;
185
186 return &dctx->stack[dctx->stack_depth--];
187}
188
189/** Unwind the entire stack, returning the root frame
190 *
191 * @param[in] dctx Stack to unwind.
192 * @return Pointer to the root frame.
193 */
195{
196 while ((dctx->stack_depth > 0) &&
197 (dctx->stack[dctx->stack_depth].nest == NEST_NONE)) {
198 dctx->stack_depth--;
199 }
200
201 return &dctx->stack[dctx->stack_depth];
202}
203
204/** Unwind the stack until it points to a particular type of stack frame
205 *
206 * @param[in] dctx Stack to unwind.
207 * @param[in] nest Frame type to unwind to.
208 * @return
209 * - Pointer to the frame matching nest
210 * - NULL, if we unwound the complete stack and didn't find the frame.
211 */
213{
214 while ((dctx->stack_depth > 0) &&
215 !(dctx->stack[dctx->stack_depth].nest & nest)) {
216 dctx->stack_depth--;
217 }
218
219 if (!(dctx->stack[dctx->stack_depth].nest & nest)) return NULL;
220
221 return &dctx->stack[dctx->stack_depth];
222}
223
224/*
225 * String split routine. Splits an input string IN PLACE
226 * into pieces, based on spaces.
227 */
228int fr_dict_str_to_argv(char *str, char **argv, int max_argc)
229{
230 int argc = 0;
231
232 while (*str) {
233 if (argc >= max_argc) break;
234
235 /*
236 * Chop out comments early.
237 */
238 if (*str == '#') {
239 *str = '\0';
240 break;
241 }
242
243 while ((*str == ' ') ||
244 (*str == '\t') ||
245 (*str == '\r') ||
246 (*str == '\n'))
247 *(str++) = '\0';
248
249 if (!*str) break;
250
251 argv[argc] = str;
252 argc++;
253
254 while (*str &&
255 (*str != ' ') &&
256 (*str != '\t') &&
257 (*str != '\r') &&
258 (*str != '\n'))
259 str++;
260 }
261
262 return argc;
263}
264
265static int dict_read_sscanf_i(unsigned int *pvalue, char const *str)
266{
267 int unsigned ret = 0;
268 int base = 10;
269 static char const *tab = "0123456789";
270
271 if ((str[0] == '0') &&
272 ((str[1] == 'x') || (str[1] == 'X'))) {
273 tab = "0123456789abcdef";
274 base = 16;
275
276 str += 2;
277 }
278
279 while (*str) {
280 char const *c;
281
282 if (*str == '.') break;
283
284 c = memchr(tab, tolower((uint8_t)*str), base);
285 if (!c) return 0;
286
287 ret *= base;
288 ret += (c - tab);
289 str++;
290 }
291
292 *pvalue = ret;
293 return 1;
294}
295
296/** Set a new root dictionary attribute
297 *
298 * @note Must only be called once per dictionary.
299 *
300 * @param[in] dict to modify.
301 * @param[in] name of dictionary root.
302 * @param[in] proto_number The artificial (or IANA allocated) number for the protocol.
303 * This is only used for
304 * @return
305 * - 0 on success.
306 * - -1 on failure.
307 */
308static int dict_root_set(fr_dict_t *dict, char const *name, unsigned int proto_number)
309{
310 fr_dict_attr_t *da;
311
312 fr_dict_attr_flags_t flags = {
313 .is_root = 1,
314 .type_size = 1,
315 .length = 1
316 };
317
318 if (!fr_cond_assert(!dict->root)) {
319 fr_strerror_const("Dictionary root already set");
320 return -1;
321 }
322
323 da = dict_attr_alloc_root(dict->pool, dict, name, proto_number, &(dict_attr_args_t){ .flags = &flags });
324 if (unlikely(!da)) return -1;
325
326 dict->root = da;
327 dict->root->dict = dict;
328 DA_VERIFY(dict->root);
329
330 return 0;
331}
332
334{
335 char *p;
337
338 /*
339 * Some types can have fixed length
340 */
341 p = strchr(name, '[');
342 if (p) {
343 char *q;
344 unsigned int length;
345
346 *p = '\0';
347 q = strchr(p + 1, ']');
348 if (!q) {
349 fr_strerror_printf("Invalid format for '%s[...]'", name);
350 return -1;
351 }
352
353 *q = '\0';
354 if (q[1]) {
355 fr_strerror_const("length, if present, must end type field");
356 return -1;
357 }
358
359 if (!dict_read_sscanf_i(&length, p + 1)) {
360 fr_strerror_printf("Invalid length for '%s[...]'", name);
361 return -1;
362 }
363
364 /*
365 * "length" has to fit into a uint8_t field.
366 */
367 if ((length == 0) || (length > 255)) {
368 fr_strerror_printf("Invalid length for '%s[...]'", name);
369 return -1;
370 }
371
372 /*
373 * Now that we have a length, check the data type.
374 */
375 if (strcmp(name, "octets") == 0) {
377
378 } else if (strcmp(name, "string") == 0) {
380
381 } else if (strcmp(name, "struct") == 0) {
383
384 } else if (strcmp(name, "bit") == 0) {
385 if (dctx->stack[dctx->stack_depth].da->type != FR_TYPE_STRUCT) {
386 fr_strerror_const("Bit fields can only be used inside of a STRUCT");
387 return -1;
388 }
389
390 (*da_p)->flags.extra = 1;
391 (*da_p)->flags.subtype = FLAG_BIT_FIELD;
392
393 if (length == 1) {
395 } else if (length <= 8) {
397 } else if (length <= 16) {
399 } else if (length <= 32) {
401 } else if (length <= 56) { /* for laziness in encode / decode */
403 } else {
404 fr_strerror_const("Invalid length for bit field");
405 return -1;
406 }
407
408 /*
409 * Cache where on a byte boundary this
410 * bit field ends. We could have the
411 * validation function loop through all
412 * previous siblings, but that's
413 * annoying.
414 */
415 (*da_p)->flags.flag_byte_offset = length;
416
417 } else {
418 fr_strerror_const("Only 'octets', 'string', 'struct', or 'bit' types can have a 'length' parameter");
419 return -1;
420 }
421
422 (*da_p)->flags.is_known_width = true;
423 (*da_p)->flags.length = length;
424 return dict_attr_type_init(da_p, type);
425 }
426
427 /*
428 * We default to using the standard FreeRADIUS types.
429 *
430 * However, if there is a protocol-specific type parsing
431 * function, we call that, too. That ordering allows the
432 * protocol-specific names to over-ride the default ones.
433 */
435
436 if (dctx->dict->proto->attr.type_parse &&
437 !dctx->dict->proto->attr.type_parse(&type, da_p, name)) {
438 return -1;
439 }
440
441 /*
442 * Still not known, or is still a NULL type, that's an error.
443 *
444 * The protocol-specific function can return an error if
445 * it has an error in its parsing. Or, it can return
446 * "true"
447 */
448 if (fr_type_is_null(type)) {
449 fr_strerror_printf("Unknown data type '%s'", name);
450 return -1;
451 }
452
453 return dict_attr_type_init(da_p, type);
454}
455
456/** Define a flag setting function, which sets one bit in a fr_dict_attr_flags_t
457 *
458 * This is here, because AFAIK there's no completely portable way to get the bit
459 * offset of a bit field in a structure.
460 */
461#define FLAG_FUNC(_name) \
462static int dict_flag_##_name(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)\
463{ \
464 (*da_p)->flags._name = 1; \
465 return 0; \
466}
467
468FLAG_FUNC(array)
469
470static int dict_flag_clone(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
471{
472 if (((*da_p)->type != FR_TYPE_TLV) && ((*da_p)->type != FR_TYPE_STRUCT)) {
473 fr_strerror_const("'clone=...' references can only be used for 'tlv' and 'struct' types");
474 return -1;
475 }
476
477 /*
478 * Allow cloning of any types, so long as
479 * the types are the same. We do the checks later.
480 */
482
483 return 0;
484}
485
486FLAG_FUNC(counter)
487
488static int dict_flag_enum(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
489{
490 /*
491 * Allow enum=... as a synonym for
492 * "clone". We check the sources and not
493 * the targets, because that's easier.
494 *
495 * Plus, ENUMs are really just normal attributes
496 * in disguise.
497 */
498 if (!fr_type_is_leaf((*da_p)->type)) {
499 fr_strerror_const("'enum=...' references cannot be used for structural types");
500 return -1;
501 }
502
504
505 return 0;
506}
507
508FLAG_FUNC(internal)
509
510static int dict_flag_key(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
511{
512 fr_dict_attr_t *da = *da_p;
513
514 if ((da->type != FR_TYPE_UINT8) && (da->type != FR_TYPE_UINT16) && (da->type != FR_TYPE_UINT32)) {
515 fr_strerror_const("The 'key' flag can only be used for attributes of type 'uint8', 'uint16', or 'uint32'");
516 return -1;
517 }
518
519 if (da->flags.extra) {
520 fr_strerror_const("Bit fields cannot be key fields");
521 return -1;
522 }
523
524 da->flags.extra = 1;
525 da->flags.subtype = FLAG_KEY_FIELD;
526
527 return 0;
528}
529
530static int dict_flag_length(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
531{
532 fr_dict_attr_t *da = *da_p;
533
534 if (strcmp(value, "uint8") == 0) {
535 da->flags.extra = 1;
536 da->flags.subtype = FLAG_LENGTH_UINT8;
537
538 } else if (strcmp(value, "uint16") == 0) {
539 da->flags.extra = 1;
540 da->flags.subtype = FLAG_LENGTH_UINT16;
541
542 } else {
543 fr_strerror_const("Invalid value given for the 'length' flag");
544 return -1;
545 }
546 da->flags.type_size = 0;
547
548 return 0;
549}
550
551static int dict_flag_offset(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
552{
553 fr_dict_attr_t *da = *da_p;
554 int offset;
555
556 if (da->type != FR_TYPE_STRUCT) {
557 fr_strerror_const("The 'offset' flag can only be used with data type 'struct'");
558 return -1;
559 }
560
561 if (!da->flags.extra || (!(da->flags.subtype == FLAG_LENGTH_UINT8) || (da->flags.subtype == FLAG_LENGTH_UINT16))) {
562 fr_strerror_const("The 'offset' flag can only be used in combination with 'length=uint8' or 'length=uint16'");
563 return -1;
564 }
565
566 offset = atoi(value);
567 if ((offset <= 0) || (offset > 255)) {
568 fr_strerror_const("The 'offset' value must be between 1..255");
569 return -1;
570 }
571 da->flags.type_size = offset;
572
573 return 0;
574}
575
577{
578 fr_dict_attr_t *da = *da_p;
579 int precision;
580
581 switch (da->type) {
582 case FR_TYPE_DATE:
584 break;
585
586 default:
587 fr_strerror_const("The 'precision' flag can only be used with data types 'date' or 'time'");
588 return -1;
589 }
590
592 if (precision < 0) {
593 fr_strerror_printf("Unknown %s precision '%s'", fr_type_to_str(da->type), value);
594 return -1;
595 }
596 da->flags.flag_time_res = precision;
597
598 return 0;
599}
600
601static int dict_flag_ref(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
602{
603 fr_dict_attr_t *da = *da_p;
604
605 if (da->flags.extra) {
606 fr_strerror_const("Cannot use 'ref' with other flags");
607 return -1;
608 }
609
610 if (da->type != FR_TYPE_GROUP) {
611 fr_strerror_printf("The 'ref' flag cannot be used for type '%s'",
612 fr_type_to_str(da->type));
613 return -1;
614 }
615
617
618 return 0;
619}
620
622{
623 fr_dict_attr_t *da = *da_p;
624
625 da->flags.secret = 1;
626
627 if ((da->type != FR_TYPE_STRING) && (da->type != FR_TYPE_OCTETS)) {
628 fr_strerror_const("The 'secret' flag can only be used with data types 'string' or 'octets'");
629 return -1;
630 }
631
632 return 0;
633}
634
635static int dict_flag_subtype(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
636{
637 fr_dict_attr_t *da = *da_p;
638 fr_type_t subtype;
639
640 switch (da->type) {
641 case FR_TYPE_DATE:
643 break;
644
645 default:
646 fr_strerror_const("The 'subtype' flag can only be used with data types 'date' or 'time'");
647 return -1;
648 }
649
650 subtype = fr_type_from_str(value);
651 if (fr_type_is_null(subtype)) {
652 unknown_type:
653 fr_strerror_printf("Unknown or unsupported %s type '%s'",
654 fr_type_to_str(subtype),
655 value);
656 return -1;
657 }
658
659 switch (subtype) {
660 default:
661 goto unknown_type;
662
663 case FR_TYPE_INT16:
664 if (da->type == FR_TYPE_DATE) goto unknown_type;
665 da->flags.length = 2;
666 break;
667
668 case FR_TYPE_UINT16:
669 da->flags.is_unsigned = true;
670 da->flags.length = 2;
671 break;
672
673 case FR_TYPE_INT32:
674 if (da->type == FR_TYPE_DATE) goto unknown_type;
675 da->flags.length = 4;
676 break;
677
678 case FR_TYPE_UINT32:
679 da->flags.is_unsigned = true;
680 da->flags.length = 4;
681 break;
682
683 case FR_TYPE_INT64:
684 if (da->type == FR_TYPE_DATE) goto unknown_type;
685 da->flags.length = 8;
686 break;
687
688 case FR_TYPE_UINT64:
689 da->flags.is_unsigned = true;
690 da->flags.length = 8;
691 break;
692 }
693
694 return 0;
695}
696
697FLAG_FUNC(unsafe)
698
699/** A lookup function for dictionary attribute flags
700 *
701 */
703 fr_dict_attr_flag_to_parser, fr_dict_flag_parser_rule_t const *, fr_dict_flag_parser_rule_t const *)
704
705static int CC_HINT(nonnull) dict_process_flag_field(dict_tokenize_ctx_t *dctx, char *name, fr_dict_attr_t **da_p)
706{
707 static fr_dict_flag_parser_t dict_common_flags[] = {
708 { L("array"), { .func = dict_flag_array } },
709 { L("clone"), { .func = dict_flag_clone, .needs_value = true } },
710 { L("counter"), { .func = dict_flag_counter } },
711 { L("enum"), { .func = dict_flag_enum, .needs_value = true } },
712 { L("internal"), { .func = dict_flag_internal } },
713 { L("key"), { .func = dict_flag_key } },
714 { L("length"), { .func = dict_flag_length, .needs_value = true } },
715 { L("offset"), { .func = dict_flag_offset, .needs_value = true } },
716 { L("precision"), { .func = dict_flag_precision, .needs_value = true } },
717 { L("ref"), { .func = dict_flag_ref, .needs_value = true } },
718 { L("secret"), { .func = dict_flag_secret } },
719 { L("subtype"), { .func = dict_flag_subtype, .needs_value = true } },
720 { L("unsafe"), { .func = dict_flag_unsafe } },
721 };
722 static size_t dict_common_flags_len = NUM_ELEMENTS(dict_common_flags);
723
724 char *p, *next = NULL;
725
726 if ((*da_p)->type == FR_TYPE_NULL) {
727 fr_strerror_const("Type must be specified before parsing flags");
728 return -1;
729 }
730
731 for (p = name; p && *p != '\0' ; p = next) {
732 char *key, *value;
733 fr_dict_flag_parser_rule_t const *parser;
734
735 key = p;
736
737 /*
738 * Search for the first '=' or ','
739 */
740 for (next = p + 1; *next && (*next != '=') && (*next != ','); next++) {
741 /* do nothing */
742 }
743
744 /*
745 * We have a value, zero out the '=' and point to the value.
746 */
747 if (*next == '=') {
748 *(next++) = '\0';
749 value = next;
750
751 if (!*value || (*value == ',')) {
752 fr_strerror_printf("Missing value after '%s='", key);
753 return -1;
754 }
755 } else {
756 value = NULL;
757 }
758
759 /*
760 * Skip any trailing text in the value.
761 */
762 for (/* nothing */; *next; next++) {
763 if (*next == ',') {
764 *(next++) = '\0';
765 break;
766 }
767 }
768
769 /*
770 * Search the protocol table, then the main table.
771 * This allows protocols to overload common flags.
772 */
773 if (!((dctx->dict->proto->attr.flags.table &&
774 fr_dict_attr_flag_to_parser(&parser, dctx->dict->proto->attr.flags.table,
775 dctx->dict->proto->attr.flags.table_len, key, NULL)) ||
776 fr_dict_attr_flag_to_parser(&parser, dict_common_flags, dict_common_flags_len, key, NULL))) {
777 fr_strerror_printf("Unknown flag '%s'", key);
778 return -1;
779 }
780
781 if (parser->needs_value && !value) {
782 fr_strerror_printf("Flag '%s' requires a value", key);
783 return -1;
784 }
785
786 if (unlikely(parser->func(da_p, value, parser) < 0)) return -1;
787 }
788
789 /*
790 * Don't check the flags field for validity via
791 * dict_attr_flags_valid(). It may be updated by various
792 * protocol-specific callback functions. And,
793 * fr_dict_attr_add() calls dict_attr_flags_valid() anyways.
794 */
795
796 return 0;
797}
798
800{
801 if (dict_fixup_apply(&dctx->fixup) < 0) return -1;
802
803 dctx->value_attr = NULL;
804 dctx->relative_attr = NULL;
805
806 return 0;
807}
808
809static inline CC_HINT(always_inline)
811{
812 da->filename = dctx->stack[dctx->stack_depth].filename;
813 da->line = dctx->stack[dctx->stack_depth].line;
814}
815
816/** Add an attribute to the dictionary, or add it to a list of attributes to clone later
817 *
818 * @param[in] fixup context to add an entry to (if needed).
819 * @param[in] da_p to either add, or create a fixup for.
820 * @return
821 * - 0 on success, and an attribute was added.
822 * - 1 on success, and a deferred entry was added.
823 * - -1 on failure.
824 */
826{
828 fr_dict_attr_t *da = *da_p;
829 int ret = 0;
830
831 /*
832 * Check for any references associated with the attribute,
833 * if they're unresolved, then add fixups.
834 *
835 * We do this now, as we know the attribute memory chunk
836 * is stable, and we can safely add the fixups.
837 */
839 if (ref && fr_dict_attr_ref_is_unresolved(ref->type)) {
840 /*
841 * See if we can immediately apply the ref.
842 */
843 fr_dict_attr_t const *src;
844
845 switch (fr_dict_attr_ref_type(ref->type)) {
847 /*
848 * IF the ref exists, we can always add it. The ref won't be changed later.
849 */
850 if (dict_protocol_reference(&src, da->parent, ref->unresolved) < 0) return -1;
851
852 if (src && (dict_attr_ref_set(*da_p, src, FR_DICT_ATTR_REF_ALIAS) < 0)) return -1;
853
854 if (fr_dict_attr_add_initialised(da) < 0) {
855 error:
856 talloc_free(da);
857 *da_p = NULL;
858 return -1;
859 }
860
861 if (!src && (dict_fixup_group_enqueue(fixup, da, ref->unresolved) < 0)) return -1;
862 ret = 1;
863 break;
864
866 /*
867 * Do NOT copy the enums now. Later dictionaries may add more values, and we
868 * want to be able to copy all values.
869 */
870 if (fr_dict_attr_add_initialised(da) < 0) goto error;
871
872 if (dict_fixup_clone_enum_enqueue(fixup, da, ref->unresolved) < 0) return -1;
873 break;
874
876 /*
877 * @todo - if we defer this clone, we get errors loading dictionary.wimax. That
878 * likely means there are issues with the dict_fixup_clone_apply() function.
879 */
880 if (dict_protocol_reference(&src, da->parent, ref->unresolved) < 0) return -1;
881 if (src) {
882 if (dict_fixup_clone(da_p, src) < 0) return -1;
883 break;
884 }
885
886 if (dict_fixup_clone_enqueue(fixup, da, ref->unresolved) < 0) return -1;
887 ret = 1;
888 break;
889
890 default:
891 fr_strerror_const("Unknown reference type");
892 return -1;
893 }
894 } else {
895 if (fr_dict_attr_add_initialised(da) < 0) goto error;
896 }
897
898 return ret;
899}
900
901/** Check if this definition is a duplicate, and if it is, whether we should skip it error out
902 *
903 * @return
904 * - 1 if this is not a duplicate.
905 * - 0 if this is a duplicate, and we should ignore the definition.
906 * - -1 if this is a duplicate, and we should error out.
907 */
909{
910 fr_dict_attr_t const *dup_name = NULL;
911 fr_dict_attr_t const *dup_num = NULL;
912 fr_dict_attr_t const *found;
913
914 /*
915 * Search in the parent for a duplicate by name and then by num
916 */
917 if (!da->parent) return 1; /* no parent no conflicts possible */
918
919 dup_name = fr_dict_attr_by_name(NULL, da->parent, da->name);
920 if (da->flags.name_only) dup_num = fr_dict_attr_child_by_num(da->parent, da->attr);
921
922 /*
923 * Not a duplicate...
924 */
925 if (!dup_name && !dup_num) return 1;
926
927 found = dup_name ? dup_name : dup_num;
928
929 switch (da->type) {
930 /*
931 * For certain STRUCTURAL types, we allow strict duplicates
932 * as if the user wants to add extra children in the custom
933 * dictionary, or wants to avoid ordering issues between
934 * multiple dictionaries, we need to support this.
935 */
936 case FR_TYPE_VSA:
937 case FR_TYPE_VENDOR:
938 case FR_TYPE_TLV:
939 if (fr_dict_attr_cmp_fields(da, found) == 0) return -1;
940 break;
941
942 default:
943 break;
944 }
945
946 if (dup_name) {
947 fr_strerror_printf("Duplicate attribute name '%s' in namespace '%s'. Originally defined %s[%d]",
948 da->name, da->parent->name, dup_name->filename, dup_name->line);
949 return 0;
950 }
951
952 fr_strerror_printf("Duplicate attribute number %u in parent '%s'. Originally defined %s[%d]",
953 da->attr, da->parent->name, dup_num->filename, dup_num->line);
954 return 0;
955}
956
958{
959 /*
960 * Adding an attribute of type 'struct' is an implicit
961 * BEGIN-STRUCT.
962 */
963 if (da->type == FR_TYPE_STRUCT) {
964 if (dict_dctx_push(dctx, da, 0) < 0) return -1;
965 dctx->value_attr = NULL;
966 } else if (fr_type_is_leaf(da->type)) {
967 memcpy(&dctx->value_attr, &da, sizeof(da));
968 } else {
969 dctx->value_attr = NULL;
970 }
971
972 return 0;
973}
974
976 fr_dict_attr_t const *parent, char const *name,
977 char const *type_name, char *flag_name,
978 fr_dict_attr_flags_t const *base_flags)
979{
980 fr_dict_attr_t *da, *to_free = NULL;
981
982 /*
983 * Dictionaries need to have real names, not shitty ones.
984 */
985 if (strncmp(name, "Attr-", 5) == 0) {
986 fr_strerror_const("Invalid name");
987 return -1;
988 }
989
990 /*
991 * Allocate the attribute here, and then fill in the fields
992 * as we start parsing the various elements of the definition.
993 */
994 if (!*da_p) {
995 da = dict_attr_alloc_null(dctx->dict->pool, dctx->dict->proto);
996 if (unlikely(!da)) return -1;
997 to_free = da;
998
999 } else {
1000 da = *da_p;
1001 }
1002 dict_attr_location_set(dctx, da);
1003 da->dict = dctx->dict;
1004
1005 /*
1006 * Set some fields to be friendlier to the type / flag
1007 * parsing and validation routines.
1008 */
1009 da->parent = parent;
1010 da->name = name;
1011
1012 /*
1013 * Set the attribute flags from the base flags.
1014 */
1015 memcpy(&da->flags, base_flags, sizeof(da->flags));
1016
1017 /*
1018 * Set the base type of the attribute.
1019 */
1020 if (dict_process_type_field(dctx, type_name, &da) < 0) {
1021 error:
1022 if (da == to_free) talloc_free(to_free);
1023 return -1;
1024 }
1025
1026 /*
1027 * Clear the temporary parent pointer.
1028 */
1029 da->parent = NULL;
1030 if (unlikely(dict_attr_parent_init(&da, parent) < 0)) goto error;
1031
1032 /*
1033 * Parse optional flags. We pass in the partially allocated
1034 * attribute so that flags can be set directly.
1035 *
1036 * Where flags contain variable length fields, this is
1037 * significantly easier than populating a temporary struct.
1038 */
1039 if (flag_name) if (dict_process_flag_field(dctx, flag_name, &da) < 0) goto error;
1040
1041 da->name = NULL; /* the real name will be a talloc'd chunk */
1042
1043 *da_p = da;
1044 return 0;
1045}
1046
1047/*
1048 * Process the $INCLUDE command
1049 */
1050static int dict_read_process_include(dict_tokenize_ctx_t *dctx, char **argv, int argc, char const *dir)
1051{
1052 int rcode;
1053 int stack_depth = dctx->stack_depth;
1054 char *fn = CURRENT_FILENAME(dctx);
1055 int line = CURRENT_LINE(dctx);
1056
1057 /*
1058 * Allow "$INCLUDE" or "$INCLUDE-", but
1059 * not anything else.
1060 */
1061 if ((argv[0][8] != '\0') && ((argv[0][8] != '-') || (argv[0][9] != '\0'))) {
1062 fr_strerror_printf("Invalid keyword '%s'", argv[0]);
1063 return -1;
1064 }
1065
1066 if (argc != 2) {
1067 fr_strerror_printf("Unexpected text after $INCLUDE at %s[%d]", fr_cwd_strip(fn), line);
1068 return -1;
1069 }
1070
1071 /*
1072 * Allow limited macro capability, so
1073 * people don't have to remember where
1074 * the root dictionaries are located.
1075 */
1076 if (strncmp(argv[1], "${dictdir}/", 11) != 0) {
1077 rcode = _dict_from_file(dctx, dir, argv[1], fn, line);
1078 } else {
1079 rcode = _dict_from_file(dctx, fr_dict_global_ctx_dir(), argv[1] + 11, fn, line);
1080 }
1081
1082 if ((rcode == -2) && (argv[0][8] == '-')) {
1083 fr_strerror_clear(); /* delete all errors */
1084 return 0;
1085 }
1086
1087 if (rcode < 0) {
1088 fr_strerror_printf_push("from $INCLUDE at %s[%d]", fr_cwd_strip(fn), line);
1089 return -1;
1090 }
1091
1092 if (dctx->stack_depth < stack_depth) {
1093 fr_strerror_printf_push("unexpected END-??? in $INCLUDE at %s[%d]",
1094 fr_cwd_strip(fn), line);
1095 return -1;
1096 }
1097
1098 while (dctx->stack_depth > stack_depth) {
1099 if (dctx->stack[dctx->stack_depth].nest == NEST_NONE) {
1100 dctx->stack_depth--;
1101 continue;
1102 }
1103
1104 fr_strerror_printf_push("BEGIN-??? without END-... in file $INCLUDEd from %s[%d]",
1105 fr_cwd_strip(fn), line);
1106 return -1;
1107 }
1108
1109 /*
1110 * Reset the filename.
1111 */
1112 dctx->stack[dctx->stack_depth].filename = fn;
1113
1114 return 0;
1115}
1116
1117static int dict_read_parse_format(char const *format, int *ptype, int *plength, bool *pcontinuation)
1118{
1119 char const *p;
1120 int type, length;
1121 bool continuation = false;
1122
1123 if (strncasecmp(format, "format=", 7) != 0) {
1124 fr_strerror_printf("Invalid format for VENDOR. Expected 'format=', got '%s'",
1125 format);
1126 return -1;
1127 }
1128
1129 p = format + 7;
1130 if ((strlen(p) < 3) ||
1131 !isdigit((uint8_t)p[0]) ||
1132 (p[1] != ',') ||
1133 !isdigit((uint8_t)p[2]) ||
1134 (p[3] && (p[3] != ','))) {
1135 fr_strerror_printf("Invalid format for VENDOR. Expected text like '1,1', got '%s'",
1136 p);
1137 return -1;
1138 }
1139
1140 type = (int)(p[0] - '0');
1141 length = (int)(p[2] - '0');
1142
1143 if ((type != 1) && (type != 2) && (type != 4)) {
1144 fr_strerror_printf("Invalid type value %d for VENDOR", type);
1145 return -1;
1146 }
1147
1148 if ((length != 0) && (length != 1) && (length != 2)) {
1149 fr_strerror_printf("Invalid length value %d for VENDOR", length);
1150 return -1;
1151 }
1152
1153 if (p[3] == ',') {
1154 if (!p[4]) {
1155 fr_strerror_printf("Invalid format for VENDOR. Expected text like '1,1', got '%s'",
1156 p);
1157 return -1;
1158 }
1159
1160 if ((p[4] != 'c') ||
1161 (p[5] != '\0')) {
1162 fr_strerror_printf("Invalid format for VENDOR. Expected text like '1,1', got '%s'",
1163 p);
1164 return -1;
1165 }
1166 continuation = true;
1167
1168 if ((type != 1) || (length != 1)) {
1169 fr_strerror_const("Only VSAs with 'format=1,1' can have continuations");
1170 return -1;
1171 }
1172 }
1173
1174 *ptype = type;
1175 *plength = length;
1176 *pcontinuation = continuation;
1177 return 0;
1178}
1179
1180/*
1181 * Process the ALIAS command
1182 *
1183 * ALIAS name ref
1184 *
1185 * Creates an attribute "name" in the root namespace of the current
1186 * dictionary, which is a pointer to "ref".
1187 */
1188static int dict_read_process_alias(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
1189{
1190 fr_dict_attr_t const *da;
1191 fr_dict_attr_t const *parent = dctx->stack[dctx->stack_depth].da;
1192 fr_dict_attr_t const *ref_namespace;
1193
1194 if (argc != 2) {
1195 fr_strerror_const("Invalid ALIAS syntax");
1196 return -1;
1197 }
1198
1199 /*
1200 * Dictionaries need to have real names, not shitty ones.
1201 */
1202 if (strncmp(argv[0], "Attr-", 5) == 0) {
1203 fr_strerror_const("Invalid ALIAS name");
1204 return -1;
1205 }
1206
1207 /*
1208 * Relative refs get resolved from the current namespace.
1209 */
1210 if (argv[1][0] == '.') {
1211 ref_namespace = parent;
1212 /*
1213 * No dot, so we're looking in the root namespace.
1214 */
1215 } else {
1216 ref_namespace = dctx->dict->root;
1217 }
1218
1219 /*
1220 * The <ref> can be a name.
1221 */
1222 da = fr_dict_attr_by_oid(NULL, ref_namespace, argv[1]);
1223 if (!da) {
1224 /*
1225 * If we can't find it now, the file
1226 * containing the ALIASes may have
1227 * been allowed before the ALIASed
1228 * attributes.
1229 */
1230 return dict_fixup_alias_enqueue(&dctx->fixup, CURRENT_FRAME(dctx)->filename, CURRENT_FRAME(dctx)->line,
1231 fr_dict_attr_unconst(parent), argv[0],
1232 fr_dict_attr_unconst(ref_namespace), argv[1]);
1233 }
1234
1235 return dict_attr_alias_add(fr_dict_attr_unconst(parent), argv[0], da);
1236}
1237
1238/*
1239 * Process the ATTRIBUTE command
1240 */
1241static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
1242{
1243 bool set_relative_attr;
1244
1245 ssize_t slen;
1246 unsigned int attr;
1247
1248 fr_dict_attr_t const *parent;
1249 fr_dict_attr_t *da;
1250
1251 if ((argc < 3) || (argc > 4)) {
1252 fr_strerror_const("Invalid ATTRIBUTE syntax");
1253 return -1;
1254 }
1255
1256#ifdef STATIC_ANALYZER
1257 if (!dctx->dict) return -1;
1258#endif
1259
1260 /*
1261 * A non-relative ATTRIBUTE definition means that it is
1262 * in the context of the previous BEGIN-FOO. So we
1263 * unwind the stack to match.
1264 */
1265 if (argv[1][0] != '.') {
1266 parent = dict_dctx_unwind(dctx)->da;
1267
1268 /*
1269 * Allow '0xff00' as attribute numbers, but only
1270 * if there is no OID component.
1271 */
1272 if (strchr(argv[1], '.') == 0) {
1273 if (!dict_read_sscanf_i(&attr, argv[1])) {
1274 fr_strerror_const("Invalid ATTRIBUTE number");
1275 return -1;
1276 }
1277
1278 } else {
1279 slen = fr_dict_attr_by_oid_legacy(dctx->dict, &parent, &attr, argv[1]);
1280 if (slen <= 0) return -1;
1281 }
1282
1283 /*
1284 * We allow relative attributes only for TLVs.
1285 *
1286 * We haven't parsed the type field yet, so we
1287 * just check it here manually.
1288 */
1289 set_relative_attr = (strcasecmp(argv[2], "tlv") == 0);
1290
1291 } else {
1292 if (!dctx->relative_attr) {
1293 fr_strerror_const("Unknown parent for partial OID");
1294 return -1;
1295 }
1296
1297 parent = dctx->relative_attr;
1298
1299 slen = fr_dict_attr_by_oid_legacy(dctx->dict, &parent, &attr, argv[1]);
1300 if (slen <= 0) return -1;
1301
1302 set_relative_attr = false;
1303 }
1304
1305 if (!fr_cond_assert(parent)) return -1; /* Should have provided us with a parent */
1306
1307 /*
1308 * Members of a 'struct' MUST use MEMBER, not ATTRIBUTE.
1309 */
1310 if (parent->type == FR_TYPE_STRUCT) {
1311 fr_strerror_printf("Member %s of ATTRIBUTE %s type 'struct' MUST use the \"MEMBER\" keyword",
1312 argv[0], parent->name);
1313 return -1;
1314 }
1315
1316 da = dict_attr_alloc_null(dctx->dict->pool, dctx->dict->proto);
1317 if (unlikely(!da)) return -1;
1318
1319 /*
1320 * Record the attribute number BEFORE we parse the type and flags.
1321 *
1322 * This is needed for the DER dictionaries, and 'option'.
1323 *
1324 * It can also be useful for other protocols, which may
1325 * have restrictions on the various fields. It is
1326 * therefore useful to have all fields initialized before
1327 * the type/flag validation routines are called.
1328 */
1329 if (unlikely(dict_attr_num_init(da, attr) < 0)) {
1330 error:
1331 talloc_free(da);
1332 return -1;
1333 }
1334
1335 if (dict_read_process_common(dctx, &da, parent, argv[0], argv[2],
1336 (argc > 3) ? argv[3] : NULL, base_flags) < 0) {
1337 goto error;
1338 }
1339
1340 if (da->flags.extra && (da->flags.subtype == FLAG_BIT_FIELD)) {
1341 fr_strerror_const("Bit fields can only be defined as a MEMBER of a STRUCT");
1342 goto error;
1343 }
1344
1345
1346#ifdef WITH_DICTIONARY_WARNINGS
1347 /*
1348 * Hack to help us discover which vendors have illegal
1349 * attributes.
1350 */
1351 if (!vendor && (attr < 256) &&
1352 !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
1353 fprintf(stderr, "WARNING: Illegal attribute %s in %s\n",
1354 argv[0], fn);
1355 }
1356#endif
1357
1358 /*
1359 * Set the attribute name
1360 */
1361 if (unlikely(dict_attr_finalise(&da, argv[0]) < 0)) {
1362 goto error;
1363 }
1364
1365 /*
1366 * Check to see if this is a duplicate attribute
1367 * and whether we should ignore it or error out...
1368 */
1369 switch (dict_attr_allow_dup(da)) {
1370 case 1:
1371 break;
1372
1373 case 0:
1374 talloc_free(da);
1375 return 0;
1376
1377 default:
1378 goto error;
1379 }
1380
1381 /*
1382 * Add the attribute we allocated earlier
1383 */
1384 switch (dict_attr_add_or_fixup(&dctx->fixup, &da)) {
1385 default:
1386 goto error;
1387
1388 /* New attribute, fixup stack */
1389 case 0:
1390 /*
1391 * Dynamically define where VSAs go. Note that we CANNOT
1392 * define VSAs until we define an attribute of type VSA!
1393 */
1394 if (da->type == FR_TYPE_VSA) {
1395 if (parent->flags.is_root) dctx->dict->vsa_parent = attr;
1396
1397 if (dict_fixup_vsa_enqueue(&dctx->fixup, UNCONST(fr_dict_attr_t *, da)) < 0) {
1398 return -1; /* Leaves attr added */
1399 }
1400 }
1401
1402 /*
1403 * Adding an attribute of type 'struct' is an implicit
1404 * BEGIN-STRUCT.
1405 */
1406 if (da->type == FR_TYPE_STRUCT) {
1407 if (dict_dctx_push(dctx, da, 0) < 0) return -1;
1408 dctx->value_attr = NULL;
1409 } else {
1410 memcpy(&dctx->value_attr, &da, sizeof(da));
1411 }
1412
1413 if (set_relative_attr) dctx->relative_attr = da;
1414 break;
1415
1416 /* Deferred attribute, don't begin the TLV section automatically */
1417 case 1:
1418 break;
1419 }
1420
1421 return 0;
1422}
1423
1424static int dict_read_process_begin(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
1425{
1426 dict_tokenize_frame_t const *frame;
1427 fr_dict_attr_t const *da;
1428 fr_dict_attr_t const *common;
1429
1430 dctx->value_attr = NULL;
1431 dctx->relative_attr = NULL;
1432
1433 if (argc != 1) {
1434 fr_strerror_const_push("Invalid BEGIN keyword. Expected BEGIN <name>");
1435 error:
1436 return -1;
1437 }
1438
1440 if (!fr_cond_assert_msg(frame, "Context stack doesn't have an attribute or dictionary "
1441 "root to begin searching from %s[%d]", CURRENT_FILENAME(dctx), CURRENT_LINE(dctx)) ||
1442 !fr_cond_assert_msg(fr_type_is_structural(frame->da->type), "Context attribute is not structural %s[%d]",
1443 CURRENT_FILENAME(dctx), CURRENT_LINE(dctx))) {
1444 return -1;
1445 }
1446
1447 /*
1448 * Not really a reference as we don't support any of the
1449 * fancy syntaxes like refs do. A straight OID string
1450 * resolved from the current level of nesting is all we support.
1451 */
1452 da = fr_dict_attr_by_oid(NULL, frame->da, argv[0]);
1453 if (!da) {
1454 fr_strerror_printf_push("BEGIN '%s' not resolvable in context '%s'", argv[0], frame->da->name);
1455 goto error;
1456 }
1457
1458 if (!fr_type_is_tlv(da->type) && !fr_type_is_struct(da->type)) {
1459 fr_strerror_printf_push("BEGIN %s should be a 'tlv' or 'struct', but is a '%s'",
1460 argv[0],
1461 fr_type_to_str(da->type));
1462 goto error;
1463 }
1464
1465 common = fr_dict_attr_common_parent(frame->da, da, true);
1466 if (!common) {
1467 fr_strerror_printf_push("BEGIN %s should be a child of '%s'",
1468 argv[0], dctx->stack[dctx->stack_depth].da->name);
1469 goto error;
1470 }
1471
1472 if (dict_dctx_push(dctx, da, NEST_ATTRIBUTE) < 0) goto error;
1473
1474 return 0;
1475}
1476
1477static int dict_read_process_begin_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1478 UNUSED fr_dict_attr_flags_t *base_flags)
1479{
1480 fr_dict_t *found;
1481 dict_tokenize_frame_t const *frame;
1482
1483 dctx->value_attr = NULL;
1484 dctx->relative_attr = NULL;
1485
1486 if (argc != 1) {
1487 fr_strerror_const_push("Invalid BEGIN-PROTOCOL entry");
1488 error:
1489 return -1;
1490 }
1491
1492 /*
1493 * If we're not parsing in the context of the internal
1494 * dictionary, then we don't allow BEGIN-PROTOCOL
1495 * statements.
1496 */
1497 if (dctx->dict != dict_gctx->internal) {
1498 fr_strerror_const_push("Nested BEGIN-PROTOCOL statements are not allowed");
1499 goto error;
1500 }
1501
1502 found = dict_by_protocol_name(argv[0]);
1503 if (!found) {
1504 fr_strerror_printf("Unknown protocol '%s'", argv[0]);
1505 goto error;
1506 }
1507
1508 frame = dict_dctx_find_frame(dctx, NEST_PROTOCOL);
1509 if (frame) {
1510 fr_strerror_printf_push("Nested BEGIN-PROTOCOL is forbidden. Previous definition is at %s[%d]",
1511 frame->filename, frame->line);
1512 goto error;
1513 }
1514
1515 /*
1516 * Add a temporary fixup pool
1517 *
1518 * @todo - make a nested ctx?
1519 */
1520 dict_fixup_init(NULL, &dctx->fixup);
1521
1522 /*
1523 * We're in the middle of loading this dictionary. Tell
1524 * fr_dict_protocol_afrom_file() to suppress recursive references.
1525 */
1526 found->loading = true;
1527
1528 dctx->dict = found;
1529
1530 if (dict_dctx_push(dctx, dctx->dict->root, NEST_PROTOCOL) < 0) goto error;
1531
1532 return 0;
1533}
1534
1535static int dict_read_process_begin_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1536 UNUSED fr_dict_attr_flags_t *base_flags)
1537{
1538 fr_dict_vendor_t const *vendor;
1540
1541 fr_dict_attr_t const *vsa_da;
1542 fr_dict_attr_t const *vendor_da;
1543 fr_dict_attr_t *new;
1544 dict_tokenize_frame_t const *frame;
1545 char *p;
1546
1547 dctx->value_attr = NULL;
1548 dctx->relative_attr = NULL;
1549
1550 if (argc < 1) {
1551 fr_strerror_const_push("Invalid BEGIN-VENDOR entry");
1552 error:
1553 return -1;
1554 }
1555
1556 vendor = fr_dict_vendor_by_name(dctx->dict, argv[0]);
1557 if (!vendor) {
1558 fr_strerror_printf_push("Unknown vendor '%s'", argv[0]);
1559 goto error;
1560 }
1561
1562 /*
1563 * Check for extended attr VSAs
1564 *
1565 * BEGIN-VENDOR foo parent=Foo-Encapsulation-Attr
1566 */
1567 if (argc > 1) {
1568 fr_dict_attr_t const *da;
1569
1570 if (strncmp(argv[1], "parent=", 7) != 0) {
1571 fr_strerror_printf_push("BEGIN-VENDOR invalid argument (%s)", argv[1]);
1572 goto error;
1573 }
1574
1575 p = argv[1] + 7;
1576 da = fr_dict_attr_by_oid(NULL, dctx->stack[dctx->stack_depth].da, p);
1577 if (!da) {
1578 fr_strerror_printf_push("BEGIN-VENDOR invalid argument (%s)", argv[1]);
1579 goto error;
1580 }
1581
1582 if (da->type != FR_TYPE_VSA) {
1583 fr_strerror_printf_push("Invalid parent for BEGIN-VENDOR. "
1584 "Attribute '%s' should be 'vsa' but is '%s'", p,
1585 fr_type_to_str(da->type));
1586 goto error;
1587 }
1588
1589 vsa_da = da;
1590
1591 } else if (dctx->dict->vsa_parent) {
1592 /*
1593 * Check that the protocol-specific VSA parent exists.
1594 */
1595 vsa_da = dict_attr_child_by_num(dctx->stack[dctx->stack_depth].da, dctx->dict->vsa_parent);
1596 if (!vsa_da) {
1597 fr_strerror_printf_push("Failed finding VSA parent for Vendor %s",
1598 vendor->name);
1599 goto error;
1600 }
1601
1602 } else if (dctx->dict->string_based) {
1603 vsa_da = dctx->dict->root;
1604
1605 } else {
1606 fr_strerror_printf_push("BEGIN-VENDOR is forbidden for protocol %s - it has no ATTRIBUTE of type 'vsa'",
1607 dctx->dict->root->name);
1608 goto error;
1609 }
1610
1611 frame = dict_dctx_find_frame(dctx, NEST_VENDOR);
1612 if (frame) {
1613 fr_strerror_printf_push("Nested BEGIN-VENDOR is forbidden. Previous definition is at %s[%d]",
1614 frame->filename, frame->line);
1615 goto error;
1616 }
1617
1618 /*
1619 * Create a VENDOR attribute on the fly, either in the context
1620 * of the VSA (26) attribute.
1621 */
1622 vendor_da = dict_attr_child_by_num(vsa_da, vendor->pen);
1623 if (!vendor_da) {
1624 memset(&flags, 0, sizeof(flags));
1625
1626 flags.type_size = dctx->dict->proto->default_type_size;
1627 flags.length = dctx->dict->proto->default_type_length;
1628
1629 /*
1630 * See if this vendor has
1631 * specific sizes for type /
1632 * length.
1633 *
1634 * @todo - Make this more protocol agnostic!
1635 */
1636 if ((vsa_da->type == FR_TYPE_VSA) &&
1637 (vsa_da->parent->flags.is_root)) {
1638 fr_dict_vendor_t const *dv;
1639
1640 dv = fr_dict_vendor_by_num(dctx->dict, vendor->pen);
1641 if (dv) {
1642 flags.type_size = dv->type;
1643 flags.length = dv->length;
1644 }
1645 }
1646
1647 new = dict_attr_alloc(dctx->dict->pool,
1648 vsa_da, argv[0], vendor->pen, FR_TYPE_VENDOR,
1649 &(dict_attr_args_t){ .flags = &flags });
1650 if (unlikely(!new)) goto error;
1651
1652 if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, vsa_da), new) < 0) {
1653 talloc_free(new);
1654 goto error;
1655 }
1656
1657 if (dict_attr_add_to_namespace(UNCONST(fr_dict_attr_t *, vsa_da), new) < 0) {
1658 talloc_free(new);
1659 goto error;
1660 }
1661
1662 vendor_da = new;
1663 } else {
1664 fr_assert(vendor_da->type == FR_TYPE_VENDOR);
1665 }
1666
1667 if (dict_dctx_push(dctx, vendor_da, NEST_VENDOR) < 0) goto error;
1668
1669 return 0;
1670}
1671
1672/*
1673 * Process the DEFINE command
1674 *
1675 * Which is mostly like ATTRIBUTE, but does not have a number.
1676 */
1677static int dict_read_process_define(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1678 fr_dict_attr_flags_t *base_flags)
1679{
1680 fr_dict_attr_t const *parent;
1681 fr_dict_attr_t *da = NULL;
1682 dict_tokenize_frame_t const *frame;
1683
1684 if ((argc < 2) || (argc > 3)) {
1685 fr_strerror_const("Invalid DEFINE syntax");
1686 return -1;
1687 }
1688
1689 frame = dict_dctx_unwind(dctx);
1690 if (!fr_cond_assert(frame && frame->da)) return -1; /* Should have provided us with a parent */
1691
1692 parent = frame->da;
1693
1694 /*
1695 * Members of a 'struct' MUST use MEMBER, not ATTRIBUTE.
1696 */
1697 if (parent->type == FR_TYPE_STRUCT) {
1698 fr_strerror_printf("Member %s of parent %s type 'struct' MUST use the \"MEMBER\" keyword",
1699 argv[0], parent->name);
1700 return -1;
1701 }
1702
1703 /*
1704 * We don't set the attribute number before parsing the
1705 * type and flags. The number is chosen internally, and
1706 * no one should depend on it.
1707 */
1708 if (dict_read_process_common(dctx, &da, parent, argv[0], argv[1],
1709 (argc > 2) ? argv[2] : NULL, base_flags) < 0) {
1710 return -1;
1711 }
1712
1713 /*
1714 * Certain structural types MUST have numbers.
1715 */
1716 switch (da->type) {
1717 case FR_TYPE_VSA:
1718 case FR_TYPE_VENDOR:
1719 fr_strerror_printf("DEFINE cannot be used for type '%s'", argv[1]);
1720 error:
1721 talloc_free(da);
1722 return -1;
1723
1724 default:
1725 break;
1726 }
1727
1728 if (da->flags.extra && (da->flags.subtype == FLAG_BIT_FIELD)) {
1729 fr_strerror_const("Bit fields can only be defined as a MEMBER of a STRUCT");
1730 goto error;
1731 }
1732
1733#ifdef STATIC_ANALYZER
1734 if (!dctx->dict) goto error;
1735#endif
1736
1737 /*
1738 * Since there is no number, the attribute cannot be
1739 * encoded as a number.
1740 */
1741 da->flags.name_only = true;
1742
1743 /*
1744 * Add an attribute number now so the allocations occur in order
1745 */
1746 if (unlikely(dict_attr_num_init_name_only(da) < 0)) goto error;
1747
1748 /*
1749 * Set the attribute name
1750 */
1751 if (unlikely(dict_attr_finalise(&da, argv[0]) < 0)) goto error;
1752
1753 /*
1754 * Check to see if this is a duplicate attribute
1755 * and whether we should ignore it or error out...
1756 */
1757 switch (dict_attr_allow_dup(da)) {
1758 case 1:
1759 break;
1760
1761 case 0:
1762 talloc_free(da);
1763 return 0;
1764
1765 default:
1766 goto error;
1767 }
1768
1769 /*
1770 * Add the attribute we allocated earlier
1771 */
1772 switch (dict_attr_add_or_fixup(&dctx->fixup, &da)) {
1773 default:
1774 goto error;
1775
1776 /* New attribute, fixup stack */
1777 case 0:
1778 if (dict_set_value_attr(dctx, da) < 0) return -1;
1779
1780 if (da->type == FR_TYPE_TLV) {
1781 dctx->relative_attr = da;
1782 } else {
1783 dctx->relative_attr = NULL;
1784 }
1785 break;
1786
1787 /* Deferred attribute, don't begin the TLV section automatically */
1788 case 1:
1789 break;
1790 }
1791
1792 return 0;
1793}
1794
1795static int dict_read_process_end(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1796 UNUSED fr_dict_attr_flags_t *base_flags)
1797{
1798 fr_dict_attr_t const *current;
1799 fr_dict_attr_t const *da;
1800 dict_tokenize_frame_t const *frame;
1801
1802 dctx->value_attr = NULL;
1803 dctx->relative_attr = NULL;
1804
1805 if (argc > 2) {
1806 fr_strerror_const("Invalid END syntax, expected END <ref>");
1807 goto error;
1808 }
1809
1810 /*
1811 * Unwind until we hit an attribute nesting section
1812 */
1814 fr_strerror_const("Unbalanced BEGIN and END keywords");
1815 error:
1816 return -1;
1817 }
1818
1819 /*
1820 * Pop the stack to get the attribute we're ending.
1821 */
1822 current = dict_dctx_pop(dctx)->da;
1823
1824 /*
1825 * No checks on the attribute, we're just popping _A_ frame,
1826 * we don't care what attribute it represents.
1827 */
1828 if (argc == 1) return 0;
1829
1830 /*
1831 * This is where we'll have begun the previous search to
1832 * evaluate the BEGIN keyword.
1833 */
1835 if (!fr_cond_assert(frame)) goto error;
1836
1837 da = fr_dict_attr_by_oid(NULL, frame->da, argv[0]);
1838 if (!da) {
1839 fr_strerror_const_push("Failed resolving attribute in BEGIN entry");
1840 goto error;
1841 }
1842
1843 if (da != current) {
1844 fr_strerror_printf_push("END %s does not match previous BEGIN %s", argv[0], current->name);
1845 goto error;
1846 }
1847
1848 return 0;
1849}
1850
1851static int dict_read_process_end_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1852 UNUSED fr_dict_attr_flags_t *base_flags)
1853{
1854 fr_dict_t const *found;
1855
1856 dctx->value_attr = NULL;
1857 dctx->relative_attr = NULL;
1858
1859 if (argc != 1) {
1860 fr_strerror_const("Invalid END-PROTOCOL entry");
1861 error:
1862 return -1;
1863 }
1864
1865 found = dict_by_protocol_name(argv[0]);
1866 if (!found) {
1867 fr_strerror_printf("END-PROTOCOL %s does not refer to a valid protocol", argv[0]);
1868 goto error;
1869 }
1870
1871 if (found != dctx->dict) {
1872 fr_strerror_printf("END-PROTOCOL %s does not match previous BEGIN-PROTOCOL %s",
1873 argv[0], dctx->dict->root->name);
1874 goto error;
1875 }
1876
1877 /*
1878 * Pop the stack until we get to a PROTOCOL nesting.
1879 */
1880 while ((dctx->stack_depth > 0) && (dctx->stack[dctx->stack_depth].nest != NEST_PROTOCOL)) {
1881 if (dctx->stack[dctx->stack_depth].nest != NEST_NONE) {
1882 fr_strerror_printf_push("END-PROTOCOL %s with mismatched BEGIN-??? %s", argv[0],
1883 dctx->stack[dctx->stack_depth].da->name);
1884 goto error;
1885 }
1886
1887 dctx->stack_depth--;
1888 }
1889
1890 if (dctx->stack_depth == 0) {
1891 fr_strerror_printf_push("END-PROTOCOL %s with no previous BEGIN-PROTOCOL", argv[0]);
1892 goto error;
1893 }
1894
1895 if (found->root != dctx->stack[dctx->stack_depth].da) {
1896 fr_strerror_printf_push("END-PROTOCOL %s does not match previous BEGIN-PROTOCOL %s", argv[0],
1897 dctx->stack[dctx->stack_depth].da->name);
1898 goto error;
1899 }
1900
1901 /*
1902 * Applies fixups to any attributes added
1903 * to the protocol dictionary. Note that
1904 * the finalise function prints out the
1905 * original filename / line of the
1906 * error. So we don't need to do that
1907 * here.
1908 */
1909 if (dict_finalise(dctx) < 0) goto error;
1910
1911 dctx->stack_depth--;
1912 dctx->dict = dctx->stack[dctx->stack_depth].dict;
1913
1914 return 0;
1915}
1916
1917static int dict_read_process_end_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1918 UNUSED fr_dict_attr_flags_t *base_flags)
1919{
1920 fr_dict_vendor_t const *vendor;
1921
1922 dctx->value_attr = NULL;
1923 dctx->relative_attr = NULL;
1924
1925 if (argc != 1) {
1926 fr_strerror_const_push("Invalid END-VENDOR entry");
1927 error:
1928 return -1;
1929 }
1930
1931 vendor = fr_dict_vendor_by_name(dctx->dict, argv[0]);
1932 if (!vendor) {
1933 fr_strerror_printf_push("Unknown vendor '%s'", argv[0]);
1934 goto error;
1935 }
1936
1937 /*
1938 * Pop the stack until we get to a VENDOR nesting.
1939 */
1940 while ((dctx->stack_depth > 0) && (dctx->stack[dctx->stack_depth].nest != NEST_VENDOR)) {
1941 if (dctx->stack[dctx->stack_depth].nest != NEST_NONE) {
1942 fr_strerror_printf_push("END-VENDOR %s with mismatched BEGIN-??? %s", argv[0],
1943 dctx->stack[dctx->stack_depth].da->name);
1944 goto error;
1945 }
1946
1947 dctx->stack_depth--;
1948 }
1949
1950 if (dctx->stack_depth == 0) {
1951 fr_strerror_printf_push("END-VENDOR %s with no previous BEGIN-VENDOR", argv[0]);
1952 goto error;
1953 }
1954
1955 if (vendor->pen != dctx->stack[dctx->stack_depth].da->attr) {
1956 fr_strerror_printf_push("END-VENDOR %s does not match previous BEGIN-VENDOR %s", argv[0],
1957 dctx->stack[dctx->stack_depth].da->name);
1958 goto error;
1959 }
1960
1961 dctx->stack_depth--;
1962
1963 return 0;
1964}
1965
1966/*
1967 * Process the ENUM command
1968 */
1969static int dict_read_process_enum(dict_tokenize_ctx_t *dctx, char **argv, int argc,
1970 fr_dict_attr_flags_t *base_flags)
1971{
1972 fr_dict_attr_t const *parent;
1973 fr_dict_attr_t *da = NULL;
1974
1975 if (argc != 2) {
1976 fr_strerror_const("Invalid ENUM syntax");
1977 return -1;
1978 }
1979
1980 /*
1981 * Dictionaries need to have real names, not shitty ones.
1982 */
1983 if (strncmp(argv[0], "Attr-", 5) == 0) {
1984 fr_strerror_const("Invalid ENUM name");
1985 return -1;
1986 }
1987
1988#ifdef STATIC_ANALYZER
1989 if (!dctx->dict) goto error;
1990#endif
1991
1992 /*
1993 * Allocate the attribute here, and then fill in the fields
1994 * as we start parsing the various elements of the definition.
1995 */
1996 da = dict_attr_alloc_null(dctx->dict->pool, dctx->dict->proto);
1997 if (unlikely(da == NULL)) return -1;
1998 dict_attr_location_set(dctx, da);
1999 da->dict = dctx->dict;
2000
2001 /*
2002 * Set the attribute flags from the base flags.
2003 */
2004 memcpy(&da->flags, base_flags, sizeof(da->flags));
2005
2006 da->flags.name_only = true; /* values for ENUM are irrelevant */
2007 da->flags.internal = true; /* ENUMs will never get encoded into a protocol */
2008#if 0
2009 flags.is_enum = true; /* it's an enum, and can't be assigned to a #fr_pair_t */
2010#endif
2011
2012 /*
2013 * Set the base type of the attribute.
2014 */
2015 if (dict_process_type_field(dctx, argv[1], &da) < 0) {
2016 error:
2017 talloc_free(da);
2018 return -1;
2019 }
2020
2021 if (da->flags.extra && (da->flags.subtype == FLAG_BIT_FIELD)) {
2022 fr_strerror_const("Bit fields can only be defined as a MEMBER of a STRUCT");
2023 goto error;
2024 }
2025
2026 switch (da->type) {
2027 case FR_TYPE_LEAF:
2028 break;
2029
2030 default:
2031 fr_strerror_printf("ENUMs can only be a leaf type, not %s",
2032 fr_type_to_str(da->type));
2033 break;
2034 }
2035
2036 parent = dctx->stack[dctx->stack_depth].da;
2037 if (!parent) {
2038 fr_strerror_const("Invalid location for ENUM");
2039 goto error;
2040 }
2041
2042 /*
2043 * ENUMs cannot have a flag field, so we don't parse that.
2044 *
2045 * Maybe we do want a flag field for named time deltas?
2046 */
2047
2048 if (unlikely(dict_attr_parent_init(&da, parent) < 0)) goto error;
2049 if (unlikely(dict_attr_finalise(&da, argv[0]) < 0)) goto error;
2050
2051 /*
2052 * Add the attribute we allocated earlier
2053 */
2054 switch (dict_attr_add_or_fixup(&dctx->fixup, &da)) {
2055 default:
2056 goto error;
2057
2058 case 0:
2059 memcpy(&dctx->value_attr, &da, sizeof(da));
2060 break;
2061
2062 case 1:
2063 break;
2064 }
2065
2066 return 0;
2067}
2068
2069/*
2070 * Process the FLAGS command
2071 */
2072static int dict_read_process_flags(UNUSED dict_tokenize_ctx_t *dctx, char **argv, int argc,
2073 fr_dict_attr_flags_t *base_flags)
2074{
2075 bool sense = true;
2076
2077 if (argc == 1) {
2078 char *p;
2079
2080 p = argv[0];
2081 if (*p == '!') {
2082 sense = false;
2083 p++;
2084 }
2085
2086 if (strcmp(p, "internal") == 0) {
2087 base_flags->internal = sense;
2088 return 0;
2089 }
2090 }
2091
2092 fr_strerror_const("Invalid FLAGS syntax");
2093 return -1;
2094}
2095
2096/*
2097 * Process the MEMBER command
2098 */
2099static int dict_read_process_member(dict_tokenize_ctx_t *dctx, char **argv, int argc,
2100 fr_dict_attr_flags_t *base_flags)
2101{
2102 fr_dict_attr_t *da = NULL;
2103
2104 if ((argc < 2) || (argc > 3)) {
2105 fr_strerror_const("Invalid MEMBER syntax");
2106 return -1;
2107 }
2108
2109 if (dctx->stack[dctx->stack_depth].da->type != FR_TYPE_STRUCT) {
2110 fr_strerror_printf("MEMBER can only be used for ATTRIBUTEs of type 'struct', not %s of type %s",
2111 dctx->stack[dctx->stack_depth].da->name,
2112 fr_type_to_str(dctx->stack[dctx->stack_depth].da->type));
2113 return -1;
2114 }
2115
2116 /*
2117 * Check if the parent 'struct' is fixed size. And if
2118 * so, complain if we're adding a variable sized member.
2119 */
2120 if (dctx->stack[dctx->stack_depth].struct_is_closed) {
2121 fr_strerror_printf("Cannot add MEMBER to 'struct' %s after a variable sized member %s",
2122 dctx->stack[dctx->stack_depth].da->name,
2123 dctx->stack[dctx->stack_depth].struct_is_closed->name);
2124 return -1;
2125 }
2126
2127 /*
2128 * We don't set the attribute number before parsing the
2129 * type and flags. The number is chosen internally, and
2130 * no one should depend on it.
2131 *
2132 * Although _arguably_, it may be useful to know which
2133 * field this is, 0..N?
2134 */
2135 if (dict_read_process_common(dctx, &da, dctx->stack[dctx->stack_depth].da, argv[0], argv[1],
2136 (argc > 2) ? argv[2] : NULL, base_flags) < 0) {
2137 return -1;
2138 }
2139
2140#ifdef STATIC_ANALYZER
2141 if (!dctx->dict) goto error;
2142#endif
2143
2144 /*
2145 * If our parent is a fixed-size struct, then we have to be fixed-size, too.
2146 */
2147 da->flags.is_known_width |= dctx->stack[dctx->stack_depth].da->flags.is_known_width;
2148
2149 /*
2150 * Double check any bit field magic
2151 */
2152 if (dctx->stack[dctx->stack_depth].member_num > 0) {
2153 fr_dict_attr_t const *previous;
2154
2155 previous = dict_attr_child_by_num(dctx->stack[dctx->stack_depth].da,
2156 dctx->stack[dctx->stack_depth].member_num);
2157 /*
2158 * Check that the previous bit field ended on a
2159 * byte boundary.
2160 *
2161 * Note that the previous attribute might be a deferred TLV, in which case it doesn't
2162 * exist. That's fine.
2163 */
2164 if (previous && previous->flags.extra && (previous->flags.subtype == FLAG_BIT_FIELD)) {
2165 /*
2166 * This attribute is a bit field. Keep
2167 * track of where in the byte we are
2168 * located.
2169 */
2170 if (da->flags.extra && (da->flags.subtype == FLAG_BIT_FIELD)) {
2171 da->flags.flag_byte_offset = (da->flags.length + previous->flags.flag_byte_offset) & 0x07;
2172
2173 } else {
2174 if (previous->flags.flag_byte_offset != 0) {
2175 fr_strerror_printf("Previous bitfield %s did not end on a byte boundary",
2176 previous->name);
2177 error:
2178 talloc_free(da);
2179 return -1;
2180 }
2181 }
2182 }
2183 }
2184
2185 /*
2186 * Ensure that no previous child has "key" or "length" set.
2187 */
2188 if (da->type == FR_TYPE_TLV) {
2189 fr_dict_attr_t const *key;
2190 int i;
2191
2192 /*
2193 * @todo - cache the key field in the stack frame, so we don't have to loop over the children.
2194 */
2195 for (i = 1; i <= dctx->stack[dctx->stack_depth].member_num; i++) {
2196 key = dict_attr_child_by_num(dctx->stack[dctx->stack_depth].da, i);
2197 if (!key) continue; /* really should be WTF? */
2198
2199 if (fr_dict_attr_is_key_field(key)) {
2200 fr_strerror_printf("'struct' %s has a 'key' field %s, and cannot end with a TLV %s",
2201 dctx->stack[dctx->stack_depth].da->name, key->name, argv[0]);
2202 goto error;
2203 }
2204
2205 if (da_is_length_field(key)) {
2206 fr_strerror_printf("'struct' %s has a 'length' field %s, and cannot end with a TLV %s",
2207 dctx->stack[dctx->stack_depth].da->name, key->name, argv[0]);
2208 goto error;
2209 }
2210 }
2211 }
2212
2213 if (unlikely(dict_attr_num_init(da, ++dctx->stack[dctx->stack_depth].member_num) < 0)) goto error;
2214 if (unlikely(dict_attr_finalise(&da, argv[0]) < 0)) goto error;
2215
2216 /*
2217 * Check to see if this is a duplicate attribute
2218 * and whether we should ignore it or error out...
2219 */
2220 switch (dict_attr_allow_dup(da)) {
2221 case 1:
2222 break;
2223
2224 case 0:
2225 talloc_free(da);
2226 return 0;
2227
2228 default:
2229 goto error;
2230 }
2231
2232 switch (dict_attr_add_or_fixup(&dctx->fixup, &da)) {
2233 default:
2234 goto error;
2235
2236 /* New attribute, fixup stack */
2237 case 0:
2238 /*
2239 * A 'struct' can have a MEMBER of type 'tlv', but ONLY
2240 * as the last entry in the 'struct'. If we see that,
2241 * set the previous attribute to the TLV we just added.
2242 * This allows the children of the TLV to be parsed as
2243 * partial OIDs, so we don't need to know the full path
2244 * to them.
2245 */
2246 if (da->type == FR_TYPE_TLV) {
2248 dctx->stack[dctx->stack_depth].member_num);
2249 if (dctx->relative_attr && (dict_dctx_push(dctx, dctx->relative_attr, 0) < 0)) return -1;
2250 return 0;
2251
2252 }
2253
2254 /*
2255 * Add the size of this member to the parent struct.
2256 */
2257 if (dctx->stack[dctx->stack_depth].da->flags.length) {
2258 /*
2259 * Fixed-size struct can't have MEMBERs of unknown sizes.
2260 */
2261 if (!da->flags.is_known_width) {
2262 fr_strerror_printf("'struct' %s has fixed size %u, but member %s is of unknown size",
2263 dctx->stack[dctx->stack_depth].da->name, dctx->stack[dctx->stack_depth].da->flags.length,
2264 argv[0]);
2265 return -1;
2266 }
2267
2268 dctx->stack[dctx->stack_depth].struct_size += da->flags.length;
2269
2270 }
2271
2272 /*
2273 * Check for overflow.
2274 */
2275 if (dctx->stack[dctx->stack_depth].da->flags.length &&
2276 (dctx->stack[dctx->stack_depth].struct_size > dctx->stack[dctx->stack_depth].da->flags.length)) {
2277 fr_strerror_printf("'struct' %s has fixed size %u, but member %s overflows that length",
2278 dctx->stack[dctx->stack_depth].da->name, dctx->stack[dctx->stack_depth].da->flags.length,
2279 argv[0]);
2280 return -1;
2281 }
2282
2283 if (dict_set_value_attr(dctx, da) < 0) return -1;
2284
2285 /*
2286 * Check if this MEMBER closes the structure.
2287 *
2288 * @todo - close this struct if the child struct is variable sized. For now, it
2289 * looks like most child structs are at the end of the parent.
2290 *
2291 * The solution is to update the unwind() function to check if the da we've
2292 * unwound to is a struct, and then if so... get the last child, and mark it
2293 * closed.
2294 */
2295 if (!da->flags.is_known_width) dctx->stack[dctx->stack_depth].struct_is_closed = da;
2296 break;
2297
2298 /* Deferred attribute, don't begin the TLV section automatically */
2299 case 1:
2300 break;
2301 }
2302
2303 return 0;
2304}
2305
2306/** Process a STRUCT name attr value
2307 *
2308 * Define struct 'name' when key 'attr' has 'value'.
2309 *
2310 * Which MUST be a sub-structure of another struct
2311 */
2312static int dict_read_process_struct(dict_tokenize_ctx_t *dctx, char **argv, int argc,
2313 UNUSED fr_dict_attr_flags_t *base_flags)
2314{
2316 int i;
2317 fr_dict_attr_t const *parent = NULL;
2318 unsigned int attr;
2319 char *key_attr = argv[1];
2320 char *name = argv[0];
2321 fr_dict_attr_t *da;
2322
2323 if ((argc < 3) || (argc > 4)) {
2324 fr_strerror_const("Invalid STRUCT syntax");
2325 return -1;
2326 }
2327
2328 fr_assert(dctx->stack_depth > 0);
2329
2330 /*
2331 * Unwind the stack until we find a parent which has a child named "key_attr"
2332 */
2333 for (i = dctx->stack_depth; i > 0; i--) {
2334 parent = dict_attr_by_name(NULL, dctx->stack[i].da, key_attr);
2335 if (parent) {
2336 dctx->stack_depth = i;
2337 break;
2338 }
2339 }
2340
2341 /*
2342 * Else maybe it's a fully qualified name?
2343 */
2344 if (!parent) {
2345 parent = fr_dict_attr_by_oid(NULL, dctx->stack[dctx->stack_depth].da->dict->root, key_attr);
2346 }
2347
2348 if (!parent) {
2349 fr_strerror_printf("Invalid STRUCT definition, unknown key attribute %s",
2350 key_attr);
2351 return -1;
2352 }
2353
2355 fr_strerror_printf("Attribute '%s' is not a 'key' attribute", key_attr);
2356 return -1;
2357 }
2358
2359 /*
2360 * Rely on dict_attr_flags_valid() to ensure that
2361 * da->type is an unsigned integer, AND that da->parent->type == struct
2362 */
2363 if (!fr_cond_assert(parent->parent->type == FR_TYPE_STRUCT)) return -1;
2364
2365 /*
2366 * Parse the value.
2367 */
2368 if (fr_value_box_from_str(NULL, &value, parent->type, NULL, argv[2], strlen(argv[2]), NULL) < 0) {
2369 fr_strerror_printf_push("Invalid value for STRUCT \"%s\"", argv[2]);
2370 return -1;
2371 }
2372
2373 /*
2374 * Allocate the attribute here, and then fill in the fields
2375 * as we start parsing the various elements of the definition.
2376 */
2377 da = dict_attr_alloc_null(dctx->dict->pool, dctx->dict->proto);
2378 if (unlikely(da == NULL)) return -1;
2379 dict_attr_location_set(dctx, da);
2380 da->dict = dctx->dict;
2381
2383 error:
2384 talloc_free(da);
2385 return -1;
2386 }
2387
2388 /*
2389 * Structs can be prefixed with 16-bit lengths, but not
2390 * with any other type of length.
2391 */
2392 if (argc == 4) {
2393 if (dict_process_flag_field(dctx, argv[3], &da) < 0) goto error;
2394 }
2395
2396 /*
2397 * @todo - auto-number from a parent UNION, instead of overloading the value.
2398 */
2399 switch (parent->type) {
2400 case FR_TYPE_UINT8:
2401 attr = value.vb_uint8;
2402 break;
2403
2404 case FR_TYPE_UINT16:
2405 attr = value.vb_uint16;
2406 break;
2407
2408 case FR_TYPE_UINT32:
2409 attr = value.vb_uint32;
2410 break;
2411
2412 default:
2413 fr_strerror_printf("Invalid data type in attribute '%s'", key_attr);
2414 return -1;
2415 }
2416
2417 if (unlikely(dict_attr_num_init(da, attr) < 0)) goto error;
2418 if (unlikely(dict_attr_parent_init(&da, parent) < 0)) goto error;
2419 if (unlikely(dict_attr_finalise(&da, name) < 0)) goto error;
2420
2421 /*
2422 * Check to see if this is a duplicate attribute
2423 * and whether we should ignore it or error out...
2424 */
2425 switch (dict_attr_allow_dup(da)) {
2426 case 1:
2427 break;
2428
2429 case 0:
2430 talloc_free(da);
2431 return 0;
2432
2433 default:
2434 goto error;
2435 }
2436
2437 /*
2438 * Add the keyed STRUCT to the global namespace, and as a child of "parent".
2439 */
2440 switch (dict_attr_add_or_fixup(&dctx->fixup, &da)) {
2441 default:
2442 goto error;
2443
2444 /* FIXME: Should dict_attr_enum_add_name also be called in the fixup code? */
2445 case 0:
2446 da = dict_attr_by_name(NULL, parent, name);
2447 if (!da) return -1;
2448
2449 /*
2450 * A STRUCT definition is an implicit BEGIN-STRUCT.
2451 */
2452 dctx->relative_attr = NULL;
2453 if (dict_dctx_push(dctx, da, 0) < 0) return -1;
2454
2455 /*
2456 * Add the VALUE to the parent attribute, and ensure that
2457 * the VALUE also contains a pointer to the child struct.
2458 */
2459 if (dict_attr_enum_add_name(fr_dict_attr_unconst(parent), name, &value, false, true, da) < 0) {
2461 return -1;
2462 }
2464 break;
2465
2466 case 1:
2467 break;
2468 }
2469
2470 return 0;
2471}
2472
2473/** Process a value alias
2474 *
2475 */
2476static int dict_read_process_value(dict_tokenize_ctx_t *dctx, char **argv, int argc,
2477 UNUSED fr_dict_attr_flags_t *base_flags)
2478{
2479 fr_dict_attr_t *da;
2481 fr_slen_t enum_len;
2482 fr_dict_attr_t const *parent = dctx->stack[dctx->stack_depth].da;
2483
2484 if (argc != 3) {
2485 fr_strerror_const("Invalid VALUE syntax");
2486 return -1;
2487 }
2488
2489 /*
2490 * Most VALUEs are bunched together by ATTRIBUTE. We can
2491 * save a lot of lookups on dictionary initialization by
2492 * caching the last attribute for a VALUE.
2493 *
2494 * If it's not the same, we look up the attribute in the
2495 * current context, which is generally:
2496 *
2497 * * the current attribute of type `struct`
2498 * * if no `struct`, then the VENDOR for VSAs
2499 * * if no VENDOR, then the dictionary root
2500 */
2501 if (!dctx->value_attr || (strcasecmp(argv[0], dctx->value_attr->name) != 0)) {
2502 fr_dict_attr_t const *tmp;
2503
2504 if (!(tmp = fr_dict_attr_by_oid(NULL, parent, argv[0]))) goto fixup;
2505 dctx->value_attr = fr_dict_attr_unconst(tmp);
2506 }
2507 da = dctx->value_attr;
2508
2509 /*
2510 * Verify the enum name matches the expected from.
2511 */
2512 enum_len = (fr_slen_t)strlen(argv[1]);
2513 if (fr_dict_enum_name_from_substr(NULL, NULL, &FR_SBUFF_IN(argv[1], enum_len), NULL) != enum_len) {
2514 fr_strerror_printf_push("Invalid VALUE name '%s' for attribute '%s'", argv[1], da->name);
2515 return -1;
2516 }
2517
2518 /*
2519 * Remember which attribute is associated with this
2520 * value. This allows us to define enum
2521 * values before the attribute exists, and fix them
2522 * up later.
2523 */
2524 if (!da) {
2525 fixup:
2526 if (!fr_cond_assert_msg(dctx->fixup.pool, "fixup pool context invalid")) return -1;
2527
2529 CURRENT_FRAME(dctx)->filename, CURRENT_FRAME(dctx)->line,
2530 argv[0], strlen(argv[0]),
2531 argv[1], strlen(argv[1]),
2532 argv[2], strlen(argv[2]), parent) < 0) {
2533 fr_strerror_const("Out of memory");
2534 return -1;
2535 }
2536 return 0;
2537 }
2538
2539 /*
2540 * Only a leaf types can have values defined.
2541 */
2542 if (!fr_type_is_leaf(da->type)) {
2543 fr_strerror_printf_push("Cannot define VALUE for attribute '%s' of data type '%s'", da->name,
2544 fr_type_to_str(da->type));
2545 return -1;
2546 }
2547
2548 if (fr_value_box_from_str(NULL, &value, da->type, NULL,
2549 argv[2], strlen(argv[2]),
2550 NULL) < 0) {
2551 fr_strerror_printf_push("Invalid VALUE '%s' for attribute '%s' of data type '%s'",
2552 argv[2],
2553 da->name,
2554 fr_type_to_str(da->type));
2555 return -1;
2556 }
2557
2558 if (fr_dict_enum_add_name(da, argv[1], &value, false, true) < 0) {
2560 return -1;
2561 }
2563
2564 return 0;
2565}
2566
2567/*
2568 * Process the VENDOR command
2569 */
2570static int dict_read_process_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
2571{
2572 unsigned int value;
2573 int type, length;
2574 bool continuation = false;
2575 fr_dict_vendor_t const *dv;
2576 fr_dict_vendor_t *mutable;
2577 fr_dict_t *dict = dctx->dict;
2578
2579 dctx->value_attr = NULL;
2580 dctx->relative_attr = NULL;
2581
2582 if ((argc < 2) || (argc > 3)) {
2583 fr_strerror_const("Invalid VENDOR syntax");
2584 return -1;
2585 }
2586
2587 /*
2588 * Validate all entries
2589 */
2590 if (!dict_read_sscanf_i(&value, argv[1])) {
2591 fr_strerror_const("Invalid number in VENDOR");
2592 return -1;
2593 }
2594
2595 /*
2596 * Look for a format statement. Allow it to over-ride the hard-coded formats below.
2597 */
2598 if (argc == 3) {
2599 if (dict_read_parse_format(argv[2], &type, &length, &continuation) < 0) return -1;
2600
2601 } else {
2602 type = length = 1;
2603 }
2604
2605 /* Create a new VENDOR entry for the list */
2606 if (dict_vendor_add(dict, argv[0], value) < 0) return -1;
2607
2608 dv = fr_dict_vendor_by_num(dict, value);
2609 if (!dv) {
2610 fr_strerror_const("Failed adding format for VENDOR");
2611 return -1;
2612 }
2613
2614 mutable = UNCONST(fr_dict_vendor_t *, dv);
2615 mutable->type = type;
2616 mutable->length = length;
2617 mutable->continuation = continuation;
2618
2619 return 0;
2620}
2621
2622/** Register the specified dictionary as a protocol dictionary
2623 *
2624 * Allows vendor and TLV context to persist across $INCLUDEs
2625 */
2626static int dict_read_process_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flag)
2627{
2628 unsigned int value;
2629 unsigned int type_size = 0;
2630 fr_dict_t *dict;
2631 fr_dict_attr_t *mutable;
2632 bool require_dl = false;
2633 bool string_based = false;
2634
2635 dctx->value_attr = NULL;
2636 dctx->relative_attr = NULL;
2637
2638 if ((argc < 2) || (argc > 3)) {
2639 fr_strerror_const("Missing arguments after PROTOCOL. Expected PROTOCOL <num> <name>");
2640 return -1;
2641 }
2642
2643 /*
2644 * Validate all entries
2645 */
2646 if (!dict_read_sscanf_i(&value, argv[1])) {
2647 fr_strerror_printf("Invalid number '%s' following PROTOCOL", argv[1]);
2648 return -1;
2649 }
2650
2651 /*
2652 * 255 protocols FR_TYPE_GROUP type_size hack
2653 */
2654 if (!value) {
2655 fr_strerror_printf("Invalid value '%u' following PROTOCOL", value);
2656 return -1;
2657 }
2658
2659 /*
2660 * Look for a format statement. This may specify the
2661 * type length of the protocol's types.
2662 */
2663 if (argc == 3) {
2664 char const *p;
2665 char *q;
2666
2667 /*
2668 * For now, we don't allow multiple options here.
2669 *
2670 * @todo - allow multiple options.
2671 */
2672 if (strcmp(argv[2], "verify=lib") == 0) {
2673 require_dl = true;
2674 goto post_option;
2675 }
2676
2677 if (strcmp(argv[2], "format=string") == 0) {
2678 type_size = 4;
2679 string_based = true;
2680 goto post_option;
2681 }
2682
2683 if (strncasecmp(argv[2], "format=", 7) != 0) {
2684 fr_strerror_printf("Invalid format for PROTOCOL. Expected 'format=', got '%s'", argv[2]);
2685 return -1;
2686 }
2687 p = argv[2] + 7;
2688
2689 type_size = strtoul(p, &q, 10);
2690 if (q != (p + strlen(p))) {
2691 fr_strerror_printf("Found trailing garbage '%s' after format specifier", p);
2692 return -1;
2693 }
2694 }
2695post_option:
2696
2697 /*
2698 * Cross check name / number.
2699 */
2700 dict = dict_by_protocol_name(argv[0]);
2701 if (dict) {
2702#ifdef STATIC_ANALYZER
2703 if (!dict->root) return -1;
2704#endif
2705
2706 if (dict->root->attr != value) {
2707 fr_strerror_printf("Conflicting numbers %u vs %u for PROTOCOL \"%s\"",
2708 dict->root->attr, value, dict->root->name);
2709 return -1;
2710 }
2711
2712 } else if ((dict = dict_by_protocol_num(value)) != NULL) {
2713#ifdef STATIC_ANALYZER
2714 if (!dict->root || !dict->root->name || !argv[0]) return -1;
2715#endif
2716
2717 if (strcasecmp(dict->root->name, argv[0]) != 0) {
2718 fr_strerror_printf("Conflicting names current \"%s\" vs new \"%s\" for PROTOCOL %u",
2719 dict->root->name, argv[0], dict->root->attr);
2720 return -1;
2721 }
2722 }
2723
2724 /*
2725 * And check types no matter what.
2726 */
2727 if (dict) {
2728 if (type_size && (dict->root->flags.type_size != type_size)) {
2729 fr_strerror_printf("Conflicting flags for PROTOCOL \"%s\" (current %d versus new %u)",
2730 dict->root->name, dict->root->flags.type_size, type_size);
2731 return -1;
2732 }
2733 goto done;
2734 }
2735
2736 dict = dict_alloc(dict_gctx);
2737
2738 /*
2739 * Try to load protocol-specific validation routines.
2740 * Some protocols don't need them, so it's OK if the
2741 * validation routines don't exist.
2742 */
2743 if ((dict_dlopen(dict, argv[0]) < 0) && require_dl) {
2744 error:
2745 talloc_free(dict);
2746 return -1;
2747 }
2748
2749 /*
2750 * Set the root attribute with the protocol name
2751 */
2752 if (dict_root_set(dict, argv[0], value) < 0) goto error;
2753
2754 if (dict_protocol_add(dict) < 0) goto error;
2755
2756 mutable = UNCONST(fr_dict_attr_t *, dict->root);
2757 dict->string_based = string_based;
2758 if (!type_size) {
2759 mutable->flags.type_size = dict->proto->default_type_size;
2760 mutable->flags.length = dict->proto->default_type_length;
2761 } else {
2762 mutable->flags.type_size = type_size;
2763 mutable->flags.length = 1; /* who knows... */
2764 }
2765
2766done:
2767 /*
2768 * Make the root available on the stack, in case
2769 * something wants to begin it...
2770 */
2771 if (unlikely(dict_dctx_push_or_update(dctx, dict->root, NEST_NONE) < 0)) goto error;
2772
2773 return 0;
2774}
2775
2776/** Maintain a linked list of filenames which we've seen loading this dictionary
2777 *
2778 * This is used for debug messages, so we have a copy of the original file path
2779 * that we can reference from fr_dict_attr_t without having the memory bloat of
2780 * assigning a buffer to every attribute.
2781 */
2782static inline int dict_filename_add(char **filename_out, fr_dict_t *dict, char const *filename,
2783 char const *src_file, int src_line)
2784{
2786
2787 file = talloc_zero(dict, fr_dict_filename_t);
2788 if (unlikely(!file)) {
2789 oom:
2790 fr_strerror_const("Out of memory");
2791 return -1;
2792 }
2793 *filename_out = file->filename = talloc_typed_strdup(file, filename);
2794 if (unlikely(!*filename_out)) goto oom;
2795
2796 if (src_file) {
2797 file->src_line = src_line;
2798 file->src_file = talloc_typed_strdup(file, src_file);
2799 if (!file->src_file) goto oom;
2800 }
2801
2802 fr_dlist_insert_tail(&dict->filenames, file);
2803
2804 return 0;
2805}
2806
2807#ifndef NDEBUG
2808/** See if we have already loaded the file,
2809 *
2810 */
2811static inline bool dict_filename_loaded(fr_dict_t *dict, char const *filename,
2812 char const *src_file, int src_line)
2813{
2815
2816 for (file = (fr_dict_filename_t *) fr_dlist_head(&dict->filenames);
2817 file != NULL;
2818 file = (fr_dict_filename_t *) fr_dlist_next(&dict->filenames, &file->entry)) {
2819 if (file->src_file && src_file) {
2820 if (file->src_line != src_line) continue;
2821 if (strcmp(file->src_file, src_file) != 0) continue;
2822 }
2823
2824 if (strcmp(file->filename, filename) == 0) return true; /* this should always be true */
2825 }
2826
2827 return false;
2828}
2829#endif
2830
2832{
2833 fr_dict_attr_t const *da;
2834
2835 da = dctx->stack[dctx->stack_depth].da;
2836 if (da->type == FR_TYPE_STRUCT) {
2837 /*
2838 * The structure was fixed-size,
2839 * but the fields don't fill it.
2840 * That's an error.
2841 *
2842 * Since process_member() checks
2843 * for overflow, the check here
2844 * is really only for underflow.
2845 */
2846 if (da->flags.length && (dctx->stack[dctx->stack_depth].struct_size != da->flags.length)) {
2847 fr_strerror_printf("MEMBERs of %s struct[%u] do not exactly fill the fixed-size structure",
2848 da->name, da->flags.length);
2849 return -1;
2850 }
2851
2852 /*
2853 * If the structure is fixed
2854 * size, AND small enough to fit
2855 * into an 8-bit length field,
2856 * then update the length field
2857 * with the structure size/
2858 */
2859 if (dctx->stack[dctx->stack_depth].struct_size <= 255) {
2860 UNCONST(fr_dict_attr_t *, da)->flags.length = dctx->stack[dctx->stack_depth].struct_size;
2861 } /* else length 0 means "unknown / variable size / too large */
2862 } else {
2863 fr_assert_msg(da->type == FR_TYPE_TLV, "Expected parent type of 'tlv', got '%s'", fr_type_to_str(da->type));
2864 }
2865
2866 return 0;
2867}
2868
2869/** Process an inline BEGIN PROTOCOL block
2870 */
2872{
2873 fr_dict_attr_t const *da;
2874
2876 da = CURRENT_DA(dctx);
2877 fr_assert_msg(fr_type_is_tlv(da->type), "Expected dictionary root to be a tlv, got '%s'", fr_type_to_str(da->type));
2878 fr_assert(da->flags.is_root);
2879
2880 dctx->dict = da->dict;
2881
2882 /*
2883 * Push a PROTOCOL block onto the stack
2884 */
2885 return dict_dctx_push(dctx, da, NEST_PROTOCOL);
2886}
2887
2888/** Keyword parser
2889 *
2890 * @param[in] dctx containing the dictionary we're currently parsing.
2891 * @param[in] argv arguments to the keyword.
2892 * @param[in] argc number of arguments.
2893 * @param[in] base_flags set in the context of the current file.
2894 * @return
2895 * - 0 on success.
2896 * - -1 on failure.
2897 */
2898typedef int (*fr_dict_keyword_parse_t)(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags);
2899
2900/** Pushes a new frame onto the top of the stack based on the current frame
2901 *
2902 * Whenever a protocol, vendor, or attribute is defined in the dictionary it either mutates or
2903 * pushes a new NONE frame onto the stack. This holds the last defined object at a given level
2904 * of nesting.
2905 *
2906 * This function is used to push an additional frame onto the stack, effectively entering the
2907 * context of the last defined object at a given level of nesting
2908 *
2909 * @param[in] dctx Contains the current state of the dictionary parser.
2910 * Used to track what PROTOCOL, VENDOR or TLV block
2911 * we're in.
2912 * @return
2913 * - 0 on success.
2914 * - -1 on failure.
2915 */
2917
2918typedef struct {
2919 fr_dict_keyword_parse_t parse; //!< Function to parse the keyword with.
2920 fr_dict_section_begin_t begin; //!< Can have a BEGIN prefix
2922
2923typedef struct {
2924 fr_table_elem_name_t name; //!< Name of the keyword, e.g. "ATTRIBUTE"
2925 fr_dict_keyword_parser_t value; //!< Value to return from lookup.
2927
2929 fr_dict_keyword, fr_dict_keyword_parser_t const *, fr_dict_keyword_parser_t const *)
2930
2931/** Parse a dictionary file
2932 *
2933 * @param[in] dctx Contains the current state of the dictionary parser.
2934 * Used to track what PROTOCOL, VENDOR or TLV block
2935 * we're in. Block context changes in $INCLUDEs should
2936 * not affect the context of the including file.
2937 * @param[in] dir_name Directory containing the dictionary we're loading.
2938 * @param[in] filename we're parsing.
2939 * @param[in] src_file The including file.
2940 * @param[in] src_line Line on which the $INCLUDE or $NCLUDE- statement was found.
2941 * @return
2942 * - 0 on success.
2943 * - -1 on failure.
2944 */
2945static int _dict_from_file(dict_tokenize_ctx_t *dctx,
2946 char const *dir_name, char const *filename,
2947 char const *src_file, int src_line)
2948{
2949 static fr_dict_keyword_t const keywords[] = {
2950 { L("ALIAS"), { .parse = dict_read_process_alias } },
2951 { L("ATTRIBUTE"), { .parse = dict_read_process_attribute } },
2952 { L("BEGIN-PROTOCOL"), { .parse = dict_read_process_begin_protocol } },
2953 { L("BEGIN-VENDOR"), { .parse = dict_read_process_begin_vendor } },
2954 { L("DEFINE"), { .parse = dict_read_process_define } },
2955 { L("END"), { .parse = dict_read_process_end } },
2956 { L("END-PROTOCOL"), { .parse = dict_read_process_end_protocol } },
2957 { L("END-VENDOR"), { .parse = dict_read_process_end_vendor } },
2958 { L("ENUM"), { .parse = dict_read_process_enum } },
2959 { L("FLAGS"), { .parse = dict_read_process_flags } },
2960 { L("MEMBER"), { .parse = dict_read_process_member } },
2961 { L("PROTOCOL"), { .parse = dict_read_process_protocol, .begin = dict_begin_protocol }},
2962 { L("STRUCT"), { .parse = dict_read_process_struct } },
2963 { L("VALUE"), { .parse = dict_read_process_value } },
2964 { L("VENDOR"), { .parse = dict_read_process_vendor } },
2965 };
2966
2967 FILE *fp;
2968 char dir[256], fn[256];
2969 char buf[256];
2970 char *p;
2971 int line = 0;
2972 bool was_member = false;
2973
2974 struct stat statbuf;
2975 char *argv[DICT_MAX_ARGV];
2976 int argc;
2977
2978 /*
2979 * Base flags are only set for the current file
2980 */
2981 fr_dict_attr_flags_t base_flags = {};
2982
2983 if (!fr_cond_assert(!dctx->dict->root || dctx->stack[dctx->stack_depth].da)) return -1;
2984
2985 if ((strlen(dir_name) + 3 + strlen(filename)) > sizeof(dir)) {
2986 fr_strerror_printf_push("%s: Filename name too long", "Error reading dictionary");
2987 return -1;
2988 }
2989
2990 /*
2991 * If it's an absolute dir, forget the parent dir,
2992 * and remember the new one.
2993 *
2994 * If it's a relative dir, tack on the current filename
2995 * to the parent dir. And use that.
2996 */
2997 if (!FR_DIR_IS_RELATIVE(filename)) {
2998 strlcpy(dir, filename, sizeof(dir));
2999 p = strrchr(dir, FR_DIR_SEP);
3000 if (p) {
3001 p[1] = '\0';
3002 } else {
3003 strlcat(dir, "/", sizeof(dir));
3004 }
3005
3006 strlcpy(fn, filename, sizeof(fn));
3007 } else {
3008 strlcpy(dir, dir_name, sizeof(dir));
3009 p = strrchr(dir, FR_DIR_SEP);
3010 if (p) {
3011 if (p[1]) strlcat(dir, "/", sizeof(dir));
3012 } else {
3013 strlcat(dir, "/", sizeof(dir));
3014 }
3015 strlcat(dir, filename, sizeof(dir));
3016 p = strrchr(dir, FR_DIR_SEP);
3017 if (p) {
3018 p[1] = '\0';
3019 } else {
3020 strlcat(dir, "/", sizeof(dir));
3021 }
3022
3023 p = strrchr(filename, FR_DIR_SEP);
3024 if (p) {
3025 snprintf(fn, sizeof(fn), "%s%s", dir, p);
3026 } else {
3027 snprintf(fn, sizeof(fn), "%s%s", dir, filename);
3028 }
3029 }
3030
3031 /*
3032 * See if we have already loaded this filename. If so, suppress it.
3033 */
3034#ifndef NDEBUG
3035 if (unlikely(dict_filename_loaded(dctx->dict, fn, src_file, src_line))) {
3036 fr_strerror_printf("ERROR - we have a recursive $INCLUDE or load of dictionary %s", fn);
3037 return -1;
3038 }
3039#endif
3040
3041 if ((fp = fopen(fn, "r")) == NULL) {
3042 if (!src_file) {
3043 fr_strerror_printf_push("Couldn't open dictionary %s: %s", fr_syserror(errno), fn);
3044 } else {
3045 fr_strerror_printf_push("Error reading dictionary: %s[%d]: Couldn't open dictionary '%s': %s",
3046 fr_cwd_strip(src_file), src_line, fn,
3047 fr_syserror(errno));
3048 }
3049 return -2;
3050 }
3051
3052 /*
3053 * If fopen works, this works.
3054 */
3055 if (fstat(fileno(fp), &statbuf) < 0) {
3056 fr_strerror_printf_push("Failed stating dictionary \"%s\" - %s", fn, fr_syserror(errno));
3057
3058 perm_error:
3059 fclose(fp);
3060 return -1;
3061 }
3062
3063 if (!S_ISREG(statbuf.st_mode)) {
3064 fr_strerror_printf_push("Dictionary is not a regular file: %s", fn);
3065 goto perm_error;
3066 }
3067
3068 /*
3069 * Globally writable dictionaries means that users can control
3070 * the server configuration with little difficulty.
3071 */
3072#ifdef S_IWOTH
3073 if (dict_gctx->perm_check && ((statbuf.st_mode & S_IWOTH) != 0)) {
3074 fr_strerror_printf_push("Dictionary is globally writable: %s. "
3075 "Refusing to start due to insecure configuration", fn);
3076 goto perm_error;
3077 }
3078#endif
3079
3080 /*
3081 * Now that we've opened the file, copy the filename into the dictionary and add it to the ctx
3082 * This string is safe to assign to the filename pointer in any attributes added beneath the
3083 * dictionary.
3084 */
3085 if (unlikely(dict_filename_add(&CURRENT_FILENAME(dctx), dctx->dict, fn, src_file, src_line) < 0)) {
3086 goto perm_error;
3087 }
3088
3089 while (fgets(buf, sizeof(buf), fp) != NULL) {
3090 bool do_begin = false;
3091 fr_dict_keyword_parser_t const *parser;
3092 char **argv_p = argv;
3093
3094 dctx->stack[dctx->stack_depth].line = ++line;
3095
3096 switch (buf[0]) {
3097 case '#':
3098 case '\0':
3099 case '\n':
3100 case '\r':
3101 continue;
3102 }
3103
3104 /*
3105 * Comment characters should NOT be appearing anywhere but
3106 * as start of a comment;
3107 */
3108 p = strchr(buf, '#');
3109 if (p) *p = '\0';
3110
3111 argc = fr_dict_str_to_argv(buf, argv, DICT_MAX_ARGV);
3112 if (argc == 0) continue;
3113
3114 if (argc == 1) {
3115 fr_strerror_const("Invalid entry");
3116
3117 error:
3118 fr_strerror_printf_push("Failed parsing dictionary at %s[%d]", fr_cwd_strip(fn), line);
3119 fclose(fp);
3120 return -1;
3121 }
3122
3123 /*
3124 * Special prefix for "beginnable" keywords.
3125 * These are keywords that can automatically change
3126 * the context of subsequent definitions if they're
3127 * prefixed with a BEGIN keyword.
3128 */
3129 if (strcasecmp(argv_p[0], "BEGIN") == 0) {
3130 do_begin = true;
3131 argv_p++;
3132 argc--;
3133 }
3134
3135 if (fr_dict_keyword(&parser, keywords, NUM_ELEMENTS(keywords), argv_p[0], NULL)) {
3136 /*
3137 * We are allowed to have attributes
3138 * named for keywords. Most notably
3139 * "value". If there's no such attribute
3140 * 'value', then the user will get a
3141 * descriptive error.
3142 */
3143 if (do_begin && !parser->begin) {
3144 goto process_begin;
3145 }
3146
3147 /*
3148 * Note: This is broken. It won't apply correctly to deferred
3149 * definitions of attributes we need some kind of proper
3150 * finalisation API.
3151 */
3152 if (parser->parse == dict_read_process_member) {
3153 was_member = true;
3154 } else if (was_member) {
3155 if (unlikely(dict_struct_finalise(dctx) < 0)) goto error;
3156 was_member = false;
3157 }
3158 if (unlikely(parser->parse(dctx, argv_p + 1 , argc - 1, &base_flags) < 0)) goto error;
3159
3160 /*
3161 * We've processed the definition, now enter the section
3162 */
3163 if (do_begin && unlikely(parser->begin(dctx) < 0)) goto error;
3164 continue;
3165 }
3166
3167 /*
3168 * It's a naked BEGIN keyword
3169 */
3170 if (do_begin) {
3171 process_begin:
3172 if (unlikely(dict_read_process_begin(dctx, argv_p, argc, &base_flags) < 0)) goto error;
3173 continue;
3174 }
3175
3176 /*
3177 * See if we need to import another dictionary.
3178 */
3179 if (strncasecmp(argv_p[0], "$INCLUDE", 8) == 0) {
3180 /*
3181 * Included files operate on a copy of the context.
3182 *
3183 * This copy means that they inherit the
3184 * current context, including parents,
3185 * TLVs, etc. But if the included file
3186 * leaves a "dangling" TLV or "last
3187 * attribute", then it won't affect the
3188 * parent.
3189 */
3190 if (dict_read_process_include(dctx, argv_p, argc, dir) < 0) goto error;
3191 continue;
3192 } /* $INCLUDE */
3193
3194 /*
3195 * Any other string: We don't recognize it.
3196 */
3197 fr_strerror_printf_push("Invalid keyword '%s'", argv_p[0]);
3198 goto error;
3199 }
3200
3201 if (was_member && unlikely(dict_struct_finalise(dctx) < 0)) goto error;
3202
3203 /*
3204 * Note that we do NOT walk back up the stack to check
3205 * for missing END-FOO to match BEGIN-FOO. The context
3206 * was copied from the parent, so there are guaranteed to
3207 * be missing things.
3208 */
3209 fclose(fp);
3210
3211
3212 return 0;
3213}
3214
3215static int dict_from_file(fr_dict_t *dict,
3216 char const *dir_name, char const *filename,
3217 char const *src_file, int src_line)
3218{
3219 int ret;
3221
3222 memset(&dctx, 0, sizeof(dctx));
3223 dctx.dict = dict;
3224 dict_fixup_init(NULL, &dctx.fixup);
3225 dctx.stack[0].dict = dict;
3226 dctx.stack[0].da = dict->root;
3227 dctx.stack[0].nest = NEST_ROOT;
3228
3229 ret = _dict_from_file(&dctx, dir_name, filename, src_file, src_line);
3230 if (ret < 0) {
3231 talloc_free(dctx.fixup.pool);
3232 return ret;
3233 }
3234
3235 /*
3236 * Applies to any attributes added to the *internal*
3237 * dictionary.
3238 *
3239 * Fixups should have been applied already to any protocol
3240 * dictionaries.
3241 */
3242 return dict_finalise(&dctx);
3243}
3244
3245/** (Re-)Initialize the special internal dictionary
3246 *
3247 * This dictionary has additional programmatically generated attributes added to it,
3248 * and is checked in addition to the protocol specific dictionaries.
3249 *
3250 * @note The dictionary pointer returned in out must have its reference counter
3251 * decremented with #fr_dict_free when no longer used.
3252 *
3253 * @param[out] out Where to write pointer to the internal dictionary.
3254 * @param[in] dict_subdir name of the internal dictionary dir (may be NULL).
3255 * @param[in] dependent Either C src file, or another dictionary.
3256 * @return
3257 * - 0 on success.
3258 * - -1 on failure.
3259 */
3260int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent)
3261{
3262 fr_dict_t *dict;
3263 char *dict_path = NULL;
3264 size_t i;
3265 fr_dict_attr_flags_t flags = { .internal = true };
3266 char *type_name;
3267 fr_dict_attr_t *cast_base;
3269
3270 if (unlikely(!dict_gctx)) {
3271 fr_strerror_const("fr_dict_global_ctx_init() must be called before loading dictionary files");
3272 return -1;
3273 }
3274
3275 /*
3276 * Increase the reference count of the internal dictionary.
3277 */
3278 if (dict_gctx->internal) {
3281 return 0;
3282 }
3283
3284 dict_path = dict_subdir ?
3285 talloc_asprintf(NULL, "%s%c%s", fr_dict_global_ctx_dir(), FR_DIR_SEP, dict_subdir) :
3286 talloc_strdup(NULL, fr_dict_global_ctx_dir());
3287
3288 fr_strerror_clear(); /* Ensure we don't report spurious errors */
3289
3290 dict = dict_alloc(dict_gctx);
3291 if (!dict) {
3292 error:
3293 if (!dict_gctx->internal) talloc_free(dict);
3294 talloc_free(dict_path);
3295 return -1;
3296 }
3297
3298 /*
3299 * Set the root name of the dictionary
3300 */
3301 if (dict_root_set(dict, "internal", 0) < 0) goto error;
3302
3303 if (dict_path && dict_from_file(dict, dict_path, FR_DICTIONARY_FILE, NULL, 0) < 0) goto error;
3304
3305 TALLOC_FREE(dict_path);
3306
3307 dict_dependent_add(dict, dependent);
3308
3309 if (!dict_gctx->internal) {
3310 dict_gctx->internal = dict;
3311 dict_dependent_add(dict, "global");
3312 }
3313
3314 /*
3315 * Try to load libfreeradius-internal, too. If that
3316 * fails (i.e. fuzzers???), ignore it.
3317 */
3318 (void) dict_dlopen(dict, "internal");
3319
3320 cast_base = dict_attr_child_by_num(dict->root, FR_CAST_BASE);
3321 if (!cast_base) {
3322 fr_strerror_printf("Failed to find 'Cast-Base' in internal dictionary");
3323 goto error;
3324 }
3325
3326 fr_assert(cast_base->type == FR_TYPE_UINT8);
3327 fr_value_box_init(&box, FR_TYPE_UINT8, NULL, false);
3328
3329 /*
3330 * Add cast attributes. We do it this way,
3331 * so cast attributes get added automatically for new types.
3332 *
3333 * We manually add the attributes to the dictionary, and bypass
3334 * fr_dict_attr_add(), because we know what we're doing, and
3335 * that function does too many checks.
3336 */
3337 for (i = 0; i < fr_type_table_len; i++) {
3340
3341 switch (p->value) {
3342 case FR_TYPE_NULL: /* Can't cast to NULL */
3343 case FR_TYPE_VENDOR: /* Vendors can't exist in dictionaries as attributes */
3344 continue;
3345 }
3346
3347 type_name = talloc_typed_asprintf(NULL, "Tmp-Cast-%s", p->name.str);
3348
3349 n = dict_attr_alloc(dict->pool, dict->root, type_name,
3350 FR_CAST_BASE + p->value, p->value, &(dict_attr_args_t){ .flags = &flags});
3351 if (!n) {
3352 talloc_free(type_name);
3353 goto error;
3354 }
3355
3356 if (dict_attr_add_to_namespace(dict->root, n) < 0) {
3357 fr_strerror_printf_push("Failed inserting '%s' into internal dictionary", type_name);
3358 talloc_free(type_name);
3359 goto error;
3360 }
3361
3362 talloc_free(type_name);
3363
3364 /*
3365 * Set up parenting for the attribute.
3366 */
3367 if (dict_attr_child_add(dict->root, n) < 0) goto error;
3368
3369 /*
3370 * Add the enum, too.
3371 */
3372 box.vb_uint8 = p->value;
3373 if (dict_attr_enum_add_name(cast_base, p->name.str, &box, false, false, NULL) < 0) {
3374 fr_strerror_printf_push("Failed adding '%s' as a VALUE into internal dictionary", p->name.str);
3375 goto error;
3376 }
3377 }
3378
3379 *out = dict;
3380
3381 return 0;
3382}
3383
3384/** (Re)-initialize a protocol dictionary
3385 *
3386 * Initialize the directory, then fix the attr number of all attributes.
3387 *
3388 * @param[out] out Where to write a pointer to the new dictionary. Will free existing
3389 * dictionary if files have changed and *out is not NULL.
3390 * @param[in] proto_name that we're loading the dictionary for.
3391 * @param[in] proto_dir Explicitly set where to hunt for the dictionary files. May be NULL.
3392 * @param[in] dependent Either C src file, or another dictionary.
3393 * @return
3394 * - 0 on success.
3395 * - -1 on failure.
3396 */
3397int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir, char const *dependent)
3398{
3399 char *dict_dir = NULL;
3400 fr_dict_t *dict;
3401 bool added = false;
3402
3403 *out = NULL;
3404
3405 if (unlikely(!dict_gctx)) {
3406 fr_strerror_const("fr_dict_global_ctx_init() must be called before loading dictionary files");
3407 return -1;
3408 }
3409
3410 if (unlikely(!dict_gctx->internal)) {
3411 fr_strerror_const("Internal dictionary must be initialised before loading protocol dictionaries");
3412 return -1;
3413 }
3414
3415 /*
3416 * Increment the reference count if the dictionary
3417 * has already been loaded and return that.
3418 */
3419 dict = dict_by_protocol_name(proto_name);
3420 if (dict) {
3421 /*
3422 * If we're in the middle of loading this dictionary, then the only way we get back here
3423 * is via a circular reference. So we catch that, and drop the circular dependency.
3424 *
3425 * When we have A->B->A, it means that we don't need to track B->A, because we track
3426 * A->B. And if A is freed, then B is freed.
3427 */
3428 added = true;
3429 dict_dependent_add(dict, dependent);
3430
3431 /*
3432 * But we only return a pre-existing dict if _this function_ has loaded it.
3433 */
3434 if (dict->loaded) {
3435 *out = dict;
3436 return 0;
3437 }
3438
3439 /*
3440 * Set the flag to true _before_ loading the file. That prevents recursion.
3441 */
3442 dict->loaded = true;
3443 }
3444
3445 if (!proto_dir) {
3446 dict_dir = talloc_asprintf(NULL, "%s%c%s", fr_dict_global_ctx_dir(), FR_DIR_SEP, proto_name);
3447 } else {
3448 dict_dir = talloc_asprintf(NULL, "%s%c%s", fr_dict_global_ctx_dir(), FR_DIR_SEP, proto_dir);
3449 }
3450
3451 fr_strerror_clear(); /* Ensure we don't report spurious errors */
3452
3453 /*
3454 * Start in the context of the internal dictionary,
3455 * and switch to the context of a protocol dictionary
3456 * when we hit a BEGIN-PROTOCOL line.
3457 *
3458 * This allows a single file to provide definitions
3459 * for multiple protocols, which'll probably be useful
3460 * at some point.
3461 */
3462 if (dict_from_file(dict_gctx->internal, dict_dir, FR_DICTIONARY_FILE, NULL, 0) < 0) {
3463 error:
3464 if (dict) dict->loading = false;
3465 talloc_free(dict_dir);
3466 return -1;
3467 }
3468
3469 /*
3470 * Check the dictionary actually defined the protocol
3471 */
3472 dict = dict_by_protocol_name(proto_name);
3473 if (!dict) {
3474 fr_strerror_printf("Dictionary \"%s\" missing \"BEGIN-PROTOCOL %s\" declaration", dict_dir, proto_name);
3475 goto error;
3476 }
3477
3478 /*
3479 * Initialize the library.
3480 */
3481 dict->loaded = true;
3482 if (dict->proto && dict->proto->init) {
3483 if (dict->proto->init() < 0) goto error;
3484 }
3485 dict->loading = false;
3486
3487 dict->dir = talloc_steal(dict, dict_dir);
3488
3489 if (!added) dict_dependent_add(dict, dependent);
3490
3491 *out = dict;
3492
3493 return 0;
3494}
3495
3496/* Alloc a new root dictionary attribute
3497 *
3498 * @note Must only be called once per dictionary.
3499 *
3500 * @param[in] proto_name that we're loading the dictionary for.
3501 * @param[in] proto_number The artificial (or IANA allocated) number for the protocol.
3502 * @return
3503 * - A pointer to the new dict context on success.
3504 * - NULL on failure.
3505 */
3506fr_dict_t *fr_dict_alloc(char const *proto_name, unsigned int proto_number)
3507{
3508 fr_dict_t *dict;
3509
3510 if (unlikely(!dict_gctx)) {
3511 fr_strerror_printf("fr_dict_global_ctx_init() must be called before loading dictionary files");
3512 return NULL;
3513 }
3514
3515 /*
3516 * Alloc dict instance.
3517 */
3518 dict = dict_alloc(dict_gctx);
3519 if (!dict) return NULL;
3520
3521 /*
3522 * Set the root name of the dictionary
3523 */
3524 if (dict_root_set(dict, proto_name, proto_number) < 0) {
3525 talloc_free(dict);
3526 return NULL;
3527 }
3528
3529 return dict;
3530}
3531
3532/** Read supplementary attribute definitions into an existing dictionary
3533 *
3534 * @param[in] dict Existing dictionary.
3535 * @param[in] dir dictionary is located in.
3536 * @param[in] filename of the dictionary.
3537 * @return
3538 * - 0 on success.
3539 * - -1 on failure.
3540 */
3541int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
3542{
3543 INTERNAL_IF_NULL(dict, -1);
3544
3545 if (!dir) dir = dict->dir;
3546
3547 if (unlikely(dict->read_only)) {
3548 fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
3549 return -1;
3550 }
3551
3552 if (!dict->vendors_by_name) {
3553 fr_strerror_printf("%s: Must initialise dictionary before calling fr_dict_read()", __FUNCTION__);
3554 return -1;
3555 }
3556
3557 return dict_from_file(dict, dir, filename, NULL, 0);
3558}
3559
3560/*
3561 * External API for testing
3562 */
3564{
3565 int argc;
3566 char *argv[DICT_MAX_ARGV];
3567 int ret;
3568 fr_dict_attr_flags_t base_flags;
3570
3571 INTERNAL_IF_NULL(dict, -1);
3572
3573 argc = fr_dict_str_to_argv(buf, argv, DICT_MAX_ARGV);
3574 if (argc == 0) return 0;
3575
3576
3577 memset(&dctx, 0, sizeof(dctx));
3578 dctx.dict = dict;
3579 dctx.stack[0].dict = dict;
3580 dctx.stack[0].da = dict->root;
3581 dctx.stack[0].nest = NEST_ROOT;
3582
3583 if (dict_fixup_init(NULL, &dctx.fixup) < 0) return -1;
3584
3585 if (strcasecmp(argv[0], "VALUE") == 0) {
3586 if (argc < 4) {
3587 fr_strerror_printf("VALUE needs at least 4 arguments, got %i", argc);
3588 error:
3589 TALLOC_FREE(dctx.fixup.pool);
3590 return -1;
3591 }
3592
3593 if (!fr_dict_attr_by_oid(NULL, fr_dict_root(dict), argv[1])) {
3594 fr_strerror_printf("Attribute '%s' does not exist in dictionary \"%s\"",
3595 argv[1], dict->root->name);
3596 goto error;
3597 }
3598 ret = dict_read_process_value(&dctx, argv + 1, argc - 1, &base_flags);
3599 if (ret < 0) goto error;
3600
3601 } else if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
3602 if (parent && (parent != dict->root)) dctx.stack[++dctx.stack_depth].da = parent;
3603
3604 memset(&base_flags, 0, sizeof(base_flags));
3605
3606 ret = dict_read_process_attribute(&dctx,
3607 argv + 1, argc - 1, &base_flags);
3608 if (ret < 0) goto error;
3609 } else if (strcasecmp(argv[0], "VENDOR") == 0) {
3610 ret = dict_read_process_vendor(&dctx, argv + 1, argc - 1, &base_flags);
3611 if (ret < 0) goto error;
3612 } else {
3613 fr_strerror_printf("Invalid input '%s'", argv[0]);
3614 goto error;
3615 }
3616
3617 return dict_finalise(&dctx);
3618}
int const char * file
Definition acutest.h:702
int n
Definition acutest.h:577
int const char int line
Definition acutest.h:702
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define DIAG_ON(_x)
Definition build.h:460
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define DIAG_OFF(_x)
Definition build.h:459
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#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:210
#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:156
size_t type
Length of type data.
Definition dict.h:252
int fr_dict_attr_add_initialised(fr_dict_attr_t *da)
A variant of fr_dict_attr_t that allows a pre-allocated, populated fr_dict_attr_t to be added.
Definition dict_util.c:1592
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:3517
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace)
Add a value name.
Definition dict_util.c:1943
char const * name
Vendor name.
Definition dict.h:254
unsigned int is_root
Is root of a dictionary.
Definition dict.h:75
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:2039
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:3265
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition dict_util.c:4599
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2402
fr_dict_flag_parse_func_t func
Custom parsing function to convert a flag value string to a C type value.
Definition dict.h:372
unsigned int internal
Internal attribute, should not be received in protocol packets, should not be encoded.
Definition dict.h:87
#define DA_VERIFY(_x)
Definition dict.h:66
fr_slen_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:2127
uint32_t pen
Private enterprise number.
Definition dict.h:250
#define da_is_length_field(_da)
Definition dict.h:159
uint8_t type_size
For TLV2 and root attributes.
Definition dict.h:140
size_t length
Length of length data.
Definition dict.h:253
char const * fr_dict_global_ctx_dir(void)
Definition dict_util.c:4496
@ FR_DICT_ATTR_EXT_REF
Attribute references another attribute and/or dictionary.
Definition dict.h:169
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:2659
bool needs_value
This parsing flag must have a value. Else we error.
Definition dict.h:374
fr_dict_attr_t const * fr_dict_attr_by_oid(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *oid))
Resolve an attribute using an OID string.
Definition dict_util.c:2375
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:2682
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:3330
#define fr_dict_attr_is_key_field(_da)
Definition dict.h:157
static int8_t fr_dict_attr_cmp_fields(const fr_dict_attr_t *a, const fr_dict_attr_t *b)
Compare two dictionary attributes by their contents.
Definition dict.h:648
uint8_t length
length of the attribute
Definition dict.h:132
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:153
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:154
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:151
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:152
Values of the encryption flags.
Protocol specific custom flag definitnion.
Definition dict.h:402
Private enterprise.
Definition dict.h:249
#define fr_dict_attr_ref_type(_type)
Definition dict_ext.h:71
fr_dict_attr_ref_type_t type
The state of the reference.
Definition dict_ext.h:77
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:140
#define fr_dict_attr_ref_is_unresolved(_type)
Definition dict_ext.h:70
@ FR_DICT_ATTR_REF_ENUM
The attribute is an enumeration value.
Definition dict_ext.h:64
@ FR_DICT_ATTR_REF_ALIAS
The attribute is an alias for another attribute.
Definition dict_ext.h:60
@ FR_DICT_ATTR_REF_CLONE
The attribute is a "copy" of another attribute.
Definition dict_ext.h:63
Attribute extension - Holds a reference to an attribute in another dictionary.
Definition dict_ext.h:76
static int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref, fr_dict_attr_ref_type_t type)
static int dict_attr_ref_aunresolved(fr_dict_attr_t **da_p, char const *ref, fr_dict_attr_ref_type_t type)
int dict_fixup_apply(dict_fixup_ctx_t *fctx)
Apply all outstanding fixes to a set of dictionaries.
Definition dict_fixup.c:863
int dict_protocol_reference(fr_dict_attr_t const **da_p, fr_dict_attr_t const *rel, char const *ref)
Resolve a reference string to a dictionary attribute.
Definition dict_fixup.c:135
int dict_fixup_enumv_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line, char const *attr, size_t attr_len, char const *name, size_t name_len, char const *value, size_t value_len, fr_dict_attr_t const *parent)
Add an enumeration value to an attribute which has not yet been defined.
Definition dict_fixup.c:268
int dict_fixup_alias_enqueue(dict_fixup_ctx_t *fctx, char const *filename, int line, fr_dict_attr_t *alias_parent, char const *alias, fr_dict_attr_t *ref_parent, char const *ref)
Resolve a group reference.
Definition dict_fixup.c:792
int dict_fixup_clone_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Clone one area of a tree into another.
Definition dict_fixup.c:418
int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx)
Initialise a fixup ctx.
Definition dict_fixup.c:844
int dict_fixup_clone_enum_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Clone enumeration values from one attribute to another.
Definition dict_fixup.c:628
int dict_fixup_vsa_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da)
Push a fixup for a VSA.
Definition dict_fixup.c:731
int dict_fixup_clone(fr_dict_attr_t **dst_p, fr_dict_attr_t const *src)
Clone a dictionary attribute from a ref.
Definition dict_fixup.c:451
int dict_fixup_group_enqueue(dict_fixup_ctx_t *fctx, fr_dict_attr_t *da, char const *ref)
Resolve a group reference.
Definition dict_fixup.c:351
TALLOC_CTX * pool
Temporary pool for fixups, reduces holes.
int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace, fr_dict_attr_t const *child_struct)
Definition dict_util.c:1754
int dict_attr_type_init(fr_dict_attr_t **da_p, fr_type_t type)
Initialise type specific fields within the dictionary attribute.
Definition dict_util.c:514
int dict_attr_parent_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *parent)
Initialise fields which depend on a parent attribute.
Definition dict_util.c:608
#define dict_attr_alloc(_ctx, _parent, _name, _attr, _type, _args)
Definition dict_priv.h:239
fr_dict_t * dict_alloc(TALLOC_CTX *ctx)
Allocate a new dictionary.
Definition dict_util.c:3874
#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:1526
fr_dict_attr_t * dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Internal version of fr_dict_attr_child_by_num.
Definition dict_util.c:3283
fr_dict_attr_t * dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
Definition dict_util.c:3219
fr_dict_t * dict_by_protocol_num(unsigned int num)
Internal version of fr_dict_by_protocol_num.
Definition dict_util.c:2524
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:1427
int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
Add a vendor to the dictionary.
Definition dict_util.c:1311
int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref)
Add an alias to an existing attribute.
Definition dict_util.c:1176
int dict_attr_finalise(fr_dict_attr_t **da_p, char const *name)
Set remaining fields in a dictionary attribute before insertion.
Definition dict_util.c:704
int dict_attr_num_init(fr_dict_attr_t *da, unsigned int num)
Set the attribute number (if any)
Definition dict_util.c:660
int dict_attr_num_init_name_only(fr_dict_attr_t *da)
Set the attribute number (if any)
Definition dict_util.c:678
int dict_dlopen(fr_dict_t *dict, char const *name)
Definition dict_util.c:3557
fr_dict_t * dict_by_protocol_name(char const *name)
Internal version of fr_dict_by_protocol_name.
Definition dict_util.c:2510
fr_dict_t * internal
Magic internal dictionary.
Definition dict_priv.h:155
fr_dict_attr_t * dict_attr_alloc_null(TALLOC_CTX *ctx, fr_dict_protocol_t const *dict)
Partial initialisation functions.
Definition dict_util.c:912
int dict_dependent_add(fr_dict_t *dict, char const *dependent)
Record a new dependency on a dictionary.
Definition dict_util.c:3649
#define dict_attr_alloc_root(_ctx, _dict, _name, _attr, _args)
Definition dict_priv.h:231
int dict_protocol_add(fr_dict_t *dict)
Add a protocol to the global protocol table.
Definition dict_util.c:1238
fr_dict_gctx_t * dict_gctx
Top level structure containing global dictionary state.
Definition dict_util.c:41
bool perm_check
Whether we should check dictionary file permissions as they're loaded.
Definition dict_priv.h:132
Optional arguments for initialising/allocating attributes.
Definition dict_priv.h:175
Entry in the filename list of files associated with this dictionary.
Definition dict_priv.h:69
Test enumeration values.
Definition dict_test.h:92
static fr_table_num_sorted_t const dict_nest_table[]
static int dict_read_process_include(dict_tokenize_ctx_t *dctx, char **argv, int argc, char const *dir)
dict_nest_t nest
for manual vs automatic begin / end things
dict_fixup_ctx_t fixup
static int dict_read_process_common(dict_tokenize_ctx_t *dctx, fr_dict_attr_t **da_p, fr_dict_attr_t const *parent, char const *name, char const *type_name, char *flag_name, fr_dict_attr_flags_t const *base_flags)
static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
int member_num
structure member numbers
static int dict_filename_add(char **filename_out, fr_dict_t *dict, char const *filename, char const *src_file, int src_line)
Maintain a linked list of filenames which we've seen loading this dictionary.
static int dict_process_type_field(dict_tokenize_ctx_t *dctx, char const *name, fr_dict_attr_t **da_p)
static int dict_read_process_alias(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
static int _dict_from_file(dict_tokenize_ctx_t *dctx, char const *dir_name, char const *filename, char const *src_file, int src_line)
fr_dict_section_begin_t begin
Can have a BEGIN prefix.
static int dict_attr_allow_dup(fr_dict_attr_t const *da)
Check if this definition is a duplicate, and if it is, whether we should skip it error out.
static int dict_finalise(dict_tokenize_ctx_t *dctx)
static int dict_read_process_member(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
fr_dict_t * fr_dict_alloc(char const *proto_name, unsigned int proto_number)
static int dict_flag_ref(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static int dict_flag_precision(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static int dict_read_process_end(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
int stack_depth
points to the last used stack frame
ssize_t struct_size
size of the struct.
static int dict_read_process_struct(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
Process a STRUCT name attr value.
fr_dict_attr_t const * struct_is_closed
no more members are allowed
int(* fr_dict_keyword_parse_t)(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
Keyword parser.
static int dict_read_process_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
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_section_begin_t)(dict_tokenize_ctx_t *dctx)
Pushes a new frame onto the top of the stack based on the current frame.
int fr_dict_str_to_argv(char *str, char **argv, int max_argc)
static int dict_read_sscanf_i(unsigned int *pvalue, char const *str)
static int dict_read_process_define(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
static size_t const dict_nest_table_len
static int dict_read_parse_format(char const *format, int *ptype, int *plength, bool *pcontinuation)
static int dict_read_process_begin_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
#define ASSERT_CURRENT_NEST(_dctx, _nest)
static dict_tokenize_frame_t const * dict_dctx_unwind_until(dict_tokenize_ctx_t *dctx, dict_nest_t nest)
Unwind the stack until it points to a particular type of stack frame.
static int dict_from_file(fr_dict_t *dict, char const *dir_name, char const *filename, char const *src_file, int src_line)
fr_dict_attr_t const * da
the da we care about
static int dict_dctx_push_or_update(dict_tokenize_ctx_t *dctx, fr_dict_attr_t const *da, dict_nest_t nest)
Either updates the da in the current stack frame if 'nest' matches, or pushes a new frame of type 'ne...
fr_dict_attr_t * value_attr
Cache of last attribute to speed up value processing.
static int dict_read_process_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flag)
Register the specified dictionary as a protocol dictionary.
fr_dict_t * dict
The dictionary before the current BEGIN-PROTOCOL block.
#define FLAG_FUNC(_name)
Define a flag setting function, which sets one bit in a fr_dict_attr_flags_t.
#define CURRENT_LINE(_dctx)
static dict_tokenize_frame_t const * dict_dctx_pop(dict_tokenize_ctx_t *dctx)
Pop the current stack frame.
char * filename
name of the file we're reading
static int dict_set_value_attr(dict_tokenize_ctx_t *dctx, fr_dict_attr_t *da)
static int dict_read_process_enum(dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
#define CURRENT_FILENAME(_dctx)
static int dict_struct_finalise(dict_tokenize_ctx_t *dctx)
static int dict_flag_offset(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static int dict_read_process_begin_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
fr_dict_t * dict
Protocol dictionary we're inserting attributes into.
static int dict_flag_clone(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rules)
dict_tokenize_frame_t stack[DICT_MAX_STACK]
stack of attributes to track
int line
line number of this file
static bool dict_filename_loaded(fr_dict_t *dict, char const *filename, char const *src_file, int src_line)
See if we have already loaded the file,.
static int dict_flag_enum(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static dict_tokenize_frame_t const * dict_dctx_unwind(dict_tokenize_ctx_t *dctx)
Unwind the entire stack, returning the root frame.
#define CURRENT_DA(_dctx)
#define DICT_MAX_ARGV
Maximum number of arguments.
static int dict_read_process_value(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
Process a value alias.
static dict_tokenize_frame_t const * dict_dctx_find_frame(dict_tokenize_ctx_t *dctx, dict_nest_t nest)
fr_dict_keyword_parser_t value
Value to return from lookup.
static int dict_flag_length(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static int dict_read_process_end_vendor(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
#define DICT_MAX_STACK
Maximum stack size.
int fr_dict_parse_str(fr_dict_t *dict, char *buf, fr_dict_attr_t const *parent)
static int dict_flag_subtype(fr_dict_attr_t **da_p, char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
static int dict_read_process_begin(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
static int dict_flag_key(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent)
(Re-)Initialize the special internal dictionary
static int dict_dctx_push(dict_tokenize_ctx_t *dctx, fr_dict_attr_t const *da, dict_nest_t nest)
static int dict_begin_protocol(dict_tokenize_ctx_t *dctx)
Process an inline BEGIN PROTOCOL block.
static int dict_read_process_flags(UNUSED dict_tokenize_ctx_t *dctx, char **argv, int argc, fr_dict_attr_flags_t *base_flags)
static int dict_attr_add_or_fixup(dict_fixup_ctx_t *fixup, fr_dict_attr_t **da_p)
Add an attribute to the dictionary, or add it to a list of attributes to clone later.
#define CURRENT_FRAME(_dctx)
static void dict_attr_location_set(dict_tokenize_ctx_t *dctx, fr_dict_attr_t *da)
fr_dict_attr_t const * relative_attr
for ".82" instead of "1.2.3.82". only for parents of type "tlv"
static int dict_flag_secret(fr_dict_attr_t **da_p, UNUSED char const *value, UNUSED fr_dict_flag_parser_rule_t const *rule)
fr_table_elem_name_t name
Name of the keyword, e.g. "ATTRIBUTE".
static int dict_read_process_end_protocol(dict_tokenize_ctx_t *dctx, char **argv, int argc, UNUSED fr_dict_attr_flags_t *base_flags)
fr_dict_keyword_parse_t parse
Function to parse the keyword with.
void dict_dctx_debug(dict_tokenize_ctx_t *dctx)
dict_nest_t
This represents explicit BEGIN/END frames pushed onto the stack.
@ NEST_VENDOR
@ NEST_PROTOCOL
@ NEST_ROOT
@ NEST_ATTRIBUTE
@ NEST_NONE
static int dict_root_set(fr_dict_t *dict, char const *name, unsigned int proto_number)
Set a new root dictionary attribute.
Parser context for dict_from_file.
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
char const * fr_cwd_strip(char const *filename)
Intended to be used in logging functions to make output more readable.
Definition file.c:384
talloc_free(reap)
static int stack_depth
Definition radmin.c:156
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:36
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
#define fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
static bool done
Definition radclient.c:81
char const * name
Test name (as specified in the request).
Definition radclient.h:101
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
size_t strlcat(char *dst, char const *src, size_t siz)
Definition strlcat.c:35
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
char const * str
Literal string.
Definition table.h:42
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
#define TABLE_TYPE_NAME_FUNC_RPTR(_func, _our_table_type, _our_name, _our_def_type, _our_out_type)
Create a type-specific name-to-value function.
Definition table.h:144
static void const * table_sorted_value_by_str(void const *table, size_t table_len, size_t element_size, char const *name)
Convert a string to a value using a lexicographically sorted table.
Definition table.h:328
fr_table_elem_name_t name
Definition table.h:58
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:488
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition talloc.c:441
fr_table_num_ordered_t const fr_time_precision_table[]
Definition time.c:46
#define FR_DICTIONARY_FILE
Definition conf.h:7
static fr_slen_t parent
Definition pair.h:845
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
#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_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition types.c:31
size_t fr_type_table_len
Definition types.c:84
#define fr_type_is_structural(_x)
Definition types.h:371
#define fr_type_is_null(_x)
Definition types.h:326
#define fr_type_is_tlv(_x)
Definition types.h:351
#define fr_type_is_leaf(_x)
Definition types.h:372
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_struct(_x)
Definition types.h:352
static fr_type_t fr_type_from_str(char const *type)
Return the constant value representing a type.
Definition types.h:443
#define FR_TYPE_LEAF
Definition types.h:297
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
Definition value.c:5450
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3946
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:499
int nonnull(2, 5))
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:598
int format(printf, 5, 0))
static size_t char ** out
Definition value.h:1012