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