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