The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
cf_file.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: 51d54f65af2e25c1aca5cafe83b6238b1ac5eaef $
19  * @file cf_file.c
20  * @brief Read the radiusd.conf file.
21  *
22  * @note Yep I should learn to use lex & yacc, or at least
23  * write a decent parser. I know how to do that, really :)
24  * miquels@cistron.nl
25  *
26  * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
27  * @copyright 2000,2006 The FreeRADIUS server project
28  * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
29  * @copyright 2000 Alan DeKok (aland@freeradius.org)
30  */
31 RCSID("$Id: 51d54f65af2e25c1aca5cafe83b6238b1ac5eaef $")
32 
33 #include <freeradius-devel/server/cf_file.h>
34 #include <freeradius-devel/server/cf_priv.h>
35 #include <freeradius-devel/server/log.h>
36 #include <freeradius-devel/server/tmpl.h>
37 #include <freeradius-devel/server/util.h>
38 #include <freeradius-devel/server/virtual_servers.h>
39 #include <freeradius-devel/util/debug.h>
40 #include <freeradius-devel/util/file.h>
41 #include <freeradius-devel/util/misc.h>
42 #include <freeradius-devel/util/perm.h>
43 #include <freeradius-devel/util/syserror.h>
44 
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 
49 #ifdef HAVE_DIRENT_H
50 # include <dirent.h>
51 #endif
52 
53 #ifdef HAVE_GLOB_H
54 # include <glob.h>
55 #endif
56 
57 #ifdef HAVE_SYS_STAT_H
58 # include <sys/stat.h>
59 #endif
60 
61 #include <ctype.h>
62 #include <fcntl.h>
63 
64 #include <freeradius-devel/server/main_config.h>
65 
66 bool check_config = false;
67 static uid_t conf_check_uid = (uid_t)-1;
68 static gid_t conf_check_gid = (gid_t)-1;
69 
70 typedef enum conf_property {
75 
77  { L("instance"), CONF_PROPERTY_INSTANCE },
78  { L("name"), CONF_PROPERTY_NAME }
79 };
81 
82 typedef enum {
84 #ifdef HAVE_DIRENT_H
85  CF_STACK_DIR,
86 #endif
87 #ifdef HAVE_GLOB_H
88  CF_STACK_GLOB
89 #endif
91 
92 #define MAX_STACK (32)
93 typedef struct {
95 
96  char const *filename; //!< filename we're reading
97  int lineno; //!< line in that filename
98 
99  union {
100  struct {
101  FILE *fp; //!< FP we're reading
102  };
103 
104 #ifdef HAVE_DIRENT_H
105  struct {
106  fr_heap_t *heap; //!< sorted heap of files
107  char *directory; //!< directory name we're reading
108  };
109 #endif
110 
111 #ifdef HAVE_GLOB_H
112  struct {
113  size_t gl_current;
114  glob_t glob; //! reading glob()
115  bool required;
116  };
117 #endif
118  };
119 
120  CONF_SECTION *parent; //!< which started this file
121  CONF_SECTION *current; //!< sub-section we're reading
122  CONF_SECTION *special; //!< map / update section
123 
124  bool require_edits; //!< are we required to do edits?
125 
126  int braces;
127  bool from_dir; //!< this file was read from $include foo/
129 
130 /*
131  * buff[0] is the data we read from the file
132  * buff[1] is name
133  * buff[2] is name2 OR value for pair
134  * buff[3] is a temporary buffer
135  */
136 typedef struct {
137  char **buff; //!< buffers for reading / parsing
138  size_t bufsize; //!< size of the buffers
139  int depth; //!< stack depth
140  char const *ptr; //!< current parse pointer
141  char *fill; //!< where we start filling the buffer from
142  cf_stack_frame_t frame[MAX_STACK]; //!< stack frames
143 } cf_stack_t;
144 
145 
146 static inline CC_HINT(always_inline) int cf_tmpl_rules_verify(CONF_SECTION *cs, tmpl_rules_t const *rules)
147 {
148  if (cf_section_find_parent(cs, "policy", NULL)) {
149  if (!fr_cond_assert_msg(!rules->attr.dict_def || (rules->attr.dict_def == fr_dict_internal()),
150  "Protocol dictionary must be NULL not %s",
151  fr_dict_root(rules->attr.dict_def)->name)) return -1;
152 
153  } else {
154  if (!fr_cond_assert_msg(rules->attr.dict_def, "No protocol dictionary set")) return -1;
155  if (!fr_cond_assert_msg(rules->attr.dict_def != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
156  }
157 
158  if (!fr_cond_assert_msg(!rules->attr.allow_foreign, "rules->allow_foreign must be false")) return -1;
159  if (!fr_cond_assert_msg(!rules->at_runtime, "rules->at_runtime must be false")) return -1;
160 
161  return 0;
162 }
163 
164 #define RULES_VERIFY(_cs, _rules) if (cf_tmpl_rules_verify(_cs, _rules) < 0) return NULL
165 
166 static ssize_t fr_skip_xlat(char const *start, char const *end);
167 
168 /*
169  * Expand the variables in an input string.
170  *
171  * Input and output should be two different buffers, as the
172  * output may be longer than the input.
173  */
174 char const *cf_expand_variables(char const *cf, int lineno,
175  CONF_SECTION *outer_cs,
176  char *output, size_t outsize,
177  char const *input, ssize_t inlen, bool *soft_fail)
178 {
179  char *p;
180  char const *end, *next, *ptr;
181  CONF_SECTION const *parent_cs;
182  char name[8192];
183 
184  if (soft_fail) *soft_fail = false;
185 
186  /*
187  * Find the master parent conf section.
188  * We can't use main_config->root_cs, because we're in the
189  * process of re-building it, and it isn't set up yet...
190  */
191  parent_cs = cf_root(outer_cs);
192 
193  p = output;
194  ptr = input;
195 
196  if (inlen < 0) {
197  end = NULL;
198  } else {
199  end = input + inlen;
200  }
201 
202  /*
203  * Note that this CAN go over "end" if the input string
204  * is malformed. e.g. pass "${foo.bar}", and pass
205  * "inlen=5". Well, too bad.
206  */
207  while (*ptr && (!end || (ptr < end))) {
208  /*
209  * Ignore anything other than "${"
210  */
211  if ((*ptr == '$') && (ptr[1] == '{')) {
212  CONF_ITEM *ci;
213  CONF_PAIR *cp;
214  char *q;
215  ssize_t len;
216 
217  len = fr_skip_xlat(ptr, end);
218  if (len <= 0) {
219  ERROR("%s[%d]: Failed parsing variable expansion '%s''",
220  cf, lineno, input);
221  return NULL;
222  }
223 
224  next = ptr + len;
225  ptr += 2;
226 
227  /*
228  * Can't really happen because input lines are
229  * capped at 8k, which is sizeof(name)
230  */
231  if ((size_t) len >= sizeof(name)) {
232  ERROR("%s[%d]: Reference string is too large",
233  cf, lineno);
234  return NULL;
235  }
236 
237  memcpy(name, ptr, len - 3);
238  name[len - 3] = '\0';
239 
240  /*
241  * Read configuration value from a file.
242  *
243  * Note that this is "read binary data", and the contents aren't stripped of
244  * CRLF.
245  */
246  if (name[0] == '/') {
247  int fd = open(name, O_RDONLY);
248  struct stat buf;
249 
250  if (fd < 0) {
251  ERROR("%s[%d]: Reference \"${%s}\" failed opening file - %s", cf, lineno, name, fr_syserror(errno));
252  return NULL;
253  }
254 
255  if (fstat(fd, &buf) < 0) {
256  fail_fd:
257  close(fd);
258  ERROR("%s[%d]: Reference \"${%s}\" failed reading file - %s", cf, lineno, name, fr_syserror(errno));
259  return NULL;
260  }
261 
262  if (buf.st_size >= ((output + outsize) - p)) {
263  close(fd);
264  ERROR("%s[%d]: Reference \"${%s}\" file is too large (%zd >= %zd)", cf, lineno, name,
265  (size_t) buf.st_size, ((output + outsize) - p));
266  return NULL;
267  }
268 
269  len = read(fd, p, (output + outsize) - p);
270  if (len < 0) goto fail_fd;
271 
272  close(fd);
273  p += len;
274  *p = '\0';
275  ptr = next;
276  goto check_eos;
277  }
278 
279  q = strchr(name, ':');
280  if (q) {
281  *(q++) = '\0';
282  }
283 
284  ci = cf_reference_item(parent_cs, outer_cs, name);
285  if (!ci) {
286  if (soft_fail) *soft_fail = true;
287  ERROR("%s[%d]: Reference \"${%s}\" not found", cf, lineno, name);
288  return NULL;
289  }
290 
291  /*
292  * The expansion doesn't refer to another item or section
293  * it's the property of a section.
294  */
295  if (q) {
296  CONF_SECTION *find = cf_item_to_section(ci);
297 
298  if (ci->type != CONF_ITEM_SECTION) {
299  ERROR("%s[%d]: Can only reference properties of sections", cf, lineno);
300  return NULL;
301  }
302 
304  case CONF_PROPERTY_NAME:
305  strcpy(p, find->name1);
306  break;
307 
309  strcpy(p, find->name2 ? find->name2 : find->name1);
310  break;
311 
312  default:
313  ERROR("%s[%d]: Invalid property '%s'", cf, lineno, q);
314  return NULL;
315  }
316  p += strlen(p);
317  ptr = next;
318 
319  } else if (ci->type == CONF_ITEM_PAIR) {
320  /*
321  * Substitute the value of the variable.
322  */
323  cp = cf_item_to_pair(ci);
324 
325  /*
326  * If the thing we reference is
327  * marked up as being expanded in
328  * pass2, don't expand it now.
329  * Let it be expanded in pass2.
330  */
331  if (cp->pass2) {
332  if (soft_fail) *soft_fail = true;
333 
334  ERROR("%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
335  cf, lineno, input);
336  return NULL;
337  }
338 
339  if (!cp->value) {
340  ERROR("%s[%d]: Reference \"%s\" has no value",
341  cf, lineno, input);
342  return NULL;
343  }
344 
345  if (p + strlen(cp->value) >= output + outsize) {
346  ERROR("%s[%d]: Reference \"%s\" is too long",
347  cf, lineno, input);
348  return NULL;
349  }
350 
351  strcpy(p, cp->value);
352  p += strlen(p);
353  ptr = next;
354 
355  } else if (ci->type == CONF_ITEM_SECTION) {
356  CONF_SECTION *subcs;
357 
358  /*
359  * Adding an entry again to a
360  * section is wrong. We don't
361  * want an infinite loop.
362  */
363  if (cf_item_to_section(ci->parent) == outer_cs) {
364  ERROR("%s[%d]: Cannot reference different item in same section", cf, lineno);
365  return NULL;
366  }
367 
368  /*
369  * Copy the section instead of
370  * referencing it.
371  */
372  subcs = cf_item_to_section(ci);
373  subcs = cf_section_dup(outer_cs, outer_cs, subcs,
374  cf_section_name1(subcs), cf_section_name2(subcs),
375  false);
376  if (!subcs) {
377  ERROR("%s[%d]: Failed copying reference %s", cf, lineno, name);
378  return NULL;
379  }
380 
381  cf_filename_set(subcs, ci->filename);
382  cf_lineno_set(subcs, ci->lineno);
383 
384  ptr = next;
385 
386  } else {
387  ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, lineno, input);
388  return NULL;
389  }
390  } else if (strncmp(ptr, "$ENV{", 5) == 0) {
391  char *env;
392 
393  ptr += 5;
394 
395  /*
396  * Look for trailing '}', and log a
397  * warning for anything that doesn't match,
398  * and exit with a fatal error.
399  */
400  next = strchr(ptr, '}');
401  if (next == NULL) {
402  *p = '\0';
403  ERROR("%s[%d]: Environment variable expansion missing }",
404  cf, lineno);
405  return NULL;
406  }
407 
408  /*
409  * Can't really happen because input lines are
410  * capped at 8k, which is sizeof(name)
411  */
412  if ((size_t) (next - ptr) >= sizeof(name)) {
413  ERROR("%s[%d]: Environment variable name is too large",
414  cf, lineno);
415  return NULL;
416  }
417 
418  memcpy(name, ptr, next - ptr);
419  name[next - ptr] = '\0';
420 
421  /*
422  * Get the environment variable.
423  * If none exists, then make it an empty string.
424  */
425  env = getenv(name);
426  if (env == NULL) {
427  *name = '\0';
428  env = name;
429  }
430 
431  if (p + strlen(env) >= output + outsize) {
432  ERROR("%s[%d]: Reference \"%s\" is too long",
433  cf, lineno, input);
434  return NULL;
435  }
436 
437  strcpy(p, env);
438  p += strlen(p);
439  ptr = next + 1;
440 
441  } else {
442  /*
443  * Copy it over verbatim.
444  */
445  *(p++) = *(ptr++);
446  }
447 
448  check_eos:
449  if (p >= (output + outsize)) {
450  ERROR("%s[%d]: Reference \"%s\" is too long",
451  cf, lineno, input);
452  return NULL;
453  }
454  } /* loop over all of the input string. */
455 
456  *p = '\0';
457 
458  return output;
459 }
460 
461 /*
462  * Merge the template so everything else "just works".
463  */
464 static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
465 {
466  if (!cs || !template) return true;
467 
468  cs->template = NULL;
469 
470  /*
471  * Walk over the template, adding its' entries to the
472  * current section. But only if the entries don't
473  * already exist in the current section.
474  */
475  cf_item_foreach(&template->item, ci) {
476  if (ci->type == CONF_ITEM_PAIR) {
477  CONF_PAIR *cp1, *cp2;
478 
479  /*
480  * It exists, don't over-write it.
481  */
482  cp1 = cf_item_to_pair(ci);
483  if (cf_pair_find(cs, cp1->attr)) {
484  continue;
485  }
486 
487  /*
488  * Create a new pair with all of the data
489  * of the old one.
490  */
491  cp2 = cf_pair_dup(cs, cp1);
492  if (!cp2) return false;
493 
494  cf_filename_set(cp2, cp1->item.filename);
495  cf_lineno_set(cp2, cp1->item.lineno);
496  continue;
497  }
498 
499  if (ci->type == CONF_ITEM_SECTION) {
500  CONF_SECTION *subcs1, *subcs2;
501 
502  subcs1 = cf_item_to_section(ci);
503  fr_assert(subcs1 != NULL);
504 
505  subcs2 = cf_section_find(cs, subcs1->name1, subcs1->name2);
506  if (subcs2) {
507  /*
508  * sub-sections get merged.
509  */
510  if (!cf_template_merge(subcs2, subcs1)) {
511  return false;
512  }
513  continue;
514  }
515 
516  /*
517  * Our section doesn't have a matching
518  * sub-section. Copy it verbatim from
519  * the template.
520  */
521  subcs2 = cf_section_dup(cs, cs, subcs1,
522  cf_section_name1(subcs1), cf_section_name2(subcs1),
523  false);
524  if (!subcs2) return false;
525 
526  cf_filename_set(subcs2, subcs1->item.filename);
527  cf_lineno_set(subcs2, subcs1->item.lineno);
528  continue;
529  }
530 
531  /* ignore everything else */
532  }
533 
534  return true;
535 }
536 
537 /*
538  * Functions for tracking files by inode
539  */
540 static int8_t _inode_cmp(void const *one, void const *two)
541 {
542  cf_file_t const *a = one, *b = two;
543 
544  CMP_RETURN(a, b, buf.st_dev);
545 
546  return CMP(a->buf.st_ino, b->buf.st_ino);
547 }
548 
549 static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
550 {
551  cf_file_t *file;
552  CONF_SECTION *top;
553  fr_rb_tree_t *tree;
554  int fd = -1;
555  FILE *fp;
556 
557  top = cf_root(cs);
558  tree = cf_data_value(cf_data_find(top, fr_rb_tree_t, "filename"));
559  fr_assert(tree);
560 
561  /*
562  * If we're including a wildcard directory, then ignore
563  * any files the users has already explicitly loaded in
564  * that directory.
565  */
566  if (from_dir) {
567  cf_file_t my_file;
568  char const *r;
569  int dirfd;
570 
571  my_file.cs = cs;
572  my_file.filename = filename;
573 
574  /*
575  * Find and open the directory containing filename so we can use
576  * the "at"functions to avoid time of check/time of use insecurities.
577  */
578  if (fr_dirfd(&dirfd, &r, filename) < 0) {
579  ERROR("Failed to open directory containing %s", filename);
580  return -1;
581  }
582 
583  if (fstatat(dirfd, r, &my_file.buf, 0) < 0) goto error;
584 
585  file = fr_rb_find(tree, &my_file);
586 
587  /*
588  * The file was previously read by including it
589  * explicitly. After it was read, we have a
590  * $INCLUDE of the directory it is in. In that
591  * case, we ignore the file.
592  *
593  * However, if the file WAS read from a wildcard
594  * $INCLUDE directory, then we read it again.
595  */
596  if (file && !file->from_dir) {
597  if (dirfd != AT_FDCWD) close(dirfd);
598  return 1;
599  }
600  fd = openat(dirfd, r, O_RDONLY, 0);
601  fp = (fd < 0) ? NULL : fdopen(fd, "r");
602  if (dirfd != AT_FDCWD) close(dirfd);
603  } else {
604  fp = fopen(filename, "r");
605  if (fp) fd = fileno(fp);
606  }
607 
608  DEBUG2("including configuration file %s", filename);
609 
610  if (!fp) {
611  error:
612  ERROR("Unable to open file \"%s\": %s", filename, fr_syserror(errno));
613  return -1;
614  }
615 
616  MEM(file = talloc(tree, cf_file_t));
617 
618  file->filename = talloc_strdup(file, filename); /* The rest of the code expects this to be a talloced buffer */
619  file->cs = cs;
620  file->from_dir = from_dir;
621 
622  if (fstat(fd, &file->buf) == 0) {
623 #ifdef S_IWOTH
624  if ((file->buf.st_mode & S_IWOTH) != 0) {
625  ERROR("Configuration file %s is globally writable. "
626  "Refusing to start due to insecure configuration.", filename);
627 
628  fclose(fp);
629  talloc_free(file);
630  return -1;
631  }
632 #endif
633  }
634 
635  /*
636  * We can include the same file twice. e.g. when it
637  * contains common definitions, such as for SQL.
638  *
639  * Though the admin should really use templates for that.
640  */
641  if (!fr_rb_insert(tree, file)) talloc_free(file);
642 
643  *fp_p = fp;
644  return 0;
645 }
646 
647 /** Do some checks on the file as an "input" file. i.e. one read by a module.
648  *
649  * @note Must be called with super user privileges.
650  *
651  * @param cp currently being processed.
652  * @param check_perms If true - will return false if file is world readable,
653  * or not readable by the unprivileged user/group.
654  * @return
655  * - true if permissions are OK, or the file exists.
656  * - false if the file does not exist or the permissions are incorrect.
657  */
658 bool cf_file_check(CONF_PAIR *cp, bool check_perms)
659 {
660  cf_file_t *file;
661  CONF_SECTION *top;
662  fr_rb_tree_t *tree;
663  char const *filename = cf_pair_value(cp);
664  int fd = -1;
665 
666  top = cf_root(cp);
667  tree = cf_data_value(cf_data_find(top, fr_rb_tree_t, "filename"));
668  if (!tree) return false;
669 
670  file = talloc(tree, cf_file_t);
671  if (!file) return false;
672 
673  file->filename = talloc_strdup(file, filename); /* The rest of the code expects this to be talloced */
674  file->cs = cf_item_to_section(cf_parent(cp));
675 
676  if (!check_perms) {
677  if (stat(filename, &file->buf) < 0) {
678  perm_error:
679  fr_perm_file_error(errno); /* Write error and euid/egid to error buff */
680  cf_log_perr(cp, "Unable to open file \"%s\"", filename);
681  error:
682  if (fd >= 0) close(fd);
683  talloc_free(file);
684  return false;
685  }
686  talloc_free(file);
687  return true;
688  }
689 
690  /*
691  * This really does seem to be the simplest way
692  * to check that the file can be read with the
693  * euid/egid.
694  */
695  {
696  uid_t euid = (uid_t)-1;
697  gid_t egid = (gid_t)-1;
698 
699  if ((conf_check_gid != (gid_t)-1) && ((egid = getegid()) != conf_check_gid)) {
700  if (setegid(conf_check_gid) < 0) {
701  cf_log_perr(cp, "Failed setting effective group ID (%i) for file check: %s",
702  conf_check_gid, fr_syserror(errno));
703  goto error;
704  }
705  }
706  if ((conf_check_uid != (uid_t)-1) && ((euid = geteuid()) != conf_check_uid)) {
707  if (seteuid(conf_check_uid) < 0) {
708  cf_log_perr(cp, "Failed setting effective user ID (%i) for file check: %s",
709  conf_check_uid, fr_syserror(errno));
710  goto error;
711  }
712  }
713  fd = open(filename, O_RDONLY);
714  if (conf_check_uid != euid) {
715  if (seteuid(euid) < 0) {
716  cf_log_perr(cp, "Failed restoring effective user ID (%i) after file check: %s",
717  euid, fr_syserror(errno));
718  goto error;
719  }
720  }
721  if (conf_check_gid != egid) {
722  if (setegid(egid) < 0) {
723  cf_log_perr(cp, "Failed restoring effective group ID (%i) after file check: %s",
724  egid, fr_syserror(errno));
725  goto error;
726  }
727  }
728  }
729 
730  if (fd < 0) goto perm_error;
731  if (fstat(fd, &file->buf) < 0) goto perm_error;
732 
733  close(fd);
734 
735 #ifdef S_IWOTH
736  if ((file->buf.st_mode & S_IWOTH) != 0) {
737  cf_log_perr(cp, "Configuration file %s is globally writable. "
738  "Refusing to start due to insecure configuration.", filename);
739  talloc_free(file);
740  return false;
741  }
742 #endif
743 
744  /*
745  * It's OK to include the same file twice...
746  */
747  if (!fr_rb_insert(tree, file)) talloc_free(file);
748 
749  return true;
750 }
751 
752 /*
753  * Do variable expansion in pass2.
754  *
755  * This is a breadth-first expansion. "deep
756  */
758 {
759  cf_item_foreach(&cs->item, ci) {
760  char const *value;
761  CONF_PAIR *cp;
762  char buffer[8192];
763 
764  if (ci->type != CONF_ITEM_PAIR) continue;
765 
766  cp = cf_item_to_pair(ci);
767  if (!cp->value || !cp->pass2) continue;
768 
769  fr_assert((cp->rhs_quote == T_BARE_WORD) ||
770  (cp->rhs_quote == T_HASH) ||
773 
774  value = cf_expand_variables(ci->filename, ci->lineno, cs, buffer, sizeof(buffer), cp->value, -1, NULL);
775  if (!value) return -1;
776 
778  cp->value = talloc_typed_strdup(cp, value);
779  }
780 
781  cf_item_foreach(&cs->item, ci) {
782  if (ci->type != CONF_ITEM_SECTION) continue;
783 
784  if (cf_section_pass2(cf_item_to_section(ci)) < 0) return -1;
785  }
786 
787  return 0;
788 }
789 
790 
791 static char const *cf_local_file(char const *base, char const *filename,
792  char *buffer, size_t bufsize)
793 {
794  size_t dirsize;
795  char *p;
796 
797  strlcpy(buffer, base, bufsize);
798 
799  p = strrchr(buffer, FR_DIR_SEP);
800  if (!p) return filename;
801  if (p[1]) { /* ./foo */
802  p[1] = '\0';
803  }
804 
805  dirsize = (p - buffer) + 1;
806 
807  if ((dirsize + strlen(filename)) >= bufsize) {
808  return NULL;
809  }
810 
811  strlcpy(p + 1, filename, bufsize - dirsize);
812 
813  return buffer;
814 }
815 
816 /*
817  * Like gettoken(), but uses the new API which seems better for a
818  * host of reasons.
819  */
820 static int cf_get_token(CONF_SECTION *parent, char const **ptr_p, fr_token_t *token, char *buffer, size_t buflen,
821  char const *filename, int lineno)
822 {
823  char const *ptr = *ptr_p;
824  ssize_t slen;
825  char const *out;
826  size_t outlen;
827 
828  /*
829  * Discover the string content, returning what kind of
830  * string it is.
831  *
832  * Don't allow casts or regexes. But do allow bare
833  * %{...} expansions.
834  */
835  slen = tmpl_preparse(&out, &outlen, ptr, strlen(ptr), token, NULL, false, true);
836  if (slen <= 0) {
837  char *spaces, *text;
838 
839  fr_canonicalize_error(parent, &spaces, &text, slen, ptr);
840 
841  ERROR("%s[%d]: %s", filename, lineno, text);
842  ERROR("%s[%d]: %s^ - %s", filename, lineno, spaces, fr_strerror());
843 
845  talloc_free(text);
846  return -1;
847  }
848 
849  if ((size_t) slen >= buflen) {
850  ERROR("%s[%d]: Name is too long", filename, lineno);
851  return -1;
852  }
853 
854  /*
855  * Unescape it or copy it verbatim as necessary.
856  */
857  if (!cf_expand_variables(filename, lineno, parent, buffer, buflen,
858  out, outlen, NULL)) {
859  return -1;
860  }
861 
862  ptr += slen;
863  fr_skip_whitespace(ptr);
864 
865  *ptr_p = ptr;
866  return 0;
867 }
868 
869 typedef struct cf_file_heap_t {
870  char const *filename;
873 
874 static int8_t filename_cmp(void const *one, void const *two)
875 {
876  int ret;
877  cf_file_heap_t const *a = one;
878  cf_file_heap_t const *b = two;
879 
880  ret = strcmp(a->filename, b->filename);
881  return CMP(ret, 0);
882 }
883 
884 
885 static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *ptr, bool required, bool relative)
886 {
887  char const *value;
888  cf_stack_frame_t *frame = &stack->frame[stack->depth];
889 
890  /*
891  * Can't do this inside of update / map.
892  */
893  if (frame->special) {
894  ERROR("%s[%d]: Parse error: Invalid location for $INCLUDE",
895  frame->filename, frame->lineno);
896  return -1;
897  }
898 
899  fr_skip_whitespace(ptr);
900 
901  /*
902  * Grab all of the non-whitespace text.
903  */
904  value = ptr;
905  while (*ptr && !isspace((uint8_t) *ptr)) ptr++;
906 
907  /*
908  * We're OK with whitespace after the filename.
909  */
910  fr_skip_whitespace(ptr);
911 
912  /*
913  * But anything else after the filename is wrong.
914  */
915  if (*ptr) {
916  ERROR("%s[%d]: Unexpected text after $INCLUDE", frame->filename, frame->lineno);
917  return -1;
918  }
919 
920  /*
921  * Hack for ${confdir}/foo
922  */
923  if (*value == '$') relative = false;
924 
925  value = cf_expand_variables(frame->filename, frame->lineno, parent, stack->buff[1], stack->bufsize,
926  value, ptr - value, NULL);
927  if (!value) return -1;
928 
929  if (!FR_DIR_IS_RELATIVE(value)) relative = false;
930 
931  if (relative) {
932  value = cf_local_file(frame->filename, value, stack->buff[2], stack->bufsize);
933  if (!value) {
934  ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
935  return -1;
936  }
937  }
938 
939  if (strchr(value, '*') != 0) {
940 #ifndef HAVE_GLOB_H
941  ERROR("%s[%d]: Filename globbing is not supported.", frame->filename, frame->lineno);
942  return -1;
943 #else
944  stack->depth++;
945  frame = &stack->frame[stack->depth];
946  memset(frame, 0, sizeof(*frame));
947 
948  frame->type = CF_STACK_GLOB;
949  frame->required = required;
950  frame->parent = parent;
951  frame->current = parent;
952  frame->special = NULL;
953 
954  /*
955  * For better debugging.
956  */
957  frame->filename = frame[-1].filename;
958  frame->lineno = frame[-1].lineno;
959 
960  if (glob(value, GLOB_ERR | GLOB_NOESCAPE, NULL, &frame->glob) < 0) {
961  stack->depth--;
962  ERROR("%s[%d]: Failed expanding '%s' - %s", frame->filename, frame->lineno,
963  value, fr_syserror(errno));
964  return -1;
965  }
966 
967  /*
968  * If nothing matches, that may be an error.
969  */
970  if (frame->glob.gl_pathc == 0) {
971  if (!required) {
972  stack->depth--;
973  return 0;
974  }
975 
976  ERROR("%s[%d]: Failed expanding '%s' - No matching files", frame->filename, frame->lineno,
977  value);
978  return -1;
979  }
980 
981  return 1;
982 #endif
983  }
984 
985  /*
986  * Allow $-INCLUDE for directories, too.
987  */
988  if (!required) {
989  struct stat statbuf;
990 
991  if (stat(value, &statbuf) < 0) {
992  WARN("Not including file %s: %s", value, fr_syserror(errno));
993  return 0;
994  }
995  }
996 
997  /*
998  * The filename doesn't end in '/', so it must be a file.
999  */
1000  if (value[strlen(value) - 1] != '/') {
1001  if ((stack->depth + 1) >= MAX_STACK) {
1002  ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
1003  return -1;
1004  }
1005 
1006  stack->depth++;
1007  frame = &stack->frame[stack->depth];
1008  memset(frame, 0, sizeof(*frame));
1009 
1010  frame->type = CF_STACK_FILE;
1011  frame->fp = NULL;
1012  frame->parent = parent;
1013  frame->current = parent;
1014  frame->filename = talloc_strdup(frame->parent, value);
1015  frame->special = NULL;
1016  return 1;
1017  }
1018 
1019 #ifdef HAVE_DIRENT_H
1020  /*
1021  * $INCLUDE foo/
1022  *
1023  * Include ALL non-"dot" files in the directory.
1024  * careful!
1025  */
1026  {
1027  char *directory;
1028  DIR *dir;
1029  struct dirent *dp;
1030  struct stat stat_buf;
1031  cf_file_heap_t *h;
1032 
1033  /*
1034  * We need to keep a copy of parent while the
1035  * included files mangle our buff[] array.
1036  */
1037  directory = talloc_strdup(parent, value);
1038 
1039  cf_log_debug(parent, "Including files in directory \"%s\"", directory);
1040 
1041  dir = opendir(directory);
1042  if (!dir) {
1043  ERROR("%s[%d]: Error reading directory %s: %s",
1044  frame->filename, frame->lineno, value,
1045  fr_syserror(errno));
1046  error:
1047  talloc_free(directory);
1048  return -1;
1049  }
1050 #ifdef S_IWOTH
1051  /*
1052  * Security checks.
1053  */
1054  if (fstat(dirfd(dir), &stat_buf) < 0) {
1055  ERROR("%s[%d]: Failed reading directory %s: %s", frame->filename, frame->lineno,
1056  directory, fr_syserror(errno));
1057  goto error;
1058  }
1059 
1060  if ((stat_buf.st_mode & S_IWOTH) != 0) {
1061  ERROR("%s[%d]: Directory %s is globally writable. Refusing to start due to "
1062  "insecure configuration", frame->filename, frame->lineno, directory);
1063  goto error;
1064  }
1065 #endif
1066 
1067  /*
1068  * Directory plus next filename.
1069  */
1070  if ((stack->depth + 2) >= MAX_STACK) {
1071  ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
1072  goto error;
1073  }
1074 
1075  stack->depth++;
1076  frame = &stack->frame[stack->depth];
1077  *frame = (cf_stack_frame_t){
1078  .type = CF_STACK_DIR,
1079  .directory = directory,
1080  .parent = parent,
1081  .current = parent,
1082  .from_dir = true
1083  };
1084 
1085  MEM(frame->heap = fr_heap_alloc(frame->directory, filename_cmp, cf_file_heap_t, heap_id, 0));
1086 
1087  /*
1088  * Read the whole directory before loading any
1089  * individual file. We stat() files to ensure
1090  * that they're readable. We ignore
1091  * subdirectories and files with odd filenames.
1092  */
1093  while ((dp = readdir(dir)) != NULL) {
1094  char const *p;
1095 
1096  if (dp->d_name[0] == '.') continue;
1097 
1098  /*
1099  * Check for valid characters
1100  */
1101  for (p = dp->d_name; *p != '\0'; p++) {
1102  if (isalpha((uint8_t)*p) ||
1103  isdigit((uint8_t)*p) ||
1104  (*p == '-') ||
1105  (*p == '_') ||
1106  (*p == '.')) continue;
1107  break;
1108  }
1109  if (*p != '\0') continue;
1110 
1111  snprintf(stack->buff[1], stack->bufsize, "%s%s",
1112  frame->directory, dp->d_name);
1113 
1114  if (stat(stack->buff[1], &stat_buf) != 0) {
1115  ERROR("%s[%d]: Failed checking file %s: %s",
1116  (frame - 1)->filename, (frame - 1)->lineno,
1117  stack->buff[1], fr_syserror(errno));
1118  continue;
1119  }
1120 
1121  if (S_ISDIR(stat_buf.st_mode)) {
1122  WARN("%s[%d]: Ignoring directory %s",
1123  (frame - 1)->filename, (frame - 1)->lineno,
1124  stack->buff[1]);
1125  continue;
1126  }
1127 
1128  MEM(h = talloc_zero(frame->heap, cf_file_heap_t));
1129  MEM(h->filename = talloc_typed_strdup(h, stack->buff[1]));
1130  h->heap_id = FR_HEAP_INDEX_INVALID;
1131  (void) fr_heap_insert(&frame->heap, h);
1132  }
1133  closedir(dir);
1134 
1135  /*
1136  * No "$INCLUDE dir/" inside of update / map. That's dumb.
1137  */
1138  frame->special = NULL;
1139  return 1;
1140  }
1141 #else
1142  ERROR("%s[%d]: Error including %s: No support for directories!",
1143  frame->filename, frame->lineno, value);
1144  return -1;
1145 #endif
1146 }
1147 
1148 
1150 {
1151  CONF_ITEM *ci;
1152  CONF_SECTION *parent_cs, *templatecs;
1153  fr_token_t token;
1154  cf_stack_frame_t *frame = &stack->frame[stack->depth];
1155  CONF_SECTION *parent = frame->current;
1156 
1157  token = getword(&stack->ptr, stack->buff[2], stack->bufsize, true);
1158  if (token != T_EOL) {
1159  ERROR("%s[%d]: Unexpected text after $TEMPLATE", frame->filename, frame->lineno);
1160  return -1;
1161  }
1162 
1163  if (!parent) {
1164  ERROR("%s[%d]: Internal sanity check error in template reference", frame->filename, frame->lineno);
1165  return -1;
1166  }
1167 
1168  if (parent->template) {
1169  ERROR("%s[%d]: Section already has a template", frame->filename, frame->lineno);
1170  return -1;
1171  }
1172 
1173  /*
1174  * Allow in-line templates.
1175  */
1176  templatecs = cf_section_find(cf_item_to_section(cf_parent(parent)), "template", stack->buff[2]);
1177  if (templatecs) {
1178  parent->template = templatecs;
1179  return 0;
1180  }
1181 
1182  parent_cs = cf_root(parent);
1183 
1184  templatecs = cf_section_find(parent_cs, "templates", NULL);
1185  if (!templatecs) {
1186  ERROR("%s[%d]: Cannot find template \"%s\", as no 'templates' section exists.",
1187  frame->filename, frame->lineno, stack->buff[2]);
1188  return -1;
1189  }
1190 
1191  ci = cf_reference_item(parent_cs, templatecs, stack->buff[2]);
1192  if (!ci || (ci->type != CONF_ITEM_SECTION)) {
1193  ERROR("%s[%d]: No such template \"%s\" in the 'templates' section.",
1194  frame->filename, frame->lineno, stack->buff[2]);
1195  return -1;
1196  }
1197 
1198  parent->template = cf_item_to_section(ci);
1199  return 0;
1200 }
1201 
1202 
1203 static int cf_file_fill(cf_stack_t *stack);
1204 
1205 
1206 /** Skip an xlat expression.
1207  *
1208  * This is a simple "peek ahead" parser which tries to not be wrong. It may accept
1209  * some things which will later parse as invalid (e.g. unknown attributes, etc.)
1210  * But it also rejects all malformed expressions.
1211  *
1212  * It's used as a quick hack because the full parser isn't always available.
1213  *
1214  * @param[in] start start of the expression, MUST point to the "%{" or "%("
1215  * @param[in] end end of the string (or NULL for zero-terminated strings)
1216  * @return
1217  * >0 length of the string which was parsed
1218  * <=0 on error
1219  */
1220 static ssize_t fr_skip_xlat(char const *start, char const *end)
1221 {
1222  int depth = 1; /* caller skips '{' */
1223  ssize_t slen;
1224  char quote, end_quote;
1225  char const *p = start;
1226 
1227  /*
1228  * At least %{1}
1229  */
1230  if (end && ((start + 4) > end)) {
1231  fr_strerror_const("Invalid expansion");
1232  return 0;
1233  }
1234 
1235  if ((*p != '%') && (*p != '$')) {
1236  fr_strerror_const("Unexpected character in expansion");
1237  return -(p - start);
1238  }
1239 
1240  p++;
1241  if ((*p != '{') && (*p != '(')) {
1242  char const *q = p;
1243 
1244  /*
1245  * New xlat syntax: %foo(...)
1246  */
1247  while (isalnum((int) *q) || (*q == '.') || (*q == '_') || (*q == '-')) {
1248  q++;
1249  }
1250  if (*q == '(') {
1251  p = q;
1252  goto do_quote;
1253  }
1254 
1255  fr_strerror_const("Invalid character after '%'");
1256  return -(p - start);
1257  }
1258 
1259 do_quote:
1260  quote = *(p++);
1261  if (quote == '{') {
1262  end_quote = '}';
1263  } else {
1264  end_quote = ')';
1265  }
1266 
1267  while ((end && (p < end)) || (*p >= ' ')) {
1268  if (*p == quote) {
1269  p++;
1270  depth++;
1271  continue;
1272  }
1273 
1274  if (*p == end_quote) {
1275  p++;
1276  depth--;
1277  if (!depth) return p - start;
1278 
1279  continue;
1280  }
1281 
1282  /*
1283  * Nested expansion.
1284  */
1285  if ((p[0] == '$') || (p[0] == '%')) {
1286  if (end && (p + 2) >= end) break;
1287 
1288  if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
1289  slen = fr_skip_xlat(p, end);
1290 
1291  check:
1292  if (slen <= 0) return -(p - start) + slen;
1293 
1294  p += slen;
1295  continue;
1296  }
1297 
1298  /*
1299  * Bare $ or %, just leave it alone.
1300  */
1301  p++;
1302  continue;
1303  }
1304 
1305  /*
1306  * A quoted string.
1307  */
1308  if ((*p == '"') || (*p == '\'') || (*p == '`')) {
1309  slen = fr_skip_string(p, end);
1310  goto check;
1311  }
1312 
1313  /*
1314  * @todo - bare '(' is a condition or nested
1315  * expression. The brackets need to balance
1316  * here, too.
1317  */
1318 
1319  if (*p != '\\') {
1320  p++;
1321  continue;
1322  }
1323 
1324  if (end && ((p + 2) >= end)) break;
1325 
1326  /*
1327  * Escapes here are only one-character escapes.
1328  */
1329  if (p[1] < ' ') break;
1330  p += 2;
1331  }
1332 
1333  /*
1334  * Unexpected end of xlat
1335  */
1336  fr_strerror_const("Unexpected end of expansion");
1337  return -(p - start);
1338 }
1339 
1340 static const bool terminal_end_section[UINT8_MAX + 1] = {
1341  ['{'] = true,
1342 };
1343 
1344 static const bool terminal_end_line[UINT8_MAX + 1] = {
1345  [0] = true,
1346 
1347  ['\r'] = true,
1348  ['\n'] = true,
1349 
1350  ['#'] = true,
1351  [','] = true,
1352  [';'] = true,
1353  ['}'] = true,
1354 };
1355 
1356 /** Skip a conditional expression.
1357  *
1358  * This is a simple "peek ahead" parser which tries to not be wrong. It may accept
1359  * some things which will later parse as invalid (e.g. unknown attributes, etc.)
1360  * But it also rejects all malformed expressions.
1361  *
1362  * It's used as a quick hack because the full parser isn't always available.
1363  *
1364  * @param[in] start start of the condition.
1365  * @param[in] end end of the string (or NULL for zero-terminated strings)
1366  * @param[in] terminal terminal character(s)
1367  * @param[out] eol did the parse error happen at eol?
1368  * @return
1369  * >0 length of the string which was parsed. *eol is false.
1370  * <=0 on error, *eol may be set.
1371  */
1372 static ssize_t fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX + 1], bool *eol)
1373 {
1374  char const *p = start;
1375  bool was_regex = false;
1376  int depth = 0;
1377  ssize_t slen;
1378 
1379  if (eol) *eol = false;
1380 
1381  /*
1382  * Keep parsing the condition until we hit EOS or EOL.
1383  */
1384  while ((end && (p < end)) || *p) {
1385  if (isspace((uint8_t) *p)) {
1386  p++;
1387  continue;
1388  }
1389 
1390  /*
1391  * In the configuration files, conditions end with ") {" or just "{"
1392  */
1393  if ((depth == 0) && terminal && terminal[(uint8_t) *p]) {
1394  return p - start;
1395  }
1396 
1397  /*
1398  * "recurse" to get more conditions.
1399  */
1400  if (*p == '(') {
1401  p++;
1402  depth++;
1403  was_regex = false;
1404  continue;
1405  }
1406 
1407  if (*p == ')') {
1408  if (!depth) {
1409  fr_strerror_const("Too many ')'");
1410  return -(p - start);
1411  }
1412 
1413  p++;
1414  depth--;
1415  was_regex = false;
1416  continue;
1417  }
1418 
1419  /*
1420  * Parse xlats. They cannot span EOL.
1421  */
1422  if ((*p == '$') || (*p == '%')) {
1423  if (end && ((p + 2) >= end)) {
1424  fr_strerror_const("Expansions cannot extend across end of line");
1425  return -(p - start);
1426  }
1427 
1428  if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
1429  slen = fr_skip_xlat(p, end);
1430 
1431  check:
1432  if (slen <= 0) return -(p - start) + slen;
1433 
1434  p += slen;
1435  continue;
1436  }
1437 
1438  /*
1439  * Bare $ or %, just leave it alone.
1440  */
1441  p++;
1442  was_regex = false;
1443  continue;
1444  }
1445 
1446  /*
1447  * Parse quoted strings. They cannot span EOL.
1448  */
1449  if ((*p == '"') || (*p == '\'') || (*p == '`') || (was_regex && (*p == '/'))) {
1450  was_regex = false;
1451 
1452  slen = fr_skip_string((char const *) p, end);
1453  goto check;
1454  }
1455 
1456  /*
1457  * 192.168/16 is a netmask. So we only
1458  * allow regex after a regex operator.
1459  *
1460  * This isn't perfect, but is good enough
1461  * for most purposes.
1462  */
1463  if ((p[0] == '=') || (p[0] == '!')) {
1464  if (end && ((p + 2) >= end)) {
1465  fr_strerror_const("Operators cannot extend across end of line");
1466  return -(p - start);
1467  }
1468 
1469  if (p[1] == '~') {
1470  was_regex = true;
1471  p += 2;
1472  continue;
1473  }
1474 
1475  /*
1476  * Some other '==' or '!=', just leave it alone.
1477  */
1478  p++;
1479  was_regex = false;
1480  continue;
1481  }
1482 
1483  /*
1484  * Any control characters (other than \t) cause an error.
1485  */
1486  if (*p < ' ') break;
1487 
1488  was_regex = false;
1489 
1490  /*
1491  * Normal characters just get skipped.
1492  */
1493  if (*p != '\\') {
1494  p++;
1495  continue;
1496  }
1497 
1498  /*
1499  * Backslashes at EOL are ignored.
1500  */
1501  if (end && ((p + 2) >= end)) break;
1502 
1503  /*
1504  * Escapes here are only one-character escapes.
1505  */
1506  if (p[1] < ' ') break;
1507  p += 2;
1508  }
1509 
1510  /*
1511  * We've fallen off of the end of a string. It may be OK?
1512  */
1513  if (eol) *eol = (depth > 0);
1514 
1515  if (terminal && terminal[(uint8_t) *p]) return p - start;
1516 
1517  fr_strerror_const("Unexpected end of condition");
1518  return -(p - start);
1519 }
1520 
1522 {
1523  ssize_t slen = 0;
1524  fr_dict_t const *dict = NULL;
1525  CONF_SECTION *cs;
1526  uint8_t const *p;
1527  char const *ptr = stack->ptr;
1528  cf_stack_frame_t *frame = &stack->frame[stack->depth];
1529  CONF_SECTION *parent = frame->current;
1530  char *buff[4];
1531  tmpl_rules_t t_rules;
1532 
1533  /*
1534  * Short names are nicer.
1535  */
1536  buff[1] = stack->buff[1];
1537  buff[2] = stack->buff[2];
1538  buff[3] = stack->buff[3];
1539 
1541 
1542  t_rules = (tmpl_rules_t) {
1543  .attr = {
1544  .dict_def = dict,
1545  .list_def = request_attr_request,
1546  .allow_unresolved = true,
1547  .allow_unknown = true
1548  }
1549  };
1550 
1551  /*
1552  * Create the CONF_SECTION. We don't pass a name2, as it
1553  * hasn't yet been parsed.
1554  */
1555  cs = cf_section_alloc(parent, parent, buff[1], NULL);
1556  if (!cs) {
1557  cf_log_err(parent, "Failed allocating memory for section");
1558  return NULL;
1559  }
1560  cf_filename_set(cs, frame->filename);
1561  cf_lineno_set(cs, frame->lineno);
1562 
1563  RULES_VERIFY(cs, &t_rules);
1564 
1565  /*
1566  * Keep "parsing" the condition until we hit EOL.
1567  *
1568  *
1569  */
1570  while (true) {
1571  int rcode;
1572  bool eol;
1573 
1574  /*
1575  * Try to parse the condition. We can have a parse success, or a parse failure.
1576  */
1577  slen = fr_skip_condition(ptr, NULL, terminal_end_section, &eol);
1578 
1579  /*
1580  * Parse success means we stop reading more data.
1581  */
1582  if (slen > 0) break;
1583 
1584  /*
1585  * Parse failures not at EOL are real errors.
1586  */
1587  if (!eol) {
1588  slen = 0;
1589  fr_strerror_const("Unexpected EOF");
1590  error:
1591  cf_canonicalize_error(cs, slen, "Parse error in condition", ptr);
1592  talloc_free(cs);
1593  return NULL;
1594  }
1595 
1596  /*
1597  * Parse failures at EOL means that we read more data.
1598  */
1599  p = (uint8_t const *) ptr + (-slen);
1600 
1601  /*
1602  * Auto-continue across CR LF until we reach the
1603  * end of the string. We mash everything into one line.
1604  */
1605  if (*p && (*p < ' ')) {
1606  while ((*p == '\r') || (*p == '\n')) {
1607  char *q;
1608 
1609  q = UNCONST(char *, p);
1610  *q = ' ';
1611  p++;
1612  continue;
1613  }
1614 
1615  /*
1616  * Hopefully the next line is already in
1617  * the buffer, and we don't have to read
1618  * more data.
1619  */
1620  continue;
1621  }
1622 
1623  /*
1624  * Anything other than EOL is a problem at this point.
1625  */
1626  if (*p) {
1627  fr_strerror_const("Unexpected text");
1628  goto error;
1629  }
1630 
1631  /*
1632  * We hit EOL, so the parse error is really "read more data".
1633  */
1634  stack->fill = UNCONST(char *, p);
1635  rcode = cf_file_fill(stack);
1636  if (rcode < 0) {
1637  cf_log_err(cs, "Failed parsing condition");
1638  return NULL;
1639  }
1640  }
1641 
1642  fr_assert((size_t) slen < (stack->bufsize - 1));
1643 
1644  /*
1645  * Save the parsed condition (minus trailing whitespace)
1646  * into a buffer.
1647  */
1648  memcpy(buff[2], stack->ptr, slen);
1649  buff[2][slen] = '\0';
1650 
1651  while (slen > 0) {
1652  if (!isspace((uint8_t) buff[2][slen])) break;
1653 
1654  buff[2][slen] = '\0';
1655  slen--;
1656  }
1657 
1658  /*
1659  * Expand the variables in the pre-parsed condition.
1660  */
1661  if (!cf_expand_variables(frame->filename, frame->lineno, parent,
1662  buff[3], stack->bufsize, buff[2], slen, NULL)) {
1663  fr_strerror_const("Failed expanding configuration variable");
1664  return NULL;
1665  }
1666 
1667  MEM(cs->name2 = talloc_typed_strdup(cs, buff[3]));
1668  cs->name2_quote = T_BARE_WORD;
1669 
1670  ptr += slen;
1671  fr_skip_whitespace(ptr);
1672 
1673  if (*ptr != '{') {
1674  cf_log_err(cs, "Expected '{' instead of %s", ptr);
1675  talloc_free(cs);
1676  return NULL;
1677  }
1678  ptr++;
1679 
1680  stack->ptr = ptr;
1681 
1682  cs->allow_unlang = cs->allow_locals = true;
1683  return cf_section_to_item(cs);
1684 }
1685 
1687 {
1688  char const *mod;
1689  char const *value = NULL;
1690  CONF_SECTION *css;
1691  fr_token_t token;
1692  char const *ptr = stack->ptr;
1693  cf_stack_frame_t *frame = &stack->frame[stack->depth];
1694  CONF_SECTION *parent = frame->current;
1695  char *buff[4];
1696 
1697  /*
1698  * Short names are nicer.
1699  */
1700  buff[1] = stack->buff[1];
1701  buff[2] = stack->buff[2];
1702 
1703  if (cf_get_token(parent, &ptr, &token, buff[1], stack->bufsize,
1704  frame->filename, frame->lineno) < 0) {
1705  return NULL;
1706  }
1707 
1708  if (token != T_BARE_WORD) {
1709  ERROR("%s[%d]: Invalid syntax for 'map' - module name must not be a quoted string",
1710  frame->filename, frame->lineno);
1711  return NULL;
1712  }
1713  mod = buff[1];
1714 
1715  /*
1716  * Maps without an expansion string are allowed, though
1717  * it's not clear why.
1718  */
1719  if (*ptr == '{') {
1720  ptr++;
1721  goto alloc_section;
1722  }
1723 
1724  /*
1725  * Now get the expansion string.
1726  */
1727  if (cf_get_token(parent, &ptr, &token, buff[2], stack->bufsize,
1728  frame->filename, frame->lineno) < 0) {
1729  return NULL;
1730  }
1731  if (!fr_str_tok[token]) {
1732  ERROR("%s[%d]: Expecting string expansions in 'map' definition",
1733  frame->filename, frame->lineno);
1734  return NULL;
1735  }
1736 
1737  if (*ptr != '{') {
1738  ERROR("%s[%d]: Expecting section start brace '{' in 'map' definition",
1739  frame->filename, frame->lineno);
1740  return NULL;
1741  }
1742  ptr++;
1743  value = buff[2];
1744 
1745  /*
1746  * Allocate the section
1747  */
1748 alloc_section:
1749  css = cf_section_alloc(parent, parent, "map", mod);
1750  if (!css) {
1751  ERROR("%s[%d]: Failed allocating memory for section",
1752  frame->filename, frame->lineno);
1753  return NULL;
1754  }
1755  cf_filename_set(css, frame->filename);
1756  cf_lineno_set(css, frame->lineno);
1757  css->name2_quote = T_BARE_WORD;
1758 
1759  css->argc = 0;
1760  if (value) {
1761  css->argv = talloc_array(css, char const *, 1);
1762  css->argv[0] = talloc_typed_strdup(css->argv, value);
1763  css->argv_quote = talloc_array(css, fr_token_t, 1);
1764  css->argv_quote[0] = token;
1765  css->argc++;
1766  }
1767  stack->ptr = ptr;
1768  frame->special = css;
1769 
1770  return cf_section_to_item(css);
1771 }
1772 
1773 
1775 {
1776  char const *mod = NULL;
1777  CONF_SECTION *css;
1778  fr_token_t token;
1779  char const *ptr = stack->ptr;
1780  cf_stack_frame_t *frame = &stack->frame[stack->depth];
1781  CONF_SECTION *parent = frame->current;
1782  char *buff[4];
1783  int values = 0;
1784 
1785  /*
1786  * Short names are nicer.
1787  */
1788  buff[1] = stack->buff[1];
1789  buff[2] = stack->buff[2];
1790  buff[3] = stack->buff[3];
1791 
1792  /*
1793  * subrequest { ... } is allowed.
1794  */
1795  fr_skip_whitespace(ptr);
1796  if (*ptr == '{') {
1797  ptr++;
1798  goto alloc_section;
1799  }
1800 
1801  /*
1802  * Get the name of the Packet-Type.
1803  */
1804  if (cf_get_token(parent, &ptr, &token, buff[1], stack->bufsize,
1805  frame->filename, frame->lineno) < 0) {
1806  return NULL;
1807  }
1808 
1809  if (token != T_BARE_WORD) {
1810  ERROR("%s[%d]: The first argument to 'subrequest' must be a name or an attribute reference",
1811  frame->filename, frame->lineno);
1812  return NULL;
1813  }
1814  mod = buff[1];
1815 
1816  /*
1817  * subrequest Access-Request { ... } is allowed.
1818  */
1819  if (*ptr == '{') {
1820  ptr++;
1821  goto alloc_section;
1822  }
1823 
1824  /*
1825  * subrequest Access-Request &foo { ... }
1826  */
1827  if (cf_get_token(parent, &ptr, &token, buff[2], stack->bufsize,
1828  frame->filename, frame->lineno) < 0) {
1829  return NULL;
1830  }
1831 
1832  if (token != T_BARE_WORD) {
1833  ERROR("%s[%d]: The second argument to 'subrequest' must be an attribute reference",
1834  frame->filename, frame->lineno);
1835  return NULL;
1836  }
1837  values++;
1838 
1839  if (*ptr == '{') {
1840  ptr++;
1841  goto alloc_section;
1842  }
1843 
1844  /*
1845  * subrequest Access-Request &foo &bar { ... }
1846  */
1847  if (cf_get_token(parent, &ptr, &token, buff[3], stack->bufsize,
1848  frame->filename, frame->lineno) < 0) {
1849  return NULL;
1850  }
1851 
1852  if (token != T_BARE_WORD) {
1853  ERROR("%s[%d]: The third argument to 'subrequest' must be an attribute reference",
1854  frame->filename, frame->lineno);
1855  return NULL;
1856  }
1857  values++;
1858 
1859  if (*ptr != '{') {
1860  ERROR("%s[%d]: Expecting section start brace '{' in 'subrequest' definition",
1861  frame->filename, frame->lineno);
1862  return NULL;
1863  }
1864  ptr++;
1865 
1866  /*
1867  * Allocate the section
1868  */
1869 alloc_section:
1870  css = cf_section_alloc(parent, parent, "subrequest", mod);
1871  if (!css) {
1872  ERROR("%s[%d]: Failed allocating memory for section",
1873  frame->filename, frame->lineno);
1874  return NULL;
1875  }
1876  cf_filename_set(css, frame->filename);
1877  cf_lineno_set(css, frame->lineno);
1878  if (mod) css->name2_quote = T_BARE_WORD;
1879 
1880  css->argc = values;
1881  if (values) {
1882  int i;
1883 
1884  css->argv = talloc_array(css, char const *, values);
1885  css->argv_quote = talloc_array(css, fr_token_t, values);
1886 
1887  for (i = 0; i < values; i++) {
1888  css->argv[i] = talloc_typed_strdup(css->argv, buff[2 + i]);
1889  css->argv_quote[i] = T_BARE_WORD;
1890  }
1891  }
1892 
1893  stack->ptr = ptr;
1894  frame->special = css;
1895 
1896  css->allow_unlang = css->allow_locals = true;
1897  return cf_section_to_item(css);
1898 }
1899 
1901 {
1902  CONF_SECTION *css;
1903  int argc = 0;
1904  char const *ptr = stack->ptr;
1905  cf_stack_frame_t *frame = &stack->frame[stack->depth];
1906  CONF_SECTION *parent = frame->current;
1907  char *name2 = NULL;
1908  char *argv[RLM_MODULE_NUMCODES];
1909 
1910  while (true) {
1911  char const *p;
1912  size_t len;
1913 
1914  fr_skip_whitespace(ptr);
1915 
1916  /*
1917  * We have an open bracket, it's the end of the "catch" statement.
1918  */
1919  if (*ptr == '{') {
1920  ptr++;
1921  break;
1922  }
1923 
1924  /*
1925  * The arguments have to be short, unquoted words.
1926  */
1927  p = ptr;
1928  while (isalpha((uint8_t) *ptr)) ptr++;
1929 
1930  len = ptr - p;
1931  if (len > 16) {
1932  ERROR("%s[%d]: Invalid syntax for 'catch' - unknown rcode '%s'",
1933  frame->filename, frame->lineno, p);
1934  return NULL;
1935  }
1936 
1937  if ((*ptr != '{') && !isspace((uint8_t) *ptr)) {
1938  ERROR("%s[%d]: Invalid syntax for 'catch' - unexpected text at '%s'",
1939  frame->filename, frame->lineno, ptr);
1940  return NULL;
1941  }
1942 
1943  if (!name2) {
1944  name2 = talloc_strndup(NULL, p, len);
1945  continue;
1946  }
1947 
1948  if (argc > RLM_MODULE_NUMCODES) {
1949  ERROR("%s[%d]: Invalid syntax for 'catch' - too many arguments at'%s'",
1950  frame->filename, frame->lineno, ptr);
1951  return NULL;
1952  }
1953 
1954  argv[argc++] = talloc_strndup(name2, p, len);
1955  }
1956 
1957  css = cf_section_alloc(parent, parent, "catch", name2);
1958  if (!css) {
1959  talloc_free(name2);
1960  ERROR("%s[%d]: Failed allocating memory for section",
1961  frame->filename, frame->lineno);
1962  return NULL;
1963  }
1964  cf_filename_set(css, frame->filename);
1965  cf_lineno_set(css, frame->lineno);
1966  css->name2_quote = T_BARE_WORD;
1967  css->allow_unlang = 1;
1968 
1969  css->argc = argc;
1970  if (argc) {
1971  int i;
1972 
1973  css->argv = talloc_array(css, char const *, argc + 1);
1974  css->argv_quote = talloc_array(css, fr_token_t, argc);
1975  css->argc = argc;
1976 
1977  for (i = 0; i < argc; i++) {
1978  css->argv[i] = talloc_typed_strdup(css->argv, argv[i]);
1979  css->argv_quote[i] = T_BARE_WORD;
1980  }
1981 
1982  css->argv[argc] = NULL;
1983  }
1984  talloc_free(name2);
1985 
1986  stack->ptr = ptr;
1987  frame->special = css;
1988 
1989  return cf_section_to_item(css);
1990 }
1991 
1992 static int add_section_pair(CONF_SECTION **parent, char const **attr, char const *dot, char *buffer, size_t buffer_len, char const *filename, int lineno)
1993 {
1994  CONF_SECTION *cs;
1995  char const *name1 = *attr;
1996  char *name2 = NULL;
1997  char const *next;
1998  char *p;
1999 
2000  if (!dot[1] || (dot[1] == '.')) {
2001  ERROR("%s[%d]: Invalid name", filename, lineno);
2002  return -1;
2003  }
2004 
2005  if ((size_t) (dot - name1) >= buffer_len) {
2006  ERROR("%s[%d]: Name too long", filename, lineno);
2007  return -1;
2008  }
2009 
2010  memcpy(buffer, name1, dot - name1);
2011  buffer[dot - name1] = '\0';
2012  next = dot + 1;
2013 
2014  /*
2015  * Look for name1[name2]
2016  */
2017  p = strchr(buffer, '[');
2018  if (p) {
2019  name2 = p;
2020 
2021  p = strchr(p, ']');
2022  if (!p || ((p[1] != '\0') && (p[1] != '.'))) {
2023  cf_log_err(*parent, "Could not parse name2 in '%s', expected 'name1[name2]", name1);
2024  return -1;
2025  }
2026 
2027  *p = '\0';
2028  *(name2++) = '\0';
2029  }
2030 
2031  /*
2032  * Reference a subsection which already exists. If not,
2033  * create it.
2034  */
2035  cs = cf_section_find(*parent, buffer, name2);
2036  if (!cs) {
2037  cs = cf_section_alloc(*parent, *parent, buffer, NULL);
2038  if (!cs) {
2039  cf_log_err(*parent, "Failed allocating memory for section");
2040  return -1;
2041  }
2042  cf_filename_set(cs, filename);
2043  cf_lineno_set(cs, lineno);
2044  }
2045 
2046  *parent = cs;
2047  *attr = next;
2048 
2049  p = strchr(next + 1, '.');
2050  if (!p) return 0;
2051 
2052  return add_section_pair(parent, attr, p, buffer, buffer_len, filename, lineno);
2053 }
2054 
2055 static int add_pair(CONF_SECTION *parent, char const *attr, char const *value,
2056  fr_token_t name1_token, fr_token_t op_token, fr_token_t value_token,
2057  char *buff, char const *filename, int lineno)
2058 {
2059  CONF_DATA const *cd;
2060  conf_parser_t *rule;
2061  CONF_PAIR *cp;
2062  bool pass2 = false;
2063 
2064  /*
2065  * For laziness, allow specifying paths for CONF_PAIRs
2066  *
2067  * section.subsection.pair = value
2068  *
2069  * Note that we do this ONLY for CONF_PAIRs which have
2070  * values, so that we don't pick up module references /
2071  * methods. And we don't do this for things which begin
2072  * with '&' (or %), so we don't pick up attribute
2073  * references.
2074  */
2075  if ((*attr >= 'A') && (name1_token == T_BARE_WORD) && value && !parent->attr) {
2076  char const *p = strchr(attr, '.');
2077 
2078  if (p && (add_section_pair(&parent, &attr, p, buff, talloc_array_length(buff), filename, lineno) < 0)) {
2079  return -1;
2080  }
2081  }
2082 
2083  /*
2084  * If we have the value, expand any configuration
2085  * variables in it.
2086  */
2087  if (value && *value) {
2088  bool soft_fail;
2089  char const *expanded;
2090 
2091  expanded = cf_expand_variables(filename, lineno, parent, buff, talloc_array_length(buff), value, -1, &soft_fail);
2092  if (expanded) {
2093  value = expanded;
2094 
2095  } else if (!soft_fail) {
2096  return -1;
2097 
2098  } else {
2099  /*
2100  * References an item which doesn't exist,
2101  * or which is already marked up as being
2102  * expanded in pass2. Wait for pass2 to
2103  * do the expansions.
2104  *
2105  * Leave the input value alone.
2106  */
2107  pass2 = true;
2108  }
2109  }
2110 
2111  cp = cf_pair_alloc(parent, attr, value, op_token, name1_token, value_token);
2112  if (!cp) return -1;
2113  cf_filename_set(cp, filename);
2114  cf_lineno_set(cp, lineno);
2115  cp->pass2 = pass2;
2116 
2118  if (!cd) return 0;
2119 
2120  rule = cf_data_value(cd);
2121  if (!rule->on_read) return 0;
2122 
2123  /*
2124  * Do the on_read callback after adding the value.
2125  */
2126  return rule->on_read(parent, NULL, NULL, cf_pair_to_item(cp), rule);
2127 }
2128 
2130  { L("catch"), (void *) process_catch },
2131  { L("elsif"), (void *) process_if },
2132  { L("if"), (void *) process_if },
2133  { L("map"), (void *) process_map },
2134  { L("subrequest"), (void *) process_subrequest }
2135 };
2137 
2138 typedef CONF_ITEM *(*cf_process_func_t)(cf_stack_t *);
2139 
2141 {
2142  fr_token_t name1_token, name2_token, value_token, op_token;
2143  char const *value;
2144  CONF_SECTION *css;
2145  char const *ptr = stack->ptr;
2146  cf_stack_frame_t *frame = &stack->frame[stack->depth];
2147  CONF_SECTION *parent = frame->current;
2148  char *buff[4];
2149  cf_process_func_t process;
2150 
2151  /*
2152  * Short names are nicer.
2153  */
2154  buff[0] = stack->buff[0];
2155  buff[1] = stack->buff[1];
2156  buff[2] = stack->buff[2];
2157  buff[3] = stack->buff[3];
2158 
2159  fr_assert(parent != NULL);
2160 
2161  /*
2162  * Catch end of a subsection.
2163  */
2164  if (*ptr == '}') {
2165  /*
2166  * We're already at the parent section
2167  * which loaded this file. We cannot go
2168  * back up another level.
2169  *
2170  * This limitation means that we cannot
2171  * put half of a CONF_SECTION in one
2172  * file, and then the second half in
2173  * another file. That's fine.
2174  */
2175  if (parent == frame->parent) {
2176  ERROR("%s[%d]: Too many closing braces", frame->filename, frame->lineno);
2177  return -1;
2178  }
2179 
2180  fr_assert(frame->braces > 0);
2181  frame->braces--;
2182 
2183  /*
2184  * Merge the template into the existing
2185  * section. parent uses more memory, but
2186  * means that templates now work with
2187  * sub-sections, etc.
2188  */
2189  if (!cf_template_merge(parent, parent->template)) return -1;
2190 
2191  if (parent == frame->special) frame->special = NULL;
2192 
2193  frame->current = cf_item_to_section(parent->item.parent);
2194 
2195  ptr++;
2196  stack->ptr = ptr;
2197  return 1;
2198  }
2199 
2200  /*
2201  * Found nothing to get excited over. It MUST be
2202  * a key word.
2203  */
2204  if (cf_get_token(parent, &ptr, &name1_token, buff[1], stack->bufsize,
2205  frame->filename, frame->lineno) < 0) {
2206  return -1;
2207  }
2208 
2209  /*
2210  * See which unlang keywords are allowed
2211  *
2212  * 0 - no unlang keywords are allowed.
2213  * 1 - unlang keywords are allowed
2214  * 2 - unlang keywords are allowed only in sub-sections
2215  * i.e. policy { ... } doesn't allow "if". But the "if"
2216  * keyword is allowed in children of "policy".
2217  */
2218  if (parent->allow_unlang != 1) {
2219  if ((strcmp(buff[1], "if") == 0) ||
2220  (strcmp(buff[1], "elsif") == 0)) {
2221  ERROR("%s[%d]: Invalid location for '%s'",
2222  frame->filename, frame->lineno, buff[1]);
2223  return -1;
2224  }
2225 
2226  } else if ((name1_token == T_BARE_WORD) && isalpha((uint8_t) *buff[1])) {
2227  fr_type_t type;
2228 
2229  /*
2230  * The next thing should be a keyword.
2231  */
2233  if (process) {
2234  CONF_ITEM *ci;
2235 
2236  stack->ptr = ptr;
2237  ci = process(stack);
2238  ptr = stack->ptr;
2239  if (!ci) return -1;
2240  if (cf_item_is_section(ci)) {
2241  parent->allow_locals = false;
2242  css = cf_item_to_section(ci);
2243  goto add_section;
2244  }
2245 
2246  /*
2247  * Else the item is a pair, and it's already added to the section.
2248  */
2249  goto added_pair;
2250  }
2251 
2252  /*
2253  * The next token is an assignment operator, so we ignore it.
2254  */
2255  if (!isalnum((int) *ptr)) goto check_for_eol;
2256 
2257  /*
2258  * It's not a keyword, check for a data type, which means we have a local variable
2259  * definition.
2260  */
2262  if (type == FR_TYPE_NULL) {
2263  parent->allow_locals = false;
2264  goto check_for_eol;
2265  }
2266 
2267  if (!parent->allow_locals && (cf_section_find_in_parent(parent, "dictionary", NULL) == NULL)) {
2268  ERROR("%s[%d]: Parse error: Invalid location for variable definition",
2269  frame->filename, frame->lineno);
2270  return -1;
2271  }
2272 
2273  if (type == FR_TYPE_TLV) goto parse_name2;
2274 
2275  /*
2276  * We don't have an operator, so set it to a magic value.
2277  */
2278  op_token = T_OP_CMP_TRUE;
2279 
2280  /*
2281  * Parse the name of the local variable, and use it as the "value" for the CONF_PAIR.
2282  */
2283  if (cf_get_token(parent, &ptr, &value_token, buff[2], stack->bufsize,
2284  frame->filename, frame->lineno) < 0) {
2285  return -1;
2286  }
2287  value = buff[2];
2288 
2289  goto alloc_pair;
2290  }
2291 
2292  /*
2293  * parent single word is done. Create a CONF_PAIR.
2294  */
2295 check_for_eol:
2296  if (!*ptr || (*ptr == '#') || (*ptr == ',') || (*ptr == ';') || (*ptr == '}')) {
2297  parent->allow_locals = false;
2298  value_token = T_INVALID;
2299  op_token = T_OP_EQ;
2300  value = NULL;
2301  goto alloc_pair;
2302  }
2303 
2304  /*
2305  * A common pattern is: name { ...}
2306  * Check for it and skip ahead.
2307  */
2308  if (*ptr == '{') {
2309  ptr++;
2310  name2_token = T_INVALID;
2311  value = NULL;
2312  goto alloc_section;
2313  }
2314 
2315  /*
2316  * We allow certain kinds of strings, attribute
2317  * references (i.e. foreach) and bare names that
2318  * start with a letter. We also allow UTF-8
2319  * characters.
2320  *
2321  * Once we fix the parser to be less generic, we
2322  * can tighten these rules. Right now, it's
2323  * *technically* possible to define a module with
2324  * &foo or "with spaces" as the second name.
2325  * Which seems bad. But the old parser allowed
2326  * it, so oh well.
2327  */
2328  if ((*ptr == '"') || (*ptr == '`') || (*ptr == '\'') || ((*ptr == '&') && (ptr[1] != '=')) ||
2329  ((*((uint8_t const *) ptr) & 0x80) != 0) || isalpha((uint8_t) *ptr) || isdigit((uint8_t) *ptr)) {
2330  parse_name2:
2331  if (cf_get_token(parent, &ptr, &name2_token, buff[2], stack->bufsize,
2332  frame->filename, frame->lineno) < 0) {
2333  return -1;
2334  }
2335 
2336  if (*ptr != '{') {
2337  ERROR("%s[%d]: Parse error: expected '{', got text \"%s\"",
2338  frame->filename, frame->lineno, ptr);
2339  return -1;
2340  }
2341  ptr++;
2342  value = buff[2];
2343 
2344  alloc_section:
2345  css = cf_section_alloc(parent, parent, buff[1], value);
2346  if (!css) {
2347  ERROR("%s[%d]: Failed allocating memory for section",
2348  frame->filename, frame->lineno);
2349  return -1;
2350  }
2351 
2352  cf_filename_set(css, frame->filename);
2353  cf_lineno_set(css, frame->lineno);
2354  css->name2_quote = name2_token;
2355 
2356  /*
2357  * Hack for better error messages in
2358  * nested sections. parent information
2359  * should really be put into a parser
2360  * struct, as with tmpls.
2361  */
2362  if (!frame->special && (strcmp(css->name1, "update") == 0)) {
2363  frame->special = css;
2364  }
2365 
2366  /*
2367  * Only a few top-level sections allow "unlang"
2368  * statements. And for those, "unlang"
2369  * statements are only allowed in child
2370  * subsection.
2371  */
2372  if (!parent->allow_unlang && !parent->item.parent) {
2373  if (strcmp(css->name1, "server") == 0) css->allow_unlang = 2;
2374  if (strcmp(css->name1, "policy") == 0) css->allow_unlang = 2;
2375 
2376  } else if ((parent->allow_unlang == 2) && (strcmp(css->name1, "listen") == 0)) { /* hacks for listeners */
2377  css->allow_unlang = css->allow_locals = false;
2378 
2379  } else {
2380  /*
2381  * Allow unlang if the parent allows it, but don't allow
2382  * unlang in list assignment sections.
2383  */
2384  css->allow_unlang = css->allow_locals = parent->allow_unlang && !fr_list_assignment_op[name2_token];
2385  }
2386 
2387  add_section:
2388  /*
2389  * The current section is now the child section.
2390  */
2391  frame->current = css;
2392  frame->braces++;
2393  css = NULL;
2394  stack->ptr = ptr;
2395  return 1;
2396  }
2397 
2398  /*
2399  * The next thing MUST be an operator. All
2400  * operators start with one of these characters,
2401  * so we check for them first.
2402  */
2403  if ((ptr[0] != '=') && (ptr[0] != '!') && (ptr[0] != '<') && (ptr[0] != '>') &&
2404  (ptr[1] != '=') && (ptr[1] != '~')) {
2405  ERROR("%s[%d]: Parse error at unexpected text: %s",
2406  frame->filename, frame->lineno, ptr);
2407  return -1;
2408  }
2409 
2410  /*
2411  * If we're not parsing a section, then the next
2412  * token MUST be an operator.
2413  */
2414  name2_token = gettoken(&ptr, buff[2], stack->bufsize, false);
2415  switch (name2_token) {
2416  case T_OP_ADD_EQ:
2417  case T_OP_SUB_EQ:
2418  case T_OP_AND_EQ:
2419  case T_OP_OR_EQ:
2420  case T_OP_NE:
2421  case T_OP_RSHIFT_EQ:
2422  case T_OP_GE:
2423  case T_OP_GT:
2424  case T_OP_LSHIFT_EQ:
2425  case T_OP_LE:
2426  case T_OP_LT:
2427  case T_OP_CMP_EQ:
2428  case T_OP_CMP_FALSE:
2429  /*
2430  * As a hack, allow any operators when using &foo=bar
2431  */
2432  if (!frame->special && (buff[1][0] != '&')) {
2433  ERROR("%s[%d]: Invalid operator in assignment for %s ...",
2434  frame->filename, frame->lineno, buff[1]);
2435  return -1;
2436  }
2437  FALL_THROUGH;
2438 
2439  case T_OP_EQ:
2440  case T_OP_SET:
2441  case T_OP_PREPEND:
2442  fr_skip_whitespace(ptr);
2443  op_token = name2_token;
2444  break;
2445 
2446  default:
2447  ERROR("%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
2448  frame->filename, frame->lineno, buff[1], fr_table_str_by_value(fr_tokens_table, name2_token, "<INVALID>"));
2449 
2450  return -1;
2451  }
2452 
2453  /*
2454  * MUST have something after the operator.
2455  */
2456  if (!*ptr || (*ptr == '#') || (*ptr == ',') || (*ptr == ';')) {
2457  ERROR("%s[%d]: Syntax error: Expected to see a value after the operator '%s': %s",
2458  frame->filename, frame->lineno, buff[2], ptr);
2459  return -1;
2460  }
2461 
2462  /*
2463  * foo = { ... } for nested groups.
2464  *
2465  * As a special case, we allow sub-sections after '=', etc.
2466  *
2467  * This syntax is only for inside of "update"
2468  * sections, and for attributes of type "group".
2469  * But the parser isn't (yet) smart enough to
2470  * know about that context. So we just silently
2471  * allow it everywhere.
2472  */
2473  if (*ptr == '{') {
2474  if (!parent->allow_unlang && !frame->require_edits) {
2475  ERROR("%s[%d]: Parse error: Invalid location for grouped attribute",
2476  frame->filename, frame->lineno);
2477  return -1;
2478  }
2479 
2480  if (*buff[1] != '&') {
2481  ERROR("%s[%d]: Parse error: Expected '&' before attribute name",
2482  frame->filename, frame->lineno);
2483  return -1;
2484  }
2485 
2486  if (!fr_list_assignment_op[name2_token]) {
2487  ERROR("%s[%d]: Parse error: Invalid assignment operator '%s' for list",
2488  frame->filename, frame->lineno, buff[2]);
2489  return -1;
2490  }
2491 
2492  /*
2493  * Now that we've peeked ahead to
2494  * see the open brace, parse it
2495  * for real.
2496  */
2497  ptr++;
2498 
2499  /*
2500  * Leave name2_token as the
2501  * operator (as a hack). But
2502  * note that there's no actual
2503  * name2. We'll deal with that
2504  * situation later.
2505  */
2506  value = NULL;
2507  frame->require_edits = true;
2508  goto alloc_section;
2509  }
2510 
2511  fr_skip_whitespace(ptr);
2512 
2513  /*
2514  * Parse the value for a CONF_PAIR.
2515  *
2516  * If it's not an "update" section, and it's an "edit" thing, then try to parse an expression.
2517  */
2518  if (!frame->special && (frame->require_edits || (*buff[1] == '&'))) {
2519  bool eol;
2520  ssize_t slen;
2521  char const *ptr2 = ptr;
2522 
2523  /*
2524  * If the RHS is an expression (foo) or function %foo(), then mark it up as an expression.
2525  */
2526  if ((*ptr == '(') || (*ptr == '%')) {
2527  /* nothing */
2528 
2529  } else if (cf_get_token(parent, &ptr2, &value_token, buff[2], stack->bufsize,
2530  frame->filename, frame->lineno) == 0) {
2531  /*
2532  * We have one token (bare word), followed by EOL. It's just a token.
2533  */
2534  fr_skip_whitespace(ptr2);
2535  if (terminal_end_line[(uint8_t) *ptr2]) {
2536  parent->allow_locals = false;
2537  ptr = ptr2;
2538  value = buff[2];
2539  goto alloc_pair;
2540  }
2541  } /* else it looks like an expression */
2542 
2543  /*
2544  * Parse the text as an expression.
2545  *
2546  * Note that unlike conditions, expressions MUST use \ at the EOL for continuation.
2547  * If we automatically read past EOL, as with:
2548  *
2549  * &foo := (bar -
2550  * baz)
2551  *
2552  * That works, mostly. Until the user forgets to put the trailing ')', and then
2553  * the parse is bad enough that it tries to read to EOF, or to some other random
2554  * parse error.
2555  *
2556  * So the simplest way to avoid utter craziness is to simply require a signal which
2557  * says "yes, I intended to put this over multiple lines".
2558  */
2559  slen = fr_skip_condition(ptr, NULL, terminal_end_line, &eol);
2560  if (slen < 0) {
2561  ERROR("%s[%d]: Parse error in expression: %s",
2562  frame->filename, frame->lineno, fr_strerror());
2563  return -1;
2564  }
2565 
2566  /*
2567  * We parsed until the end of the string, but the condition still needs more data.
2568  */
2569  if (eol) {
2570  ERROR("%s[%d]: Expression is unfinished at end of line",
2571  frame->filename, frame->lineno);
2572  return -1;
2573  }
2574 
2575  /*
2576  * Keep a copy of the entire RHS.
2577  */
2578  memcpy(buff[2], ptr, slen);
2579  buff[2][slen] = '\0';
2580 
2581  value = buff[2];
2582 
2583  /*
2584  * Mark it up as an expression
2585  *
2586  * @todo - we should really just call cf_data_add() to add a flag, but this is good for
2587  * now. See map_afrom_cp()
2588  */
2589  value_token = T_HASH;
2590 
2591  /*
2592  * Skip terminal characters
2593  */
2594  ptr += slen;
2595  if ((*ptr == ',') || (*ptr == ';')) ptr++;
2596 
2597  } else {
2598  if (cf_get_token(parent, &ptr, &value_token, buff[2], stack->bufsize,
2599  frame->filename, frame->lineno) < 0) {
2600  return -1;
2601  }
2602  value = buff[2];
2603  }
2604 
2605  /*
2606  * Add parent CONF_PAIR to our CONF_SECTION
2607  */
2608  parent->allow_locals = false;
2609 
2610 alloc_pair:
2611  if (add_pair(parent, buff[1], value, name1_token, op_token, value_token, buff[3], frame->filename, frame->lineno) < 0) return -1;
2612 
2613 added_pair:
2614  fr_skip_whitespace(ptr);
2615 
2616  /*
2617  * Skip semicolon if we see it after a
2618  * CONF_PAIR. Also allow comma for
2619  * backwards compatibility with secret
2620  * things in v3.
2621  */
2622  if ((*ptr == ';') || (*ptr == ',')) {
2623  ptr++;
2624  stack->ptr = ptr;
2625  return 1;
2626  }
2627 
2628  /*
2629  * Closing brace is allowed after a CONF_PAIR
2630  * definition.
2631  */
2632  if (*ptr == '}') {
2633  stack->ptr = ptr;
2634  return 1;
2635  }
2636 
2637  /*
2638  * Anything OTHER than EOL or comment is a syntax
2639  * error.
2640  */
2641  if (*ptr && (*ptr != '#')) {
2642  ERROR("%s[%d]: Syntax error: Unexpected text: %s",
2643  frame->filename, frame->lineno, ptr);
2644  return -1;
2645  }
2646 
2647  /*
2648  * Since we're at EOL or comment, just drop the
2649  * text, and go read another line of text.
2650  */
2651  return 0;
2652 }
2653 
2654 
2656 {
2657  cf_stack_frame_t *frame = &stack->frame[stack->depth];
2658  CONF_SECTION *parent = frame->current;
2659  cf_file_heap_t *h;
2660 
2661  h = fr_heap_pop(&frame->heap);
2662  if (!h) {
2663  /*
2664  * Done reading the directory entry. Close it, and go
2665  * back up a stack frame.
2666  */
2667  talloc_free(frame->directory);
2668  stack->depth--;
2669  return 1;
2670  }
2671 
2672  /*
2673  * Push the next filename onto the stack.
2674  */
2675  stack->depth++;
2676  frame = &stack->frame[stack->depth];
2677  memset(frame, 0, sizeof(*frame));
2678 
2679  frame->type = CF_STACK_FILE;
2680  frame->fp = NULL;
2681  frame->parent = parent;
2682  frame->current = parent;
2683  frame->filename = h->filename;
2684  frame->lineno = 0;
2685  frame->from_dir = true;
2686  frame->special = NULL; /* can't do includes inside of update / map */
2687  frame->require_edits = stack->frame[stack->depth - 1].require_edits;
2688  return 1;
2689 }
2690 
2691 
2693 {
2694  bool at_eof, has_spaces;
2695  size_t len;
2696  char const *ptr;
2697  cf_stack_frame_t *frame = &stack->frame[stack->depth];
2698 
2699 read_more:
2700  has_spaces = false;
2701 
2702 read_continuation:
2703  /*
2704  * Get data, and remember if we are at EOF.
2705  */
2706  at_eof = (fgets(stack->fill, stack->bufsize - (stack->fill - stack->buff[0]), frame->fp) == NULL);
2707  frame->lineno++;
2708 
2709  /*
2710  * We read the entire 8k worth of data: complain.
2711  * Note that we don't care if the last character
2712  * is \n: it's still forbidden. This means that
2713  * the maximum allowed length of text is 8k-1, which
2714  * should be plenty.
2715  */
2716  len = strlen(stack->fill);
2717  if ((stack->fill + len + 1) >= (stack->buff[0] + stack->bufsize)) {
2718  ERROR("%s[%d]: Line too long", frame->filename, frame->lineno);
2719  return -1;
2720  }
2721 
2722  /*
2723  * Suppress leading whitespace after a
2724  * continuation line.
2725  */
2726  if (has_spaces) {
2727  ptr = stack->fill;
2728  fr_skip_whitespace(ptr);
2729 
2730  if (ptr > stack->fill) {
2731  memmove(stack->fill, ptr, len - (ptr - stack->fill));
2732  len -= (ptr - stack->fill);
2733  }
2734  }
2735 
2736  /*
2737  * Skip blank lines when we're at the start of
2738  * the read buffer.
2739  */
2740  if (stack->fill == stack->buff[0]) {
2741  if (at_eof) return 0;
2742 
2743  ptr = stack->buff[0];
2744  fr_skip_whitespace(ptr);
2745 
2746  if (!*ptr || (*ptr == '#')) goto read_more;
2747 
2748  } else if (at_eof || (len == 0)) {
2749  ERROR("%s[%d]: Continuation at EOF is illegal", frame->filename, frame->lineno);
2750  return -1;
2751  }
2752 
2753  /*
2754  * See if there's a continuation.
2755  */
2756  while ((len > 0) &&
2757  ((stack->fill[len - 1] == '\n') || (stack->fill[len - 1] == '\r'))) {
2758  len--;
2759  stack->fill[len] = '\0';
2760  }
2761 
2762  if ((len > 0) && (stack->fill[len - 1] == '\\')) {
2763  /*
2764  * Check for "suppress spaces" magic.
2765  */
2766  if (!has_spaces && (len > 2) && (stack->fill[len - 2] == '"')) {
2767  has_spaces = true;
2768  }
2769 
2770  stack->fill[len - 1] = '\0';
2771  stack->fill += len - 1;
2772  goto read_continuation;
2773  }
2774 
2775  ptr = stack->fill;
2776 
2777  /*
2778  * We now have one full line of text in the input
2779  * buffer, without continuations.
2780  */
2781  fr_skip_whitespace(ptr);
2782 
2783  /*
2784  * Nothing left, or just a comment. Go read
2785  * another line of text.
2786  */
2787  if (!*ptr || (*ptr == '#')) goto read_more;
2788 
2789  return 1;
2790 }
2791 
2792 
2793 /*
2794  * Read a configuration file or files.
2795  */
2797 {
2799  char const *ptr;
2800 
2801  cf_stack_frame_t *frame;
2802  int rcode;
2803 
2804 do_frame:
2805  frame = &stack->frame[stack->depth];
2806  parent = frame->current; /* add items here */
2807 
2808  switch (frame->type) {
2809 #ifdef HAVE_GLOB_H
2810  case CF_STACK_GLOB:
2811  if (frame->gl_current == frame->glob.gl_pathc) {
2812  globfree(&frame->glob);
2813  goto pop_stack;
2814  }
2815 
2816  /*
2817  * Process the filename as an include.
2818  */
2819  if (process_include(stack, parent, frame->glob.gl_pathv[frame->gl_current++], frame->required, false) < 0) return -1;
2820 
2821  /*
2822  * Run the correct frame. If the file is NOT
2823  * required, then the call to process_include()
2824  * may return 0, and we just process the next
2825  * glob. Otherwise, the call to
2826  * process_include() may return a directory or a
2827  * filename. Go handle that.
2828  */
2829  goto do_frame;
2830 #endif
2831 
2832 #ifdef HAVE_DIRENT_H
2833  case CF_STACK_DIR:
2834  rcode = frame_readdir(stack);
2835  if (rcode == 0) goto do_frame;
2836  if (rcode < 0) return -1;
2837 
2838  /*
2839  * Reset which frame we're looking at.
2840  */
2841  frame = &stack->frame[stack->depth];
2842  fr_assert(frame->type == CF_STACK_FILE);
2843  break;
2844 #endif
2845 
2846  case CF_STACK_FILE:
2847  break;
2848  }
2849 
2850 #ifndef NDEBUG
2851  /*
2852  * One last sanity check.
2853  */
2854  if (frame->type != CF_STACK_FILE) {
2855  cf_log_err(frame->current, "%s: Internal sanity check failed", __FUNCTION__);
2856  goto pop_stack;
2857  }
2858 #endif
2859 
2860  /*
2861  * Open the new file if necessary. It either came from
2862  * the first call to the function, or was pushed onto the
2863  * stack by another function.
2864  */
2865  if (!frame->fp) {
2866  rcode = cf_file_open(frame->parent, frame->filename, frame->from_dir, &frame->fp);
2867  if (rcode < 0) return -1;
2868 
2869  /*
2870  * Ignore this file
2871  */
2872  if (rcode == 1) {
2873  cf_log_warn(frame->current, "Ignoring file %s - it was already read",
2874  frame->filename);
2875  goto pop_stack;
2876  }
2877  }
2878 
2879  /*
2880  * Read, checking for line continuations ('\\' at EOL)
2881  */
2882  for (;;) {
2883  /*
2884  * Fill the buffers with data.
2885  */
2886  stack->fill = stack->buff[0];
2887  rcode = cf_file_fill(stack);
2888  if (rcode < 0) return -1;
2889  if (rcode == 0) break;
2890 
2891  /*
2892  * The text here MUST be at the start of a line,
2893  * OR have only whitespace in front of it.
2894  */
2895  ptr = stack->buff[0];
2896  fr_skip_whitespace(ptr);
2897 
2898  if (*ptr == '$') {
2899  /*
2900  * Allow for $INCLUDE files
2901  */
2902  if (strncasecmp(ptr, "$INCLUDE", 8) == 0) {
2903  ptr += 8;
2904 
2905  if (process_include(stack, parent, ptr, true, true) < 0) return -1;
2906  goto do_frame;
2907  }
2908 
2909  if (strncasecmp(ptr, "$-INCLUDE", 9) == 0) {
2910  ptr += 9;
2911 
2912  rcode = process_include(stack, parent, ptr, false, true);
2913  if (rcode < 0) return -1;
2914  if (rcode == 0) continue;
2915  goto do_frame;
2916  }
2917 
2918  /*
2919  * Allow for $TEMPLATE things
2920  */
2921  if (strncasecmp(ptr, "$TEMPLATE", 9) == 0) {
2922  ptr += 9;
2923  fr_skip_whitespace(ptr);
2924 
2925  stack->ptr = ptr;
2926  if (process_template(stack) < 0) return -1;
2927  continue;
2928  }
2929 
2930  ERROR("%s[%d]: Invalid text starting with '$'", frame->filename, frame->lineno);
2931  return -1;
2932  }
2933 
2934  /*
2935  * All of the file handling code is done. Parse the input.
2936  */
2937  do {
2938  fr_skip_whitespace(ptr);
2939  if (!*ptr || (*ptr == '#')) break;
2940 
2941  stack->ptr = ptr;
2942  rcode = parse_input(stack);
2943  ptr = stack->ptr;
2944 
2945  if (rcode < 0) return -1;
2946  parent = frame->current;
2947  } while (rcode == 1);
2948  }
2949 
2950  fr_assert(frame->fp != NULL);
2951 
2952  /*
2953  * See if EOF was unexpected.
2954  */
2955  if (feof(frame->fp) && (parent != frame->parent)) {
2956  ERROR("%s[%d]: EOF reached without closing brace for section %s starting at line %d",
2957  frame->filename, frame->lineno, cf_section_name1(parent), cf_lineno(parent));
2958  return -1;
2959  }
2960 
2961  fclose(frame->fp);
2962  frame->fp = NULL;
2963 
2964 pop_stack:
2965  /*
2966  * More things to read, go read them.
2967  */
2968  if (stack->depth > 0) {
2969  stack->depth--;
2970  goto do_frame;
2971  }
2972 
2973  return 0;
2974 }
2975 
2977 {
2978  cf_stack_frame_t *frame = &stack->frame[stack->depth];
2979 
2980  while (stack->depth >= 0) {
2981  switch (frame->type) {
2982  case CF_STACK_FILE:
2983  if (frame->fp) fclose(frame->fp);
2984  frame->fp = NULL;
2985  break;
2986 
2987 #ifdef HAVE_DIRENT_H
2988  case CF_STACK_DIR:
2989  talloc_free(frame->directory);
2990  break;
2991 #endif
2992 
2993 #ifdef HAVE_GLOB_H
2994  case CF_STACK_GLOB:
2995  globfree(&frame->glob);
2996  break;
2997 #endif
2998  }
2999 
3000  frame--;
3001  stack->depth--;
3002  }
3003 
3004  talloc_free(stack->buff);
3005 }
3006 
3007 /*
3008  * Bootstrap a config file.
3009  */
3010 int cf_file_read(CONF_SECTION *cs, char const *filename)
3011 {
3012  int i;
3013  char *p;
3014  CONF_PAIR *cp;
3015  fr_rb_tree_t *tree;
3016  cf_stack_t stack;
3017  cf_stack_frame_t *frame;
3018 
3019  cp = cf_pair_alloc(cs, "confdir", filename, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
3020  if (!cp) return -1;
3021 
3022  p = strrchr(cp->value, FR_DIR_SEP);
3023  if (p) *p = '\0';
3024 
3025  MEM(tree = fr_rb_inline_talloc_alloc(cs, cf_file_t, node, _inode_cmp, NULL));
3026 
3027  cf_data_add(cs, tree, "filename", false);
3028 
3029 #ifndef NDEBUG
3030  memset(&stack, 0, sizeof(stack));
3031 #endif
3032 
3033  /*
3034  * Allocate temporary buffers on the heap (so we don't use *all* the stack space)
3035  */
3036  stack.buff = talloc_array(cs, char *, 4);
3037  for (i = 0; i < 4; i++) MEM(stack.buff[i] = talloc_array(stack.buff, char, 8192));
3038 
3039  stack.depth = 0;
3040  stack.bufsize = 8192;
3041  frame = &stack.frame[stack.depth];
3042 
3043  memset(frame, 0, sizeof(*frame));
3044  frame->parent = frame->current = cs;
3045 
3046  frame->type = CF_STACK_FILE;
3047  frame->filename = talloc_strdup(frame->parent, filename);
3048  cs->item.filename = frame->filename;
3049 
3050  if (cf_file_include(&stack) < 0) {
3052  return -1;
3053  }
3054 
3055  talloc_free(stack.buff);
3056 
3057  /*
3058  * Now that we've read the file, go back through it and
3059  * expand the variables.
3060  */
3061  if (cf_section_pass2(cs) < 0) {
3062  cf_log_err(cs, "Parsing config items failed");
3063  return -1;
3064  }
3065 
3066  return 0;
3067 }
3068 
3070 {
3071  talloc_free(cs);
3072 }
3073 
3074 /** Set the euid/egid used when performing file checks
3075  *
3076  * Sets the euid, and egid used when cf_file_check is called to check
3077  * permissions on conf items of type #CONF_FLAG_FILE_INPUT
3078  *
3079  * @note This is probably only useful for the freeradius daemon itself.
3080  *
3081  * @param uid to set, (uid_t)-1 to use current euid.
3082  * @param gid to set, (gid_t)-1 to use current egid.
3083  */
3084 void cf_file_check_user(uid_t uid, gid_t gid)
3085 {
3086  if (uid != 0) conf_check_uid = uid;
3087  if (gid != 0) conf_check_gid = gid;
3088 }
3089 
3090 static char const parse_tabs[] = " ";
3091 
3092 static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, fr_token_t t)
3093 {
3094  size_t outlen;
3095  char c;
3096  char buffer[2048];
3097 
3098  switch (t) {
3099  default:
3100  c = '\0';
3101  break;
3102 
3104  c = '"';
3105  break;
3106 
3108  c = '\'';
3109  break;
3110 
3111  case T_BACK_QUOTED_STRING:
3112  c = '`';
3113  break;
3114  }
3115 
3116  if (c) fprintf(fp, "%c", c);
3117 
3118  outlen = fr_snprint(buffer, sizeof(buffer), string, len, c);
3119  fwrite(buffer, outlen, 1, fp);
3120 
3121  if (c) fprintf(fp, "%c", c);
3122  return 1;
3123 }
3124 
3125 static int cf_pair_write(FILE *fp, CONF_PAIR *cp)
3126 {
3127  if (!cp->value) {
3128  fprintf(fp, "%s\n", cp->attr);
3129  return 0;
3130  }
3131 
3132  cf_string_write(fp, cp->attr, strlen(cp->attr), cp->lhs_quote);
3133  fprintf(fp, " %s ", fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"));
3134  cf_string_write(fp, cp->value, strlen(cp->value), cp->rhs_quote);
3135  fprintf(fp, "\n");
3136 
3137  return 1; /* FIXME */
3138 }
3139 
3140 
3141 int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
3142 {
3143  if (!fp || !cs) return -1;
3144 
3145  /*
3146  * Print the section name1, etc.
3147  */
3148  fwrite(parse_tabs, depth, 1, fp);
3149  cf_string_write(fp, cs->name1, strlen(cs->name1), T_BARE_WORD);
3150 
3151  /*
3152  * FIXME: check for "if" or "elsif". And if so, print
3153  * out the parsed condition, instead of the input text
3154  *
3155  * cf_data_find(cs, CF_DATA_TYPE_UNLANG, "if");
3156  */
3157  if (cs->name2) {
3158  fputs(" ", fp);
3159 
3160 #if 0
3161  c = cf_data_value(cf_data_find(cs, fr_cond_t, NULL));
3162  if (c) {
3163  char buffer[1024];
3164 
3165  cond_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), c);
3166  fprintf(fp, "(%s)", buffer);
3167  } else
3168 #endif
3169  cf_string_write(fp, cs->name2, strlen(cs->name2), cs->name2_quote);
3170  }
3171 
3172  fputs(" {\n", fp);
3173 
3174  /*
3175  * Loop over the children. Either recursing, or opening
3176  * a new file.
3177  */
3178  cf_item_foreach(&cs->item, ci) {
3179  switch (ci->type) {
3180  case CONF_ITEM_SECTION:
3182  break;
3183 
3184  case CONF_ITEM_PAIR:
3185  /*
3186  * Ignore internal things.
3187  */
3188  if (!ci->filename || (ci->filename[0] == '<')) break;
3189 
3190  fwrite(parse_tabs, depth + 1, 1, fp);
3191  cf_pair_write(fp, cf_item_to_pair(ci));
3192  break;
3193 
3194  default:
3195  break;
3196  }
3197  }
3198 
3199  fwrite(parse_tabs, depth, 1, fp);
3200  fputs("}\n\n", fp);
3201 
3202  return 1;
3203 }
3204 
3205 
3207  CONF_SECTION const *outer_cs,
3208  char const *ptr)
3209 {
3210  CONF_PAIR *cp;
3211  CONF_SECTION *next;
3212  CONF_SECTION const *cs = outer_cs;
3213  char name[8192];
3214  char *p;
3215 
3216  if (!ptr || (!parent_cs && !outer_cs)) return NULL;
3217 
3218  strlcpy(name, ptr, sizeof(name));
3219 
3220  p = name;
3221 
3222  /*
3223  * ".foo" means "foo from the current section"
3224  */
3225  if (*p == '.') {
3226  p++;
3227 
3228  /*
3229  * Just '.' means the current section
3230  */
3231  if (*p == '\0') return cf_section_to_item(cs);
3232 
3233  /*
3234  * ..foo means "foo from the section
3235  * enclosing this section" (etc.)
3236  */
3237  while (*p == '.') {
3238  if (cs->item.parent) cs = cf_item_to_section(cs->item.parent);
3239 
3240  /*
3241  * .. means the section
3242  * enclosing this section
3243  */
3244  if (!*++p) return cf_section_to_item(cs);
3245  }
3246 
3247  /*
3248  * "foo.bar.baz" means "from the root"
3249  */
3250  } else if (strchr(p, '.') != NULL) {
3251  if (!parent_cs) return NULL;
3252  cs = parent_cs;
3253  }
3254 
3255  while (*p) {
3256  char *q, *r;
3257 
3258  r = strchr(p, '[');
3259  q = strchr(p, '.');
3260  if (!r && !q) break;
3261 
3262  if (r && q > r) q = NULL;
3263  if (q && q < r) r = NULL;
3264 
3265  /*
3266  * Split off name2.
3267  */
3268  if (r) {
3269  q = strchr(r + 1, ']');
3270  if (!q) return NULL; /* parse error */
3271 
3272  /*
3273  * Points to foo[bar]xx: parse error,
3274  * it should be foo[bar] or foo[bar].baz
3275  */
3276  if (q[1] && q[1] != '.') return NULL;
3277 
3278  *r = '\0';
3279  *q = '\0';
3280  next = cf_section_find(cs, p, r + 1);
3281  if (!next && cs->template) next = cf_section_find(cs->template, p, r + 1);
3282  *r = '[';
3283  *q = ']';
3284 
3285  /*
3286  * Points to a named instance of a section.
3287  */
3288  if (!q[1]) {
3289  if (!next) return NULL;
3290  return &(next->item);
3291  }
3292 
3293  q++; /* ensure we skip the ']' and '.' */
3294 
3295  } else {
3296  *q = '\0';
3297  next = cf_section_find(cs, p, NULL);
3298  if (!next && cs->template) next = cf_section_find(cs->template, p, NULL);
3299  *q = '.';
3300  }
3301 
3302  if (!next) break; /* it MAY be a pair in this section! */
3303 
3304  cs = next;
3305  p = q + 1;
3306  }
3307 
3308  if (!*p) return NULL;
3309 
3310 retry:
3311  /*
3312  * Find it in the current referenced
3313  * section.
3314  */
3315  cp = cf_pair_find(cs, p);
3316  if (!cp && cs->template) cp = cf_pair_find(cs->template, p);
3317  if (cp) {
3318  cp->referenced = true; /* conf pairs which are referenced count as used */
3319  return &(cp->item);
3320  }
3321 
3322  next = cf_section_find(cs, p, NULL);
3323  if (next) return &(next->item);
3324 
3325  /*
3326  * "foo" is "in the current section, OR in main".
3327  */
3328  if ((p == name) && (parent_cs != NULL) && (cs != parent_cs)) {
3329  cs = parent_cs;
3330  goto retry;
3331  }
3332 
3333  return NULL;
3334 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
strcpy(log_entry->msg, buffer)
static fr_dict_t * dict
Definition: fuzzer.c:46
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition: build.h:119
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define NUM_ELEMENTS(_t)
Definition: build.h:335
CONF_SECTION * current
sub-section we're reading
Definition: cf_file.c:121
cf_stack_file_t type
Definition: cf_file.c:94
static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
Definition: cf_file.c:464
static int parse_input(cf_stack_t *stack)
Definition: cf_file.c:2140
char * fill
where we start filling the buffer from
Definition: cf_file.c:141
struct cf_file_heap_t cf_file_heap_t
conf_property
Definition: cf_file.c:70
@ CONF_PROPERTY_NAME
Definition: cf_file.c:72
@ CONF_PROPERTY_INSTANCE
Definition: cf_file.c:73
@ CONF_PROPERTY_INVALID
Definition: cf_file.c:71
static int unlang_keywords_len
Definition: cf_file.c:2136
static char const * cf_local_file(char const *base, char const *filename, char *buffer, size_t bufsize)
Definition: cf_file.c:791
bool require_edits
are we required to do edits?
Definition: cf_file.c:124
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
static CONF_ITEM * process_map(cf_stack_t *stack)
Definition: cf_file.c:1686
bool check_config
Definition: cf_file.c:66
fr_heap_index_t heap_id
Definition: cf_file.c:871
static int frame_readdir(cf_stack_t *stack)
Definition: cf_file.c:2655
static ssize_t fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX+1], bool *eol)
Skip a conditional expression.
Definition: cf_file.c:1372
static int add_pair(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t name1_token, fr_token_t op_token, fr_token_t value_token, char *buff, char const *filename, int lineno)
Definition: cf_file.c:2055
#define RULES_VERIFY(_cs, _rules)
Definition: cf_file.c:164
static void cf_stack_cleanup(cf_stack_t *stack)
Definition: cf_file.c:2976
static int cf_tmpl_rules_verify(CONF_SECTION *cs, tmpl_rules_t const *rules)
Definition: cf_file.c:146
int depth
stack depth
Definition: cf_file.c:139
static CONF_ITEM * process_catch(cf_stack_t *stack)
Definition: cf_file.c:1900
static ssize_t fr_skip_xlat(char const *start, char const *end)
Skip an xlat expression.
Definition: cf_file.c:1220
CONF_ITEM *(* cf_process_func_t)(cf_stack_t *)
Definition: cf_file.c:2138
static CONF_ITEM * process_subrequest(cf_stack_t *stack)
Definition: cf_file.c:1774
static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
Definition: cf_file.c:549
static int8_t filename_cmp(void const *one, void const *two)
Definition: cf_file.c:874
int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
Definition: cf_file.c:3141
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 lineno
line in that filename
Definition: cf_file.c:97
int cf_file_read(CONF_SECTION *cs, char const *filename)
Definition: cf_file.c:3010
cf_stack_file_t
Definition: cf_file.c:82
@ CF_STACK_FILE
Definition: cf_file.c:83
static const bool terminal_end_section[UINT8_MAX+1]
Definition: cf_file.c:1340
static size_t conf_property_name_len
Definition: cf_file.c:80
static fr_table_num_sorted_t const conf_property_name[]
Definition: cf_file.c:76
int cf_section_pass2(CONF_SECTION *cs)
Definition: cf_file.c:757
bool from_dir
this file was read from $include foo/
Definition: cf_file.c:127
static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, fr_token_t t)
Definition: cf_file.c:3092
static char const parse_tabs[]
Definition: cf_file.c:3090
CONF_SECTION * special
map / update section
Definition: cf_file.c:122
static int cf_file_include(cf_stack_t *stack)
Definition: cf_file.c:2796
static uid_t conf_check_uid
Definition: cf_file.c:67
static gid_t conf_check_gid
Definition: cf_file.c:68
static int cf_get_token(CONF_SECTION *parent, char const **ptr_p, fr_token_t *token, char *buffer, size_t buflen, char const *filename, int lineno)
Definition: cf_file.c:820
static int8_t _inode_cmp(void const *one, void const *two)
Definition: cf_file.c:540
static int cf_file_fill(cf_stack_t *stack)
Definition: cf_file.c:2692
char const * ptr
current parse pointer
Definition: cf_file.c:140
char const * filename
Definition: cf_file.c:870
void cf_file_check_user(uid_t uid, gid_t gid)
Set the euid/egid used when performing file checks.
Definition: cf_file.c:3084
static int add_section_pair(CONF_SECTION **parent, char const **attr, char const *dot, char *buffer, size_t buffer_len, char const *filename, int lineno)
Definition: cf_file.c:1992
enum conf_property CONF_PROPERTY
static fr_table_ptr_sorted_t unlang_keywords[]
Definition: cf_file.c:2129
char ** buff
buffers for reading / parsing
Definition: cf_file.c:137
CONF_SECTION * parent
which started this file
Definition: cf_file.c:120
static int process_template(cf_stack_t *stack)
Definition: cf_file.c:1149
size_t bufsize
size of the buffers
Definition: cf_file.c:138
static int cf_pair_write(FILE *fp, CONF_PAIR *cp)
Definition: cf_file.c:3125
static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *ptr, bool required, bool relative)
Definition: cf_file.c:885
void cf_file_free(CONF_SECTION *cs)
Definition: cf_file.c:3069
static CONF_ITEM * process_if(cf_stack_t *stack)
Definition: cf_file.c:1521
#define MAX_STACK
Definition: cf_file.c:92
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition: cf_file.c:3206
static const bool terminal_end_line[UINT8_MAX+1]
Definition: cf_file.c:1344
char const * filename
filename we're reading
Definition: cf_file.c:96
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
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
CONF_SECTION * cs
CONF_SECTION associated with the file.
Definition: cf_priv.h:127
CONF_ITEM item
Common set of fields.
Definition: cf_priv.h:90
CONF_ITEM * parent
Parent.
Definition: cf_priv.h:56
fr_token_t name2_quote
The type of quoting around name2.
Definition: cf_priv.h:95
char const * name2
Second name token. Given foo bar {} would be bar.
Definition: cf_priv.h:93
bool allow_locals
allow local variables
Definition: cf_priv.h:105
int argc
number of additional arguments
Definition: cf_priv.h:97
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
int allow_unlang
depth at which we allow unlang
Definition: cf_priv.h:103
fr_token_t * argv_quote
Definition: cf_priv.h:99
fr_token_t op
Operator e.g. =, :=.
Definition: cf_priv.h:76
CONF_ITEM item
Common set of fields.
Definition: cf_priv.h:71
bool pass2
do expansion in pass2.
Definition: cf_priv.h:80
char const * filename
The file the config item was parsed from.
Definition: cf_priv.h:64
struct stat buf
stat about the file
Definition: cf_priv.h:128
CONF_SECTION * template
Definition: cf_priv.h:107
char const * filename
name of the file
Definition: cf_priv.h:126
@ 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
char const ** argv
additional arguments
Definition: cf_priv.h:98
fr_token_t lhs_quote
Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition: cf_priv.h:77
int lineno
The line number the config item began on.
Definition: cf_priv.h:63
CONF_ITEM_TYPE type
Whether the config item is a config_pair, conf_section or cf_data.
Definition: cf_priv.h:61
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_SECTION * cf_section_find_parent(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a parent CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:1039
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
CONF_SECTION * cf_section_find_in_parent(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a section in the lineage of a CONF_SECTION which matches a specific name1 and optionally name2.
Definition: cf_util.c:1012
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_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
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
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:649
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition: cf_util.c:583
CONF_SECTION * cf_section_dup(TALLOC_CTX *ctx, CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
Definition: cf_util.c:894
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_dup(CONF_SECTION *parent, CONF_PAIR *cp)
Duplicate a CONF_PAIR.
Definition: cf_util.c:1261
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
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_lineno(_cf)
Definition: cf_util.h:101
#define cf_data_add(_cf, _data, _name, _free)
Definition: cf_util.h:231
#define cf_data_find(_cf, _type, _name)
Definition: cf_util.h:220
#define cf_lineno_set(_ci, _lineno)
Definition: cf_util.h:128
#define cf_root(_cf)
Definition: cf_util.h:95
#define cf_parent(_cf)
Definition: cf_util.h:98
#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_filename_set(_ci, _filename)
Definition: cf_util.h:125
#define cf_log_warn(_cf, _fmt,...)
Definition: cf_util.h:266
#define cf_log_debug(_cf, _fmt,...)
Definition: cf_util.h:268
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:154
static char const * spaces
Definition: dependency.c:364
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
Test enumeration values.
Definition: dict_test.h:92
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
Definition: file.c:393
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
Definition: heap.c:322
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition: heap.c:146
unsigned int fr_heap_index_t
Definition: heap.h:80
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition: heap.h:100
#define FR_HEAP_INDEX_INVALID
Definition: heap.h:83
The main heap structure.
Definition: heap.h:66
talloc_free(reap)
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
static char * stack[MAX_STACK]
Definition: radmin.c:158
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define UINT8_MAX
Definition: merged_model.c:32
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition: misc.h:59
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:36
void fr_perm_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.
Definition: perm.c:403
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition: print.c:229
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
static char const * eol
Definition: radwho.c:47
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition: rb.c:576
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition: rb.h:246
The main red black tree structure.
Definition: rb.h:73
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition: rcode.h:50
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
#define check(_handle, _len_p)
static char const * name
#define FR_SBUFF_OUT(_start, _len_or_end)
bool at_runtime
Produce an ephemeral/runtime tmpl.
Definition: tmpl.h:353
ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen, fr_token_t *type, fr_dict_attr_t const **castda, bool require_regex, bool allow_xlat))
Preparse a string in preparation for passing it to tmpl_afrom_substr()
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
struct tmpl_rules_s tmpl_rules_t
Definition: tmpl.h:236
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:34
uint8_t allow_foreign
Allow arguments not found in dict_def.
Definition: tmpl.h:327
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
An element in a lexicographically sorted array of name to ptr mappings.
Definition: table.h:61
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 bool fr_list_assignment_op[T_TOKEN_LAST]
Definition: token.c:185
ssize_t fr_skip_string(char const *start, char const *end)
Skip a quoted string.
Definition: token.c:504
fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
Definition: token.c:447
fr_table_num_ordered_t const fr_tokens_table[]
Definition: token.c:33
const bool fr_str_tok[T_TOKEN_LAST]
Definition: token.c:231
int getword(char const **ptr, char *buf, int buflen, bool unescape)
Definition: token.c:438
enum fr_token fr_token_t
@ T_OP_SUB_EQ
Definition: token.h:70
@ T_INVALID
Definition: token.h:39
@ T_EOL
Definition: token.h:40
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_OP_AND_EQ
Definition: token.h:74
@ T_OP_CMP_TRUE
Definition: token.h:104
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
@ T_BACK_QUOTED_STRING
Definition: token.h:123
@ T_HASH
Definition: token.h:119
@ T_OP_SET
Definition: token.h:84
@ T_OP_NE
Definition: token.h:97
@ T_OP_ADD_EQ
Definition: token.h:69
@ T_OP_CMP_FALSE
Definition: token.h:105
@ T_OP_LSHIFT_EQ
Definition: token.h:77
@ T_OP_RSHIFT_EQ
Definition: token.h:76
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
@ T_OP_CMP_EQ
Definition: token.h:106
@ T_OP_LE
Definition: token.h:100
@ T_OP_GE
Definition: token.h:98
@ T_OP_GT
Definition: token.h:99
@ T_OP_OR_EQ
Definition: token.h:73
@ T_OP_LT
Definition: token.h:101
@ T_OP_PREPEND
Definition: token.h:85
close(uq->fd)
static fr_slen_t parent
Definition: pair.h:844
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
#define fr_strerror_const(_msg)
Definition: strerror.h:223
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition: types.c:31
static size_t char fr_sbuff_t size_t inlen
Definition: value.h:984
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.