The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
cf_tests.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Tests for cf_file, cf_util, and cf_parse
18 *
19 * @file src/lib/server/cf_tests.c
20 *
21 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
22 */
23
24static void test_init(void);
25# define TEST_INIT test_init()
26
27#include <freeradius-devel/util/test/acutest.h>
28#include <freeradius-devel/util/test/acutest_helpers.h>
29#include <freeradius-devel/server/cf_file.h>
30#include <freeradius-devel/server/cf_parse.h>
31#include <freeradius-devel/server/tmpl.h>
32#include <freeradius-devel/server/cf_priv.h>
33
34static TALLOC_CTX *autofree;
35
36/** Global initialisation
37 */
38static void test_init(void)
39{
41 if (!autofree) {
42 fr_perror("cf_tests");
43 fr_exit_now(EXIT_FAILURE);
44 }
45
46 /*
47 * Mismatch between the binary and the libraries it depends on
48 */
50 fr_perror("cf_tests");
51 fr_exit_now(EXIT_FAILURE);
52 }
53}
54
55
56/*
57 * Section allocation and accessors
58 */
59
61{
62 CONF_SECTION *cs;
63
64 cs = cf_section_alloc(autofree, NULL, "server", NULL);
65 TEST_ASSERT(cs != NULL);
66
67 TEST_CHECK(strcmp(cf_section_name1(cs), "server") == 0);
68 TEST_CHECK(cf_section_name2(cs) == NULL);
69 TEST_CHECK(strcmp(cf_section_name(cs), "server") == 0);
70
71 talloc_free(cs);
72}
73
75{
76 CONF_SECTION *cs;
77
78 cs = cf_section_alloc(autofree, NULL, "server", "default");
79 TEST_ASSERT(cs != NULL);
80
81 TEST_CHECK(strcmp(cf_section_name1(cs), "server") == 0);
82 TEST_CHECK(strcmp(cf_section_name2(cs), "default") == 0);
83
84 talloc_free(cs);
85}
86
88{
89 CONF_SECTION *parent, *child;
90
91 parent = cf_section_alloc(autofree, NULL, "root", NULL);
92 TEST_ASSERT(parent != NULL);
93
94 child = cf_section_alloc(autofree, parent, "child", NULL);
95 TEST_ASSERT(child != NULL);
96
98 TEST_CHECK(cf_root(child) == parent);
99
101}
102
103static void test_section_name_cmp(void)
104{
105 CONF_SECTION *cs;
106
107 cs = cf_section_alloc(autofree, NULL, "server", "default");
108 TEST_ASSERT(cs != NULL);
109
110 TEST_CHECK(cf_section_name_cmp(cs, "server", "default") == 0);
111 TEST_CHECK(cf_section_name_cmp(cs, "server", "other") != 0);
112 TEST_CHECK(cf_section_name_cmp(cs, "other", NULL) != 0);
113
114 talloc_free(cs);
115}
116
118{
119 CONF_SECTION *cs;
120 CONF_ITEM *ci;
121
122 cs = cf_section_alloc(autofree, NULL, "test", NULL);
123 TEST_ASSERT(cs != NULL);
124
125 ci = cf_section_to_item(cs);
126 TEST_ASSERT(ci != NULL);
131
132 talloc_free(cs);
133}
134
135
136/*
137 * Pair allocation and accessors
138 */
139
140static void test_pair_alloc_basic(void)
141{
142 CONF_SECTION *cs;
143 CONF_PAIR *cp;
144
145 cs = cf_section_alloc(autofree, NULL, "test", NULL);
146 TEST_ASSERT(cs != NULL);
147
148 cp = cf_pair_alloc(cs, "key", "value", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
149 TEST_ASSERT(cp != NULL);
150
151 TEST_CHECK(strcmp(cf_pair_attr(cp), "key") == 0);
152 TEST_CHECK(strcmp(cf_pair_value(cp), "value") == 0);
154
155 talloc_free(cs);
156}
157
158static void test_pair_alloc_quoted(void)
159{
160 CONF_SECTION *cs;
161 CONF_PAIR *cp;
162
163 cs = cf_section_alloc(autofree, NULL, "test", NULL);
164 TEST_ASSERT(cs != NULL);
165
166 cp = cf_pair_alloc(cs, "msg", "hello world", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING);
167 TEST_ASSERT(cp != NULL);
168
171
172 talloc_free(cs);
173}
174
176{
177 CONF_SECTION *cs;
178 CONF_PAIR *cp;
179
180 cs = cf_section_alloc(autofree, NULL, "test", NULL);
181 TEST_ASSERT(cs != NULL);
182
183 cp = cf_pair_alloc(cs, "flag", NULL, T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
184 TEST_ASSERT(cp != NULL);
185
186 TEST_CHECK(strcmp(cf_pair_attr(cp), "flag") == 0);
187 TEST_CHECK(cf_pair_value(cp) == NULL);
188
189 talloc_free(cs);
190}
191
193{
194 CONF_SECTION *cs;
195 CONF_PAIR *cp_set, *cp_add, *cp_cmp;
196
197 cs = cf_section_alloc(autofree, NULL, "test", NULL);
198 TEST_ASSERT(cs != NULL);
199
200 cp_set = cf_pair_alloc(cs, "a", "1", T_OP_SET, T_BARE_WORD, T_BARE_WORD);
201 TEST_ASSERT(cp_set != NULL);
203
204 cp_add = cf_pair_alloc(cs, "b", "2", T_OP_ADD_EQ, T_BARE_WORD, T_BARE_WORD);
205 TEST_ASSERT(cp_add != NULL);
207
208 cp_cmp = cf_pair_alloc(cs, "c", "3", T_OP_CMP_EQ, T_BARE_WORD, T_BARE_WORD);
209 TEST_ASSERT(cp_cmp != NULL);
211
212 talloc_free(cs);
213}
214
215static void test_pair_replace(void)
216{
217 CONF_SECTION *cs;
218 CONF_PAIR *cp;
219 int ret;
220
221 cs = cf_section_alloc(autofree, NULL, "test", NULL);
222 TEST_ASSERT(cs != NULL);
223
224 cp = cf_pair_alloc(cs, "key", "old", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
225 TEST_ASSERT(cp != NULL);
226
227 ret = cf_pair_replace(cs, cp, "new");
228 TEST_CHECK(ret == 0);
229 TEST_CHECK(strcmp(cf_pair_value(cp), "new") == 0);
230
231 talloc_free(cs);
232}
233
235{
236 CONF_SECTION *cs;
237 CONF_PAIR *cp;
238 CONF_ITEM *ci;
239
240 cs = cf_section_alloc(autofree, NULL, "test", NULL);
241 TEST_ASSERT(cs != NULL);
242
243 cp = cf_pair_alloc(cs, "attr", "val", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
244 TEST_ASSERT(cp != NULL);
245
246 ci = cf_pair_to_item(cp);
247 TEST_ASSERT(ci != NULL);
250 TEST_CHECK(cf_item_to_pair(ci) == cp);
251
252 talloc_free(cs);
253}
254
255
256/*
257 * Section search and traversal
258 */
259
260static void test_section_find_child(void)
261{
262 CONF_SECTION *parent, *c1, *c2, *c3, *found;
263
264 parent = cf_section_alloc(autofree, NULL, "root", NULL);
265 TEST_ASSERT(parent != NULL);
266
267 c1 = cf_section_alloc(autofree, parent, "alpha", NULL);
268 TEST_ASSERT(c1 != NULL);
269
270 c2 = cf_section_alloc(autofree, parent, "beta", NULL);
271 TEST_ASSERT(c2 != NULL);
272
273 c3 = cf_section_alloc(autofree, parent, "gamma", NULL);
274 TEST_ASSERT(c3 != NULL);
275
276 found = cf_section_find(parent, "beta", NULL);
277 TEST_CHECK(found == c2);
278
279 found = cf_section_find(parent, "gamma", NULL);
280 TEST_CHECK(found == c3);
281
283}
284
286{
287 CONF_SECTION *parent, *s1, *s2, *found;
288
289 parent = cf_section_alloc(autofree, NULL, "root", NULL);
290 TEST_ASSERT(parent != NULL);
291
292 s1 = cf_section_alloc(autofree, parent, "server", "default");
293 TEST_ASSERT(s1 != NULL);
294
295 s2 = cf_section_alloc(autofree, parent, "server", "inner");
296 TEST_ASSERT(s2 != NULL);
297
298 found = cf_section_find(parent, "server", "default");
299 TEST_CHECK(found == s1);
300
301 found = cf_section_find(parent, "server", "inner");
302 TEST_CHECK(found == s2);
303
305}
306
308{
309 CONF_SECTION *parent, *found;
310
311 parent = cf_section_alloc(autofree, NULL, "root", NULL);
312 TEST_ASSERT(parent != NULL);
313
314 cf_section_alloc(autofree, parent, "exists", NULL);
315
316 found = cf_section_find(parent, "nope", NULL);
317 TEST_CHECK(found == NULL);
318
320}
321
322static void test_section_find_next(void)
323{
324 CONF_SECTION *parent, *s1, *s2, *found;
325
326 parent = cf_section_alloc(autofree, NULL, "root", NULL);
327 TEST_ASSERT(parent != NULL);
328
329 s1 = cf_section_alloc(autofree, parent, "server", "a");
330 TEST_ASSERT(s1 != NULL);
331
332 s2 = cf_section_alloc(autofree, parent, "server", "b");
333 TEST_ASSERT(s2 != NULL);
334
335 found = cf_section_find(parent, "server", CF_IDENT_ANY);
336 TEST_CHECK(found == s1);
337
338 found = cf_section_find_next(parent, found, "server", CF_IDENT_ANY);
339 TEST_CHECK(found == s2);
340
341 found = cf_section_find_next(parent, found, "server", CF_IDENT_ANY);
342 TEST_CHECK(found == NULL);
343
345}
346
347static void test_section_first_next(void)
348{
349 CONF_SECTION *parent, *c1, *c2, *c3, *iter;
350
351 parent = cf_section_alloc(autofree, NULL, "root", NULL);
352 TEST_ASSERT(parent != NULL);
353
354 c1 = cf_section_alloc(autofree, parent, "a", NULL);
355 TEST_ASSERT(c1 != NULL);
356
357 c2 = cf_section_alloc(autofree, parent, "b", NULL);
358 TEST_ASSERT(c2 != NULL);
359
360 c3 = cf_section_alloc(autofree, parent, "c", NULL);
361 TEST_ASSERT(c3 != NULL);
362
363 iter = cf_section_first(parent);
364 TEST_CHECK(iter == c1);
365
366 iter = cf_section_next(parent, iter);
367 TEST_CHECK(iter == c2);
368
369 iter = cf_section_next(parent, iter);
370 TEST_CHECK(iter == c3);
371
372 iter = cf_section_next(parent, iter);
373 TEST_CHECK(iter == NULL);
374
376}
377
378static void test_section_prev(void)
379{
380 CONF_SECTION *parent, *c1, *c2, *c3, *iter;
381
382 parent = cf_section_alloc(autofree, NULL, "root", NULL);
383 TEST_ASSERT(parent != NULL);
384
385 c1 = cf_section_alloc(autofree, parent, "a", NULL);
386 TEST_ASSERT(c1 != NULL);
387
388 c2 = cf_section_alloc(autofree, parent, "b", NULL);
389 TEST_ASSERT(c2 != NULL);
390
391 c3 = cf_section_alloc(autofree, parent, "c", NULL);
392 TEST_ASSERT(c3 != NULL);
393
394 iter = cf_section_prev(parent, c3);
395 TEST_CHECK(iter == c2);
396
397 iter = cf_section_prev(parent, c2);
398 TEST_CHECK(iter == c1);
399
400 iter = cf_section_prev(parent, c1);
401 TEST_CHECK(iter == NULL);
402
404}
405
406static void test_section_value_find(void)
407{
408 CONF_SECTION *cs;
409 char const *val;
410
411 cs = cf_section_alloc(autofree, NULL, "test", NULL);
412 TEST_ASSERT(cs != NULL);
413
414 cf_pair_alloc(cs, "name", "myvalue", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
415
416 val = cf_section_value_find(cs, "name");
417 TEST_ASSERT(val != NULL);
418 TEST_CHECK(strcmp(val, "myvalue") == 0);
419
420 val = cf_section_value_find(cs, "missing");
421 TEST_CHECK(val == NULL);
422
423 talloc_free(cs);
424}
425
426
427/*
428 * Pair search and traversal
429 */
430
431static void test_pair_find_basic(void)
432{
433 CONF_SECTION *cs;
434 CONF_PAIR *cp, *found;
435
436 cs = cf_section_alloc(autofree, NULL, "test", NULL);
437 TEST_ASSERT(cs != NULL);
438
439 cf_pair_alloc(cs, "key1", "val1", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
440 cp = cf_pair_alloc(cs, "key2", "val2", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
441
442 found = cf_pair_find(cs, "key2");
443 TEST_CHECK(found == cp);
444 TEST_CHECK(strcmp(cf_pair_value(found), "val2") == 0);
445
446 talloc_free(cs);
447}
448
449static void test_pair_find_missing(void)
450{
451 CONF_SECTION *cs;
452 CONF_PAIR *found;
453
454 cs = cf_section_alloc(autofree, NULL, "test", NULL);
455 TEST_ASSERT(cs != NULL);
456
457 cf_pair_alloc(cs, "exists", "val", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
458
459 found = cf_pair_find(cs, "nope");
460 TEST_CHECK(found == NULL);
461
462 talloc_free(cs);
463}
464
465static void test_pair_find_next(void)
466{
467 CONF_SECTION *cs;
468 CONF_PAIR *cp1, *cp2, *found;
469
470 cs = cf_section_alloc(autofree, NULL, "test", NULL);
471 TEST_ASSERT(cs != NULL);
472
473 cp1 = cf_pair_alloc(cs, "host", "a", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
474 TEST_ASSERT(cp1 != NULL);
475
476 cp2 = cf_pair_alloc(cs, "host", "b", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
477 TEST_ASSERT(cp2 != NULL);
478
479 found = cf_pair_find(cs, "host");
480 TEST_CHECK(found == cp1);
481
482 found = cf_pair_find_next(cs, found, "host");
483 TEST_CHECK(found == cp2);
484
485 found = cf_pair_find_next(cs, found, "host");
486 TEST_CHECK(found == NULL);
487
488 talloc_free(cs);
489}
490
491static void test_pair_first_next(void)
492{
493 CONF_SECTION *cs;
494 CONF_PAIR *cp1, *cp2, *cp3, *iter;
495
496 cs = cf_section_alloc(autofree, NULL, "test", NULL);
497 TEST_ASSERT(cs != NULL);
498
499 cp1 = cf_pair_alloc(cs, "a", "1", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
500 TEST_ASSERT(cp1 != NULL);
501
502 cp2 = cf_pair_alloc(cs, "b", "2", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
503 TEST_ASSERT(cp2 != NULL);
504
505 cp3 = cf_pair_alloc(cs, "c", "3", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
506 TEST_ASSERT(cp3 != NULL);
507
508 iter = cf_pair_first(cs);
509 TEST_CHECK(iter == cp1);
510
511 iter = cf_pair_next(cs, iter);
512 TEST_CHECK(iter == cp2);
513
514 iter = cf_pair_next(cs, iter);
515 TEST_CHECK(iter == cp3);
516
517 iter = cf_pair_next(cs, iter);
518 TEST_CHECK(iter == NULL);
519
520 talloc_free(cs);
521}
522
523static void test_pair_prev(void)
524{
525 CONF_SECTION *cs;
526 CONF_PAIR *cp1, *cp2, *cp3, *iter;
527
528 cs = cf_section_alloc(autofree, NULL, "test", NULL);
529 TEST_ASSERT(cs != NULL);
530
531 cp1 = cf_pair_alloc(cs, "a", "1", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
532 cp2 = cf_pair_alloc(cs, "b", "2", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
533 cp3 = cf_pair_alloc(cs, "c", "3", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
534
535 iter = cf_pair_prev(cs, cp3);
536 TEST_CHECK(iter == cp2);
537
538 iter = cf_pair_prev(cs, cp2);
539 TEST_CHECK(iter == cp1);
540
541 iter = cf_pair_prev(cs, cp1);
542 TEST_CHECK(iter == NULL);
543
544 talloc_free(cs);
545}
546
547static void test_pair_count(void)
548{
549 CONF_SECTION *cs;
550
551 cs = cf_section_alloc(autofree, NULL, "test", NULL);
552 TEST_ASSERT(cs != NULL);
553
559
560 TEST_CHECK(cf_pair_count(cs, "x") == 3);
561 TEST_CHECK(cf_pair_count(cs, "y") == 2);
562 TEST_CHECK(cf_pair_count(cs, "z") == 0);
563
564 talloc_free(cs);
565}
566
568{
569 CONF_SECTION *parent, *child;
570
571 parent = cf_section_alloc(autofree, NULL, "root", NULL);
572 TEST_ASSERT(parent != NULL);
573
576
577 child = cf_section_alloc(autofree, parent, "sub", NULL);
578 TEST_ASSERT(child != NULL);
579
580 cf_pair_alloc(child, "c", "3", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
581
584
586}
587
588
589/*
590 * Item manipulation
591 */
592
593static void test_item_remove_pair(void)
594{
595 CONF_SECTION *cs;
596 CONF_PAIR *cp;
597
598 cs = cf_section_alloc(autofree, NULL, "test", NULL);
599 TEST_ASSERT(cs != NULL);
600
601 cp = cf_pair_alloc(cs, "remove_me", "val", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
602 TEST_ASSERT(cp != NULL);
603
604 TEST_CHECK(cf_pair_find(cs, "remove_me") == cp);
605
606 cf_item_remove(cs, cp);
607 TEST_CHECK(cf_pair_find(cs, "remove_me") == NULL);
608
609 talloc_free(cp);
610 talloc_free(cs);
611}
612
614{
615 CONF_SECTION *parent, *child;
616
617 parent = cf_section_alloc(autofree, NULL, "root", NULL);
618 TEST_ASSERT(parent != NULL);
619
620 child = cf_section_alloc(autofree, parent, "removable", NULL);
621 TEST_ASSERT(child != NULL);
622
623 TEST_CHECK(cf_section_find(parent, "removable", NULL) == child);
624
625 cf_item_remove(parent, child);
626 TEST_CHECK(cf_section_find(parent, "removable", NULL) == NULL);
627
628 talloc_free(child);
630}
631
632static void test_item_next_mixed(void)
633{
635 CONF_PAIR *cp;
636 CONF_SECTION *cs;
637 CONF_ITEM *ci;
638 int count = 0;
639
640 parent = cf_section_alloc(autofree, NULL, "root", NULL);
641 TEST_ASSERT(parent != NULL);
642
643 cp = cf_pair_alloc(parent, "key", "val", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
644 TEST_ASSERT(cp != NULL);
645
646 cs = cf_section_alloc(autofree, parent, "sub", NULL);
647 TEST_ASSERT(cs != NULL);
648
650
651 /*
652 * cf_item_next iterates all children regardless of type.
653 */
654 for (ci = cf_item_next(parent, NULL); ci; ci = cf_item_next(parent, ci)) {
655 count++;
656 }
657 TEST_CHECK(count == 3);
658 TEST_MSG("Expected 3 items, got %d", count);
659
661}
662
663static void test_item_free_children(void)
664{
665 CONF_SECTION *cs;
666
667 cs = cf_section_alloc(autofree, NULL, "test", NULL);
668 TEST_ASSERT(cs != NULL);
669
672 cf_section_alloc(autofree, cs, "child", NULL);
673
674 TEST_CHECK(cf_pair_first(cs) != NULL);
675 TEST_CHECK(cf_section_first(cs) != NULL);
676
678
679 TEST_CHECK(cf_pair_first(cs) == NULL);
680 TEST_CHECK(cf_section_first(cs) == NULL);
681
682 talloc_free(cs);
683}
684
685static void test_item_mark_parsed(void)
686{
687 CONF_SECTION *cs;
688 CONF_PAIR *cp;
689
690 cs = cf_section_alloc(autofree, NULL, "test", NULL);
691 TEST_ASSERT(cs != NULL);
692
693 cp = cf_pair_alloc(cs, "key", "val", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
694 TEST_ASSERT(cp != NULL);
695
697
700
701 talloc_free(cs);
702}
703
704
705/*
706 * Section duplication
707 */
708
709static void test_section_dup_basic(void)
710{
711 CONF_SECTION *cs, *dup;
712 CONF_PAIR *cp;
713
714 cs = cf_section_alloc(autofree, NULL, "server", "main");
715 TEST_ASSERT(cs != NULL);
716
717 cp = cf_pair_alloc(cs, "listen", "1812", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
718 TEST_ASSERT(cp != NULL);
719 cf_filename_set(cp, "test.conf");
720
721 cp = cf_pair_alloc(cs, "type", "auth", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
722 TEST_ASSERT(cp != NULL);
723 cf_filename_set(cp, "test.conf");
724
725 dup = cf_section_dup(autofree, NULL, cs, cf_section_name1(cs), cf_section_name2(cs), false);
726 TEST_ASSERT(dup != NULL);
727 TEST_CHECK(dup != cs);
728 TEST_CHECK(strcmp(cf_section_name1(dup), "server") == 0);
729 TEST_CHECK(strcmp(cf_section_name2(dup), "main") == 0);
730
731 cp = cf_pair_find(dup, "listen");
732 TEST_ASSERT(cp != NULL);
733 TEST_CHECK(strcmp(cf_pair_value(cp), "1812") == 0);
734
735 cp = cf_pair_find(dup, "type");
736 TEST_ASSERT(cp != NULL);
737 TEST_CHECK(strcmp(cf_pair_value(cp), "auth") == 0);
738
739 talloc_free(cs);
740 talloc_free(dup);
741}
742
743static void test_section_dup_rename(void)
744{
745 CONF_SECTION *cs, *dup;
746 CONF_PAIR *cp;
747
748 cs = cf_section_alloc(autofree, NULL, "server", "old");
749 TEST_ASSERT(cs != NULL);
750
751 cp = cf_pair_alloc(cs, "port", "1812", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
752 TEST_ASSERT(cp != NULL);
753 cf_filename_set(cp, "test.conf");
754
755 dup = cf_section_dup(autofree, NULL, cs, "newname", "newname2", false);
756 TEST_ASSERT(dup != NULL);
757 TEST_CHECK(strcmp(cf_section_name1(dup), "newname") == 0);
758 TEST_CHECK(strcmp(cf_section_name2(dup), "newname2") == 0);
759
760 /*
761 * Children should still be present.
762 */
763 TEST_CHECK(cf_pair_find(dup, "port") != NULL);
764
765 talloc_free(cs);
766 talloc_free(dup);
767}
768
770{
771 CONF_SECTION *cs, *sub, *dup, *dup_sub;
772 CONF_PAIR *cp;
773
774 cs = cf_section_alloc(autofree, NULL, "tcp", NULL);
775 TEST_ASSERT(cs != NULL);
776
777 cf_pair_alloc(cs, "port", "49", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
778
779 sub = cf_section_alloc(autofree, cs, "networks", NULL);
780 TEST_ASSERT(sub != NULL);
781
782 cf_pair_alloc(sub, "allow", "0.0.0.0/0", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
783 cf_pair_alloc(sub, "allow", "192.0.2.0/24", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
784
785 dup = cf_section_dup(autofree, NULL, cs, cf_section_name1(cs), cf_section_name2(cs), false);
786 TEST_ASSERT(dup != NULL);
787
788 /* Top-level pair should survive the copy. */
789 cp = cf_pair_find(dup, "port");
790 TEST_ASSERT(cp != NULL);
791 TEST_CHECK(strcmp(cf_pair_value(cp), "49") == 0);
792
793 /* The nested subsection must exist in the copy. */
794 dup_sub = cf_section_find(dup, "networks", NULL);
795 TEST_ASSERT(dup_sub != NULL);
796
797 /* Both pairs inside the nested subsection must be present. */
798 cp = cf_pair_find(dup_sub, "allow");
799 TEST_ASSERT(cp != NULL);
800 TEST_CHECK(strcmp(cf_pair_value(cp), "0.0.0.0/0") == 0);
801
802 cp = cf_pair_find_next(dup_sub, cp, "allow");
803 TEST_ASSERT(cp != NULL);
804 TEST_CHECK(strcmp(cf_pair_value(cp), "192.0.2.0/24") == 0);
805
806 talloc_free(cs);
807 talloc_free(dup);
808}
809
810static void test_pair_dup(void)
811{
812 CONF_SECTION *cs1, *cs2;
813 CONF_PAIR *cp, *dup;
814
815 cs1 = cf_section_alloc(autofree, NULL, "src", NULL);
816 TEST_ASSERT(cs1 != NULL);
817
818 cs2 = cf_section_alloc(autofree, NULL, "dst", NULL);
819 TEST_ASSERT(cs2 != NULL);
820
821 cp = cf_pair_alloc(cs1, "key", "val", T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
822 TEST_ASSERT(cp != NULL);
823
824 dup = cf_pair_dup(cs2, cp, false);
825 TEST_ASSERT(dup != NULL);
826 TEST_CHECK(dup != cp);
827 TEST_CHECK(strcmp(cf_pair_attr(dup), "key") == 0);
828 TEST_CHECK(strcmp(cf_pair_value(dup), "val") == 0);
831
832 talloc_free(cs1);
833 talloc_free(cs2);
834}
835
836
837/*
838 * Metadata
839 */
840
841static void test_filename_lineno(void)
842{
843 CONF_SECTION *cs;
844
845 cs = cf_section_alloc(autofree, NULL, "test", NULL);
846 TEST_ASSERT(cs != NULL);
847
848 /*
849 * In debug builds, cf_section_alloc sets filename to __FILE__
850 * and lineno to __LINE__. Just verify they are set to something.
851 */
852#ifndef NDEBUG
853 TEST_CHECK(cf_filename(cs) != NULL);
854 TEST_CHECK(cf_lineno(cs) > 0);
855#endif
856
857 talloc_free(cs);
858}
859
860static void test_filename_set(void)
861{
862 CONF_SECTION *cs;
863
864 cs = cf_section_alloc(autofree, NULL, "test", NULL);
865 TEST_ASSERT(cs != NULL);
866
867 cf_filename_set(cs, "test.conf");
868 TEST_CHECK(strcmp(cf_filename(cs), "test.conf") == 0);
869
870 talloc_free(cs);
871}
872
873static void test_lineno_set(void)
874{
875 CONF_SECTION *cs;
876
877 cs = cf_section_alloc(autofree, NULL, "test", NULL);
878 TEST_ASSERT(cs != NULL);
879
880 cf_lineno_set(cs, 42);
881 TEST_CHECK(cf_lineno(cs) == 42);
882
883 talloc_free(cs);
884}
885
886static void test_cf_root(void)
887{
888 CONF_SECTION *root, *mid, *leaf;
889
890 root = cf_section_alloc(autofree, NULL, "root", NULL);
891 TEST_ASSERT(root != NULL);
892
893 mid = cf_section_alloc(autofree, root, "mid", NULL);
894 TEST_ASSERT(mid != NULL);
895
896 leaf = cf_section_alloc(autofree, mid, "leaf", NULL);
897 TEST_ASSERT(leaf != NULL);
898
899 TEST_CHECK(cf_root(leaf) == root);
900 TEST_CHECK(cf_root(mid) == root);
901 TEST_CHECK(cf_root(root) == root);
902
903 talloc_free(root);
904}
905
906
907/*
908 * CONF_DATA
909 */
910
911static void test_data_add_find(void)
912{
913 CONF_SECTION *cs;
914 uint32_t *val;
915 CONF_DATA const *cd;
916 void *found;
917
918 cs = cf_section_alloc(autofree, NULL, "test", NULL);
919 TEST_ASSERT(cs != NULL);
920
921 val = talloc(cs, uint32_t);
922 TEST_ASSERT(val != NULL);
923 *val = 12345;
924
925 cd = cf_data_add(cs, val, "counter", false);
926 TEST_CHECK(cd != NULL);
927
928 found = cf_data_value(cd);
929 TEST_CHECK(found == val);
930 TEST_CHECK(*(uint32_t *)found == 12345);
931
932 talloc_free(cs);
933}
934
935static void test_data_find_missing(void)
936{
937 CONF_SECTION *cs;
938 CONF_DATA const *cd;
939
940 cs = cf_section_alloc(autofree, NULL, "test", NULL);
941 TEST_ASSERT(cs != NULL);
942
943 cd = _cf_data_find(cf_section_to_item(cs), "uint32_t", "nonexistent");
944 TEST_CHECK(cd == NULL);
945
946 talloc_free(cs);
947}
948
949static void test_data_remove(void)
950{
951 CONF_SECTION *cs;
952 uint32_t *val;
953 CONF_DATA const *cd;
954
955 cs = cf_section_alloc(autofree, NULL, "test", NULL);
956 TEST_ASSERT(cs != NULL);
957
958 val = talloc(cs, uint32_t);
959 *val = 99;
960
961 cd = cf_data_add(cs, val, "remove_me", false);
962 TEST_CHECK(cd != NULL);
963
965
966 cd = _cf_data_find(cf_section_to_item(cs), "uint32_t", "remove_me");
967 TEST_CHECK(cd == NULL);
968
969 talloc_free(cs);
970}
971
972
973/*
974 * Variable expansion - cf_expand_variables
975 */
976
978{
979 CONF_SECTION *cs;
980 char output[256];
981 char const *result;
982
983 cs = cf_section_alloc(autofree, NULL, "root", NULL);
984 TEST_ASSERT(cs != NULL);
985
986 result = cf_expand_variables("test.conf", 1, cs,
987 output, sizeof(output),
988 "hello world", -1, NULL, false);
989 TEST_CHECK(result != NULL);
990 if (result) {
991 TEST_CHECK(strcmp(result, "hello world") == 0);
992 TEST_MSG("Expected 'hello world', got '%s'", result);
993 }
994
995 talloc_free(cs);
996}
997
998static void test_expand_section_ref(void)
999{
1000 CONF_SECTION *cs;
1001 char output[256];
1002 char const *result;
1003
1004 cs = cf_section_alloc(autofree, NULL, "root", NULL);
1005 TEST_ASSERT(cs != NULL);
1006
1007 cf_pair_alloc(cs, "name", "testval", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
1008
1009 result = cf_expand_variables("test.conf", 1, cs,
1010 output, sizeof(output),
1011 "${name}", -1, NULL, false);
1012 TEST_CHECK(result != NULL);
1013 if (result) {
1014 TEST_CHECK(strcmp(result, "testval") == 0);
1015 TEST_MSG("Expected 'testval', got '%s'", result);
1016 }
1017
1018 talloc_free(cs);
1019}
1020
1021static void test_expand_nested_ref(void)
1022{
1023 CONF_SECTION *root, *sub;
1024 char output[256];
1025 char const *result;
1026
1027 root = cf_section_alloc(autofree, NULL, "root", NULL);
1028 TEST_ASSERT(root != NULL);
1029
1030 sub = cf_section_alloc(autofree, root, "server", NULL);
1031 TEST_ASSERT(sub != NULL);
1032
1033 cf_pair_alloc(sub, "name", "myserver", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
1034
1035 result = cf_expand_variables("test.conf", 1, root,
1036 output, sizeof(output),
1037 "${server.name}", -1, NULL, false);
1038 TEST_CHECK(result != NULL);
1039 if (result) {
1040 TEST_CHECK(strcmp(result, "myserver") == 0);
1041 TEST_MSG("Expected 'myserver', got '%s'", result);
1042 }
1043
1044 talloc_free(root);
1045}
1046
1048{
1049 CONF_SECTION *cs;
1050 char output[256];
1051 char const *result;
1052 bool soft_fail = false;
1053
1054 cs = cf_section_alloc(autofree, NULL, "root", NULL);
1055 TEST_ASSERT(cs != NULL);
1056
1057 result = cf_expand_variables("test.conf", 1, cs,
1058 output, sizeof(output),
1059 "${nonexistent}", -1, &soft_fail, false);
1060 TEST_CHECK(result == NULL);
1061 TEST_CHECK(soft_fail == true);
1062 TEST_MSG("Expected soft_fail to be set for missing reference");
1063
1064 talloc_free(cs);
1065}
1066
1067
1068/*
1069 * cf_reference_item
1070 */
1071
1073{
1074 CONF_SECTION *cs;
1075 CONF_PAIR *cp;
1076 CONF_ITEM *ci;
1077
1078 cs = cf_section_alloc(autofree, NULL, "root", NULL);
1079 TEST_ASSERT(cs != NULL);
1080
1081 cp = cf_pair_alloc(cs, "mykey", "myval", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
1082 TEST_ASSERT(cp != NULL);
1083
1084 ci = cf_reference_item(cs, cs, "mykey");
1085 TEST_CHECK(ci != NULL);
1086 if (ci) {
1088 TEST_CHECK(cf_item_to_pair(ci) == cp);
1089 }
1090
1091 talloc_free(cs);
1092}
1093
1095{
1096 CONF_SECTION *root, *child;
1097 CONF_ITEM *ci;
1098
1099 root = cf_section_alloc(autofree, NULL, "root", NULL);
1100 TEST_ASSERT(root != NULL);
1101
1102 child = cf_section_alloc(autofree, root, "child", NULL);
1103 TEST_ASSERT(child != NULL);
1104
1105 ci = cf_reference_item(root, root, "child");
1106 TEST_CHECK(ci != NULL);
1107 if (ci) {
1109 TEST_CHECK(cf_item_to_section(ci) == child);
1110 }
1111
1112 talloc_free(root);
1113}
1114
1116{
1117 CONF_SECTION *cs;
1118 CONF_ITEM *ci;
1119
1120 cs = cf_section_alloc(autofree, NULL, "root", NULL);
1121 TEST_ASSERT(cs != NULL);
1122
1123 ci = cf_reference_item(cs, cs, "nonexistent");
1124 TEST_CHECK(ci == NULL);
1125
1126 talloc_free(cs);
1127}
1128
1129
1130/*
1131 * cf_pair_in_table
1132 */
1133
1135 { L("bar"), 2 },
1136 { L("foo"), 1 },
1137};
1139
1141{
1142 CONF_SECTION *cs;
1143 CONF_PAIR *cp;
1144 int32_t out = 0;
1145 int ret;
1146
1147 cs = cf_section_alloc(autofree, NULL, "test", NULL);
1148 TEST_ASSERT(cs != NULL);
1149
1150 cp = cf_pair_alloc(cs, "type", "foo", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
1151 TEST_ASSERT(cp != NULL);
1152
1154 TEST_CHECK(ret == 0);
1155 TEST_CHECK(out == 1);
1156
1157 talloc_free(cs);
1158}
1159
1161{
1162 CONF_SECTION *cs;
1163 CONF_PAIR *cp;
1164 int32_t out = 0;
1165 int ret;
1166
1167 cs = cf_section_alloc(autofree, NULL, "test", NULL);
1168 TEST_ASSERT(cs != NULL);
1169
1170 cp = cf_pair_alloc(cs, "type", "invalid_value", T_OP_EQ, T_BARE_WORD, T_BARE_WORD);
1171 TEST_ASSERT(cp != NULL);
1172
1174 TEST_CHECK(ret == -1);
1175
1176 talloc_free(cs);
1177}
1178
1179
1180/*
1181 * Reading a configuration from a file or a buffer
1182 */
1183
1184/** Count the pairs and sections in a section, ignoring CONF_DATA
1185 *
1186 * cf_file_read() and cf_file_read_buffer() both attach the file dedup tree to
1187 * the section as CONF_DATA, so an "empty" configuration is never childless.
1188 */
1189static unsigned int test_config_item_count(CONF_SECTION *cs)
1190{
1191 unsigned int count = 0;
1192
1194 if (cf_item_is_pair(ci) || cf_item_is_section(ci)) count++;
1195 }
1196
1197 return count;
1198}
1199
1201{
1202 CONF_SECTION *cs;
1203 char filename[] = "/tmp/cf_tests.XXXXXX";
1204 int fd;
1205 mode_t old_umask;
1206
1207 old_umask = umask(S_IRWXG | S_IRWXO);
1208 fd = mkstemp(filename);
1209 umask(old_umask);
1210 TEST_ASSERT(fd >= 0);
1211 close(fd);
1212
1213 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1214 TEST_ASSERT(cs != NULL);
1215
1216 /*
1217 * A file with no content is an empty configuration, not an
1218 * error. cf_file_fill() has read no line at this point, so
1219 * its buffer holds no terminator, and anything which measures
1220 * the buffer before checking for EOF runs off the end of it.
1221 */
1222 TEST_CHECK(cf_file_read(cs, filename, false) == 0);
1224
1225 talloc_free(cs);
1226 unlink(filename);
1227}
1228
1230{
1231 CONF_SECTION *cs;
1232 char const *input = "# nothing but a comment\n";
1233
1234 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1235 TEST_ASSERT(cs != NULL);
1236
1237 TEST_CHECK(cf_file_read_buffer(cs, input, strlen(input), "<test>") == 0);
1239
1240 talloc_free(cs);
1241}
1242
1244{
1245 CONF_SECTION *cs;
1246 CONF_PAIR *cp;
1247 char const *input = "foo = bar\n";
1248
1249 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1250 TEST_ASSERT(cs != NULL);
1251
1252 TEST_CHECK(cf_file_read_buffer(cs, input, strlen(input), "<test>") == 0);
1253
1254 cp = cf_pair_find(cs, "foo");
1255 TEST_ASSERT(cp != NULL);
1256 TEST_CHECK(strcmp(cf_pair_value(cp), "bar") == 0);
1257
1258 talloc_free(cs);
1259}
1260
1262{
1263 CONF_SECTION *cs, *subcs;
1264 CONF_PAIR *cp;
1265
1266 /*
1267 * The '"' before the trailing '\\' turns on suppression of
1268 * the leading whitespace on the continuation line. The
1269 * continuation line ends the file without a newline, so
1270 * neither the CR/LF strip nor the continuation check rewrites
1271 * the end of the line after the whitespace is moved out.
1272 */
1273 char const *input = "s {\nfoo = \"a\"\\\n }";
1274
1275 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1276 TEST_ASSERT(cs != NULL);
1277
1278 TEST_CHECK(cf_file_read_buffer(cs, input, strlen(input), "<test>") == 0);
1279
1280 subcs = cf_section_find(cs, "s", NULL);
1281 TEST_ASSERT(subcs != NULL);
1282
1283 cp = cf_pair_find(subcs, "foo");
1284 TEST_ASSERT(cp != NULL);
1285 TEST_CHECK(strcmp(cf_pair_value(cp), "a") == 0);
1286
1287 talloc_free(cs);
1288}
1289
1290/*
1291 * Parsing a pair's value to the type of a rule
1292 */
1293
1300
1302 { FR_CONF_OFFSET("bare", test_octets_t, bare) },
1303 { FR_CONF_OFFSET("quoted_hex", test_octets_t, quoted_hex) },
1304 { FR_CONF_OFFSET("quoted_text", test_octets_t, quoted_text) },
1305 { FR_CONF_OFFSET("quoted_escape", test_octets_t, quoted_escape) },
1307};
1308
1309/** The quotes around a value are the type hint for an octets item
1310 *
1311 * The parser reads a bare word that starts with 0x as hexadecimal
1312 * bytes. A quoted value is text, even when the text starts with 0x,
1313 * so "0xff" is the four characters of the text and not one byte. The
1314 * parser processes escape sequences in the text.
1315 */
1317{
1318 CONF_SECTION *cs;
1319 test_octets_t out = {};
1320 char const *input = "bare = 0xff\n"
1321 "quoted_hex = \"0xff\"\n"
1322 "quoted_text = \"password123\"\n"
1323 "quoted_escape = \"a\\\"b\\n\"\n";
1324
1325 cs = cf_section_alloc(autofree, NULL, "main", NULL);
1326 TEST_ASSERT(cs != NULL);
1327
1328 TEST_CHECK(cf_file_read_buffer(cs, input, strlen(input), "<test>") == 0);
1330 TEST_CHECK(cf_section_parse(cs, &out, cs) == 0);
1331
1332 TEST_ASSERT(out.bare != NULL);
1333 TEST_CHECK(talloc_array_length(out.bare) == 1);
1334 TEST_MSG("Expected bare to be 1 byte, got %zu", talloc_array_length(out.bare));
1335 TEST_CHECK(out.bare[0] == 0xff);
1336
1337 TEST_ASSERT(out.quoted_hex != NULL);
1338 TEST_CHECK(talloc_array_length(out.quoted_hex) == 4);
1339 TEST_MSG("Expected quoted_hex to be 4 bytes, got %zu", talloc_array_length(out.quoted_hex));
1340 TEST_CHECK(memcmp(out.quoted_hex, "0xff", 4) == 0);
1341
1342 TEST_ASSERT(out.quoted_text != NULL);
1343 TEST_CHECK(talloc_array_length(out.quoted_text) == 11);
1344 TEST_MSG("Expected quoted_text to be 11 bytes, got %zu", talloc_array_length(out.quoted_text));
1345 TEST_CHECK(memcmp(out.quoted_text, "password123", 11) == 0);
1346
1347 TEST_ASSERT(out.quoted_escape != NULL);
1348 TEST_CHECK(talloc_array_length(out.quoted_escape) == 4);
1349 TEST_MSG("Expected quoted_escape to be 4 bytes, got %zu", talloc_array_length(out.quoted_escape));
1350 TEST_CHECK(memcmp(out.quoted_escape, "a\"b\n", 4) == 0);
1351
1352 talloc_free(cs);
1353}
1354
1356 /* Section allocation and accessors */
1357 { "test_section_alloc_name1_only", test_section_alloc_name1_only },
1358 { "test_section_alloc_name1_name2", test_section_alloc_name1_name2 },
1359 { "test_section_alloc_parent", test_section_alloc_parent },
1360 { "test_section_name_cmp", test_section_name_cmp },
1361 { "test_section_to_item_roundtrip", test_section_to_item_roundtrip },
1362
1363 /* Pair allocation and accessors */
1364 { "test_pair_alloc_basic", test_pair_alloc_basic },
1365 { "test_pair_alloc_quoted", test_pair_alloc_quoted },
1366 { "test_pair_alloc_no_value", test_pair_alloc_no_value },
1367 { "test_pair_alloc_operators", test_pair_alloc_operators },
1368 { "test_pair_replace", test_pair_replace },
1369 { "test_pair_to_item_roundtrip", test_pair_to_item_roundtrip },
1370
1371 /* Section search and traversal */
1372 { "test_section_find_child", test_section_find_child },
1373 { "test_section_find_name1_name2", test_section_find_name1_name2 },
1374 { "test_section_find_missing", test_section_find_missing },
1375 { "test_section_find_next", test_section_find_next },
1376 { "test_section_first_next", test_section_first_next },
1377 { "test_section_prev", test_section_prev },
1378 { "test_section_value_find", test_section_value_find },
1379
1380 /* Pair search and traversal */
1381 { "test_pair_find_basic", test_pair_find_basic },
1382 { "test_pair_find_missing", test_pair_find_missing },
1383 { "test_pair_find_next", test_pair_find_next },
1384 { "test_pair_first_next", test_pair_first_next },
1385 { "test_pair_prev", test_pair_prev },
1386 { "test_pair_count", test_pair_count },
1387 { "test_pair_count_descendents", test_pair_count_descendents },
1388
1389 /* Item manipulation */
1390 { "test_item_remove_pair", test_item_remove_pair },
1391 { "test_item_remove_section", test_item_remove_section },
1392 { "test_item_next_mixed", test_item_next_mixed },
1393 { "test_item_free_children", test_item_free_children },
1394 { "test_item_mark_parsed", test_item_mark_parsed },
1395
1396 /* Section duplication */
1397 { "test_section_dup_basic", test_section_dup_basic },
1398 { "test_section_dup_rename", test_section_dup_rename },
1399 { "test_section_dup_nested_pairs", test_section_dup_nested_pairs },
1400 { "test_pair_dup", test_pair_dup },
1401
1402 /* Metadata */
1403 { "test_filename_lineno", test_filename_lineno },
1404 { "test_filename_set", test_filename_set },
1405 { "test_lineno_set", test_lineno_set },
1406 { "test_cf_root", test_cf_root },
1407
1408 /* CONF_DATA */
1409 { "test_data_add_find", test_data_add_find },
1410 { "test_data_find_missing", test_data_find_missing },
1411 { "test_data_remove", test_data_remove },
1412
1413 /* Variable expansion */
1414 { "test_expand_no_variables", test_expand_no_variables },
1415 { "test_expand_section_ref", test_expand_section_ref },
1416 { "test_expand_nested_ref", test_expand_nested_ref },
1417 { "test_expand_missing_ref", test_expand_missing_ref },
1418
1419 /* cf_reference_item */
1420 { "test_reference_item_pair", test_reference_item_pair },
1421 { "test_reference_item_section", test_reference_item_section },
1422 { "test_reference_item_missing", test_reference_item_missing },
1423
1424 /* cf_pair_in_table */
1425 { "test_pair_in_table_found", test_pair_in_table_found },
1426 { "test_pair_in_table_invalid", test_pair_in_table_invalid },
1427
1428 /* Reading a configuration from a file or a buffer */
1429 { "test_file_read_empty_file", test_file_read_empty_file },
1430 { "test_file_read_buffer_comment_only", test_file_read_buffer_comment_only },
1431 { "test_file_read_buffer_pair", test_file_read_buffer_pair },
1432 { "test_file_read_buffer_continuation_no_newline", test_file_read_buffer_continuation_no_newline },
1433
1434 /* Parsing a pair's value to the type of a rule */
1435 { "test_pair_parse_octets_quote", test_pair_parse_octets_quote },
1436
1438};
#define TEST_CHECK(cond)
Definition acutest.h:101
#define TEST_ASSERT(cond)
Definition acutest.h:125
#define TEST_TERMINATOR
Definition acutest.h:77
#define TEST_MSG(...)
Definition acutest.h:234
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define NUM_ELEMENTS(_t)
Definition build.h:437
int cf_file_read_buffer(CONF_SECTION *cs, char const *buffer, size_t buflen, char const *filename)
Bootstrap a configuration section from an in-memory buffer.
Definition cf_file.c:4142
char const * cf_expand_variables(char const *cf, int lineno, CONF_SECTION *outer_cs, char *output, size_t outsize, char const *input, ssize_t inlen, bool *soft_fail, bool soft_fail_env)
Definition cf_file.c:300
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition cf_file.c:4041
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:4386
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1360
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:712
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:744
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
Internal data that is associated with a configuration section.
Definition cf_priv.h:195
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
TEST_LIST
Definition cf_tests.c:1355
static void test_section_alloc_parent(void)
Definition cf_tests.c:87
static size_t test_table_len
Definition cf_tests.c:1138
static void test_section_dup_nested_pairs(void)
Definition cf_tests.c:769
static void test_item_remove_pair(void)
Definition cf_tests.c:593
static void test_data_remove(void)
Definition cf_tests.c:949
static void test_section_find_name1_name2(void)
Definition cf_tests.c:285
static TALLOC_CTX * autofree
Definition cf_tests.c:34
static void test_cf_root(void)
Definition cf_tests.c:886
uint8_t const * bare
Definition cf_tests.c:1295
static void test_section_name_cmp(void)
Definition cf_tests.c:103
static void test_filename_lineno(void)
Definition cf_tests.c:841
static void test_pair_in_table_invalid(void)
Definition cf_tests.c:1160
static void test_pair_parse_octets_quote(void)
The quotes around a value are the type hint for an octets item.
Definition cf_tests.c:1316
static void test_file_read_buffer_continuation_no_newline(void)
Definition cf_tests.c:1261
static void test_pair_find_next(void)
Definition cf_tests.c:465
static void test_item_mark_parsed(void)
Definition cf_tests.c:685
static void test_section_alloc_name1_name2(void)
Definition cf_tests.c:74
static conf_parser_t const test_octets_rules[]
Definition cf_tests.c:1301
static unsigned int test_config_item_count(CONF_SECTION *cs)
Count the pairs and sections in a section, ignoring CONF_DATA.
Definition cf_tests.c:1189
static void test_pair_count_descendents(void)
Definition cf_tests.c:567
static void test_section_to_item_roundtrip(void)
Definition cf_tests.c:117
static void test_reference_item_pair(void)
Definition cf_tests.c:1072
static void test_reference_item_section(void)
Definition cf_tests.c:1094
static void test_expand_nested_ref(void)
Definition cf_tests.c:1021
static void test_file_read_empty_file(void)
Definition cf_tests.c:1200
static void test_pair_first_next(void)
Definition cf_tests.c:491
static void test_section_first_next(void)
Definition cf_tests.c:347
static void test_expand_section_ref(void)
Definition cf_tests.c:998
static void test_section_value_find(void)
Definition cf_tests.c:406
static void test_pair_count(void)
Definition cf_tests.c:547
static void test_data_find_missing(void)
Definition cf_tests.c:935
static void test_reference_item_missing(void)
Definition cf_tests.c:1115
static void test_expand_no_variables(void)
Definition cf_tests.c:977
static void test_pair_find_basic(void)
Definition cf_tests.c:431
static void test_pair_in_table_found(void)
Definition cf_tests.c:1140
static void test_pair_replace(void)
Definition cf_tests.c:215
static void test_section_dup_basic(void)
Definition cf_tests.c:709
static void test_pair_alloc_no_value(void)
Definition cf_tests.c:175
static void test_lineno_set(void)
Definition cf_tests.c:873
static void test_file_read_buffer_pair(void)
Definition cf_tests.c:1243
static void test_section_alloc_name1_only(void)
Definition cf_tests.c:60
static void test_pair_to_item_roundtrip(void)
Definition cf_tests.c:234
static void test_expand_missing_ref(void)
Definition cf_tests.c:1047
uint8_t const * quoted_escape
Definition cf_tests.c:1298
static void test_pair_alloc_quoted(void)
Definition cf_tests.c:158
static void test_item_remove_section(void)
Definition cf_tests.c:613
static void test_section_find_missing(void)
Definition cf_tests.c:307
static void test_section_dup_rename(void)
Definition cf_tests.c:743
static void test_pair_find_missing(void)
Definition cf_tests.c:449
static void test_item_free_children(void)
Definition cf_tests.c:663
uint8_t const * quoted_text
Definition cf_tests.c:1297
static void test_pair_dup(void)
Definition cf_tests.c:810
static void test_section_find_next(void)
Definition cf_tests.c:322
static void test_item_next_mixed(void)
Definition cf_tests.c:632
static void test_section_find_child(void)
Definition cf_tests.c:260
static void test_init(void)
Global initialisation.
Definition cf_tests.c:38
static void test_data_add_find(void)
Definition cf_tests.c:911
static void test_file_read_buffer_comment_only(void)
Definition cf_tests.c:1229
uint8_t const * quoted_hex
Definition cf_tests.c:1296
static void test_pair_alloc_operators(void)
Definition cf_tests.c:192
static void test_pair_alloc_basic(void)
Definition cf_tests.c:140
static void test_section_prev(void)
Definition cf_tests.c:378
static fr_table_num_sorted_t const test_table[]
Definition cf_tests.c:1134
static void test_pair_prev(void)
Definition cf_tests.c:523
static void test_filename_set(void)
Definition cf_tests.c:860
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:619
fr_token_t cf_pair_attr_quote(CONF_PAIR const *pair)
Return the value (lhs) quoting of a pair.
Definition cf_util.c:1787
void * _cf_data_remove(CONF_ITEM *parent, CONF_DATA const *cd)
Remove data from a configuration section.
Definition cf_util.c:2031
unsigned int cf_pair_count_descendents(CONF_SECTION const *cs)
Count the number of conf pairs beneath a section.
Definition cf_util.c:1706
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
Definition cf_util.c:1654
CONF_DATA const * _cf_data_find(CONF_ITEM const *ci, char const *type, char const *name)
Find user data in a config section.
Definition cf_util.c:1869
unsigned int cf_pair_count(CONF_SECTION const *cs, char const *attr)
Count the number of times an attribute occurs in a parent section.
Definition cf_util.c:1721
int cf_pair_in_table(int32_t *out, fr_table_num_sorted_t const *table, size_t table_len, CONF_PAIR *cp)
Check to see if the CONF_PAIR value is present in the specified table.
Definition cf_util.c:2129
CONF_PAIR * cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp, bool copy_meta)
Duplicate a CONF_PAIR.
Definition cf_util.c:1529
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1922
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:725
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1487
CONF_SECTION * cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the next child that's a CONF_SECTION.
Definition cf_util.c:1216
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1391
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1247
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:671
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1640
char const * cf_section_value_find(CONF_SECTION const *cs, char const *attr)
Find a pair in a CONF_SECTION.
Definition cf_util.c:1339
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
Definition cf_util.c:1417
bool cf_item_is_data(CONF_ITEM const *ci)
Determine if CONF_ITEM is CONF_DATA.
Definition cf_util.c:633
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition cf_util.c:1772
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1802
CONF_PAIR * cf_pair_first(CONF_SECTION const *cs)
Return the first child that's a CONF_PAIR.
Definition cf_util.c:1601
CONF_PAIR * cf_pair_next(CONF_SECTION const *cs, CONF_PAIR const *curr)
Return the next child that's a CONF_PAIR.
Definition cf_util.c:1614
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:605
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
Definition cf_util.c:1052
CONF_PAIR * cf_pair_prev(CONF_SECTION const *cs, CONF_PAIR const *curr)
Return the previous child that's a CONF_PAIR.
Definition cf_util.c:1627
fr_cmp_ret_t cf_section_name_cmp(CONF_SECTION const *cs, char const *name1, char const *name2)
Check if a given section matches the specified name1/name2 identifiers.
Definition cf_util.c:1358
CONF_SECTION * cf_section_first(CONF_SECTION const *cs)
Return the first child in a CONF_SECTION.
Definition cf_util.c:1203
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:651
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition cf_util.c:1268
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1758
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair value in a given section with the given value.
Definition cf_util.c:1561
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:709
CONF_SECTION * cf_section_prev(CONF_SECTION const *cs, CONF_SECTION const *curr)
Return the previous child that's a CONF_SECTION.
Definition cf_util.c:1229
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1742
#define cf_lineno(_cf)
Definition cf_util.h:118
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:306
#define cf_item_is_parsed(_cf)
Definition cf_util.h:191
#define cf_lineno_set(_ci, _lineno)
Definition cf_util.h:183
#define cf_root(_cf)
Definition cf_util.h:112
#define cf_section_free_children(_x)
Definition cf_util.h:251
#define cf_parent(_cf)
Definition cf_util.h:115
#define cf_item_remove(_parent, _child)
Definition cf_util.h:88
#define cf_item_next(_parent, _curr)
Definition cf_util.h:91
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:198
#define cf_item_foreach(_parent, _iter)
Iterate over every child item of a CONF_SECTION (or any CONF_ITEM that has children).
Definition cf_util.h:106
#define cf_filename_set(_ci, _filename)
Definition cf_util.h:180
#define cf_filename(_cf)
Definition cf_util.h:121
#define cf_item_mark_parsed(_cf)
Definition cf_util.h:188
#define CF_IDENT_ANY
Definition cf_util.h:80
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:272
talloc_free(hp)
unsigned int uint32_t
unsigned char uint8_t
return count
Definition module.c:155
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_OP_SET
Definition token.h:82
@ T_OP_ADD_EQ
Definition token.h:67
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
@ T_OP_CMP_EQ
Definition token.h:104
static fr_slen_t parent
Definition pair.h:864
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
static fr_sbuff_err_t char ** out
Definition value.h:1061