Coverage Report

Created: 2026-08-14 07:17

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