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