Coverage Report

Created: 2026-04-12 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/server/cf_util.c
Line
Count
Source
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the Free Software
14
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15
 */
16
17
/**
18
 * $Id: b8eac4fdb4de2685f32813fde8d2682332039422 $
19
 * @file cf_util.c
20
 * @brief Functions for building and managing the structure of internal format config items.
21
 *
22
 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23
 */
24
RCSID("$Id: b8eac4fdb4de2685f32813fde8d2682332039422 $")
25
26
#include <string.h>
27
28
#include <freeradius-devel/server/cf_file.h>
29
#include <freeradius-devel/server/cf_priv.h>
30
#include <freeradius-devel/server/log.h>
31
#include <freeradius-devel/util/debug.h>
32
#include <freeradius-devel/util/atexit.h>
33
34
static inline int8_t cf_ident2_cmp(void const *a, void const *b);
35
static int8_t _cf_ident1_cmp(void const *a, void const *b);
36
static int8_t _cf_ident2_cmp(void const *a, void const *b);
37
38
/** Return the next child that's of the specified type
39
 *
40
 * @param[in] parent  to return children from.
41
 * @param[in] current child to start searching from.
42
 * @param[in] type  to search for.
43
 * @return
44
 *  - The next #CONF_ITEM that's a child of ci matching type.
45
 *  - NULL if no #CONF_ITEM matches that criteria.
46
 */
47
static CONF_ITEM *cf_next(CONF_ITEM const *parent, CONF_ITEM const *current, CONF_ITEM_TYPE type)
48
0
{
49
0
  cf_item_foreach_next(parent, ci, UNCONST(CONF_ITEM *, current)) {
50
0
    if (ci->type == type) return ci;
51
0
  }
52
53
0
  return NULL;
54
0
}
55
56
/** Return the previous child that's of the specified type
57
 *
58
 * @param[in] parent  to return children from.
59
 * @param[in] current child to start searching from.
60
 * @param[in] type  to search for.
61
 * @return
62
 *  - The next #CONF_ITEM that's a child of ci matching type.
63
 *  - NULL if no #CONF_ITEM matches that criteria.
64
 */
65
static inline CC_HINT(always_inline)
66
CONF_ITEM *cf_prev(CONF_ITEM const *parent, CONF_ITEM const *current, CONF_ITEM_TYPE type)
67
0
{
68
0
  cf_item_foreach_prev(parent, ci, UNCONST(CONF_ITEM *, current)) {
69
0
    if (ci->type == type) return ci;
70
0
  }
71
72
0
  return NULL;
73
0
}
74
75
0
#define IS_WILDCARD(_ident) (_ident == CF_IDENT_ANY)
76
77
/** Return the next child that's of the specified type with the specified identifiers
78
 *
79
 * @param[in] parent  The section we're searching in.
80
 * @param[in] type  of #CONF_ITEM we're searching for.
81
 * @param[in] ident1  The first identifier.
82
 * @param[in] ident2  The second identifier. Special value CF_IDENT_ANY
83
 *      can be used to match any ident2 value.
84
 * @return
85
 *  - The first matching item.
86
 *  - NULL if no items matched.
87
 */
88
static CONF_ITEM *cf_find(CONF_ITEM const *parent, CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
89
0
{
90
0
  CONF_SECTION  cs_find;
91
0
  CONF_PAIR cp_find;
92
0
  CONF_DATA cd_find;
93
0
  CONF_ITEM *find;
94
95
0
  if (!parent) return NULL;
96
0
  if (cf_item_has_no_children(parent)) return NULL;
97
98
0
  if (!ident1) return cf_next(parent, NULL, type);
99
100
0
  switch (type) {
101
0
  case CONF_ITEM_SECTION:
102
0
    memset(&cs_find, 0, sizeof(cs_find));
103
0
    cs_find.item.type = CONF_ITEM_SECTION;
104
0
    cs_find.name1 = ident1;
105
0
    if (!IS_WILDCARD(ident2)) cs_find.name2 = ident2;
106
107
0
    find = (CONF_ITEM *)&cs_find;
108
0
    break;
109
110
0
  case CONF_ITEM_PAIR:
111
0
    fr_assert((ident2 == NULL) || IS_WILDCARD(ident2));
112
113
0
    memset(&cp_find, 0, sizeof(cp_find));
114
0
    cp_find.item.type = CONF_ITEM_PAIR;
115
0
    cp_find.attr = ident1;
116
117
0
    find = (CONF_ITEM *)&cp_find;
118
0
    break;
119
120
0
  case CONF_ITEM_DATA:
121
0
    memset(&cd_find, 0, sizeof(cd_find));
122
0
    cd_find.item.type = CONF_ITEM_DATA;
123
0
    cd_find.type = ident1;
124
0
    if (!IS_WILDCARD(ident2)) cd_find.name = ident2;
125
126
0
    find = (CONF_ITEM *)&cd_find;
127
0
    break;
128
129
0
  default:
130
0
    fr_assert_fail(NULL);
131
0
    return NULL;
132
0
  }
133
134
  /*
135
   *  No ident1, iterate over the child list
136
   */
137
0
  if (IS_WILDCARD(ident1)) {
138
0
    cf_item_foreach(parent, ci) {
139
0
      if (find->type != ci->type) continue;
140
141
0
      if (cf_ident2_cmp(find, ci) == 0) return ci;
142
0
    }
143
144
0
    return NULL;
145
0
  }
146
147
  /*
148
   *  No ident2, use the ident1 tree.
149
   */
150
0
  if (IS_WILDCARD(ident2)) return fr_rb_find(parent->ident1, find);
151
152
  /*
153
   *  Only sections have an ident2 tree.
154
   */
155
0
  if (parent->type != CONF_ITEM_SECTION) return NULL;
156
157
  /*
158
   *  Both ident1 and ident2 use the ident2 tree.
159
   */
160
0
  return fr_rb_find(parent->ident2, find);
161
0
}
162
163
/** Return the next child that's of the specified type with the specified identifiers
164
 *
165
 * @param[in] parent  The section we're searching in.
166
 * @param[in] prev  item we found, or NULL to start from the beginning.
167
 * @param[in] type  of #CONF_ITEM we're searching for.
168
 * @param[in] ident1  The first identifier.
169
 * @param[in] ident2  The second identifier. Special value CF_IDENT_ANY
170
 *      can be used to match any ident2 value.
171
 * @return
172
 *  - The first matching item.
173
 *  - NULL if no items matched.
174
 */
175
static CONF_ITEM *cf_find_next(CONF_ITEM const *parent, CONF_ITEM const *prev,
176
             CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
177
0
{
178
0
  CONF_SECTION  cs_find;
179
0
  CONF_PAIR cp_find;
180
0
  CONF_DATA cd_find;
181
0
  CONF_ITEM *find;
182
183
0
  if (!parent) return NULL;
184
185
0
  if (!prev) {
186
0
    if (!ident1) return cf_next(parent, NULL, type);
187
0
    return cf_find(parent, type, ident1, ident2);
188
0
  }
189
0
  if (!ident1) return cf_next(parent, prev, type);
190
191
0
  switch (type) {
192
0
  case CONF_ITEM_SECTION:
193
0
    memset(&cs_find, 0, sizeof(cs_find));
194
0
    cs_find.item.type = CONF_ITEM_SECTION;
195
0
    cs_find.name1 = ident1;
196
0
    if (!IS_WILDCARD(ident2)) cs_find.name2 = ident2;
197
198
0
    find = (CONF_ITEM *)&cs_find;
199
0
    break;
200
201
0
  case CONF_ITEM_PAIR:
202
0
    fr_assert((ident2 == NULL) || IS_WILDCARD(ident2));
203
204
0
    memset(&cp_find, 0, sizeof(cp_find));
205
0
    cp_find.item.type = CONF_ITEM_PAIR;
206
0
    cp_find.attr = ident1;
207
208
0
    find = (CONF_ITEM *)&cp_find;
209
0
    break;
210
211
0
  case CONF_ITEM_DATA:
212
0
    memset(&cd_find, 0, sizeof(cd_find));
213
0
    cd_find.item.type = CONF_ITEM_DATA;
214
0
    cd_find.type = ident1;
215
0
    if (!IS_WILDCARD(ident2)) cd_find.name = ident2;
216
217
0
    find = (CONF_ITEM *)&cd_find;
218
0
    break;
219
220
0
  default:
221
0
    fr_assert_fail(NULL);
222
0
    return NULL;
223
0
  }
224
225
0
  if (IS_WILDCARD(ident1)) {
226
0
    cf_item_foreach_next(parent, ci, prev) {
227
0
      if (find->type != ci->type) continue;
228
229
0
      if (cf_ident2_cmp(find, ci) == 0) return ci;
230
0
    }
231
232
0
    return NULL;
233
0
  }
234
235
0
  if (IS_WILDCARD(ident2)) {
236
0
    cf_item_foreach_next(parent, ci, prev) {
237
0
         if (_cf_ident1_cmp(ci, find) == 0) return ci;
238
239
0
    }
240
241
0
    return NULL;
242
0
  }
243
244
0
  cf_item_foreach_next(parent, ci, prev) {
245
0
    if (_cf_ident2_cmp(ci, find) == 0) return ci;
246
0
  }
247
248
0
  return NULL;
249
0
}
250
251
/** Compare the first identifier of a child
252
 *
253
 * For CONF_ITEM_PAIR this is 'attr'.
254
 * For CONF_ITEM_SECTION this is 'name1'.
255
 * For CONF_ITEM_DATA this is 'type'.
256
 *
257
 * @param[in] one First CONF_ITEM to compare.
258
 * @param[in] two Second CONF_ITEM to compare.
259
 * @return CMP(one, two)
260
 */
261
static inline int8_t _cf_ident1_cmp(void const *one, void const *two)
262
0
{
263
0
  int ret;
264
265
0
  CONF_ITEM_TYPE type;
266
267
0
  {
268
0
    CONF_ITEM const *a = one;
269
0
    CONF_ITEM const *b = two;
270
271
0
    CMP_RETURN(a, b, type);
272
0
    type = a->type;
273
0
  }
274
275
0
  switch (type) {
276
0
  case CONF_ITEM_PAIR:
277
0
  {
278
0
    CONF_PAIR const *a = one;
279
0
    CONF_PAIR const *b = two;
280
281
0
    ret = strcmp(a->attr, b->attr);
282
0
    return CMP(ret, 0);
283
0
  }
284
285
0
  case CONF_ITEM_SECTION:
286
0
  {
287
0
    CONF_SECTION const *a = one;
288
0
    CONF_SECTION const *b = two;
289
290
0
    ret = strcmp(a->name1, b->name1);
291
0
    return CMP(ret, 0);
292
0
  }
293
294
0
  case CONF_ITEM_DATA:
295
0
  {
296
0
    CONF_DATA const *a = one;
297
0
    CONF_DATA const *b = two;
298
299
0
    ret = strcmp(a->type, b->type);
300
0
    return CMP(ret, 0);
301
0
  }
302
303
0
  default:
304
0
    fr_assert_fail(NULL);
305
0
    return 0;
306
0
  }
307
0
}
308
309
/** Compare only the second identifier of a child
310
 *
311
 * For CONF_ITEM_SECTION this is 'name2'.
312
 * For CONF_ITEM_DATA this is 'name'.
313
 *
314
 * @param[in] one First CONF_ITEM to compare.
315
 * @param[in] two Second CONF_ITEM to compare.
316
 * @return CMP(one,two)
317
 */
318
static inline int8_t cf_ident2_cmp(void const *one, void const *two)
319
0
{
320
0
  CONF_ITEM const *ci = one;
321
0
  int ret;
322
323
0
  switch (ci->type) {
324
0
  case CONF_ITEM_PAIR:
325
0
    return 0;
326
327
0
  case CONF_ITEM_SECTION:
328
0
  {
329
0
    CONF_SECTION const *a = one;
330
0
    CONF_SECTION const *b = two;
331
332
0
    if (!b->name2 && a->name2) return +1;
333
0
    if (b->name2 && !a->name2) return -1;
334
0
    if (!b->name2 && !a->name2) return 0;
335
336
0
    ret = strcmp(a->name2, b->name2);
337
0
    return CMP(ret, 0);
338
0
  }
339
340
0
  case CONF_ITEM_DATA:
341
0
  {
342
0
    CONF_DATA const *a = one;
343
0
    CONF_DATA const *b = two;
344
345
0
    if (!b->name && a->name) return +1;
346
0
    if (b->name && !a->name) return -1;
347
0
    if (!b->name && !a->name) return 0;
348
349
0
    ret = strcmp(a->name, b->name);
350
0
    return CMP(ret, 0);
351
0
  }
352
353
0
  default:
354
0
    fr_assert_fail(NULL);
355
0
    return 0;
356
0
  }
357
0
}
358
359
/** Compare the first and second identifiers of a child
360
 *
361
 * For CONF_ITEM_SECTION this is 'name2'.
362
 * For CONF_ITEM_DATA this is 'name'.
363
 *
364
 * @param[in] a First CONF_ITEM to compare.
365
 * @param[in] b Second CONF_ITEM to compare.
366
 * @return CMP(a, b)
367
 */
368
static int8_t _cf_ident2_cmp(void const *a, void const *b)
369
0
{
370
0
  int ret;
371
372
0
  ret = _cf_ident1_cmp(a, b);
373
0
  if (ret != 0) return ret;
374
375
0
  return cf_ident2_cmp(a, b);
376
0
}
377
378
/** Add a child
379
 *
380
 * @param[in] parent  to add child to.
381
 * @param[in] child to add.
382
 */
383
void _cf_item_add(CONF_ITEM *parent, CONF_ITEM *child)
384
0
{
385
0
  fr_assert(parent != child);
386
387
0
  if (!parent || !child) return;
388
389
  /*
390
   *  New child, add child trees.
391
   */
392
0
  if (!parent->ident1) parent->ident1 = fr_rb_inline_alloc(parent, CONF_ITEM, ident1_node,
393
0
                 _cf_ident1_cmp, NULL);
394
0
  fr_rb_insert(parent->ident1, child);
395
0
  fr_dlist_insert_tail(&parent->children, child); /* Append to the list of children */
396
397
0
  if (parent->type != CONF_ITEM_SECTION) return; /* Only sections can have ident2 trees */
398
399
0
  if (!parent->ident2) parent->ident2 = fr_rb_inline_alloc(parent, CONF_ITEM, ident2_node,
400
0
                 _cf_ident2_cmp, NULL);
401
0
  fr_rb_insert(parent->ident2, child);    /* NULL ident2 is still a value */
402
0
}
403
404
/** Insert a child after a given one
405
 *
406
 * @param[in] parent  to add child to.
407
 * @param[in] prev  previous
408
 * @param[in] child to add.
409
 */
410
void _cf_item_insert_after(CONF_ITEM *parent, CONF_ITEM *prev, CONF_ITEM *child)
411
0
{
412
0
  fr_assert(parent != child);
413
0
  fr_assert(prev != child);
414
415
  /*
416
   *  Must be given something.  Can't insert at HEAD.
417
   */
418
0
  if (!parent || !child) return;
419
420
0
  if (!prev) {
421
0
    cf_item_add(parent, child);
422
0
    return;
423
0
  }
424
425
  /*
426
   *  If there's a prev, then the ident trees must be there.
427
   */
428
0
  fr_assert(parent->ident1 != NULL);
429
430
0
  fr_rb_insert(parent->ident1, child);
431
0
  fr_dlist_insert_after(&parent->children, prev, child);  /* insert in the list of children */
432
433
0
  if (parent->type != CONF_ITEM_SECTION) return;   /* only sections can have ident2 trees */
434
435
0
  fr_assert(parent->ident2 != NULL);
436
0
  fr_rb_insert(parent->ident2, child);      /* NULL ident2 is still a value */
437
0
}
438
439
440
/** Remove item from parent and fixup trees
441
 *
442
 * @param[in] parent  to remove child from.
443
 * @param[in] child to remove.
444
 * @return
445
 *  - The previous item (makes iteration easier)
446
 *  - NULL if the item wasn't set.
447
 */
448
CONF_ITEM *_cf_item_remove(CONF_ITEM *parent, CONF_ITEM *child)
449
0
{
450
0
  CONF_ITEM *found = NULL;
451
0
  CONF_ITEM *prev;
452
0
  bool    in_ident1, in_ident2;
453
454
0
  if (!parent || cf_item_has_no_children(parent)) return NULL;
455
0
  if (parent != child->parent) return NULL;
456
457
0
  cf_item_foreach(parent, ci) {
458
0
    if (ci == child) {
459
0
      found = ci;
460
0
      break;
461
0
    }
462
0
  }
463
464
0
  if (!found) return NULL;
465
466
  /*
467
   *  Fixup the linked list
468
   */
469
0
  prev = fr_dlist_remove(&parent->children, child);
470
471
0
  in_ident1 = (fr_rb_remove_by_inline_node(parent->ident1, &child->ident1_node) != NULL);
472
473
  /*
474
   *  Only sections can have ident2 trees.
475
   */
476
0
  if (parent->type != CONF_ITEM_SECTION) {
477
0
    in_ident2 = false;
478
0
  } else {
479
0
    in_ident2 = (fr_rb_remove_by_inline_node(parent->ident2, &child->ident2_node) != NULL);
480
0
  }
481
482
  /*
483
   *  Look for twins.  They weren't in the tree initially,
484
   *  because "child" was there.
485
   */
486
0
  cf_item_foreach(parent, ci) {
487
0
    if (!in_ident1 && !in_ident2) break;
488
489
0
    if (in_ident1 && (_cf_ident1_cmp(ci, child) == 0)) {
490
0
      fr_rb_insert(parent->ident1, ci);
491
0
      in_ident1 = false;
492
0
    }
493
494
0
    if (in_ident2 && (_cf_ident2_cmp(ci, child) == 0)) {
495
0
      fr_rb_insert(parent->ident2, ci);
496
0
      in_ident2 = false;
497
0
    }
498
0
  }
499
500
0
  return prev;
501
0
}
502
503
/** Return the next child of the CONF_ITEM
504
 *
505
 * @param[in] parent  to return children from.
506
 * @param[in] curr  child to start searching from.
507
 * @return
508
 *  - The next #CONF_ITEM that's a child of cs.
509
 *  - NULL if no more #CONF_ITEM.
510
 */
511
CONF_ITEM *_cf_item_next(CONF_ITEM const *parent, CONF_ITEM const *curr)
512
0
{
513
0
  if (!parent) return NULL;
514
515
0
  return fr_dlist_next(&parent->children, curr);
516
0
}
517
518
/** Return the next child of cs
519
 *
520
 * @param[in] ci  to return children from.
521
 * @param[in] curr  child to start searching from.
522
 * @return
523
 *  - The next #CONF_ITEM that's a child of cs.
524
 *  - NULL if no more #CONF_ITEM.
525
 */
526
CONF_ITEM *_cf_item_prev(CONF_ITEM const *ci, CONF_ITEM const *curr)
527
0
{
528
0
  if (!ci) return NULL;
529
530
0
  return fr_dlist_prev(&ci->children, curr);
531
0
}
532
533
/** Initialize a CONF_ITEM, so we don't have repeated code
534
 *
535
 * @param[in] ci  the CONF_ITEM to initialize
536
 * @param[in] type  the type to set
537
 * @param[in] parent  the parent node hosting this one
538
 * @param[in] filename  which caused this node to be created
539
 * @param[in] lineno  where in the filename
540
 */
541
static void cf_item_init(CONF_ITEM *ci, CONF_ITEM_TYPE type, CONF_ITEM *parent, char const *filename, int lineno)
542
0
{
543
0
  ci->type = type;
544
0
  ci->parent = parent;
545
546
0
  fr_dlist_init(&ci->children, CONF_ITEM, entry);
547
548
0
  if (filename) cf_filename_set(ci, filename);
549
0
  if (lineno) cf_lineno_set(ci, lineno);
550
0
}
551
552
/** Return the top level #CONF_SECTION holding all other #CONF_ITEM
553
 *
554
 * @param[in] ci  to traverse up from.
555
 * @return
556
 *  - NULL if ci was NULL.
557
 *  - The top level #CONF_SECTION
558
 */
559
CONF_SECTION *_cf_root(CONF_ITEM const *ci)
560
0
{
561
0
  CONF_ITEM const *ci_p;
562
563
0
  if (!ci) return NULL;
564
565
0
  for (ci_p = ci; ci_p->parent; ci_p = ci_p->parent);
566
567
0
  return cf_item_to_section(ci_p);
568
0
}
569
570
/** Return the parent of a #CONF_ITEM
571
 *
572
 * @param[in] ci  to return the parent of.
573
 * @return
574
 *  - NULL if ci was NULL or it has no parents.
575
 *  - The parent of ci.
576
 */
577
CONF_ITEM *_cf_parent(CONF_ITEM const *ci)
578
0
{
579
0
  if (!ci) return NULL;
580
581
0
  return ci->parent;
582
0
}
583
584
/** Return the lineno the #CONF_ITEM was parsed at
585
 *
586
 * @param[in] ci  to return the location of.
587
 * @return
588
 *  - -1 if the #CONF_ITEM was created programmatically.
589
 *  - >= 0 where in the config file the line was parsed from.
590
 */
591
int _cf_lineno(CONF_ITEM const *ci)
592
0
{
593
0
  if (!ci) return -1;
594
595
0
  return ci->lineno;
596
0
}
597
598
/** Return the filename the #CONF_ITEM was parsed in
599
 *
600
 * @param[in] ci  to return the location of.
601
 * @return
602
 *  - NULL if the #CONF_ITEM was created programmatically.
603
 *  - The path of the config file the #CONF_ITEM was located in.
604
 */
605
char const *_cf_filename(CONF_ITEM const *ci)
606
0
{
607
0
  if (!ci) return NULL;
608
609
0
  return ci->filename;
610
0
}
611
612
/** Determine if #CONF_ITEM is a #CONF_SECTION
613
 *
614
 * @param[in] ci  to check.
615
 * @return
616
 *  - true if ci is a #CONF_SECTION.
617
 *  - false if ci is another specialisation.
618
 */
619
bool cf_item_is_section(CONF_ITEM const *ci)
620
0
{
621
0
  if (!ci) return false;
622
623
0
  return ci->type == CONF_ITEM_SECTION;
624
0
}
625
626
/** Determine if #CONF_ITEM is a #CONF_PAIR
627
 *
628
 * @param[in] ci  to check.
629
 * @return
630
 *  - true if ci is a #CONF_PAIR.
631
 *  - false if ci is another specialisation.
632
 */
633
bool cf_item_is_pair(CONF_ITEM const *ci)
634
0
{
635
0
  if (!ci) return false;
636
637
0
  return ci->type == CONF_ITEM_PAIR;
638
0
}
639
640
/** Determine if #CONF_ITEM is #CONF_DATA
641
 *
642
 * @param[in] ci  to check.
643
 * @return
644
 *  - true if ci is #CONF_DATA.
645
 *  - false if ci is another specialisation.
646
 */
647
bool cf_item_is_data(CONF_ITEM const *ci)
648
0
{
649
0
  if (!ci) return false;
650
651
0
  return ci->type == CONF_ITEM_DATA;
652
0
}
653
654
/** Cast a #CONF_ITEM to a #CONF_PAIR
655
 *
656
 * @note Will assert if ci does not contain #CONF_PAIR.
657
 *
658
 * @param[in] ci  to cast.
659
 * @return
660
 *  - #CONF_PAIR.
661
 *  - NULL if ci was NULL.
662
 *
663
 * @hidecallergraph
664
 */
665
CONF_PAIR *cf_item_to_pair(CONF_ITEM const *ci)
666
0
{
667
0
  if (ci == NULL) return NULL;
668
669
0
  fr_assert(ci->type == CONF_ITEM_PAIR);
670
671
0
  return UNCONST(CONF_PAIR *, ci);
672
0
}
673
674
/** Cast a #CONF_ITEM to a #CONF_SECTION
675
 *
676
 * @note Will assert if ci does not contain #CONF_SECTION.
677
 *
678
 * @param[in] ci  to cast.
679
 * @return
680
 *  - #CONF_SECTION.
681
 *  - NULL if ci was NULL.
682
 *
683
 * @hidecallergraph
684
 */
685
CONF_SECTION *cf_item_to_section(CONF_ITEM const *ci)
686
0
{
687
0
  if (ci == NULL) return NULL;
688
689
0
  fr_assert(ci->type == CONF_ITEM_SECTION);
690
691
0
  return UNCONST(CONF_SECTION *, ci);
692
0
}
693
694
/** Cast #CONF_ITEM to #CONF_DATA performing a type check
695
 *
696
 * @note Will assert if ci does not contain #CONF_DATA.
697
 *
698
 * @param[in] ci  to cast.
699
 * @return
700
 *  - #CONF_DATA.
701
 *  - NULL if ci was NULL.
702
 *
703
 * @hidecallergraph
704
 */
705
CONF_DATA *cf_item_to_data(CONF_ITEM const *ci)
706
0
{
707
0
  if (ci == NULL) return NULL;
708
709
0
  fr_assert(ci->type == CONF_ITEM_DATA);
710
711
0
  return UNCONST(CONF_DATA *, ci);
712
0
}
713
714
/** Cast a #CONF_PAIR to a #CONF_ITEM
715
 *
716
 * @param[in] cp  to cast.
717
 * @return
718
 *  - The common #CONF_ITEM header.
719
 *  - NULL if cp was NULL.
720
 *
721
 * @hidecallergraph
722
 */
723
CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp)
724
0
{
725
0
  if (cp == NULL) return NULL;
726
727
0
  return UNCONST(CONF_ITEM *, cp);
728
0
}
729
730
/** Cast a #CONF_SECTION to a #CONF_ITEM
731
 *
732
 * @param[in] cs  to cast.
733
 * @return
734
 *  - The common #CONF_ITEM header.
735
 *  - NULL if cs was NULL.
736
 *
737
 * @hidecallergraph
738
 */
739
CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs)
740
0
{
741
0
  if (cs == NULL) return NULL;
742
743
0
  return UNCONST(CONF_ITEM *, cs);
744
0
}
745
746
/** Cast #CONF_DATA to a #CONF_ITEM
747
 *
748
 * @param[in] cd  to cast.
749
 * @return
750
 *  - The common #CONF_ITEM header.
751
 *  - NULL if cd was NULL.
752
 *
753
 * @hidecallergraph
754
 */
755
CONF_ITEM *cf_data_to_item(CONF_DATA const *cd)
756
0
{
757
0
  if (cd == NULL) return NULL;
758
759
0
  return UNCONST(CONF_ITEM *, cd);
760
0
}
761
762
/** Free a section and associated trees
763
 *
764
 * @param[in] cs  to free.
765
 * @return 0
766
 */
767
static int _cf_section_free(CONF_SECTION *cs)
768
0
{
769
0
  if (cs->item.ident1) TALLOC_FREE(cs->item.ident1);
770
0
  if (cs->item.ident2) TALLOC_FREE(cs->item.ident2);
771
772
0
  return 0;
773
0
}
774
775
/** Allocate a #CONF_SECTION
776
 *
777
 * @param[in] ctx to allocate
778
 * @param[in] parent  #CONF_SECTION to hang this #CONF_SECTION off of.
779
 *      If parent is not NULL, the new section will be added as a child.
780
 * @param[in] name1 Primary name.
781
 * @param[in] name2 Secondary name.
782
 * @param[in] filename  Caller file name for debugging.  May be overridden later.
783
 * @param[in] lineno  Caller line number for debugging.  May be overridden later.
784
 * @return
785
 *  - NULL on error.
786
 *  - A new #CONF_SECTION parented by parent.
787
 */
788
CONF_SECTION *_cf_section_alloc(TALLOC_CTX *ctx, CONF_SECTION *parent,
789
        char const *name1, char const *name2,
790
        char const *filename, int lineno)
791
0
{
792
0
  CONF_SECTION  *cs;
793
0
  char    buffer[1024];
794
795
0
  if (!name1) return NULL;
796
797
0
  if (name2 && parent) {
798
0
    char const *p;
799
800
0
    p = strchr(name2, '$');
801
0
    if (p && (p[1] != '{')) p = NULL;
802
803
0
    if (p) {
804
0
      name2 = cf_expand_variables(parent->item.filename,
805
0
                parent->item.lineno,
806
0
                parent,
807
0
                buffer, sizeof(buffer), name2, -1, NULL, false);
808
809
0
      if (!name2) {
810
0
        ERROR("Failed expanding section name");
811
0
        return NULL;
812
0
      }
813
0
    }
814
0
  }
815
816
0
  cs = talloc_zero(ctx, CONF_SECTION);
817
0
  if (!cs) return NULL;
818
819
0
  cf_item_init(cf_section_to_item(cs), CONF_ITEM_SECTION, cf_section_to_item(parent), filename, lineno);
820
821
0
  MEM(cs->name1 = talloc_strdup(cs, name1));
822
0
  if (name2) {
823
0
    MEM(cs->name2 = talloc_strdup(cs, name2));
824
0
    cs->name2_quote = T_BARE_WORD;
825
0
  }
826
0
  talloc_set_destructor(cs, _cf_section_free);
827
828
0
  if (parent) {
829
0
    CONF_DATA const *cd;
830
0
    conf_parser_t *rule;
831
832
    /*
833
     *  Look up the parents parsing rules for itself.
834
     *  If there are rules, then one of them might be
835
     *  parsing rules for this new child.  If that
836
     *  happens, we push the child parsing rules to
837
     *  this new child.
838
     */
839
0
    cd = cf_data_find(CF_TO_ITEM(parent), conf_parser_t, cf_section_name1(parent));
840
0
    if (cd) {
841
0
      rule = cf_data_value(cd);
842
843
0
      if ((rule->flags & CONF_FLAG_SUBSECTION) &&
844
0
          rule->on_read && rule->subcs) {
845
0
        conf_parser_t const *rule_p;
846
847
0
        for (rule_p = rule->subcs; rule_p->name1; rule_p++) {
848
0
          if ((rule_p->flags & CONF_FLAG_SUBSECTION) &&
849
0
              rule_p->on_read &&
850
0
              (strcmp(rule_p->name1, name1) == 0)) {
851
0
            if (_cf_section_rule_push(cs, rule_p,
852
0
                    cd->item.filename, cd->item.lineno) < 0) {
853
0
            error:
854
0
              talloc_free(cs);
855
0
              return NULL;
856
0
            }
857
858
0
            if (rule_p->on_read(ctx, NULL, NULL,
859
0
                 cf_section_to_item(cs), rule_p) < 0) goto error;
860
0
            goto done;
861
0
          }
862
0
        }
863
0
      }
864
0
    }
865
866
    /*
867
     *  Or, the parent may already have parse rules
868
     *  for this new child.  In which case we push the
869
     *  child rules for this section, and then do the
870
     *  on_read callback.
871
     */
872
0
    cd = cf_data_find(CF_TO_ITEM(parent), conf_parser_t, name1);
873
0
    if (cd) {
874
0
      rule = cf_data_value(cd);
875
0
      if ((rule->flags & CONF_FLAG_SUBSECTION) &&
876
0
          rule->on_read) {
877
0
        if (cf_section_rules_push(cs, rule->subcs) < 0) goto error;
878
0
        if (rule->on_read(ctx, NULL, NULL, cf_section_to_item(cs), rule) < 0) goto error;
879
0
      }
880
0
    }
881
882
0
  done:
883
0
    cs->depth = parent->depth + 1;
884
0
    cf_item_add(parent, &(cs->item));
885
0
  }
886
887
0
  return cs;
888
0
}
889
890
/** Set the filename of a #CONF_ITEM
891
 *
892
 * @param[in] ci  to set filename on.
893
 * @param[in] filename  to set.
894
 */
895
void _cf_filename_set(CONF_ITEM *ci, char const *filename)
896
0
{
897
0
  talloc_const_free(ci->filename);
898
899
0
  ci->filename = talloc_strdup(ci, filename);
900
0
}
901
902
/** Set the line number of a #CONF_ITEM
903
 *
904
 * @param[in] ci  to set the lineno for.
905
 * @param[in] lineno  to set.
906
 */
907
void _cf_lineno_set(CONF_ITEM *ci, int lineno)
908
0
{
909
0
  ci->lineno = lineno;
910
0
}
911
912
/** Duplicate a configuration section
913
 *
914
 * @note recursively duplicates any child sections.
915
 * @note does not duplicate any data associated with a section, or its child sections.
916
 *
917
 * @param[in] ctx to allocate memory in.
918
 * @param[in] parent  section (may be NULL).
919
 * @param[in] cs  to duplicate.
920
 * @param[in] name1 of new section.
921
 * @param[in] name2 of new section.
922
 * @param[in] copy_meta Copy additional meta data for a section
923
 *      (like template, base, depth, parsed state,
924
 *      and variables).
925
 * @return
926
 *  - A duplicate of the existing section.
927
 *  - NULL on error.
928
 */
929
CONF_SECTION *cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs,
930
           char const *name1, char const *name2, bool copy_meta)
931
0
{
932
0
  CONF_SECTION  *new, *subcs;
933
0
  CONF_PAIR *cp;
934
935
0
  new = cf_section_alloc(ctx, parent, name1, name2);
936
937
0
  if (copy_meta) {
938
0
    new->template = cs->template;
939
0
    new->base = cs->base;
940
0
    new->depth = cs->depth;
941
0
  }
942
943
0
  cf_filename_set(new, cs->item.filename);
944
0
  cf_lineno_set(new, cs->item.lineno);
945
946
0
  cf_item_foreach(&cs->item, ci) {
947
0
    switch (ci->type) {
948
0
    case CONF_ITEM_SECTION:
949
0
      subcs = cf_item_to_section(ci);
950
0
      subcs = cf_section_dup(new, new, subcs,
951
0
                 cf_section_name1(subcs), cf_section_name2(subcs),
952
0
                 copy_meta);
953
0
      if (!subcs) {
954
0
        talloc_free(new);
955
0
        return NULL;
956
0
      }
957
0
      break;
958
959
0
    case CONF_ITEM_PAIR:
960
0
      cp = cf_pair_dup(new, cf_item_to_pair(ci), copy_meta);
961
0
      if (!cp) {
962
0
        talloc_free(new);
963
0
        return NULL;
964
0
      }
965
0
      break;
966
967
0
    case CONF_ITEM_DATA: /* Skip data */
968
0
      break;
969
970
0
    case CONF_ITEM_INVALID:
971
0
      fr_assert(0);
972
0
    }
973
0
  }
974
975
0
  return new;
976
0
}
977
978
/** Return the first child in a CONF_SECTION
979
 *
980
 * @param[in] cs  to return children from.
981
 * @return
982
 *  - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
983
 *  - NULL if no #CONF_ITEM matches that criteria.
984
 */
985
CONF_SECTION *cf_section_first(CONF_SECTION const *cs)
986
0
{
987
0
  return cf_item_to_section(cf_next(cf_section_to_item(cs), NULL, CONF_ITEM_SECTION));
988
0
}
989
990
/** Return the next child that's a #CONF_SECTION
991
 *
992
 * @param[in] cs  to return children from.
993
 * @param[in] curr  child to start searching from.
994
 * @return
995
 *  - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
996
 *  - NULL if no #CONF_ITEM matches that criteria.
997
 */
998
CONF_SECTION *cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *curr)
999
0
{
1000
0
  return cf_item_to_section(cf_next(cf_section_to_item(cs), cf_section_to_item(curr), CONF_ITEM_SECTION));
1001
0
}
1002
1003
/** Return the previous child that's a #CONF_SECTION
1004
 *
1005
 * @param[in] cs  to return children from.
1006
 * @param[in] curr  child to start searching from.
1007
 * @return
1008
 *  - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
1009
 *  - NULL if no #CONF_ITEM matches that criteria.
1010
 */
1011
CONF_SECTION *cf_section_prev(CONF_SECTION const *cs, CONF_SECTION const *curr)
1012
0
{
1013
0
  return cf_item_to_section(cf_prev(cf_section_to_item(cs), cf_section_to_item(curr), CONF_ITEM_SECTION));
1014
0
}
1015
1016
/** Find a CONF_SECTION with name1 and optionally name2.
1017
 *
1018
 * @param[in] cs  The section we're searching in.
1019
 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1020
 *      can be used to match any name1 value.
1021
 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1022
 *      can be used to match any name2 value.
1023
 * @return
1024
 *  - The first matching subsection.
1025
 *  - NULL if no subsections match.
1026
 *
1027
 * @hidecallergraph
1028
 */
1029
CONF_SECTION *cf_section_find(CONF_SECTION const *cs,
1030
            char const *name1, char const *name2)
1031
0
{
1032
0
  return cf_item_to_section(cf_find(cf_section_to_item(cs), CONF_ITEM_SECTION, name1, name2));
1033
0
}
1034
1035
/** Return the next matching section
1036
 *
1037
 * @param[in] cs  The section we're searching in.
1038
 * @param[in] prev  section we found.  May be NULL in which case
1039
 *      we just return the next section after prev.
1040
 * @param[in] name1 of the section we're searching for.  Special value CF_IDENT_ANY
1041
 *      can be used to match any name1 value.
1042
 * @param[in] name2 of the section we're searching for.  Special value CF_IDENT_ANY
1043
 *      can be used to match any name2 value.
1044
 * @return
1045
 *  - The next CONF_SECTION.
1046
 *  - NULL if there are no more CONF_SECTIONs
1047
 *
1048
 * @hidecallergraph
1049
 */
1050
CONF_SECTION *cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev,
1051
           char const *name1, char const *name2)
1052
0
{
1053
0
  return cf_item_to_section(cf_find_next(cf_section_to_item(cs), cf_section_to_item(prev),
1054
0
                 CONF_ITEM_SECTION, name1, name2));
1055
0
}
1056
1057
/** Find an ancestor of the passed CONF_ITEM which has a child matching a specific name1 and optionally name2.
1058
 *
1059
 * @note Despite the name, this function also searches in ci for a matching item.
1060
 *
1061
 * Will walk up the configuration tree, searching in each parent until a matching section is found or
1062
 * we hit the root.
1063
 *
1064
 * @param[in] ci  The conf item we're searching back from.
1065
 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1066
 *      can be used to match any name1 value.
1067
 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1068
 *      can be used to match any name2 value.
1069
 * @return
1070
 *  - The first matching subsection.
1071
 *  - NULL if no subsections match.
1072
 */
1073
CONF_SECTION *_cf_section_find_in_parent(CONF_ITEM const *ci,
1074
                 char const *name1, char const *name2)
1075
0
{
1076
0
  do {
1077
0
    CONF_ITEM *found;
1078
1079
0
    found = cf_find(ci, CONF_ITEM_SECTION, name1, name2);
1080
0
    if (found) return cf_item_to_section(found);
1081
0
  } while ((ci = cf_parent(ci)));
1082
1083
0
  return NULL;
1084
0
}
1085
1086
/** Find a parent CONF_SECTION with name1 and optionally name2.
1087
 *
1088
 * @param[in] ci  The section we're searching in.
1089
 * @param[in] name1 of the section we're searching for. Special value CF_IDENT_ANY
1090
 *      can be used to match any name1 value.
1091
 * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
1092
 *      can be used to match any name2 value.
1093
 * @return
1094
 *  - The first matching subsection.
1095
 *  - NULL if no subsections match.
1096
 */
1097
CONF_SECTION *_cf_section_find_parent(CONF_ITEM const *ci,
1098
              char const *name1, char const *name2)
1099
0
{
1100
0
  while ((ci = cf_parent(ci))) {
1101
0
    CONF_SECTION *found;
1102
1103
0
    if (!cf_item_is_section(ci)) continue; /* Could be data hanging off a pair*/
1104
1105
0
    found = cf_item_to_section(ci);
1106
1107
0
    if (cf_section_name_cmp(found, name1, name2) == 0) return found;
1108
0
  }
1109
1110
0
  return NULL;
1111
0
}
1112
1113
/** Find a pair in a #CONF_SECTION
1114
 *
1115
 * @param[in] cs  the #CONF_SECTION to search in.
1116
 * @param[in] attr  to search for.
1117
 * @return
1118
 *  - NULL if no pair can be found.
1119
 *  - The value of the pair found.
1120
 */
1121
char const *cf_section_value_find(CONF_SECTION const *cs, char const *attr)
1122
0
{
1123
0
  CONF_PAIR *cp;
1124
1125
0
  cp = cf_pair_find(cs, attr);
1126
1127
0
  return (cp ? cp->value : NULL);
1128
0
}
1129
1130
/** Check if a given section matches the specified name1/name2 identifiers
1131
 *
1132
 * @param[in] cs  to check.
1133
 * @param[in] name1 identifier.  May be CF_IDENT_ANY for wildcard matches.
1134
 * @param[in] name2 identifier.  May be CF_IDENT_ANY for wildcard matches.
1135
 * @return
1136
 *  - >1 if cs is greater than the identifiers.
1137
 *  - 0 if cs matches the identifiers.
1138
 *  - <0 if cs is less than the identifiers.
1139
 */
1140
int8_t cf_section_name_cmp(CONF_SECTION const *cs, char const *name1, char const *name2)
1141
0
{
1142
0
  int8_t ret;
1143
1144
0
  if (name1 != CF_IDENT_ANY) {
1145
0
    ret = CMP(strcmp(cf_section_name1(cs), name1), 0);
1146
0
    if (ret != 0) return ret;
1147
0
  }
1148
1149
0
  if (name2 != CF_IDENT_ANY) {
1150
0
    char const *cs_name2 = cf_section_name2(cs);
1151
1152
0
    if (!cs_name2) {
1153
0
      if (!name2) return 0;
1154
0
      return 1;
1155
0
    }
1156
0
    if (!name2) return -1;
1157
1158
0
    return CMP(strcmp(cs_name2, name2), 0);
1159
0
  }
1160
1161
0
  return 0;
1162
0
}
1163
1164
/** Return the first identifier of a #CONF_SECTION
1165
 *
1166
 * @param[in] cs  to return identifiers for.
1167
 * @return
1168
 *  - The first identifier.
1169
 *  - NULL if cs was NULL or no name1 set.
1170
 *
1171
 * @hidecallergraph
1172
 */
1173
char const *cf_section_name1(CONF_SECTION const *cs)
1174
0
{
1175
0
  return (cs ? cs->name1 : NULL);
1176
0
}
1177
1178
/** Return the second identifier of a #CONF_SECTION
1179
 *
1180
 * @param[in] cs  to return identifiers for.
1181
 * @return
1182
 *  - The second identifier.
1183
 *  - NULL if cs was NULL or no name2 set.
1184
 *
1185
 * @hidecallergraph
1186
 */
1187
char const *cf_section_name2(CONF_SECTION const *cs)
1188
0
{
1189
0
  return (cs ? cs->name2 : NULL);
1190
0
}
1191
1192
/** Return name2 if set, else name1
1193
 *
1194
 * @param[in] cs  to return identifiers for.
1195
 * @return name1 or name2 identifier.
1196
 *
1197
 * @hidecallergraph
1198
 */
1199
char const *cf_section_name(CONF_SECTION const *cs)
1200
0
{
1201
0
  char const *name;
1202
1203
0
  name = cf_section_name2(cs);
1204
0
  if (name) return name;
1205
1206
0
  return cf_section_name1(cs);
1207
0
}
1208
1209
/** Return variadic argument at the specified index
1210
 *
1211
 * @param[in] cs  containing the arguments.
1212
 * @param[in] argc  Argument index. Note name1 and name2 are not counted in this index.
1213
 * @return the argument value or NULL.
1214
 */
1215
char const *cf_section_argv(CONF_SECTION const *cs, int argc)
1216
0
{
1217
0
  if (!cs || !cs->argv || (argc < 0) || (argc >= cs->argc)) return NULL;
1218
1219
0
  return cs->argv[argc];
1220
0
}
1221
1222
/** Return the quoting of the name2 identifier
1223
 *
1224
 * @param[in] cs  containing name2.
1225
 * @return
1226
 *  - #T_BARE_WORD.
1227
 *  - #T_SINGLE_QUOTED_STRING.
1228
 *  - #T_BACK_QUOTED_STRING.
1229
 *  - #T_DOUBLE_QUOTED_STRING.
1230
 *  - #T_INVALID if cs was NULL.
1231
 */
1232
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
1233
0
{
1234
0
  if (!cs) return T_INVALID;
1235
1236
0
  return cs->name2_quote;
1237
0
}
1238
1239
/** Return the quoting for one of the variadic arguments
1240
 *
1241
 * @param[in] cs  containing the arguments.
1242
 * @param[in] argc  Argument index.  Note name1 and name2 are not counted in this index.
1243
 * @return
1244
 *  - #T_BARE_WORD.
1245
 *  - #T_SINGLE_QUOTED_STRING.
1246
 *  - #T_BACK_QUOTED_STRING.
1247
 *  - #T_DOUBLE_QUOTED_STRING.
1248
 *  - #T_INVALID if cs was NULL or the index was invalid.
1249
 */
1250
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
1251
0
{
1252
0
  if (!cs || !cs->argv_quote || (argc < 0) || (argc >= cs->argc)) return T_INVALID;
1253
1254
0
  return cs->argv_quote[argc];
1255
0
}
1256
1257
/** Allocate a #CONF_PAIR
1258
 *
1259
 * @param[in] parent    #CONF_SECTION to hang this #CONF_PAIR off of.
1260
 * @param[in] attr    name.
1261
 * @param[in] value   of #CONF_PAIR.
1262
 * @param[in] op    #T_OP_EQ, #T_OP_SET etc.
1263
 * @param[in] lhs_quote   #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
1264
 * @param[in] rhs_quote   #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
1265
 * @return
1266
 *  - NULL on error.
1267
 *  - A new #CONF_SECTION parented by parent.
1268
 */
1269
CONF_PAIR *cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
1270
       fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
1271
0
{
1272
0
  CONF_PAIR *cp;
1273
1274
0
  fr_assert(fr_comparison_op[op] || fr_assignment_op[op] || fr_binary_op[op]);
1275
0
  if (!attr) return NULL;
1276
1277
0
  cp = talloc_zero(parent, CONF_PAIR);
1278
0
  if (!cp) return NULL;
1279
1280
0
  cf_item_init(cf_pair_to_item(cp), CONF_ITEM_PAIR, cf_section_to_item(parent), NULL, 0);
1281
1282
0
  cp->lhs_quote = lhs_quote;
1283
0
  cp->rhs_quote = rhs_quote;
1284
0
  cp->op = op;
1285
1286
0
  cp->attr = talloc_strdup(cp, attr);
1287
0
  if (!cp->attr) {
1288
0
  error:
1289
0
    talloc_free(cp);
1290
0
    return NULL;
1291
0
  }
1292
1293
0
  if (value) {
1294
0
    cp->value = talloc_strdup(cp, value);
1295
0
    if (!cp->value) goto error;
1296
0
  }
1297
1298
0
  cf_item_add(parent, &(cp->item));
1299
0
  return cp;
1300
0
}
1301
1302
/** Duplicate a #CONF_PAIR
1303
 *
1304
 * @param parent  to allocate new pair in.
1305
 * @param cp    to duplicate.
1306
 * @param copy_meta Copy additional meta data for a pair
1307
 * @return
1308
 *  - NULL on error.
1309
 *  - A duplicate of the input pair.
1310
 */
1311
CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp, bool copy_meta)
1312
0
{
1313
0
  CONF_PAIR *new;
1314
1315
0
  fr_assert(parent);
1316
0
  fr_assert(cp);
1317
1318
0
  new = cf_pair_alloc(parent, cp->attr, cf_pair_value(cp), cp->op, cp->lhs_quote, cp->rhs_quote);
1319
0
  if (!new) return NULL;
1320
1321
0
  if (copy_meta) {
1322
0
    new->item.parsed = cp->item.parsed;
1323
0
    new->item.referenced = cp->item.referenced;
1324
0
  }
1325
0
  cf_lineno_set(new, cp->item.lineno);
1326
0
  cf_filename_set(new, cp->item.filename);
1327
1328
0
  return new;
1329
0
}
1330
1331
/** Replace pair value in a given section with the given value.
1332
 *
1333
 * @note A new pair with the same metadata as the #CONF_PAIR will be added
1334
 *  even if the #CONF_PAIR can't be found inside the #CONF_SECTION.
1335
 *
1336
 * @param[in] cs  to replace pair in.
1337
 * @param[in] cp  to replace.
1338
 * @param[in] value New value to assign to cp.
1339
 * @return
1340
 *  - 0 on success.
1341
 *  - -1 on failure.
1342
 */
1343
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
1344
{
1345
  if (!cs || !cp || !value) return -1;
1346
1347
  talloc_const_free(cp->value);
1348
1349
  MEM(cp->value = talloc_strdup(cp, value));
1350
1351
  return 0;
1352
}
1353
1354
1355
/** Mark an item as parsed
1356
 *
1357
 * @param[in] ci  to mark as parsed.
1358
 */
1359
void _cf_item_mark_parsed(CONF_ITEM *ci)
1360
0
{
1361
0
  ci->parsed = true;
1362
0
}
1363
1364
/** Return whether an item has already been parsed
1365
 *
1366
 * @param[in] ci  to check.
1367
 * @return
1368
 *  - true if item has been parsed.
1369
 *  - false if the pair hasn't been parsed.
1370
 */
1371
bool _cf_item_is_parsed(CONF_ITEM *ci)
1372
0
{
1373
0
  return ci->parsed;
1374
0
}
1375
1376
/** Return the first child that's a #CONF_PAIR
1377
 *
1378
 * @param[in] cs  to return children from.
1379
 * @return
1380
 *  - The first #CONF_ITEM that's a child of cs and a CONF_PAIR.
1381
 *  - NULL if no #CONF_ITEM matches that criteria.
1382
 */
1383
CONF_PAIR *cf_pair_first(CONF_SECTION const *cs)
1384
0
{
1385
0
  return cf_item_to_pair(cf_next(cf_section_to_item(cs), NULL, CONF_ITEM_PAIR));
1386
0
}
1387
1388
/** Return the next child that's a #CONF_PAIR
1389
 *
1390
 * @param[in] cs  to return children from.
1391
 * @param[in] curr  child to start searching from.
1392
 * @return
1393
 *  - The next #CONF_ITEM that's a child of cs and a CONF_PAIR.
1394
 *  - NULL if no #CONF_ITEM matches that criteria.
1395
 */
1396
CONF_PAIR *cf_pair_next(CONF_SECTION const *cs, CONF_PAIR const *curr)
1397
0
{
1398
0
  return cf_item_to_pair(cf_next(cf_section_to_item(cs), cf_pair_to_item(curr), CONF_ITEM_PAIR));
1399
0
}
1400
1401
/** Return the previous child that's a #CONF_PAIR
1402
 *
1403
 * @param[in] cs  to return children from.
1404
 * @param[in] curr  child to start searching from.
1405
 * @return
1406
 *  - The previous #CONF_ITEM that's a child of cs and a CONF_PAIR.
1407
 *  - NULL if no #CONF_ITEM matches that criteria.
1408
 */
1409
CONF_PAIR *cf_pair_prev(CONF_SECTION const *cs, CONF_PAIR const *curr)
1410
0
{
1411
0
  return cf_item_to_pair(cf_prev(cf_section_to_item(cs), cf_pair_to_item(curr), CONF_ITEM_PAIR));
1412
0
}
1413
1414
/** Search for a #CONF_PAIR with a specific name
1415
 *
1416
 * @param[in] cs  to search in.
1417
 * @param[in] attr  to find.
1418
 * @return
1419
 *  - The next matching #CONF_PAIR.
1420
 *  - NULL if none matched.
1421
 */
1422
CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *attr)
1423
0
{
1424
0
  return cf_item_to_pair(cf_find(cf_section_to_item(cs), CONF_ITEM_PAIR, attr, NULL));
1425
0
}
1426
1427
/** Find a pair with a name matching attr, after specified pair
1428
 *
1429
 * @param[in] cs  to search in.
1430
 * @param[in] prev  Pair to search from (may be NULL).
1431
 * @param[in] attr  to find (may be NULL in which case any attribute matches).
1432
 * @return
1433
 *  - The next matching #CONF_PAIR
1434
 *  - NULL if none matched.
1435
 */
1436
CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
1437
0
{
1438
0
  return cf_item_to_pair(cf_find_next(cf_section_to_item(cs), cf_pair_to_item(prev), CONF_ITEM_PAIR, attr, NULL));
1439
0
}
1440
1441
/** Find a pair with a name matching attr in the specified section or one of its parents
1442
 *
1443
 * @param[in] cs  to search in.  Will start in the current section
1444
 *      and work upwards.
1445
 * @param[in] attr  to find.
1446
 * @return
1447
 *  - A matching #CONF_PAIR.
1448
 *  - NULL if none matched.
1449
 */
1450
CONF_PAIR *cf_pair_find_in_parent(CONF_SECTION const *cs, char const *attr)
1451
0
{
1452
0
  CONF_ITEM const *parent = cf_section_to_item(cs);
1453
1454
0
  do {
1455
0
    CONF_ITEM *found;
1456
1457
0
    found = cf_find(parent, CONF_ITEM_PAIR, attr, NULL);
1458
0
    if (found) return cf_item_to_pair(found);
1459
0
  } while ((parent = cf_parent(parent)));
1460
1461
0
  return NULL;
1462
0
}
1463
1464
/** Callback to determine the number of pairs in a section
1465
 *
1466
 * @param[out] count  Where we store the number of pairs found.
1467
 * @param[in] cs  we're currently searching in.
1468
 */
1469
static void _pair_count(int *count, CONF_SECTION const *cs)
1470
0
{
1471
0
  CONF_ITEM const *ci = NULL;
1472
1473
0
  while ((ci = cf_item_next(cs, ci))) {
1474
0
    if (cf_item_is_section(ci)) {
1475
0
      _pair_count(count, cf_item_to_section(ci));
1476
0
      continue;
1477
0
    }
1478
1479
0
    (*count)++;
1480
0
  }
1481
0
}
1482
1483
/** Count the number of conf pairs beneath a section
1484
 *
1485
 * @param[in] cs to search for items in.
1486
 * @return The number of pairs nested within section.
1487
 */
1488
unsigned int cf_pair_count_descendents(CONF_SECTION const *cs)
1489
0
{
1490
0
  int count = 0;
1491
1492
0
  _pair_count(&count, cs);
1493
1494
0
  return count;
1495
0
}
1496
1497
/** Count the number of times an attribute occurs in a parent section
1498
 *
1499
 * @param[in] cs  to search for items in.
1500
 * @param[in] attr  to search for.
1501
 * @return The number of pairs of that attribute type.
1502
 */
1503
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
1504
0
{
1505
0
  size_t    i;
1506
0
  CONF_PAIR *cp = NULL;
1507
1508
0
  for (i = 0; (cp = cf_pair_find_next(cs, cp, attr)); i++);
1509
1510
0
  return i;
1511
0
}
1512
1513
/** Concatenate the values of any pairs with name attr
1514
 *
1515
 * @param[out] out  where to write the concatenated values.
1516
 * @param[in] cs  to search in.
1517
 * @param[in] attr  to search for.
1518
 * @param[in] sep to use to separate values
1519
 * @return
1520
 *      - Length of the data written to out on success.
1521
 *  - < 0 on failure.  Number of additional bytes required in buffer.
1522
 */
1523
fr_slen_t cf_pair_values_concat(fr_sbuff_t *out, CONF_SECTION const *cs, char const *attr, char const *sep)
1524
0
{
1525
0
  fr_sbuff_t    our_out = FR_SBUFF(out);
1526
0
  CONF_PAIR   *cp;
1527
0
  fr_slen_t   slen = 0;
1528
0
  fr_sbuff_escape_rules_t e_rules = {
1529
0
          .name = __FUNCTION__,
1530
0
          .chr = '\\'
1531
0
        };
1532
1533
0
  if (sep) e_rules.subs[(uint8_t)*sep] = *sep;
1534
1535
0
  for (cp = cf_pair_find(cs, attr); cp;) {
1536
0
    char const *value = cf_pair_value(cp);
1537
1538
0
    cp = cf_pair_find_next(cs, cp, attr);
1539
1540
0
    if (!value) continue;
1541
1542
0
    slen = fr_sbuff_in_escape(&our_out, value, strlen(value), &e_rules);
1543
0
    if (slen < 0) return slen;
1544
1545
0
    if (cp && sep) {
1546
0
      slen = fr_sbuff_in_strcpy(&our_out, sep);
1547
0
      if (slen < 0) return slen;
1548
0
    }
1549
0
  }
1550
1551
0
  FR_SBUFF_SET_RETURN(out, &our_out);
1552
0
}
1553
1554
/** Return the attr of a #CONF_PAIR
1555
 *
1556
 * Return the LHS value of a pair (the attribute).
1557
 *
1558
 * @param[in] pair  to return the attribute for.
1559
 * @return
1560
 *  - NULL if the pair was NULL.
1561
 *  - The attribute name of the pair.
1562
 *
1563
 * @hidecallergraph
1564
 */
1565
char const *cf_pair_attr(CONF_PAIR const *pair)
1566
0
{
1567
0
  return (pair ? pair->attr : NULL);
1568
0
}
1569
1570
/** Return the value of a #CONF_PAIR
1571
 *
1572
 * Return the RHS value of a pair (the value).
1573
 *
1574
 * @param[in] pair to return the value of.
1575
 * @return
1576
 *  - NULL if pair was NULL or the pair has no value.
1577
 *  - The string value of the pair.
1578
 *
1579
 * @hidecallergraph
1580
 */
1581
char const *cf_pair_value(CONF_PAIR const *pair)
1582
0
{
1583
0
  return (pair ? pair->value : NULL);
1584
0
}
1585
1586
/** Return the operator of a pair
1587
 *
1588
 * @param[in] pair  to return the operator of.
1589
 * @return
1590
 *  - T_INVALID if pair was NULL.
1591
 *  - T_OP_* (one of the operator constants).
1592
 *
1593
 * @hidecallergraph
1594
 */
1595
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
1596
0
{
1597
0
  return (pair ? pair->op : T_INVALID);
1598
0
}
1599
1600
/** Return the value (lhs) quoting of a pair
1601
 *
1602
 * @param pair to extract value type from.
1603
 * @return
1604
 *  - #T_BARE_WORD.
1605
 *  - #T_SINGLE_QUOTED_STRING.
1606
 *  - #T_BACK_QUOTED_STRING.
1607
 *  - #T_DOUBLE_QUOTED_STRING.
1608
 *  - #T_INVALID if the pair is NULL.
1609
 */
1610
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
1611
0
{
1612
0
  return (pair ? pair->lhs_quote : T_INVALID);
1613
0
}
1614
1615
/** Return the value (rhs) quoting of a pair
1616
 *
1617
 * @param pair to extract value type from.
1618
 * @return
1619
 *  - #T_BARE_WORD.
1620
 *  - #T_SINGLE_QUOTED_STRING.
1621
 *  - #T_BACK_QUOTED_STRING.
1622
 *  - #T_DOUBLE_QUOTED_STRING.
1623
 *  - #T_INVALID if the pair is NULL.
1624
 */
1625
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
1626
0
{
1627
0
  return (pair ? pair->rhs_quote : T_INVALID);
1628
0
}
1629
1630
/** Free user data associated with #CONF_DATA
1631
 *
1632
 * @param[in] cd  being freed.
1633
 * @return 0
1634
 */
1635
static int _cd_free(CONF_DATA *cd)
1636
0
{
1637
0
  void *to_free;
1638
1639
0
  memcpy(&to_free, &cd->data, sizeof(to_free));
1640
1641
0
  if (cd->free) talloc_decrease_ref_count(to_free); /* Also works OK for non-reference counted chunks */
1642
1643
0
  return 0;
1644
0
}
1645
1646
/** Allocate a new user data container
1647
 *
1648
 * @param[in] parent  #CONF_PAIR, or #CONF_SECTION to hang CONF_DATA off of.
1649
 * @param[in] data  being added.
1650
 * @param[in] type  of data being added.
1651
 * @param[in] name  String identifier of the user data.
1652
 * @param[in] do_free function, called when the parent #CONF_SECTION is being freed.
1653
 * @return
1654
 *  - CONF_DATA on success.
1655
 *  - NULL on error.
1656
 */
1657
static CONF_DATA *cf_data_alloc(CONF_ITEM *parent, void const *data, char const *type, char const *name, bool do_free)
1658
0
{
1659
0
  CONF_DATA *cd;
1660
1661
0
  cd = talloc_zero(parent, CONF_DATA);
1662
0
  if (!cd) return NULL;
1663
1664
0
  cf_item_init(cf_data_to_item(cd), CONF_ITEM_DATA, parent, NULL, 0);
1665
1666
  /*
1667
   *  strdup so if the data is freed, we can
1668
   *  still remove it from the section without
1669
   *  explosions.
1670
   */
1671
0
  if (data) {
1672
0
    cd->type = talloc_strdup(cd, type);
1673
0
    cd->data = data;
1674
0
  }
1675
0
  if (name) cd->name = talloc_strdup(cd, name);
1676
1677
0
  if (do_free) {
1678
0
    cd->free = true;
1679
0
    talloc_set_destructor(cd, _cd_free);
1680
0
  }
1681
1682
0
  cf_item_add(parent, cd);
1683
0
  return cd;
1684
0
}
1685
1686
/** Find user data in a config section
1687
 *
1688
 * @param[in] ci  The section to search for data in.
1689
 * @param[in] type  of user data.  Used for name spacing and walking over a specific
1690
 *      type of user data.
1691
 * @param[in] name  String identifier of the user data.  Special value CF_IDENT_ANY
1692
 *      may be used to match on type only.
1693
 * @return
1694
 *  - The user data.
1695
 *  - NULL if no user data exists.
1696
 */
1697
CONF_DATA const *_cf_data_find(CONF_ITEM const *ci, char const *type, char const *name)
1698
0
{
1699
0
  return cf_item_to_data(cf_find(ci, CONF_ITEM_DATA, type, name));
1700
0
}
1701
1702
/** Return the next item of user data
1703
 *
1704
 * @param[in] ci  The section to search for data in.
1705
 * @param[in] prev  section we found.  May be NULL in which case
1706
 *      we just return the next section after prev.
1707
 * @param[in] type  of user data.  Used for name spacing and walking over a specific
1708
 *      type of user data.
1709
 * @param[in] name  String identifier of the user data.  Special value CF_IDENT_ANY
1710
 *      can be used to match any name2 value.
1711
 * @return
1712
 *  - The next matching #CONF_DATA.
1713
 *  - NULL if there is no more matching #CONF_DATA.
1714
 */
1715
CONF_DATA const *_cf_data_find_next(CONF_ITEM const *ci, CONF_ITEM const *prev, char const *type, char const *name)
1716
0
{
1717
0
  return cf_item_to_data(cf_find_next(ci, prev, CONF_ITEM_DATA, type, name));
1718
0
}
1719
1720
/** Find matching data in the specified section or one of its parents
1721
 *
1722
 * @param[in] ci  The section to search for data in.
1723
 * @param[in] type  of user data.  Used for name spacing and walking over a specific
1724
 *      type of user data.
1725
 * @param[in] name  String identifier of the user data.  Special value CF_IDENT_ANY
1726
 *      may be used to match on type only.
1727
 * @return
1728
 *  - The next matching #CONF_DATA.
1729
 *  - NULL if there is no more matching #CONF_DATA.
1730
 */
1731
CONF_DATA *_cf_data_find_in_parent(CONF_ITEM const *ci, char const *type, char const *name)
1732
0
{
1733
0
  CONF_ITEM const *parent = ci;
1734
1735
0
  do {
1736
0
    CONF_ITEM *found;
1737
1738
0
    found = cf_find(parent, CONF_ITEM_DATA, type, name);
1739
0
    if (found) return cf_item_to_data(found);
1740
0
  } while ((parent = cf_parent(parent)));
1741
1742
0
  return NULL;
1743
0
}
1744
1745
/** Return the user assigned value of #CONF_DATA
1746
 *
1747
 * @param[in] cd  to return value of.
1748
 * @return the user data stored within the #CONF_DATA.
1749
 */
1750
void *cf_data_value(CONF_DATA const *cd)
1751
0
{
1752
0
  void *to_return;
1753
1754
0
  if (!cd) return NULL;
1755
1756
0
  memcpy(&to_return, &cd->data, sizeof(to_return));
1757
1758
0
  return to_return;
1759
0
}
1760
1761
/** Add talloced user data to a config section
1762
 *
1763
 * @param[in] ci  to add data to.
1764
 * @param[in] data  to add.
1765
 * @param[in] name  String identifier of the user data.
1766
 * @param[in] do_free Function to free user data when the CONF_SECTION is freed.
1767
 * @param[in] filename  Source file the #CONF_DATA was added in.
1768
 * @param[in] lineno  the #CONF_DATA was added at.
1769
 * @return
1770
 *  - #CONF_DATA  - opaque handle to the stored data - on success.
1771
 *  - NULL error.
1772
 */
1773
CONF_DATA const *_cf_data_add(CONF_ITEM *ci, void const *data, char const *name, bool do_free,
1774
            char const *filename, int lineno)
1775
0
{
1776
0
  CONF_DATA *cd;
1777
0
  CONF_DATA const *found;
1778
0
  char const  *type = NULL;
1779
1780
0
  if (!ci) return NULL;
1781
1782
0
  if (data) type = talloc_get_name(data);
1783
1784
  /*
1785
   *  Already exists.  Can't add it.
1786
   */
1787
0
  found = _cf_data_find(ci, type, name);
1788
0
  if (found) {
1789
0
    return NULL;
1790
0
  }
1791
1792
0
  cd = cf_data_alloc(ci, data, type, name, do_free);
1793
0
  if (!cd) {
1794
0
    cf_log_err(ci, "Failed allocating data");
1795
0
    return NULL;
1796
0
  }
1797
0
  cd->is_talloced = true;
1798
0
  cf_filename_set(cd, filename);
1799
0
  cf_lineno_set(cd, lineno);
1800
1801
0
  return cd;
1802
0
}
1803
1804
/** Add non-talloced user data to a config section
1805
 *
1806
 * @param[in] ci  to add data to.
1807
 * @param[in] data  to add.
1808
 * @param[in] type  identifier of the user data.
1809
 * @param[in] name  String identifier of the user data.
1810
 * @param[in] filename  Source file the #CONF_DATA was added in.
1811
 * @param[in] lineno  the #CONF_DATA was added at.
1812
 *  - #CONF_DATA  - opaque handle to the stored data - on success.
1813
 *  - NULL error.
1814
 */
1815
CONF_DATA const *_cf_data_add_static(CONF_ITEM *ci, void const *data, char const *type, char const *name,
1816
             char const *filename, int lineno)
1817
0
{
1818
0
  CONF_DATA *cd;
1819
0
  CONF_DATA const *found;
1820
1821
  /*
1822
   *  Already exists.  Can't add it.
1823
   */
1824
0
  found = _cf_data_find(ci, type, name);
1825
0
  if (found) {
1826
    /*
1827
     *  Suppress these, as it's OK for the conf_parser_t in main_config.c
1828
           */
1829
0
    if (strcmp(type, "conf_parser_t") == 0) return NULL;
1830
1831
0
    cf_log_err(ci, "Data of type %s with name \"%s\" already exists.  Existing data added %s[%i]", type,
1832
0
         name, found->item.filename, found->item.lineno);
1833
0
    return NULL;
1834
0
  }
1835
1836
0
  cd = cf_data_alloc(ci, data, type, name, false);
1837
0
  if (!cd) {
1838
0
    cf_log_err(ci, "Failed allocating data");
1839
0
    return NULL;
1840
0
  }
1841
0
  cd->is_talloced = false;
1842
0
  cf_filename_set(cd, filename);
1843
0
  cf_lineno_set(cd, lineno);
1844
1845
0
  return cd;
1846
0
}
1847
1848
/** Remove data from a configuration section
1849
 *
1850
 * @note If cd was not found it will not be freed, and it is the caller's responsibility
1851
 *  to free it explicitly, or free the section it belongs to.
1852
 *
1853
 * @param[in] parent  to remove data from.
1854
 * @param[in] cd  opaque handle of the stored data.
1855
 * @return
1856
 *  - The value stored within the data (if cd is valid and was found and removed).
1857
 *  - NULL if not found.
1858
 */
1859
void *_cf_data_remove(CONF_ITEM *parent, CONF_DATA const *cd)
1860
0
{
1861
0
  void *data;
1862
1863
0
  if (!cd) return NULL;
1864
1865
0
  (void)cf_item_remove(parent, cd);
1866
1867
0
  talloc_set_destructor(cd, NULL);  /* Disarm the destructor */
1868
0
  memcpy(&data, &cd->data, sizeof(data));
1869
0
  talloc_const_free(cd);
1870
1871
0
  return data;
1872
0
}
1873
1874
/** Walk over a specific type of CONF_DATA
1875
 *
1876
 * @param[in] ci  containing the CONF_DATA to walk over.
1877
 * @param[in] type  of CONF_DATA to walk over.
1878
 * @param[in] cb  to call when we find CONF_DATA of the specified type.
1879
 * @param[in] ctx to pass to cb.
1880
 * @return
1881
 *  - 0 on success.
1882
 *  - -1 on failure.
1883
 */
1884
int _cf_data_walk(CONF_ITEM *ci, char const *type, cf_walker_t cb, void *ctx)
1885
0
{
1886
0
  CONF_DATA     *cd;
1887
0
  CONF_ITEM     *item;
1888
0
  fr_rb_tree_t      *tree;
1889
0
  fr_rb_iter_inorder_t  iter;
1890
0
  int       ret = 0;
1891
1892
0
  if (!ci->ident2) return 0;
1893
1894
0
  tree = ci->ident2;
1895
1896
0
  for (item = fr_rb_iter_init_inorder(tree, &iter);
1897
0
       item;
1898
0
       item = fr_rb_iter_next_inorder(tree, &iter)) {
1899
    /*
1900
     *  We're walking ident2, not all of the items will be data
1901
     */
1902
0
    if (item->type != CONF_ITEM_DATA) continue;
1903
1904
0
    cd = (void *) item;
1905
0
    if ((cd->type != type) && (strcmp(cd->type, type) != 0)) continue;
1906
1907
0
    ret = cb(UNCONST(void *, cd->data), ctx);
1908
0
    if (ret) {
1909
0
      break;
1910
0
    }
1911
0
  }
1912
1913
0
  return ret;
1914
0
}
1915
1916
static inline CC_HINT(nonnull) void truncate_filename(char const **e, char const **p, int *len, char const *filename)
1917
0
{
1918
0
  size_t flen;
1919
0
  char const *q;
1920
1921
0
  #define FILENAME_TRUNCATE 60
1922
1923
0
  *p = filename;
1924
0
  *e = "";
1925
1926
0
  flen = talloc_strlen(filename);
1927
0
  if (flen <= FILENAME_TRUNCATE) {
1928
0
    *len = (int)flen;
1929
0
    return;
1930
0
  }
1931
1932
0
  *p += flen - FILENAME_TRUNCATE;
1933
0
  *len = FILENAME_TRUNCATE;
1934
1935
0
  q = strchr(*p, FR_DIR_SEP);
1936
0
  if (q) {
1937
0
    q++;
1938
0
    *len -= (q - *p);
1939
0
    *p += (q - *p);
1940
0
  }
1941
1942
0
  *e = "...";
1943
0
}
1944
1945
/** Check to see if the CONF_PAIR value is present in the specified table
1946
 *
1947
 * If it's not present, return an error and produce a helpful log message
1948
 *
1949
 * @param[out] out  The result of parsing the pair value.
1950
 * @param[in] table to look for string values in.
1951
 * @param[in] table_len Length of the table.
1952
 * @param[in] cp  to parse.
1953
 * @return
1954
 *  - 0 on success.
1955
 *  - -1 on failure.
1956
 */
1957
int cf_pair_in_table(int32_t *out, fr_table_num_sorted_t const *table, size_t table_len, CONF_PAIR *cp)
1958
{
1959
  char        *list = NULL;
1960
  int32_t       res;
1961
  size_t        i;
1962
1963
  res = fr_table_value_by_str(table, cf_pair_value(cp), FR_TABLE_NOT_FOUND);
1964
  if (res != FR_TABLE_NOT_FOUND) {
1965
    *out = res;
1966
    return 0;
1967
  }
1968
1969
  for (i = 0; i < table_len; i++) MEM(list = talloc_asprintf_append_buffer(list, "'%s', ", table[i].name.str));
1970
1971
  if (!list) {
1972
    cf_log_err(cp, "Internal error parsing %s: Table was empty", cf_pair_attr(cp));
1973
    return -1;
1974
  }
1975
1976
  /*
1977
   *  Trim the final ", "
1978
   */
1979
  MEM(list = talloc_bstr_realloc(NULL, list, talloc_array_length(list) - 2));
1980
1981
  cf_log_err(cp, "Invalid value \"%s\". Expected one of %s", cf_pair_value(cp), list);
1982
1983
  talloc_free(list);
1984
1985
  return -1;
1986
}
1987
1988
/** Log an error message relating to a #CONF_ITEM
1989
 *
1990
 * @param[in] type  of log message.
1991
 * @param[in] ci  #CONF_ITEM to print file/lineno for.
1992
 * @param[in] file  src file the log message was generated in.
1993
 * @param[in] line  number the log message was generated on.
1994
 * @param[in] fmt of the message.
1995
 * @param[in] ap  Message args.
1996
 */
1997
void _cf_vlog(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, va_list ap)
1998
0
{
1999
0
  va_list aq;
2000
2001
0
  if ((type == L_DBG) && !DEBUG_ENABLED) return;
2002
2003
0
  if (!ci || !ci->filename || !*ci->filename || (*ci->filename == '<') ||
2004
0
      (((type == L_DBG) || (type == L_INFO)) && !DEBUG_ENABLED4)) {
2005
0
    va_copy(aq, ap);
2006
0
    fr_vlog(LOG_DST, type, file, line, fmt, aq);
2007
0
    va_end(aq);
2008
0
    return;
2009
0
  }
2010
2011
0
  {
2012
0
    char const  *e, *p;
2013
0
    int   len;
2014
0
    char    *msg;
2015
2016
0
    truncate_filename(&e, &p, &len, ci->filename);
2017
2018
0
    va_copy(aq, ap);
2019
0
    msg = fr_vasprintf(NULL, fmt, aq);
2020
0
    va_end(aq);
2021
2022
0
    fr_log(LOG_DST, type, file, line, "%s%.*s[%d]: %s", e, len, p, ci->lineno, msg);
2023
0
    talloc_free(msg);
2024
0
  }
2025
0
}
2026
2027
/** Log an error message relating to a #CONF_ITEM
2028
 *
2029
 * @param[in] type  of log message.
2030
 * @param[in] file  src file the log message was generated in.
2031
 * @param[in] line  number the log message was generated on.
2032
 * @param[in] ci  #CONF_ITEM to print file/lineno for.
2033
 * @param[in] fmt of the message.
2034
 * @param[in] ... Message args.
2035
 */
2036
void _cf_log(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, ...)
2037
0
{
2038
0
  va_list ap;
2039
2040
0
  if ((type == L_DBG) && !DEBUG_ENABLED) return;
2041
2042
0
  va_start(ap, fmt);
2043
0
  _cf_vlog(type, ci, file, line, fmt, ap);
2044
0
  va_end(ap);
2045
0
}
2046
2047
/** Log an error message relating to a #CONF_ITEM
2048
 *
2049
 * Drains the fr_strerror() stack emitting one or more error messages.
2050
 *
2051
 * @param[in] type  of log message.
2052
 * @param[in] file  src file the log message was generated in.
2053
 * @param[in] line  number the log message was generated on.
2054
 * @param[in] ci  #CONF_ITEM to print file/lineno for.
2055
 * @param[in] f_rules Additional optional formatting controls.
2056
 * @param[in] fmt of the message.
2057
 * @param[in] ap  Message args.
2058
 */
2059
void _cf_vlog_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line,
2060
       fr_log_perror_format_t const *f_rules, char const *fmt, va_list ap)
2061
0
{
2062
0
  va_list aq;
2063
2064
0
  if ((type == L_DBG) && !DEBUG_ENABLED) return;
2065
2066
0
  if (!ci || !ci->filename) {
2067
0
    va_copy(aq, ap);
2068
0
    fr_vlog_perror(LOG_DST, type, file, line, f_rules, fmt, aq);
2069
0
    va_end(aq);
2070
0
    return;
2071
0
  }
2072
2073
0
  {
2074
0
    char const    *e, *p;
2075
0
    int     len;
2076
0
    char      *prefix;
2077
0
    TALLOC_CTX    *thread_log_pool;
2078
0
    TALLOC_CTX    *pool;
2079
0
    fr_log_perror_format_t  our_f_rules;
2080
2081
0
    if (f_rules) {
2082
0
      our_f_rules = *f_rules;
2083
0
    } else {
2084
0
      our_f_rules = (fr_log_perror_format_t){};
2085
0
    }
2086
2087
    /*
2088
     *  Get some scratch space from the logging code
2089
     */
2090
0
    thread_log_pool = fr_log_pool_init();
2091
0
    pool = talloc_new(thread_log_pool);
2092
2093
0
    truncate_filename(&e, &p, &len, ci->filename);
2094
2095
    /*
2096
     *  Create the file location string
2097
     */
2098
0
    prefix = fr_asprintf(pool, "%s%.*s[%d]: ", e, len, p, ci->lineno);
2099
2100
    /*
2101
     *  Prepend it to an existing first prefix
2102
     */
2103
0
    if (f_rules && f_rules->first_prefix) {
2104
0
      char *first;
2105
2106
0
      first = talloc_bstrdup(pool, prefix);
2107
0
      talloc_buffer_append_buffer(pool, first, f_rules->first_prefix);
2108
2109
0
      our_f_rules.first_prefix = first;
2110
0
    } else {
2111
0
      our_f_rules.first_prefix = prefix;
2112
0
    }
2113
2114
    /*
2115
     *  Prepend it to an existing subsq prefix
2116
     */
2117
0
    if (f_rules && f_rules->subsq_prefix) {
2118
0
      char *subsq;
2119
2120
0
      subsq = talloc_bstrdup(pool, prefix);
2121
0
      talloc_buffer_append_buffer(pool, subsq, f_rules->subsq_prefix);
2122
2123
0
      our_f_rules.subsq_prefix = subsq;
2124
0
    } else {
2125
0
      our_f_rules.subsq_prefix = prefix;
2126
0
    }
2127
2128
0
    va_copy(aq, ap);
2129
0
    fr_vlog_perror(LOG_DST, type, file, line, &our_f_rules, fmt, aq);
2130
0
    va_end(aq);
2131
2132
0
    talloc_free(pool);
2133
0
  }
2134
0
}
2135
2136
/** Log an error message relating to a #CONF_ITEM
2137
 *
2138
 * Drains the fr_strerror() stack emitting one or more error messages.
2139
 *
2140
 * @param[in] type  of log message.
2141
 * @param[in] file  src file the log message was generated in.
2142
 * @param[in] line  number the log message was generated on.
2143
 * @param[in] ci  #CONF_ITEM to print file/lineno for.
2144
 * @param[in] f_rules Additional optional formatting controls.
2145
 * @param[in] fmt of the message.
2146
 * @param[in] ... Message args.
2147
 */
2148
void _cf_log_perr(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line,
2149
      fr_log_perror_format_t const *f_rules, char const *fmt, ...)
2150
0
{
2151
0
  va_list ap;
2152
2153
0
  if ((type == L_DBG) && !DEBUG_ENABLED) return;
2154
2155
0
  va_start(ap, fmt);
2156
0
  _cf_vlog_perr(type, ci, file, line, f_rules, fmt, ap);
2157
0
  va_end(ap);
2158
0
}
2159
2160
/** Log a debug message relating to a #CONF_ITEM
2161
 *
2162
 * Always emits a filename/lineno prefix if available
2163
 *
2164
 * @param[in] type  of log message.
2165
 * @param[in] file  src file the log message was generated in.
2166
 * @param[in] line  number the log message was generated on.
2167
 * @param[in] ci  #CONF_ITEM to print file/lineno for.
2168
 * @param[in] fmt of the message.
2169
 * @param[in] ... Message args.
2170
 */
2171
void _cf_log_with_filename(fr_log_type_t type, CONF_ITEM const *ci, char const *file, int line, char const *fmt, ...)
2172
0
{
2173
0
  va_list ap;
2174
2175
0
  if ((type == L_DBG) && !DEBUG_ENABLED) return;
2176
2177
0
  if (!ci || !ci->filename) {
2178
0
    va_start(ap, fmt);
2179
0
    fr_vlog(LOG_DST, type, file, line, fmt, ap);
2180
0
    va_end(ap);
2181
0
    return;
2182
0
  }
2183
2184
0
  {
2185
0
    char const  *e, *p;
2186
0
    int   len;
2187
0
    char    *msg;
2188
2189
0
    truncate_filename(&e, &p, &len, ci->filename);
2190
2191
0
    va_start(ap, fmt);
2192
0
    msg = fr_vasprintf(NULL, fmt, ap);
2193
0
    va_end(ap);
2194
2195
0
    fr_log(LOG_DST, type, file, line, "%s%.*s[%d]: %s", e, len, p, ci->lineno, msg);
2196
0
    talloc_free(msg);
2197
0
  }
2198
0
}
2199
2200
/** Log an error message in the context of a child pair of the specified parent
2201
 *
2202
 * @param[in] parent  containing the pair.
2203
 * @param[in] child name to use as a logging context.
2204
 * @param[in] type  of log message.
2205
 * @param[in] file  src file the log message was generated in.
2206
 * @param[in] line  number the log message was generated on.
2207
 * @param[in] fmt of the message.
2208
 * @param[in] ... Message args.
2209
 */
2210
void _cf_log_by_child(fr_log_type_t type, CONF_SECTION const *parent, char const *child,
2211
          char const *file, int line, char const *fmt, ...)
2212
0
{
2213
0
  va_list   ap;
2214
0
  CONF_PAIR const *cp;
2215
2216
0
  cp = cf_pair_find(parent, child);
2217
0
  if (cp) {
2218
0
    va_start(ap, fmt);
2219
0
    _cf_vlog(type, CF_TO_ITEM(cp), file, line, fmt, ap);
2220
0
    va_end(ap);
2221
0
    return;
2222
0
  }
2223
2224
0
  va_start(ap, fmt);
2225
0
  _cf_vlog(type, CF_TO_ITEM(parent), file, line, fmt, ap);
2226
0
  va_end(ap);
2227
0
}
2228
2229
2230
/** Log an error message in the context of a child pair of the specified parent
2231
 *
2232
 * @param[in] parent  containing the pair.
2233
 * @param[in] child name to use as a logging context.
2234
 * @param[in] type  of log message.
2235
 * @param[in] file  src file the log message was generated in.
2236
 * @param[in] line  number the log message was generated on.
2237
 * @param[in] f_rules Line prefixes.
2238
 * @param[in] fmt of the message.
2239
 * @param[in] ... Message args.
2240
 */
2241
void _cf_log_perr_by_child(fr_log_type_t type, CONF_SECTION const *parent, char const *child,
2242
         char const *file, int line, fr_log_perror_format_t const *f_rules,
2243
         char const *fmt, ...)
2244
0
{
2245
0
  va_list   ap;
2246
0
  CONF_PAIR const *cp;
2247
2248
0
  cp = cf_pair_find(parent, child);
2249
0
  if (cp) {
2250
0
    va_start(ap, fmt);
2251
0
    _cf_vlog_perr(type, CF_TO_ITEM(cp), file, line, f_rules, fmt, ap);
2252
0
    va_end(ap);
2253
0
    return;
2254
0
  }
2255
2256
0
  va_start(ap, fmt);
2257
0
  _cf_vlog_perr(type, CF_TO_ITEM(parent), file, line, f_rules, fmt, ap);
2258
0
  va_end(ap);
2259
0
}
2260
2261
/** Print out debugging information about a CONFIG_ITEM
2262
 *
2263
 * @param[in] ci  being debugged.
2264
 */
2265
void _cf_item_debug(CONF_ITEM const *ci)
2266
0
{
2267
  /*
2268
   *  Print summary of the item
2269
   */
2270
0
  switch (ci->type) {
2271
0
  case CONF_ITEM_SECTION:
2272
0
  {
2273
0
    CONF_SECTION const *cs = cf_item_to_section(ci);
2274
0
    int i;
2275
2276
0
    DEBUG("SECTION - %p", cs);
2277
0
    DEBUG("  name1         : %s", cs->name1);
2278
0
    DEBUG("  name2         : %s", cs->name2 ? cs->name2 : "<none>");
2279
0
    DEBUG("  name2_quote   : %s", fr_table_str_by_value(fr_token_quotes_table, cs->name2_quote, "<INVALID>"));
2280
0
    DEBUG("  argc          : %d", cs->argc);
2281
2282
0
    for (i = 0; i < cs->argc; i++) {
2283
0
      char const *quote = fr_table_str_by_value(fr_token_quotes_table, cs->argv_quote[i], "<INVALID>");
2284
0
      DEBUG("  argv[%i]      : %s%s%s", i, quote, cs->argv[i], quote);
2285
0
    }
2286
0
  }
2287
0
    break;
2288
2289
0
  case CONF_ITEM_PAIR:
2290
0
  {
2291
0
    CONF_PAIR const *cp = cf_item_to_pair(ci);
2292
2293
0
    DEBUG("PAIR - %p", cp);
2294
0
    DEBUG("  attr          : %s", cp->attr);
2295
0
    DEBUG("  value         : %s", cp->value);
2296
0
    DEBUG("  operator      : %s", fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"));
2297
0
    DEBUG("  lhs_quote     : %s", fr_table_str_by_value(fr_token_quotes_table, cp->lhs_quote, "<INVALID>"));
2298
0
    DEBUG("  rhs_quote     : %s", fr_table_str_by_value(fr_token_quotes_table, cp->rhs_quote, "<INVALID>"));
2299
0
    DEBUG("  pass2         : %s", cp->pass2 ? "yes" : "no");
2300
0
    DEBUG("  parsed        : %s", cp->item.parsed ? "yes" : "no");
2301
0
  }
2302
0
    break;
2303
2304
0
  case CONF_ITEM_DATA:
2305
0
  {
2306
0
    CONF_DATA const *cd = cf_item_to_data(ci);
2307
2308
0
    DEBUG("DATA - %p", cd);
2309
0
    DEBUG("  type          : %s", cd->type);
2310
0
    DEBUG("  name          : %s", cd->name);
2311
0
    DEBUG("  data          : %p", cd->data);
2312
0
    DEBUG("  free wth prnt : %s", cd->free ? "yes" : "no");
2313
0
  }
2314
0
    break;
2315
2316
0
  default:
2317
0
    DEBUG("INVALID - %p", ci);
2318
0
    return;
2319
0
  }
2320
2321
0
  DEBUG("  filename      : %s", ci->filename);
2322
0
  DEBUG("  line          : %i", ci->lineno);
2323
0
  if (ci->parent) DEBUG("  next          : %p", fr_dlist_next(&ci->parent->children, ci));
2324
0
  DEBUG("  parent        : %p", ci->parent);
2325
0
  DEBUG("  children      : %s", cf_item_has_no_children(ci) ? "no" : "yes");
2326
0
  DEBUG("  ident1 tree   : %p (%u entries)", ci->ident1, ci->ident1 ? fr_rb_num_elements(ci->ident1) : 0);
2327
0
  DEBUG("  ident2 tree   : %p (%u entries)", ci->ident2, ci->ident2 ? fr_rb_num_elements(ci->ident2) : 0);
2328
2329
0
  if (cf_item_has_no_children(ci)) return;
2330
2331
  /*
2332
   *  Print summary of the item's children
2333
   */
2334
0
  DEBUG("CHILDREN");
2335
2336
0
  cf_item_foreach(ci, child) {
2337
0
        char const *in_ident1, *in_ident2;
2338
2339
0
    in_ident1 = fr_rb_find(ci->ident1, child) == child? "in ident1 " : "";
2340
2341
0
    if (ci->type != CONF_ITEM_SECTION) {
2342
0
      in_ident2 = NULL;
2343
0
    } else {
2344
0
      in_ident2 = fr_rb_find(ci->ident2, child) == child? "in ident2 " : "";
2345
0
    }
2346
2347
0
    switch (child->type) {
2348
0
    case CONF_ITEM_SECTION:
2349
0
    {
2350
0
      CONF_SECTION const *cs = cf_item_to_section(child);
2351
2352
0
      DEBUG("  SECTION %p (%s %s) %s%s", child, cs->name1, cs->name2 ? cs->name2 : "<none>",
2353
0
            in_ident1, in_ident2);
2354
0
    }
2355
0
      break;
2356
2357
0
    case CONF_ITEM_PAIR:
2358
0
    {
2359
0
      CONF_PAIR const *cp = cf_item_to_pair(child);
2360
0
      char const  *lhs_quote = fr_table_str_by_value(fr_token_quotes_table, cp->lhs_quote, "<INVALID>");
2361
0
      char const  *rhs_quote = fr_table_str_by_value(fr_token_quotes_table, cp->rhs_quote, "<INVALID>");
2362
2363
0
      DEBUG("  PAIR %p (%s%s%s %s %s%s%s) %s%s", child,
2364
0
            lhs_quote, cp->attr, lhs_quote,
2365
0
            fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"),
2366
0
            rhs_quote, cp->value, rhs_quote,
2367
0
            in_ident1, in_ident2);
2368
0
    }
2369
0
      break;
2370
2371
0
    case CONF_ITEM_DATA:
2372
0
    {
2373
0
      CONF_DATA const *cd = cf_item_to_data(child);
2374
2375
0
      DEBUG("  DATA %p (%s *)%s = %p %s%s", child,
2376
0
            cd->type, cd->name ? cd->name : "", cd->data,
2377
0
            in_ident1, in_ident2);
2378
0
      break;
2379
0
    }
2380
2381
0
    default:
2382
0
      DEBUG("  INVALID - %p", child);
2383
0
      break;
2384
0
    }
2385
0
  }
2386
0
}
2387
2388
/** Ease of use from debugger
2389
 */
2390
void cf_pair_debug(CONF_PAIR *cp)
2391
0
{
2392
0
  cf_item_debug(cp);
2393
0
}
2394
2395
/** Ease of use from debugger
2396
 */
2397
void cf_section_debug(CONF_SECTION *cs)
2398
0
{
2399
0
  cf_item_debug(cs);
2400
0
}
2401
2402
/*
2403
 *  Used when we don't need the children any more, as with
2404
 *
2405
 *    if (0) { ... }
2406
 */
2407
void cf_item_free_children(CONF_ITEM *ci)
2408
0
{
2409
0
  cf_item_foreach(ci, child) {
2410
0
    _cf_item_remove(ci, child);
2411
0
  }
2412
0
}
2413
2414
void _cf_canonicalize_error(CONF_ITEM *ci, ssize_t slen, char const *msg, char const *str)
2415
0
{
2416
0
  char *spaces, *text;
2417
2418
0
  fr_canonicalize_error(ci, &spaces, &text, slen, str);
2419
2420
0
  cf_log_err(ci, "%s", msg);
2421
0
  cf_log_err(ci, "%s", text);
2422
0
  cf_log_perr(ci, "%s^", spaces);
2423
2424
0
  talloc_free(spaces);
2425
  talloc_free(text);
2426
0
}