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