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