Coverage Report

Created: 2025-12-14 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/util/dict_util.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
/** Multi-protocol AVP dictionary API
18
 *
19
 * @file src/lib/util/dict_util.c
20
 *
21
 * @copyright 2000,2006 The FreeRADIUS server project
22
 * @copyright 2024 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23
 */
24
RCSID("$Id: 124f5057fc464e7495854ec4ca9761788ccf1495 $")
25
26
#define _DICT_PRIVATE 1
27
28
#include <freeradius-devel/util/atexit.h>
29
#include <freeradius-devel/util/conf.h>
30
#include <freeradius-devel/util/dict.h>
31
#include <freeradius-devel/util/dict_ext_priv.h>
32
#include <freeradius-devel/util/dict_fixup_priv.h>
33
#include <freeradius-devel/util/hash.h>
34
#include <freeradius-devel/util/proto.h>
35
#include <freeradius-devel/util/rand.h>
36
#include <freeradius-devel/util/syserror.h>
37
38
#ifdef HAVE_SYS_STAT_H
39
#  include <sys/stat.h>
40
#endif
41
42
fr_dict_gctx_t *dict_gctx = NULL; //!< Top level structure containing global dictionary state.
43
44
#define DICT_ATTR_ALLOWED_CHARS \
45
  ['-'] = true, ['/'] = true, ['_'] = true, \
46
  ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, \
47
  ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, \
48
  ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true, \
49
  ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true, \
50
  ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, \
51
  ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, \
52
  ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true, \
53
  ['Z'] = true, \
54
  ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, \
55
  ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true, \
56
  ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true, \
57
  ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true, \
58
  ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true, \
59
  ['z'] = true
60
61
/** Characters allowed in a single dictionary attribute name
62
 *
63
 */
64
bool const fr_dict_attr_allowed_chars[UINT8_MAX + 1] = {
65
  DICT_ATTR_ALLOWED_CHARS
66
};
67
68
/** Characters allowed in a nested dictionary attribute name
69
 *
70
 */
71
bool const fr_dict_attr_nested_allowed_chars[UINT8_MAX + 1] = {
72
  DICT_ATTR_ALLOWED_CHARS,
73
  [ '.' ] = true
74
};
75
76
/** Characters allowed in enumeration value names
77
 *
78
 */
79
bool const fr_dict_enum_allowed_chars[UINT8_MAX + 1] = {
80
  ['+'] = true, ['-'] = true, ['.'] = true, ['/'] = true, ['_'] = true,
81
  ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
82
  ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
83
  ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
84
  ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true,
85
  ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true,
86
  ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true,
87
  ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true,
88
  ['Z'] = true,
89
  ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
90
  ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
91
  ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
92
  ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
93
  ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
94
  ['z'] = true
95
};
96
97
/** Default protocol rules set for every dictionary
98
 *
99
 * This is usually overriden by the public symbol from the protocol library
100
 * associated with the dictionary
101
 * e.g. libfreeradius-dhcpv6.so -> libfreeradius_dhcpv6_dict_protocol.
102
 */
103
static fr_dict_protocol_t dict_proto_default = {
104
  .name = "default",
105
  .default_type_size = 2,
106
  .default_type_length = 2,
107
};
108
109
/*
110
 *  Create the hash of the name.
111
 *
112
 *  We copy the hash function here because it's substantially faster.
113
 */
114
268k
#define FNV_MAGIC_INIT (0x811c9dc5)
115
3.54M
#define FNV_MAGIC_PRIME (0x01000193)
116
117
static void hash_pool_free(void *to_free)
118
39.0k
{
119
39.0k
  talloc_free(to_free);
120
39.0k
}
121
122
/** Apply a simple (case insensitive) hashing function to the name of an attribute, vendor or protocol
123
 *
124
 * @param[in] name  of the attribute, vendor or protocol.
125
 * @param[in] len length of the input string.
126
 *
127
 * @return the hashed derived from the name.
128
 */
129
static uint32_t dict_hash_name(char const *name, size_t len)
130
268k
{
131
268k
  uint32_t hash = FNV_MAGIC_INIT;
132
133
268k
  char const *p = name, *q = name + len;
134
135
3.81M
  while (p < q) {
136
3.54M
    int c = *(unsigned char const *)p;
137
3.54M
    if (isalpha(c)) c = tolower(c);
138
139
    /* coverity[overflow_const] */
140
3.54M
    hash *= FNV_MAGIC_PRIME;
141
3.54M
    hash ^= (uint32_t)(c & 0xff);
142
3.54M
    p++;
143
3.54M
  }
144
145
268k
  return hash;
146
268k
}
147
148
/** Wrap name hash function for fr_dict_protocol_t
149
 *
150
 * @param[in] data fr_dict_attr_t to hash.
151
 * @return the hash derived from the name of the attribute.
152
 */
153
static uint32_t dict_protocol_name_hash(void const *data)
154
1.14k
{
155
1.14k
  char const *name;
156
157
1.14k
  name = ((fr_dict_t const *)data)->root->name;
158
159
1.14k
  return dict_hash_name(name, strlen(name));
160
1.14k
}
161
162
/** Compare two protocol names
163
 *
164
 */
165
static int8_t dict_protocol_name_cmp(void const *one, void const *two)
166
1.05k
{
167
1.05k
  fr_dict_t const *a = one;
168
1.05k
  fr_dict_t const *b = two;
169
1.05k
  int ret;
170
171
1.05k
  ret = strcasecmp(a->root->name, b->root->name);
172
1.05k
  return CMP(ret, 0);
173
1.05k
}
174
175
/** Hash a protocol number
176
 *
177
 */
178
static uint32_t dict_protocol_num_hash(void const *data)
179
72
{
180
72
  return fr_hash(&(((fr_dict_t const *)data)->root->attr), sizeof(((fr_dict_t const *)data)->root->attr));
181
72
}
182
183
/** Compare two protocol numbers
184
 *
185
 */
186
static int8_t dict_protocol_num_cmp(void const *one, void const *two)
187
24
{
188
24
  fr_dict_t const *a = one;
189
24
  fr_dict_t const *b = two;
190
191
24
  return CMP(a->root->attr, b->root->attr);
192
24
}
193
194
/** Wrap name hash function for fr_dict_attr_t
195
 *
196
 * @param data    fr_dict_attr_t to hash.
197
 * @return the hash derived from the name of the attribute.
198
 */
199
static uint32_t dict_attr_name_hash(void const *data)
200
226k
{
201
226k
  char const *name;
202
203
226k
  name = ((fr_dict_attr_t const *)data)->name;
204
205
226k
  return dict_hash_name(name, strlen(name));
206
226k
}
207
208
/** Compare two attribute names
209
 *
210
 */
211
static int8_t dict_attr_name_cmp(void const *one, void const *two)
212
69.5k
{
213
69.5k
  fr_dict_attr_t const *a = one, *b = two;
214
69.5k
  int ret;
215
216
69.5k
  ret = strcasecmp(a->name, b->name);
217
69.5k
  return CMP(ret, 0);
218
69.5k
}
219
220
/** Compare two attributes by total order.
221
 *
222
 *  This function is safe / ordered even when the attributes are in
223
 *  different dictionaries.  This allows it to work for local
224
 *  variables, as those are in a different dictionary from the
225
 *  protocol ones.
226
 *
227
 *  This function orders parents first, then their children.
228
 */
229
int8_t fr_dict_attr_ordered_cmp(fr_dict_attr_t const *a, fr_dict_attr_t const *b)
230
0
{
231
0
  int8_t ret;
232
233
  /*
234
   *  Order by parent first.  If the parents are different,
235
   *  we order by parent numbers.
236
   *
237
   *  If the attributes share the same parent at some point,
238
   *  then the deeper child is sorted later.
239
   */
240
0
  if (a->depth < b->depth) {
241
0
    ret = fr_dict_attr_ordered_cmp(a, b->parent);
242
0
    if (ret != 0) return ret;
243
244
0
    return -1; /* order a before b */
245
0
  }
246
247
0
  if (a->depth > b->depth) {
248
0
    ret = fr_dict_attr_ordered_cmp(a->parent, b);
249
0
    if (ret != 0) return ret;
250
251
0
    return +1; /* order b before a */
252
0
  }
253
254
  /*
255
   *  We're at the root (e.g. "RADIUS").  Compare by
256
   *  protocol number.
257
   *
258
   *  Or, the parents are the same.  We can then order by
259
   *  our (i.e. child) attribute number.
260
   */
261
0
  if ((a->depth == 0) || (a->parent == b->parent)) {
262
    /*
263
     *  Order known attributes before unknown / raw ones.
264
     */
265
0
    ret = (b->flags.is_unknown | b->flags.is_raw) - (a->flags.is_unknown | a->flags.is_raw);
266
0
    if (ret != 0) return 0;
267
268
0
    return CMP(a->attr, b->attr);
269
0
  }
270
271
  /*
272
   *  The parents are different, we don't need to order by
273
   *  our attribute number.  Instead, we order by the
274
   *  parent.
275
   *
276
   *  Note that at this point, the call below will never
277
   *  return 0, because the parents are different.
278
   */
279
0
  return fr_dict_attr_ordered_cmp(a->parent, b->parent);
280
0
}
281
282
/** Wrap name hash function for fr_dict_vendor_t
283
 *
284
 * @param data fr_dict_vendor_t to hash.
285
 * @return the hash derived from the name of the attribute.
286
 */
287
static uint32_t dict_vendor_name_hash(void const *data)
288
2.43k
{
289
2.43k
  char const *name;
290
291
2.43k
  name = ((fr_dict_vendor_t const *)data)->name;
292
293
2.43k
  return dict_hash_name(name, strlen(name));
294
2.43k
}
295
296
/** Compare two attribute names
297
 *
298
 */
299
static int8_t dict_vendor_name_cmp(void const *one, void const *two)
300
1.62k
{
301
1.62k
  fr_dict_vendor_t const *a = one;
302
1.62k
  fr_dict_vendor_t const *b = two;
303
1.62k
  int ret;
304
305
1.62k
  ret = strcasecmp(a->name, b->name);
306
1.62k
  return CMP(ret, 0);
307
1.62k
}
308
309
/** Hash a vendor number
310
 *
311
 */
312
static uint32_t dict_vendor_pen_hash(void const *data)
313
24.4k
{
314
24.4k
  return fr_hash(&(((fr_dict_vendor_t const *)data)->pen),
315
24.4k
           sizeof(((fr_dict_vendor_t const *)data)->pen));
316
24.4k
}
317
318
/** Compare two vendor numbers
319
 *
320
 */
321
static int8_t dict_vendor_pen_cmp(void const *one, void const *two)
322
13.9k
{
323
13.9k
  fr_dict_vendor_t const *a = one;
324
13.9k
  fr_dict_vendor_t const *b = two;
325
326
13.9k
  return CMP(a->pen, b->pen);
327
13.9k
}
328
329
/** Hash a enumeration name
330
 *
331
 */
332
static uint32_t dict_enum_name_hash(void const *data)
333
38.7k
{
334
38.7k
  fr_dict_enum_value_t const *enumv = data;
335
336
38.7k
  return dict_hash_name((void const *)enumv->name, enumv->name_len);
337
38.7k
}
338
339
/** Compare two dictionary attribute enum values
340
 *
341
 */
342
static int8_t dict_enum_name_cmp(void const *one, void const *two)
343
50
{
344
50
  fr_dict_enum_value_t const *a = one;
345
50
  fr_dict_enum_value_t const *b = two;
346
50
  size_t len;
347
50
  int ret;
348
349
50
  if (a->name_len >= b->name_len) {
350
50
    len = a->name_len;
351
50
  } else {
352
0
    len = b->name_len;
353
0
  }
354
355
50
  ret = strncasecmp(a->name, b->name, len);
356
50
  return CMP(ret, 0);
357
50
}
358
359
/** Hash a dictionary enum value
360
 *
361
 */
362
static uint32_t dict_enum_value_hash(void const *data)
363
93.2k
{
364
93.2k
  fr_dict_enum_value_t const *enumv = data;
365
366
93.2k
  return fr_value_box_hash(enumv->value);
367
93.2k
}
368
369
/** Compare two dictionary enum values
370
 *
371
 */
372
static int8_t dict_enum_value_cmp(void const *one, void const *two)
373
12.5k
{
374
12.5k
  fr_dict_enum_value_t const *a = one;
375
12.5k
  fr_dict_enum_value_t const *b = two;
376
12.5k
  int ret;
377
378
12.5k
  ret = fr_value_box_cmp(a->value, b->value); /* not yet int8_t! */
379
12.5k
  return CMP(ret, 0);
380
12.5k
}
381
382
/** Resolve an alias attribute to the concrete attribute it points to
383
 *
384
 * @param[out] err  where to write the error (if any).
385
 * @param[in] da  to resolve.
386
 * @return
387
 *  - NULL on error.
388
 *  - The concrete attribute on success.
389
 */
390
static inline fr_dict_attr_t const *dict_attr_alias(fr_dict_attr_err_t *err, fr_dict_attr_t const *da)
391
1.02M
{
392
1.02M
  fr_dict_attr_t const *ref;
393
394
1.02M
  if (!da->flags.is_alias) return da;
395
396
24
  ref = fr_dict_attr_ref(da);
397
24
  if (unlikely(!ref)) {
398
0
    fr_strerror_printf("ALIAS attribute '%s' missing reference", da->name);
399
0
    if (err) *err = FR_DICT_ATTR_INTERNAL_ERROR;
400
0
    return NULL;
401
24
  } else {
402
24
    if (err) *err = FR_DICT_ATTR_OK;
403
24
  }
404
405
24
  return ref;
406
24
}
407
408
/** Set a dictionary attribute's name
409
 *
410
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
411
 *
412
 * @param[in] da_p  to set name for.
413
 * @param[in] name  to set.  If NULL a name will be automatically generated.
414
 */
415
static inline CC_HINT(always_inline) int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
416
6.09M
{
417
6.09M
  char    buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
418
6.09M
  size_t    name_len;
419
6.09M
  char    *name_start, *name_end;
420
6.09M
  fr_dict_attr_t  *da = *da_p;
421
422
  /*
423
   *  Generate a name if none is specified
424
   */
425
6.09M
  if (!name) {
426
3.59M
    fr_sbuff_t unknown_name = FR_SBUFF_OUT(buffer, sizeof(buffer));
427
428
429
3.59M
    (void) fr_sbuff_in_sprintf(&unknown_name, "%u", da->attr);
430
431
3.59M
    name = fr_sbuff_buff(&unknown_name);
432
3.59M
    name_len = fr_sbuff_used(&unknown_name);
433
3.59M
  } else {
434
2.49M
    name_len = strlen(name);
435
2.49M
  }
436
437
  /*
438
   *  Grow the structure to hold the name
439
   *
440
   *  We add the name as an extension because it makes
441
   *  the code less complex, and means the name value
442
   *  is copied automatically when if the fr_dict_attr_t
443
   *  is copied.
444
   *
445
   *  We do still need to fixup the da->name pointer
446
   *  though.
447
   */
448
6.09M
  name_start = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_NAME, name_len + 1);
449
6.09M
  if (!name_start) return -1;
450
451
6.09M
  name_end = name_start + name_len;
452
453
6.09M
  memcpy(name_start, name, name_len);
454
6.09M
  *name_end = '\0';
455
456
6.09M
  (*da_p)->name = name_start;
457
6.09M
  (*da_p)->name_len = name_len;
458
459
6.09M
  return 0;
460
6.09M
}
461
462
/** Add a child/nesting extension to an attribute
463
 *
464
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
465
 *
466
 * @param[in] da_p    to set a group reference for.
467
 */
468
static inline CC_HINT(always_inline) int dict_attr_children_init(fr_dict_attr_t **da_p)
469
56.3k
{
470
56.3k
  fr_dict_attr_ext_children_t *ext;
471
472
56.3k
  ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_CHILDREN);
473
56.3k
  if (unlikely(!ext)) return -1;
474
475
56.3k
  return 0;
476
56.3k
}
477
478
/** Cache the vendor pointer for an attribute
479
 *
480
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
481
 *
482
 * @param[in] da_p    to set a group reference for.
483
 * @param[in] vendor    to set.
484
 */
485
static inline CC_HINT(always_inline) int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
486
0
{
487
0
  fr_dict_attr_ext_vendor_t *ext;
488
0
489
0
  ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_VENDOR);
490
0
  if (unlikely(!ext)) return -1;
491
0
492
0
  ext->vendor = vendor;
493
0
494
0
  return 0;
495
0
}
496
497
/** Initialise an attribute's da stack from its parent
498
 *
499
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
500
 *
501
 * @param[in] da_p    to populate the da_stack for.
502
 */
503
static inline CC_HINT(always_inline) int dict_attr_da_stack_set(fr_dict_attr_t **da_p)
504
6.09M
{
505
6.09M
  fr_dict_attr_ext_da_stack_t *ext, *p_ext;
506
6.09M
  fr_dict_attr_t      *da = *da_p;
507
6.09M
  fr_dict_attr_t const    *parent = da->parent;
508
509
6.09M
  if (!parent) return 1;
510
6.09M
  if (da->depth > FR_DICT_DA_STACK_CACHE_MAX) return 1;
511
6.07M
  if (fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_DA_STACK)) return 1;
512
513
6.07M
  p_ext = fr_dict_attr_ext(parent, FR_DICT_ATTR_EXT_DA_STACK);
514
6.07M
  if (!p_ext) return 1;
515
516
0
  ext = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_DA_STACK, sizeof(ext->da_stack[0]) * (da->depth + 1));
517
0
  if (unlikely(!ext)) return -1;
518
519
0
  memcpy(ext->da_stack, p_ext->da_stack, sizeof(ext->da_stack[0]) * parent->depth);
520
521
  /*
522
   *  Always set the last stack entry to ourselves.
523
   */
524
0
  ext->da_stack[da->depth] = da;
525
526
0
  return 0;
527
0
}
528
529
/** Initialise a per-attribute enumeration table
530
 *
531
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
532
 *
533
 * @param[in] da_p    to set a group reference for.
534
 */
535
static inline CC_HINT(always_inline) int dict_attr_enumv_init(fr_dict_attr_t **da_p)
536
6.03M
{
537
6.03M
  fr_dict_attr_ext_enumv_t  *ext;
538
539
6.03M
  ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_ENUMV);
540
6.03M
  if (unlikely(!ext)) return -1;
541
542
6.03M
  return 0;
543
6.03M
}
544
545
/** Initialise a per-attribute namespace
546
 *
547
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
548
 *
549
 * @param[in] da_p    to set a group reference for.
550
 */
551
static inline CC_HINT(always_inline) int dict_attr_namespace_init(fr_dict_attr_t **da_p)
552
56.3k
{
553
56.3k
  fr_dict_attr_ext_namespace_t  *ext;
554
555
56.3k
  ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_NAMESPACE);
556
56.3k
  if (unlikely(!ext)) return -1;
557
558
  /*
559
   *  Create the table of attributes by name.
560
   *      There MAY NOT be multiple attributes of the same name.
561
   *
562
   *  If the attribute already has extensions
563
   *  then we don't want to leak the old
564
   *  namespace hash table.
565
   */
566
56.3k
  if (!ext->namespace) {
567
56.3k
    ext->namespace = fr_hash_table_talloc_alloc(*da_p, fr_dict_attr_t,
568
56.3k
                  dict_attr_name_hash, dict_attr_name_cmp, NULL);
569
56.3k
    if (!ext->namespace) {
570
0
      fr_strerror_printf("Failed allocating \"namespace\" table");
571
0
      return -1;
572
0
    }
573
56.3k
  }
574
575
56.3k
  return 0;
576
56.3k
}
577
578
/** Initialise type specific fields within the dictionary attribute
579
 *
580
 * Call when the type of the attribute is known.
581
 *
582
 * @param[in,out] da_p  to set the type for.
583
 * @param[in] type  to set.
584
 * @return
585
 *  - 0 on success.
586
 *  - < 0 on error.
587
 */
588
int dict_attr_type_init(fr_dict_attr_t **da_p, fr_type_t type)
589
6.09M
{
590
6.09M
  if (unlikely((*da_p)->type != FR_TYPE_NULL)) {
591
0
    fr_strerror_const("Attribute type already set");
592
0
    return -1;
593
0
  }
594
595
6.09M
  if (unlikely((*da_p)->state.finalised == true)) {
596
0
    fr_strerror_const("Can't perform type initialisation on finalised attribute");
597
0
    return -1;
598
0
  }
599
600
  /*
601
   *  Structural types can have children
602
   *  so add the extension for them.
603
   */
604
6.09M
  switch (type) {
605
117k
  case FR_TYPE_STRUCTURAL:
606
    /*
607
     *  Groups don't have children or namespaces.  But
608
     *  they always have refs.  Either to the root of
609
     *  the current dictionary, or to another dictionary,
610
     *  via its top-level TLV.
611
     *
612
     *  Note that when multiple TLVs have the same
613
     *  children, the dictionary has to use "clone="
614
     *  instead of "ref=".  That's because the
615
     *  children of the TLVs all require the correct
616
     *  parentage.  Perhaps that can be changed when
617
     *  the encoders / decoders are updated.  It would be good to just reference the DAs instead of cloning an entire subtree.
618
     */
619
117k
    if (type == FR_TYPE_GROUP) {
620
692
      if (dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_REF) == NULL) return -1;
621
692
      break;
622
692
    }
623
624
56.3k
    if (dict_attr_children_init(da_p) < 0) return -1;
625
56.3k
    if (dict_attr_namespace_init(da_p) < 0) return -1; /* Needed for all TLV style attributes */
626
627
56.3k
    (*da_p)->last_child_attr = (1 << 24); /* High enough not to conflict with protocol numbers */
628
56.3k
    break;
629
630
  /*
631
   *  Leaf types
632
   */
633
6.03M
  default:
634
6.03M
    if (dict_attr_enumv_init(da_p) < 0) return -1;
635
6.03M
    break;
636
6.09M
  }
637
638
6.09M
  (*da_p)->flags.is_known_width |= fr_type_fixed_size[type];
639
640
  /*
641
   *  Set default type-based flags
642
   */
643
6.09M
  switch (type) {
644
945
  case FR_TYPE_DATE:
645
4.68k
  case FR_TYPE_TIME_DELTA:
646
4.68k
    (*da_p)->flags.length = 4;
647
4.68k
    (*da_p)->flags.flag_time_res = FR_TIME_RES_SEC;
648
4.68k
    break;
649
650
651
5.97M
  case FR_TYPE_OCTETS:
652
5.99M
  case FR_TYPE_STRING:
653
5.99M
    (*da_p)->flags.is_known_width = ((*da_p)->flags.length != 0);
654
5.99M
    break;
655
656
92.9k
  default:
657
92.9k
    break;
658
6.09M
  }
659
660
6.09M
  (*da_p)->type = type;
661
662
6.09M
  return 0;
663
6.09M
}
664
665
/** Initialise fields which depend on a parent attribute
666
 *
667
 * @param[in,out] da_p  to initialise.
668
 * @param[in] parent  of the attribute.
669
 * @return
670
 *  - 0 on success.
671
 *  - < 0 on error.
672
 */
673
int dict_attr_parent_init(fr_dict_attr_t **da_p, fr_dict_attr_t const *parent)
674
6.09M
{
675
6.09M
  fr_dict_attr_t      *da = *da_p;
676
6.09M
  fr_dict_t const     *dict = parent->dict;
677
6.09M
  fr_dict_attr_ext_vendor_t *ext;
678
679
6.09M
  if (unlikely((*da_p)->type == FR_TYPE_NULL)) {
680
0
    fr_strerror_const("Attribute type must be set before initialising parent.  Use dict_attr_type_init() first");
681
0
    return -1;
682
0
  }
683
684
6.09M
  if (unlikely(da->parent != NULL)) {
685
0
    fr_strerror_printf("Attempting to set parent for '%s' to '%s', but parent already set to '%s'",
686
0
           da->name, parent->name, da->parent->name);
687
0
    return -1;
688
0
  }
689
690
6.09M
  if (unlikely((*da_p)->state.finalised == true)) {
691
0
    fr_strerror_printf("Attempting to set parent for '%s' to '%s', but attribute already finalised",
692
0
           da->name, parent->name);
693
0
    return -1;
694
0
  }
695
696
6.09M
  da->parent = parent;
697
6.09M
  da->dict = parent->dict;
698
6.09M
  da->depth = parent->depth + 1;
699
6.09M
  da->flags.internal |= parent->flags.internal;
700
701
  /*
702
   *  Point to the vendor definition.  Since ~90% of
703
   *  attributes are VSAs, caching this pointer will help.
704
   */
705
6.09M
  if (da->type == FR_TYPE_VENDOR) {
706
28.1k
    da->flags.type_size = dict->root->flags.type_size;
707
28.1k
    da->flags.length = dict->root->flags.type_size;
708
709
28.1k
    if ((dict->root->attr == FR_DICT_PROTO_RADIUS) && (da->depth == 2)) {
710
9.22k
      fr_dict_vendor_t const *dv;
711
712
9.22k
      dv = fr_dict_vendor_by_num(dict, da->attr);
713
9.22k
      if (dv) {
714
764
        da->flags.type_size = dv->type;
715
764
        da->flags.length = dv->length;
716
764
      }
717
9.22k
    }
718
719
6.06M
  } else if (da->type == FR_TYPE_TLV) {
720
27.1k
    da->flags.type_size = dict->root->flags.type_size;
721
27.1k
    da->flags.length = dict->root->flags.type_size;
722
27.1k
  }
723
724
6.09M
  if (parent->type == FR_TYPE_VENDOR) {
725
61.2k
    ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_VENDOR);
726
61.2k
    if (unlikely(!ext)) return -1;
727
728
61.2k
    ext->vendor = parent;
729
730
6.03M
  } else {
731
6.03M
    ext = dict_attr_ext_copy(da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
732
6.03M
  }
733
734
  /*
735
   *  Cache the da_stack so we don't need
736
   *  to generate it at runtime.
737
   */
738
6.09M
  dict_attr_da_stack_set(da_p);
739
740
6.09M
  da = *da_p;
741
742
6.09M
  if (!ext || ((da->type != FR_TYPE_TLV) && (da->type != FR_TYPE_VENDOR))) return 0;
743
744
24.7k
  da->flags.type_size = ext->vendor->flags.type_size;
745
24.7k
  da->flags.length = ext->vendor->flags.type_size;
746
747
24.7k
  return 0;
748
6.09M
}
749
750
/** Set the attribute number (if any)
751
 *
752
 * @param[in] da    to set the attribute number for.
753
 * @param[in] num   to set.
754
 */
755
int dict_attr_num_init(fr_dict_attr_t *da, unsigned int num)
756
6.09M
{
757
6.09M
  if (da->state.attr_set) {
758
0
    fr_strerror_const("Attribute number already set");
759
0
    return -1;
760
0
  }
761
6.09M
  da->attr = num;
762
6.09M
  da->state.attr_set = true;
763
764
6.09M
  return 0;
765
6.09M
}
766
767
/** Set the attribute number (if any)
768
 *
769
 * @note Must have a parent set.
770
 *
771
 * @param[in] da    to set the attribute number for.
772
 */
773
int dict_attr_num_init_name_only(fr_dict_attr_t *da)
774
326
{
775
326
  if (!da->parent) {
776
0
    fr_strerror_const("Attribute must have parent set before automatically setting attribute number");
777
0
    return -1;
778
0
  }
779
326
  return dict_attr_num_init(da, ++fr_dict_attr_unconst(da->parent)->last_child_attr);
780
326
}
781
782
/** Set where the dictionary attribute was defined
783
 *
784
 */
785
void dict_attr_location_init(fr_dict_attr_t *da, char const *filename, int line)
786
6.05M
{
787
6.05M
  da->filename = filename;
788
6.05M
  da->line = line;
789
6.05M
}
790
791
/** Set remaining fields in a dictionary attribute before insertion
792
 *
793
 * @param[in] da_p    to finalise.
794
 * @param[in] name    of the attribute.
795
 * @return
796
 *  - 0 on success.
797
 *  - < 0 on error.
798
 */
799
int dict_attr_finalise(fr_dict_attr_t **da_p, char const *name)
800
6.09M
{
801
6.09M
  fr_dict_attr_t    *da;
802
803
  /*
804
  * Finalising the attribute allocates its
805
  * automatic number if its a name only attribute.
806
  */
807
6.09M
  da = *da_p;
808
809
  /*
810
   *  Initialize the length field automatically if it's not been set already
811
   */
812
6.09M
  if (!da->flags.length && fr_type_is_leaf(da->type) && !fr_type_is_variable_size(da->type)) {
813
37.2k
    fr_value_box_t box;
814
815
37.2k
    fr_value_box_init(&box, da->type, NULL, false);
816
37.2k
    da->flags.length = fr_value_box_network_length(&box);
817
37.2k
  }
818
819
6.09M
  switch(da->type) {
820
896
  case FR_TYPE_STRUCT:
821
896
    da->flags.is_known_width |= da->flags.array;
822
896
    break;
823
824
706
  case FR_TYPE_GROUP:
825
706
  {
826
706
    fr_dict_attr_ext_ref_t  *ext;
827
    /*
828
    * If it's a group attribute, the default
829
    * reference goes to the root of the
830
    * dictionary as that's where the default
831
    * name/numberspace is.
832
    *
833
    * This may be updated by the caller.
834
    */
835
706
    ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_REF);
836
706
    if (unlikely(ext == NULL)) {
837
0
      fr_strerror_const("Missing ref extension");
838
0
      return -1;
839
0
    }
840
841
    /*
842
     *  For groups, if a ref wasn't provided then
843
     *  set it to the dictionary root.
844
     */
845
706
    if ((ext->type == FR_DICT_ATTR_REF_NONE) &&
846
628
        (unlikely(dict_attr_ref_set(da, fr_dict_root(da->dict), FR_DICT_ATTR_REF_ALIAS) < 0))) {
847
0
      return -1;
848
0
    }
849
706
  }
850
706
    break;
851
852
6.09M
  default:
853
6.09M
    break;
854
6.09M
  }
855
856
  /*
857
   *  Name is a separate talloc chunk.  We allocate
858
   *  it last because we cache the pointer value.
859
   */
860
6.09M
  if (dict_attr_name_set(da_p, name) < 0) return -1;
861
862
6.09M
  DA_VERIFY(*da_p);
863
864
6.09M
  (*da_p)->state.finalised = true;
865
866
6.09M
  return 0;
867
6.09M
}
868
869
static inline CC_HINT(always_inline)
870
int dict_attr_init_common(char const *filename, int line,
871
        fr_dict_attr_t **da_p,
872
        fr_dict_attr_t const *parent,
873
        fr_type_t type, dict_attr_args_t const *args)
874
6.05M
{
875
6.05M
  dict_attr_location_init((*da_p), filename, line);
876
877
6.05M
  if (unlikely(dict_attr_type_init(da_p, type) < 0)) return -1;
878
879
6.05M
  if (args->flags) (*da_p)->flags = *args->flags;
880
881
6.05M
  if (parent && (dict_attr_parent_init(da_p, parent) < 0)) return -1;
882
883
6.05M
  if (args->ref && (dict_attr_ref_aset(da_p, args->ref, FR_DICT_ATTR_REF_ALIAS) < 0)) return -1;
884
885
  /*
886
   *  Everything should be created correctly.
887
   */
888
6.05M
  if (!(*da_p)->flags.internal && !(*da_p)->flags.is_alias &&
889
6.04M
      parent && ((parent->type == FR_TYPE_TLV) || (parent->type ==FR_TYPE_VENDOR))) {
890
5.98M
    if (!parent->flags.type_size) {
891
0
      fr_strerror_printf("Parent %s has zero type_size", parent->name);
892
0
      return -1;
893
0
    }
894
895
5.98M
    if ((uint64_t) (*da_p)->attr >= ((uint64_t) 1 << (8 * parent->flags.type_size))) {
896
0
      fr_strerror_printf("Child of parent %s has invalid attribute number %u for type_size %u",
897
0
             parent->name, (*da_p)->attr, parent->flags.type_size);
898
0
      return -1;
899
0
    }
900
5.98M
  }
901
902
6.05M
  return 0;
903
6.05M
}
904
905
/** Initialise fields in a dictionary attribute structure
906
 *
907
 * This function is a wrapper around the other initialisation functions.
908
 *
909
 * The reason for the separation, is that sometimes we're initialising a dictionary attribute
910
 * by parsing an actual dictionary file, and other times we're copying attribute, or initialising
911
 * them programatically.
912
 *
913
 * This function should only be used for the second case, where we have a complet attribute
914
 * definition already.
915
 *
916
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
917
 *
918
 * @param[in] filename    file.
919
 * @param[in] line    number.
920
 * @param[in] da_p    to initialise.
921
 * @param[in] parent    of the attribute, if none, this attribute will
922
 *        be initialised as a dictionary root.
923
 * @param[in] name    of attribute.  Pass NULL for auto-generated name.
924
 * @param[in] attr    number.
925
 * @param[in] type    of the attribute.
926
 * @param[in] args    optional initialisation arguments.
927
 * @return
928
 *  - 0 on success.
929
 *  - <0 on error.
930
 */
931
int _dict_attr_init(char const *filename, int line,
932
        fr_dict_attr_t **da_p,
933
        fr_dict_attr_t const *parent,
934
        char const *name, unsigned int attr,
935
        fr_type_t type, dict_attr_args_t const *args)
936
6.05M
{
937
  /*
938
   *  We initialize the number first, as doing that doesn't have any other side effects.
939
   */
940
6.05M
  if (unlikely(dict_attr_num_init(*da_p, attr) < 0)) return -1;
941
942
  /*
943
   *  This function then checks the number, for things like VSAs.
944
   */
945
6.05M
  if (unlikely(dict_attr_init_common(filename, line, da_p, parent, type, args) < 0)) return -1;
946
947
6.05M
  if (unlikely(dict_attr_finalise(da_p, name) < 0)) return -1;
948
949
6.05M
  return 0;
950
6.05M
}
951
952
/** Initialise fields in a dictionary attribute structure
953
 *
954
 * This function is a wrapper around the other initialisation functions.
955
 *
956
 * The reason for the separation, is that sometimes we're initialising a dictionary attribute
957
 * by parsing an actual dictionary file, and other times we're copying attribute, or initialising
958
 * them programatically.
959
 *
960
 * This function should only be used for the second case, where we have a complet attribute
961
 * definition already.
962
 *
963
 * @note This function can only be used _before_ the attribute is inserted into the dictionary.
964
 *
965
 * @param[in] filename    file.
966
 * @param[in] line    number.
967
 * @param[in] da_p    to initialise.
968
 * @param[in] parent    of the attribute, if none, this attribute will
969
 *        be initialised as a dictionary root.
970
 * @param[in] name    of attribute.  Pass NULL for auto-generated name.
971
 *        automatically generated.
972
 * @param[in] type    of the attribute.
973
 * @param[in] args    optional initialisation arguments.
974
 * @return
975
 *  - 0 on success.
976
 *  - <0 on error.
977
 */
978
int _dict_attr_init_name_only(char const *filename, int line,
979
       fr_dict_attr_t **da_p,
980
       fr_dict_attr_t const *parent,
981
       char const *name,
982
       fr_type_t type, dict_attr_args_t const *args)
983
0
{
984
0
  if (unlikely(dict_attr_init_common(filename, line, da_p, parent, type, args) < 0)) return -1;
985
986
  /*
987
   *  Automatically generate the attribute number when the attribut is added.
988
   */
989
0
  (*da_p)->flags.name_only = true;
990
991
0
  if (unlikely(dict_attr_finalise(da_p, name) < 0)) return -1;
992
993
0
  return 0;
994
0
}
995
996
static int _dict_attr_free(fr_dict_attr_t *da)
997
6.09M
{
998
6.09M
  fr_dict_attr_ext_enumv_t  *ext;
999
1000
#if 0
1001
#ifdef WITH_VERIFY_PTR
1002
  /*
1003
   *  Check that any attribute we reference is still valid
1004
   *  when we're being freed.
1005
   */
1006
  fr_dict_attr_t const *ref = fr_dict_attr_ref(da);
1007
1008
  if (ref) (void)talloc_get_type_abort_const(ref, fr_dict_attr_t);
1009
#endif
1010
#endif
1011
1012
6.09M
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
1013
6.09M
  if (ext) talloc_free(ext->value_by_name);    /* Ensure this is freed before the enumvs */
1014
1015
6.09M
  return 0;
1016
6.09M
}
1017
1018
/** Allocate a partially completed attribute
1019
 *
1020
 * This is useful in some instances where we need to pre-allocate the attribute
1021
 * for talloc hierarchy reasons, but want to finish initialising it
1022
 * with #dict_attr_init later.
1023
 *
1024
 * @param[in] ctx   to allocate attribute in.
1025
 * @param[in] proto   protocol specific extensions.
1026
 * @return
1027
 *  - A new, partially completed, fr_dict_attr_t on success.
1028
 *  - NULL on failure (memory allocation error).
1029
 */
1030
fr_dict_attr_t *dict_attr_alloc_null(TALLOC_CTX *ctx, fr_dict_protocol_t const *proto)
1031
6.09M
{
1032
6.09M
  fr_dict_attr_t *da;
1033
1034
  /*
1035
   *  Do not use talloc zero, the caller
1036
   *  always initialises memory allocated
1037
   *  here.
1038
   */
1039
6.09M
  da = talloc_zero(ctx, fr_dict_attr_t);
1040
6.09M
  if (unlikely(!da)) return NULL;
1041
1042
  /*
1043
   *  Allocate room for the protocol specific flags
1044
   */
1045
6.09M
  if (proto->attr.flags.len > 0) {
1046
407k
    if (unlikely(dict_attr_ext_alloc_size(&da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC,
1047
407k
                  proto->attr.flags.len) == NULL)) {
1048
0
      talloc_free(da);
1049
0
      return NULL;
1050
0
    }
1051
407k
  }
1052
6.09M
  talloc_set_destructor(da, _dict_attr_free);
1053
1054
6.09M
  return da;
1055
6.09M
}
1056
1057
/** Allocate a dictionary root attribute on the heap
1058
 *
1059
 * @param[in] filename    file.
1060
 * @param[in] line    number.
1061
 * @param[in] ctx   to allocate the attribute in.
1062
 * @param[in] dict    the attribute will be used in.
1063
 * @param[in] name    of the attribute.  If NULL an OID string
1064
 *        will be created and set as the name.
1065
 * @param[in] proto_number    number.  This should be
1066
 * @param[in] args    optional initialisation arguments.
1067
 * @return
1068
 *  - A new fr_dict_attr_t on success.
1069
 *  - NULL on failure.
1070
 */
1071
fr_dict_attr_t *_dict_attr_alloc_root(char const *filename, int line,
1072
              TALLOC_CTX *ctx,
1073
              fr_dict_t const *dict,
1074
              char const *name, int proto_number,
1075
              dict_attr_args_t const *args)
1076
46
{
1077
46
  fr_dict_attr_t  *n;
1078
1079
46
  n = dict_attr_alloc_null(ctx, dict->proto);
1080
46
  if (unlikely(!n)) return NULL;
1081
1082
46
  if (_dict_attr_init(filename, line, &n, NULL, name, proto_number, FR_TYPE_TLV, args) < 0) {
1083
0
    talloc_free(n);
1084
0
    return NULL;
1085
0
  }
1086
1087
46
  return n;
1088
46
}
1089
1090
/** Allocate a dictionary attribute on the heap
1091
 *
1092
 * @param[in] filename    file.
1093
 * @param[in] line    number.
1094
 * @param[in] ctx   to allocate the attribute in.
1095
 * @param[in] parent    of the attribute.
1096
 * @param[in] name    of the attribute.  If NULL an OID string
1097
 *        will be created and set as the name.
1098
 * @param[in] attr    number.
1099
 * @param[in] type    of the attribute.
1100
 * @param[in] args    optional initialisation arguments.
1101
 * @return
1102
 *  - A new fr_dict_attr_t on success.
1103
 *  - NULL on failure.
1104
 */
1105
fr_dict_attr_t *_dict_attr_alloc(char const *filename, int line,
1106
         TALLOC_CTX *ctx,
1107
         fr_dict_attr_t const *parent,
1108
         char const *name, int attr,
1109
         fr_type_t type, dict_attr_args_t const *args)
1110
3.59M
{
1111
3.59M
  fr_dict_attr_t  *n;
1112
1113
3.59M
  n = dict_attr_alloc_null(ctx, parent->dict->proto);
1114
3.59M
  if (unlikely(!n)) return NULL;
1115
1116
3.59M
  if (_dict_attr_init(filename, line, &n, parent, name, attr, type, args) < 0) {
1117
0
    talloc_free(n);
1118
0
    return NULL;
1119
0
  }
1120
1121
3.59M
  return n;
1122
3.59M
}
1123
1124
/** Copy a an existing attribute, possibly to a new location
1125
 *
1126
 * @param[in] ctx   to allocate new attribute in.
1127
 * @param[in] parent    where to parent the copy from. If NULL, in->parent is used.
1128
 * @param[in] in    attribute to copy.
1129
 * @param[in] name    to assign to the attribute. If NULL, in->name is used.
1130
 * @return
1131
 *  - A copy of the input fr_dict_attr_t on success.
1132
 *  - NULL on failure.
1133
 */
1134
fr_dict_attr_t *dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, fr_dict_attr_t const *in,
1135
        char const *name)
1136
800
{
1137
800
  fr_dict_attr_t    *n;
1138
1139
800
  if (in->flags.has_fixup) {
1140
0
    fr_strerror_printf("Cannot copy from %s - source attribute is waiting for additional definitions",
1141
0
           in->name);
1142
0
    return NULL;
1143
0
  }
1144
1145
800
  fr_assert(parent || name);
1146
1147
800
  n = dict_attr_alloc(ctx, parent ? parent : in->parent, name ? name : in->name,
1148
800
          in->attr, in->type, &(dict_attr_args_t){ .flags = &in->flags });
1149
800
  if (unlikely(!n)) return NULL;
1150
1151
  /*
1152
   *  This newly allocated attribute is not the target of a ref.
1153
   */
1154
800
  n->flags.is_ref_target = false;
1155
1156
800
  if (dict_attr_ext_copy_all(&n, in) < 0) {
1157
0
  error:
1158
0
    talloc_free(n);
1159
0
    return NULL;
1160
0
  }
1161
800
  DA_VERIFY(n);
1162
1163
800
  if (fr_type_is_structural(in->type) && in->flags.has_alias) {
1164
8
    if (dict_attr_acopy_aliases(n, in) < 0) goto error;
1165
8
  }
1166
1167
800
  return n;
1168
800
}
1169
1170
int fr_dict_attr_acopy_local(fr_dict_attr_t const *dst, fr_dict_attr_t const *src)
1171
0
{
1172
0
  if (!dst->flags.local) {
1173
0
    fr_strerror_const("Cannot copy attributes to a non-local dictionary");
1174
0
    return -1;
1175
0
  }
1176
1177
0
  if (src->flags.has_fixup) {
1178
0
    fr_strerror_printf("Cannot copy from %s to %s - source attribute is waiting for additional definitions",
1179
0
           src->name, dst->name);
1180
0
    return -1;
1181
0
  }
1182
1183
  /*
1184
   *  Why not?  @todo - check and fix
1185
   */
1186
0
  if (src->flags.local) {
1187
0
    fr_strerror_const("Cannot copy a local attribute");
1188
0
    return -1;
1189
0
  }
1190
1191
0
  return dict_attr_acopy_children(dst->dict, UNCONST(fr_dict_attr_t *, dst), src);
1192
0
}
1193
1194
static int dict_attr_acopy_child(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src,
1195
         fr_dict_attr_t const *child)
1196
800
{
1197
800
  fr_dict_attr_t      *copy;
1198
1199
800
  copy = dict_attr_acopy(dict->pool, dst, child, child->name);
1200
800
  if (!copy) return -1;
1201
1202
800
  fr_assert(copy->parent == dst);
1203
800
  copy->depth = copy->parent->depth + 1;
1204
1205
800
  if (dict_attr_child_add(dst, copy) < 0) return -1;
1206
1207
800
  if (dict_attr_add_to_namespace(dst, copy) < 0) return -1;
1208
1209
800
  if (!dict_attr_children(child)) return 0;
1210
1211
140
  if (dict_attr_acopy_children(dict, copy, child) < 0) return -1;
1212
1213
  /*
1214
   *  Children of a UNION get an ALIAS added to the parent of the UNION.  This allows the UNION
1215
   *  attribute to be omitted from parsing and printing.
1216
   */
1217
140
  if (src->type != FR_TYPE_UNION) return 0;
1218
1219
60
  return dict_attr_alias_add(dst->parent, copy->name, copy);
1220
140
}
1221
1222
1223
/** Copy the children of an existing attribute
1224
 *
1225
 * @param[in] dict    to allocate the children in
1226
 * @param[in] dst   where to copy the children to
1227
 * @param[in] src   where to copy the children from
1228
 * @return
1229
 *  - 0 on success
1230
 *  - <0 on error
1231
 */
1232
int dict_attr_acopy_children(fr_dict_t *dict, fr_dict_attr_t *dst, fr_dict_attr_t const *src)
1233
226
{
1234
226
  uint        child_num;
1235
226
  fr_dict_attr_t const    *child = NULL, *src_key = NULL;
1236
226
  fr_dict_attr_t      *dst_key;
1237
1238
226
  fr_assert(fr_dict_attr_has_ext(dst, FR_DICT_ATTR_EXT_CHILDREN));
1239
226
  fr_assert(dst->type == src->type);
1240
226
  fr_assert(fr_dict_attr_is_key_field(src) == fr_dict_attr_is_key_field(dst));
1241
1242
  /*
1243
   *  For non-struct parents, we can copy their children in any order.
1244
   */
1245
226
  if (likely(src->type != FR_TYPE_STRUCT)) {
1246
130
    for (child = fr_dict_attr_iterate_children(src, &child);
1247
722
         child != NULL;
1248
592
         child = fr_dict_attr_iterate_children(src, &child)) {
1249
592
      if (dict_attr_acopy_child(dict, dst, src, child) < 0) return -1;
1250
592
    }
1251
1252
130
    return 0;
1253
130
  }
1254
1255
  /*
1256
   *  For structs, we copy the children in order.  This allows "key" fields to be copied before
1257
   *  fields which depend on them.
1258
   *
1259
   *  Note that due to the checks in the DEFINE and ATTRIBUTE parsers (but not the validate
1260
   *  routines), STRUCTs can only have children which are MEMBERs.  And MEMBERs are allocated in
1261
   *  order.
1262
   */
1263
96
  for (child_num = 1, child = fr_dict_attr_child_by_num(src, child_num);
1264
320
       child != NULL;
1265
224
       child_num++, child = fr_dict_attr_child_by_num(src, child_num)) {
1266
    /*
1267
     *  If the key field has enums, then delay copying the enums until after we've copied all
1268
     *  of the other children.
1269
     *
1270
     *  For a UNION which is inside of a STRUCT, the UNION has a reference to the key field.
1271
     *  So the key field needs to be defined before we create the UNION.
1272
     *
1273
     *  But the key field also has a set of ENUMs, each of which has a key ref to the UNION
1274
     *  member which is associated with that key value.  This means that we have circular
1275
     *  dependencies.
1276
     *
1277
     *  The loop is resolved by creating the key first, and allocating room for an ENUM
1278
     *  extension.  This allows the UNION to reference the key.  Once the UNION is created, we
1279
     *  go back and copy all of the ENUMs over.  The ENUM copy routine will take care of
1280
     *  fixing up the refs.
1281
     */
1282
224
    if (unlikely(fr_dict_attr_is_key_field(child) && child->flags.has_value)) {
1283
16
      src_key = child;
1284
1285
16
      if (src_key->flags.has_fixup) {
1286
0
        fr_strerror_printf("Cannot copy from %s - source attribute is waiting for additional definitions",
1287
0
               src_key->name);
1288
0
        return -1;
1289
0
      }
1290
1291
16
      dst_key = dict_attr_alloc(dict, dst, src_key->name,
1292
16
              src_key->attr, src_key->type, &(dict_attr_args_t){ .flags = &src_key->flags });
1293
16
      if (unlikely(!dst_key)) return -1;
1294
1295
16
      if (!dict_attr_ext_alloc(&dst_key, FR_DICT_ATTR_EXT_ENUMV)) return -1;
1296
1297
16
      fr_assert(dst_key->parent == dst);
1298
16
      dst_key->depth = dst->depth + 1;
1299
1300
16
      if (dict_attr_child_add(dst, dst_key) < 0) return -1;
1301
1302
16
      if (dict_attr_add_to_namespace(dst, dst_key) < 0) return -1;
1303
1304
16
      continue;
1305
16
    }
1306
1307
208
    if (dict_attr_acopy_child(dict, dst, src, child) < 0) return -1;
1308
1309
208
    DA_VERIFY(child);
1310
208
  }
1311
1312
96
  DA_VERIFY(dst);
1313
1314
96
  if (!src_key) return 0;
1315
1316
16
  if (!dict_attr_ext_copy(&dst_key, src_key, FR_DICT_ATTR_EXT_ENUMV)) return -1;
1317
1318
16
  return 0;
1319
16
}
1320
1321
/** Copy the VALUEs of an existing attribute, by casting them
1322
 *
1323
 * @param[in] dst   where to cast the VALUEs to
1324
 * @param[in] src   where to cast the VALUEs from
1325
 * @return
1326
 *  - 0 on success
1327
 *  - <0 on error
1328
 */
1329
int dict_attr_acopy_enumv(fr_dict_attr_t *dst, fr_dict_attr_t const *src)
1330
0
{
1331
0
  fr_dict_attr_ext_enumv_t  *ext;
1332
1333
0
  fr_assert(!fr_type_is_non_leaf(dst->type));
1334
0
  fr_assert(!fr_type_is_non_leaf(src->type));
1335
1336
0
  fr_assert(fr_dict_attr_has_ext(dst, FR_DICT_ATTR_EXT_ENUMV));
1337
0
  fr_assert(fr_dict_attr_has_ext(src, FR_DICT_ATTR_EXT_ENUMV));
1338
1339
0
  ext = fr_dict_attr_ext(src, FR_DICT_ATTR_EXT_ENUMV);
1340
0
  if (!ext) {
1341
0
    fr_assert(0);
1342
0
    return -1;
1343
0
  }
1344
1345
0
  if (!ext->name_by_value) {
1346
0
    fr_strerror_printf("Reference enum %s does not have any VALUEs to copy", src->name);
1347
0
    return -1;
1348
0
  }
1349
1350
0
  if (dict_attr_ext_copy(&dst, src, FR_DICT_ATTR_EXT_ENUMV)) return fr_hash_table_num_elements(ext->name_by_value);
1351
1352
0
  return -1;
1353
0
}
1354
1355
1356
/** Copy aliases of an existing attribute to a new one.
1357
 *
1358
 * @param[in] dst   where to copy the children to
1359
 * @param[in] src   where to copy the children from
1360
 * @return
1361
 *  - 0 on success
1362
 *  - <0 on error
1363
 */
1364
int dict_attr_acopy_aliases(UNUSED fr_dict_attr_t *dst, fr_dict_attr_t const *src)
1365
8
{
1366
8
  fr_hash_table_t *namespace;
1367
8
  fr_hash_iter_t  iter;
1368
8
  fr_dict_attr_t const *da;
1369
1370
8
  if (!src->flags.has_alias) return 0;
1371
1372
8
  switch (src->type) {
1373
0
  case FR_TYPE_TLV:
1374
0
  case FR_TYPE_VENDOR:
1375
0
  case FR_TYPE_VSA:
1376
0
    break;
1377
1378
    /*
1379
     *  Automatically added aliases are copied in dict_attr_acopy_child().
1380
     */
1381
8
  case FR_TYPE_STRUCT:
1382
8
    return 0;
1383
1384
0
  default:
1385
0
    fr_strerror_printf("Cannot add ALIAS to parent attribute %s of data type '%s'", src->name, fr_type_to_str(src->type));
1386
0
    return -1;
1387
1388
8
  }
1389
1390
0
  namespace = dict_attr_namespace(src);
1391
0
  fr_assert(namespace != NULL);
1392
1393
0
  for (da = fr_hash_table_iter_init(namespace, &iter);
1394
0
       da != NULL;
1395
0
       da = fr_hash_table_iter_next(namespace, &iter)) {
1396
0
    if (!da->flags.is_alias) continue;
1397
1398
0
#if 1
1399
0
    fr_strerror_printf("Cannot clone ALIAS %s.%s to %s.%s", src->name, da->name, dst->name, da->name);
1400
0
    return -1;
1401
    
1402
#else
1403
    fr_dict_attr_t const *parent, *ref;
1404
    fr_dict_attr_t const *new_ref;
1405
1406
    ref = fr_dict_attr_ref(da);
1407
    fr_assert(ref != NULL);
1408
1409
    /*
1410
     *  ALIASes are normally down the tree, to shorten sibling relationships.
1411
     *  e.g. Cisco-AVPAir -> Vendor-Specific.Cisco.AV-Pair.
1412
     *
1413
     *  The question is to we want to allow aliases to create cross-tree links?  I suspect
1414
     *  not.
1415
     */
1416
    parent = fr_dict_attr_common_parent(src, ref, true);
1417
    if (!parent) {
1418
      fr_strerror_printf("Cannot clone ALIAS %s.%s to %s.%s, the alias reference %s is outside of the shared tree",
1419
             src->name, da->name, dst->name, da->name, ref->name);
1420
      return -1;
1421
    }
1422
1423
    fr_assert(parent == src);
1424
1425
    new_ref = fr_dict_attr_by_name(NULL, dst, da->name);
1426
    fr_assert(new_ref == NULL);
1427
1428
    /*
1429
     *  This function needs to walk back up from "ref" to "src", finding the intermediate DAs.
1430
     *  Once that's done, it needs to walk down from "dst" to create a new "ref".
1431
     */
1432
    new_ref = dict_alias_reref(dst, src, ref);
1433
    fr_assert(new_ref != NULL);
1434
1435
    if (dict_attr_alias_add(dst, da->name, new_ref) < 0) return -1;
1436
#endif
1437
0
  }
1438
1439
0
  return 0;
1440
0
}
1441
1442
/** Add an alias to an existing attribute
1443
 *
1444
 */
1445
int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref)
1446
1.26k
{
1447
1.26k
  fr_dict_attr_t const *da, *common;
1448
1.26k
  fr_dict_attr_t *self;
1449
1.26k
  fr_hash_table_t *namespace;
1450
1451
1.26k
  switch (parent->type) {
1452
316
  case FR_TYPE_STRUCT:
1453
    /*
1454
     *  If we are a STRUCT, the reference an only be to children of a UNION.
1455
     */
1456
316
    fr_assert(ref->parent->type == FR_TYPE_UNION);
1457
1458
    /*
1459
     *  And the UNION must be a MEMBER of the STRUCT.
1460
     */
1461
316
    fr_assert(ref->parent->parent == parent);
1462
316
    break;
1463
1464
832
  case FR_TYPE_TLV:
1465
944
  case FR_TYPE_VENDOR:
1466
944
  case FR_TYPE_VSA:
1467
944
    break;
1468
1469
0
  default:
1470
0
    fr_strerror_printf("Cannot add ALIAS to parent attribute %s of data type '%s'",
1471
0
           parent->name, fr_type_to_str(parent->type));
1472
0
    return -1;
1473
1.26k
  }
1474
1475
1.26k
  if ((ref->type == FR_TYPE_UNION) || fr_dict_attr_is_key_field(ref)) {
1476
0
    fr_strerror_printf("Cannot add ALIAS to target attribute %s of data type '%s'",
1477
0
           ref->name, fr_type_to_str(ref->type));
1478
0
    return -1;
1479
0
  }
1480
1481
1.26k
  da = dict_attr_by_name(NULL, parent, alias);
1482
1.26k
  if (da) {
1483
0
    fr_strerror_printf("ALIAS '%s' conflicts with another attribute in namespace %s",
1484
0
           alias, parent->name);
1485
0
    return -1;
1486
0
  }
1487
1488
  /*
1489
   *  ALIASes can point across the tree and down, for the same parent.  ALIASes cannot go back up
1490
   *  the tree.
1491
   */
1492
1.26k
  common = fr_dict_attr_common_parent(parent, ref, true);
1493
1.26k
  if (!common) {
1494
0
    fr_strerror_printf("Invalid ALIAS to target attribute %s of data type '%s' - the attributes do not share a parent",
1495
0
           ref->name, fr_type_to_str(ref->type));
1496
0
    return -1;
1497
0
  }
1498
1499
  /*
1500
   *  Note that we do NOT call fr_dict_attr_add() here.
1501
   *
1502
   *  When that function adds two equivalent attributes, the
1503
   *  second one is prioritized for printing.  For ALIASes,
1504
   *  we want the pre-existing one to be prioritized.
1505
   *
1506
   *  i.e. you can lookup the ALIAS by "name", but you
1507
   *  actually get returned "ref".
1508
   */
1509
1.26k
  {
1510
1.26k
    fr_dict_attr_flags_t flags = ref->flags;
1511
1512
1.26k
    flags.is_alias = 1; /* These get followed automatically by public functions */
1513
1514
1.26k
    self = dict_attr_alloc(parent->dict->pool, parent, alias, ref->attr, FR_TYPE_VOID, (&(dict_attr_args_t){ .flags = &flags, .ref = ref }));
1515
1.26k
    if (unlikely(!self)) return -1;
1516
1.26k
  }
1517
1518
1.26k
  self->dict = parent->dict;
1519
1.26k
  UNCONST(fr_dict_attr_t *, parent)->flags.has_alias = true;
1520
1521
1.26k
  fr_assert(fr_dict_attr_ref(self) == ref);
1522
1523
1.26k
  namespace = dict_attr_namespace(parent);
1524
1.26k
  if (!namespace) {
1525
0
    fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
1526
0
  error:
1527
0
    talloc_free(self);
1528
0
    return -1;
1529
0
  }
1530
1531
1.26k
  if (!fr_hash_table_insert(namespace, self)) {
1532
0
    fr_strerror_const("Internal error storing attribute");
1533
0
    goto error;
1534
0
  }
1535
1536
1.26k
  return 0;
1537
1.26k
}
1538
1539
/** Add a protocol to the global protocol table
1540
 *
1541
 * Inserts a protocol into the global protocol table.  Uses the root attributes
1542
 * of the dictionary for comparisons.
1543
 *
1544
 * @param[in] dict of protocol we're inserting.
1545
 * @return
1546
 *  - 0 on success.
1547
 *  - -1 on failure.
1548
 */
1549
int dict_protocol_add(fr_dict_t *dict)
1550
24
{
1551
24
  if (!dict->root) return -1; /* Should always have root */
1552
1553
24
  if (!fr_hash_table_insert(dict_gctx->protocol_by_name, dict)) {
1554
0
    fr_dict_t *old_proto;
1555
1556
0
    old_proto = fr_hash_table_find(dict_gctx->protocol_by_name, dict);
1557
0
    if (!old_proto) {
1558
0
      fr_strerror_printf("%s: Failed inserting protocol name %s", __FUNCTION__, dict->root->name);
1559
0
      return -1;
1560
0
    }
1561
1562
0
    if ((strcmp(old_proto->root->name, dict->root->name) == 0) &&
1563
0
        (old_proto->root->name == dict->root->name)) {
1564
0
      fr_strerror_printf("%s: Duplicate protocol name %s", __FUNCTION__, dict->root->name);
1565
0
      return -1;
1566
0
    }
1567
1568
0
    return 0;
1569
0
  }
1570
24
  dict->in_protocol_by_name = true;
1571
1572
24
  if (!fr_hash_table_insert(dict_gctx->protocol_by_num, dict)) {
1573
0
    fr_strerror_printf("%s: Duplicate protocol number %u", __FUNCTION__, dict->root->attr);
1574
0
    return -1;
1575
0
  }
1576
24
  dict->in_protocol_by_num = true;
1577
1578
24
  dict_dependent_add(dict, "global");
1579
1580
  /*
1581
   *  Create and add sub-attributes which allow other
1582
   *  protocols to be encapsulated in the internal
1583
   *  namespace.
1584
   */
1585
24
  if (dict_gctx->internal && (dict != dict_gctx->internal)) {
1586
24
    fr_dict_attr_t const *da;
1587
24
    fr_dict_attr_flags_t flags = { 0 };
1588
1589
24
    if (!dict_gctx->attr_protocol_encapsulation) dict_gctx->attr_protocol_encapsulation = fr_dict_attr_by_name(NULL, dict_gctx->internal->root, "Proto");
1590
24
    fr_assert(dict_gctx->attr_protocol_encapsulation != NULL);
1591
1592
24
    da = fr_dict_attr_child_by_num(dict_gctx->attr_protocol_encapsulation, dict->root->attr);
1593
24
    if (!da) {
1594
24
      if (fr_dict_attr_add(dict_gctx->internal, dict_gctx->attr_protocol_encapsulation,
1595
24
               dict->root->name, dict->root->attr, FR_TYPE_GROUP, &flags) < 0) {
1596
0
        return -1;
1597
0
      }
1598
1599
24
      da = fr_dict_attr_child_by_num(dict_gctx->attr_protocol_encapsulation, dict->root->attr);
1600
24
      fr_assert(da != NULL);
1601
24
    }
1602
1603
24
    dict_attr_ref_set(da, dict->root, FR_DICT_ATTR_REF_ALIAS);
1604
24
  }
1605
1606
24
  return 0;
1607
24
}
1608
1609
/** Add a vendor to the dictionary
1610
 *
1611
 * Inserts a vendor entry into the vendor hash table.  This must be done before adding
1612
 * attributes under a VSA.
1613
 *
1614
 * @param[in] dict    of protocol context we're operating in.
1615
 *        If NULL the internal dictionary will be used.
1616
 * @param[in] name    of the vendor.
1617
 * @param[in] num   Vendor's Private Enterprise Number.
1618
 * @return
1619
 *  - 0 on success.
1620
 *  - -1 on failure.
1621
 */
1622
int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
1623
810
{
1624
810
  size_t      len;
1625
810
  fr_dict_vendor_t  *vendor;
1626
1627
810
  INTERNAL_IF_NULL(dict, -1);
1628
1629
810
  len = strlen(name);
1630
810
  if (len >= FR_DICT_VENDOR_MAX_NAME_LEN) {
1631
0
    fr_strerror_printf("%s: Vendor name too long", __FUNCTION__);
1632
0
    return -1;
1633
0
  }
1634
1635
810
  vendor = talloc_zero(dict, fr_dict_vendor_t);
1636
810
  if (!vendor) {
1637
0
  oom:
1638
0
    fr_strerror_const("Out of memory");
1639
0
    return -1;
1640
0
  }
1641
1642
810
  vendor->name = talloc_typed_strdup(vendor, name);
1643
810
  if (!vendor->name) {
1644
0
    talloc_free(vendor);
1645
0
    goto oom;
1646
0
  }
1647
810
  vendor->pen = num;
1648
810
  vendor->type = vendor->length = 1; /* defaults */
1649
1650
810
  if (!fr_hash_table_insert(dict->vendors_by_name, vendor)) {
1651
0
    fr_dict_vendor_t const *old_vendor;
1652
1653
0
    old_vendor = fr_hash_table_find(dict->vendors_by_name, vendor);
1654
0
    if (!old_vendor) {
1655
0
      fr_strerror_printf("%s: Failed inserting vendor name %s", __FUNCTION__, name);
1656
0
      return -1;
1657
0
    }
1658
0
    if ((strcmp(old_vendor->name, vendor->name) == 0) && (old_vendor->pen != vendor->pen)) {
1659
0
      fr_strerror_printf("%s: Duplicate vendor name %s", __FUNCTION__, name);
1660
0
      return -1;
1661
0
    }
1662
1663
    /*
1664
     *  Already inserted.  Discard the duplicate entry.
1665
     */
1666
0
    talloc_free(vendor);
1667
1668
0
    return 0;
1669
0
  }
1670
1671
  /*
1672
   *  Insert the SAME pointer (not free'd when this table is
1673
   *  deleted), into another table.
1674
   *
1675
   *  We want this behaviour because we want OLD names for
1676
   *  the attributes to be read from the configuration
1677
   *  files, but when we're printing them, (and looking up
1678
   *  by value) we want to use the NEW name.
1679
   */
1680
810
  if (fr_hash_table_replace(NULL, dict->vendors_by_num, vendor) < 0) {
1681
0
    fr_strerror_printf("%s: Failed inserting vendor %s", __FUNCTION__, name);
1682
0
    return -1;
1683
0
  }
1684
1685
810
  return 0;
1686
810
}
1687
1688
/** See if a #fr_dict_attr_t can have children
1689
 *
1690
 *  The check for children is complicated by the need for "int" types
1691
 *  to have children, when they are `key` fields in a `struct`.  This
1692
 *  situation occurs when a struct has multiple sub-structures, which
1693
 *  are selected based on a `key` field.
1694
 *
1695
 *  There is no other place for the sub-structures to go.  In the
1696
 *  future, we may extend the functionality of the `key` field, by
1697
 *  allowing non-integer data types.  That would require storing keys
1698
 *  as #fr_dict_enum_value_t, and then placing the child (i.e. sub)
1699
 *  structures there.  But that would involve adding children to
1700
 *  enums, which is currently not supported.
1701
 *
1702
 * @param da the dictionary attribute to check.
1703
 */
1704
bool dict_attr_can_have_children(fr_dict_attr_t const *da)
1705
70.7k
{
1706
70.7k
  switch (da->type) {
1707
27.6k
  case FR_TYPE_TLV:
1708
57.1k
  case FR_TYPE_VENDOR:
1709
67.8k
  case FR_TYPE_VSA:
1710
70.4k
  case FR_TYPE_STRUCT:
1711
70.7k
  case FR_TYPE_UNION:
1712
70.7k
    return true;
1713
1714
0
  default:
1715
0
    break;
1716
70.7k
  }
1717
1718
0
  return false;
1719
70.7k
}
1720
1721
/** Add a child to a parent.
1722
 *
1723
 * @param[in] parent  we're adding a child to.
1724
 * @param[in] child to add to parent.
1725
 * @return
1726
 *  - 0 on success.
1727
 *  - -1 on failure (memory allocation error).
1728
 */
1729
int dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child)
1730
50.0k
{
1731
50.0k
  fr_dict_attr_t const * const *bin;
1732
50.0k
  fr_dict_attr_t **this;
1733
50.0k
  fr_dict_attr_t const **children;
1734
1735
  /*
1736
   *  Setup fields in the child
1737
   */
1738
50.0k
  fr_assert(child->parent == parent);
1739
1740
50.0k
  DA_VERIFY(child);
1741
1742
50.0k
  if (fr_dict_attr_ref(parent)) {
1743
0
    fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
1744
0
           parent->name, fr_dict_attr_ref(parent)->name);
1745
0
    return -1;
1746
0
  }
1747
1748
50.0k
  if (!dict_attr_can_have_children(parent)) {
1749
0
    fr_strerror_printf("Cannot add children to attribute '%s' of type %s",
1750
0
           parent->name,
1751
0
           fr_type_to_str(parent->type));
1752
0
    return -1;
1753
0
  }
1754
1755
50.0k
  if ((parent->type == FR_TYPE_VSA) && (child->type != FR_TYPE_VENDOR)) {
1756
0
    fr_strerror_printf("Cannot add non-vendor children to attribute '%s' of type %s",
1757
0
           parent->name,
1758
0
           fr_type_to_str(parent->type));
1759
0
    return -1;
1760
0
  }
1761
1762
  /*
1763
   *  The parent has children by name only, not by number.  Don't even bother trying to track
1764
   *  numbers, except for VENDOR in root, and MEMBER of a struct.
1765
   */
1766
50.0k
  if (!parent->flags.is_root && parent->flags.name_only &&
1767
344
      (parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) {
1768
0
    return 0;
1769
0
  }
1770
1771
  /*
1772
   *  We only allocate the pointer array *if* the parent has children.
1773
   */
1774
50.0k
  children = dict_attr_children(parent);
1775
50.0k
  if (!children) {
1776
2.69k
    children = talloc_zero_array(parent, fr_dict_attr_t const *, UINT8_MAX + 1);
1777
2.69k
    if (!children) {
1778
0
      fr_strerror_const("Out of memory");
1779
0
      return -1;
1780
0
    }
1781
2.69k
    if (dict_attr_children_set(parent, children) < 0) return -1;
1782
2.69k
  }
1783
1784
  /*
1785
   *  Treat the array as a hash of 255 bins, with attributes
1786
   *  sorted into bins using num % 255.
1787
   *
1788
   *  Although the various protocols may define numbers higher than 255:
1789
   *
1790
   *  RADIUS/DHCPv4     - 1-255
1791
   *  Diameter/Internal - 1-4294967295
1792
   *  DHCPv6            - 1-65535
1793
   *
1794
   *  In reality very few will ever use attribute numbers > 500, so for
1795
   *  the majority of lookups we get O(1) performance.
1796
   *
1797
   *  Attributes are inserted into the bin in order of their attribute
1798
   *  numbers to allow slightly more efficient lookups.
1799
   */
1800
51.2k
  for (bin = &children[child->attr & 0xff]; *bin; bin = &(*bin)->next) {
1801
    /*
1802
     *  Workaround for vendors that overload the RFC space.
1803
     *  Structural attributes always take priority.
1804
     */
1805
7.62k
    bool child_is_struct = fr_type_is_structural(child->type);
1806
7.62k
    bool bin_is_struct = fr_type_is_structural((*bin)->type);
1807
1808
7.62k
    if (child_is_struct && !bin_is_struct) break;
1809
7.32k
    if (fr_dict_vendor_num_by_da(child) <= fr_dict_vendor_num_by_da(*bin)) break;  /* Prioritise RFC attributes */
1810
1.26k
    if (child->attr <= (*bin)->attr) break;
1811
1.26k
  }
1812
1813
50.0k
  memcpy(&this, &bin, sizeof(this));
1814
50.0k
  child->next = *this;
1815
50.0k
  *this = child;
1816
1817
50.0k
  return 0;
1818
50.0k
}
1819
1820
/** Add an attribute to the name table for an attribute
1821
 *
1822
 * @param[in] parent    containing the namespace to add this attribute to.
1823
 * @param[in] da    to add to the name lookup tables.
1824
 * @return
1825
 *  - 0 on success.
1826
 *  - -1 on failure.
1827
 */
1828
int dict_attr_add_to_namespace(fr_dict_attr_t const *parent, fr_dict_attr_t *da)
1829
50.0k
{
1830
50.0k
  fr_hash_table_t   *namespace;
1831
1832
50.0k
  namespace = dict_attr_namespace(parent);
1833
50.0k
  if (unlikely(!namespace)) {
1834
0
    fr_strerror_printf("Parent \"%s\" has no namespace", parent->name);
1835
0
  error:
1836
0
    return -1;
1837
0
  }
1838
1839
  /*
1840
   *  Sanity check to stop children of vendors ending
1841
   *  up in the Vendor-Specific or root namespace.
1842
   */
1843
50.0k
  if ((fr_dict_vendor_num_by_da(da) != 0) && (da->type != FR_TYPE_VENDOR) &&
1844
28.5k
      ((parent->type == FR_TYPE_VSA) || parent->flags.is_root)) {
1845
0
    fr_strerror_printf("Cannot insert attribute '%s' of type %s into %s",
1846
0
           da->name,
1847
0
           fr_type_to_str(da->type),
1848
0
           parent->name);
1849
0
    goto error;
1850
0
  }
1851
1852
  /*
1853
   *  Insert the attribute, only if it's not a duplicate.
1854
   */
1855
50.0k
  if (!fr_hash_table_insert(namespace, da)) {
1856
0
    fr_dict_attr_t *a;
1857
1858
    /*
1859
     *  Find the old name.  If it's the same name and
1860
     *  but the parent, or number, or type are
1861
     *  different, that's an error.
1862
     */
1863
0
    a = fr_hash_table_find(namespace, da);
1864
0
    if (a && (strcasecmp(a->name, da->name) == 0)) {
1865
0
      if ((a->attr != da->attr) || (a->type != da->type) || (a->parent != da->parent)) {
1866
0
        fr_strerror_printf("Duplicate attribute name '%s' in namespace '%s'.  "
1867
0
                 "Originally defined %s[%d]",
1868
0
               da->name, parent->name,
1869
0
               a->filename, a->line);
1870
0
        goto error;
1871
0
      }
1872
0
    }
1873
1874
    /*
1875
     *  Otherwise the attribute has been redefined later
1876
     *  in the dictionary.
1877
     *
1878
     *  The original fr_dict_attr_t remains in the
1879
     *  dictionary but entry in the name hash table is
1880
     *  updated to point to the new definition.
1881
     */
1882
0
    if (fr_hash_table_replace(NULL, namespace, da) < 0) {
1883
0
      fr_strerror_const("Internal error storing attribute");
1884
0
      goto error;
1885
0
    }
1886
0
  }
1887
1888
50.0k
  return 0;
1889
50.0k
}
1890
1891
/** A variant of fr_dict_attr_t that allows a pre-allocated, populated fr_dict_attr_t to be added
1892
 *
1893
 */
1894
int fr_dict_attr_add_initialised(fr_dict_attr_t *da)
1895
47.5k
{
1896
47.5k
  fr_dict_attr_t const  *exists;
1897
1898
47.5k
  if (unlikely(da->dict->read_only)) {
1899
0
    fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(da->dict)->name);
1900
0
    return -1;
1901
0
  }
1902
1903
47.5k
  if (unlikely(da->state.finalised == false)) {
1904
0
    fr_strerror_const("Attribute has not been finalised");
1905
0
    return -1;
1906
0
  }
1907
1908
  /*
1909
   *  Check that the definition is valid.
1910
   */
1911
47.5k
  if (!dict_attr_valid(da)) return -1;
1912
1913
  /*
1914
   *  Don't allow duplicate names
1915
   *
1916
   *  Previously we allowed duplicate names, but only if the
1917
   *  attributes were compatible (we'd just ignore the operation).
1918
   *
1919
   *  But as attribute parsing may have generated fixups, which
1920
   *  we'd now need to unpick, it's easier just to error out
1921
   *  and have the user fix the duplicate.
1922
   */
1923
47.5k
  exists = fr_dict_attr_by_name(NULL, da->parent, da->name);
1924
47.5k
  if (exists) {
1925
0
    fr_strerror_printf("Duplicate attribute name '%s' in namespace '%s'.  "
1926
0
           "Originally defined %s[%d]", da->name, da->parent->name,
1927
0
           exists->filename, exists->line);
1928
0
    return -1;
1929
0
  }
1930
1931
  /*
1932
   *  In some cases name_only attributes may have explicitly
1933
   *  assigned numbers. Ensure that there are no conflicts
1934
   *  between auto-assigned and explkicitly assigned.
1935
   */
1936
47.5k
  if (da->flags.name_only) {
1937
326
    if (da->state.attr_set) {
1938
326
      fr_dict_attr_t *parent = fr_dict_attr_unconst(da->parent);
1939
1940
326
      if (da->attr > da->parent->last_child_attr) {
1941
0
        parent->last_child_attr = da->attr;
1942
1943
        /*
1944
        * If the attribute is outside of the bounds of
1945
        * the type size, then it MUST be an internal
1946
        * attribute.  Set the flag in this attribute, so
1947
        * that the encoder doesn't have to do complex
1948
        * checks.
1949
        */
1950
0
        if ((da->attr >= (((uint64_t)1) << (8 * parent->flags.type_size)))) da->flags.internal = true;
1951
0
      }
1952
326
    } else if (unlikely(dict_attr_num_init_name_only(da)) < 0) {
1953
0
      return -1;
1954
0
    }
1955
326
  }
1956
1957
  /*
1958
   *  Attributes can also be indexed by number.  Ensure that
1959
   *  all attributes of the same number have the same
1960
   *  properties.
1961
   */
1962
47.5k
  exists = fr_dict_attr_child_by_num(da->parent, da->attr);
1963
47.5k
  if (exists) {
1964
0
    fr_strerror_printf("Duplicate attribute number %u in namespace '%s'.  "
1965
0
           "Originally defined by '%s' at %s[%d]",
1966
0
           da->attr, da->parent->name, exists->name, exists->filename, exists->line);
1967
0
    return -1;
1968
0
  }
1969
1970
  /*
1971
   *  Add in by number
1972
   */
1973
47.5k
  if (dict_attr_child_add(UNCONST(fr_dict_attr_t *, da->parent), da) < 0) return -1;
1974
1975
  /*
1976
   *  Add in by name
1977
   */
1978
47.5k
  if (dict_attr_add_to_namespace(da->parent, da) < 0) return -1;
1979
1980
47.5k
#ifndef NDEBUG
1981
47.5k
  {
1982
47.5k
    fr_dict_attr_t const *found;
1983
1984
    /*
1985
     *  Check if we added the attribute
1986
     */
1987
47.5k
    found = dict_attr_child_by_num(da->parent, da->attr);
1988
47.5k
    if (!found) {
1989
0
      fr_strerror_printf("FATAL - Failed to find attribute number %u we just added to namespace '%s'", da->attr, da->parent->name);
1990
0
      return -1;
1991
0
    }
1992
1993
47.5k
    if (!dict_attr_by_name(NULL, da->parent, da->name)) {
1994
0
      fr_strerror_printf("FATAL - Failed to find attribute '%s' we just added to namespace '%s'", da->name, da->parent->name);
1995
0
      return -1;
1996
0
    }
1997
47.5k
  }
1998
47.5k
#endif
1999
2000
47.5k
  return 0;
2001
47.5k
}
2002
2003
/** Add an attribute to the dictionary
2004
 *
2005
 * @param[in] dict    of protocol context we're operating in.
2006
 *        If NULL the internal dictionary will be used.
2007
 * @param[in] parent    to add attribute under.
2008
 * @param[in] name    of the attribute.
2009
 * @param[in] attr    number.
2010
 * @param[in] type    of attribute.
2011
 * @param[in] flags   to set in the attribute.
2012
 * @return
2013
 *  - 0 on success.
2014
 *  - -1 on failure.
2015
 */
2016
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent,
2017
         char const *name, unsigned int attr, fr_type_t type, fr_dict_attr_flags_t const *flags)
2018
4.60k
{
2019
4.60k
  fr_dict_attr_t *da;
2020
2021
4.60k
  if (fr_dict_attr_ref(parent)) {
2022
0
    fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
2023
0
           parent->name, fr_dict_attr_ref(parent)->name);
2024
0
    return -1;
2025
0
  }
2026
2027
4.60k
  if (!dict_attr_can_have_children(parent)) {
2028
0
    fr_strerror_printf("Cannot add children to attribute '%s' of type %s",
2029
0
           parent->name,
2030
0
           fr_type_to_str(parent->type));
2031
0
    return -1;
2032
0
  }
2033
2034
4.60k
  da = dict_attr_alloc_null(dict->pool, dict->proto);
2035
4.60k
  if (unlikely(!da)) return -1;
2036
2037
4.60k
  if (dict_attr_init(&da, parent, name,
2038
4.60k
         attr, type, &(dict_attr_args_t){ .flags = flags}) < 0) return -1;
2039
2040
4.60k
  return fr_dict_attr_add_initialised(da);
2041
4.60k
}
2042
2043
/** Add an attribute to the dictionary
2044
 *
2045
 * @param[in] dict    of protocol context we're operating in.
2046
 *        If NULL the internal dictionary will be used.
2047
 * @param[in] parent    to add attribute under.
2048
 * @param[in] name    of the attribute.
2049
 * @param[in] type    of attribute.
2050
 * @param[in] flags   to set in the attribute.
2051
 * @return
2052
 *  - 0 on success.
2053
 *  - -1 on failure.
2054
 */
2055
int fr_dict_attr_add_name_only(fr_dict_t *dict, fr_dict_attr_t const *parent,
2056
             char const *name, fr_type_t type, fr_dict_attr_flags_t const *flags)
2057
0
{
2058
0
  fr_dict_attr_t *da;
2059
2060
0
  da = dict_attr_alloc_null(dict->pool, dict->proto);
2061
0
  if (unlikely(!da)) return -1;
2062
2063
0
  if (dict_attr_init_name_only(&da, parent, name,type, &(dict_attr_args_t){ .flags = flags}) < 0) return -1;
2064
2065
0
  return fr_dict_attr_add_initialised(da);
2066
0
}
2067
2068
2069
int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name,
2070
          fr_value_box_t const *value,
2071
          bool coerce, bool takes_precedence,
2072
          fr_dict_attr_t const *key_child_ref)
2073
38.3k
{
2074
38.3k
  size_t        len;
2075
38.3k
  fr_dict_enum_value_t    *enumv = NULL;
2076
38.3k
  fr_value_box_t      *enum_value = NULL;
2077
38.3k
  fr_dict_attr_ext_enumv_t  *ext;
2078
2079
38.3k
  if (!da) {
2080
0
    fr_strerror_printf("%s: Dictionary attribute not specified", __FUNCTION__);
2081
0
    return -1;
2082
0
  }
2083
2084
38.3k
  if (!*name) {
2085
0
    fr_strerror_printf("%s: Empty names are not permitted", __FUNCTION__);
2086
0
    return -1;
2087
0
  }
2088
2089
38.3k
  len = strlen(name);
2090
38.3k
  if (len >= FR_DICT_ENUM_MAX_NAME_LEN) {
2091
0
    fr_strerror_printf("VALUE name is too long");
2092
0
    return -1;
2093
0
  }
2094
2095
  /*
2096
   *  If the parent isn't a key field, then we CANNOT add a child struct.
2097
   */
2098
38.3k
  if (!fr_dict_attr_is_key_field(da) && key_child_ref) {
2099
0
    fr_strerror_const("Child attributes cannot be defined for VALUEs which are not 'key' attributes");
2100
0
    return -1;
2101
0
  }
2102
2103
38.3k
  if (fr_type_is_structural(da->type) || (da->type == FR_TYPE_STRING)) {
2104
0
    fr_strerror_printf("Enumeration names cannot be added for data type '%s'", fr_type_to_str(da->type));
2105
0
    return -1;
2106
0
  }
2107
2108
38.3k
  if (da->flags.is_alias) {
2109
0
    fr_strerror_printf("Enumeration names cannot be added for ALIAS '%s'", da->name);
2110
0
    return -1;
2111
0
  }
2112
2113
38.3k
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
2114
38.3k
  if (!ext) {
2115
0
    fr_strerror_printf("VALUE cannot be defined for %s", da->name);
2116
0
    return -1;
2117
0
  }
2118
2119
  /*
2120
   *  Initialise enumv hash tables
2121
   */
2122
38.3k
  if (!ext->value_by_name || !ext->name_by_value) {
2123
3.98k
    ext->value_by_name = fr_hash_table_talloc_alloc(da, fr_dict_enum_value_t, dict_enum_name_hash,
2124
3.98k
                dict_enum_name_cmp, hash_pool_free);
2125
3.98k
    if (!ext->value_by_name) {
2126
0
      fr_strerror_printf("Failed allocating \"value_by_name\" table");
2127
0
      return -1;
2128
0
    }
2129
2130
3.98k
    ext->name_by_value = fr_hash_table_talloc_alloc(da, fr_dict_enum_value_t, dict_enum_value_hash,
2131
3.98k
                dict_enum_value_cmp, NULL);
2132
3.98k
    if (!ext->name_by_value) {
2133
0
      fr_strerror_printf("Failed allocating \"name_by_value\" table");
2134
0
      return -1;
2135
0
    }
2136
3.98k
  }
2137
2138
  /*
2139
   *  Allocate a structure to map between
2140
   *  the name and value.
2141
   */
2142
38.3k
  enumv = talloc_zero_size(da, sizeof(fr_dict_enum_value_t));
2143
38.3k
  if (!enumv) {
2144
0
  oom:
2145
0
    fr_strerror_printf("%s: Out of memory", __FUNCTION__);
2146
0
    return -1;
2147
0
  }
2148
38.3k
  talloc_set_type(enumv, fr_dict_enum_value_t);
2149
2150
38.3k
  enumv->name = talloc_typed_strdup(enumv, name);
2151
38.3k
  enumv->name_len = len;
2152
2153
38.3k
  if (key_child_ref) {
2154
316
    fr_dict_enum_ext_attr_ref_t *ref;
2155
2156
316
    ref = dict_enum_ext_alloc(&enumv, FR_DICT_ENUM_EXT_ATTR_REF);
2157
316
    if (!ref) goto oom;
2158
2159
316
    ref->da = key_child_ref;
2160
316
  }
2161
2162
38.3k
  enum_value = fr_value_box_alloc(enumv, da->type, NULL);
2163
38.3k
  if (!enum_value) goto oom;
2164
2165
38.3k
  if (da->type != value->type) {
2166
0
    if (!coerce) {
2167
0
      fr_strerror_printf("Type mismatch between attribute (%s) and enum (%s)",
2168
0
             fr_type_to_str(da->type),
2169
0
             fr_type_to_str(value->type));
2170
0
      return -1;
2171
0
    }
2172
2173
0
    if (fr_value_box_cast(enumv, enum_value, da->type, NULL, value) < 0) {
2174
0
      fr_strerror_printf_push("Failed coercing enum type (%s) to attribute type (%s)",
2175
0
              fr_type_to_str(value->type),
2176
0
              fr_type_to_str(da->type));
2177
2178
0
      return -1;
2179
0
    }
2180
38.3k
  } else {
2181
38.3k
    if (unlikely(fr_value_box_copy(enum_value, enum_value, value) < 0)) {
2182
0
      fr_strerror_printf_push("%s: Failed copying value into enum", __FUNCTION__);
2183
0
      return -1;
2184
0
    }
2185
38.3k
  }
2186
2187
38.3k
  enumv->value = enum_value;
2188
2189
  /*
2190
   *  Add the value into the dictionary.
2191
   */
2192
38.3k
  {
2193
38.3k
    fr_dict_attr_t *tmp;
2194
38.3k
    memcpy(&tmp, &enumv, sizeof(tmp));
2195
2196
38.3k
    if (!fr_hash_table_insert(ext->value_by_name, tmp)) {
2197
20
      fr_dict_enum_value_t const *old;
2198
2199
      /*
2200
       *  Suppress duplicates with the same
2201
       *  name and value.  There are lots in
2202
       *  dictionary.ascend.
2203
       */
2204
20
      old = fr_dict_enum_by_name(da, name, -1);
2205
20
      if (!fr_cond_assert(old)) return -1;
2206
2207
20
      if (fr_value_box_cmp(old->value, enumv->value) == 0) {
2208
20
        talloc_free(enumv);
2209
20
        return 0;
2210
20
      }
2211
2212
0
      fr_strerror_printf("Duplicate VALUE name \"%s\" for Attribute '%s'. "
2213
0
             "Old value was \"%pV\", new value was \"%pV\"", name, da->name,
2214
0
             old->value, enumv->value);
2215
0
      talloc_free(enumv);
2216
0
      return -1;
2217
20
    }
2218
2219
38.2k
    if (enumv->name_len > ext->max_name_len) ext->max_name_len = enumv->name_len;
2220
38.2k
  }
2221
2222
  /*
2223
   *  There are multiple VALUE's, keyed by attribute, so we
2224
   *  take care of that here.
2225
   */
2226
38.2k
  if (takes_precedence) {
2227
37.3k
    if (fr_hash_table_replace(NULL, ext->name_by_value, enumv) < 0) {
2228
0
      fr_strerror_printf("%s: Failed inserting value %s", __FUNCTION__, name);
2229
0
      return -1;
2230
0
    }
2231
37.3k
  } else {
2232
884
    (void) fr_hash_table_insert(ext->name_by_value, enumv);
2233
884
  }
2234
2235
  /*
2236
   *  Mark the attribute up as having an enumv
2237
   */
2238
38.2k
  UNCONST(fr_dict_attr_t *, da)->flags.has_value = 1;
2239
2240
38.2k
  return 0;
2241
38.2k
}
2242
2243
/** Add a value name
2244
 *
2245
 * Aliases are textual (string) names for a given value.
2246
 *
2247
 * Value names are not limited to integers, and may be added for any non-structural
2248
 * attribute type.
2249
 *
2250
 * @param[in] da    to add enumeration value to.
2251
 * @param[in] name    Name of value name.
2252
 * @param[in] value   to associate with name.
2253
 * @param[in] coerce    if the type of the value does not match the
2254
 *        type of the da, attempt to cast it to match
2255
 *        the type of the da.  If this is false and there's
2256
 *        a type mismatch, we fail.
2257
 *        We also fail if the value cannot be coerced to
2258
 *        the attribute type.
2259
 * @param[in] takes_precedence  This name should take precedence over previous
2260
 *        names for the same value, when resolving value
2261
 *        to name.
2262
 * @return
2263
 *  - 0 on success.
2264
 *  - -1 on failure.
2265
 */
2266
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name,
2267
             fr_value_box_t const *value,
2268
             bool coerce, bool takes_precedence)
2269
36.8k
{
2270
36.8k
  return dict_attr_enum_add_name(da, name, value, coerce, takes_precedence, NULL);
2271
36.8k
}
2272
2273
/** Add an name to an integer attribute hashing the name for the integer value
2274
 *
2275
 * If the integer value conflicts with an existing name, it's incremented
2276
 * until we find a free value.
2277
 */
2278
int fr_dict_enum_add_name_next(fr_dict_attr_t *da, char const *name)
2279
0
{
2280
0
  fr_value_box_t  v = {
2281
0
        .type = da->type
2282
0
      };
2283
0
  fr_value_box_t  s = {
2284
0
        .type = da->type
2285
0
      };
2286
2287
0
  if (fr_dict_enum_by_name(da, name, -1)) return 0;
2288
2289
0
  switch (da->type) {
2290
0
  case FR_TYPE_INT8:
2291
0
    v.vb_int8 = s.vb_int8 = fr_hash_string(name) & INT8_MAX;
2292
0
    break;
2293
2294
0
  case FR_TYPE_INT16:
2295
0
    v.vb_int16 = s.vb_int16 = fr_hash_string(name) & INT16_MAX;
2296
0
    break;
2297
2298
0
  case FR_TYPE_INT32:
2299
0
    v.vb_int32 = s.vb_int32 = fr_hash_string(name) & INT32_MAX;
2300
0
    break;
2301
2302
0
  case FR_TYPE_INT64:
2303
0
    v.vb_int64 = s.vb_int64 = fr_hash_string(name) & INT64_MAX;
2304
0
    break;
2305
2306
0
  case FR_TYPE_UINT8:
2307
0
    v.vb_uint8 = s.vb_uint8 = fr_hash_string(name) & UINT8_MAX;
2308
0
    break;
2309
2310
0
  case FR_TYPE_UINT16:
2311
0
    v.vb_uint16 = s.vb_uint16 = fr_hash_string(name) & UINT16_MAX;
2312
0
    break;
2313
2314
0
  case FR_TYPE_UINT32:
2315
0
    v.vb_uint32 = s.vb_uint32 = fr_hash_string(name) & UINT32_MAX;
2316
0
    break;
2317
2318
0
  case FR_TYPE_UINT64:
2319
0
    v.vb_uint64 = s.vb_uint64 = fr_hash_string(name) & UINT64_MAX;
2320
0
    break;
2321
2322
0
  default:
2323
0
    fr_strerror_printf("Attribute is wrong type for auto-numbering, expected numeric type, got %s",
2324
0
           fr_type_to_str(da->type));
2325
0
    return -1;
2326
0
  }
2327
2328
  /*
2329
   *  If there's no existing value, add an enum
2330
   *  with the hash value of the name.
2331
   *
2332
   *  This helps with debugging as the values
2333
   *  are consistent.
2334
   */
2335
0
  if (!fr_dict_enum_by_value(da, &v)) {
2336
0
  add:
2337
0
    return fr_dict_enum_add_name(da, name, &v, false, false);
2338
0
  }
2339
2340
0
  for (;;) {
2341
0
    fr_value_box_increment(&v);
2342
2343
0
    if (fr_value_box_cmp_op(T_OP_CMP_EQ, &v, &s) == 0) {
2344
0
      fr_strerror_const("No free integer values for enumeration");
2345
0
      return -1;
2346
0
    }
2347
2348
0
    if (!fr_dict_enum_by_value(da, &v)) goto add;
2349
0
  }
2350
  /* NEVER REACHED */
2351
0
}
2352
2353
/** Find a common ancestor that two TLV type attributes share
2354
 *
2355
 * @param[in] a     first TLV attribute.
2356
 * @param[in] b     second TLV attribute.
2357
 * @param[in] is_ancestor Enforce a->b relationship (a is parent or ancestor of b).
2358
 * @return
2359
 *  - Common ancestor if one exists.
2360
 *  - NULL if no common ancestor exists.
2361
 */
2362
fr_dict_attr_t const *fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
2363
1.48k
{
2364
1.48k
  unsigned int i;
2365
1.48k
  fr_dict_attr_t const *p_a, *p_b;
2366
2367
1.48k
  if (!a || !b) return NULL;
2368
2369
1.48k
  if (is_ancestor && (b->depth <= a->depth)) return NULL; /* fast_path */
2370
2371
  /*
2372
   *  Find a common depth to work back from
2373
   */
2374
1.48k
  if (a->depth > b->depth) {
2375
0
    p_b = b;
2376
0
    for (p_a = a, i = a->depth - b->depth; p_a && (i > 0); p_a = p_a->parent, i--);
2377
0
    if (is_ancestor && (p_a != p_b)) return NULL;
2378
1.48k
  } else if (a->depth < b->depth) {
2379
1.48k
    p_a = a;
2380
4.19k
    for (p_b = b, i = b->depth - a->depth; p_b && (i > 0); p_b = p_b->parent, i--);
2381
1.48k
    if (is_ancestor && (p_a != p_b)) return NULL;
2382
1.48k
  } else {
2383
0
    p_a = a;
2384
0
    p_b = b;
2385
0
  }
2386
2387
1.48k
  while (p_a && p_b) {
2388
1.48k
    if (p_a == p_b) return p_a;
2389
2390
0
    p_a = p_a->parent;
2391
0
    p_b = p_b->parent;
2392
0
  }
2393
2394
0
  return NULL;
2395
1.48k
}
2396
2397
/** Process a single OID component
2398
 *
2399
 * @param[out] out    Value of component.
2400
 * @param[in] oid   string to parse.
2401
 * @return
2402
 *  - 0 on success.
2403
 *  - -1 on format error.
2404
 */
2405
int fr_dict_oid_component_legacy(unsigned int *out, char const **oid)
2406
4.64k
{
2407
4.64k
  char const *p = *oid;
2408
4.64k
  char *q;
2409
4.64k
  unsigned long num;
2410
2411
4.64k
  *out = 0;
2412
2413
4.64k
  num = strtoul(p, &q, 10);
2414
4.64k
  if ((p == q) || (num == ULONG_MAX)) {
2415
0
    fr_strerror_printf("Invalid OID component \"%s\" (%lu)", p, num);
2416
0
    return -1;
2417
0
  }
2418
2419
4.64k
  switch (*q) {
2420
3.01k
  case '\0':
2421
4.64k
  case '.':
2422
4.64k
    *oid = q;
2423
4.64k
    *out = (unsigned int)num;
2424
2425
4.64k
    return 0;
2426
2427
0
  default:
2428
0
    fr_strerror_const("Unexpected text after OID component");
2429
0
    *out = 0;
2430
0
    return -1;
2431
4.64k
  }
2432
4.64k
}
2433
2434
/** Get the leaf attribute of an OID string
2435
 *
2436
 * @note On error, vendor will be set (if present), parent will be the
2437
 *  maximum depth we managed to resolve to, and attr will be the child
2438
 *  we failed to resolve.
2439
 *
2440
 * @param[in] dict    of protocol context we're operating in.
2441
 *        If NULL the internal dictionary will be used.
2442
 * @param[out] attr   Number we parsed.
2443
 * @param[in,out] parent  attribute (or root of dictionary).
2444
 *        Will be updated to the parent directly beneath the leaf.
2445
 * @param[in] oid   string to parse.
2446
 * @return
2447
 *  - > 0 on success (number of bytes parsed).
2448
 *  - <= 0 on parse error (negative offset of parse error).
2449
 */
2450
ssize_t fr_dict_attr_by_oid_legacy(fr_dict_t const *dict, fr_dict_attr_t const **parent, unsigned int *attr, char const *oid)
2451
4.64k
{
2452
4.64k
  char const    *p = oid;
2453
4.64k
  unsigned int    num = 0;
2454
4.64k
  ssize_t     slen;
2455
2456
4.64k
  if (!*parent) return -1;
2457
2458
  /*
2459
   *  It's a partial OID.  Grab it, and skip to the next bit.
2460
   */
2461
4.64k
  if (p[0] == '.') {
2462
2.55k
    p++;
2463
2.55k
  }
2464
2465
4.64k
  *attr = 0;
2466
2467
4.64k
  if (fr_dict_oid_component_legacy(&num, &p) < 0) return oid - p;
2468
2469
  /*
2470
   *  Record progress even if we error out.
2471
   *
2472
   *  Don't change this, you will break things.
2473
   */
2474
4.64k
  *attr = num;
2475
2476
  /*
2477
   *  Only a limited number of structural types can have children.  Specifically, groups cannot.
2478
   */
2479
4.64k
  if (!dict_attr_can_have_children(*parent)) {
2480
0
    fr_strerror_printf("Attribute %s (%u) cannot contain a child attribute.  "
2481
0
           "Error at sub OID \"%s\"", (*parent)->name, (*parent)->attr, oid);
2482
0
    return 0; /* We parsed nothing */
2483
0
  }
2484
2485
4.64k
  switch (p[0]) {
2486
  /*
2487
   *  We've not hit the leaf yet, so the attribute must be
2488
   *  defined already.
2489
   */
2490
1.63k
  case '.':
2491
1.63k
  {
2492
1.63k
    fr_dict_attr_t const *child;
2493
1.63k
    p++;
2494
2495
1.63k
    child = dict_attr_child_by_num(*parent, num);
2496
1.63k
    if (!child) {
2497
0
      fr_strerror_printf("Unknown attribute '%u' in OID string \"%s\" for parent %s",
2498
0
             num, oid, (*parent)->name);
2499
0
      return 0; /* We parsed nothing */
2500
0
    }
2501
2502
    /*
2503
     *  Record progress even if we error out.
2504
     *
2505
     *  Don't change this, you will break things.
2506
     */
2507
1.63k
    *parent = child;
2508
2509
1.63k
    slen = fr_dict_attr_by_oid_legacy(dict, parent, attr, p);
2510
1.63k
    if (slen <= 0) return slen - (p - oid);
2511
1.63k
    return slen + (p - oid);
2512
1.63k
  }
2513
2514
  /*
2515
   *  Hit the leaf, this is the attribute we need to define.
2516
   */
2517
3.01k
  case '\0':
2518
3.01k
    *attr = num;
2519
3.01k
    return p - oid;
2520
2521
0
  default:
2522
0
    fr_strerror_printf("Malformed OID string, got trailing garbage '%s'", p);
2523
0
    return oid - p;
2524
4.64k
  }
2525
4.64k
}
2526
2527
/** Parse an OID component, resolving it to a defined attribute
2528
 *
2529
 * @note Will leave the sbuff pointing at the component the error occurred at
2530
 *   so that the caller can attempt to process the component in another way.
2531
 *
2532
 * @param[out] err    The parsing error that occurred.
2533
 * @param[out] out    The deepest attribute we resolved.
2534
 * @param[in] parent    Where to resolve relative attributes from.
2535
 * @param[in] in    string to parse.
2536
 * @param[in] tt    Terminal strings.
2537
 * @return
2538
 *  - >0 the number of bytes consumed.
2539
 *  - <0 Parse error occurred here.
2540
 */
2541
fr_slen_t fr_dict_oid_component(fr_dict_attr_err_t *err,
2542
              fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
2543
              fr_sbuff_t *in, fr_sbuff_term_t const *tt)
2544
11.4k
{
2545
11.4k
  fr_sbuff_t    our_in = FR_SBUFF(in);
2546
11.4k
  uint32_t    num = 0;
2547
11.4k
  fr_sbuff_parse_error_t  sberr;
2548
11.4k
  fr_dict_attr_t const  *child;
2549
2550
11.4k
  if (err) *err = FR_DICT_ATTR_OK;
2551
2552
11.4k
  *out = NULL;
2553
2554
11.4k
  if (!dict_attr_can_have_children(parent)) {
2555
0
    fr_strerror_printf("Attribute '%s' is type %s and cannot contain child attributes.  "
2556
0
           "Error at OID \"%.*s\"",
2557
0
           parent->name,
2558
0
           fr_type_to_str(parent->type),
2559
0
           (int)fr_sbuff_remaining(&our_in),
2560
0
           fr_sbuff_current(&our_in));
2561
0
    if (err) *err =FR_DICT_ATTR_NO_CHILDREN;
2562
0
    FR_SBUFF_ERROR_RETURN(&our_in);
2563
0
  }
2564
2565
11.4k
  fr_sbuff_out(&sberr, &num, &our_in);
2566
11.4k
  switch (sberr) {
2567
  /*
2568
   *  Lookup by number
2569
   */
2570
134
  case FR_SBUFF_PARSE_OK:
2571
134
    if (!fr_sbuff_is_char(&our_in, '.') && !fr_sbuff_is_terminal(&our_in, tt)) {
2572
16
      fr_sbuff_set_to_start(&our_in);
2573
16
      goto oid_str;
2574
16
    }
2575
2576
118
    child = dict_attr_child_by_num(parent, num);
2577
118
    if (!child) {
2578
0
      fr_strerror_printf("Failed resolving child %u in namespace '%s'",
2579
0
             num, parent->name);
2580
0
      if (err) *err = FR_DICT_ATTR_NOTFOUND;
2581
0
      FR_SBUFF_ERROR_RETURN(&our_in);
2582
0
    }
2583
118
    break;
2584
2585
  /*
2586
   *  Lookup by name
2587
   */
2588
11.3k
  case FR_SBUFF_PARSE_ERROR_NOT_FOUND:
2589
11.3k
  case FR_SBUFF_PARSE_ERROR_TRAILING:
2590
11.3k
  {
2591
11.3k
    fr_dict_attr_err_t  our_err;
2592
11.3k
  oid_str:
2593
    /* Sets its own errors, don't override */
2594
11.3k
    if (fr_dict_attr_by_name_substr(&our_err, &child, parent, &our_in, tt) < 0) {
2595
148
      if (err) *err = our_err;
2596
148
      FR_SBUFF_ERROR_RETURN(&our_in);
2597
148
    }
2598
11.3k
  }
2599
11.2k
    break;
2600
2601
11.2k
  default:
2602
0
    fr_strerror_printf("Invalid OID component (%s) \"%.*s\"",
2603
0
           fr_table_str_by_value(sbuff_parse_error_table, sberr, "<INVALID>"),
2604
0
           (int)fr_sbuff_remaining(&our_in), fr_sbuff_current(&our_in));
2605
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
2606
0
    FR_SBUFF_ERROR_RETURN(&our_in);
2607
11.4k
  }
2608
2609
11.3k
  child = dict_attr_alias(err, child);
2610
11.3k
  if (unlikely(!child)) FR_SBUFF_ERROR_RETURN(&our_in);
2611
2612
11.3k
  *out = child;
2613
2614
11.3k
  FR_SBUFF_SET_RETURN(in, &our_in);
2615
11.3k
}
2616
2617
/** Resolve an attribute using an OID string
2618
 *
2619
 * @note Will leave the sbuff pointing at the component the error occurred at
2620
 *   so that the caller can attempt to process the component in another way.
2621
 *   An err pointer should be provided in order to determine if an error
2622
 *   occurred.
2623
 *
2624
 * @param[out] err    The parsing error that occurred.
2625
 * @param[out] out    The deepest attribute we resolved.
2626
 * @param[in] parent    Where to resolve relative attributes from.
2627
 * @param[in] in    string to parse.
2628
 * @param[in] tt    Terminal strings.
2629
 * @return The number of bytes of name consumed.
2630
 */
2631
fr_slen_t fr_dict_attr_by_oid_substr(fr_dict_attr_err_t *err,
2632
             fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
2633
             fr_sbuff_t *in, fr_sbuff_term_t const *tt)
2634
10.5k
{
2635
10.5k
  fr_sbuff_t    our_in = FR_SBUFF(in);
2636
10.5k
  fr_sbuff_marker_t m_c;
2637
10.5k
  fr_dict_attr_t const  *our_parent = parent;
2638
2639
10.5k
  fr_sbuff_marker(&m_c, &our_in);
2640
2641
  /*
2642
   *  If the OID doesn't begin with '.' we
2643
   *  resolve it from the root.
2644
   */
2645
#if 0
2646
  if (!fr_sbuff_next_if_char(&our_in, '.')) our_parent = fr_dict_root(fr_dict_by_da(parent));
2647
#else
2648
10.5k
  (void) fr_sbuff_next_if_char(&our_in, '.');
2649
10.5k
#endif
2650
10.5k
  *out = NULL;
2651
2652
11.4k
  for (;;) {
2653
11.4k
    fr_dict_attr_t const  *child;
2654
2655
11.4k
    if ((fr_dict_oid_component(err, &child, our_parent, &our_in, tt) < 0) || !child) {
2656
148
      *out = our_parent;
2657
148
      fr_sbuff_set(&our_in, &m_c);  /* Reset to the start of the last component */
2658
148
      break;  /* Resolved as much as we can */
2659
148
    }
2660
2661
11.3k
    our_parent = child;
2662
11.3k
    *out = child;
2663
2664
11.3k
    fr_sbuff_set(&m_c, &our_in);
2665
11.3k
    if (!fr_sbuff_next_if_char(&our_in, '.')) break;
2666
11.3k
  }
2667
2668
10.5k
  FR_SBUFF_SET_RETURN(in, &our_in);
2669
10.5k
}
2670
2671
/** Resolve an attribute using an OID string
2672
 *
2673
 * @param[out] err    The parsing error that occurred.
2674
 * @param[in] parent    Where to resolve relative attributes from.
2675
 * @param[in] oid   string to parse.
2676
 * @return
2677
 *  - NULL if we couldn't resolve the attribute.
2678
 *  - The resolved attribute.
2679
 */
2680
fr_dict_attr_t const *fr_dict_attr_by_oid(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *oid)
2681
10.3k
{
2682
10.3k
  fr_sbuff_t    sbuff = FR_SBUFF_IN(oid, strlen(oid));
2683
10.3k
  fr_dict_attr_t const  *da;
2684
2685
10.3k
  if (fr_dict_attr_by_oid_substr(err, &da, parent, &sbuff, NULL) <= 0) return NULL;
2686
10.2k
  if (err && *err != FR_DICT_ATTR_OK) return NULL;
2687
2688
  /*
2689
   *  If we didn't parse the entire string, then the parsing stopped at an unknown child.
2690
   *  e.g. Vendor-Specific.Cisco.Foo.  In that case, the full attribute wasn't found.
2691
   */
2692
10.2k
  if (fr_sbuff_remaining(&sbuff) > 0) {
2693
0
    if (err) *err = FR_DICT_ATTR_NOTFOUND;
2694
0
    return NULL;
2695
0
  }
2696
2697
10.2k
  return da;
2698
10.2k
}
2699
2700
/** Return the root attribute of a dictionary
2701
 *
2702
 * @param dict      to return root for.
2703
 * @return the root attribute of the dictionary.
2704
 *
2705
 * @hidecallergraph
2706
 */
2707
fr_dict_attr_t const *fr_dict_root(fr_dict_t const *dict)
2708
1.71M
{
2709
1.71M
  return dict->root;
2710
1.71M
}
2711
2712
bool fr_dict_is_read_only(fr_dict_t const *dict)
2713
149k
{
2714
149k
  return dict->read_only;
2715
149k
}
2716
2717
dl_t *fr_dict_dl(fr_dict_t const *dict)
2718
0
{
2719
0
  return dict->dl;
2720
0
}
2721
2722
fr_slen_t dict_by_protocol_substr(fr_dict_attr_err_t *err,
2723
          fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
2724
44
{
2725
44
  fr_dict_attr_t    root;
2726
2727
44
  fr_sbuff_t    our_name;
2728
44
  fr_dict_t   *dict;
2729
44
  fr_slen_t   slen;
2730
44
  char      buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1];  /* +1 \0 +1 for "too long" */
2731
2732
44
  if (!dict_gctx || !name || !out) {
2733
0
    if (err) *err = FR_DICT_ATTR_EINVAL;
2734
0
    if (name) FR_SBUFF_ERROR_RETURN(name);
2735
0
    return 0;
2736
0
  }
2737
2738
44
  our_name = FR_SBUFF(name);
2739
44
  memset(&root, 0, sizeof(root));
2740
2741
  /*
2742
   *  Advance p until we get something that's not part of
2743
   *  the dictionary attribute name.
2744
   */
2745
44
  slen = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(buffer, sizeof(buffer)),
2746
44
               &our_name, SIZE_MAX,
2747
44
               fr_dict_attr_allowed_chars);
2748
44
  if (slen == 0) {
2749
0
    fr_strerror_const("Zero length attribute name");
2750
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
2751
0
    FR_SBUFF_ERROR_RETURN(&our_name);
2752
0
  }
2753
44
  if (slen > FR_DICT_ATTR_MAX_NAME_LEN) {
2754
0
    fr_strerror_const("Attribute name too long");
2755
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
2756
0
    FR_SBUFF_ERROR_RETURN(&our_name);
2757
0
  }
2758
2759
  /*
2760
   *  The remaining operations don't generate errors
2761
   */
2762
44
  if (err) *err = FR_DICT_ATTR_OK;
2763
2764
  /*
2765
   *  If what we stopped at wasn't a '.', then there
2766
   *  can't be a protocol name in this string.
2767
   */
2768
44
  if (*(our_name.p) && (*(our_name.p) != '.')) {
2769
0
    memcpy(out, &dict_def, sizeof(*out));
2770
0
    return 0;
2771
0
  }
2772
2773
44
  root.name = buffer;
2774
44
  dict = fr_hash_table_find(dict_gctx->protocol_by_name, &(fr_dict_t){ .root = &root });
2775
2776
44
  if (!dict) {
2777
8
    if (strcasecmp(root.name, "internal") != 0) {
2778
8
      fr_strerror_printf("Unknown protocol '%s'", root.name);
2779
8
      memcpy(out, &dict_def, sizeof(*out));
2780
8
      fr_sbuff_set_to_start(&our_name);
2781
8
      FR_SBUFF_ERROR_RETURN(&our_name);
2782
8
    }
2783
2784
0
    dict = dict_gctx->internal;
2785
0
  }
2786
2787
36
  *out = dict;
2788
2789
36
  FR_SBUFF_SET_RETURN(name, &our_name);
2790
44
}
2791
2792
/** Look up a protocol name embedded in another string
2793
 *
2794
 * @param[out] err    Parsing error.
2795
 * @param[out] out    the resolve dictionary or NULL if the dictionary
2796
 *        couldn't be resolved.
2797
 * @param[in] name    string start.
2798
 * @param[in] dict_def    The dictionary to return if no dictionary qualifier was found.
2799
 * @return
2800
 *  - 0 and *out != NULL.  Couldn't find a dictionary qualifier, so returned dict_def.
2801
 *  - < 0 on error and (*out == NULL) (offset as negative integer)
2802
 *  - > 0 on success (number of bytes parsed).
2803
 */
2804
fr_slen_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err, fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
2805
0
{
2806
0
  return dict_by_protocol_substr(err, UNCONST(fr_dict_t **, out), name, dict_def);
2807
0
}
2808
2809
/** Internal version of #fr_dict_by_protocol_name
2810
 *
2811
 * @note For internal use by the dictionary API only.
2812
 *
2813
 * @copybrief fr_dict_by_protocol_name
2814
 */
2815
fr_dict_t *dict_by_protocol_name(char const *name)
2816
1.04k
{
2817
1.04k
  if (!dict_gctx || !name) return NULL;
2818
2819
1.04k
  return fr_hash_table_find(dict_gctx->protocol_by_name,
2820
1.04k
          &(fr_dict_t){ .root = &(fr_dict_attr_t){ .name = name } });
2821
1.04k
}
2822
2823
/** Internal version of #fr_dict_by_protocol_num
2824
 *
2825
 * @note For internal use by the dictionary API only.
2826
 *
2827
 * @copybrief fr_dict_by_protocol_num
2828
 */
2829
fr_dict_t *dict_by_protocol_num(unsigned int num)
2830
24
{
2831
24
  if (!dict_gctx) return NULL;
2832
2833
24
  return fr_hash_table_find(dict_gctx->protocol_by_num,
2834
24
          &(fr_dict_t) { .root = &(fr_dict_attr_t){ .attr = num } });
2835
24
}
2836
2837
/** Internal version of #fr_dict_by_da
2838
 *
2839
 * @note For internal use by the dictionary API only.
2840
 *
2841
 * @copybrief fr_dict_by_da
2842
 */
2843
fr_dict_t *dict_by_da(fr_dict_attr_t const *da)
2844
41.1k
{
2845
41.1k
#ifndef NDEBUG
2846
41.1k
  {
2847
41.1k
    fr_dict_attr_t const  *da_p = da;
2848
41.1k
    fr_dict_t const   *dict;
2849
2850
41.1k
    dict = da->dict;
2851
56.1k
    while (da_p->parent) {
2852
15.0k
      da_p = da_p->parent;
2853
15.0k
      fr_cond_assert_msg(da_p->dict == dict, "Inconsistent dict membership.  "
2854
15.0k
             "Expected %s, got %s",
2855
15.0k
             !da_p->dict ? "(null)" : fr_dict_root(da_p->dict)->name,
2856
15.0k
             !dict ? "(null)" : fr_dict_root(dict)->name);
2857
15.0k
      DA_VERIFY(da_p);
2858
15.0k
    }
2859
2860
41.1k
    if (!da_p->flags.is_root) {
2861
0
      fr_strerror_printf("%s: Attribute %s has not been inserted into a dictionary",
2862
0
             __FUNCTION__, da->name);
2863
0
      return NULL;
2864
0
    }
2865
41.1k
  }
2866
41.1k
#endif
2867
2868
  /*
2869
   *  Parent of the root attribute must
2870
   *  be the dictionary.
2871
   */
2872
41.1k
  return talloc_get_type_abort(da->dict, fr_dict_t);
2873
41.1k
}
2874
2875
/** Lookup a protocol by its name
2876
 *
2877
 * @note For internal use by the dictionary API only.
2878
 *
2879
 * @param[in] name of the protocol to locate.
2880
 * @return
2881
 *  - Attribute matching name.
2882
 *  - NULL if no matching protocol could be found.
2883
 */
2884
fr_dict_t const *fr_dict_by_protocol_name(char const *name)
2885
0
{
2886
0
  return dict_by_protocol_name(name);
2887
0
}
2888
2889
/** Lookup a protocol by its number
2890
 *
2891
 * Returns the #fr_dict_t belonging to the protocol with the specified number
2892
 * if any have been registered.
2893
 *
2894
 * @param[in] num to search for.
2895
 * @return dictionary representing the protocol (if it exists).
2896
 */
2897
fr_dict_t const *fr_dict_by_protocol_num(unsigned int num)
2898
0
{
2899
0
  return dict_by_protocol_num(num);
2900
0
}
2901
2902
/** Attempt to locate the protocol dictionary containing an attribute
2903
 *
2904
 * @note Unlike fr_dict_by_attr_name, doesn't search through all the dictionaries,
2905
 *  just uses the fr_dict_attr_t hierarchy and the talloc hierarchy to locate
2906
 *  the dictionary (much much faster and more scalable).
2907
 *
2908
 * @param[in] da    To get the containing dictionary for.
2909
 * @return
2910
 *  - The dictionary containing da.
2911
 *  - NULL.
2912
 */
2913
fr_dict_t const *fr_dict_by_da(fr_dict_attr_t const *da)
2914
34.7k
{
2915
34.7k
  return dict_by_da(da);
2916
34.7k
}
2917
2918
/** See if two dictionaries have the same end parent
2919
 *
2920
 * @param[in] dict1 one dictionary
2921
 * @param[in] dict2 two dictionary
2922
 * @return
2923
 *  - true the dictionaries have the same end parent
2924
 *  - false the dictionaries do not have the same end parent.
2925
 */
2926
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
2927
0
{
2928
0
  while (dict1->next) dict1 = dict1->next;
2929
2930
0
  while (dict2->next) dict2 = dict2->next;
2931
2932
0
  return (dict1 == dict2);
2933
0
}
2934
2935
/** Look up a vendor by one of its child attributes
2936
 *
2937
 * @param[in] da  The vendor attribute.
2938
 * @return
2939
 *  - The vendor.
2940
 *  - NULL if no vendor with that number was registered for this protocol.
2941
 */
2942
fr_dict_vendor_t const *fr_dict_vendor_by_da(fr_dict_attr_t const *da)
2943
2.07k
{
2944
2.07k
  fr_dict_t     *dict;
2945
2.07k
  fr_dict_vendor_t  dv;
2946
2947
2.07k
  dv.pen = fr_dict_vendor_num_by_da(da);
2948
2.07k
  if (!dv.pen) return NULL;
2949
2950
1.66k
  dict = dict_by_da(da);
2951
2952
1.66k
  return fr_hash_table_find(dict->vendors_by_num, &dv);
2953
2.07k
}
2954
2955
/** Look up a vendor by its name
2956
 *
2957
 * @param[in] dict    of protocol context we're operating in.
2958
 *        If NULL the internal dictionary will be used.
2959
 * @param[in] name    to search for.
2960
 * @return
2961
 *  - The vendor.
2962
 *  - NULL if no vendor with that name was registered for this protocol.
2963
 */
2964
fr_dict_vendor_t const *fr_dict_vendor_by_name(fr_dict_t const *dict, char const *name)
2965
1.62k
{
2966
1.62k
  fr_dict_vendor_t  *found;
2967
2968
1.62k
  INTERNAL_IF_NULL(dict, NULL);
2969
2970
1.62k
  if (!name) return 0;
2971
2972
1.62k
  found = fr_hash_table_find(dict->vendors_by_name, &(fr_dict_vendor_t) { .name = name });
2973
1.62k
  if (!found) return 0;
2974
2975
1.62k
  return found;
2976
1.62k
}
2977
2978
/** Look up a vendor by its PEN
2979
 *
2980
 * @param[in] dict    of protocol context we're operating in.
2981
 *        If NULL the internal dictionary will be used.
2982
 * @param[in] vendor_pen  to search for.
2983
 * @return
2984
 *  - The vendor.
2985
 *  - NULL if no vendor with that number was registered for this protocol.
2986
 */
2987
fr_dict_vendor_t const *fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen)
2988
21.2k
{
2989
21.2k
  INTERNAL_IF_NULL(dict, NULL);
2990
2991
21.2k
  return fr_hash_table_find(dict->vendors_by_num, &(fr_dict_vendor_t) { .pen = vendor_pen });
2992
21.2k
}
2993
2994
/** Return vendor attribute for the specified dictionary and pen
2995
 *
2996
 * @param[in] vendor_root of the vendor root attribute.  Could be 26 (for example) in RADIUS.
2997
 * @param[in] vendor_pen  to find.
2998
 * @return
2999
 *  - NULL if vendor does not exist.
3000
 *  - A fr_dict_attr_t representing the vendor in the dictionary hierarchy.
3001
 */
3002
fr_dict_attr_t const *fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
3003
0
{
3004
0
  fr_dict_attr_t const *vendor;
3005
3006
0
  switch (vendor_root->type) {
3007
0
  case FR_TYPE_VSA: /* Vendor specific attribute */
3008
0
    break;
3009
3010
0
  default:
3011
0
    fr_strerror_printf("Wrong type for vendor root, expected '%s', got '%s'",
3012
0
           fr_type_to_str(FR_TYPE_VSA),
3013
0
           fr_type_to_str(vendor_root->type));
3014
0
    return NULL;
3015
0
  }
3016
3017
0
  vendor = dict_attr_child_by_num(vendor_root, vendor_pen);
3018
0
  if (!vendor) {
3019
0
    fr_strerror_printf("Vendor %u not defined", vendor_pen);
3020
0
    return NULL;
3021
0
  }
3022
3023
0
  if (vendor->type != FR_TYPE_VENDOR) {
3024
0
    fr_strerror_printf("Wrong type for vendor, expected '%s' got '%s'",
3025
0
           fr_type_to_str(vendor->type),
3026
0
           fr_type_to_str(FR_TYPE_VENDOR));
3027
0
    return NULL;
3028
0
  }
3029
3030
0
  return vendor;
3031
0
}
3032
3033
/** Callback function for resolving dictionary attributes
3034
 *
3035
 * @param[out] err  Where to write error codes.  Any error
3036
 *      other than FR_DICT_ATTR_NOTFOUND will
3037
 *      prevent resolution from continuing.
3038
 * @param[out] out  Where to write resolved DA.
3039
 * @param[in] parent  The dictionary root or other attribute to search from.
3040
 * @param[in] in  Contains the string to resolve.
3041
 * @param[in] tt  Terminal sequences to use to determine the portion
3042
 *      of in to search.
3043
 * @return
3044
 *  - < 0 on failure.
3045
 *  - The number of bytes of name consumed on success.
3046
 */
3047
typedef fr_slen_t (*dict_attr_resolve_func_t)(fr_dict_attr_err_t *err,
3048
                  fr_dict_attr_t const **out, fr_dict_attr_t const *parent,
3049
                  fr_sbuff_t *in, fr_sbuff_term_t const *tt);
3050
3051
/** Internal function for searching for attributes in multiple dictionaries
3052
 *
3053
 * @param[out] err    Any errors that occurred searching.
3054
 * @param[out] out    The attribute we found.
3055
 * @param[in] dict_def    The default dictionary to search in.
3056
 * @param[in] in    string to resolve to an attribute.
3057
 * @param[in] tt    terminals that indicate the end of the string.
3058
 * @param[in] internal    Resolve the attribute in the internal dictionary.
3059
 * @param[in] foreign   Resolve attribute in a foreign dictionary,
3060
 *        i.e. one other than dict_def.
3061
 * @param[in] func    to use for resolution.
3062
 * @return
3063
 *  - <=0 on error (the offset of the error).
3064
 *  - >0 on success.
3065
 */
3066
static inline CC_HINT(always_inline)
3067
fr_slen_t dict_attr_search(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3068
         fr_dict_t const *dict_def,
3069
         fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3070
         bool internal, bool foreign,
3071
         dict_attr_resolve_func_t func)
3072
0
{
3073
0
  fr_dict_attr_err_t  our_err = FR_DICT_ATTR_OK;
3074
0
  fr_hash_iter_t    iter;
3075
0
  fr_dict_t   *dict = NULL;
3076
0
  fr_sbuff_t    our_in = FR_SBUFF(in);
3077
3078
0
  if (internal && !dict_gctx->internal) internal = false;
3079
3080
  /*
3081
   *  Always going to fail...
3082
   */
3083
0
  if (unlikely(!internal && !foreign && !dict_def)) {
3084
0
    if (err) *err = FR_DICT_ATTR_EINVAL;
3085
0
    *out = NULL;
3086
0
    return 0;
3087
0
  }
3088
3089
  /*
3090
   *  dict_def search in the specified dictionary
3091
   */
3092
0
  if (dict_def) {
3093
0
    (void)func(&our_err, out, fr_dict_root(dict_def), &our_in, tt);
3094
0
    switch (our_err) {
3095
0
    case FR_DICT_ATTR_OK:
3096
0
      FR_SBUFF_SET_RETURN(in, &our_in);
3097
3098
0
    case FR_DICT_ATTR_NOTFOUND:
3099
0
      if (!internal && !foreign) goto error;
3100
0
      break;
3101
3102
0
    default:
3103
0
      goto error;
3104
0
    }
3105
0
  }
3106
3107
  /*
3108
   *  Next in the internal dictionary
3109
   */
3110
0
  if (internal) {
3111
0
    (void)func(&our_err, out, fr_dict_root(dict_gctx->internal), &our_in, tt);
3112
0
    switch (our_err) {
3113
0
    case FR_DICT_ATTR_OK:
3114
0
      FR_SBUFF_SET_RETURN(in, &our_in);
3115
3116
0
    case FR_DICT_ATTR_NOTFOUND:
3117
0
      if (!foreign) goto error;
3118
0
      break;
3119
3120
0
    default:
3121
0
      goto error;
3122
0
    }
3123
0
  }
3124
3125
  /*
3126
   *  Now loop over the protocol dictionaries
3127
   */
3128
0
  for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
3129
0
       dict;
3130
0
       dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter)) {
3131
0
    if (dict == dict_def) continue;
3132
0
    if (dict == dict_gctx->internal) continue;
3133
3134
0
    (void)func(&our_err, out, fr_dict_root(dict), &our_in, tt);
3135
0
    switch (our_err) {
3136
0
    case FR_DICT_ATTR_OK:
3137
0
      FR_SBUFF_SET_RETURN(in, &our_in);
3138
3139
0
    case FR_DICT_ATTR_NOTFOUND:
3140
0
      continue;
3141
3142
0
    default:
3143
0
      break;
3144
0
    }
3145
0
  }
3146
3147
0
error:
3148
  /*
3149
   *  Add a more helpful error message about
3150
   *  which dictionaries we tried to locate
3151
   *  the attribute in.
3152
   */
3153
0
  if (our_err == FR_DICT_ATTR_NOTFOUND) {
3154
0
    fr_sbuff_marker_t start;
3155
0
    char      *list = NULL;
3156
3157
0
#define DICT_NAME_APPEND(_in, _dict) \
3158
0
do { \
3159
0
  char *_n; \
3160
0
  _n = talloc_strdup_append_buffer(_in, fr_dict_root(_dict)->name); \
3161
0
  if (unlikely(!_n)) { \
3162
0
    talloc_free(_in); \
3163
0
    goto done; \
3164
0
  } \
3165
0
  _in = _n; \
3166
0
  _n = talloc_strdup_append_buffer(_in, ", "); \
3167
0
  if (unlikely(!_n)) { \
3168
0
    talloc_free(_in); \
3169
0
    goto done; \
3170
0
  } \
3171
0
  _in = _n; \
3172
0
} while (0)
3173
3174
0
    our_in = FR_SBUFF(in);
3175
0
    fr_sbuff_marker(&start, &our_in);
3176
3177
0
    list = talloc_strdup(NULL, "");
3178
0
    if (unlikely(!list)) goto done;
3179
3180
0
    if (dict_def) DICT_NAME_APPEND(list, dict_def);
3181
0
    if (internal) DICT_NAME_APPEND(list, dict_gctx->internal);
3182
3183
0
    if (foreign) {
3184
0
      for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
3185
0
           dict;
3186
0
           dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter)) {
3187
0
        if (dict == dict_def) continue;
3188
0
        if (dict == dict_gctx->internal) continue;
3189
3190
0
        if (internal) DICT_NAME_APPEND(list, dict);
3191
0
      }
3192
0
    }
3193
3194
0
    fr_strerror_printf("Attribute '%pV' not found.  Searched in: %pV",
3195
0
           fr_box_strvalue_len(fr_sbuff_current(&start),
3196
0
                     fr_sbuff_adv_until(&our_in, SIZE_MAX, tt, '\0')),
3197
0
           fr_box_strvalue_len(list, talloc_array_length(list) - 3));
3198
3199
0
    talloc_free(list);
3200
0
  }
3201
3202
0
done:
3203
0
  if (err) *err = our_err;
3204
0
  *out = NULL;
3205
3206
0
  FR_SBUFF_ERROR_RETURN(&our_in);
3207
0
}
3208
3209
/** Internal function for searching for attributes in multiple dictionaries
3210
 *
3211
 * Unlike #dict_attr_search this function searches for a protocol name preceding
3212
 * the attribute identifier.
3213
 */
3214
static inline CC_HINT(always_inline)
3215
fr_slen_t dict_attr_search_qualified(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3216
             fr_dict_t const *dict_def,
3217
             fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3218
             bool internal, bool foreign,
3219
             dict_attr_resolve_func_t func)
3220
0
{
3221
0
  fr_sbuff_t    our_in = FR_SBUFF(in);
3222
0
  fr_dict_attr_err_t  our_err;
3223
0
  fr_dict_t     *initial;
3224
0
  fr_slen_t   slen;
3225
3226
  /*
3227
   *  Check for dictionary prefix
3228
   */
3229
0
  slen = dict_by_protocol_substr(&our_err, &initial, &our_in, dict_def);
3230
0
  if (our_err != FR_DICT_ATTR_OK) {
3231
0
  error:
3232
0
    if (err) *err = our_err;
3233
0
    *out = NULL;
3234
0
    FR_SBUFF_ERROR_RETURN(&our_in);
3235
0
  }
3236
3237
  /*
3238
   *  Has dictionary qualifier, can't fallback
3239
   */
3240
0
  if (slen > 0) {
3241
    /*
3242
     *  Next thing SHOULD be a '.'
3243
     */
3244
0
    if (!fr_sbuff_next_if_char(&our_in, '.')) {
3245
0
      if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
3246
0
      *out = NULL;
3247
0
      FR_SBUFF_ERROR_RETURN(&our_in);
3248
0
    }
3249
3250
0
    internal = foreign = false;
3251
0
  }
3252
3253
0
  if (dict_attr_search(&our_err, out, initial, &our_in, tt, internal, foreign, func) < 0) goto error;
3254
0
  if (err) *err = FR_DICT_ATTR_OK;
3255
3256
0
  FR_SBUFF_SET_RETURN(in, &our_in);
3257
0
}
3258
3259
/** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
3260
 *
3261
 * This function will search through all loaded dictionaries, or a subset of
3262
 * loaded dictionaries, for a matching attribute in the top level namespace.
3263
 *
3264
 * This attribute may be qualified with `<protocol>.` to selection an attribute
3265
 * in a specific case.
3266
 *
3267
 * @note If calling this function from the server any list or request qualifiers
3268
 *  should be stripped first.
3269
 *
3270
 * @param[out] err    Why parsing failed. May be NULL.
3271
 *        @see fr_dict_attr_err_t
3272
 * @param[out] out    Dictionary found attribute.
3273
 * @param[in] dict_def    Default dictionary for non-qualified dictionaries.
3274
 * @param[in] name    Dictionary/Attribute name.
3275
 * @param[in] tt    Terminal strings.
3276
 * @param[in] internal    If true, fallback to the internal dictionary.
3277
 * @param[in] foreign   If true, fallback to foreign dictionaries.
3278
 * @return
3279
 *  - < 0 on failure.
3280
 *  - The number of bytes of name consumed on success.
3281
 */
3282
fr_slen_t fr_dict_attr_search_by_qualified_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3283
                   fr_dict_t const *dict_def,
3284
                   fr_sbuff_t *name, fr_sbuff_term_t const *tt,
3285
                   bool internal, bool foreign)
3286
0
{
3287
0
  return dict_attr_search_qualified(err, out, dict_def, name, tt,
3288
0
            internal, foreign, fr_dict_attr_by_name_substr);
3289
0
}
3290
3291
/** Locate a #fr_dict_attr_t by its name in the top level namespace of a dictionary
3292
 *
3293
 * This function will search through all loaded dictionaries, or a subset of
3294
 * loaded dictionaries, for a matching attribute in the top level namespace.
3295
 *
3296
 * @note If calling this function from the server any list or request qualifiers
3297
 *  should be stripped first.
3298
 *
3299
 * @param[out] err    Why parsing failed. May be NULL.
3300
 *        @see fr_dict_attr_err_t
3301
 * @param[out] out    Dictionary found attribute.
3302
 * @param[in] dict_def    Default dictionary for non-qualified dictionaries.
3303
 * @param[in] name    Dictionary/Attribute name.
3304
 * @param[in] tt    Terminal strings.
3305
 * @param[in] internal    If true, fallback to the internal dictionary.
3306
 * @param[in] foreign   If true, fallback to foreign dictionaries.
3307
 * @return
3308
 *  - < 0 on failure.
3309
 *  - The number of bytes of name consumed on success.
3310
 */
3311
fr_slen_t fr_dict_attr_search_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3312
               fr_dict_t const *dict_def,
3313
               fr_sbuff_t *name, fr_sbuff_term_t const *tt,
3314
               bool internal, bool foreign)
3315
0
{
3316
0
  return dict_attr_search_qualified(err, out, dict_def, name, tt,
3317
0
            internal, foreign, fr_dict_attr_by_name_substr);
3318
0
}
3319
3320
/** Locate a qualified #fr_dict_attr_t by a dictionary qualified OID string
3321
 *
3322
 * This function will search through all loaded dictionaries, or a subset of
3323
 * loaded dictionaries, for a matching attribute.
3324
 *
3325
 * @note If calling this function from the server any list or request qualifiers
3326
 *  should be stripped first.
3327
 *
3328
 * @note err should be checked to determine if a parse error occurred.
3329
 *
3330
 * @param[out] err    Why parsing failed. May be NULL.
3331
 *        @see fr_dict_attr_err_t
3332
 * @param[out] out    Dictionary found attribute.
3333
 * @param[in] dict_def    Default dictionary for non-qualified dictionaries.
3334
 * @param[in] in    Dictionary/Attribute name.
3335
 * @param[in] tt    Terminal strings.
3336
 * @param[in] internal    If true, fallback to the internal dictionary.
3337
 * @param[in] foreign   If true, fallback to foreign dictionaries.
3338
 * @return The number of bytes of name consumed.
3339
 */
3340
fr_slen_t fr_dict_attr_search_by_qualified_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3341
                  fr_dict_t const *dict_def,
3342
                  fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3343
                  bool internal, bool foreign)
3344
0
{
3345
0
  return dict_attr_search_qualified(err, out, dict_def, in, tt,
3346
0
            internal, foreign, fr_dict_attr_by_oid_substr);
3347
0
}
3348
3349
/** Locate a qualified #fr_dict_attr_t by a dictionary using a non-qualified OID string
3350
 *
3351
 * This function will search through all loaded dictionaries, or a subset of
3352
 * loaded dictionaries, for a matching attribute.
3353
 *
3354
 * @note If calling this function from the server any list or request qualifiers
3355
 *  should be stripped first.
3356
 *
3357
 * @note err should be checked to determine if a parse error occurred.
3358
 *
3359
 * @param[out] err    Why parsing failed. May be NULL.
3360
 *        @see fr_dict_attr_err_t
3361
 * @param[out] out    Dictionary found attribute.
3362
 * @param[in] dict_def    Default dictionary for non-qualified dictionaries.
3363
 * @param[in] in    Dictionary/Attribute name.
3364
 * @param[in] tt    Terminal strings.
3365
 * @param[in] internal    If true, fallback to the internal dictionary.
3366
 * @param[in] foreign   If true, fallback to foreign dictionaries.
3367
 * @return The number of bytes of name consumed.
3368
 */
3369
fr_slen_t fr_dict_attr_search_by_oid_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3370
              fr_dict_t const *dict_def,
3371
              fr_sbuff_t *in, fr_sbuff_term_t const *tt,
3372
              bool internal, bool foreign)
3373
0
{
3374
0
  return dict_attr_search_qualified(err, out, dict_def, in, tt,
3375
0
            internal, foreign, fr_dict_attr_by_oid_substr);
3376
0
}
3377
3378
/** Locate a qualified #fr_dict_attr_t by its name and a dictionary qualifier
3379
 *
3380
 * @param[out] err    Why parsing failed. May be NULL.
3381
 *        @see fr_dict_attr_err_t.
3382
 * @param[in] dict_def    Default dictionary for non-qualified dictionaries.
3383
 * @param[in] name    Dictionary/Attribute name.
3384
 * @param[in] internal    If true, fallback to the internal dictionary.
3385
 * @param[in] foreign   If true, fallback to foreign dictionaries.
3386
 * @return an #fr_dict_attr_err_t value.
3387
 */
3388
fr_dict_attr_t const *fr_dict_attr_search_by_qualified_oid(fr_dict_attr_err_t *err, fr_dict_t const *dict_def,
3389
                 char const *name,
3390
                 bool internal, bool foreign)
3391
0
{
3392
0
  ssize_t     slen;
3393
0
  fr_sbuff_t    our_name;
3394
0
  fr_dict_attr_t const  *da;
3395
0
  fr_dict_attr_err_t  our_err;
3396
3397
0
  fr_sbuff_init_in(&our_name, name, strlen(name));
3398
3399
0
  slen = fr_dict_attr_search_by_qualified_oid_substr(&our_err, &da, dict_def, &our_name, NULL, internal, foreign);
3400
0
  if (our_err != FR_DICT_ATTR_OK) {
3401
0
    if (err) *err = our_err;
3402
0
    return NULL;
3403
0
  }
3404
0
  if ((size_t)slen != fr_sbuff_len(&our_name)) {
3405
0
    fr_strerror_printf("Trailing garbage after attr string \"%s\"", name);
3406
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
3407
0
    return NULL;
3408
0
  }
3409
3410
0
  return da;
3411
0
}
3412
3413
/** Look up a dictionary attribute by a name embedded in another string
3414
 *
3415
 * Find the first invalid attribute name char in the string pointed
3416
 * to by name.
3417
 *
3418
 * Copy the characters between the start of the name string and the first
3419
 * none #fr_dict_attr_allowed_chars char to a buffer and perform a dictionary lookup
3420
 * using that value.
3421
 *
3422
 * If the attribute exists, advance the pointer pointed to by name
3423
 * to the first none #fr_dict_attr_allowed_chars char, and return the DA.
3424
 *
3425
 * If the attribute does not exist, don't advance the pointer and return
3426
 * NULL.
3427
 *
3428
 * @param[out] err    Why parsing failed. May be NULL.
3429
 *        @see fr_dict_attr_err_t
3430
 * @param[out] out    Where to store the resolve attribute.
3431
 * @param[in] parent    containing the namespace to search in.
3432
 * @param[in] name    string start.
3433
 * @param[in] tt    Terminal sequences to use to determine the portion
3434
 *        of in to search.
3435
 * @return
3436
 *  - <= 0 on failure.
3437
 *  - The number of bytes of name consumed on success.
3438
 */
3439
fr_slen_t fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
3440
              fr_dict_attr_t const *parent, fr_sbuff_t *name, UNUSED fr_sbuff_term_t const *tt)
3441
11.3k
{
3442
11.3k
  fr_dict_attr_t const  *da;
3443
11.3k
  size_t      len;
3444
11.3k
  fr_dict_attr_t const  *ref;
3445
11.3k
  char const    *p;
3446
11.3k
  char      buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1 + 1];  /* +1 \0 +1 for "too long" */
3447
11.3k
  fr_sbuff_t    our_name = FR_SBUFF(name);
3448
11.3k
  fr_hash_table_t   *namespace;
3449
3450
11.3k
  *out = NULL;
3451
3452
#ifdef STATIC_ANALYZER
3453
  memset(buffer, 0, sizeof(buffer));
3454
#endif
3455
3456
11.3k
  len = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(buffer, sizeof(buffer)),
3457
11.3k
              &our_name, SIZE_MAX,
3458
11.3k
              fr_dict_attr_allowed_chars);
3459
11.3k
  if (len == 0) {
3460
0
    fr_strerror_const("Zero length attribute name");
3461
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
3462
0
    FR_SBUFF_ERROR_RETURN(&our_name);
3463
0
  }
3464
11.3k
  if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
3465
0
    fr_strerror_const("Attribute name too long");
3466
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
3467
0
    FR_SBUFF_ERROR_RETURN(&our_name);
3468
0
  }
3469
3470
  /*
3471
   *  Do a second pass, ensuring that the name has at least one alphanumeric character.
3472
   */
3473
11.3k
  for (p = buffer; p < (buffer + len); p++) {
3474
11.3k
    if (sbuff_char_alpha_num[(uint8_t) *p]) break;
3475
11.3k
  }
3476
3477
11.3k
  if ((size_t) (p - buffer) == len) {
3478
0
    fr_strerror_const("Invalid attribute name");
3479
0
    if (err) *err = FR_DICT_ATTR_PARSE_ERROR;
3480
0
    FR_SBUFF_ERROR_RETURN(&our_name);
3481
0
  }
3482
3483
11.3k
  ref = fr_dict_attr_ref(parent);
3484
11.3k
  if (ref) parent = ref;
3485
3486
11.3k
redo:
3487
11.3k
  namespace = dict_attr_namespace(parent);
3488
11.3k
  if (!namespace) {
3489
0
    fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
3490
0
    if (err) *err = FR_DICT_ATTR_NO_CHILDREN;
3491
0
    fr_sbuff_set_to_start(&our_name);
3492
0
    FR_SBUFF_ERROR_RETURN(&our_name);
3493
0
  }
3494
3495
11.3k
  da = fr_hash_table_find(namespace, &(fr_dict_attr_t){ .name = buffer });
3496
11.3k
  if (!da) {
3497
148
    if (parent->flags.is_root) {
3498
148
      fr_dict_t const *dict = fr_dict_by_da(parent);
3499
3500
148
      if (dict->next) {
3501
0
        parent = dict->next->root;
3502
0
        goto redo;
3503
0
      }
3504
148
    }
3505
3506
148
    if (err) *err = FR_DICT_ATTR_NOTFOUND;
3507
148
    fr_strerror_printf("Attribute '%s' not found in namespace '%s'", buffer, parent->name);
3508
148
    fr_sbuff_set_to_start(&our_name);
3509
148
    FR_SBUFF_ERROR_RETURN(&our_name);
3510
148
  }
3511
3512
11.2k
  da = dict_attr_alias(err, da);
3513
11.2k
  if (unlikely(!da)) FR_SBUFF_ERROR_RETURN(&our_name);
3514
3515
11.2k
  *out = da;
3516
11.2k
  if (err) *err = FR_DICT_ATTR_OK;
3517
3518
11.2k
  FR_SBUFF_SET_RETURN(name, &our_name);
3519
11.2k
}
3520
3521
/* Internal version of fr_dict_attr_by_name
3522
 *
3523
 */
3524
fr_dict_attr_t *dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
3525
163k
{
3526
163k
  fr_hash_table_t   *namespace;
3527
163k
  fr_dict_attr_t    *da;
3528
3529
163k
  DA_VERIFY(parent);
3530
3531
163k
redo:
3532
163k
  namespace = dict_attr_namespace(parent);
3533
163k
  if (!namespace) {
3534
0
    fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
3535
0
    if (err) *err = FR_DICT_ATTR_NO_CHILDREN;
3536
0
    return NULL;
3537
0
  }
3538
3539
163k
  da = fr_hash_table_find(namespace, &(fr_dict_attr_t) { .name = name });
3540
163k
  if (!da) {
3541
105k
    if (parent->flags.is_root) {
3542
32.5k
      fr_dict_t const *dict = fr_dict_by_da(parent);
3543
3544
32.5k
      if (dict->next) {
3545
0
        parent = dict->next->root;
3546
0
        goto redo;
3547
0
      }
3548
32.5k
    }
3549
3550
105k
    if (err) *err = FR_DICT_ATTR_NOTFOUND;
3551
105k
    fr_strerror_printf("Attribute '%s' not found in namespace '%s'", name, parent->name);
3552
105k
    return NULL;
3553
105k
  }
3554
3555
58.2k
  if (err) *err = FR_DICT_ATTR_OK;
3556
3557
58.2k
  return da;
3558
163k
}
3559
3560
/** Locate a #fr_dict_attr_t by its name
3561
 *
3562
 * @param[out] err    Why the lookup failed. May be NULL.
3563
 *        @see fr_dict_attr_err_t.
3564
 * @param[in] parent    containing the namespace we're searching in.
3565
 * @param[in] name    of the attribute to locate.
3566
 * @return
3567
 *  - Attribute matching name.
3568
 *  - NULL if no matching attribute could be found.
3569
 */
3570
fr_dict_attr_t const *fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *name)
3571
114k
{
3572
114k
  fr_dict_attr_t const *da;
3573
3574
114k
  DA_VERIFY(parent);
3575
3576
114k
  da = dict_attr_by_name(err, parent, name);
3577
114k
  if (!da) return NULL;
3578
3579
10.7k
  da = dict_attr_alias(err, da);
3580
10.7k
  if (unlikely(!da)) return NULL;
3581
3582
10.7k
  return da;
3583
10.7k
}
3584
3585
/** Internal version of fr_dict_attr_child_by_num
3586
 *
3587
 */
3588
fr_dict_attr_t *dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
3589
4.81M
{
3590
4.81M
  fr_dict_attr_t const *bin;
3591
4.81M
  fr_dict_attr_t const **children;
3592
4.81M
  fr_dict_attr_t const *ref;
3593
3594
4.81M
  DA_VERIFY(parent);
3595
3596
  /*
3597
   *  Do any necessary dereferencing
3598
   */
3599
4.81M
  ref = fr_dict_attr_ref(parent);
3600
4.81M
  if (ref) parent = ref;
3601
3602
4.81M
  children = dict_attr_children(parent);
3603
4.81M
  if (!children) return NULL;
3604
3605
  /*
3606
   *  Child arrays may be trimmed back to save memory.
3607
   *  Check that so we don't SEGV.
3608
   */
3609
4.79M
  if ((attr & 0xff) > talloc_array_length(children)) return NULL;
3610
3611
4.79M
  bin = children[attr & 0xff];
3612
5.03M
  for (;;) {
3613
5.03M
    if (!bin) return NULL;
3614
1.28M
    if (bin->attr == attr) {
3615
1.03M
      fr_dict_attr_t *out;
3616
3617
1.03M
      memcpy(&out, &bin, sizeof(bin));
3618
3619
1.03M
      return out;
3620
1.03M
    }
3621
241k
    bin = bin->next;
3622
241k
  }
3623
3624
0
  return NULL;
3625
4.79M
}
3626
3627
/** Check if a child attribute exists in a parent using an attribute number
3628
 *
3629
 * @param[in] parent    to check for child in.
3630
 * @param[in] attr    number to look for.
3631
 * @return
3632
 *  - The child attribute on success.
3633
 *  - NULL if the child attribute does not exist.
3634
 */
3635
fr_dict_attr_t const *fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
3636
4.75M
{
3637
4.75M
  fr_dict_attr_t const *da;
3638
3639
4.75M
  da = dict_attr_child_by_num(parent, attr);
3640
4.75M
  if (!da) return NULL;
3641
3642
987k
  da = dict_attr_alias(NULL, da);
3643
987k
  if (unlikely(!da)) return NULL;
3644
3645
987k
  return da;
3646
987k
}
3647
3648
/** Iterate over all enumeration values for an attribute
3649
 *
3650
 * @param[in] da    to iterate over.
3651
 * @param[in] iter    to use for iteration.
3652
 * @return
3653
 *  - First #fr_dict_enum_value_t in the attribute.
3654
 *  - NULL if no enumeration values exist.
3655
 */
3656
fr_dict_enum_value_t const *fr_dict_enum_iter_init(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
3657
0
{
3658
0
  fr_dict_attr_ext_enumv_t  *ext;
3659
3660
0
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
3661
0
  if (!ext) {
3662
0
    fr_strerror_printf("%s has no enumeration values to iterate over", da->name);
3663
0
    return NULL;
3664
0
  }
3665
3666
0
  return fr_hash_table_iter_init(ext->value_by_name, iter);
3667
0
}
3668
3669
/* Iterate over next enumeration value for an attribute
3670
 *
3671
 * @param[in] da    to iterate over.
3672
 * @param[in] iter    to use for iteration.
3673
 * @return
3674
 *  - Next #fr_dict_enum_value_t in the attribute.
3675
 *  - NULL if no more enumeration values exist.
3676
 */
3677
fr_dict_enum_value_t const *fr_dict_enum_iter_next(fr_dict_attr_t const *da, fr_dict_enum_iter_t *iter)
3678
0
{
3679
0
  fr_dict_attr_ext_enumv_t  *ext;
3680
0
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
3681
0
  if (!ext) {
3682
0
    fr_strerror_printf("%s has no enumeration values to iterate over", da->name);
3683
0
    return NULL;
3684
0
  }
3685
3686
0
  return fr_hash_table_iter_next(ext->value_by_name, iter);;
3687
0
}
3688
3689
/** Lookup the structure representing an enum value in a #fr_dict_attr_t
3690
 *
3691
 * @param[in] da    to search in.
3692
 * @param[in] value   to search for.
3693
 * @return
3694
 *  - Matching #fr_dict_enum_value_t.
3695
 *  - NULL if no matching #fr_dict_enum_value_t could be found.
3696
 */
3697
fr_dict_enum_value_t const *fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
3698
17.7k
{
3699
17.7k
  fr_dict_attr_ext_enumv_t  *ext;
3700
3701
17.7k
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
3702
17.7k
  if (!ext) {
3703
0
    fr_strerror_printf("VALUE cannot be defined for %s attributes",
3704
0
           fr_type_to_str(da->type));
3705
0
    return NULL;
3706
0
  }
3707
3708
  /*
3709
   *  No values associated with this attribute
3710
   */
3711
17.7k
  if (!ext->name_by_value) return NULL;
3712
3713
  /*
3714
   *  Could be NULL or an unknown attribute, in which case
3715
   *  we want to avoid the lookup gracefully...
3716
   */
3717
17.7k
  if (value->type != da->type) return NULL;
3718
3719
17.7k
  return fr_hash_table_find(ext->name_by_value, &(fr_dict_enum_value_t){ .value = value });
3720
17.7k
}
3721
3722
/** Lookup the name of an enum value in a #fr_dict_attr_t
3723
 *
3724
 * @param[in] da    to search in.
3725
 * @param[in] value   number to search for.
3726
 * @return
3727
 *  - Name of value.
3728
 *  - NULL if no matching value could be found.
3729
 */
3730
char const *fr_dict_enum_name_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
3731
0
{
3732
0
  fr_dict_enum_value_t const *dv;
3733
3734
0
  dv = fr_dict_enum_by_value(da, value);
3735
0
  if (!dv) return NULL;
3736
3737
0
  return dv->name;
3738
0
}
3739
3740
/*
3741
 *  Get a value by its name, keyed off of an attribute.
3742
 */
3743
fr_dict_enum_value_t const *fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
3744
455
{
3745
455
  fr_dict_attr_ext_enumv_t  *ext;
3746
3747
455
  if (!name) return NULL;
3748
3749
455
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
3750
455
  if (!ext) {
3751
0
    fr_strerror_printf("VALUE cannot be defined for %s attributes",
3752
0
           fr_type_to_str(da->type));
3753
0
    return NULL;
3754
0
  }
3755
3756
  /*
3757
   *  No values associated with this attribute
3758
   */
3759
455
  if (!ext->value_by_name) return NULL;
3760
3761
455
  if (len < 0) len = strlen(name);
3762
3763
455
  return fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = name, .name_len = len});
3764
455
}
3765
3766
/*
3767
 *  Get a value by its name, keyed off of an attribute, from an sbuff
3768
 */
3769
fr_slen_t fr_dict_enum_by_name_substr(fr_dict_enum_value_t **out, fr_dict_attr_t const *da, fr_sbuff_t *in)
3770
0
{
3771
0
  fr_dict_attr_ext_enumv_t  *ext;
3772
0
  fr_sbuff_t  our_in = FR_SBUFF(in);
3773
0
  fr_dict_enum_value_t *found = NULL;
3774
0
  size_t    found_len = 0;
3775
0
  uint8_t   *p;
3776
0
  uint8_t   name[FR_DICT_ENUM_MAX_NAME_LEN + 1];
3777
3778
  /*
3779
   *  No values associated with this attribute, do nothing.
3780
   */
3781
0
  ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_ENUMV);
3782
0
  if (!ext || !ext->value_by_name) return 0;
3783
3784
  /*
3785
   *  Loop until we exhaust all of the possibilities.
3786
   */
3787
0
  for (p = name; (size_t) (p - name) < ext->max_name_len; p++) {
3788
0
    int len = (p - name) + 1;
3789
0
    fr_dict_enum_value_t *enumv;
3790
3791
0
    *p = fr_sbuff_char(&our_in, '\0');
3792
0
    if (!fr_dict_enum_allowed_chars[*p]) {
3793
0
      break;
3794
0
    }
3795
0
    fr_sbuff_next(&our_in);
3796
3797
0
    enumv = fr_hash_table_find(ext->value_by_name, &(fr_dict_enum_value_t){ .name = (char const *) name,
3798
0
                      .name_len = len});
3799
3800
    /*
3801
     *  Return the LONGEST match, as there may be
3802
     *  overlaps.  e.g. "Framed", and "Framed-User".
3803
     */
3804
0
    if (enumv) {
3805
0
      found = enumv;
3806
0
      found_len = len;
3807
0
    }
3808
0
  }
3809
3810
0
  if (found) {
3811
0
    *out = found;
3812
0
    FR_SBUFF_SET_RETURN(in, found_len);
3813
0
  }
3814
3815
0
  return 0;
3816
0
}
3817
3818
/** Extract an enumeration name from a string
3819
 *
3820
 * This function defines the canonical format for an enumeration name.
3821
 *
3822
 * An enumeration name is made up of one or more fr_dict_attr_allowed_chars
3823
 * with at least one character in the sequence not being a special character
3824
 * i.e. [-+/_] or a number.
3825
 *
3826
 * This disambiguates enumeration identifiers from mathematical expressions.
3827
 *
3828
 * If we allowed enumeration names consisting of sequences of numbers separated
3829
 * by special characters it would not be possible to determine if the special
3830
 * character were an operator in a subexpression.
3831
 *
3832
 * For example take:
3833
 *
3834
 *    &My-Enum-Attr == 01234-5678
3835
 *
3836
 * Without having access to the enumeration values of My-Enum-Attr (which we
3837
 * might not have during tokenisation), we cannot tell if this is:
3838
 *
3839
 * (&My-Enum-Attr == 01234-5678)
3840
 *
3841
 * OR
3842
 *
3843
 * ((&My-Enum-Attr == 01234) - 5678)
3844
 *
3845
 * If an alpha character occurs anywhere in the string i.e:
3846
 *
3847
 *    (&My-Enum-Attr == 01234-A5678)
3848
 *
3849
 * we know 01234-A5678 can't be a mathematical sub-expression because the
3850
 * second potential operand can no longer be parsed as an integer constant.
3851
 *
3852
 * @param[out] out  The name string we managed to extract.
3853
 *      May be NULL in which case only the length of the name
3854
 *      will be returned.
3855
 * @param[out] err  Type of parsing error which occurred.  May be NULL.
3856
 * @param[in] in  The string containing the enum identifier.
3857
 * @param[in] tt  If non-null verify that a terminal sequence occurs
3858
 *      after the enumeration name.
3859
 * @return
3860
 *  - <0 the offset at which the parse error occurred.
3861
 *  - >1 the number of bytes parsed.
3862
 */
3863
fr_slen_t fr_dict_enum_name_from_substr(fr_sbuff_t *out, fr_sbuff_parse_error_t *err,
3864
          fr_sbuff_t *in, fr_sbuff_term_t const *tt)
3865
36.8k
{
3866
36.8k
  fr_sbuff_t our_in = FR_SBUFF(in);
3867
36.8k
  bool seen_alpha = false;
3868
3869
511k
  while (fr_sbuff_is_in_charset(&our_in, fr_dict_enum_allowed_chars)) {
3870
474k
    if (fr_sbuff_is_alpha(&our_in)) seen_alpha = true;
3871
474k
    fr_sbuff_next(&our_in);
3872
474k
  }
3873
3874
36.8k
  if (!seen_alpha) {
3875
0
    if (fr_sbuff_used(&our_in) == 0) {
3876
0
      fr_strerror_const("VALUE name is empty");
3877
0
      if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND;
3878
0
      FR_SBUFF_ERROR_RETURN(&our_in);
3879
0
    }
3880
3881
0
    fr_strerror_const("VALUE name must contain at least one alpha character");
3882
0
    if (err) *err = FR_SBUFF_PARSE_ERROR_FORMAT;
3883
0
    fr_sbuff_set_to_start(&our_in); /* Marker should be at the start of the enum */
3884
0
    FR_SBUFF_ERROR_RETURN(&our_in);
3885
0
  }
3886
3887
  /*
3888
   *  Check that the sequence is correctly terminated
3889
   */
3890
36.8k
  if (tt && !fr_sbuff_is_terminal(&our_in, tt)) {
3891
0
    fr_strerror_const("VALUE name has trailing text");
3892
0
    if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING;
3893
0
    FR_SBUFF_ERROR_RETURN(&our_in);
3894
0
  }
3895
3896
36.8k
  if (out) return fr_sbuff_out_bstrncpy_exact(out, in, fr_sbuff_used(&our_in));
3897
3898
36.8k
  if (err) *err = FR_SBUFF_PARSE_OK;
3899
3900
36.8k
  FR_SBUFF_SET_RETURN(in, &our_in);
3901
36.8k
}
3902
3903
int dict_dlopen(fr_dict_t *dict, char const *name)
3904
46
{
3905
46
  char      *lib_name;
3906
46
  char      *sym_name;
3907
46
  fr_dict_protocol_t  *proto;
3908
3909
46
  if (!name) return 0;
3910
3911
46
  lib_name = talloc_typed_asprintf(NULL, "libfreeradius-%s", name);
3912
46
  if (unlikely(lib_name == NULL)) {
3913
0
  oom:
3914
0
    fr_strerror_const("Out of memory");
3915
0
    return -1;
3916
0
  }
3917
46
  talloc_bstr_tolower(lib_name);
3918
3919
46
  dict->dl = dl_by_name(dict_gctx->dict_loader, lib_name, NULL, false);
3920
46
  if (!dict->dl) {
3921
0
    fr_strerror_printf_push("Failed loading dictionary validation library \"%s\"", lib_name);
3922
0
    talloc_free(lib_name);
3923
0
    return -1;
3924
0
  }
3925
46
  talloc_free(lib_name);
3926
3927
  /*
3928
   *  The public symbol that contains per-protocol rules
3929
   *  and extensions.
3930
   *
3931
   *  It ends up being easier to do this using dlsym to
3932
   *  resolve the symbol and not use the autoloader
3933
   *  callbacks as theoretically multiple dictionaries
3934
   *  could use the same protocol library, and then the
3935
   *  autoloader callback would only run for the first
3936
   *  dictionary which loaded the protocol.
3937
   */
3938
46
  sym_name = talloc_typed_asprintf(NULL, "libfreeradius_%s_dict_protocol", name);
3939
46
  if (unlikely(sym_name == NULL)) {
3940
0
    talloc_free(lib_name);
3941
0
    goto oom;
3942
0
  }
3943
46
  talloc_bstr_tolower(sym_name);
3944
3945
  /*
3946
   *  De-hyphenate the symbol name
3947
   */
3948
46
  {
3949
46
    char *p, *q;
3950
3951
1.63k
    for (p = sym_name, q = p + (talloc_array_length(sym_name) - 1); p < q; p++) *p = *p == '-' ? '_' : *p;
3952
46
  }
3953
3954
46
  proto = dlsym(dict->dl->handle, sym_name);
3955
46
  talloc_free(sym_name);
3956
3957
  /*
3958
   *  Soft failure, not all protocol libraires provide
3959
   *  custom validation functions or flats.
3960
   */
3961
46
  if (!proto) return 0;
3962
3963
  /*
3964
   *  Replace the default protocol with the custom one
3965
   *  if we have it...
3966
   */
3967
22
  dict->proto = proto;
3968
3969
22
  return 0;
3970
46
}
3971
3972
/** Find a dependent in the tree of dependents
3973
 *
3974
 */
3975
static int8_t _dict_dependent_cmp(void const *a, void const *b)
3976
6.97k
{
3977
6.97k
  fr_dict_dependent_t const *dep_a = a;
3978
6.97k
  fr_dict_dependent_t const *dep_b = b;
3979
6.97k
  int ret;
3980
3981
6.97k
  ret = strcmp(dep_a->dependent, dep_b->dependent);
3982
6.97k
  return CMP(ret, 0);
3983
6.97k
}
3984
3985
/** Record a new dependency on a dictionary
3986
 *
3987
 * These are used to determine what is currently depending on a dictionary.
3988
 *
3989
 * @param[in] dict  to record dependency on.
3990
 * @param[in] dependent Either C src file, or another dictionary.
3991
 * @return
3992
 *  - 0 on success.
3993
 *      - -1 on failure.
3994
 */
3995
int dict_dependent_add(fr_dict_t *dict, char const *dependent)
3996
1.04k
{
3997
1.04k
  fr_dict_dependent_t *found;
3998
3999
1.04k
  found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
4000
1.04k
  if (!found) {
4001
1.04k
    fr_dict_dependent_t *new;
4002
4003
1.04k
    new = talloc_zero(dict->dependents, fr_dict_dependent_t);
4004
1.04k
    if (unlikely(!new)) return -1;
4005
4006
    /*
4007
     *  If the dependent is in a module that gets
4008
     *  unloaded, any strings in the text area also
4009
     *  get unloaded (including dependent locations).
4010
     *
4011
     *  Strdup the string here so we don't get
4012
     *  random segfaults if a module forgets to unload
4013
     *  a dictionary.
4014
     */
4015
1.04k
    new->dependent = talloc_typed_strdup(new, dependent);
4016
1.04k
    fr_rb_insert(dict->dependents, new);
4017
4018
1.04k
    new->count = 1;
4019
4020
1.04k
    return 0;
4021
1.04k
  }
4022
4023
0
  found->count++; /* Increase ref count */
4024
4025
0
  return 0;
4026
1.04k
}
4027
4028
/** Manually increase the reference count for a dictionary
4029
 *
4030
 * This is useful if a previously loaded dictionary needs to
4031
 * be bound to the lifetime of an additional object.
4032
 *
4033
 * @param[in] dict  to increase the reference count for.
4034
 * @param[in] dependent requesting the loading of the dictionary.
4035
 * @return
4036
 *  - 0 on success.
4037
 *  - -1 on error.
4038
 */
4039
int fr_dict_dependent_add(fr_dict_t const *dict, char const *dependent)
4040
0
{
4041
0
  fr_dict_t *m_dict = fr_dict_unconst(dict);
4042
4043
0
  if (unlikely(!m_dict)) return -1;
4044
4045
0
  return dict_dependent_add(m_dict, dependent);
4046
0
}
4047
4048
/** Decrement ref count for a dependent in a dictionary
4049
 *
4050
 * @param[in] dict  to remove dependency from.
4051
 * @param[in] dependent Either C src, or another dictionary dependent.
4052
 *      What depends on this dictionary.
4053
 */
4054
int dict_dependent_remove(fr_dict_t *dict, char const *dependent)
4055
1.04k
{
4056
1.04k
  fr_dict_dependent_t *found;
4057
4058
1.04k
  found = fr_rb_find(dict->dependents, &(fr_dict_dependent_t){ .dependent = dependent } );
4059
1.04k
  if (!found) {
4060
0
    fr_strerror_printf("Dependent \"%s\" not found in dictionary \"%s\"", dependent, dict->root->name);
4061
0
    return -1;
4062
0
  }
4063
4064
1.04k
  if (found->count == 0) {
4065
0
    fr_strerror_printf("Zero ref count invalid for dependent \"%s\", dictionary \"%s\"",
4066
0
           dependent, dict->root->name);
4067
0
    return -1;
4068
0
  }
4069
4070
1.04k
  if (--found->count == 0) {
4071
1.04k
    fr_rb_delete(dict->dependents, found);
4072
1.04k
    talloc_free(found);
4073
1.04k
    return 0;
4074
1.04k
  }
4075
4076
0
  return 1;
4077
1.04k
}
4078
4079
/** Check if a dictionary still has dependents
4080
 *
4081
 * @param[in] dict  to check
4082
 * @return
4083
 *  - true if there's still at least one dependent.
4084
 *  - false if there are no dependents.
4085
 */
4086
bool dict_has_dependents(fr_dict_t *dict)
4087
6.00k
{
4088
6.00k
  return (fr_rb_num_elements(dict->dependents) > 0);
4089
6.00k
}
4090
4091
#ifndef NDEBUG
4092
static void dependent_debug(fr_dict_t *dict)
4093
0
{
4094
0
  fr_rb_iter_inorder_t  iter;
4095
0
  fr_dict_dependent_t *dep;
4096
0
4097
0
  if (!dict_has_dependents(dict)) return;
4098
0
4099
0
  fprintf(stderr, "DEPENDENTS FOR %s\n", dict->root->name);
4100
0
4101
0
  for (dep = fr_rb_iter_init_inorder(&iter, dict->dependents);
4102
0
       dep;
4103
0
       dep = fr_rb_iter_next_inorder(&iter)) {
4104
0
    fprintf(stderr, "\t<- %s (%d)\n", dep->dependent, dep->count);
4105
0
  }
4106
0
}
4107
#endif
4108
4109
4110
static int dict_autoref_free(fr_dict_t *dict)
4111
24
{
4112
24
  fr_dict_t **refd_list;
4113
24
  unsigned int i;
4114
4115
24
  if (!dict->autoref) return 0;
4116
4117
24
  if (fr_hash_table_flatten(dict->autoref, (void ***)&refd_list, dict->autoref) < 0) {
4118
0
    fr_strerror_const("failed flattening autoref hash table");
4119
0
    return -1;
4120
0
  }
4121
4122
  /*
4123
   *  Free the dictionary.  It will call proto->free() if there's nothing more to do.
4124
   */
4125
32
  for (i = 0; i < talloc_array_length(refd_list); i++) {
4126
8
    if (fr_dict_free(&refd_list[i], dict->root->name) < 0) {
4127
0
      fr_strerror_printf("failed freeing autoloaded protocol %s", refd_list[i]->root->name);
4128
0
      return -1;
4129
0
    }
4130
8
  }
4131
4132
24
  TALLOC_FREE(dict->autoref);
4133
4134
24
  return 0;
4135
24
}
4136
4137
static int _dict_free(fr_dict_t *dict)
4138
5.01k
{
4139
  /*
4140
   *  We don't necessarily control the order of freeing
4141
   *  children.
4142
   */
4143
5.01k
  if (dict != dict->gctx->internal) {
4144
24
    fr_dict_attr_t const *da;
4145
4146
24
    if (dict->gctx->attr_protocol_encapsulation && dict->root) {
4147
24
      da = fr_dict_attr_child_by_num(dict->gctx->attr_protocol_encapsulation, dict->root->attr);
4148
24
      if (da && fr_dict_attr_ref(da)) dict_attr_ref_null(da);
4149
24
    }
4150
24
  }
4151
4152
#ifdef STATIC_ANALYZER
4153
  if (!dict->root) {
4154
    fr_strerror_const("dict root is missing");
4155
    return -1;
4156
  }
4157
#endif
4158
4159
  /*
4160
   *  If we called init(), then call free()
4161
   */
4162
5.01k
  if (dict->proto && dict->proto->free) {
4163
22
    dict->proto->free();
4164
22
  }
4165
4166
5.01k
  if (!fr_cond_assert(!dict->in_protocol_by_name || fr_hash_table_delete(dict->gctx->protocol_by_name, dict))) {
4167
0
    fr_strerror_printf("Failed removing dictionary from protocol hash \"%s\"", dict->root->name);
4168
0
    return -1;
4169
0
  }
4170
5.01k
  dict->in_protocol_by_name = false;
4171
4172
5.01k
  if (!fr_cond_assert(!dict->in_protocol_by_num || fr_hash_table_delete(dict->gctx->protocol_by_num, dict))) {
4173
0
    fr_strerror_printf("Failed removing dictionary from protocol number_hash \"%s\"", dict->root->name);
4174
0
    return -1;
4175
0
  }
4176
5.01k
  dict->in_protocol_by_num = false;
4177
4178
5.01k
  if (dict_has_dependents(dict)) {
4179
4.96k
    fr_rb_iter_inorder_t  iter;
4180
4.96k
    fr_dict_dependent_t *dep;
4181
4182
4.96k
    fr_strerror_printf("Refusing to free dictionary \"%s\", still has dependents", dict->root->name);
4183
4184
4.96k
    for (dep = fr_rb_iter_init_inorder(&iter, dict->dependents);
4185
14.8k
         dep;
4186
9.93k
         dep = fr_rb_iter_next_inorder(&iter)) {
4187
9.93k
      fr_strerror_printf_push("%s (%d)", dep->dependent, dep->count);
4188
9.93k
    }
4189
4190
4.96k
    return -1;
4191
4.96k
  }
4192
4193
  /*
4194
   *  Free the hash tables with free functions first
4195
   *  so that the things the hash tables reference
4196
   *  are still there.
4197
   */
4198
5.01k
  talloc_free(dict->vendors_by_name);
4199
4200
  /*
4201
   *  Decrease the reference count on the validation
4202
   *  library we loaded.
4203
   */
4204
46
  dl_free(dict->dl);
4205
4206
46
  if (dict == dict->gctx->internal) {
4207
22
    dict->gctx->internal = NULL;
4208
22
    dict->gctx->attr_protocol_encapsulation = NULL;
4209
22
  }
4210
4211
46
  return 0;
4212
5.01k
}
4213
4214
/** Allocate a new dictionary
4215
 *
4216
 * @param[in] ctx to allocate dictionary in.
4217
 * @return
4218
 *  - NULL on memory allocation error.
4219
 */
4220
fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
4221
46
{
4222
46
  fr_dict_t *dict;
4223
4224
46
  if (!dict_gctx) {
4225
0
    fr_strerror_const("Initialise global dictionary ctx with fr_dict_global_ctx_init()");
4226
0
    return NULL;
4227
0
  }
4228
4229
46
  dict = talloc_zero(ctx, fr_dict_t);
4230
46
  if (!dict) {
4231
0
    fr_strerror_const("Failed allocating memory for dictionary");
4232
0
  error:
4233
0
    talloc_free(dict);
4234
0
    return NULL;
4235
0
  }
4236
46
  dict->gctx = dict_gctx; /* Record which global context this was allocated in */
4237
46
  talloc_set_destructor(dict, _dict_free);
4238
4239
  /*
4240
   *  A list of all the files that constitute this dictionary
4241
   */
4242
46
  fr_dlist_talloc_init(&dict->filenames, fr_dict_filename_t, entry);
4243
4244
  /*
4245
   *  Pre-Allocate pool memory for rapid startup
4246
   *  As that's the working memory required during
4247
   *  dictionary initialisation.
4248
   */
4249
46
  dict->pool = talloc_pool(dict, DICT_POOL_SIZE);
4250
46
  if (!dict->pool) {
4251
0
    fr_strerror_const("Failed allocating talloc pool for dictionary");
4252
0
    goto error;
4253
0
  }
4254
4255
  /*
4256
   *  Create the table of vendor by name.   There MAY NOT
4257
   *  be multiple vendors of the same name.
4258
   */
4259
46
  dict->vendors_by_name = fr_hash_table_alloc(dict, dict_vendor_name_hash, dict_vendor_name_cmp, hash_pool_free);
4260
46
  if (!dict->vendors_by_name) {
4261
0
    fr_strerror_printf("Failed allocating \"vendors_by_name\" table");
4262
0
    goto error;
4263
0
  }
4264
  /*
4265
   *  Create the table of vendors by value.  There MAY
4266
   *  be vendors of the same value.  If there are, we
4267
   *  pick the latest one.
4268
   */
4269
46
  dict->vendors_by_num = fr_hash_table_alloc(dict, dict_vendor_pen_hash, dict_vendor_pen_cmp, NULL);
4270
46
  if (!dict->vendors_by_num) {
4271
0
    fr_strerror_printf("Failed allocating \"vendors_by_num\" table");
4272
0
    goto error;
4273
0
  }
4274
4275
  /*
4276
   *  Inter-dictionary reference caching
4277
   */
4278
46
  dict->autoref = fr_hash_table_alloc(dict, dict_protocol_name_hash, dict_protocol_name_cmp, NULL);
4279
46
  if (!dict->autoref) {
4280
0
    fr_strerror_printf("Failed allocating \"autoref\" table");
4281
0
    goto error;
4282
0
  }
4283
4284
  /*
4285
   *  Who/what depends on this dictionary
4286
   */
4287
46
  dict->dependents = fr_rb_inline_alloc(dict, fr_dict_dependent_t, node, _dict_dependent_cmp, NULL);
4288
4289
  /*
4290
   *  Set the default dictionary protocol, this can
4291
   *  be overriden by the protocol library.
4292
   */
4293
46
  dict->proto = &dict_proto_default;
4294
4295
46
  return dict;
4296
46
}
4297
4298
/** Allocate a new local dictionary
4299
 *
4300
 * @param[in] parent parent dictionary and talloc ctx
4301
 * @return
4302
 *  - NULL on memory allocation error.
4303
 *
4304
 *  This dictionary cannot define vendors, or inter-dictionary
4305
 *  dependencies.  However, we initialize the relevant fields just in
4306
 *  case.  We should arguably just skip initializing those fields, and
4307
 *  just allow the server to crash if programmers do something stupid with it.
4308
 */
4309
fr_dict_t *fr_dict_protocol_alloc(fr_dict_t const *parent)
4310
0
{
4311
0
  fr_dict_t *dict;
4312
0
  fr_dict_attr_t *da;
4313
4314
0
  fr_dict_attr_flags_t flags = {
4315
0
    .is_root = true,
4316
0
    .local = true,
4317
0
    .internal = true,
4318
0
    .type_size = parent->root->flags.type_size,
4319
0
    .length = parent->root->flags.length,
4320
0
  };
4321
4322
0
  dict = dict_alloc(UNCONST(fr_dict_t *, parent));
4323
0
  if (!dict) return NULL;
4324
4325
  /*
4326
   *  Allocate the root attribute.  This dictionary is
4327
   *  always protocol "local", and number "0".
4328
   */
4329
0
  da = dict_attr_alloc_root(dict->pool, parent, "local", 0,
4330
0
          &(dict_attr_args_t){ .flags = &flags });
4331
0
  if (unlikely(!da)) {
4332
0
    talloc_free(dict);
4333
0
    return NULL;
4334
0
  }
4335
4336
0
  da->last_child_attr = fr_dict_root(parent)->last_child_attr;
4337
4338
0
  dict->root = da;
4339
0
  dict->root->dict = dict;
4340
0
  dict->next = parent;
4341
4342
0
  DA_VERIFY(dict->root);
4343
4344
0
  return dict;
4345
0
}
4346
4347
/** Decrement the reference count on a previously loaded dictionary
4348
 *
4349
 * @param[in] dict  to free.
4350
 * @param[in] dependent that originally allocated this dictionary.
4351
 * @return
4352
 *  - 0 on success (dictionary freed).
4353
 *  - 1 if other things still depend on the dictionary.
4354
 *  - -1 on error (dependent doesn't exist)
4355
 */
4356
int fr_dict_const_free(fr_dict_t const **dict, char const *dependent)
4357
968
{
4358
968
  fr_dict_t **our_dict = UNCONST(fr_dict_t **, dict);
4359
4360
968
  return fr_dict_free(our_dict, dependent);
4361
968
}
4362
4363
/** Decrement the reference count on a previously loaded dictionary
4364
 *
4365
 * @param[in] dict  to free.
4366
 * @param[in] dependent that originally allocated this dictionary.
4367
 * @return
4368
 *  - 0 on success (dictionary freed).
4369
 *  - 1 if other things still depend on the dictionary.
4370
 *  - -1 on error (dependent doesn't exist)
4371
 */
4372
int fr_dict_free(fr_dict_t **dict, char const *dependent)
4373
1.02k
{
4374
1.02k
  if (!*dict) return 0;
4375
4376
998
  switch (dict_dependent_remove(*dict, dependent)) {
4377
998
  case 0:   /* dependent has no more refs */
4378
998
    if (!dict_has_dependents(*dict)) {
4379
22
      talloc_free(*dict);
4380
22
      return 0;
4381
22
    }
4382
976
    FALL_THROUGH;
4383
4384
976
  case 1:   /* dependent has more refs */
4385
976
    return 1;
4386
4387
0
  default:  /* error */
4388
0
    return -1;
4389
998
  }
4390
998
}
4391
4392
/** Process a dict_attr_autoload element to load/verify a dictionary attribute
4393
 *
4394
 * @param[in] to_load attribute definition
4395
 * @return
4396
 *  - 0 on success.
4397
 *  - -1 on failure.
4398
 */
4399
int fr_dict_enum_autoload(fr_dict_enum_autoload_t const *to_load)
4400
0
{
4401
0
  fr_dict_enum_autoload_t const *p = to_load;
4402
0
  fr_dict_enum_value_t const    *enumv;
4403
4404
0
  for (p = to_load; p->out; p++) {
4405
0
    if (unlikely(!p->attr)) {
4406
0
      fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing attribute pointer", p->name);
4407
0
      return -1;
4408
0
    }
4409
4410
0
    if (unlikely(!*p->attr)) {
4411
0
      fr_strerror_printf("Can't resolve value \"%s\", attribute not loaded", p->name);
4412
0
      fr_strerror_printf_push("Check fr_dict_attr_autoload_t struct has "
4413
0
            "an entry to load the attribute \"%s\" is located in, and that "
4414
0
            "the fr_dict_autoload_attr_t symbol name is correct", p->name);
4415
0
      return -1;
4416
0
    }
4417
4418
0
    enumv = fr_dict_enum_by_name(*(p->attr), p->name, -1);
4419
0
    if (!enumv) {
4420
0
      fr_strerror_printf("Value '%s' not found in \"%s\" attribute",
4421
0
             p->name, (*(p->attr))->name);
4422
0
      return -1;
4423
0
    }
4424
4425
0
    if (p->out) *(p->out) = enumv->value;
4426
0
  }
4427
4428
0
  return 0;
4429
0
}
4430
4431
/** Process a dict_attr_autoload element to load/verify a dictionary attribute
4432
 *
4433
 * @param[in] to_load attribute definition
4434
 * @return
4435
 *  - 0 on success.
4436
 *  - -1 on failure.
4437
 */
4438
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
4439
962
{
4440
962
  fr_dict_attr_t const    *da;
4441
962
  fr_dict_attr_autoload_t const *p = to_load;
4442
4443
7.27k
  for (p = to_load; p->out; p++) {
4444
6.31k
    if (!p->dict) {
4445
0
      fr_strerror_printf("Invalid attribute autoload entry for \"%s\", missing dictionary pointer", p->name);
4446
0
      return -1;
4447
0
    }
4448
4449
6.31k
    if (!*p->dict) {
4450
0
      fr_strerror_printf("Autoloader autoloader can't resolve attribute \"%s\", dictionary not loaded", p->name);
4451
0
      fr_strerror_printf_push("Check fr_dict_autoload_t struct has "
4452
0
            "an entry to load the dictionary \"%s\" is located in, and that "
4453
0
            "the fr_dict_autoload_t symbol name is correct", p->name);
4454
0
      return -1;
4455
0
    }
4456
4457
6.31k
    da = fr_dict_attr_by_oid(NULL, fr_dict_root(*p->dict), p->name);
4458
6.31k
    if (!da) {
4459
0
      fr_strerror_printf("Autoloader attribute \"%s\" not found in \"%s\" dictionary", p->name,
4460
0
             *p->dict ? (*p->dict)->root->name : "internal");
4461
0
      return -1;
4462
0
    }
4463
4464
6.31k
    if (da->type != p->type) {
4465
0
      fr_strerror_printf("Autoloader attribute \"%s\" should be type %s, but defined as type %s", da->name,
4466
0
             fr_type_to_str(p->type),
4467
0
             fr_type_to_str(da->type));
4468
0
      return -1;
4469
0
    }
4470
4471
6.31k
    DA_VERIFY(da);
4472
4473
6.31k
    if (p->out) *(p->out) = da;
4474
6.31k
  }
4475
4476
962
  return 0;
4477
962
}
4478
4479
/** Process a dict_autoload element to load a protocol
4480
 *
4481
 * @param[in] to_load dictionary definition.
4482
 * @param[in] dependent that is loading this dictionary.
4483
 * @return
4484
 *  - 0 on success.
4485
 *  - -1 on failure.
4486
 */
4487
int _fr_dict_autoload(fr_dict_autoload_t const *to_load, char const *dependent)
4488
962
{
4489
962
  fr_dict_autoload_t const  *p;
4490
4491
1.93k
  for (p = to_load; p->out; p++) {
4492
968
    fr_dict_t *dict = NULL;
4493
4494
968
    if (unlikely(!p->proto)) {
4495
0
      fr_strerror_const("autoload missing parameter proto");
4496
0
      return -1;
4497
0
    }
4498
4499
    /*
4500
     *  Load the internal dictionary
4501
     */
4502
968
    if (strcmp(p->proto, "freeradius") == 0) {
4503
6
      if (fr_dict_internal_afrom_file(&dict, p->proto, dependent) < 0) return -1;
4504
962
    } else {
4505
962
      if (fr_dict_protocol_afrom_file(&dict, p->proto, p->base_dir, dependent) < 0) return -1;
4506
962
    }
4507
4508
968
    *(p->out) = dict;
4509
968
  }
4510
4511
962
  return 0;
4512
962
}
4513
4514
4515
/** Decrement the reference count on a previously loaded dictionary
4516
 *
4517
 * @param[in] to_free previously loaded dictionary to free.
4518
 * @param[in] dependent that originally allocated this dictionary
4519
 */
4520
int _fr_dict_autofree(fr_dict_autoload_t const *to_free, char const *dependent)
4521
962
{
4522
962
  fr_dict_autoload_t const *p;
4523
4524
1.93k
  for (p = to_free; p->out; p++) {
4525
968
    int ret;
4526
4527
968
    if (!*p->out) continue;
4528
968
    ret = fr_dict_const_free(p->out, dependent);
4529
4530
968
    if (ret == 0) *p->out = NULL;
4531
968
    if (ret < 0) return -1;
4532
968
  }
4533
4534
962
  return 0;
4535
962
}
4536
4537
/** Structure used to managed the lifetime of a dictionary
4538
 *
4539
 * This should only be used when dictionaries are being dynamically loaded during
4540
 * compilation.  It should not be used to load dictionaries at runtime, or if
4541
 * modules need to load dictionaries (use static fr_dict_autoload_t defs).
4542
4543
 */
4544
struct fr_dict_autoload_talloc_s {
4545
  fr_dict_autoload_t load[2];   //!< Autoloader def.
4546
  char const *dependent;      //!< Dependent that loaded the dictionary.
4547
};
4548
4549
/** Talloc destructor to automatically free dictionaries
4550
 *
4551
 * @param[in] to_free dictionary autoloader definition describing the dictionary to free.
4552
 */
4553
static int _fr_dict_autoload_talloc_free(fr_dict_autoload_talloc_t const *to_free)
4554
0
{
4555
0
  return _fr_dict_autofree(to_free->load, to_free->dependent);
4556
0
}
4557
4558
/** Autoload a dictionary and bind the lifetime to a talloc chunk
4559
 *
4560
 * Mainly useful for resolving "forward" references from unlang immediately.
4561
 *
4562
 * @note If the talloc chunk is freed it does not mean the dictionary will
4563
 *   be immediately freed.  It will be freed when all other references
4564
 *   to the dictionary are gone.
4565
 *
4566
 * @param[in] ctx to bind the dictionary lifetime to.
4567
 * @param[out] out  pointer to the loaded dictionary.
4568
 * @param[in] proto to load.
4569
 * @param[in] dependent to register this reference to.  Will be dupd.
4570
 */
4571
fr_dict_autoload_talloc_t *_fr_dict_autoload_talloc(TALLOC_CTX *ctx, fr_dict_t const **out, char const *proto, char const *dependent)
4572
0
{
4573
0
  fr_dict_autoload_talloc_t *dict_ref;
4574
0
  int ret;
4575
4576
0
  dict_ref = talloc(ctx, fr_dict_autoload_talloc_t);
4577
0
  if (unlikely(dict_ref == NULL)) {
4578
0
  oom:
4579
0
    fr_strerror_const("Out of memory");
4580
0
    return NULL;
4581
0
  }
4582
4583
0
  dict_ref->load[0] = (fr_dict_autoload_t){ .proto = proto, .out = out};
4584
0
  dict_ref->load[1] = (fr_dict_autoload_t) DICT_AUTOLOAD_TERMINATOR;
4585
0
  dict_ref->dependent = talloc_strdup(dict_ref, dependent);
4586
0
  if (unlikely(dict_ref->dependent == NULL)) {
4587
0
    talloc_free(dict_ref);
4588
0
    goto oom;
4589
0
  }
4590
4591
0
  ret = _fr_dict_autoload(dict_ref->load, dependent);
4592
0
  if (ret < 0) {
4593
0
    talloc_free(dict_ref);
4594
0
    return NULL;
4595
0
  }
4596
4597
0
  return dict_ref;
4598
0
}
4599
4600
/** Callback to automatically resolve enum values
4601
 *
4602
 * @param[in] module  being loaded.
4603
 * @param[in] symbol  An array of fr_dict_enum_autoload_t to load.
4604
 * @param[in] user_ctx  unused.
4605
 * @return
4606
 *  - 0 on success.
4607
 *  - -1 on failure.
4608
 */
4609
int fr_dl_dict_enum_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4610
0
{
4611
0
  if (fr_dict_enum_autoload((fr_dict_enum_autoload_t *)symbol) < 0) return -1;
4612
4613
0
  return 0;
4614
0
}
4615
4616
/** Callback to automatically resolve attributes and check the types are correct
4617
 *
4618
 * @param[in] module  being loaded.
4619
 * @param[in] symbol  An array of fr_dict_attr_autoload_t to load.
4620
 * @param[in] user_ctx  unused.
4621
 * @return
4622
 *  - 0 on success.
4623
 *  - -1 on failure.
4624
 */
4625
int fr_dl_dict_attr_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4626
0
{
4627
0
  if (fr_dict_attr_autoload((fr_dict_attr_autoload_t *)symbol) < 0) return -1;
4628
4629
0
  return 0;
4630
0
}
4631
4632
/** Callback to automatically load dictionaries required by modules
4633
 *
4634
 * @param[in] module  being loaded.
4635
 * @param[in] symbol  An array of fr_dict_autoload_t to load.
4636
 * @param[in] user_ctx  unused.
4637
 * @return
4638
 *  - 0 on success.
4639
 *  - -1 on failure.
4640
 */
4641
int fr_dl_dict_autoload(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4642
0
{
4643
0
  if (fr_dict_autoload((fr_dict_autoload_t const *)symbol) < 0) return -1;
4644
4645
0
  return 0;
4646
0
}
4647
4648
/** Callback to automatically free a dictionary when the module is unloaded
4649
 *
4650
 * @param[in] module  being loaded.
4651
 * @param[in] symbol  An array of fr_dict_autoload_t to load.
4652
 * @param[in] user_ctx  unused.
4653
 */
4654
void fr_dl_dict_autofree(UNUSED dl_t const *module, void *symbol, UNUSED void *user_ctx)
4655
0
{
4656
0
  fr_dict_autofree(((fr_dict_autoload_t *)symbol));
4657
0
}
4658
4659
static int _dict_global_free_at_exit(void *uctx)
4660
22
{
4661
22
  return talloc_free(uctx);
4662
22
}
4663
4664
static int _dict_global_free(fr_dict_gctx_t *gctx)
4665
22
{
4666
22
  fr_hash_iter_t  iter;
4667
22
  fr_dict_t *dict;
4668
22
  bool    still_loaded = false;
4669
4670
  /*
4671
   *  Make sure this doesn't fire later and mess
4672
   *  things up...
4673
   */
4674
22
  if (gctx->free_at_exit) fr_atexit_global_disarm(true, _dict_global_free_at_exit, gctx);
4675
4676
  /*
4677
   *  Free up autorefs first, which will free up inter-dictionary dependencies.
4678
   */
4679
22
  for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
4680
46
       dict;
4681
24
       dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
4682
24
    (void)talloc_get_type_abort(dict, fr_dict_t);
4683
4684
24
    if (dict_autoref_free(dict) < 0) return -1;
4685
24
  }
4686
4687
22
  for (dict = fr_hash_table_iter_init(gctx->protocol_by_name, &iter);
4688
46
       dict;
4689
24
       dict = fr_hash_table_iter_next(gctx->protocol_by_name, &iter)) {
4690
24
        (void)talloc_get_type_abort(dict, fr_dict_t);
4691
24
        dict_dependent_remove(dict, "global");      /* remove our dependency */
4692
4693
24
    if (talloc_free(dict) < 0) {
4694
0
#ifndef NDEBUG
4695
0
      FR_FAULT_LOG("gctx failed to free dictionary %s - %s", dict->root->name, fr_strerror());
4696
0
#endif
4697
0
      still_loaded = true;
4698
0
    }
4699
24
  }
4700
4701
  /*
4702
   *  Free the internal dictionary as the last step, after all of the protocol dictionaries and
4703
   *  libraries have freed their references to it.
4704
   */
4705
22
  if (gctx->internal) {
4706
22
    dict_dependent_remove(gctx->internal, "global");  /* remove our dependency */
4707
4708
22
    if (talloc_free(gctx->internal) < 0) still_loaded = true;
4709
22
  }
4710
4711
22
  if (still_loaded) {
4712
0
#ifndef NDEBUG
4713
0
    fr_dict_gctx_debug(stderr, gctx);
4714
0
#endif
4715
0
    return -1;
4716
0
  }
4717
4718
  /*
4719
   *  Set this to NULL just in case the caller tries to use
4720
   *  dict_global_init() again.
4721
   */
4722
22
  if (gctx == dict_gctx) dict_gctx = NULL; /* In case the active context isn't this one */
4723
4724
22
  return 0;
4725
22
}
4726
4727
/** Initialise the global protocol hashes
4728
 *
4729
 * @note Must be called before any other dictionary functions.
4730
 *
4731
 * @param[in] ctx   to allocate global resources in.
4732
 * @param[in] free_at_exit  Install an at_exit handler to free the global ctx.
4733
 *        This is useful when dictionaries are held by other
4734
 *        libraries which free them using atexit handlers.
4735
 * @param[in] dict_dir    the default location for the dictionaries.
4736
 * @return
4737
 *  - A pointer to the new global context on success.
4738
 *  - NULL on failure.
4739
 */
4740
fr_dict_gctx_t *fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
4741
45
{
4742
45
  fr_dict_gctx_t *new_ctx;
4743
4744
45
  if (!dict_dir) {
4745
0
    fr_strerror_const("No dictionary location provided");
4746
0
    return NULL;
4747
0
  }
4748
4749
45
  new_ctx = talloc_zero(ctx, fr_dict_gctx_t);
4750
45
  if (!new_ctx) {
4751
0
    fr_strerror_const("Out of Memory");
4752
0
    return NULL;
4753
0
  }
4754
45
  new_ctx->perm_check = true; /* Check file permissions by default */
4755
4756
45
  new_ctx->protocol_by_name = fr_hash_table_alloc(new_ctx, dict_protocol_name_hash, dict_protocol_name_cmp, NULL);
4757
45
  if (!new_ctx->protocol_by_name) {
4758
0
    fr_strerror_const("Failed initializing protocol_by_name hash");
4759
0
  error:
4760
0
    talloc_free(new_ctx);
4761
0
    return NULL;
4762
0
  }
4763
4764
45
  new_ctx->protocol_by_num = fr_hash_table_alloc(new_ctx, dict_protocol_num_hash, dict_protocol_num_cmp, NULL);
4765
45
  if (!new_ctx->protocol_by_num) {
4766
0
    fr_strerror_const("Failed initializing protocol_by_num hash");
4767
0
    goto error;
4768
0
  }
4769
4770
45
  new_ctx->dict_dir_default = talloc_strdup(new_ctx, dict_dir);
4771
45
  if (!new_ctx->dict_dir_default) goto error;
4772
4773
45
  new_ctx->dict_loader = dl_loader_init(new_ctx, NULL, false, false);
4774
45
  if (!new_ctx->dict_loader) goto error;
4775
4776
45
  new_ctx->free_at_exit = free_at_exit;
4777
4778
45
  talloc_set_destructor(new_ctx, _dict_global_free);
4779
4780
45
  if (!dict_gctx) dict_gctx = new_ctx; /* Set as the default */
4781
4782
45
  if (free_at_exit) fr_atexit_global(_dict_global_free_at_exit, new_ctx);
4783
4784
45
  return new_ctx;
4785
45
}
4786
4787
/** Set whether we check dictionary file permissions
4788
 *
4789
 * @param[in] gctx  to alter.
4790
 * @param[in] enable  Whether we should check file permissions as they're loaded.
4791
 */
4792
void fr_dict_global_ctx_perm_check(fr_dict_gctx_t *gctx, bool enable)
4793
0
{
4794
0
  gctx->perm_check = enable;
4795
0
}
4796
4797
/** Set a new, active, global dictionary context
4798
 *
4799
 * @param[in] gctx  To set.
4800
 */
4801
void fr_dict_global_ctx_set(fr_dict_gctx_t const *gctx)
4802
0
{
4803
0
  memcpy(&dict_gctx, &gctx, sizeof(dict_gctx));
4804
0
}
4805
4806
/** Explicitly free all data associated with a global dictionary context
4807
 *
4808
 * @note You should *NOT* ignore the return code of this function.
4809
 *       You should use perror() or PERROR() to print out the reason
4810
 *       why freeing failed.
4811
 *
4812
 * @param[in] gctx  To set.
4813
 * @return
4814
 *  - 0 on success.
4815
 *  - -1 on failure.
4816
 */
4817
int fr_dict_global_ctx_free(fr_dict_gctx_t const *gctx)
4818
0
{
4819
0
  if (dict_gctx == gctx) dict_gctx = NULL;
4820
4821
0
  return talloc_const_free(gctx);
4822
0
}
4823
4824
/** Allow the default dict dir to be changed after initialisation
4825
 *
4826
 * @param[in] dict_dir  New default dict dir to use.
4827
 * @return
4828
 *  - 0 on success.
4829
 *  - -1 on failure.
4830
 */
4831
int fr_dict_global_ctx_dir_set(char const *dict_dir)
4832
0
{
4833
0
  if (!dict_gctx) return -1;
4834
4835
0
  talloc_free(dict_gctx->dict_dir_default);    /* Free previous value */
4836
0
  dict_gctx->dict_dir_default = talloc_strdup(dict_gctx, dict_dir);
4837
0
  if (!dict_gctx->dict_dir_default) return -1;
4838
4839
0
  return 0;
4840
0
}
4841
4842
char const *fr_dict_global_ctx_dir(void)
4843
46
{
4844
46
  return dict_gctx->dict_dir_default;
4845
46
}
4846
4847
/** Mark all dictionaries and the global dictionary ctx as read only
4848
 *
4849
 * Any attempts to add new attributes will now fail.
4850
 */
4851
void fr_dict_global_ctx_read_only(void)
4852
0
{
4853
0
  fr_hash_iter_t  iter;
4854
0
  fr_dict_t *dict;
4855
4856
0
  if (!dict_gctx) return;
4857
4858
  /*
4859
   *  Set everything to read only
4860
   */
4861
0
  for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &iter);
4862
0
       dict;
4863
0
       dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &iter)) {
4864
0
        dict_hash_tables_finalise(dict);
4865
0
    dict->read_only = true;
4866
0
  }
4867
4868
0
  dict = dict_gctx->internal;
4869
0
  dict_hash_tables_finalise(dict);
4870
0
  dict->read_only = true;
4871
0
  dict_gctx->read_only = true;
4872
0
}
4873
4874
/** Dump information about currently loaded dictionaries
4875
 *
4876
 * Intended to be called from a debugger
4877
 */
4878
void fr_dict_gctx_debug(FILE *fp, fr_dict_gctx_t const *gctx)
4879
0
{
4880
0
  fr_hash_iter_t      dict_iter;
4881
0
  fr_dict_t     *dict;
4882
0
  fr_rb_iter_inorder_t    dep_iter;
4883
0
  fr_dict_dependent_t   *dep;
4884
4885
0
  if (gctx == NULL) gctx = dict_gctx;
4886
4887
0
  if (!gctx) {
4888
0
    fprintf(fp, "gctx not initialised\n");
4889
0
    return;
4890
0
  }
4891
4892
0
  fprintf(fp, "gctx %p report\n", dict_gctx);
4893
0
  for (dict = fr_hash_table_iter_init(gctx->protocol_by_num, &dict_iter);
4894
0
       dict;
4895
0
       dict = fr_hash_table_iter_next(gctx->protocol_by_num, &dict_iter)) {
4896
0
    for (dep = fr_rb_iter_init_inorder(&dep_iter, dict->dependents);
4897
0
         dep;
4898
0
         dep = fr_rb_iter_next_inorder(&dep_iter)) {
4899
0
      fprintf(fp, "\t%s is referenced from %s count (%d)\n",
4900
0
        dict->root->name, dep->dependent, dep->count);
4901
0
    }
4902
0
  }
4903
4904
0
  if (gctx->internal) {
4905
0
    for (dep = fr_rb_iter_init_inorder(&dep_iter, gctx->internal->dependents);
4906
0
         dep;
4907
0
         dep = fr_rb_iter_next_inorder(&dep_iter)) {
4908
0
      fprintf(fp, "\t%s is referenced from %s count (%d)\n",
4909
0
        gctx->internal->root->name, dep->dependent, dep->count);
4910
0
    }
4911
0
  }
4912
0
}
4913
4914
/** Iterate protocols by name
4915
 *
4916
 */
4917
fr_dict_t *fr_dict_global_ctx_iter_init(fr_dict_global_ctx_iter_t *iter)
4918
0
{
4919
0
  if (!dict_gctx) return NULL;
4920
4921
0
  return fr_hash_table_iter_init(dict_gctx->protocol_by_name, iter);
4922
0
}
4923
4924
fr_dict_t *fr_dict_global_ctx_iter_next(fr_dict_global_ctx_iter_t *iter)
4925
0
{
4926
0
  if (!dict_gctx) return NULL;
4927
4928
0
  return fr_hash_table_iter_next(dict_gctx->protocol_by_name, iter);
4929
0
}
4930
4931
4932
/** Coerce to non-const
4933
 *
4934
 */
4935
fr_dict_t *fr_dict_unconst(fr_dict_t const *dict)
4936
350
{
4937
350
  if (unlikely(dict->read_only)) {
4938
0
    fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4939
0
    return NULL;
4940
0
  }
4941
350
  return UNCONST(fr_dict_t *, dict);
4942
350
}
4943
4944
/** Coerce to non-const
4945
 *
4946
 */
4947
fr_dict_attr_t *fr_dict_attr_unconst(fr_dict_attr_t const *da)
4948
4.75k
{
4949
4.75k
  fr_dict_t *dict;
4950
4951
4.75k
  dict = dict_by_da(da);
4952
4.75k
  if (unlikely(dict->read_only)) {
4953
0
    fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(dict)->name);
4954
0
    return NULL;
4955
0
  }
4956
4957
4.75k
  return UNCONST(fr_dict_attr_t *, da);
4958
4.75k
}
4959
4960
fr_dict_t const *fr_dict_internal(void)
4961
129k
{
4962
129k
  if (!dict_gctx) return NULL;
4963
4964
129k
  return dict_gctx->internal;
4965
129k
}
4966
4967
/*
4968
 *  Check for the allowed characters.
4969
 */
4970
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
4971
47.5k
{
4972
47.5k
  char const *p = name, *end;
4973
47.5k
  bool unknown = false;
4974
47.5k
  bool alnum = false;
4975
4976
47.5k
  if (len < 0) len = strlen(name);
4977
4978
47.5k
  if (len > FR_DICT_ATTR_MAX_NAME_LEN) {
4979
0
    fr_strerror_const("Attribute name is too long");
4980
0
    return -1;
4981
0
  }
4982
4983
47.5k
  end = p + len;
4984
4985
  /*
4986
   *  Unknown attributes can have '.' in their name.
4987
   */
4988
47.5k
  if ((len > 5) && (memcmp(name, "Attr-", 5) == 0)) unknown = true;
4989
4990
743k
  while (p < end) {
4991
695k
    if ((*p == '.') && unknown) p++;
4992
4993
695k
    if (!fr_dict_attr_allowed_chars[(uint8_t)*p]) {
4994
0
      fr_strerror_printf("Invalid character '%pV' in attribute name \"%pV\"",
4995
0
             fr_box_strvalue_len(p, 1), fr_box_strvalue_len(name, len));
4996
4997
0
      return -(p - name);
4998
0
    }
4999
5000
695k
    alnum |= sbuff_char_alpha_num[(uint8_t)*p];
5001
5002
695k
    p++;
5003
695k
  }
5004
5005
47.5k
  if (!alnum) {
5006
0
    fr_strerror_const("Invalid attribute name");
5007
0
    return -1;
5008
0
  }
5009
5010
47.5k
  return len;
5011
47.5k
}
5012
5013
ssize_t fr_dict_valid_oid_str(char const *name, ssize_t len)
5014
8
{
5015
8
  char const *p = name, *end;
5016
8
  bool alnum = false;
5017
5018
8
  if (len < 0) len = strlen(name);
5019
8
  end = p + len;
5020
5021
48
  do {
5022
48
    if (!fr_dict_attr_allowed_chars[(uint8_t)*p] && (*p != '.')) {
5023
0
      fr_strerror_printf("Invalid character '%pV' in oid string \"%pV\"",
5024
0
             fr_box_strvalue_len(p, 1), fr_box_strvalue_len(name, len));
5025
5026
0
      return -(p - name);
5027
0
    }
5028
5029
48
    alnum |= sbuff_char_alpha_num[(uint8_t)*p];
5030
48
    p++;
5031
48
  } while (p < end);
5032
5033
8
  if (!alnum) return 0;
5034
5035
8
  return len;
5036
8
}
5037
5038
/** Iterate over children of a DA.
5039
 *
5040
 *  @param[in] parent the parent da to iterate over
5041
 *  @param[in,out] prev pointer to NULL to start, otherwise pointer to the previously returned child
5042
 *  @return
5043
 *     - NULL for end of iteration
5044
 *     - !NULL for a valid child.  This child MUST be passed to the next loop.
5045
 */
5046
fr_dict_attr_t const *fr_dict_attr_iterate_children(fr_dict_attr_t const *parent, fr_dict_attr_t const **prev)
5047
722
{
5048
722
  fr_dict_attr_t const * const *bin;
5049
722
  fr_dict_attr_t const **children;
5050
722
  fr_dict_attr_t const *ref;
5051
722
  size_t len, i, start;
5052
5053
722
  if (!parent || !prev) return NULL;
5054
5055
722
  ref = fr_dict_attr_ref(parent);
5056
722
  if (ref) parent = ref;
5057
5058
722
  children = dict_attr_children(parent);
5059
722
  if (!children) return NULL;
5060
5061
722
  if (!*prev) {
5062
130
    start = 0;
5063
5064
592
  } else if ((*prev)->next) {
5065
    /*
5066
     *  There are more children in this bin, return
5067
     *  the next one.
5068
     */
5069
0
    return (*prev)->next;
5070
5071
592
  } else {
5072
    /*
5073
     *  Figure out which bin we were in.  If it was
5074
     *  the last one, we're done.
5075
     */
5076
592
    start = (*prev)->attr & 0xff;
5077
592
    if (start == 255) return NULL;
5078
5079
    /*
5080
     *  Start at the next bin.
5081
     */
5082
592
    start++;
5083
592
  }
5084
5085
  /*
5086
   *  Look for a non-empty bin, and return the first child
5087
   *  from there.
5088
   */
5089
722
  len = talloc_array_length(children);
5090
33.4k
  for (i = start; i < len; i++) {
5091
33.2k
    bin = &children[i & 0xff];
5092
5093
33.2k
    if (*bin) return *bin;
5094
33.2k
  }
5095
5096
130
  return NULL;
5097
722
}
5098
5099
/** Call the specified callback for da and then for all its children
5100
 *
5101
 */
5102
static int dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
5103
0
{
5104
0
  size_t i, len;
5105
0
  fr_dict_attr_t const **children;
5106
5107
0
  children = dict_attr_children(da);
5108
5109
0
  if (fr_dict_attr_ref(da) || !children) return callback(da, uctx);
5110
5111
0
  len = talloc_array_length(children);
5112
0
  for (i = 0; i < len; i++) {
5113
0
    int ret;
5114
0
    fr_dict_attr_t const *bin;
5115
5116
0
    if (!children[i]) continue;
5117
5118
0
    for (bin = children[i]; bin; bin = bin->next) {
5119
0
      ret = dict_walk(bin, callback, uctx);
5120
0
      if (ret < 0) return ret;
5121
0
    }
5122
0
  }
5123
5124
0
  return 0;
5125
0
}
5126
5127
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
5128
0
{
5129
0
  return dict_walk(da, callback, uctx);
5130
0
}
5131
5132
5133
void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
5134
19.4M
{
5135
19.4M
  int i;
5136
19.4M
  fr_dict_attr_t const *da_p;
5137
5138
19.4M
  if (!da) fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t pointer was NULL", file, line);
5139
5140
19.4M
  (void) talloc_get_type_abort_const(da, fr_dict_attr_t);
5141
5142
19.4M
  if ((!da->flags.is_root) && (da->depth == 0)) {
5143
0
    fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5144
0
             "Is not root, but depth is 0",
5145
0
             file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr);
5146
0
  }
5147
5148
19.4M
  if (da->depth > FR_DICT_MAX_TLV_STACK) {
5149
0
    fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5150
0
             "Indicated depth (%u) greater than TLV stack depth (%d)",
5151
0
             file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr,
5152
0
             da->depth, FR_DICT_MAX_TLV_STACK);
5153
0
  }
5154
5155
39.1M
  for (da_p = da; da_p; da_p = da_p->next) {
5156
19.6M
    (void) talloc_get_type_abort_const(da_p, fr_dict_attr_t);
5157
19.6M
  }
5158
5159
58.2M
  for (i = da->depth, da_p = da; (i >= 0) && da; i--, da_p = da_p->parent) {
5160
38.7M
    if (!da_p) {
5161
0
      fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5162
0
               "Depth indicated there should be a parent, but parent is NULL",
5163
0
               file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr);
5164
0
    }
5165
38.7M
    if (i != (int)da_p->depth) {
5166
0
      fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t %s vendor: %u, attr %u: "
5167
0
               "Depth out of sequence, expected %i, got %u",
5168
0
               file, line, da->name, fr_dict_vendor_num_by_da(da), da->attr, i, da_p->depth);
5169
0
    }
5170
5171
38.7M
  }
5172
5173
19.4M
  if ((i + 1) < 0) {
5174
0
    fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: fr_dict_attr_t top of hierarchy was not at depth 0",
5175
0
             file, line);
5176
0
  }
5177
5178
19.4M
  if (da->parent && (da->parent->type == FR_TYPE_VENDOR) && !fr_dict_attr_has_ext(da, FR_DICT_ATTR_EXT_VENDOR)) {
5179
0
    fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: VSA missing 'vendor' extension", file, line);
5180
0
  }
5181
5182
19.4M
  switch (da->type) {
5183
18.6M
  case FR_TYPE_STRUCTURAL:
5184
18.6M
  {
5185
18.6M
    fr_hash_table_t *ht;
5186
5187
18.6M
    if (da->type == FR_TYPE_GROUP) break;
5188
5189
6.01M
    fr_assert_msg(fr_dict_attr_has_ext(da, FR_DICT_ATTR_EXT_CHILDREN),
5190
6.01M
            "CONSISTENCY CHECK FAILED %s[%d]: %s missing 'children' extension",
5191
6.01M
            file, line,
5192
6.01M
            fr_type_to_str(da->type));
5193
5194
6.01M
    fr_assert_msg(fr_dict_attr_has_ext(da, FR_DICT_ATTR_EXT_NAMESPACE),
5195
6.01M
            "CONSISTENCY CHECK FAILED %s[%d]: %s missing 'namespace' extension",
5196
6.01M
            file, line,
5197
6.01M
            fr_type_to_str(da->type));
5198
5199
    /*
5200
     *  Check the namespace hash table is ok
5201
     */
5202
6.01M
    ht = dict_attr_namespace(da);
5203
6.01M
    if (unlikely(!ht)) break;
5204
6.01M
    fr_hash_table_verify(ht);
5205
6.01M
  }
5206
0
    break;
5207
5208
13.4M
  default:
5209
13.4M
    break;
5210
19.4M
  }
5211
19.4M
}
5212
5213
/** See if a structural da is allowed to contain another da
5214
 *
5215
 *  We have some complex rules with different structural types,
5216
 *  different protocol dictionaries, references to other protocols,
5217
 *  etc.
5218
 *
5219
 *  @param[in] parent The parent da, must be structural
5220
 *  @param[in] child  The alleged child
5221
 *  @return
5222
 *  - false - the child is not allowed to be contained by the parent
5223
 *  - true - the child is allowed to be contained by the parent
5224
 */
5225
bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child)
5226
743k
{
5227
  /*
5228
   *  This is the common case: child is from the parent.
5229
   */
5230
743k
  if (child->parent == parent) return true;
5231
5232
110k
  if (child->flags.is_raw) return true; /* let people do stupid things */
5233
5234
  /*
5235
   *  Only structural types can have children.
5236
   */
5237
38.3k
  if (!fr_type_structural[parent->type]) return false;
5238
5239
  /*
5240
   *  An internal attribute can go into any other container.
5241
   *
5242
   *  Any other attribute can go into an internal structural
5243
   *  attribute, because why not?
5244
   */
5245
38.3k
  if (dict_gctx) {
5246
38.3k
    if (child->dict == dict_gctx->internal) return true;
5247
5248
35.7k
    if (parent->dict == dict_gctx->internal) return true;
5249
35.7k
  }
5250
5251
  /*
5252
   *  Anything can go into internal groups.
5253
   */
5254
35.7k
  if ((parent->type == FR_TYPE_GROUP) && parent->flags.internal) return true;
5255
5256
  /*
5257
   *  Protocol attributes have to be in the same dictionary.
5258
   *
5259
   *  Unless they're a cross-protocol grouping attribute.
5260
   *  In which case we check if the ref is the same.
5261
   */
5262
30.9k
  if (child->dict != parent->dict) {
5263
30.4k
    fr_dict_attr_t const *ref;
5264
5265
30.4k
    ref = fr_dict_attr_ref(parent);
5266
5267
30.4k
    return (ref && (ref->dict == child->dict));
5268
30.4k
  }
5269
5270
  /*
5271
   *  Key fields can have children, but everyone else thinks
5272
   *  that the struct is the parent.  <sigh>
5273
   */
5274
513
  if ((parent->type == FR_TYPE_STRUCT) && child->parent->parent == parent) return true;
5275
5276
  /*
5277
   *  We're in the same protocol dictionary, but the child
5278
   *  isn't directly from the parent.  Therefore the only
5279
   *  type of same-protocol structure it can go into is a
5280
   *  group.
5281
   */
5282
513
  return (parent->type == FR_TYPE_GROUP);
5283
513
}
5284
5285
/** Return the protocol descriptor for the dictionary.
5286
 *
5287
 */
5288
fr_dict_protocol_t const *fr_dict_protocol(fr_dict_t const *dict)
5289
615k
{
5290
615k
  return dict->proto;
5291
615k
}
5292
5293
/*
5294
 *  Get the real protocol namespace behind a local one.
5295
 */
5296
fr_dict_attr_t const *fr_dict_unlocal(fr_dict_attr_t const *da)
5297
0
{
5298
0
  if (!da->flags.local) return da;
5299
5300
0
  fr_assert(da->dict->root == da);
5301
5302
0
  while (da->dict->next) {
5303
0
    da = da->dict->next->root;
5304
0
  }
5305
5306
0
  return da;
5307
0
}
5308
5309
/*
5310
 *  Get the real protocol dictionary behind a local one.
5311
 */
5312
fr_dict_t const *fr_dict_proto_dict(fr_dict_t const *dict)
5313
0
{
5314
0
  while (dict->next) dict = dict->next;
5315
5316
0
  return dict;
5317
0
}
5318
5319
int fr_dict_attr_set_group(fr_dict_attr_t **da_p)
5320
14
{
5321
14
  if ((*da_p)->type == FR_TYPE_GROUP) {
5322
0
    fr_assert(fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_REF) != NULL);
5323
0
    return 0;
5324
0
  }
5325
5326
14
  (*da_p)->type = FR_TYPE_GROUP;
5327
5328
14
  fr_assert(fr_dict_attr_ext(*da_p, FR_DICT_ATTR_EXT_REF) == NULL);
5329
5330
14
  if (!dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_REF)) {
5331
0
    return -1;
5332
0
  }
5333
5334
14
  return 0;
5335
14
}