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