Coverage Report

Created: 2024-08-28 06:17

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