The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
cf_parse.c
Go to the documentation of this file.
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: e462f6b22f92c6399247e4d41b7d080319984e73 $
19 * @file cf_parse.c
20 * @brief Convert internal format configuration values into native C types.
21 *
22 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Alan DeKok (aland@freeradius.org)
25 */
26RCSID("$Id: e462f6b22f92c6399247e4d41b7d080319984e73 $")
27
28#include <string.h>
29#include <sys/errno.h>
30#include <sys/fcntl.h>
31
32#include <freeradius-devel/server/cf_file.h>
33#include <freeradius-devel/server/cf_parse.h>
34#include <freeradius-devel/server/cf_priv.h>
35#include <freeradius-devel/server/log.h>
36#include <freeradius-devel/server/tmpl.h>
37#include <freeradius-devel/server/virtual_servers.h>
38#include <freeradius-devel/server/main_config.h>
39#include <freeradius-devel/util/debug.h>
40#include <freeradius-devel/util/inet.h>
41#include <freeradius-devel/util/misc.h>
42#include <freeradius-devel/util/perm.h>
43
45static char const parse_spaces[] = " ";
46
47#define PAIR_SPACE(_cs) ((_cs->depth + 1) * 2)
48#define SECTION_SPACE(_cs) (_cs->depth * 2)
49
50void cf_pair_debug_log(CONF_SECTION const *cs, CONF_PAIR *cp, conf_parser_t const *rule)
51{
52 char const *value;
53 char *tmp = NULL;
54 char const *quote = "";
55 bool secret = (rule && (rule->flags & CONF_FLAG_SECRET));
57
58 if (cp->printed) return;
59
60 /*
61 * tmpls are special, they just need to get printed as string
62 */
63 if (!rule || (rule->flags & CONF_FLAG_TMPL)) {
65 } else {
66 type = rule->type;
67 }
68
69 if (secret && (fr_debug_lvl < L_DBG_LVL_3)) {
70 cf_log_debug(cs, "%.*s%s = <<< secret >>>", PAIR_SPACE(cs), parse_spaces, cp->attr);
71 return;
72 }
73
74 /*
75 * Print the strings with the correct quotation character and escaping.
76 */
78 value = tmp = fr_asprint(NULL, cp->value, talloc_strlen(cp->value), fr_token_quote[cp->rhs_quote]);
79
80 } else {
81 value = cf_pair_value(cp);
82 }
83
85 switch (cf_pair_value_quote(cp)) {
86 default:
87 break;
88
90 quote = "\"";
91 break;
92
94 quote = "'";
95 break;
96
98 quote = "`";
99 break;
100
102 quote = "/";
103 break;
104 }
105 }
106
107 cf_log_debug(cs, "%.*s%s = %s%s%s", PAIR_SPACE(cs), parse_spaces, cp->attr, quote, value, quote);
108
109 talloc_free(tmp);
110
111 cp->printed = true;
112}
113
114/** Parses a #CONF_PAIR into a boxed value
115 *
116 * @copybrief cf_pair_value
117 * @see cf_pair_value
118 *
119 * @param[in] ctx to allocate any dynamic buffers in.
120 * @param[out] out Where to write the parsed value.
121 * @param[in] cp to parse.
122 * @param[in] rule to parse to. May contain flags.
123 * @return
124 * - 0 on success.
125 * - -1 on failure.
126 */
127int cf_pair_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, CONF_PAIR *cp, conf_parser_t const *rule)
128{
129 tmpl_t *vpt;
130 fr_slen_t slen;
131 size_t len = talloc_strlen(cp->value);
132 tmpl_rules_t rules = {
133 .cast = rule->type,
134 .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
135 };
136
137 /*
138 * The tmpl value parser reads the quotes around the value as
139 * the type hint. The parser reads a bare word as the type of
140 * the rule, and reads a quoted value as text. For an octets
141 * rule, 0xff is one byte and "0xff" is the four characters of
142 * the text.
143 *
144 * The value of a pair is never an expansion, so a '%' in the
145 * text is text. The value parser therefore replaces the full
146 * tokenizer here.
147 */
148 slen = tmpl_afrom_value_substr(cp, &vpt, &FR_SBUFF_IN(cp->value, len), cp->rhs_quote,
149 &rules, false, value_parse_rules_unquoted[cp->rhs_quote]);
150 if (slen < 0) {
152 cf_canonicalize_error(cp, slen, fr_strerror(), cp->value);
153 return -1;
154 }
155
156 if ((size_t)slen != len) {
157 fr_strerror_const("Unexpected text after value");
158 slen = -slen;
160 goto parse_error;
161 }
162
163 /*
164 * fr_value_box_memcpy_out() writes the field by the type of
165 * the box, so the box must be the type of the rule.
166 */
168
169 if (unlikely(fr_value_box_copy(ctx, out, tmpl_value(vpt)) < 0)) {
170 cf_log_perr(cp, "Failed copying the value of \"%s\"", cp->attr);
172 return -1;
173 }
175
176 /*
177 * Strings can be file paths...
178 */
179 if (fr_type_is_string(rule->type)) {
180 if (fr_rule_file_socket(rule)) {
181 /*
182 * Attempt to actually connect to the socket.
183 * There's no real standard behaviour across
184 * operating systems for this.
185 *
186 * This also implies fr_rule_file_exists.
187 */
188 if (fr_rule_file_readable(rule) || fr_rule_file_writable(rule)) {
190 cf_log_perr(cp, "File check failed");
191 return -1;
192 }
193 /*
194 * Otherwise just passively check if the socket
195 * exists.
196 */
197 } else if (fr_rule_file_exists(rule)) {
199 cf_log_perr(cp, "File check failed");
200 return -1;
201 }
202 /*
203 * ...and if there's no existence requirement
204 * just check that it's a unix socket.
205 */
206 } else {
208 default:
209 /* ok */
210 break;
211
213 cf_log_perr(cp, "File check failed");
214 return -1;
215 }
216 }
217 }
218 /*
219 * If there's out AND it's an input file, check
220 * that we can read it. This check allows errors
221 * to be caught as early as possible, during
222 * server startup.
223 */
224 else if (fr_rule_file_readable(rule) && (cf_file_check(cp, true) < 0)) {
225 error:
227 return -1;
228 }
229 else if (fr_rule_file_exists(rule) && (cf_file_check(cp, false) < 0)) goto error;
230 }
231
233
234 return 0;
235}
236
237/** Parses a #CONF_PAIR into a C data type
238 *
239 * @copybrief cf_pair_value
240 * @see cf_pair_value
241 *
242 * @param[in] ctx to allocate any dynamic buffers in.
243 * @param[out] out Where to write the parsed value.
244 * @param[in] base address of the structure out points into.
245 * May be NULL in the case of manual parsing.
246 * @param[in] ci to parse.
247 * @param[in] rule to parse to. May contain flags.
248 * @return
249 * - 0 on success.
250 * - -1 on failure.
251 */
252int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
253{
254 int ret = 0;
255 bool cant_be_empty, tmpl;
256
257 fr_slen_t slen;
258
259 CONF_PAIR *cp = cf_item_to_pair(ci);
260
261 cant_be_empty = fr_rule_not_empty(rule);
262 tmpl = fr_rule_is_tmpl(rule);
263
264 fr_assert(cp);
265 fr_assert(!fr_rule_is_attribute(rule) || tmpl); /* Attribute flag only valid for templates */
266
267 if (fr_rule_required(rule)) cant_be_empty = true; /* May want to review this in the future... */
268
269 /*
270 * Everything except templates must have a base type.
271 */
272 if (!rule->type && !tmpl) {
273 cf_log_err(cp, "Configuration pair \"%s\" must have a data type", cp->attr);
274 return -1;
275 }
276
277 /*
278 * Catch crazy errors.
279 */
280 if (!cp->value) {
281 cf_log_err(cp, "Configuration pair \"%s\" must have a value", cp->attr);
282 return -1;
283 }
284
285 /*
286 * Check for zero length strings
287 */
288 if ((cp->value[0] == '\0') && cant_be_empty) {
289 cf_log_err(cp, "Configuration pair \"%s\" must not be empty (zero length)", cp->attr);
290 if (!fr_rule_required(rule)) cf_log_err(cp, "Comment item to silence this message");
291 error:
292 ret = -1;
293 return ret;
294 }
295
296 if (tmpl) {
297 tmpl_t *vpt;
298 static tmpl_rules_t rules = {
299 .attr = {
300 .allow_unknown = true,
301 .allow_unresolved = true,
302 .allow_foreign = true,
303 },
304 .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
305 };
306 fr_sbuff_t sbuff = FR_SBUFF_IN(cp->value, strlen(cp->value));
307
309
310 /*
311 * Bare words are magical sometimes.
312 */
313 if (cp->rhs_quote == T_BARE_WORD) {
314 /*
315 * Attributes are parsed as attributes.
316 */
317 if (fr_rule_is_attribute(rule)) {
318 slen = tmpl_afrom_attr_substr(cp, NULL, &vpt, &sbuff, NULL, &rules);
319 if (slen < 0) goto tmpl_error;
320
321 fr_assert(vpt);
322
323 *(tmpl_t **)out = vpt;
324 goto finish;
325 }
326
327 /*
328 * @todo - otherwise bare words are NOT parsed as attributes, they're parsed as
329 * bare words, ala v3.
330 */
331
332 } else if (fr_rule_is_attribute(rule)) {
333 cf_log_err(cp, "Unexpected quoted string. An attribute name is required here.");
334 goto error;
335 }
336
337 slen = tmpl_afrom_substr(cp, &vpt, &sbuff, cp->rhs_quote,
339 &rules);
340 if (slen < 0) {
341 tmpl_error:
342 cf_canonicalize_error(cp, slen, fr_strerror(), cp->value);
343 goto error;
344 }
345 fr_assert(vpt);
346
347 /*
348 * The caller told us what data type was expected. If we do have data, then try to cast
349 * it to the requested type.
350 */
351 if ((rule->type != FR_TYPE_VOID) && tmpl_contains_data(vpt)) {
352 slen = 0; // for errors
353
355 tmpl_cast_set(vpt, rule->type);
356
357 if (tmpl_resolve(vpt, NULL) < 0) goto tmpl_error;
358
359 } else if (rule->type != tmpl_value_type(vpt)) {
361
362 if (tmpl_cast_in_place(vpt, rule->type, NULL) < 0) goto tmpl_error;
363 }
364 }
365
366 /*
367 * The code that reads the value never expands the tmpl, so
368 * only a fixed value can be used.
369 */
371 cf_log_err(cp, "Invalid value for \"%s\". The value must be fixed, as it is not expanded at runtime",
372 cp->attr);
373 goto error;
374 }
375
376 *(tmpl_t **)out = vpt;
377 goto finish;
378 }
379
380 /*
381 * Parse as a boxed value out of sheer laziness...
382 *
383 * Then we get all the internal types for free, and only need to add
384 * one set of printing and parsing functions for new types...
385 */
386 {
388
389 if (cf_pair_to_value_box(ctx, &vb, cf_item_to_pair(ci), rule) < 0) goto error;
390
391 if (fr_value_box_memcpy_out(out, &vb) < 0) {
392 cf_log_perr(cp, "Failed unboxing parsed configuration item value");
394 goto error;
395 }
396 }
397
398finish:
399
400 return ret;
401}
402
403/** Allocate a pair using the dflt value and quotation
404 *
405 * The pair created by this function should fed to #cf_pair_parse for parsing.
406 *
407 * @param[out] out Where to write the CONF_PAIR we created with the default value.
408 * @param[in] parent being populated.
409 * @param[in] cs to parent the CONF_PAIR from.
410 * @param[in] rule to use to create the default.
411 * @return
412 * - 0 on success.
413 * - -1 on failure.
414 */
415static int cf_pair_default(CONF_PAIR **out, void *parent, CONF_SECTION *cs, conf_parser_t const *rule)
416
417{
418 int lineno = 0;
419 char const *expanded;
420 CONF_PAIR *cp;
421 char buffer[8192];
422 fr_token_t dflt_quote = rule->quote;
423
424 fr_assert(rule->dflt || rule->dflt_func);
425
426 if (fr_rule_required(rule)) {
427 cf_log_err(cs, "Configuration pair \"%s\" must have a value", rule->name1);
428 return -1;
429 }
430
431 /*
432 * If no default quote was set, determine it from the type
433 */
434 if (dflt_quote == T_INVALID) {
435 if (fr_type_is_quoted(rule->type)) {
436 dflt_quote = T_DOUBLE_QUOTED_STRING;
437 } else {
438 dflt_quote = T_BARE_WORD;
439 }
440 }
441
442 /*
443 * Use the dynamic default function if set
444 */
445 if (rule->dflt_func) {
446 if (rule->dflt_func(out, parent, cs, dflt_quote, rule) < 0) {
447 cf_log_perr(cs, "Failed producing default for \"%s\"", rule->name1);
448 return -1;
449 }
450
451 return 0;
452 }
453
454 expanded = cf_expand_variables("<internal>", lineno, cs, buffer, sizeof(buffer), rule->dflt, -1, NULL,
455 (dflt_quote != T_BARE_WORD));
456 if (!expanded) {
457 cf_log_err(cs, "Failed expanding variable %s", rule->name1);
458 return -1;
459 }
460
461 cp = cf_pair_alloc(cs, rule->name1, expanded, T_OP_EQ, T_BARE_WORD, dflt_quote);
462 if (!cp) return -1;
463
464 /*
465 * Set the ret to indicate we used a default value
466 */
467 *out = cp;
468
469 return 1;
470}
471
472static int cf_pair_unescape(CONF_PAIR *cp, conf_parser_t const *rule)
473{
474 char const *p;
475 char *str, *unescaped, *q;
476
477 if (!cp->value) return 0;
478
479 if (cp->rhs_quote != T_DOUBLE_QUOTED_STRING) return 0;
480
481 if (!(rule->flags & CONF_FLAG_TMPL)) {
482 if (rule->type != FR_TYPE_STRING) return 0;
483 }
484
485 if (strchr(cp->value, '\\') == NULL) return 0;
486
487 str = talloc_strdup(cp, cp->value);
488 if (!str) return -1;
489
490 p = cp->value;
491 q = str;
492 while (*p) {
493 if (*p != '\\') {
494 *(q++) = *(p++);
495 continue;
496 }
497
498 p++;
499 if (*p == '\0') {
500 *q++ = '\\';
501 continue;
502 }
503 switch (*p) {
504 case 'r':
505 *q++ = '\r';
506 break;
507 case 'n':
508 *q++ = '\n';
509 break;
510 case 't':
511 *q++ = '\t';
512 break;
513
514 default:
515 if ((*p >= '0') && (*p <= '7')) {
516 unsigned long oct;
517 char *end;
518
519 oct = strtoul(p, &end, 8);
520 if (oct == ULONG_MAX) {
521 cf_log_err(cp, "Failed parsing octal string");
522 error:
523 talloc_free(str);
524 return -1;
525 }
526
527 if (!oct) {
528 cf_log_err(cp, "Cannot have embedded zeros in value at %s", p);
529 goto error;
530 }
531
532 if (oct > UINT8_MAX) {
533 cf_log_err(cp, "Invalid octal number in value at %s", p);
534 goto error;
535 }
536
537 *q++ = oct;
538 p = end;
539 continue;
540 } else {
541 *q++ = *p;
542 }
543 break;
544 }
545 p++;
546 }
547 *q = '\0';
548
549 unescaped = talloc_strdup(cp, str); /* no embedded NUL */
550 talloc_free(str);
551 if (!unescaped) return -1;
552
553 /*
554 * Replace the old value with the new one.
555 */
557 cp->value = unescaped;
558
559 return 0;
560}
561
562/** Parses a #CONF_PAIR into a C data type, with a default value.
563 *
564 * @param[in] ctx To allocate arrays and values in.
565 * @param[out] out Where to write the result.
566 * Must not be NULL unless rule->runc is provided.
567 * @param[in] base address of the structure out points into.
568 * May be NULL in the case of manual parsing.
569 * @param[in] cs to search for matching #CONF_PAIR in.
570 * @param[in] rule to parse #CONF_PAIR with.
571 * @return
572 * - 1 if default value was used, or if there was no CONF_PAIR or dflt.
573 * - 0 on success.
574 * - -1 on error.
575 * - -2 if deprecated.
576 */
577static int CC_HINT(nonnull(4,5)) cf_pair_parse_internal(TALLOC_CTX *ctx, void *out, void *base,
578 CONF_SECTION *cs, conf_parser_t const *rule)
579{
580 bool required, v3_deprecated, was_dflt = false;
581 size_t count = 0;
582 CONF_PAIR *cp = NULL, *dflt_cp = NULL;
583
584#ifndef NDEBUG
585 char const *dflt = rule->dflt;
586 fr_token_t dflt_quote = rule->quote;
587#endif
588 cf_parse_t func = rule->func ? rule->func : cf_pair_parse_value;
589
590 fr_assert(!fr_rule_is_tmpl(rule) || !dflt || (dflt_quote != T_INVALID)); /* We ALWAYS need a quoting type for templates */
591
592 /*
593 * Functions don't necessarily *need* to write
594 * anywhere, so their data pointer can be NULL.
595 */
596 if (!out) {
597 if (!rule->func) {
598 cf_log_err(cs, "Rule doesn't specify output destination");
599 return -1;
600 }
601 }
602
603 required = fr_rule_required(rule);
604 v3_deprecated = fr_rule_v3_deprecated(rule);
605
606 cp = cf_pair_find(cs, rule->name1);
607 if (cp && cp->item.parsed) {
608 return 0;
609 }
610 cp = NULL;
611
612 /*
613 * If the item is multi-valued we allocate an array
614 * to hold the multiple values.
615 */
616 if (fr_rule_multi(rule)) {
617 void **array;
618 size_t i = 0;
619
620 /*
621 * Easier than re-allocing
622 */
623 count = cf_pair_count(cs, rule->name1);
624
625 /*
626 * Multivalued, but there's no value, create a
627 * default pair.
628 */
629 if (!count) {
630 if (v3_deprecated) return 0;
631
632 if (!fr_rule_dflt(rule)) {
633 if (required) {
634 need_value:
635 cf_log_err(cs, "Configuration item \"%s\" must have a value", rule->name1);
636 return -1;
637 }
638 return 1;
639 }
640
641 if (cf_pair_default(&dflt_cp, base, cs, rule) < 0) return -1;
642 count = cf_pair_count(cs, rule->name1); /* Dynamic functions can add multiple defaults */
643 if (!count) {
644 if (fr_rule_not_empty(rule)) {
645 cf_log_err(cs, "Configuration item \"%s\" cannot be empty", rule->name1);
646 return -1;
647 }
648 return 0;
649 }
650 }
651
652 if (v3_deprecated) {
653 /*
654 * Emit the deprecated warning in the
655 * context of the first pair.
656 */
657 cp = cf_pair_find(cs, rule->name1);
658 fr_assert(cp);
659
660 v3_deprecated:
661 cf_log_err(cp, "Configuration pair \"%s\" is from v3, and cannot be used in v4", cp->attr);
662 return -2;
663 }
664
665 /*
666 * No output, so don't bother allocing the array
667 */
668 if (!out) {
669 array = NULL;
670
671 /*
672 * Tmpl is outside normal range
673 */
674 } else if (fr_rule_is_tmpl(rule)) {
675 MEM(array = (void **)talloc_zero_array(ctx, tmpl_t *, count));
676
677 /*
678 * Allocate an array of values.
679 *
680 * We don't NULL terminate. Consumer must use
681 * talloc_array_length().
682 */
683 } else {
684 array = fr_type_array_alloc(ctx, rule->type, count);
685 if (unlikely(array == NULL)) {
686 cf_log_perr(cp, "Failed allocating value array");
687 return -1;
688 }
689 }
690
691 while ((cp = cf_pair_find_next(cs, cp, rule->name1))) {
692 int ret;
693 void *entry;
694 TALLOC_CTX *value_ctx = array;
695
696 /*
697 * Figure out where to write the output
698 */
699 if (!array) {
700 entry = NULL;
701 } else if ((rule->type == FR_TYPE_VOID) || (rule->flags & CONF_FLAG_TMPL)) {
702 entry = &array[i++];
703 } else {
704 entry = ((uint8_t *) array) + (i++ * fr_value_box_field_sizes[rule->type]);
705 }
706
707 if (cf_pair_unescape(cp, rule) < 0) return -1;
708
709 /*
710 * Switch between custom parsing function
711 * and the standard value parsing function.
712 */
713 cf_pair_debug_log(cs, cp, rule);
714
715 if (cp->item.parsed) continue;
716 ret = func(value_ctx, entry, base, cf_pair_to_item(cp), rule);
717 if (ret < 0) {
718 talloc_free(array);
719 return -1;
720 }
721 cp->item.parsed = true;
722 }
723 if (array) *(void **)out = array;
724 /*
725 * Single valued config item gets written to
726 * the data pointer directly.
727 */
728 } else {
729 CONF_PAIR *next;
730 int ret;
731
732 cp = cf_pair_find(cs, rule->name1);
733 if (!cp) {
734 if (v3_deprecated) return 0;
735
736 if (!fr_rule_dflt(rule)) {
737 if (required) goto need_value;
738 return 1;
739 }
740
741 if (cf_pair_default(&dflt_cp, base, cs, rule) < 0) return -1;
742 cp = dflt_cp;
743 if (!cp) {
744 if (fr_rule_not_empty(rule)) {
745 cf_log_err(cs, "Configuration item \"%s\" cannot be empty", rule->name1);
746 return -1;
747 }
748
749 return 0;
750 }
751 was_dflt = true;
752 } else {
753 if (cf_pair_unescape(cp, rule) < 0) return -1;
754 }
755
756 next = cf_pair_find_next(cs, cp, rule->name1);
757 if (next) {
758 cf_log_err(cf_pair_to_item(next), "Invalid duplicate configuration item '%s'", rule->name1);
759 return -1;
760 }
761 if (v3_deprecated) goto v3_deprecated;
762
763 cf_pair_debug_log(cs, cp, rule);
764
765 if (cp->item.parsed) return 0;
766 ret = func(ctx, out, base, cf_pair_to_item(cp), rule);
767 if (ret < 0) return -1;
768 cp->item.parsed = true;
769 }
770
771 return was_dflt ? 1 : 0;
772}
773
774/** Parses a #CONF_PAIR into a C data type, with a default value.
775 *
776 * Takes fields from a #conf_parser_t struct and uses them to parse the string value
777 * of a #CONF_PAIR into a C data type matching the type argument.
778 *
779 * The format of the types are the same as #fr_value_box_t types.
780 *
781 * @note The dflt value will only be used if no matching #CONF_PAIR is found. Empty strings will not
782 * result in the dflt value being used.
783 *
784 * **fr_type_t to data type mappings**
785 * | fr_type_t | Data type | Dynamically allocated |
786 * | ----------------------- | ------------------ | ---------------------- |
787 * | FR_TYPE_BOOL | ``bool`` | No |
788 * | FR_TYPE_UINT32 | ``uint32_t`` | No |
789 * | FR_TYPE_UINT16 | ``uint16_t`` | No |
790 * | FR_TYPE_UINT64 | ``uint64_t`` | No |
791 * | FR_TYPE_INT32 | ``int32_t`` | No |
792 * | FR_TYPE_STRING | ``char const *`` | Yes |
793 * | FR_TYPE_IPV4_ADDR | ``fr_ipaddr_t`` | No |
794 * | FR_TYPE_IPV4_PREFIX | ``fr_ipaddr_t`` | No |
795 * | FR_TYPE_IPV6_ADDR | ``fr_ipaddr_t`` | No |
796 * | FR_TYPE_IPV6_PREFIX | ``fr_ipaddr_t`` | No |
797 * | FR_TYPE_COMBO_IP_ADDR | ``fr_ipaddr_t`` | No |
798 * | FR_TYPE_COMBO_IP_PREFIX | ``fr_ipaddr_t`` | No |
799 * | FR_TYPE_TIME_DELTA | ``fr_time_delta_t``| No |
800 *
801 * @param[in] ctx To allocate arrays and values in.
802 * @param[in] cs to search for matching #CONF_PAIR in.
803 * @param[in] name of #CONF_PAIR to search for.
804 * @param[in] type Data type to parse #CONF_PAIR value as.
805 * Should be one of the following ``data`` types,
806 * and one or more of the following ``flag`` types or'd together:
807
808 * - ``data`` #FR_TYPE_BOOL - @copybrief FR_TYPE_BOOL
809 * - ``data`` #FR_TYPE_UINT32 - @copybrief FR_TYPE_UINT32
810 * - ``data`` #FR_TYPE_UINT16 - @copybrief FR_TYPE_UINT16
811 * - ``data`` #FR_TYPE_UINT64 - @copybrief FR_TYPE_UINT64
812 * - ``data`` #FR_TYPE_INT32 - @copybrief FR_TYPE_INT32
813 * - ``data`` #FR_TYPE_STRING - @copybrief FR_TYPE_STRING
814 * - ``data`` #FR_TYPE_IPV4_ADDR - @copybrief FR_TYPE_IPV4_ADDR (IPv4 address with prefix 32).
815 * - ``data`` #FR_TYPE_IPV4_PREFIX - @copybrief FR_TYPE_IPV4_PREFIX (IPv4 address with variable prefix).
816 * - ``data`` #FR_TYPE_IPV6_ADDR - @copybrief FR_TYPE_IPV6_ADDR (IPv6 address with prefix 128).
817 * - ``data`` #FR_TYPE_IPV6_PREFIX - @copybrief FR_TYPE_IPV6_PREFIX (IPv6 address with variable prefix).
818 * - ``data`` #FR_TYPE_COMBO_IP_ADDR - @copybrief FR_TYPE_COMBO_IP_ADDR (IPv4/IPv6 address with
819 * prefix 32/128).
820 * - ``data`` #FR_TYPE_COMBO_IP_PREFIX - @copybrief FR_TYPE_COMBO_IP_PREFIX (IPv4/IPv6 address with
821 * variable prefix).
822 * - ``data`` #FR_TYPE_TIME_DELTA - @copybrief FR_TYPE_TIME_DELTA
823 * - ``flag`` #CONF_FLAG_TMPL - @copybrief CONF_FLAG_TMPL
824 * Feeds the value into #tmpl_afrom_substr. Value can be
825 * obtained when processing requests, with #tmpl_expand or #tmpl_aexpand.
826 * - ``flag`` #CONF_FLAG_V3_DEPRECATED - @copybrief CONF_FLAG_V3_DEPRECATED
827 * - ``flag`` #CONF_FLAG_REQUIRED - @copybrief CONF_FLAG_REQUIRED
828 * - ``flag`` #CONF_FLAG_ATTRIBUTE - @copybrief CONF_FLAG_ATTRIBUTE
829 * - ``flag`` #CONF_FLAG_SECRET - @copybrief CONF_FLAG_SECRET
830 * - ``flag`` #CONF_FLAG_FILE_READABLE - @copybrief CONF_FLAG_FILE_READABLE
831 * - ``flag`` #CONF_FLAG_FILE_WRITABLE - @copybrief CONF_FLAG_FILE_WRITABLE
832 * - ``flag`` #CONF_FLAG_NOT_EMPTY - @copybrief CONF_FLAG_NOT_EMPTY
833 * - ``flag`` #CONF_FLAG_MULTI - @copybrief CONF_FLAG_MULTI
834 * - ``flag`` #CONF_FLAG_IS_SET - @copybrief CONF_FLAG_IS_SET
835 * @param[out] data Pointer to a global variable, or pointer to a field in the struct being populated with values.
836 * @param[in] dflt value to use, if no #CONF_PAIR is found.
837 * @param[in] dflt_quote around the dflt value.
838 * @return
839 * - 1 if default value was used, or if there was no CONF_PAIR or dflt.
840 * - 0 on success.
841 * - -1 on error.
842 * - -2 if deprecated.
843 */
844int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs, char const *name,
845 unsigned int type, void *data, char const *dflt, fr_token_t dflt_quote)
846{
847 conf_parser_t rule = {
848 .name1 = name,
849 .type = type,
850 .dflt = dflt,
851 .quote = dflt_quote
852 };
853
854 return cf_pair_parse_internal(ctx, data, NULL, cs, &rule);
855}
856
857/** Find where a rule records whether the rule's config item was present
858 *
859 * @param base Struct the rule writes into, or NULL if the rule only
860 * writes through the rule's own pointers.
861 * @param rule Rule whose flags include #CONF_FLAG_IS_SET.
862 * @return
863 * - The bool that records whether the item was present.
864 * - NULL if the rule has no bool to record the presence in.
865 */
866static inline CC_HINT(always_inline) bool *cf_rule_is_set_ptr(void *base, conf_parser_t const *rule)
867{
868 if (rule->data) {
869 return rule->is_set_ptr;
870 }
871
872 if (base) {
873 return (bool *)(((uint8_t *)base) + rule->is_set_offset);
874 }
875
876 return NULL;
877}
878
879/** Pre-allocate a config section structure to allow defaults to be set
880 *
881 * @param cs The parent subsection.
882 * @param base pointer or variable.
883 * @param rule that may have defaults in this config section.
884 * @return
885 * - 0 on success.
886 * - -1 on failure.
887 */
888static int cf_section_parse_init(CONF_SECTION *cs, void *base, conf_parser_t const *rule)
889{
890 CONF_PAIR *cp;
891
892 /*
893 * This rule refers to a named subsection
894 */
895 if ((rule->flags & CONF_FLAG_SUBSECTION)) {
896 char const *name2 = NULL;
897 CONF_SECTION *subcs;
898
899 /*
900 * Optional MUST be listed before required ones
901 */
902 if ((rule->flags & CONF_FLAG_OPTIONAL) != 0) {
903 return 0;
904 }
905
906 subcs = cf_section_find(cs, rule->name1, rule->name2);
907
908 /*
909 * Set the is_set field for the subsection.
910 */
911 if (rule->flags & CONF_FLAG_IS_SET) {
912 bool *is_set;
913
914 is_set = cf_rule_is_set_ptr(base, rule);
915 if (is_set) *is_set = (subcs != NULL);
916 }
917
918 /*
919 * It exists, we don't have to do anything else.
920 */
921 if (subcs) return 0;
922
923 /*
924 * If there is no subsection, either complain,
925 * allow it, or create it with default values.
926 */
927 if (rule->flags & CONF_FLAG_REQUIRED) {
928 cf_log_err(cs, "Missing %s {} subsection", rule->name1);
929 return -1;
930 }
931
932 /*
933 * It's OK for this to be missing. Don't
934 * initialize it.
935 */
936 if ((rule->flags & CONF_FLAG_OK_MISSING) != 0) return 0;
937
938 /*
939 * If there's no subsection in the
940 * config, BUT the conf_parser_t wants one,
941 * then create an empty one. This is so
942 * that we can track the strings,
943 * etc. allocated in the subsection.
944 */
945 if (DEBUG_ENABLED4) cf_log_debug(cs, "Allocating fake section \"%s\"", rule->name1);
946
947 /*
948 * If name1 is CF_IDENT_ANY, then don't
949 * alloc the section as we have no idea
950 * what it should be called.
951 */
952 if (rule->name1 == CF_IDENT_ANY) return 0;
953
954 /*
955 * Don't specify name2 if it's CF_IDENT_ANY
956 */
957 if (rule->name2 != CF_IDENT_ANY) name2 = rule->name2;
958 subcs = cf_section_alloc(cs, cs, rule->name1, name2);
959 if (!subcs) return -1;
960
961 return 0;
962 }
963
964 /*
965 * This rule refers to another conf_parse_t which is included in-line in
966 * this section.
967 */
968 if ((rule->flags & CONF_FLAG_REF) != 0) {
969 conf_parser_t const *rule_p;
970 uint8_t *sub_base = base;
971
972 fr_assert(rule->subcs != NULL);
973
974 sub_base += rule->offset;
975
976 for (rule_p = rule->subcs; rule_p->name1; rule_p++) {
977 int ret = cf_section_parse_init(cs, sub_base, rule_p);
978 if (ret < 0) return ret;
979 }
980 return 0;
981 }
982
983 /*
984 * Don't re-initialize data which was already parsed.
985 */
986 cp = cf_pair_find(cs, rule->name1);
987 if (cp && cp->item.parsed) return 0;
988
989 if ((rule->type != FR_TYPE_STRING) &&
990 (!(rule->flags & CONF_FLAG_FILE_READABLE)) &&
991 (!(rule->flags & CONF_FLAG_FILE_WRITABLE))) {
992 return 0;
993 }
994
995 /*
996 * CONF_FLAG_NO_OUTPUT means the rule has no framework-managed
997 * output slot - nothing to NULL-init.
998 */
999 if (rule->flags & CONF_FLAG_NO_OUTPUT) return 0;
1000
1001 if (rule->data) {
1002 *(char **) rule->data = NULL;
1003 } else if (base) {
1004 *(char **) (((char *)base) + rule->offset) = NULL;
1005 } else {
1006 return 0;
1007 }
1008
1009 return 0;
1010}
1011
1013{
1014 cf_item_foreach(&cs->item, ci) {
1015 /*
1016 * Don't recurse on sections. We can only safely
1017 * check conf pairs at the same level as the
1018 * section that was just parsed.
1019 */
1020 if (ci->type == CONF_ITEM_SECTION) continue;
1021 if (ci->type == CONF_ITEM_PAIR) {
1022 CONF_PAIR *cp;
1023
1024 cp = cf_item_to_pair(ci);
1025 if (cp->item.parsed || cp->item.referenced || (ci->lineno < 0)) continue;
1026
1027 WARN("%s[%d]: The item '%s' is defined, but is unused by the configuration",
1028 ci->filename, ci->lineno,
1029 cp->attr);
1030 }
1031
1032 /*
1033 * Skip everything else.
1034 */
1035 }
1036}
1037
1038/** Parse a subsection
1039 *
1040 * @note Turns out using nested structures (instead of pointers) for subsections, was actually
1041 * a pretty bad design decision, and will need to be fixed at some future point.
1042 * For now we have a horrible hack where only multi-subsections get an array of structures
1043 * of the appropriate size.
1044 *
1045 * @param[in] ctx to allocate any additional structures under.
1046 * @param[out] out pointer to a struct/pointer to fill with data.
1047 * @param[in] base address of the structure out points into.
1048 * May be NULL in the case of manual parsing.
1049 * @param[in] cs to parse.
1050 * @param[in] rule to parse the subcs with.
1051 * @return
1052 * - 0 on success.
1053 * - -1 on general error.
1054 * - -2 if a deprecated #CONF_ITEM was found.
1055 */
1056static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, void *base, CONF_SECTION *cs, conf_parser_t const *rule)
1057{
1058 CONF_SECTION *subcs = NULL;
1059 int count = 0, i = 0, ret;
1060
1061 size_t subcs_size = rule->subcs_size;
1062 conf_parser_t const *rules = rule->subcs;
1063
1064 /*
1065 * CF_IDENT_ANY section rules act as a catch-all: skip any
1066 * subsection that's already been claimed and marked parsed
1067 * by an earlier specific rule, so the wildcard only handles
1068 * the leftovers. CONF_FLAG_ALWAYS_PARSE overrides this and
1069 * makes the rule observe every matching subsection.
1070 */
1071 bool const skip_parsed = (rule->name1 == CF_IDENT_ANY) &&
1072 !(rule->flags & CONF_FLAG_ALWAYS_PARSE);
1073
1074 bool const no_output = (rule->flags & CONF_FLAG_NO_OUTPUT);
1075
1076 uint8_t **array = NULL;
1077
1079
1080 if (skip_parsed) {
1081 while ((subcs = cf_section_find_next(cs, subcs, rule->name1, rule->name2))) {
1082 if (!cf_item_is_parsed(cf_section_to_item(subcs))) break;
1083 }
1084 } else {
1085 subcs = cf_section_find(cs, rule->name1, rule->name2);
1086 }
1087 if (!subcs) return 0;
1088
1089 /*
1090 * Handle the single subsection case (which is simple)
1091 */
1092 if (!(rule->flags & CONF_FLAG_MULTI)) {
1093 uint8_t *buff = NULL;
1094
1095 if (DEBUG_ENABLED4) cf_log_debug(cs, "Evaluating rules for %s section. Output %p",
1096 cf_section_name1(subcs), out);
1097
1098 /*
1099 * Add any rules, so the func can just call cf_section_parse
1100 * if it wants to continue after doing its stuff.
1101 */
1102 if (cf_section_rules_push(subcs, rules) < 0) return -1;
1103 if (rule->func) return rule->func(ctx, out, base, cf_section_to_item(subcs), rule);
1104
1105 /*
1106 * FIXME: We shouldn't allow nested structures like this.
1107 * Each subsection struct should be allocated separately so
1108 * we have a clean talloc hierarchy.
1109 */
1110 if (!subcs_size) return cf_section_parse(ctx, out, subcs);
1111
1112 if (out && !no_output) {
1113 MEM(buff = talloc_zero_array(ctx, uint8_t, subcs_size));
1114 if (rule->subcs_type) talloc_set_name_const(buff, rule->subcs_type);
1115 }
1116
1117 ret = cf_section_parse(buff, buff, subcs);
1118 if (ret < 0) {
1120 return ret;
1121 }
1122
1123 if (out && !no_output) *((uint8_t **)out) = buff;
1124
1125 return 0;
1126 }
1127
1128 fr_assert(subcs_size);
1129
1130 /*
1131 * Handle the multi subsection case (which is harder)
1132 */
1133 subcs = NULL;
1134 while ((subcs = cf_section_find_next(cs, subcs, rule->name1, rule->name2))) {
1135 if (skip_parsed && cf_item_is_parsed(cf_section_to_item(subcs))) continue;
1136 count++;
1137 }
1138
1139 /*
1140 * Allocate an array to hold the subsections
1141 */
1142 if (out && !no_output) {
1143 MEM(array = talloc_zero_array(ctx, uint8_t *, count));
1144 if (rule->subcs_type) talloc_set_name(array, "%s *", rule->subcs_type);
1145 }
1146 /*
1147 * Start parsing...
1148 *
1149 * Note, we allocate each subsection structure individually
1150 * so that they can be used as talloc contexts and we can
1151 * keep the talloc hierarchy clean.
1152 */
1153 subcs = NULL;
1154 while ((subcs = cf_section_find_next(cs, subcs, rule->name1, rule->name2))) {
1155 uint8_t *buff = NULL;
1156
1157 if (skip_parsed && cf_item_is_parsed(cf_section_to_item(subcs))) continue;
1158
1159 if (DEBUG_ENABLED4) cf_log_debug(cs, "Evaluating rules for %s[%i] section. Output %p",
1160 cf_section_name1(subcs),
1161 i, out);
1162
1163 if (array) {
1164 MEM(buff = talloc_zero_array(array, uint8_t, subcs_size));
1165 if (rule->subcs_type) talloc_set_name_const(buff, rule->subcs_type);
1166 array[i++] = buff;
1167 }
1168
1169 /*
1170 * Add any rules, so the func can just call cf_section_parse
1171 * if it wants to continue after doing its stuff.
1172 */
1173 if (cf_section_rules_push(subcs, rules) < 0) {
1174 talloc_free(array);
1175 return -1;
1176 }
1177 if (rule->func) {
1178 ret = rule->func(ctx, buff, base, cf_section_to_item(subcs), rule);
1179 if (ret < 0) {
1180 talloc_free(array);
1181 return ret;
1182 }
1183 continue;
1184 }
1185
1186 ret = cf_section_parse(buff, buff, subcs);
1187 if (ret < 0) {
1188 talloc_free(array);
1189 return ret;
1190 }
1191 }
1192
1193 if (out && !no_output) *((uint8_t ***)out) = array;
1194
1195 return 0;
1196}
1197
1198static int cf_section_parse_rule(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, conf_parser_t const *rule)
1199{
1200 int ret;
1201 bool *is_set = NULL;
1202 void *data = NULL;
1203
1204 /*
1205 * Ignore ON_READ parse rules if there's no subsequent
1206 * parse functions.
1207 */
1208 if (!rule->func && rule->on_read) return 0;
1209
1210 /*
1211 * Pre-allocate the config structure to hold default values
1212 */
1213 if (cf_section_parse_init(cs, base, rule) < 0) return -1;
1214
1215 if (rule->data) {
1216 data = rule->data; /* prefer this. */
1217 } else if (base &&
1218 (!(rule->flags & CONF_FLAG_NO_OUTPUT) || (rule->flags & CONF_FLAG_SUBSECTION))) {
1219 /*
1220 * CONF_FLAG_NO_OUTPUT on a pair rule means leave
1221 * data NULL so the framework won't write through
1222 * base+offset. For subsections it only suppresses
1223 * the end-of-MULTI array write (handled inside
1224 * cf_subsection_parse) - we still need to pass
1225 * `base` through so nested rules can address into it.
1226 */
1227 data = ((uint8_t *)base) + rule->offset;
1228 }
1229
1230 /*
1231 * Handle subsections specially
1232 */
1233 if (rule->flags & CONF_FLAG_SUBSECTION) {
1234 return cf_subsection_parse(ctx, data, base, cs, rule);
1235 }
1236
1237 /*
1238 * A pair rule with name1 == CF_IDENT_ANY is a catch-all:
1239 * feed every still-unparsed CONF_PAIR in this section to the
1240 * rule's parser func. Order matters - specific rules before
1241 * this entry have already claimed (and marked parsed) their
1242 * pairs, so the catch-all only sees the leftovers, unless
1243 * CONF_FLAG_ALWAYS_PARSE is set (in which case it sees every
1244 * pair regardless).
1245 *
1246 * The rule must provide a func; there's no sensible default
1247 * output offset when the pair's name varies. The func
1248 * receives one CONF_PAIR at a time via ci and can read the
1249 * name via cf_pair_attr().
1250 */
1251 if (!(rule->flags & CONF_FLAG_REF) && rule->name1 == CF_IDENT_ANY) {
1252 bool const always_parse = (rule->flags & CONF_FLAG_ALWAYS_PARSE);
1253 CONF_PAIR *cp = NULL;
1254
1255 if (!rule->func) {
1256 cf_log_err(cs, "CF_IDENT_ANY pair rule must provide a parse function");
1257 return -1;
1258 }
1259
1260 while ((cp = cf_pair_find_next(cs, cp, NULL))) {
1261 if (!always_parse && cf_item_is_parsed(cf_pair_to_item(cp))) continue;
1262
1263 if (rule->func(ctx, data, base, cf_pair_to_item(cp), rule) < 0) return -1;
1265 }
1266 return 0;
1267 }
1268
1269 /*
1270 * Ignore this rule if it's a reference, as the
1271 * rules it points to have been pushed by the
1272 * above function.
1273 */
1274 if ((rule->flags & CONF_FLAG_REF) != 0) {
1275 conf_parser_t const *rule_p;
1276 uint8_t *sub_base = base;
1277
1278 fr_assert(rule->subcs != NULL);
1279
1280 sub_base += rule->offset;
1281
1282 for (rule_p = rule->subcs; rule_p->name1; rule_p++) {
1283 if (fr_rule_v3_deprecated(rule_p)) continue; /* Skip v3 deprecated */
1284
1285 ret = cf_section_parse_rule(ctx, sub_base, cs, rule_p);
1286 if (ret < 0) return ret;
1287 }
1288
1289 /*
1290 * Ensure we have a proper terminator, type so we catch
1291 * missing terminators reliably
1292 */
1293 fr_cond_assert(rule_p->type == conf_term.type);
1294
1295 return 0;
1296 }
1297
1298 /*
1299 * Else it's a CONF_PAIR
1300 */
1301
1302 /*
1303 * Pair either needs an output destination or
1304 * there needs to be a function associated with
1305 * it.
1306 */
1307 if (!data && !rule->func) {
1308 cf_log_err(cs, "Rule doesn't specify output destination");
1309 return -1;
1310 }
1311
1312 /*
1313 * Get pointer to where we need to write out
1314 * whether the pointer was set.
1315 */
1316 if (rule->flags & CONF_FLAG_IS_SET) {
1317 is_set = cf_rule_is_set_ptr(base, rule);
1318 }
1319
1320 /*
1321 * Parse the pair we found, or a default value.
1322 */
1323 ret = cf_pair_parse_internal(ctx, data, base, cs, rule);
1324 switch (ret) {
1325 case 1: /* Used default (or not present) */
1326 if (is_set) *is_set = false;
1327 ret = 0;
1328 break;
1329
1330 case 0: /* OK */
1331 if (is_set) *is_set = true;
1332 break;
1333
1334 case -1: /* Parse error */
1335 break;
1336
1337 case -2: /* Deprecated CONF ITEM */
1338 if (((rule + 1)->offset && ((rule + 1)->offset == rule->offset)) ||
1339 ((rule + 1)->data && ((rule + 1)->data == rule->data))) {
1340 cf_log_err(cs, "Replace \"%s\" with \"%s\"", rule->name1,
1341 (rule + 1)->name1);
1342 }
1343 break;
1344 }
1345
1346 return ret;
1347}
1348
1349/** Parse a configuration section into user-supplied variables
1350 *
1351 * @param[in] ctx to allocate any strings, or additional structures in.
1352 * Usually the same as base, unless base is a nested struct.
1353 * @param[out] base pointer to a struct to fill with data.
1354 * @param[in] cs to parse.
1355 * @return
1356 * - 0 on success.
1357 * - -1 on general error.
1358 * - -2 if a deprecated #CONF_ITEM was found.
1359 */
1360int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
1361{
1362 CONF_DATA const *rule_cd = NULL;
1363
1364 if (!cs->name2) {
1365 cf_log_debug(cs, "%.*s%s {", SECTION_SPACE(cs), parse_spaces, cs->name1);
1366 } else {
1367 cf_log_debug(cs, "%.*s%s %s {", SECTION_SPACE(cs), parse_spaces, cs->name1, cs->name2);
1368 }
1369
1370 /*
1371 * Loop over all the child rules of the section
1372 */
1373 while ((rule_cd = cf_data_find_next(cs, rule_cd, conf_parser_t, CF_IDENT_ANY))) {
1374 int ret;
1375 conf_parser_t *rule;
1376
1377 rule = cf_data_value(rule_cd);
1378
1379 ret = cf_section_parse_rule(ctx, base, cs, rule);
1380 if (ret < 0) return ret;
1381 }
1382
1383 cs->base = base;
1384
1385 /*
1386 * Warn about items in the configuration which weren't
1387 * checked during parsing.
1388 */
1390
1391 cf_log_debug(cs, "%.*s}", SECTION_SPACE(cs), parse_spaces);
1392
1394 return 0;
1395}
1396
1397/*
1398 * Pass2 fixups on tmpl_t
1399 *
1400 * We don't have (or need yet) cf_pair_parse_pass2(), so we just
1401 * do it for tmpls.
1402 */
1404 bool attribute, fr_dict_t const *dict_def)
1405{
1406 tmpl_t *vpt = *out;
1407
1408 fr_assert(vpt); /* We need something to resolve */
1409
1410 if (tmpl_resolve(vpt, &(tmpl_res_rules_t){ .dict_def = dict_def, .force_dict_def = (dict_def != NULL)}) < 0) {
1411 cf_log_perr(cp, "Failed processing configuration item '%s'", cp->attr);
1412 return -1;
1413 }
1414
1415 if (attribute) {
1416 if (!tmpl_is_attr(vpt)) {
1417 cf_log_err(cp, "Expected attr got %s",
1418 tmpl_type_to_str(vpt->type));
1419 return -1;
1420 }
1421 }
1422
1423 switch (vpt->type) {
1424 /*
1425 * All attributes should have been defined by this point.
1426 */
1428 cf_log_err(cp, "Unknown attribute '%s'", tmpl_attr_tail_unresolved(vpt));
1429 return -1;
1430
1432 /*
1433 * Try to realize the underlying type, if at all possible.
1434 */
1435 if (!attribute && type && (tmpl_cast_in_place(vpt, type, NULL) < 0)) {
1436 cf_log_perr(cp, "Failed processing configuration item '%s'", cp->attr);
1437 return -1;
1438 }
1439 break;
1440
1441 case TMPL_TYPE_ATTR:
1442 case TMPL_TYPE_DATA:
1443 case TMPL_TYPE_EXEC:
1445 case TMPL_TYPE_XLAT:
1447 break;
1448
1450 case TMPL_TYPE_REGEX:
1454 case TMPL_TYPE_MAX:
1455 fr_assert(0);
1456 /* Don't add default */
1457 }
1458
1459 return 0;
1460}
1461
1462/** Fixup xlat expansions and attributes
1463 *
1464 * @param[out] base start of structure to write #tmpl_t s to.
1465 * @param[in] cs CONF_SECTION to fixup.
1466 * @return
1467 * - 0 on success.
1468 * - -1 on failure (parse errors etc...).
1469 */
1471{
1472 CONF_DATA const *rule_cd = NULL;
1473
1474 while ((rule_cd = cf_data_find_next(cs, rule_cd, conf_parser_t, CF_IDENT_ANY))) {
1475 bool attribute, multi, is_tmpl, is_xlat;
1476 CONF_PAIR *cp;
1477 conf_parser_t *rule = cf_data_value(rule_cd);
1478 void *data;
1479 fr_type_t type = rule->type;
1480 conf_parser_flags_t flags = rule->flags;
1481 fr_dict_t const *dict = NULL;
1482
1483 is_tmpl = (flags & CONF_FLAG_TMPL);
1484 is_xlat = (flags & CONF_FLAG_XLAT);
1485 attribute = (flags & CONF_FLAG_ATTRIBUTE);
1486 multi = (flags & CONF_FLAG_MULTI);
1487
1488 /*
1489 * It's a section, recurse!
1490 */
1491 if (flags & CONF_FLAG_SUBSECTION) {
1492 uint8_t *subcs_base;
1493 CONF_SECTION *subcs = cf_section_find(cs, rule->name1, rule->name2);
1494
1495 /*
1496 * Select base by whether this is a nested struct,
1497 * an array of pointers to structs, or a pointer to
1498 * one struct.
1499 */
1500 if (!base || (flags & CONF_FLAG_NO_OUTPUT)) {
1501 subcs_base = NULL;
1502 } else if (multi) {
1503 size_t j, len;
1504 uint8_t **array;
1505
1506 array = *(uint8_t ***)(((uint8_t *)base) + rule->offset);
1507 len = talloc_array_length(array);
1508
1509 for (j = 0; j < len; j++) if (cf_section_parse_pass2(array[j], subcs) < 0) return -1;
1510 continue;
1511 } else if (rule->subcs_size) {
1512 subcs_base = *(uint8_t **)(((uint8_t *)base) + rule->offset);
1513 if (!subcs_base) continue; /* The subsection was absent, or a rule func stored nothing */
1514 } else {
1515 subcs_base = (uint8_t *)base + rule->offset;
1516 }
1517
1518 if (cf_section_parse_pass2(subcs_base, subcs) < 0) return -1;
1519
1520 continue;
1521 }
1522
1523 /*
1524 * Find the CONF_PAIR, may still not exist if there was
1525 * no default set for the conf_parser_t.
1526 */
1527 cp = cf_pair_find(cs, rule->name1);
1528 if (!cp) continue;
1529
1530 /*
1531 * Figure out which data we need to fix.
1532 */
1533 data = rule->data; /* prefer this. */
1534 if (!data && base && !(rule->flags & CONF_FLAG_NO_OUTPUT)) data = ((char *)base) + rule->offset;
1535 if (!data) continue;
1536
1537 /*
1538 * Non-xlat expansions shouldn't have xlat!
1539 *
1540 * Except other libraries like libkafka may be the ones
1541 * doing the actual expansion, so we don't _know_
1542 * if the xlatlike value is destined for use in FreeRADIUS
1543 * or not, so we can't definitely determine if this is an
1544 * error.
1545 *
1546 * Code left in place to warn other people off re-adding
1547 * this check in future.
1548 */
1549#if 0
1550 if (!is_xlat && !is_tmpl) {
1551 /*
1552 * Ignore %{... in shared secrets.
1553 * They're never dynamically expanded.
1554 */
1555 if ((rule->flags & CONF_FLAG_SECRET) != 0) continue;
1556
1557 if (strstr(cp->value, "%{") != NULL) {
1558 cf_log_err(cp, "Found dynamic expansion in string which "
1559 "will not be dynamically expanded");
1560 return -1;
1561 }
1562 continue;
1563 }
1564#endif
1565
1566 /*
1567 * Search for dictionary data somewhere in the virtual
1568 * server.
1569 */
1571
1572 /*
1573 * Parse (and throw away) the xlat string (for validation).
1574 *
1575 * FIXME: All of these should be converted from CONF_FLAG_XLAT
1576 * to CONF_FLAG_TMPL.
1577 */
1578 if (is_xlat) {
1579 fr_slen_t slen;
1580 xlat_exp_head_t *xlat;
1581
1582 redo:
1583 xlat = NULL;
1584
1585 /*
1586 * xlat expansions should be parseable.
1587 */
1588 slen = xlat_tokenize(cs, &xlat,
1589 &FR_SBUFF_IN(cp->value, talloc_strlen(cp->value)), NULL,
1590 &(tmpl_rules_t) {
1591 .attr = {
1592 .dict_def = dict,
1593 .list_def = request_attr_request,
1594 .allow_unknown = false,
1595 .allow_unresolved = false,
1596 .allow_foreign = (dict == NULL)
1597 },
1598 });
1599 if (slen < 0) {
1600 char *spaces, *text;
1601
1602 fr_canonicalize_error(cs, &spaces, &text, slen, cp->value);
1603
1604 cf_log_err(cp, "Failed parsing expansion string:");
1605 cf_log_err(cp, "%s", text);
1606 cf_log_perr(cp, "%s^", spaces);
1607
1609 talloc_free(text);
1610 talloc_free(xlat);
1611 return -1;
1612 }
1613
1614 talloc_free(xlat);
1615
1616 /*
1617 * If the "multi" flag is set, check all of them.
1618 */
1619 if (multi) {
1620 cp = cf_pair_find_next(cs, cp, cp->attr);
1621 if (cp) goto redo;
1622 }
1623 continue;
1624
1625 /*
1626 * Parse the pair into a template
1627 */
1628 } else if (is_tmpl && !multi) {
1629 if (cf_parse_tmpl_pass2(cs, (tmpl_t **)data, cp, type, attribute, dict) < 0) {
1630 return -1;
1631 }
1632
1633 } else if (is_tmpl) {
1634 size_t i;
1635 char const *name = cp->attr;
1636 tmpl_t **array = *(tmpl_t ***) data;
1637
1638 for (i = 0; i < talloc_array_length(array); i++, cp = cf_pair_find_next(cs, cp, name)) {
1639 if (!cp) break;
1640
1641 if (cf_parse_tmpl_pass2(cs, &array[i], cp, type, attribute, dict) < 0) {
1642 return -1;
1643 }
1644 }
1645 }
1646 }
1647
1648 return 0;
1649}
1650
1651
1652/** Add a single rule to a #CONF_SECTION
1653 *
1654 * @param[in] cs to add rules to.
1655 * @param[in] rule to add.
1656 * @param[in] filename where the rule was pushed.
1657 * @param[in] lineno where the rule was pushed.
1658 * @return
1659 * - 0 on success.
1660 * - -1 if the rules added conflict.
1661 */
1662int _cf_section_rule_push(CONF_SECTION *cs, conf_parser_t const *rule, char const *filename, int lineno)
1663{
1664 char const *name1, *name2;
1665 CONF_DATA const *cd;
1666
1667 if (!cs || !rule) return 0;
1668
1669 name1 = rule->name1 == CF_IDENT_ANY ? "__any__" : rule->name1;
1670 name2 = rule->name2 == CF_IDENT_ANY ? "__any__" : rule->name2;
1671
1672 cd = cf_data_find(CF_TO_ITEM(cs), conf_parser_t, name1);
1673 if (cd && cd->data == rule) return 0;
1674
1675 if (DEBUG_ENABLED4) {
1676 cf_log_debug(cs, "Pushed parse rule to %s section: %s %s",
1677 cf_section_name1(cs),
1678 name1, rule->flags & CONF_FLAG_SUBSECTION ? "{}": "");
1679 }
1680
1681 /*
1682 * Qualifying with name prevents duplicate rules being added
1683 *
1684 * Fixme maybe?.. Can't have a section and pair with the same name.
1685 */
1686 if (!_cf_data_add_static(CF_TO_ITEM(cs), rule, "conf_parser_t", name1, filename, lineno)) {
1687 conf_parser_t *old;
1688
1689 cd = cf_data_find(CF_TO_ITEM(cs), conf_parser_t, name1);
1690 old = cf_data_value(cd);
1691 fr_assert(old != NULL);
1692
1693 /*
1694 * Shut up about duplicates.
1695 */
1696 if (memcmp(rule, old, sizeof(*rule)) == 0) {
1697 return 0;
1698 }
1699
1700 /*
1701 * Remove any ON_READ callbacks, and add the new
1702 * rule in its place.
1703 */
1704 if (old->on_read) {
1705 CONF_DATA *cd1;
1706
1707 /*
1708 * Over-write the rule in place.
1709 *
1710 * We'd like to call cf_item_remove(), but
1711 * that apparently doesn't work for
1712 * CONF_DATA. We don't need to
1713 * free/alloc one, so re-using this is
1714 * fine.
1715 */
1716 memcpy(&cd1, &cd, sizeof(cd1));
1717 cd1->data = rule;
1718 cd1->item.filename = filename;
1719 cd1->item.lineno = lineno;
1720 return 0;
1721 }
1722
1723 /*
1724 * If we have a duplicate sub-section, just
1725 * recurse and add the new sub-rules to the
1726 * existing sub-section.
1727 */
1728 if (rule->flags & CONF_FLAG_SUBSECTION) {
1729 CONF_SECTION *subcs;
1730
1731 subcs = cf_section_find(cs, name1, name2);
1732 if (!subcs) {
1733 if ((rule->flags & CONF_FLAG_OK_MISSING) != 0) return 0;
1734
1735 if (!name2 || (name2 == CF_IDENT_ANY)) {
1736 cf_log_err(cs, "Failed finding '%s' subsection", name1);
1737 } else {
1738 cf_log_err(cs, "Failed finding '%s %s' subsection", name1, name2);
1739 }
1740
1741 cf_item_debug(cs);
1742 return -1;
1743 }
1744
1745 /*
1746 * The old rules were delayed until we pushed a matching subsection which is actually used.
1747 */
1748 if ((old->flags & CONF_FLAG_OPTIONAL) != 0) {
1749 if (cf_section_rules_push(subcs, old->subcs) < 0) return -1;
1750 }
1751
1752 return cf_section_rules_push(subcs, rule->subcs);
1753 }
1754
1755 cf_log_err(cs, "Data of type %s with name \"%s\" already exists. "
1756 "Existing data added %s[%i]", "conf_parser_t",
1757 name1, cd->item.filename, cd->item.lineno);
1758
1759 cf_item_debug(cs);
1760 return -1;
1761 }
1762
1763 return 0;
1764}
1765
1766/** Add an array of parse rules to a #CONF_SECTION
1767 *
1768 * @param[in] cs to add rules to.
1769 * @param[in] rules to add. Last element should have NULL name field.
1770 * @param[in] filename where the rule was pushed.
1771 * @param[in] lineno where the rule was pushed.
1772 * @return
1773 * - 0 on success.
1774 * - -1 on failure.
1775 */
1776int _cf_section_rules_push(CONF_SECTION *cs, conf_parser_t const *rules, char const *filename, int lineno)
1777{
1778 conf_parser_t const *rule_p;
1779
1780 if (!cs || !rules) return 0;
1781
1782 for (rule_p = rules; rule_p->name1; rule_p++) {
1783 if (fr_rule_v3_deprecated(rule_p)) continue; /* Skip v3 deprecated */
1784 if (_cf_section_rule_push(cs, rule_p, filename, lineno) < 0) return -1;
1785 }
1786
1787 /*
1788 * Ensure we have a proper terminator, type so we catch
1789 * missing terminators reliably
1790 */
1791 fr_cond_assert(rule_p->type == conf_term.type);
1792
1793 return 0;
1794}
1795
1796/** Define a function which resolves a #CONF_PAIR value in a table, and writes the result as _type
1797 *
1798 * Each function looks the value of the #CONF_PAIR up in the #cf_table_parse_ctx_t
1799 * table passed as the rule's uctx, and stores the result in a field of type _type.
1800 * Use the function whose type matches the field, so the store writes exactly as
1801 * many bytes as the field holds. An enum field gets the function matching the
1802 * enum's fixed underlying type.
1803 *
1804 * @param[in] _name suffix of the function name, cf_table_parse_<_name>.
1805 * @param[in] _type C type of the field the function writes to.
1806 * @param[in] _out_of_range expression of num, true if num does not fit in _type.
1807 */
1808#define CF_TABLE_PARSE_DEF(_name, _type, _out_of_range) \
1809int cf_table_parse_ ## _name(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, \
1810 CONF_ITEM *ci, conf_parser_t const *rule) \
1811{ \
1812 int32_t num; \
1813 cf_table_parse_ctx_t const *parse_ctx = rule->uctx; \
1814\
1815 if (cf_pair_in_table(&num, parse_ctx->table, *parse_ctx->len, cf_item_to_pair(ci)) < 0) return -1; \
1816 if (_out_of_range) { \
1817 cf_log_err(ci, "Resolved value %i does not fit in " STRINGIFY(_type), num); \
1818 return -1; \
1819 } \
1820 *((_type *)out) = (_type)num; \
1821\
1822 return 0; \
1823}
1824
1825CF_TABLE_PARSE_DEF(int, int, false)
1826CF_TABLE_PARSE_DEF(int8, int8_t, (num < INT8_MIN) || (num > INT8_MAX))
1827CF_TABLE_PARSE_DEF(int16, int16_t, (num < INT16_MIN) || (num > INT16_MAX))
1828CF_TABLE_PARSE_DEF(int32, int32_t, false)
1829CF_TABLE_PARSE_DEF(uint8, uint8_t, (num < 0) || (num > UINT8_MAX))
1830CF_TABLE_PARSE_DEF(uint16, uint16_t, (num < 0) || (num > UINT16_MAX))
1831CF_TABLE_PARSE_DEF(uint32, uint32_t, num < 0)
1832
1833/** Generic function for resolving UID strings to uid_t values
1834 *
1835 * Type should be FR_TYPE_VOID, struct field should be a uid_t.
1836 */
1837int cf_parse_uid(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
1838 CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
1839{
1840 if (fr_perm_uid_from_str(ctx, (uid_t *)out, cf_pair_value(cf_item_to_pair(ci))) < 0) {
1841 cf_log_perr(ci, "Failed resolving UID");
1842 return -1;
1843 }
1844
1845 return 0;
1846}
1847
1848/** Generic function for resolving GID strings to uid_t values
1849 *
1850 * Type should be FR_TYPE_VOID, struct field should be a gid_t.
1851 */
1852int cf_parse_gid(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
1853 CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
1854{
1855 if (fr_perm_gid_from_str(ctx, (gid_t *)out, cf_pair_value(cf_item_to_pair(ci))) < 0) {
1856 cf_log_perr(ci, "Failed resolving GID");
1857 return -1;
1858 }
1859
1860 return 0;
1861}
1862
1863/** Generic function for resolving permissions to a mode-t
1864 *
1865 * Type should be FR_TYPE_VOID, struct field should be a gid_t.
1866 */
1867int cf_parse_permissions(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
1868 CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
1869{
1870 mode_t mode;
1871 char const *name = cf_pair_value(cf_item_to_pair(ci));
1872
1873 if (fr_perm_mode_from_str(&mode, name) < 0) {
1874 cf_log_perr(ci, "Invalid permissions string");
1875 return -1;
1876 }
1877
1878 *(mode_t *) out = mode;
1879
1880 return 0;
1881}
1882
1883/** NULL callback for sections
1884 *
1885 * This callback exists only as a place-holder to ensure that the
1886 * nested on_read functions are called. The conf file routines won't
1887 * recurse into every conf_parser_t section to check if there's an
1888 * "on_read" callback. So this place-holder is a signal to do that.
1889 *
1890 * @param[in] ctx to allocate data in.
1891 * @param[out] out Unused
1892 * @param[in] parent Base structure address.
1893 * @param[in] ci #CONF_SECTION containing the current section.
1894 * @param[in] rule unused.
1895 * @return
1896 * - 0 on success.
1897 * - -1 on failure.
1898 */
1899int cf_null_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent,
1900 UNUSED CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
1901{
1902 return 0;
1903}
1904
1905/** Bit-pos indexed table of `CONF_FLAG_*` names.
1906 *
1907 * Index is `fr_high_bit_pos()` of the flag value, which matches the
1908 * `_Generic` dispatch on `fr_table_num_indexed_bit_pos_t` in
1909 * `fr_table_str_by_value`.
1910 */
1935
static int const char char buffer[256]
Definition acutest.h:641
#define RCSID(id)
Definition build.h:603
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
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
cf_file_check_err_t cf_file_check_unix_perm(char const *filename, UNUSED void *uctx)
Check if file exists, and is a socket.
Definition cf_file.c:975
cf_file_check_err_t cf_file_check(CONF_PAIR *cp, bool check_perms)
Do some checks on the file as an "input" file.
Definition cf_file.c:1079
cf_file_check_err_t cf_file_check_effective(char const *filename, cf_file_check_err_t(*cb)(char const *filename, void *uctx), void *uctx)
Perform an operation with the effect/group set to conf_check_gid and conf_check_uid.
Definition cf_file.c:842
cf_file_check_err_t cf_file_check_unix_connect(char const *filename, UNUSED void *uctx)
Check if we can connect to a unix socket.
Definition cf_file.c:902
static int parse_error(cf_stack_t *stack, char const *ptr, char const *message)
Definition cf_file.c:2174
@ CF_FILE_NO_UNIX_SOCKET
File is not a unix socket.
Definition cf_file.h:49
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
char const * cf_parser_flag_to_enum_str(conf_parser_flags_t mask)
Return the source-identifier name for a single CONF_FLAG_* bit.
Definition cf_parse.c:1936
static size_t cf_parser_flag_table_len
Definition cf_parse.c:1934
static bool * cf_rule_is_set_ptr(void *base, conf_parser_t const *rule)
Find where a rule records whether the rule's config item was present.
Definition cf_parse.c:866
static int cf_pair_default(CONF_PAIR **out, void *parent, CONF_SECTION *cs, conf_parser_t const *rule)
Allocate a pair using the dflt value and quotation.
Definition cf_parse.c:415
#define PAIR_SPACE(_cs)
Definition cf_parse.c:47
static char const parse_spaces[]
Definition cf_parse.c:45
int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Parses a CONF_PAIR into a C data type.
Definition cf_parse.c:252
static int cf_pair_unescape(CONF_PAIR *cp, conf_parser_t const *rule)
Definition cf_parse.c:472
static void cf_section_parse_warn(CONF_SECTION *cs)
Definition cf_parse.c:1012
static conf_parser_t conf_term
Definition cf_parse.c:44
int cf_parse_gid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving GID strings to uid_t values.
Definition cf_parse.c:1852
int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt, fr_token_t dflt_quote)
Parses a CONF_PAIR into a C data type, with a default value.
Definition cf_parse.c:844
void cf_pair_debug_log(CONF_SECTION const *cs, CONF_PAIR *cp, conf_parser_t const *rule)
Definition cf_parse.c:50
int cf_null_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent, UNUSED CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
NULL callback for sections.
Definition cf_parse.c:1899
static int cf_pair_parse_internal(TALLOC_CTX *ctx, void *out, void *base, CONF_SECTION *cs, conf_parser_t const *rule)
Parses a CONF_PAIR into a C data type, with a default value.
Definition cf_parse.c:577
int cf_parse_permissions(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Generic function for resolving permissions to a mode-t.
Definition cf_parse.c:1867
int cf_section_parse_pass2(void *base, CONF_SECTION *cs)
Fixup xlat expansions and attributes.
Definition cf_parse.c:1470
static fr_table_num_indexed_bit_pos_t const cf_parser_flag_table[]
Bit-pos indexed table of CONF_FLAG_* names.
Definition cf_parse.c:1911
static int cf_section_parse_init(CONF_SECTION *cs, void *base, conf_parser_t const *rule)
Pre-allocate a config section structure to allow defaults to be set.
Definition cf_parse.c:888
int _cf_section_rule_push(CONF_SECTION *cs, conf_parser_t const *rule, char const *filename, int lineno)
Add a single rule to a CONF_SECTION.
Definition cf_parse.c:1662
#define SECTION_SPACE(_cs)
Definition cf_parse.c:48
int _cf_section_rules_push(CONF_SECTION *cs, conf_parser_t const *rules, char const *filename, int lineno)
Add an array of parse rules to a CONF_SECTION.
Definition cf_parse.c:1776
int cf_pair_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, CONF_PAIR *cp, conf_parser_t const *rule)
Parses a CONF_PAIR into a boxed value.
Definition cf_parse.c:127
static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, void *base, CONF_SECTION *cs, conf_parser_t const *rule)
Parse a subsection.
Definition cf_parse.c:1056
#define CF_TABLE_PARSE_DEF(_name, _type, _out_of_range)
Define a function which resolves a CONF_PAIR value in a table, and writes the result as _type.
Definition cf_parse.c:1808
static int cf_parse_tmpl_pass2(UNUSED CONF_SECTION *cs, tmpl_t **out, CONF_PAIR *cp, fr_type_t type, bool attribute, fr_dict_t const *dict_def)
Definition cf_parse.c:1403
static int cf_section_parse_rule(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, conf_parser_t const *rule)
Definition cf_parse.c:1198
#define fr_rule_is_static(_rule)
Definition cf_parse.h:551
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:712
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:666
#define fr_rule_file_writable(_rule)
Definition cf_parse.h:529
void * data
Pointer to a static variable to write the parsed value to.
Definition cf_parse.h:663
#define fr_rule_file_readable(_rule)
Definition cf_parse.h:527
#define fr_rule_file_socket(_rule)
Definition cf_parse.h:531
#define fr_rule_dflt(_rule)
Definition cf_parse.h:543
int cf_parse_uid(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
conf_parser_flags_t flags
Flags which control parsing behaviour.
Definition cf_parse.h:655
#define fr_rule_not_empty(_rule)
Definition cf_parse.h:537
fr_type_t type
An fr_type_t value, controls the output type.
Definition cf_parse.h:653
size_t offset
Relative offset of field or structure to write the parsed value to.
Definition cf_parse.h:657
#define fr_rule_multi(_rule)
Definition cf_parse.h:535
char const * name2
Second identifier for CONF_SECTION.
Definition cf_parse.h:651
conf_parser_flags_t
Definition cf_parse.h:458
@ CONF_FLAG_STATIC
The tmpl_t must hold a fixed value.
Definition cf_parse.h:508
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:466
@ CONF_FLAG_FILE_SOCKET
File matching value must exist, and must be a unix socket.
Definition cf_parse.h:476
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
Definition cf_parse.h:483
@ CONF_FLAG_V3_DEPRECATED
If a matching CONF_PAIR is found, error out with a deprecated message.
Definition cf_parse.h:464
@ CONF_FLAG_REF
reference another conf_parser_t inline in this one
Definition cf_parse.h:494
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
Definition cf_parse.h:470
@ CONF_FLAG_NO_OUTPUT
Rule has no framework-managed output destination.
Definition cf_parse.h:501
@ CONF_FLAG_IS_SET
Write whether this config item was left as the default to is_set_offset or is_set_ptr.
Definition cf_parse.h:488
@ CONF_FLAG_ATTRIBUTE
Value must resolve to attribute in dict (deprecated, use CONF_FLAG_TMPL).
Definition cf_parse.h:468
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:484
@ CONF_FLAG_XLAT
string will be dynamically expanded.
Definition cf_parse.h:480
@ CONF_FLAG_OPTIONAL
subsection is pushed only if a non-optional matching one is pushed
Definition cf_parse.h:495
@ CONF_FLAG_FILE_READABLE
File matching value must exist, and must be readable.
Definition cf_parse.h:472
@ CONF_FLAG_OK_MISSING
OK if it's missing.
Definition cf_parse.h:491
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:460
@ CONF_FLAG_FILE_EXISTS
File matching value must exist.
Definition cf_parse.h:478
@ CONF_FLAG_TMPL
CONF_PAIR should be parsed as a template.
Definition cf_parse.h:481
@ CONF_FLAG_HIDDEN
Used by scripts to omit items from the generated documentation.
Definition cf_parse.h:492
@ CONF_FLAG_ALWAYS_PARSE
Run this rule even against items already marked parsed.
Definition cf_parse.h:496
@ CONF_FLAG_FILE_WRITABLE
File matching value must exist, and must be writable.
Definition cf_parse.h:474
fr_token_t quote
Quoting around the default value. Only used for templates.
Definition cf_parse.h:704
#define fr_rule_file_exists(_rule)
Definition cf_parse.h:533
int(* cf_parse_t)(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Callback for performing custom parsing of a CONF_SECTION or CONF_PAIR.
Definition cf_parse.h:606
#define fr_rule_v3_deprecated(_rule)
Definition cf_parse.h:521
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:744
#define fr_rule_is_tmpl(_rule)
Definition cf_parse.h:549
char const * name1
Name of the CONF_ITEM to parse.
Definition cf_parse.h:650
#define fr_rule_is_attribute(_rule)
Definition cf_parse.h:545
cf_parse_t on_read
Function to call as the item is being read, just after it has been allocated and initialized.
Definition cf_parse.h:669
#define fr_rule_required(_rule)
Definition cf_parse.h:523
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
bool printed
Was this item printed already in debug mode?
Definition cf_priv.h:88
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:107
void * base
Definition cf_priv.h:118
char const * name2
Second name token. Given foo bar {} would be bar.
Definition cf_priv.h:110
char const * attr
Attribute name.
Definition cf_priv.h:80
@ CONF_ITEM_PAIR
Definition cf_priv.h:41
@ CONF_ITEM_SECTION
Definition cf_priv.h:42
bool referenced
Was this item referenced in the config?
Definition cf_priv.h:69
fr_token_t rhs_quote
Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition cf_priv.h:85
bool parsed
Was this item used during parsing?
Definition cf_priv.h:68
char const * value
Attribute value.
Definition cf_priv.h:81
char const * name1
First name token. Given foo bar {} would be foo.
Definition cf_priv.h:109
void const * data
User data.
Definition cf_priv.h:201
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:78
char const * filename
The file the config item was parsed from.
Definition cf_priv.h:71
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:196
int lineno
The line number the config item began on.
Definition cf_priv.h:70
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
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
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
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
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_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
CONF_DATA const * _cf_data_add_static(CONF_ITEM *ci, void const *data, char const *type, char const *name, char const *filename, int lineno)
Add non-talloced user data to a config section.
Definition cf_util.c:1987
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_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
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:709
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:295
#define cf_item_is_parsed(_cf)
Definition cf_util.h:191
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:418
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:198
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
Definition cf_util.h:65
#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_log_debug(_cf, _fmt,...)
Definition cf_util.h:343
#define cf_data_find_next(_cf, _prev, _type, _name)
Definition cf_util.h:298
#define cf_item_debug(_cf)
Definition cf_util.h:412
#define cf_item_mark_parsed(_cf)
Definition cf_util.h:188
#define CF_IDENT_ANY
Definition cf_util.h:80
fr_dict_t * dict
Definition common.c:31
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define MEM(x)
Definition debug.h:38
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
#define DEBUG_ENABLED4
True if global debug level 1-4 messages are enabled.
Definition log.h:265
int fr_debug_lvl
Definition log.c:41
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition log.c:105
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
Definition log.h:69
unsigned short uint16_t
fr_type_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_VOID
User data.
unsigned int uint32_t
unsigned char uint8_t
ssize_t fr_slen_t
#define UINT8_MAX
int fr_perm_mode_from_str(mode_t *out, char const *str)
Definition perm.c:62
int fr_perm_uid_from_str(TALLOC_CTX *ctx, uid_t *out, char const *name)
Resolve a user name to a GID.
Definition perm.c:453
int fr_perm_gid_from_str(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
Definition perm.c:475
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
Definition print.c:438
#define fr_assert(_expr)
Definition rad_assert.h:37
static char * secret
#define WARN(fmt,...)
static const char * spaces
Definition radict.c:185
static uint32_t mask
Definition rbmonkey.c:39
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:661
#define tmpl_contains_data(vpt)
Definition tmpl.h:231
fr_slen_t tmpl_afrom_value_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, tmpl_rules_t const *t_rules, bool allow_enum, fr_sbuff_parse_rules_t const *p_rules))
Create TMPL_TYPE_DATA from a string.
int tmpl_resolve(tmpl_t *vpt, tmpl_res_rules_t const *tr_rules))
Attempt to resolve functions and attributes in xlats and attribute references.
#define tmpl_value(_tmpl)
Definition tmpl.h:960
#define tmpl_is_attr(vpt)
Definition tmpl.h:215
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
fr_slen_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
static char const * tmpl_attr_tail_unresolved(tmpl_t const *vpt)
Return the last attribute reference unresolved da.
Definition tmpl.h:892
int tmpl_cast_in_place(tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv))
Convert tmpl_t of type TMPL_TYPE_DATA_UNRESOLVED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specifie...
#define tmpl_is_data(vpt)
Definition tmpl.h:213
static fr_slen_t vpt
Definition tmpl.h:1298
#define tmpl_value_type(_tmpl)
Definition tmpl.h:962
#define tmpl_is_data_unresolved(vpt)
Definition tmpl.h:224
fr_type_t cast
Whether there was an explicit cast.
Definition tmpl.h:351
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:346
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition tmpl.h:165
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition tmpl.h:206
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition tmpl.h:192
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition tmpl.h:149
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition tmpl.h:153
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition tmpl.h:157
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition tmpl.h:204
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition tmpl.h:145
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition tmpl.h:161
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition tmpl.h:186
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition tmpl.h:200
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
Definition tmpl.h:169
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition tmpl.h:196
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition tmpl.h:141
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
Similar to tmpl_rules_t, but used to specify parameters that may change during subsequent resolution ...
Definition tmpl.h:391
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:343
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
return count
Definition module.c:155
fr_aka_sim_id_type_t type
unsigned int allow_unknown
Allow unknown attributes i.e.
Definition tmpl.h:310
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:302
#define FR_TABLE_INDEXED_BIT_POS_ENTRY(_v)
Build a single fr_table_num_indexed_bit_pos_t entry from an enum identifier.
Definition table.h:125
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in a table indexed by bit position.
Definition table.h:83
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
const char fr_token_quote[T_TOKEN_LAST]
Convert tokens back to a quoting character.
Definition token.c:222
@ T_INVALID
Definition token.h:37
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_BACK_QUOTED_STRING
Definition token.h:121
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:122
enum fr_token fr_token_t
fr_slen_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Tokenize an xlat expansion.
static fr_slen_t parent
Definition pair.h:864
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#define fr_strerror_const(_msg)
Definition strerror.h:223
void ** fr_type_array_alloc(TALLOC_CTX *ctx, fr_type_t type, size_t count)
Allocate an array of a given type.
Definition types.c:700
#define fr_type_is_string(_x)
Definition types.h:348
#define fr_type_is_quoted(_x)
Definition types.h:389
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition value.c:162
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4465
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4400
fr_sbuff_parse_rules_t const * value_parse_rules_unquoted[T_TOKEN_LAST]
Parse rules for non-quoted strings.
Definition value.c:522
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4448
static int fr_value_box_memcpy_out(void *out, fr_value_box_t const *vb)
Copy the value of a value box to a field in a C struct.
Definition value.h:828
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1124
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
int nonnull(2, 5))
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:178
fr_dict_t const * virtual_server_dict_by_child_ci(CONF_ITEM const *ci)
Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server.