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