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