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