The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: 1c7c969f1ab8835230d2fcb9e161cb2b692f94c9 $
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: 1c7c969f1ab8835230d2fcb9e161cb2b692f94c9 $")
32
33#include <sys/errno.h>
34
35#include <freeradius-devel/server/cf_file.h>
36#include <freeradius-devel/server/cf_priv.h>
37#include <freeradius-devel/server/log.h>
38#include <freeradius-devel/server/tmpl.h>
39#include <freeradius-devel/server/util.h>
40#include <freeradius-devel/server/virtual_servers.h>
41#include <freeradius-devel/util/debug.h>
42#include <freeradius-devel/util/file.h>
43#include <freeradius-devel/util/misc.h>
44#include <freeradius-devel/util/perm.h>
45#include <freeradius-devel/util/skip.h>
46#include <freeradius-devel/util/md5.h>
47
48#ifdef HAVE_DIRENT_H
49#endif
50
51#ifdef HAVE_GLOB_H
52#endif
53
54#ifdef HAVE_SYS_STAT_H
55#endif
56
57#include <fcntl.h>
58
59#include <freeradius-devel/server/main_config.h>
60
61bool check_config = false;
62static uid_t conf_check_uid = (uid_t)-1;
63static gid_t conf_check_gid = (gid_t)-1;
64
70
72 { L("instance"), CONF_PROPERTY_INSTANCE },
73 { L("name"), CONF_PROPERTY_NAME }
74};
76
78 { L("accounting"), true },
79 { L("add"), true },
80 { L("authenticate"), true },
81 { L("clear"), true },
82 { L("decode"), true },
83 { L("deny"), true },
84 { L("encode"), true },
85 { L("error"), true },
86 { L("establish"), true },
87 { L("fail"), true },
88 { L("finally"), true },
89 { L("load"), true },
90 { L("new"), true },
91 { L("recv"), true },
92 { L("send"), true },
93 { L("store"), true },
94 { L("verify"), true },
95};
97
98typedef enum : uint8_t {
100#ifdef HAVE_DIRENT_H
101 CF_STACK_DIR,
102#endif
103#ifdef HAVE_GLOB_H
104 CF_STACK_GLOB
105#endif
107
108#define MAX_STACK (32)
109typedef struct {
111
112 char const *filename; //!< filename we're reading
113 int lineno; //!< line in that filename
114
115 union {
116 struct {
117 FILE *fp; //!< FP we're reading
118 };
119
120#ifdef HAVE_DIRENT_H
121 struct {
122 fr_heap_t *heap; //!< sorted heap of files
123 char *directory; //!< directory name we're reading
124 };
125#endif
126
127#ifdef HAVE_GLOB_H
128 struct {
129 size_t gl_current;
130 glob_t glob; //! reading glob()
131 bool required;
132 };
133#endif
134 };
135
136 CONF_SECTION *parent; //!< which started this file
137 CONF_SECTION *current; //!< sub-section we're reading
138 CONF_SECTION *at_reference; //!< was this thing an @foo ?
139 int at_reference_braces; //!< braces when we found this thing
140
142 bool from_dir; //!< this file was read from $include foo/
144
145/*
146 * buff[0] is the data we read from the file
147 * buff[1] is name
148 * buff[2] is name2 OR value for pair
149 * buff[3] is a temporary buffer
150 */
151typedef struct {
152 char **buff; //!< buffers for reading / parsing
153 size_t bufsize; //!< size of the buffers
154 int depth; //!< stack depth
155 char const *ptr; //!< current parse pointer
156 char *fill; //!< where we start filling the buffer from
157 cf_stack_frame_t frame[MAX_STACK]; //!< stack frames
158} cf_stack_t;
159
160/*
161 * Open and read a file.
162 */
163static int cf_expand_file(char const *cf, int lineno, char name[static PATH_MAX],
164 char **p_p, char const **ptr_p, char *output, size_t outsize,
165 bool raw)
166{
167 int fd;
168 size_t room;
169 ssize_t len;
170 char *p, *next;
171 char const *ptr;
172
173 /*
174 * Note that we do NOT recursively expand the value. It has to be a hard-coded string.
175 *
176 * We do NOT do any sanity checks on the value. i.e. filenames beginning with '/' are allowed,
177 * as are files with "../../". The value here comes from the configuration files, and only the
178 * administrator has write access to them.
179 */
180 strlcpy(name, cf, PATH_MAX);
181 p = strrchr(name, '/');
182 if (p) {
183 p++;
184 } else {
185 p = name;
186 }
187
188 ptr = *ptr_p;
189
190 /*
191 * Look for trailing '}', and log a
192 * warning for anything that doesn't match,
193 * and exit with a fatal error.
194 */
195 next = strchr(ptr, '}');
196 if (next == NULL) {
197 *p = '\0';
198 ERROR("%s[%d]: File expansion missing }",
199 cf, lineno);
200 return -1;
201 }
202
203 /*
204 * Can't really happen because input lines are
205 * capped at 8k, which is sizeof(name)
206 */
207 if ((next - ptr) >= (name + PATH_MAX - p)) {
208 ERROR("%s[%d]: File name is too large",
209 cf, lineno);
210 return -1;
211 }
212
213 memcpy(p, ptr, next - ptr);
214 p[next - ptr] = '\0';
215
216 fd = open(name, O_RDONLY);
217 if (fd < 0) {
218 ERROR("%s[%d]: Failed opening %s: %s",
219 cf, lineno, name, strerror(errno));
220 return -1;
221 }
222
223 p = *p_p;
224 room = (output + outsize) - p;
225 fr_assert(room > 0);
226
227 /*
228 * Read the raw data.
229 */
230 len = read(fd, p, room);
231 if (len < 0) {
232 ERROR("%s[%d]: Failed reading %s: %s",
233 cf, lineno, name, strerror(errno));
234 close(fd);
235 return -1;
236 }
237 close(fd);
238
239 if (!len) {
240 ERROR("%s[%d]: Failed reading %s: the file is empty",
241 cf, lineno, name);
242 return -1;
243 }
244
245 /*
246 * We don't know whether or not it was
247 * truncated, so we just error out.
248 */
249 if ((size_t) len >= room) {
250 ERROR("%s[%d]: Too much data in %s: did not read the entire file",
251 cf, lineno, name);
252 return -1;
253 }
254
255 /*
256 * If we're not reading the raw file, return only the first line.
257 */
258 if (!raw) {
259 char *q, *end = p + len;
260
261 while (p < end) {
262 if (*p >= ' ') {
263 p++;
264 continue;
265 }
266
267 break;
268 }
269
270 /*
271 * Strip trailing CR/LF.
272 */
273 for (q = p; q < end; q++) {
274 if (*q >= ' ') break;
275
276 *q = '\0';
277 }
278
279 if (q != end) {
280 ERROR("%s[%d]: Too much data in %s: expected one line of text, found multiple lines in the file",
281 cf, lineno, name);
282 return -1;
283 }
284 } else {
285 p += len;
286 }
287
288 *ptr_p = next + 1;
289 *p_p = p;
290
291 return 0;
292}
293
294/*
295 * Expand the variables in an input string.
296 *
297 * Input and output should be two different buffers, as the
298 * output may be longer than the input.
299 */
300char const *cf_expand_variables(char const *cf, int lineno,
301 CONF_SECTION *outer_cs,
302 char *output, size_t outsize,
303 char const *input, ssize_t inlen, bool *soft_fail, bool soft_fail_env)
304{
305 char *p;
306 char const *end, *next, *ptr;
307 CONF_SECTION const *parent_cs;
308 char name[PATH_MAX];
309
310 if (soft_fail) *soft_fail = false;
311
312 /*
313 * Utilities (radjson2conf rebuilding a fragment from JSON)
314 * can opt out of variable resolution so values containing
315 * `${...}` round-trip verbatim instead of failing against
316 * an incomplete tree.
317 */
318 if (!_cf_expand_variables()) {
319 size_t want = inlen >= 0 ? (size_t)inlen : strlen(input);
320 if (want >= outsize) want = outsize - 1;
321 memcpy(output, input, want);
322 output[want] = '\0';
323 return output;
324 }
325
326 /*
327 * Find the master parent conf section.
328 * We can't use main_config->root_cs, because we're in the
329 * process of re-building it, and it isn't set up yet...
330 */
331 parent_cs = cf_root(outer_cs);
332
333 p = output;
334 ptr = input;
335
336 if (inlen < 0) {
337 end = NULL;
338 } else {
339 end = input + inlen;
340 }
341
342 /*
343 * Note that this CAN go over "end" if the input string
344 * is malformed. e.g. pass "${foo.bar}", and pass
345 * "inlen=5". Well, too bad.
346 */
347 while (*ptr && (!end || (ptr < end))) {
348 /*
349 * Ignore anything other than "${"
350 */
351 if ((*ptr == '$') && (ptr[1] == '{')) {
352 CONF_ITEM *ci;
353 CONF_PAIR *cp;
354 char *q;
356
357 len = fr_skip_xlat(ptr, end);
358 if (len <= 0) {
359 ERROR("%s[%d]: Failed parsing variable expansion '%s''",
360 cf, lineno, input);
361 return NULL;
362 }
363
364 next = ptr + len;
365 ptr += 2;
366
367 /*
368 * Can't really happen because input lines are
369 * capped at 8k, which is sizeof(name)
370 */
371 if ((size_t) len >= sizeof(name)) {
372 ERROR("%s[%d]: Reference string is too large",
373 cf, lineno);
374 return NULL;
375 }
376
377 memcpy(name, ptr, len - 3);
378 name[len - 3] = '\0';
379
380 /*
381 * Read configuration value from a file.
382 *
383 * Note that this is "read binary data", and the contents aren't stripped of
384 * CRLF.
385 */
386 if (name[0] == '/') {
387 int fd = open(name, O_RDONLY);
388 struct stat buf;
389
390 if (fd < 0) {
391 ERROR("%s[%d]: Reference \"${%s}\" failed opening file - %s", cf, lineno, name, fr_syserror(errno));
392 return NULL;
393 }
394
395 if (fstat(fd, &buf) < 0) {
396 fail_fd:
397 close(fd);
398 ERROR("%s[%d]: Reference \"${%s}\" failed reading file - %s", cf, lineno, name, fr_syserror(errno));
399 return NULL;
400 }
401
402 if (buf.st_size >= ((output + outsize) - p)) {
403 close(fd);
404 ERROR("%s[%d]: Reference \"${%s}\" file is too large (%zu >= %zu)", cf, lineno, name,
405 (size_t) buf.st_size, (size_t) ((output + outsize) - p));
406 return NULL;
407 }
408
409 len = read(fd, p, (output + outsize) - p - 1);
410 if (len < 0) goto fail_fd;
411
412 close(fd);
413 p += len;
414 *p = '\0';
415 ptr = next;
416 goto check_eos;
417 }
418
419 q = strchr(name, ':');
420 if (q) {
421 *(q++) = '\0';
422 }
423
424 ci = cf_reference_item(parent_cs, outer_cs, name);
425 if (!ci) {
426 if (soft_fail) *soft_fail = true;
427 PERROR("%s[%d]: Failed finding reference \"${%s}\"", cf, lineno, name);
428 return NULL;
429 }
430
431 /*
432 * The expansion doesn't refer to another item or section
433 * it's the property of a section.
434 */
435 if (q) {
436 CONF_SECTION *find;
437 char const *f;
438 size_t flen;
439
440 if (ci->type != CONF_ITEM_SECTION) {
441 ERROR("%s[%d]: Can only reference properties of sections", cf, lineno);
442 return NULL;
443 }
444
445 find = cf_item_to_section(ci);
448 f = find->name1;
449 break;
450
452 f = find->name2 ? find->name2 : find->name1;
453 break;
454
455 default:
456 ERROR("%s[%d]: Invalid property '%s'", cf, lineno, q);
457 return NULL;
458 }
459
460 flen = talloc_strlen(f);
461 if ((p + flen) >= (output + outsize)) goto too_long;
462
463 memcpy(p, f, flen);
464 p += flen;
465 ptr = next;
466
467 } else if (ci->type == CONF_ITEM_PAIR) {
468 /*
469 * Substitute the value of the variable.
470 */
471 cp = cf_item_to_pair(ci);
472
473 /*
474 * If the thing we reference is
475 * marked up as being expanded in
476 * pass2, don't expand it now.
477 * Let it be expanded in pass2.
478 */
479 if (cp->pass2) {
480 if (soft_fail) *soft_fail = true;
481
482 ERROR("%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
483 cf, lineno, input);
484 return NULL;
485 }
486
487 if (!cp->value) {
488 ERROR("%s[%d]: Reference \"%s\" has no value",
489 cf, lineno, input);
490 return NULL;
491 }
492
493 if (p + strlen(cp->value) >= output + outsize) {
494 ERROR("%s[%d]: Reference \"%s\" is too long",
495 cf, lineno, input);
496 return NULL;
497 }
498
499 strcpy(p, cp->value);
500 cp->item.referenced = true;
501 p += strlen(p);
502 ptr = next;
503
504 } else if (ci->type == CONF_ITEM_SECTION) {
505 CONF_SECTION *subcs;
506 CONF_ITEM *ci_p;
507
508 /*
509 * We can't refer to any parent, otherwise we have an infinite loop.
510 */
511 for (ci_p = &outer_cs->item; ci_p != NULL; ci_p = ci_p->parent) {
512 if (ci_p == ci) {
513 ERROR("%s[%d]: Cannot reference different item in same section", cf, lineno);
514 return NULL;
515 }
516 }
517
518 /*
519 * Copy the section instead of
520 * referencing it.
521 */
522 subcs = cf_item_to_section(ci);
523 subcs = cf_section_dup(outer_cs, outer_cs, subcs,
524 cf_section_name1(subcs), cf_section_name2(subcs),
525 false);
526 if (!subcs) {
527 ERROR("%s[%d]: Failed copying reference %s", cf, lineno, name);
528 return NULL;
529 }
530
531 cf_filename_set(subcs, ci->filename);
532 cf_lineno_set(subcs, ci->lineno);
533
534 ptr = next;
535
536 } else {
537 ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, lineno, input);
538 return NULL;
539 }
540 } else if (strncmp(ptr, "$ENV{", 5) == 0) {
541 char *env;
542
543 ptr += 5;
544
545 /*
546 * Look for trailing '}', and log a
547 * warning for anything that doesn't match,
548 * and exit with a fatal error.
549 */
550 next = strchr(ptr, '}');
551 if (next == NULL) {
552 *p = '\0';
553 ERROR("%s[%d]: Environment variable expansion missing }",
554 cf, lineno);
555 return NULL;
556 }
557
558 /*
559 * Can't really happen because input lines are
560 * capped at 8k, which is sizeof(name)
561 */
562 if ((size_t) (next - ptr) >= sizeof(name)) {
563 ERROR("%s[%d]: Environment variable name is too large",
564 cf, lineno);
565 return NULL;
566 }
567
568 memcpy(name, ptr, next - ptr);
569 name[next - ptr] = '\0';
570
571 /*
572 * Get the environment variable.
573 * If none exists, then make it an empty string.
574 */
575 env = getenv(name);
576 if (!env) {
577 if (!soft_fail_env) {
578 ERROR("%s[%d]: Invalid reference to missing environment variable $ENV{%s}",
579 cf, lineno, name);
580 return NULL;
581 }
582
583 *name = '\0';
584 env = name;
585 }
586
587 if (p + strlen(env) >= output + outsize) {
588 ERROR("%s[%d]: Reference \"%s\" is too long",
589 cf, lineno, input);
590 return NULL;
591 }
592
593 strcpy(p, env);
594 p += strlen(p);
595 ptr = next + 1;
596
597 } else if (strncmp(ptr, "$VALUE{", 7) == 0) {
598 ptr += 7;
599
600 if (cf_expand_file(cf, lineno, name, &p, &ptr, output, outsize, false) < 0) return NULL;
601
602 } else if (strncmp(ptr, "$FILE{", 6) == 0) {
603 ptr += 6;
604
605 if (cf_expand_file(cf, lineno, name, &p, &ptr, output, outsize, true) < 0) return NULL;
606
607 } else {
608 /*
609 * Copy it over verbatim.
610 */
611 *(p++) = *(ptr++);
612 }
613
614 check_eos:
615 if (p >= (output + outsize)) {
616 too_long:
617 ERROR("%s[%d]: Reference \"%s\" is too long",
618 cf, lineno, input);
619 return NULL;
620 }
621 } /* loop over all of the input string. */
622
623 *p = '\0';
624
625 return output;
626}
627
628/*
629 * Merge the template so everything else "just works".
630 */
631static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
632{
633 if (!cs || !template) return true;
634
635 cs->template = NULL;
636
637 /*
638 * Walk over the template, adding its' entries to the
639 * current section. But only if the entries don't
640 * already exist in the current section.
641 */
642 cf_item_foreach(&template->item, ci) {
643 if (ci->type == CONF_ITEM_PAIR) {
644 CONF_PAIR *cp1, *cp2;
645
646 /*
647 * It exists, don't over-write it.
648 */
649 cp1 = cf_item_to_pair(ci);
650 if (cf_pair_find(cs, cp1->attr)) {
651 continue;
652 }
653
654 /*
655 * Create a new pair with all of the data
656 * of the old one.
657 */
658 cp2 = cf_pair_dup(cs, cp1, true);
659 if (!cp2) return false;
660
661 cf_filename_set(cp2, cp1->item.filename);
662 cf_lineno_set(cp2, cp1->item.lineno);
663 continue;
664 }
665
666 if (ci->type == CONF_ITEM_SECTION) {
667 CONF_SECTION *subcs1, *subcs2;
668
669 subcs1 = cf_item_to_section(ci);
670 fr_assert(subcs1 != NULL);
671
672 subcs2 = cf_section_find(cs, subcs1->name1, subcs1->name2);
673 if (subcs2) {
674 /*
675 * sub-sections get merged.
676 */
677 if (!cf_template_merge(subcs2, subcs1)) {
678 return false;
679 }
680 continue;
681 }
682
683 /*
684 * Our section doesn't have a matching
685 * sub-section. Copy it verbatim from
686 * the template.
687 */
688 subcs2 = cf_section_dup(cs, cs, subcs1,
689 cf_section_name1(subcs1), cf_section_name2(subcs1),
690 false);
691 if (!subcs2) return false;
692
693 cf_filename_set(subcs2, subcs1->item.filename);
694 cf_lineno_set(subcs2, subcs1->item.lineno);
695 continue;
696 }
697
698 /* ignore everything else */
699 }
700
701 return true;
702}
703
704/*
705 * Functions for tracking files by inode
706 */
707static fr_cmp_ret_t _inode_cmp(void const *one, void const *two)
708{
709 cf_file_t const *a = one, *b = two;
710
711 CMP_RETURN(a, b, buf.st_dev);
712
713 return CMP(a->buf.st_ino, b->buf.st_ino);
714}
715
716static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
717{
719 CONF_SECTION *top;
720 fr_rb_tree_t *tree;
721 FILE *fp;
722
723 top = cf_root(cs);
724 tree = cf_data_value(cf_data_find(top, fr_rb_tree_t, "filename"));
725 fr_assert(tree);
726
727 /*
728 * If we're including a wildcard directory, then ignore
729 * any files the users has already explicitly loaded in
730 * that directory.
731 */
732 if (from_dir) {
733 cf_file_t my_file;
734 char const *r;
735 int fd, my_fd;
736
737 my_file.cs = cs;
738 my_file.filename = filename;
739
740 /*
741 * Find and open the directory containing filename so we can use
742 * the "at"functions to avoid time of check/time of use insecurities.
743 */
744 if (fr_dirfd(&my_fd, &r, filename) < 0) {
745 ERROR("Failed to open directory containing %s", filename);
746 return -1;
747 }
748
749 if (fstatat(my_fd, r, &my_file.buf, 0) < 0) {
750 if (my_fd != AT_FDCWD) close(my_fd);
751 goto error;
752 }
753
754 fr_rb_find((void **)&file, tree, &my_file);
755
756 /*
757 * The file was previously read by including it
758 * explicitly. After it was read, we have a
759 * $INCLUDE of the directory it is in. In that
760 * case, we ignore the file.
761 *
762 * However, if the file WAS read from a wildcard
763 * $INCLUDE directory, then we read it again.
764 */
765 if (file && !file->from_dir) {
766 if (my_fd != AT_FDCWD) close(my_fd);
767 return 1;
768 }
769
770 fd = openat(my_fd, r, O_RDONLY, 0);
771 if (my_fd != AT_FDCWD) close(my_fd);
772 if (fd < 0) goto error;
773 fp = fdopen(fd, "r");
774 } else {
775 fp = fopen(filename, "r");
776 }
777
778 if (DEBUG_ENABLED2) cf_log_debug(cs, "including configuration file %s", filename);
779
780 if (!fp) {
781 error:
782 ERROR("Unable to open file \"%s\": %s", filename, fr_syserror(errno));
783 return -1;
784 }
785
786 MEM(file = talloc(tree, cf_file_t));
787
788 file->filename = talloc_strdup(file, filename); /* The rest of the code expects this to be a talloced buffer */
789 file->cs = cs;
790 file->from_dir = from_dir;
791
792 if (fstat(fileno(fp), &file->buf) == 0) {
793#ifdef S_IWOTH
794 if ((file->buf.st_mode & S_IWOTH) != 0) {
795 ERROR("Configuration file %s is globally writable. "
796 "Refusing to start due to insecure configuration.", filename);
797
798 fclose(fp);
800 return -1;
801 }
802#endif
803 }
804
805 /*
806 * We can include the same file twice. e.g. when it
807 * contains common definitions, such as for SQL.
808 *
809 * Though the admin should really use templates for that.
810 */
811 if (fr_rb_insert(tree, file) != 0) talloc_free(file);
812
813 *fp_p = fp;
814 return 0;
815}
816
817/** Set the euid/egid used when performing file checks
818 *
819 * Sets the euid, and egid used when cf_file_check is called to check
820 * permissions on conf items of type #CONF_FLAG_FILE_READABLE
821 *
822 * @note This is probably only useful for the freeradius daemon itself.
823 *
824 * @param uid to set, (uid_t)-1 to use current euid.
825 * @param gid to set, (gid_t)-1 to use current egid.
826 */
827void cf_file_check_set_uid_gid(uid_t uid, gid_t gid)
828{
829 if (uid != (uid_t) -1) conf_check_uid = uid;
830 if (gid != (gid_t) -1) conf_check_gid = gid;
831}
832
833/** Perform an operation with the effect/group set to conf_check_gid and conf_check_uid
834 *
835 * @param filename CONF_PAIR for the file being checked
836 * @param cb callback function to perform the check
837 * @param uctx user context for the callback
838 * @return
839 * - CF_FILE_OTHER_ERROR if there was a problem modifying permissions
840 * - The return value from the callback
841 */
843 cf_file_check_err_t (*cb)(char const *filename, void *uctx), void *uctx)
844{
845 int ret;
846
847 uid_t euid = (uid_t) -1;
848 gid_t egid = (gid_t) -1;
849
850 if ((conf_check_gid != (gid_t) -1) && ((egid = getegid()) != conf_check_gid)) {
851 if (setegid(conf_check_gid) < 0) {
852 fr_strerror_printf("Failed setting effective group ID (%d) for file check: %s",
853 (int) conf_check_gid, fr_syserror(errno));
854 return CF_FILE_OTHER_ERROR;
855 }
856 }
857 if ((conf_check_uid != (uid_t) -1) && ((euid = geteuid()) != conf_check_uid)) {
858 if (seteuid(conf_check_uid) < 0) {
859 fr_strerror_printf("Failed setting effective user ID (%d) for file check: %s",
860 (int) conf_check_uid, fr_syserror(errno));
861
862 restore_gid:
863 if ((conf_check_gid != egid) &&
864 (setegid(conf_check_gid) < 0)) {
865 fr_strerror_printf_push("Failed resetting effective group ID (%d) for file check: %s",
866 (int) conf_check_gid, fr_syserror(errno));
867 }
868
869 return CF_FILE_OTHER_ERROR;
870 }
871 }
872 ret = cb(filename, uctx);
873 if (conf_check_uid != euid) {
874 if (seteuid(euid) < 0) {
875 fr_strerror_printf("Failed restoring effective user ID (%d) after file check: %s",
876 (int) euid, fr_syserror(errno));
877 goto restore_gid;
878 }
879 }
880 if (conf_check_gid != egid) {
881 if (setegid(egid) < 0) {
882 fr_strerror_printf("Failed restoring effective group ID (%d) after file check: %s",
883 (int) egid, fr_syserror(errno));
884 return CF_FILE_OTHER_ERROR;
885 }
886 }
887
888 return ret;
889}
890
891/** Check if we can connect to a unix socket
892 *
893 * @param[in] filename CONF_PAIR for the unix socket path
894 * @param[in] uctx user context, not used
895 * @return
896 * - CF_FILE_OK if the socket exists and is a socket.
897 * - CF_FILE_NO_EXIST if the file doesn't exist.
898 * - CF_FILE_NO_PERMISSION if the file exists but is not accessible.
899 * - CF_FILE_NO_UNIX_SOCKET if the file exists but is not a socket.
900 * - CF_FILE_OTHER_ERROR any other error.
901 */
903{
904 int fd;
906
907 struct sockaddr_un addr = { .sun_family = AF_UNIX };
908
910
911 if (talloc_strlen(filename) >= sizeof(addr.sun_path)) {
912 fr_strerror_printf("Socket path \"%s\" too long", filename);
913 return CF_FILE_OTHER_ERROR;
914 }
915
916 strlcpy(addr.sun_path, filename, sizeof(addr.sun_path));
917
918 fd = socket(AF_UNIX, SOCK_STREAM, 0);
919 if (fd < 0) {
920 fr_strerror_printf("Failed checking permissions for \"%s\": %s",
921 filename, fr_syserror(errno));
922 return CF_FILE_OTHER_ERROR;
923 }
924 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
925 fr_strerror_printf("Failed setting non-blocking mode for socket %s: %s",
926 filename, fr_syserror(errno));
927 close(fd);
928 return CF_FILE_OTHER_ERROR;
929 }
930
931 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
932 switch (errno) {
933 case EINPROGRESS: /* This is fine */
934 break;
935
936 case ENOENT:
937 fr_strerror_printf("Socket path \"%s\" does not exist", filename);
938 ret = CF_FILE_NO_EXIST;
939 break;
940
941 case EACCES:
942 fr_perm_file_error(errno);
943 fr_strerror_printf_push("Socket path \"%s\" exists but is not accessible", filename);
945 break;
946
947 case ENOTSOCK:
948 fr_strerror_printf("File \"%s\" is not a socket", filename);
950 break;
951
952 default:
953 fr_strerror_printf("Failed connecting to socket %s: %s", filename, fr_syserror(errno));
955 break;
956 }
957 }
958
959 close(fd);
960
961 return ret;
962}
963
964/** Check if file exists, and is a socket
965 *
966 * @param[in] filename CONF_PAIR for the unix socket path
967 * @param[in] uctx user context, not used
968 * @return
969 * - CF_FILE_OK if the socket exists and is a socket.
970 * - CF_FILE_NO_EXIST if the file doesn't exist.
971 * - CF_FILE_NO_PERMISSION if the file exists but is not accessible.
972 * - CF_FILE_NO_UNIX_SOCKET if the file exists but is not a socket.
973 * - CF_FILE_OTHER_ERROR any other error.
974 */
975cf_file_check_err_t cf_file_check_unix_perm(char const *filename, UNUSED void *uctx)
976{
977 struct stat buf;
978
980
981 if (stat(filename, &buf) < 0) {
982 switch (errno) {
983 case ENOENT:
984 fr_strerror_printf("Socket path \"%s\" does not exist", filename);
985 return CF_FILE_NO_EXIST;
986
987 case EPERM:
988 case EACCES:
989 fr_perm_file_error(errno);
990 fr_strerror_printf_push("Socket path \"%s\" exists but is not accessible: %s",
991 filename, fr_syserror(errno));
993
994 default:
995 fr_strerror_printf("Unable to stat socket \"%s\": %s", filename, fr_syserror(errno));
996 return CF_FILE_OTHER_ERROR;
997 }
998 }
999
1000 if (!S_ISSOCK(buf.st_mode)) {
1001 fr_strerror_printf("File \"%s\" is not a socket", filename);
1003 }
1004
1005 return CF_FILE_OK;
1006}
1007
1008/** Callback for cf_file_check to open a file and check permissions.
1009 *
1010 * This is used to check if a file exists, and is readable by the
1011 * unprivileged user/group.
1012 *
1013 * @param filename currently being processed.
1014 * @param uctx user context, which is a pointer to cf_file_t
1015 * @return
1016 * - CF_FILE_OK if the file exists and is readable.
1017 * - CF_FILE_NO_EXIST if the file does not exist.
1018 * - CF_FILE_NO_PERMISSION if the file exists but is not accessible.
1019 * - CF_FILE_OTHER_ERROR if there was any other error.
1020 */
1021cf_file_check_err_t cf_file_check_open_read(char const *filename, void *uctx)
1022{
1023 int fd;
1024 cf_file_t *file = uctx;
1025
1027
1028 fd = open(filename, O_RDONLY);
1029 if (fd < 0) {
1030 int our_errno;
1031
1032 error:
1033 /*
1034 * Capture errno before close(), which may overwrite
1035 * it. The fstat() failure below arrives here with
1036 * the file still open.
1037 */
1038 our_errno = errno;
1039 if (fd >= 0) close(fd);
1040
1041 switch (our_errno) {
1042 case ENOENT:
1043 fr_strerror_printf("File \"%s\" does not exist", filename);
1044 return CF_FILE_NO_EXIST;
1045
1046 case EPERM:
1047 case EACCES:
1048 fr_perm_file_error(our_errno);
1049 fr_strerror_printf_push("File \"%s\" exists but is not accessible: %s",
1050 filename, fr_syserror(our_errno));
1051 return CF_FILE_NO_PERMISSION;
1052
1053 default:
1054 fr_strerror_printf("Unable to open file \"%s\": %s", filename, fr_syserror(our_errno));
1055 return CF_FILE_OTHER_ERROR;
1056
1057 }
1058 }
1059
1060 if (file && fstat(fd, &file->buf) < 0) goto error;
1061
1062 close(fd);
1063 return CF_FILE_OK;
1064}
1065
1066/** Do some checks on the file as an "input" file. i.e. one read by a module.
1067 *
1068 * @note Must be called with super user privileges.
1069 *
1070 * @param cp currently being processed.
1071 * @param check_perms If true - will return error if file is world readable,
1072 * or not readable by the unprivileged user/group.
1073 * @return
1074 * - CF_FILE_OK if the socket exists and is a socket.
1075 * - CF_FILE_NO_EXIST if the file doesn't exist.
1076 * - CF_FILE_NO_PERMISSION if the file exists but is not accessible.
1077 * - CF_FILE_OTHER_ERROR any other error.
1078 */
1080{
1081 cf_file_t *file;
1082 CONF_SECTION *top;
1083 fr_rb_tree_t *tree;
1084 char const *filename = cf_pair_value(cp);
1086
1087 top = cf_root(cp);
1088 tree = cf_data_value(cf_data_find(top, fr_rb_tree_t, "filename"));
1089 if (!tree) return CF_FILE_OTHER_ERROR;
1090
1091 file = talloc(tree, cf_file_t);
1092 if (!file) return CF_FILE_OTHER_ERROR;
1093
1094 file->filename = talloc_strdup(file, filename); /* The rest of the code expects this to be talloced */
1096
1097 if (!check_perms) {
1098 if (stat(filename, &file->buf) < 0) {
1099 fr_perm_file_error(errno); /* Write error and euid/egid to error buff */
1100 cf_log_perr(cp, "Unable to open file \"%s\"", filename);
1101 error:
1103 return CF_FILE_OTHER_ERROR;
1104 }
1106 return CF_FILE_OK;
1107 }
1108
1109 /*
1110 * This really does seem to be the simplest way
1111 * to check that the file can be read with the
1112 * euid/egid.
1113 */
1115 if (ret < 0) {
1116 cf_log_perr(cp, "Permissions check failed");
1117 goto error;
1118 }
1119#ifdef S_IWOTH
1120 if ((file->buf.st_mode & S_IWOTH) != 0) {
1121 cf_log_perr(cp, "Configuration file %s is globally writable. "
1122 "Refusing to start due to insecure configuration.", filename);
1124 return CF_FILE_OTHER_ERROR;
1125 }
1126#endif
1127
1128 /*
1129 * It's OK to include the same file twice...
1130 */
1131 if (fr_rb_insert(tree, file) != 0) talloc_free(file);
1132
1133 return CF_FILE_OK;
1134}
1135
1136/*
1137 * Do variable expansion in pass2.
1138 *
1139 * This is a breadth-first expansion. "deep
1140 */
1142{
1143 cf_item_foreach(&cs->item, ci) {
1144 char const *value;
1145 CONF_PAIR *cp;
1146 char buffer[8192];
1147
1148 if (ci->type != CONF_ITEM_PAIR) continue;
1149
1150 cp = cf_item_to_pair(ci);
1151 if (!cp->value || !cp->pass2) continue;
1152
1153 fr_assert((cp->rhs_quote == T_BARE_WORD) ||
1154 (cp->rhs_quote == T_HASH) ||
1157
1158 value = cf_expand_variables(ci->filename, ci->lineno, cs, buffer, sizeof(buffer), cp->value, -1, NULL,
1159 (cp->rhs_quote != T_BARE_WORD));
1160 if (!value) return -1;
1161
1162 if (!*value) {
1163 ERROR("%s[%d]: Empty filename in $INCLUDE", ci->filename, ci->lineno);
1164 return -1;
1165 }
1166
1168 cp->value = talloc_strdup(cp, value);
1169 }
1170
1171 cf_item_foreach(&cs->item, ci) {
1172 if (ci->type != CONF_ITEM_SECTION) continue;
1173
1174 if (cf_section_pass2(cf_item_to_section(ci)) < 0) return -1;
1175 }
1176
1177 return 0;
1178}
1179
1180
1181static char const *cf_local_file(char const *base, char const *filename,
1182 char *buffer, size_t bufsize)
1183{
1184 size_t dirsize;
1185 char *p;
1186
1187 strlcpy(buffer, base, bufsize);
1188
1189 p = strrchr(buffer, FR_DIR_SEP);
1190 if (!p) return filename;
1191 if (p[1]) { /* ./foo */
1192 p[1] = '\0';
1193 }
1194
1195 dirsize = (p - buffer) + 1;
1196
1197 if ((dirsize + strlen(filename)) >= bufsize) {
1198 return NULL;
1199 }
1200
1201 strlcpy(p + 1, filename, bufsize - dirsize);
1202
1203 return buffer;
1204}
1205
1206/*
1207 * Like gettoken(), but uses the new API which seems better for a
1208 * host of reasons.
1209 */
1210static int cf_get_token(CONF_SECTION *parent, char const **ptr_p, fr_token_t *token, char *buffer, size_t buflen,
1211 char const *filename, int lineno)
1212{
1213 char const *ptr = *ptr_p;
1214 ssize_t slen;
1215 char const *out;
1216 size_t outlen;
1217
1218 /*
1219 * Discover the string content, returning what kind of
1220 * string it is.
1221 *
1222 * Don't allow casts or regexes. But do allow bare
1223 * %{...} expansions.
1224 */
1225 slen = tmpl_preparse(&out, &outlen, ptr, strlen(ptr), token);
1226 if (slen <= 0) {
1227 char *spaces, *text;
1228
1229 fr_canonicalize_error(parent, &spaces, &text, slen, ptr);
1230
1231 ERROR("%s[%d]: %s", filename, lineno, text);
1232 ERROR("%s[%d]: %s^ - %s", filename, lineno, spaces, fr_strerror());
1233
1235 talloc_free(text);
1236 return -1;
1237 }
1238
1239 if ((size_t) slen >= buflen) {
1240 ERROR("%s[%d]: Name is too long", filename, lineno);
1241 return -1;
1242 }
1243
1244 /*
1245 * Unescape it or copy it verbatim as necessary.
1246 */
1247 if (!cf_expand_variables(filename, lineno, parent, buffer, buflen,
1248 out, outlen, NULL, (*token != T_BARE_WORD))) {
1249 return -1;
1250 }
1251
1252 ptr += slen;
1253 fr_skip_whitespace(ptr);
1254
1255 *ptr_p = ptr;
1256 return 0;
1257}
1258
1263
1264static fr_cmp_ret_t filename_cmp(void const *one, void const *two)
1265{
1266 int ret;
1267 cf_file_heap_t const *a = one;
1268 cf_file_heap_t const *b = two;
1269
1270 ret = strcmp(a->filename, b->filename);
1271 return CMP(ret, 0);
1272}
1273
1279
1281 { L("adoc"), CF_EXTENSION_TXT },
1282 { L("dpkg-dist"), CF_EXTENSION_PKG },
1283 { L("dpkg-old"), CF_EXTENSION_PKG },
1284 { L("md"), CF_EXTENSION_TXT },
1285 { L("rpmnew"), CF_EXTENSION_PKG },
1286 { L("rpmsave"), CF_EXTENSION_PKG },
1287};
1289
1290
1291static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *ptr, bool required, bool relative)
1292{
1293 bool do_glob = false;
1294 char const *value;
1295 cf_stack_frame_t *frame = &stack->frame[stack->depth];
1296 char p1 = '\0', p2 = '\0'; /* Last 2 characters parsed in the filename*/
1297
1298 /*
1299 * Can't do this inside of update / map.
1300 */
1301 if (parent->unlang == CF_UNLANG_ASSIGNMENT) {
1302 ERROR("%s[%d]: Parse error: Invalid location for $INCLUDE",
1303 frame->filename, frame->lineno);
1304 return -1;
1305 }
1306
1307 fr_skip_whitespace(ptr);
1308
1309 /*
1310 * Grab all of the non-whitespace text.
1311 */
1312 value = ptr;
1313 while (*ptr && !isspace((uint8_t) *ptr)) {
1314 /*
1315 * Disallow control codes as filenames. There's no reason to allow weird filenames.
1316 *
1317 * This check is mainly for the fuzzers, which do weird things.
1318 */
1319 if (*ptr < ' ') {
1320 ERROR("%s[%d]: Invalid character in filename for $INCLUDE", frame->filename, frame->lineno);
1321 return -1;
1322 }
1323
1324 /*
1325 * Disallow the pattern .* at the directory level since .* will also include the parent directory
1326 */
1327 if ((*ptr == '*') && (p1 == '.') && ((p2 == '/') || (p2 == '\0'))) {
1328 ERROR("%s[%d]: Invalid sequence \".*\" at directory level in $INCLUDE", frame->filename, frame->lineno);
1329 return -1;
1330 }
1331
1332 if (do_glob && (*ptr == FR_DIR_SEP)) {
1333 ERROR("%s[%d]: Wildcard directory names not allowed in $INCLUDE", frame->filename, frame->lineno);
1334 return -1;
1335 }
1336 if (do_glob && (*ptr == '*')) {
1337 ERROR("%s[%d]: Multiple \"*\" not allowed in $INCLUDE", frame->filename, frame->lineno);
1338 return -1;
1339 }
1340
1341 do_glob |= (*ptr == '*');
1342
1343 /* Capture the last 2 characters parsed */
1344 p2 = p1;
1345 p1 = *ptr;
1346
1347 ptr++;
1348 }
1349
1350 /*
1351 * Disallow long filenames.
1352 *
1353 * This check is mainly for the fuzzers, which do weird things.
1354 */
1355 if ((size_t) (ptr - value) > 1024) {
1356 ERROR("%s[%d]: Filename too long for $INCLUDE", frame->filename, frame->lineno);
1357 return -1;
1358 }
1359
1360 /*
1361 * We're OK with whitespace after the filename.
1362 */
1363 fr_skip_whitespace(ptr);
1364
1365 /*
1366 * But anything else after the filename is wrong.
1367 */
1368 if (*ptr) {
1369 ERROR("%s[%d]: Unexpected text after $INCLUDE", frame->filename, frame->lineno);
1370 return -1;
1371 }
1372
1373 /*
1374 * Hack for ${confdir}/foo
1375 */
1376 if (*value == '$') relative = false;
1377
1378 value = cf_expand_variables(frame->filename, frame->lineno, parent, stack->buff[1], stack->bufsize,
1379 value, ptr - value, NULL, false);
1380 if (!value) return -1;
1381
1382 if (!FR_DIR_IS_RELATIVE(value)) relative = false;
1383
1384 if (relative) {
1385 value = cf_local_file(frame->filename, value, stack->buff[2], stack->bufsize);
1386 if (!value) {
1387 ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
1388 return -1;
1389 }
1390 }
1391
1392 if (do_glob) {
1393#ifndef HAVE_GLOB_H
1394 ERROR("%s[%d]: Filename globbing is not supported.", frame->filename, frame->lineno);
1395 return -1;
1396#else
1397 int rcode;
1398
1399 stack->depth++;
1400 frame = &stack->frame[stack->depth];
1401 memset(frame, 0, sizeof(*frame));
1402
1403 frame->type = CF_STACK_GLOB;
1404 frame->required = required;
1405 frame->parent = parent;
1406 frame->current = parent;
1407
1408 /*
1409 * For better debugging.
1410 */
1411 frame->filename = frame[-1].filename;
1412 frame->lineno = frame[-1].lineno;
1413
1414 rcode = glob(value, GLOB_ERR | GLOB_NOESCAPE, NULL, &frame->glob);
1415 switch (rcode) {
1416 default:
1417 case GLOB_NOSPACE:
1418 case GLOB_ABORTED:
1419 stack->depth--;
1420 ERROR("%s[%d]: Failed expanding '%s' - %s", frame->filename, frame->lineno,
1421 value, fr_syserror(errno));
1422 return -1;
1423
1424 case 0:
1425 /*
1426 * "success" but "no match" is possible.
1427 */
1428 if (frame->glob.gl_pathc != 0) return 1;
1429 break;
1430
1431 case GLOB_NOMATCH:
1432 break;
1433 }
1434
1435 globfree(&frame->glob);
1436 stack->depth--;
1437 if (!required) return 0;
1438
1439 ERROR("%s[%d]: Failed expanding '%s' - No matching files", frame->filename, frame->lineno,
1440 value);
1441 return -1;
1442#endif
1443 }
1444
1445 /*
1446 * Allow $-INCLUDE for directories, too.
1447 */
1448 if (!required) {
1449 struct stat statbuf;
1450
1451 if (stat(value, &statbuf) < 0) {
1452 WARN("Not including file %s: %s", value, fr_syserror(errno));
1453 return 0;
1454 }
1455 }
1456
1457 /*
1458 * The filename doesn't end in '/', so it must be a file.
1459 */
1460 if (value[strlen(value) - 1] != '/') {
1461 if ((stack->depth + 1) >= MAX_STACK) {
1462 ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
1463 return -1;
1464 }
1465
1466 stack->depth++;
1467 frame = &stack->frame[stack->depth];
1468 memset(frame, 0, sizeof(*frame));
1469
1470 frame->type = CF_STACK_FILE;
1471 frame->fp = NULL;
1472 frame->parent = parent;
1473 frame->current = parent;
1474 frame->filename = talloc_strdup(frame->parent, value);
1475 return 1;
1476 }
1477
1478#ifdef HAVE_DIRENT_H
1479 /*
1480 * $INCLUDE foo/
1481 *
1482 * Include ALL non-"dot" files in the directory.
1483 * careful!
1484 */
1485 {
1486 char *directory;
1487 DIR *dir = NULL;
1488 struct dirent *dp;
1489 struct stat stat_buf;
1490 cf_file_heap_t *h;
1491#ifdef S_IWOTH
1492 int my_fd;
1493#endif
1494
1495 /*
1496 * We need to keep a copy of parent while the
1497 * included files mangle our buff[] array.
1498 */
1499 directory = talloc_strdup(parent, value);
1500
1501 if (DEBUG_ENABLED2) cf_log_debug(parent, "Including files in directory \"%s\"", directory);
1502
1503 dir = opendir(directory);
1504 if (!dir) {
1505 ERROR("%s[%d]: Error reading directory %s: %s",
1506 frame->filename, frame->lineno, value,
1507 fr_syserror(errno));
1508 error:
1509 if (dir) closedir(dir);
1510 talloc_free(directory);
1511 return -1;
1512 }
1513
1514#ifdef S_IWOTH
1515 my_fd = dirfd(dir);
1516 if (unlikely(my_fd < 0)) {
1517 ERROR("%s[%d]: Failed getting a descriptor for directory %s: %s", frame->filename, frame->lineno,
1518 directory, fr_syserror(errno));
1519 goto error;
1520 }
1521
1522 /*
1523 * Security checks.
1524 */
1525 if (fstat(my_fd, &stat_buf) < 0) {
1526 ERROR("%s[%d]: Failed reading directory %s: %s", frame->filename, frame->lineno,
1527 directory, fr_syserror(errno));
1528 goto error;
1529 }
1530
1531 if ((stat_buf.st_mode & S_IWOTH) != 0) {
1532 ERROR("%s[%d]: Directory %s is globally writable. Refusing to start due to "
1533 "insecure configuration", frame->filename, frame->lineno, directory);
1534 goto error;
1535 }
1536#endif
1537
1538 /*
1539 * Directory plus next filename.
1540 */
1541 if ((stack->depth + 2) >= MAX_STACK) {
1542 ERROR("%s[%d]: Directories too deep", frame->filename, frame->lineno);
1543 goto error;
1544 }
1545
1546 stack->depth++;
1547 frame = &stack->frame[stack->depth];
1548 *frame = (cf_stack_frame_t){
1549 .type = CF_STACK_DIR,
1550 .directory = directory,
1551 .parent = parent,
1552 .current = parent,
1553 .from_dir = true
1554 };
1555
1556 MEM(frame->heap = fr_heap_alloc(frame->directory, filename_cmp, cf_file_heap_t, heap_id, 0));
1557
1558 /*
1559 * Read the whole directory before loading any
1560 * individual file. We stat() files to ensure
1561 * that they're readable. We ignore
1562 * subdirectories and files with odd filenames.
1563 */
1564 while ((dp = readdir(dir)) != NULL) {
1565 char const *p, *ext = NULL;
1566
1567 if (dp->d_name[0] == '.') continue;
1568
1569 /*
1570 * Check for valid characters
1571 */
1572 for (p = dp->d_name; *p != '\0'; p++) {
1573 if (isalpha((uint8_t) *p) ||
1574 isdigit((uint8_t) *p) ||
1575 (*p == '-') ||
1576 (*p == '_')) continue;
1577
1578 if (*p == '.') {
1579 ext = p;
1580 continue;
1581 }
1582 break;
1583 }
1584 if (*p != '\0') continue;
1585
1586 /*
1587 * Ignore config files generated by deb / rpm packaging updates, and
1588 * documentation files.
1589 */
1590 if (ext) switch (fr_table_value_by_str(cf_file_extensions, ext + 1, CF_EXTENSION_READ)) {
1591 case CF_EXTENSION_READ:
1592 break;
1593
1594 case CF_EXTENSION_PKG:
1595 WARN("Ignoring packaging system produced file %s%s", frame->directory, dp->d_name);
1596 continue;
1597
1598 case CF_EXTENSION_TXT:
1599 continue;
1600 }
1601
1602 snprintf(stack->buff[1], stack->bufsize, "%s%s",
1603 frame->directory, dp->d_name);
1604
1605 if (stat(stack->buff[1], &stat_buf) != 0) {
1606 ERROR("%s[%d]: Failed checking file %s: %s",
1607 (frame - 1)->filename, (frame - 1)->lineno,
1608 stack->buff[1], fr_syserror(errno));
1609 continue;
1610 }
1611
1612 if (S_ISDIR(stat_buf.st_mode)) {
1613 WARN("%s[%d]: Ignoring directory %s",
1614 (frame - 1)->filename, (frame - 1)->lineno,
1615 stack->buff[1]);
1616 continue;
1617 }
1618
1619 MEM(h = talloc_zero(frame->heap, cf_file_heap_t));
1620 MEM(h->filename = talloc_strdup(h, stack->buff[1]));
1621 h->heap_id = FR_HEAP_INDEX_INVALID;
1622 (void) fr_heap_insert(&frame->heap, h);
1623 }
1624
1625 closedir(dir);
1626 return 1;
1627 }
1628#else
1629 ERROR("%s[%d]: Error including %s: No support for directories!",
1630 frame->filename, frame->lineno, value);
1631 return -1;
1632#endif
1633}
1634
1635
1637{
1638 CONF_ITEM *ci;
1639 CONF_SECTION *parent_cs, *templatecs;
1640 cf_stack_frame_t *frame = &stack->frame[stack->depth];
1641 CONF_SECTION *parent = frame->current;
1642
1643 /*
1644 * getword() returns 0 at the end of the line, and 1 when it read a word.
1645 */
1646 if (getword(&stack->ptr, stack->buff[2], stack->bufsize, true) == 0) {
1647 ERROR("%s[%d]: Missing template name after $TEMPLATE", frame->filename, frame->lineno);
1648 return -1;
1649 }
1650
1651 if (!parent) {
1652 ERROR("%s[%d]: Internal sanity check error in template reference", frame->filename, frame->lineno);
1653 return -1;
1654 }
1655
1656 if (parent->template) {
1657 ERROR("%s[%d]: Section already has a template", frame->filename, frame->lineno);
1658 return -1;
1659 }
1660
1661 /*
1662 * Allow in-line templates.
1663 */
1664 templatecs = cf_section_find(cf_item_to_section(cf_parent(parent)), "template", stack->buff[2]);
1665 if (templatecs) goto check;
1666
1667 parent_cs = cf_root(parent);
1668
1669 templatecs = cf_section_find(parent_cs, "templates", NULL);
1670 if (!templatecs) {
1671 ERROR("%s[%d]: Cannot find template \"%s\", as no 'templates' section exists.",
1672 frame->filename, frame->lineno, stack->buff[2]);
1673 return -1;
1674 }
1675
1676 ci = cf_reference_item(parent_cs, templatecs, stack->buff[2]);
1677 if (!ci || (ci->type != CONF_ITEM_SECTION)) {
1678 PERROR("%s[%d]: Failed finding item \"%s\" in the 'templates' section.",
1679 frame->filename, frame->lineno, stack->buff[2]);
1680 return -1;
1681 }
1682
1683 templatecs = cf_item_to_section(ci);
1684
1685check:
1686 /*
1687 * We can't use a template from inside of itself. Otherwise merging the template copies the
1688 * section into itself, forever.
1689 */
1690 for (ci = &parent->item; ci != NULL; ci = ci->parent) {
1691 if (ci != &templatecs->item) continue;
1692
1693 ERROR("%s[%d]: Cannot use template \"%s\" from inside of itself",
1694 frame->filename, frame->lineno, stack->buff[2]);
1695 return -1;
1696 }
1697
1698 parent->template = templatecs;
1699 return 0;
1700}
1701
1702
1703static int cf_file_fill(cf_stack_t *stack);
1704
1705
1707 ['{'] = true,
1708};
1709
1711 [0] = true,
1712
1713 ['\r'] = true,
1714 ['\n'] = true,
1715
1716 ['#'] = true,
1717 [','] = true,
1718 [';'] = true,
1719 ['}'] = true,
1720};
1721
1723{
1724 fr_slen_t slen = 0;
1725 CONF_SECTION *cs;
1726 uint8_t const *p;
1727 char const *ptr = stack->ptr;
1728 cf_stack_frame_t *frame = &stack->frame[stack->depth];
1729 CONF_SECTION *parent = frame->current;
1730 char *buff[4];
1731
1732 /*
1733 * Short names are nicer.
1734 */
1735 buff[1] = stack->buff[1];
1736 buff[2] = stack->buff[2];
1737 buff[3] = stack->buff[3];
1738
1739 /*
1740 * Create the CONF_SECTION. We don't pass a name2, as it
1741 * hasn't yet been parsed.
1742 */
1743 cs = cf_section_alloc(parent, parent, buff[1], NULL);
1744 if (!cs) {
1745 cf_log_err(parent, "Failed allocating memory for section");
1746 return NULL;
1747 }
1748 cf_filename_set(cs, frame->filename);
1749 cf_lineno_set(cs, frame->lineno);
1750
1751 /*
1752 * Keep "parsing" the condition until we hit EOL.
1753 *
1754 *
1755 */
1756 while (true) {
1757 int rcode;
1758 bool eol;
1759
1760 /*
1761 * Try to parse the condition. We can have a parse success, or a parse failure.
1762 */
1763 slen = fr_skip_condition(ptr, NULL, terminal_end_section, &eol);
1764
1765 /*
1766 * Parse success means we stop reading more data.
1767 */
1768 if (slen > 0) break;
1769
1770 /*
1771 * Parse failures not at EOL are real errors.
1772 */
1773 if (!eol) {
1774 slen = 0;
1775 fr_strerror_const("Unexpected EOF");
1776 error:
1777 cf_canonicalize_error(cs, slen, "Parse error in condition", ptr);
1778 talloc_free(cs);
1779 return NULL;
1780 }
1781
1782 /*
1783 * Parse failures at EOL means that we read more data.
1784 */
1785 p = (uint8_t const *) ptr + (-slen);
1786
1787 /*
1788 * Auto-continue across CR LF until we reach the
1789 * end of the string. We mash everything into one line.
1790 */
1791 if (*p && (*p < ' ')) {
1792 while ((*p == '\r') || (*p == '\n')) {
1793 char *q;
1794
1795 q = UNCONST(char *, p);
1796 *q = ' ';
1797 p++;
1798 continue;
1799 }
1800
1801 /*
1802 * Hopefully the next line is already in
1803 * the buffer, and we don't have to read
1804 * more data.
1805 */
1806 continue;
1807 }
1808
1809 /*
1810 * Anything other than EOL is a problem at this point.
1811 */
1812 if (*p) {
1813 fr_strerror_const("Unexpected text after condition");
1814 goto error;
1815 }
1816
1817 /*
1818 * We hit EOL, so the parse error is really "read more data".
1819 */
1820 stack->fill = UNCONST(char *, p);
1821 rcode = cf_file_fill(stack);
1822 if (rcode < 0) {
1823 cf_log_err(cs, "Failed parsing condition");
1824 return NULL;
1825 }
1826 }
1827
1828 fr_assert((size_t) slen < (stack->bufsize - 1));
1829
1830 ptr += slen;
1831 fr_skip_whitespace(ptr);
1832
1833 if (*ptr != '{') {
1834 cf_log_err(cs, "Expected '{' instead of %s", ptr);
1835 talloc_free(cs);
1836 return NULL;
1837 }
1838 ptr++;
1839
1840 /*
1841 * Save the parsed condition (minus trailing whitespace)
1842 * into a buffer.
1843 */
1844 memcpy(buff[2], stack->ptr, slen);
1845 buff[2][slen] = '\0';
1846
1847 while (slen > 0) {
1848 if (!isspace((uint8_t) buff[2][slen - 1])) break;
1849
1850 buff[2][slen - 1] = '\0';
1851 slen--;
1852 }
1853
1854 /*
1855 * Expand the variables in the pre-parsed condition.
1856 */
1857 if (!cf_expand_variables(frame->filename, frame->lineno, parent,
1858 buff[3], stack->bufsize, buff[2], slen, NULL, true)) {
1859 fr_strerror_const("Failed expanding configuration variable");
1860 return NULL;
1861 }
1862
1863 MEM(cs->name2 = talloc_strdup(cs, buff[3]));
1865
1866 stack->ptr = ptr;
1867
1868 cs->allow_locals = true;
1869 cs->unlang = CF_UNLANG_ALLOW;
1870 return cf_section_to_item(cs);
1871}
1872
1874{
1875 char const *mod;
1876 char const *value = NULL;
1877 CONF_SECTION *css;
1878 fr_token_t token;
1879 char const *ptr = stack->ptr;
1880 cf_stack_frame_t *frame = &stack->frame[stack->depth];
1881 CONF_SECTION *parent = frame->current;
1882 char *buff[4];
1883
1884 /*
1885 * Short names are nicer.
1886 */
1887 buff[1] = stack->buff[1];
1888 buff[2] = stack->buff[2];
1889
1890 if (cf_get_token(parent, &ptr, &token, buff[1], stack->bufsize,
1891 frame->filename, frame->lineno) < 0) {
1892 return NULL;
1893 }
1894
1895 if (token != T_BARE_WORD) {
1896 ERROR("%s[%d]: Invalid syntax for 'map' - module name must not be a quoted string",
1897 frame->filename, frame->lineno);
1898 return NULL;
1899 }
1900 mod = buff[1];
1901
1902 /*
1903 * Maps without an expansion string are allowed, though
1904 * it's not clear why.
1905 */
1906 if (*ptr == '{') {
1907 ptr++;
1908 goto alloc_section;
1909 }
1910
1911 /*
1912 * Now get the expansion string.
1913 */
1914 if (cf_get_token(parent, &ptr, &token, buff[2], stack->bufsize,
1915 frame->filename, frame->lineno) < 0) {
1916 return NULL;
1917 }
1918 if (!fr_str_tok[token]) {
1919 ERROR("%s[%d]: Expecting string expansions in 'map' definition",
1920 frame->filename, frame->lineno);
1921 return NULL;
1922 }
1923
1924 if (*ptr != '{') {
1925 ERROR("%s[%d]: Expecting section start brace '{' in 'map' definition",
1926 frame->filename, frame->lineno);
1927 return NULL;
1928 }
1929 ptr++;
1930 value = buff[2];
1931
1932 /*
1933 * Allocate the section
1934 */
1935alloc_section:
1936 css = cf_section_alloc(parent, parent, "map", mod);
1937 if (!css) {
1938 ERROR("%s[%d]: Failed allocating memory for section",
1939 frame->filename, frame->lineno);
1940 return NULL;
1941 }
1942 cf_filename_set(css, frame->filename);
1943 cf_lineno_set(css, frame->lineno);
1944 css->name2_quote = T_BARE_WORD;
1945
1946 css->argc = 0;
1947 if (value) {
1948 css->argv = talloc_array(css, char const *, 1);
1949 css->argv[0] = talloc_strdup(css->argv, value);
1950 css->argv_quote = talloc_array(css, fr_token_t, 1);
1951 css->argv_quote[0] = token;
1952 css->argc++;
1953 }
1954 stack->ptr = ptr;
1956
1957 return cf_section_to_item(css);
1958}
1959
1960
1962{
1963 char const *mod = NULL;
1964 CONF_SECTION *css;
1965 fr_token_t token;
1966 char const *ptr = stack->ptr;
1967 cf_stack_frame_t *frame = &stack->frame[stack->depth];
1968 CONF_SECTION *parent = frame->current;
1969 char *buff[4];
1970 int values = 0;
1971
1972 /*
1973 * Short names are nicer.
1974 */
1975 buff[1] = stack->buff[1];
1976 buff[2] = stack->buff[2];
1977 buff[3] = stack->buff[3];
1978
1979 /*
1980 * subrequest { ... } is allowed.
1981 */
1982 fr_skip_whitespace(ptr);
1983 if (*ptr == '{') {
1984 ptr++;
1985 goto alloc_section;
1986 }
1987
1988 /*
1989 * Get the name of the Packet-Type.
1990 */
1991 if (cf_get_token(parent, &ptr, &token, buff[1], stack->bufsize,
1992 frame->filename, frame->lineno) < 0) {
1993 return NULL;
1994 }
1995
1996 mod = buff[1];
1997
1998 /*
1999 * subrequest Access-Request { ... } is allowed.
2000 */
2001 if (*ptr == '{') {
2002 ptr++;
2003 goto alloc_section;
2004 }
2005
2006 /*
2007 * subrequest Access-Request &foo { ... }
2008 */
2009 if (cf_get_token(parent, &ptr, &token, buff[2], stack->bufsize,
2010 frame->filename, frame->lineno) < 0) {
2011 return NULL;
2012 }
2013
2014 if (token != T_BARE_WORD) {
2015 ERROR("%s[%d]: The second argument to 'subrequest' must be an attribute reference",
2016 frame->filename, frame->lineno);
2017 return NULL;
2018 }
2019 values++;
2020
2021 if (*ptr == '{') {
2022 ptr++;
2023 goto alloc_section;
2024 }
2025
2026 /*
2027 * subrequest Access-Request &foo &bar { ... }
2028 */
2029 if (cf_get_token(parent, &ptr, &token, buff[3], stack->bufsize,
2030 frame->filename, frame->lineno) < 0) {
2031 return NULL;
2032 }
2033
2034 if (token != T_BARE_WORD) {
2035 ERROR("%s[%d]: The third argument to 'subrequest' must be an attribute reference",
2036 frame->filename, frame->lineno);
2037 return NULL;
2038 }
2039 values++;
2040
2041 if (*ptr != '{') {
2042 ERROR("%s[%d]: Expecting section start brace '{' in 'subrequest' definition",
2043 frame->filename, frame->lineno);
2044 return NULL;
2045 }
2046 ptr++;
2047
2048 /*
2049 * Allocate the section
2050 */
2051alloc_section:
2052 css = cf_section_alloc(parent, parent, "subrequest", mod);
2053 if (!css) {
2054 ERROR("%s[%d]: Failed allocating memory for section",
2055 frame->filename, frame->lineno);
2056 return NULL;
2057 }
2058 cf_filename_set(css, frame->filename);
2059 cf_lineno_set(css, frame->lineno);
2060 if (mod) css->name2_quote = T_BARE_WORD;
2061
2062 css->argc = values;
2063 if (values) {
2064 int i;
2065
2066 css->argv = talloc_array(css, char const *, values);
2067 css->argv_quote = talloc_array(css, fr_token_t, values);
2068
2069 for (i = 0; i < values; i++) {
2070 css->argv[i] = talloc_strdup(css->argv, buff[2 + i]);
2071 css->argv_quote[i] = T_BARE_WORD;
2072 }
2073 }
2074
2075 stack->ptr = ptr;
2076
2077 css->allow_locals = true;
2078 css->unlang = CF_UNLANG_ALLOW;
2079 return cf_section_to_item(css);
2080}
2081
2083{
2084 CONF_SECTION *css;
2085 int argc = 0;
2086 char const *ptr = stack->ptr;
2087 cf_stack_frame_t *frame = &stack->frame[stack->depth];
2088 CONF_SECTION *parent = frame->current;
2089 char *name2 = NULL;
2090 char *argv[RLM_MODULE_NUMCODES];
2091
2092 while (true) {
2093 char const *p;
2094 size_t len;
2095
2096 fr_skip_whitespace(ptr);
2097
2098 /*
2099 * We have an open bracket, it's the end of the "catch" statement.
2100 */
2101 if (*ptr == '{') {
2102 ptr++;
2103 break;
2104 }
2105
2106 /*
2107 * The arguments have to be short, unquoted words.
2108 */
2109 p = ptr;
2110 while (isalpha((uint8_t) *ptr)) ptr++;
2111
2112 len = ptr - p;
2113 if (len > 16) {
2114 ERROR("%s[%d]: Invalid syntax for 'catch' - unknown rcode '%s'",
2115 frame->filename, frame->lineno, p);
2116 error:
2117 talloc_free(name2);
2118 return NULL;
2119 }
2120
2121 if ((*ptr != '{') && !isspace((uint8_t) *ptr)) {
2122 ERROR("%s[%d]: Invalid syntax for 'catch' - unexpected text at '%s'",
2123 frame->filename, frame->lineno, ptr);
2124 goto error;
2125 }
2126
2127 if (!name2) {
2128 name2 = talloc_strndup(NULL, p, len);
2129 continue;
2130 }
2131
2132 if (argc >= RLM_MODULE_NUMCODES) {
2133 ERROR("%s[%d]: Invalid syntax for 'catch' - too many arguments at'%s'",
2134 frame->filename, frame->lineno, ptr);
2135 goto error;
2136 }
2137
2138 argv[argc++] = talloc_strndup(name2, p, len);
2139 }
2140
2141 css = cf_section_alloc(parent, parent, "catch", name2);
2142 if (!css) {
2143 ERROR("%s[%d]: Failed allocating memory for section",
2144 frame->filename, frame->lineno);
2145 goto error;
2146 }
2147 cf_filename_set(css, frame->filename);
2148 cf_lineno_set(css, frame->lineno);
2149 css->name2_quote = T_BARE_WORD;
2150 css->unlang = CF_UNLANG_ALLOW;
2151
2152 css->argc = argc;
2153 if (argc) {
2154 int i;
2155
2156 css->argv = talloc_array(css, char const *, argc + 1);
2157 css->argv_quote = talloc_array(css, fr_token_t, argc);
2158 css->argc = argc;
2159
2160 for (i = 0; i < argc; i++) {
2161 css->argv[i] = talloc_strdup(css->argv, argv[i]);
2162 css->argv_quote[i] = T_BARE_WORD;
2163 }
2164
2165 css->argv[argc] = NULL;
2166 }
2167 talloc_free(name2);
2168
2169 stack->ptr = ptr;
2170
2171 return cf_section_to_item(css);
2172}
2173
2174static int parse_error(cf_stack_t *stack, char const *ptr, char const *message)
2175{
2176 char *spaces, *text;
2177 cf_stack_frame_t *frame = &stack->frame[stack->depth];
2178
2179 if (!ptr) ptr = stack->ptr;
2180
2181 /*
2182 * We must pass a _negative_ offset to this function.
2183 */
2184 fr_canonicalize_error(NULL, &spaces, &text, stack->ptr - ptr, stack->ptr);
2185
2186 ERROR("%s[%d]: %s", frame->filename, frame->lineno, text);
2187 ERROR("%s[%d]: %s^ - %s", frame->filename, frame->lineno, spaces, message);
2188
2190 talloc_free(text);
2191 return -1;
2192}
2193
2194static int parse_type_name(cf_stack_t *stack, char const **ptr_p, char const *type_ptr, fr_type_t *type_p)
2195{
2197 fr_token_t token;
2198 char const *ptr = *ptr_p;
2199 char const *ptr2;
2200
2201 /*
2202 * Parse an explicit type.
2203 */
2205 switch (type) {
2206 default:
2207 break;
2208
2209 case FR_TYPE_NULL:
2210 case FR_TYPE_VOID:
2211 case FR_TYPE_VALUE_BOX:
2212 case FR_TYPE_MAX:
2213 (void) parse_error(stack, type_ptr, "Unknown or invalid variable type in 'foreach'");
2214 return -1;
2215 }
2216
2217 fr_skip_whitespace(ptr);
2218 ptr2 = ptr;
2219
2220 /*
2221 * Parse the variable name. @todo - allow '-' in names.
2222 */
2223 token = gettoken(&ptr, stack->buff[2], stack->bufsize, false);
2224 if (token != T_BARE_WORD) {
2225 (void) parse_error(stack, ptr2, "Invalid variable name for key in 'foreach'");
2226 return -1;
2227 }
2228 fr_skip_whitespace(ptr);
2229
2230 *ptr_p = ptr;
2231 *type_p = type;
2232
2233 return 0;
2234}
2235
2236/*
2237 * foreach &User-Name { - old and deprecated
2238 *
2239 * foreach value (...) { - automatically define variable
2240 *
2241 * foreach string value ( ...) { - data type for variable
2242 *
2243 * foreach string key, type value (..) { - key is "string", value is as above
2244 */
2246{
2247 fr_token_t token;
2249 CONF_SECTION *css;
2250 char const *ptr = stack->ptr, *ptr2, *type_ptr;
2251 cf_stack_frame_t *frame = &stack->frame[stack->depth];
2252 CONF_SECTION *parent = frame->current;
2253
2254 css = cf_section_alloc(parent, parent, "foreach", NULL);
2255 if (!css) {
2256 ERROR("%s[%d]: Failed allocating memory for section",
2257 frame->filename, frame->lineno);
2258 return NULL;
2259 }
2260
2261 cf_filename_set(css, frame->filename);
2262 cf_lineno_set(css, frame->lineno);
2263 css->name2_quote = T_BARE_WORD;
2264 css->unlang = CF_UNLANG_ALLOW;
2265 css->allow_locals = true;
2266
2267 /*
2268 * Get the first argument to "foreach". For backwards
2269 * compatibility, it could be an attribute reference.
2270 */
2271 type_ptr = ptr;
2272 if (cf_get_token(parent, &ptr, &token, stack->buff[1], stack->bufsize,
2273 frame->filename, frame->lineno) < 0) {
2274 return NULL;
2275 }
2276
2277 if (token != T_BARE_WORD) {
2278 invalid_argument:
2279 (void) parse_error(stack, type_ptr, "Unexpected argument to 'foreach'");
2280 return NULL;
2281 }
2282
2283 fr_skip_whitespace(ptr);
2284
2285 /*
2286 * foreach foo { ...
2287 *
2288 * Deprecated and don't use.
2289 */
2290 if (*ptr == '{') {
2291 css->name2 = talloc_strdup(css, stack->buff[1]);
2292
2293 ptr++;
2294 stack->ptr = ptr;
2295
2296 cf_log_warn(css, "Using deprecated syntax. Please use the new 'foreach' syntax.");
2297 return cf_section_to_item(css);
2298 }
2299
2300 fr_skip_whitespace(ptr);
2301
2302 /*
2303 * foreach value (...) {
2304 */
2305 if (*ptr == '(') {
2307 strcpy(stack->buff[2], stack->buff[1]); /* so that we can parse expression in buff[1] */
2308 goto alloc_argc_2;
2309 }
2310
2311 /*
2312 * on input, type name is in stack->buff[1]
2313 * on output, variable name is in stack->buff[2]
2314 */
2315 if (parse_type_name(stack, &ptr, type_ptr, &type) < 0) return NULL;
2316
2317 /*
2318 * if we now have an expression block, then just have variable type / name.
2319 */
2320 if (*ptr == '(') goto alloc_argc_2;
2321
2322 /*
2323 * There's a comma. the first "type name" is for the key. We skip the comma, and parse the
2324 * second "type name" as being for the value.
2325 *
2326 * foreach type key, type value (...)
2327 */
2328 if (*ptr == ',') {
2329 /*
2330 * We have 4 arguments, [var-type, var-name, key-type, key-name]
2331 *
2332 * We don't really care about key-type, but we might care later.
2333 */
2334 css->argc = 4;
2335 css->argv = talloc_array(css, char const *, css->argc);
2336 css->argv_quote = talloc_array(css, fr_token_t, css->argc);
2337
2338 css->argv[2] = fr_type_to_str(type);
2339 css->argv_quote[2] = T_BARE_WORD;
2340
2341 css->argv[3] = talloc_strdup(css->argv, stack->buff[2]);
2342 css->argv_quote[3] = T_BARE_WORD;
2343
2344 ptr++;
2345 fr_skip_whitespace(ptr);
2346 type_ptr = ptr;
2347
2348 /*
2349 * Now parse "type value"
2350 */
2351 token = gettoken(&ptr, stack->buff[1], stack->bufsize, false);
2352 if (token != T_BARE_WORD) goto invalid_argument;
2353
2354 if (parse_type_name(stack, &ptr, type_ptr, &type) < 0) return NULL;
2355
2356 if (!fr_type_is_leaf(type)) {
2357 (void) parse_error(stack, type_ptr, "Invalid data type for 'key' variable");
2358 return NULL;
2359 }
2360 }
2361
2362 /*
2363 * The thing to loop over must now be in an expression block.
2364 */
2365 if (*ptr != '(') {
2366 (void) parse_error(stack, ptr, "Expected (...) after 'foreach' variable definition");
2367 return NULL;
2368 }
2369
2370 goto parse_expression;
2371
2372alloc_argc_2:
2373 css->argc = 2;
2374 css->argv = talloc_array(css, char const *, css->argc);
2375 css->argv_quote = talloc_array(css, fr_token_t, css->argc);
2376
2377
2378parse_expression:
2379 /*
2380 * "(" whitespace EXPRESSION whitespace ")"
2381 */
2382 ptr++;
2383 fr_skip_whitespace(ptr);
2384 ptr2 = ptr;
2385
2386 if (cf_get_token(parent, &ptr, &token, stack->buff[1], stack->bufsize,
2387 frame->filename, frame->lineno) < 0) {
2388 return NULL;
2389 }
2390
2391 /*
2392 * We can do &foo[*] or %func(...), but not "...".
2393 */
2394 if (token != T_BARE_WORD) {
2395 (void) parse_error(stack, ptr2, "Invalid reference in 'foreach'");
2396 return NULL;
2397 }
2398
2399 fr_skip_whitespace(ptr);
2400 if (*ptr != ')') {
2401 (void) parse_error(stack, ptr, "Missing ')' in 'foreach'");
2402 return NULL;
2403 }
2404 ptr++;
2405 fr_skip_whitespace(ptr);
2406
2407 if (*ptr != '{') {
2408 (void) parse_error(stack, ptr, "Expected '{' in 'foreach'");
2409 return NULL;
2410 }
2411
2412 css->name2 = talloc_strdup(css, stack->buff[1]);
2413
2414 /*
2415 * Add in the extra arguments
2416 */
2417 css->argv[0] = fr_type_to_str(type);
2418 css->argv_quote[0] = T_BARE_WORD;
2419
2420 css->argv[1] = talloc_strdup(css->argv, stack->buff[2]);
2421 css->argv_quote[1] = T_BARE_WORD;
2422
2423 ptr++;
2424 stack->ptr = ptr;
2425
2426 return cf_section_to_item(css);
2427}
2428
2429
2430static int add_pair(CONF_SECTION *parent, char const *attr, char const *value,
2431 fr_token_t name1_token, fr_token_t op_token, fr_token_t value_token,
2432 char *buff, char const *filename, int lineno)
2433{
2434 CONF_DATA const *cd;
2435 conf_parser_t *rule;
2436 CONF_PAIR *cp;
2437 bool pass2 = false;
2438
2439 /*
2440 * If we have the value, expand any configuration
2441 * variables in it.
2442 */
2443 if (value && *value) {
2444 bool soft_fail;
2445 char const *expanded;
2446
2447 expanded = cf_expand_variables(filename, lineno, parent, buff, talloc_array_length(buff), value, -1, &soft_fail,
2448 (value_token != T_BARE_WORD));
2449 if (expanded) {
2450 value = expanded;
2451
2452 } else if (!soft_fail) {
2453 return -1;
2454
2455 } else {
2456 /*
2457 * References an item which doesn't exist,
2458 * or which is already marked up as being
2459 * expanded in pass2. Wait for pass2 to
2460 * do the expansions.
2461 *
2462 * Leave the input value alone.
2463 */
2464 pass2 = true;
2465 }
2466 }
2467
2468 cp = cf_pair_alloc(parent, attr, value, op_token, name1_token, value_token);
2469 if (!cp) return -1;
2470 cf_filename_set(cp, filename);
2471 cf_lineno_set(cp, lineno);
2472 cp->pass2 = pass2;
2473
2475 if (!cd) return 0;
2476
2477 rule = cf_data_value(cd);
2478 if (!rule->on_read) return 0;
2479
2480 /*
2481 * Do the on_read callback after adding the value.
2482 */
2483 return rule->on_read(parent, NULL, NULL, cf_pair_to_item(cp), rule);
2484}
2485
2486/*
2487 * switch (cast) foo {
2488 */
2490{
2491 size_t match_len;
2493 fr_token_t name2_quote = T_BARE_WORD;
2494 CONF_SECTION *css;
2495 char const *ptr = stack->ptr;
2496 cf_stack_frame_t *frame = &stack->frame[stack->depth];
2497 CONF_SECTION *parent = frame->current;
2498
2499 fr_skip_whitespace(ptr);
2500 if (*ptr == '(') {
2501 char const *start;
2502
2503 ptr++;
2504 start = ptr;
2505
2506 while (isalpha(*ptr)) ptr++;
2507
2508 if (*ptr != ')') {
2509 ERROR("%s[%d]: Missing ')' in cast",
2510 frame->filename, frame->lineno);
2511 return NULL;
2512 }
2513
2515 start, ptr - start, FR_TYPE_MAX);
2516 if (type == FR_TYPE_MAX) {
2517 ERROR("%s[%d]: Unknown data type '%.*s' in cast",
2518 frame->filename, frame->lineno, (int) (ptr - start), start);
2519 return NULL;
2520 }
2521
2522 if (!fr_type_is_leaf(type)) {
2523 ERROR("%s[%d]: Invalid data type '%.*s' in cast",
2524 frame->filename, frame->lineno, (int) (ptr - start), start);
2525 return NULL;
2526 }
2527
2528 ptr++;
2529 fr_skip_whitespace(ptr);
2530 }
2531
2532 /*
2533 * Get the argument to the switch statement
2534 */
2535 if (cf_get_token(parent, &ptr, &name2_quote, stack->buff[1], stack->bufsize,
2536 frame->filename, frame->lineno) < 0) {
2537 return NULL;
2538 }
2539
2540 css = cf_section_alloc(parent, parent, "switch", NULL);
2541 if (!css) {
2542 ERROR("%s[%d]: Failed allocating memory for section",
2543 frame->filename, frame->lineno);
2544 return NULL;
2545 }
2546
2547 cf_filename_set(css, frame->filename);
2548 cf_lineno_set(css, frame->lineno);
2549 css->name2_quote = name2_quote;
2550 css->unlang = CF_UNLANG_ALLOW;
2551 css->allow_locals = true;
2552
2553 fr_skip_whitespace(ptr);
2554
2555 if (*ptr != '{') {
2556 (void) parse_error(stack, ptr, "Expected '{' in 'switch'");
2557 return NULL;
2558 }
2559
2560 css->name2 = talloc_strdup(css, stack->buff[1]);
2561
2562 /*
2563 * Add in the extra argument.
2564 */
2565 if (type != FR_TYPE_NULL) {
2566 css->argc = 1;
2567 css->argv = talloc_array(css, char const *, css->argc);
2568 css->argv_quote = talloc_array(css, fr_token_t, css->argc);
2569
2570 css->argv[0] = fr_type_to_str(type);
2571 css->argv_quote[0] = T_BARE_WORD;
2572 }
2573
2574 ptr++;
2575 stack->ptr = ptr;
2576
2577 return cf_section_to_item(css);
2578}
2579
2580
2582 { L("catch"), (void *) process_catch },
2583 { L("elsif"), (void *) process_if },
2584 { L("foreach"), (void *) process_foreach },
2585 { L("if"), (void *) process_if },
2586 { L("map"), (void *) process_map },
2587 { L("subrequest"), (void *) process_subrequest },
2588 { L("switch"), (void *) process_switch }
2589};
2591
2592typedef CONF_ITEM *(*cf_process_func_t)(cf_stack_t *);
2593
2594/*
2595 * This is fine. Don't complain.
2596 */
2597DIAG_OFF_OPTIONAL(gnu-designator)
2598
2599/** Convert tokens back to a quoting character
2600 *
2601 * Non-string types convert to '?' to screw ups can be identified easily
2602 */
2603static const bool cf_name_char1[SBUFF_CHAR_CLASS] = {
2604 [ '0' ... '9' ] = true,
2605 [ 'A' ... 'Z' ] = true,
2606 [ 'a' ... 'z' ] = true,
2607 [ '%' ] = true, // %function() in unlang
2608 [ '@' ] = true, // @policy
2609 [ '-' ] = true, // -sql, but probably only in 'unlang'
2610 [ '&' ] = true, // legacy stuff.
2611};
2612
2613
2615{
2616 fr_token_t name1_token, name2_token, value_token, op_token;
2617 char const *value;
2618 CONF_SECTION *css;
2619 char const *ptr = stack->ptr;
2620 char const *name1_ptr, *name2_ptr, *op_ptr;
2621 cf_stack_frame_t *frame = &stack->frame[stack->depth];
2622 CONF_SECTION *parent = frame->current;
2623 char *buff[4];
2624 cf_process_func_t process;
2625
2626 /*
2627 * Short names are nicer.
2628 */
2629 buff[0] = stack->buff[0];
2630 buff[1] = stack->buff[1];
2631 buff[2] = stack->buff[2];
2632 buff[3] = stack->buff[3];
2633
2634 fr_assert(parent != NULL);
2635
2636 /*
2637 * Catch end of a subsection.
2638 *
2639 * frame->current is the new thing we just created.
2640 * frame->parent is the parent of the current frame
2641 * frame->at_reference is the original frame->current, before the @reference
2642 * parent is the parent we started with when we started this section.
2643 */
2644 if (*ptr == '}') {
2645 /*
2646 * No pushed braces means that we're already in
2647 * the parent section which loaded this file. We
2648 * cannot go back up another level.
2649 *
2650 * This limitation means that we cannot put half
2651 * of a CONF_SECTION in one file, and then the
2652 * second half in another file. That's fine.
2653 */
2654 if (frame->braces == 0) {
2655 return parse_error(stack, ptr, "Too many closing braces");
2656 }
2657
2658 /*
2659 * Reset the current and parent to the original
2660 * section, before we were parsing the
2661 * @reference.
2662 */
2663 if (frame->at_reference && (frame->braces == frame->at_reference_braces + 1)) {
2664 frame->current = frame->parent = frame->at_reference;
2665 frame->at_reference = NULL;
2666
2667 } else {
2668 /*
2669 * Go back up one section, because we can.
2670 */
2671 frame->current = frame->parent = cf_item_to_section(frame->current->item.parent);
2672 }
2673
2674 fr_assert(frame->braces > 0);
2675 frame->braces--;
2676
2677 /*
2678 * Merge the template into the existing
2679 * section. parent uses more memory, but
2680 * means that templates now work with
2681 * sub-sections, etc.
2682 */
2683 if (!cf_template_merge(parent, parent->template)) return -1;
2684
2685 ptr++;
2686 stack->ptr = ptr;
2687 return 1;
2688 }
2689
2690 /*
2691 * Found nothing to get excited over. It MUST be
2692 * a key word.
2693 */
2694 name1_ptr = ptr;
2695 switch (parent->unlang) {
2696 default:
2697 /*
2698 * The LHS is a bare word / keyword in normal configuration file syntax.
2699 */
2700 name1_token = gettoken(&ptr, buff[1], stack->bufsize, false);
2701 if (name1_token == T_EOL) return 0;
2702
2703 if (name1_token == T_INVALID) {
2704 return parse_error(stack, name1_ptr, fr_strerror());
2705 }
2706
2707 if (name1_token != T_BARE_WORD) {
2708 return parse_error(stack, name1_ptr, "Invalid location for quoted string");
2709 }
2710
2711 if (*buff[1] == '%') {
2712 return parse_error(stack, name1_ptr, "Cannot use functions outside of a processing section");
2713 }
2714
2715 if (*buff[1] == '&') {
2716 return parse_error(stack, name1_ptr, "Cannot reference attributes outside of a processing section");
2717 }
2718
2719 fr_skip_whitespace(ptr);
2720 break;
2721
2722 case CF_UNLANG_ALLOW:
2723 case CF_UNLANG_EDIT:
2725 /*
2726 * The LHS can be an xlat expansion, attribute reference, etc.
2727 */
2728 if (cf_get_token(parent, &ptr, &name1_token, buff[1], stack->bufsize,
2729 frame->filename, frame->lineno) < 0) {
2730 return -1;
2731 }
2732
2733 /*
2734 * Complain about old syntax.
2735 */
2736 if (check_config && (*buff[1] == '&')) {
2737 WARN("%s[%d]: Using '&' is no longer necessary when referencing attributes. Please delete it.", frame->filename, frame->lineno);
2738 }
2739 break;
2740 }
2741
2742 /*
2743 * Check for bad names. A section named ".foo" will absolutely break the path hierarchy.
2744 */
2745 if (name1_token == T_BARE_WORD) {
2746 if (!cf_name_char1[(uint8_t) *buff[1]]) {
2747 return parse_error(stack, name1_ptr, "Invalid name");
2748 }
2749 }
2750
2751 /*
2752 * Check if the thing we just parsed is an unlang keyword.
2753 */
2754 if ((name1_token == T_BARE_WORD) && isalpha((uint8_t) *buff[1])) {
2756 if (process) {
2757 CONF_ITEM *ci;
2758
2759 /*
2760 * Disallow keywords outside of unlang sections.
2761 *
2762 * We don't strictly need to do this with the more state-oriented parser, but
2763 * people keep putting unlang into random places in the configuration files,
2764 * which is wrong.
2765 */
2766 if (parent->unlang != CF_UNLANG_ALLOW) {
2767 return parse_error(stack, name1_ptr, "Invalid location for unlang keyword");
2768 }
2769
2770 stack->ptr = ptr;
2771 ci = process(stack);
2772 if (!ci) return -1;
2773
2774 ptr = stack->ptr;
2775 if (cf_item_is_section(ci)) {
2776 parent->allow_locals = false;
2777 css = cf_item_to_section(ci);
2778 goto add_section;
2779 }
2780
2781 /*
2782 * Else the item is a pair, and the call to process() it already added it to the
2783 * current section.
2784 */
2785 goto added_pair;
2786 }
2787
2788 /*
2789 * The next token isn't text, so we ignore it.
2790 */
2791 if (!isalnum((int) *ptr)) goto check_for_eol;
2792 }
2793
2794 /*
2795 * See if this thing is a variable definition.
2796 */
2797 if ((name1_token == T_BARE_WORD) && parent->allow_locals) {
2799 char const *ptr3;
2800
2802 if (type == FR_TYPE_NULL) {
2803 parent->allow_locals = false;
2804 goto check_for_eol;
2805 }
2806
2807 if (type == FR_TYPE_TLV) goto parse_name2;
2808
2809 /*
2810 * group {
2811 *
2812 * is a section.
2813 */
2814 if (type == FR_TYPE_GROUP) {
2815 fr_skip_whitespace(ptr);
2816 if (*ptr == '{') {
2817 ptr++;
2818 value = NULL;
2819 name2_token = T_BARE_WORD;
2820 goto alloc_section;
2821 }
2822
2823 } else if (!fr_type_is_leaf(type)) {
2824 /*
2825 * Other structural types are allowed.
2826 */
2827 return parse_error(stack, name1_ptr, "Invalid data type for local variable. Must be 'tlv' or else a non-structural type");
2828 }
2829
2830 /*
2831 * We don't have an operator, so set it to a magic value.
2832 */
2834
2835 /*
2836 * Parse the name of the local variable, and use it as the "value" for the CONF_PAIR.
2837 */
2838 ptr3 = ptr;
2839 if (cf_get_token(parent, &ptr, &value_token, buff[2], stack->bufsize,
2840 frame->filename, frame->lineno) < 0) {
2841 return -1;
2842 }
2843
2844 if (value_token != T_BARE_WORD) {
2845 return parse_error(stack, ptr3, "Invalid name");
2846 }
2847
2848 value = buff[2];
2849
2850 /*
2851 * Non-structural things must be variable definitions.
2852 */
2853 if (fr_type_is_leaf(type)) goto alloc_pair;
2854
2855 /*
2856 * Parse: group foo
2857 * vs group foo { ...
2858 */
2859 fr_skip_whitespace(ptr);
2860
2861 if (*ptr != '{') goto alloc_pair;
2862
2863 ptr++;
2864 name2_token = T_BARE_WORD;
2865 goto alloc_section;
2866 }
2867
2868 /*
2869 * We've parsed the LHS thing. The RHS might be empty, or an operator, or another word, or an
2870 * open bracket.
2871 */
2872check_for_eol:
2873 if (!*ptr || (*ptr == '#') || (*ptr == ',') || (*ptr == ';') || (*ptr == '}')) {
2874 /*
2875 * Only unlang sections can have module references.
2876 *
2877 * We also allow bare words in edit lists, where the RHS is a list of values.
2878 *
2879 * @todo - detail "suppress" requires bare words :(
2880 */
2881 parent->allow_locals = false;
2882 value_token = T_INVALID;
2883 op_token = T_OP_EQ;
2884 value = NULL;
2885 goto alloc_pair;
2886 }
2887
2888 /*
2889 * A common pattern is: name { ...}
2890 * Check for it and skip ahead.
2891 */
2892 if (*ptr == '{') {
2893 ptr++;
2894 name2_token = T_INVALID;
2895 value = NULL;
2896 goto alloc_section;
2897 }
2898
2899 /*
2900 * Parse the thing after the first word. It can be an operator, or the second name for a section.
2901 */
2902 name2_ptr = ptr;
2903 switch (parent->unlang) {
2904 default:
2905 /*
2906 * Configuration sections can only have '=' after the
2907 * first word, OR a second word which is the second name
2908 * of a configuration section.
2909 */
2910 if (*ptr == '=') goto operator;
2911
2912 /*
2913 * Section name2 can only be alphanumeric or UTF-8.
2914 */
2915 parse_name2:
2916 name2_ptr = ptr;
2917
2918 if (!(isalpha((uint8_t) *ptr) || isdigit((uint8_t) *ptr) || (*(uint8_t const *) ptr >= 0x80))) {
2919 /*
2920 * Maybe they missed a closing brace somewhere?
2921 */
2922 name2_token = gettoken(&ptr, buff[2], stack->bufsize, false); /* can't be EOL */
2923 if (fr_assignment_op[name2_token]) {
2924 return parse_error(stack, name2_ptr, "Unexpected operator, was expecting a configuration section. Is there a missing '}' somewhere?");
2925 }
2926
2927 return parse_error(stack, name2_ptr, "Invalid second name for configuration section");
2928 }
2929
2930 name2_token = gettoken(&ptr, buff[2], stack->bufsize, false); /* can't be EOL */
2931 if (name2_token == T_INVALID) {
2932 return parse_error(stack, name2_ptr, fr_strerror());
2933 }
2934
2935 if (name2_token != T_BARE_WORD) {
2936 return parse_error(stack, name2_ptr, "Unexpected quoted string after section name");
2937 }
2938
2939 fr_skip_whitespace(ptr);
2940
2941 /*
2942 * load-balance and redundant-load-balance MUST have a static module name, and MAY have
2943 * an additional load-balance keyword.
2944 */
2945 if ((parent->unlang == CF_UNLANG_MODULES) && (*ptr != '{') &&
2946 ((strcmp(buff[1], "load-balance") == 0) ||
2947 (strcmp(buff[1], "redundant-load-balance") == 0))) {
2948 /*
2949 * The third name could be an attribute name, xlat expansion, etc.
2950 */
2951 if (cf_get_token(parent, &ptr, &value_token, buff[3], stack->bufsize,
2952 frame->filename, frame->lineno) < 0) {
2953 return -1;
2954 }
2955
2956 fr_skip_whitespace(ptr);
2957
2958 if (*ptr != '{') {
2959 return parse_error(stack, ptr, "Expected '{'");
2960 }
2961
2962 ptr++;
2963
2964 css = cf_section_alloc(parent, parent, buff[1], buff[2]);
2965 if (!css) goto oom;
2966
2967 css->argc = 1;
2968 css->argv = talloc_array(css, char const *, 1);
2969 css->argv[0] = talloc_strdup(css->argv, buff[3]);
2970 css->argv_quote = talloc_array(css, fr_token_t, 1);
2971 css->argv_quote[0] = value_token;
2972 goto setup_section;
2973 }
2974
2975 if (*ptr != '{') {
2976 return parse_error(stack, ptr, "Missing '{' for configuration section");
2977 }
2978
2979 ptr++;
2980 value = buff[2];
2981 goto alloc_section;
2982
2984 /*
2985 * The next thing MUST be an operator. We don't support nested attributes in "update" or
2986 * "map" sections.
2987 */
2988 goto operator;
2989
2990 case CF_UNLANG_EDIT:
2991 /*
2992 * The next thing MUST be an operator. Edit sections always do operations, even on
2993 * lists. i.e. there is no second name section when editing a list.
2994 */
2995 goto operator;
2996
2997 case CF_UNLANG_ALLOW:
2998 /*
2999 * 'case ::foo' is allowed. For generality, we just expect that the second argument to
3000 * 'case' is not an operator.
3001 *
3002 * These keywords must have a second name. Or at least, if the character after the
3003 * keyword isn't a '{', then they must have a second name, which is the argument to the
3004 * keyword.
3005 */
3006 if ((strcmp(buff[1], "case") == 0) ||
3007 (strcmp(buff[1], "limit") == 0) ||
3008 (strcmp(buff[1], "load-balance") == 0) ||
3009 (strcmp(buff[1], "redundant-load-balance") == 0) ||
3010 (strcmp(buff[1], "timeout") == 0)) {
3011 break;
3012 }
3013
3014 /*
3015 * These keywords are NOT allowed to have an argument.
3016 */
3017 if ((strcmp(buff[1], "default") == 0) ||
3018 (strcmp(buff[1], "group") == 0) ||
3019 (strcmp(buff[1], "transaction") == 0) ||
3020 (strcmp(buff[1], "try") == 0) ||
3021 (strcmp(buff[1], "redundant") == 0)) {
3022 return parse_error(stack, ptr, "Expected '{' after keyword");
3023 }
3024
3025 /*
3026 * It's not a string, bare word, or attribute reference. It must be an operator.
3027 */
3028 if (!((*ptr == '"') || (*ptr == '`') || (*ptr == '\'') || ((*ptr == '&') && (ptr[1] != '=')) ||
3029 ((*((uint8_t const *) ptr) & 0x80) != 0) || isalpha((uint8_t) *ptr) || isdigit((uint8_t) *ptr))) {
3030 goto operator;
3031 }
3032 break;
3033 }
3034
3035 /*
3036 * The second name could be a bare word, xlat expansion, string etc.
3037 */
3038 if (cf_get_token(parent, &ptr, &name2_token, buff[2], stack->bufsize,
3039 frame->filename, frame->lineno) < 0) {
3040 return -1;
3041 }
3042
3043 if (*ptr != '{') {
3045
3046 /*
3047 * Not the name of a data type.
3048 */
3049 if (type == FR_TYPE_NULL) {
3050 return parse_error(stack, ptr, "Expected '{' after section names");
3051 }
3052
3053 if (parent->unlang == CF_UNLANG_EDIT) {
3054 return parse_error(stack, name1_ptr, "Invalid location for local variable - definitions cannot be inside of an assignment");
3055 }
3056
3057 if (parent->unlang == CF_UNLANG_ALLOW) {
3058 return parse_error(stack, name1_ptr, "Invalid location for local variable - definitions must go at the start of a section");
3059 }
3060
3061 return parse_error(stack, name1_ptr, "Invalid location for local variable - definitions can only go in a processing section.");
3062 }
3063 ptr++;
3064 value = buff[2];
3065
3066alloc_section:
3067 parent->allow_locals = false;
3068
3069 /*
3070 * @policy foo { ...}
3071 *
3072 * Means "add foo to the policy section". And if
3073 * policy{} doesn't exist, create it, and then mark up
3074 * policy{} with a flag "we need to merge it", so that
3075 * when we read the actual policy{}, we merge the
3076 * contents together, instead of creating a second
3077 * policy{}.
3078 *
3079 * @todo - allow for '.' in @.ref Or at least test it. :(
3080 *
3081 * @todo - allow for two section names @ref foo bar {...}
3082 *
3083 * @todo - maybe we can use this to overload things in
3084 * virtual servers, and in modules?
3085 */
3086 if (buff[1][0] == '@') {
3087 CONF_ITEM *ci;
3088 CONF_SECTION *root;
3089 char const *name = &buff[1][1];
3090
3091 if (frame->at_reference) {
3092 ERROR("%s[%d]: Cannot nest '@' reference sections", frame->filename, frame->lineno);
3093 return -1;
3094 }
3095
3096 if (!value) {
3097 ERROR("%s[%d]: Missing section name for '@' reference", frame->filename, frame->lineno);
3098 return -1;
3099 }
3100
3101 /*
3102 * We don't allow relative references. In order to allow that, we would have to do the
3103 * reference lookup starting at the current parent section, and not cf_root().
3104 *
3105 * For now, we don't know what to do with relative references, so we just disallow them.
3106 */
3107 if (*name == '.') {
3108 ERROR("%s[%d]: '@' references must refer to an absolute path, starting at the top of the configuration", frame->filename, frame->lineno);
3109 return -1;
3110 }
3111
3112 root = cf_root(parent);
3113
3114 ci = cf_reference_item(root, parent, name);
3115 if (!ci) {
3116 if (name[1] == '.') {
3117 PERROR("%s[%d]: Failed finding top-level section for '@' reference \"%s\"", frame->filename, frame->lineno, name);
3118 return -1;
3119 }
3120
3121 css = cf_section_alloc(root, root, name, NULL);
3122 if (!css) goto oom;
3123
3124 cf_filename_set(css, frame->filename);
3125 cf_lineno_set(css, frame->lineno);
3126 css->name2_quote = name2_token;
3127 css->unlang = CF_UNLANG_NONE;
3128 css->allow_locals = false;
3129 css->at_reference = true;
3130 parent = css;
3131
3132 /*
3133 * Copy this code from below. :(
3134 */
3135 if (cf_item_to_section(parent->item.parent) == root) {
3136 if (strcmp(css->name1, "server") == 0) css->unlang = CF_UNLANG_SERVER;
3137 if (strcmp(css->name1, "policy") == 0) css->unlang = CF_UNLANG_POLICY;
3138 if (strcmp(css->name1, "modules") == 0) css->unlang = CF_UNLANG_MODULES;
3139 if (strcmp(css->name1, "templates") == 0) css->unlang = CF_UNLANG_CAN_HAVE_UPDATE;
3140 }
3141
3142 } else {
3143 if (!cf_item_is_section(ci)) {
3144 ERROR("%s[%d]: '@' reference \"%s\" is not a section", frame->filename, frame->lineno, name);
3145 return -1;
3146 }
3147
3148 /*
3149 * Set the new parent and ensure we're
3150 * not creating a duplicate section.
3151 */
3153 css = cf_section_find(parent, value, NULL);
3154 if (css) {
3155 ERROR("%s[%d]: '@' reference \"%s\" already contains a \"%s\" section at %s[%d]",
3156 frame->filename, frame->lineno, name, value,
3157 css->item.filename, css->item.lineno);
3158 return -1;
3159 }
3160 }
3161
3162 /*
3163 * We're processing a section. The @reference is
3164 * OUTSIDE of this section.
3165 *
3166 * '@reference' is only valid at the top level of a
3167 * section: once any enclosing section has been opened,
3168 * frame->current diverges from frame->parent, and the
3169 * reference has no well-defined target.
3170 */
3171 if (frame->current != frame->parent) {
3172 ERROR("%s[%d]: '@%s' references can only appear at the top level of a section",
3173 frame->filename, frame->lineno, name);
3174 return -1;
3175 }
3176 frame->at_reference = frame->parent;
3177 frame->at_reference_braces = frame->braces;
3178 name2_token = T_BARE_WORD;
3179
3180 css = cf_section_alloc(parent, parent, value, NULL);
3181 } else {
3182 /*
3183 * Check if there's already an auto-created
3184 * section of this name. If so, just use that
3185 * section instead of allocating a new one.
3186 */
3187 css = cf_section_find(parent, buff[1], value);
3188 if (css && css->at_reference) {
3189 css->at_reference = false;
3190 } else {
3192 }
3193 }
3194
3195 if (!css) {
3196 oom:
3197 ERROR("%s[%d]: Failed allocating memory for section",
3198 frame->filename, frame->lineno);
3199 return -1;
3200 }
3201
3202setup_section:
3203 if (css->depth >= CONF_SECTION_MAX_DEPTH) {
3204 ERROR("%s[%d]: Failed creating section - too many nested sections (%d)",
3205 frame->filename, frame->lineno, css->depth);
3206 return -1;
3207 }
3208
3209 cf_filename_set(css, frame->filename);
3210 cf_lineno_set(css, frame->lineno);
3211 css->name2_quote = name2_token;
3212 css->unlang = CF_UNLANG_NONE;
3213 css->allow_locals = false;
3214
3215 /*
3216 * Only a few top-level sections allow "unlang"
3217 * statements. And for those, "unlang"
3218 * statements are only allowed in child
3219 * subsection.
3220 */
3221 switch (parent->unlang) {
3222 case CF_UNLANG_NONE:
3223 if (!parent->item.parent) {
3224 if (strcmp(css->name1, "server") == 0) css->unlang = CF_UNLANG_SERVER;
3225 if (strcmp(css->name1, "policy") == 0) css->unlang = CF_UNLANG_POLICY;
3226 if (strcmp(css->name1, "modules") == 0) css->unlang = CF_UNLANG_MODULES;
3227 if (strcmp(css->name1, "templates") == 0) css->unlang = CF_UNLANG_CAN_HAVE_UPDATE;
3228
3229 } else if ((cf_item_to_section(parent->item.parent)->unlang == CF_UNLANG_MODULES) &&
3230 (strcmp(css->name1, "update") == 0)) {
3231 /*
3232 * Module configuration can contain "update" statements.
3233 */
3235 css->allow_locals = false;
3236 }
3237 break;
3238
3239 /*
3240 * It's a policy section - allow unlang inside of child sections.
3241 */
3242 case CF_UNLANG_POLICY:
3243 css->unlang = CF_UNLANG_ALLOW;
3244 css->allow_locals = true;
3245 break;
3246
3247 /*
3248 * A virtual server has processing sections, but only a limited number of them.
3249 * Rather than trying to autoload them and glue the interpreter into the conf
3250 * file parser, we just hack it.
3251 */
3252 case CF_UNLANG_SERVER:
3253 // git grep SECTION_NAME src/process/ src/lib/server/process.h | sed 's/.*SECTION_NAME("//;s/",.*//' | sort -u
3255 css->unlang = CF_UNLANG_ALLOW;
3256 css->allow_locals = true;
3257 break;
3258 }
3259
3260 /*
3261 * Allow local variables, but no unlang statements.
3262 */
3263 if (strcmp(css->name1, "dictionary") == 0) {
3265 css->allow_locals = true;
3266 break;
3267 }
3268
3269 /*
3270 * ldap sync has "update" a few levels down.
3271 */
3272 if (strcmp(css->name1, "listen") == 0) {
3274 }
3275 break;
3276
3277 /*
3278 * Virtual modules in the "modules" section can have unlang.
3279 */
3280 case CF_UNLANG_MODULES:
3281 if ((strcmp(css->name1, "group") == 0) ||
3282 (strcmp(css->name1, "load-balance") == 0) ||
3283 (strcmp(css->name1, "redundant") == 0) ||
3284 (strcmp(css->name1, "redundant-load-balance") == 0)) {
3285 css->unlang = CF_UNLANG_ALLOW;
3286 css->allow_locals = true;
3287 } else {
3289 }
3290 break;
3291
3292 case CF_UNLANG_EDIT:
3293 /*
3294 * Edit sections can only have children which are edit sections.
3295 */
3296 css->unlang = CF_UNLANG_EDIT;
3297 break;
3298
3299 case CF_UNLANG_ALLOW:
3300 /*
3301 * If we are doing list assignment, then don't allow local variables. The children are
3302 * also then all edit sections, and not unlang statements.
3303 *
3304 * If we're not doing list assignment, then name2 has to be a bare word, string, etc.
3305 */
3306 css->allow_locals = !fr_list_assignment_op[name2_token];
3307 if (css->allow_locals) {
3308 /*
3309 * @todo - tighten this up for "actions" sections, and module rcode
3310 * over-rides.
3311 *
3312 * Perhaps the best way to do that is to change the syntax for module
3313 * over-rides, so that the parser doesn't have to guess. :(
3314 */
3315 css->unlang = CF_UNLANG_ALLOW;
3316 } else {
3317 css->unlang = CF_UNLANG_EDIT;
3318 }
3319 break;
3320
3321 /*
3322 * We can (maybe?) do nested assignments inside of an old-style "update" or "map" section
3323 */
3326 break;
3327
3330 css->allow_locals = true;
3331 break;
3332
3334 if (strcmp(css->name1, "update") == 0) {
3336 } else {
3338 }
3339 break;
3340 }
3341
3342add_section:
3343 /*
3344 * The current section is now the child section.
3345 */
3346 frame->current = css;
3347 frame->braces++;
3348 css = NULL;
3349 stack->ptr = ptr;
3350 return 1;
3351
3352
3353 /*
3354 * If we're not parsing a section, then the next
3355 * token MUST be an operator.
3356 */
3357operator:
3358 op_ptr = ptr;
3359 name2_token = gettoken(&ptr, buff[2], stack->bufsize, false);
3360 switch (name2_token) {
3361 case T_OP_ADD_EQ:
3362 case T_OP_SUB_EQ:
3363 case T_OP_MUL_EQ:
3364 case T_OP_DIV_EQ:
3365 case T_OP_AND_EQ:
3366 case T_OP_OR_EQ:
3367 case T_OP_NE:
3368 case T_OP_RSHIFT_EQ:
3369 case T_OP_GE:
3370 case T_OP_GT:
3371 case T_OP_LSHIFT_EQ:
3372 case T_OP_LE:
3373 case T_OP_LT:
3374 case T_OP_CMP_EQ:
3375 case T_OP_CMP_FALSE:
3376 case T_OP_SET:
3377 case T_OP_PREPEND:
3378 /*
3379 * Allow more operators in unlang statements, edit sections, and old-style "update" sections.
3380 */
3381 if ((parent->unlang != CF_UNLANG_ALLOW) && (parent->unlang != CF_UNLANG_EDIT) && (parent->unlang != CF_UNLANG_ASSIGNMENT)) {
3382 return parse_error(stack, op_ptr, "Invalid operator for assignment");
3383 }
3385
3386 case T_OP_EQ:
3387 /*
3388 * Configuration variables can only use =
3389 */
3390 fr_skip_whitespace(ptr);
3391 op_token = name2_token;
3392 break;
3393
3394 default:
3395 return parse_error(stack, op_ptr, "Syntax error, the input should be an assignment operator");
3396 }
3397
3398 /*
3399 * MUST have something after the operator.
3400 */
3401 if (!*ptr || (*ptr == '#') || (*ptr == ',') || (*ptr == ';')) {
3402 return parse_error(stack, ptr, "Missing value after operator");
3403 }
3404
3405 /*
3406 * foo = { ... } for nested groups.
3407 *
3408 * As a special case, we allow sub-sections after '=', etc.
3409 *
3410 * This syntax is only for inside of "update"
3411 * sections, and for attributes of type "group".
3412 * But the parser isn't (yet) smart enough to
3413 * know about that context. So we just silently
3414 * allow it everywhere.
3415 */
3416 if (*ptr == '{') {
3417 if ((parent->unlang != CF_UNLANG_ALLOW) && (parent->unlang != CF_UNLANG_EDIT)) {
3418 return parse_error(stack, ptr, "Invalid location for nested attribute assignment");
3419 }
3420
3421 if (!fr_list_assignment_op[name2_token]) {
3422 return parse_error(stack, ptr, "Invalid assignment operator for list");
3423 }
3424
3425 /*
3426 * Now that we've peeked ahead to
3427 * see the open brace, parse it
3428 * for real.
3429 */
3430 ptr++;
3431
3432 /*
3433 * Leave name2_token as the
3434 * operator (as a hack). But
3435 * note that there's no actual
3436 * name2. We'll deal with that
3437 * situation later.
3438 */
3439 value = NULL;
3440 goto alloc_section;
3441 }
3442
3443 fr_skip_whitespace(ptr);
3444
3445 /*
3446 * Parse the value for a CONF_PAIR.
3447 *
3448 * If it's unlang or an edit section, the RHS can be an expression.
3449 */
3450 if ((parent->unlang == CF_UNLANG_ALLOW) || (parent->unlang == CF_UNLANG_EDIT)) {
3451 bool eol;
3452 fr_slen_t slen;
3453
3454 name2_ptr = ptr;
3455
3456 /*
3457 * If the RHS is an expression (foo) or function %foo(), then mark it up as an expression.
3458 */
3459 if ((*ptr == '(') || (*ptr == '%')) {
3460 /* nothing */
3461
3462 } else if (cf_get_token(parent, &name2_ptr, &value_token, buff[2], stack->bufsize,
3463 frame->filename, frame->lineno) == 0) {
3464 /*
3465 * We have one token (bare word), followed by EOL. It's just a token.
3466 */
3467 fr_skip_whitespace(name2_ptr);
3468 if (terminal_end_line[(uint8_t) *name2_ptr]) {
3469 parent->allow_locals = false;
3470 ptr = name2_ptr;
3471 value = buff[2];
3472 goto alloc_pair;
3473 }
3474 } /* else it looks like an expression */
3475
3476 /*
3477 * Parse the text as an expression.
3478 *
3479 * Note that unlike conditions, expressions MUST use \ at the EOL for continuation.
3480 * If we automatically read past EOL, as with:
3481 *
3482 * &foo := (bar -
3483 * baz)
3484 *
3485 * That works, mostly. Until the user forgets to put the trailing ')', and then
3486 * the parse is bad enough that it tries to read to EOF, or to some other random
3487 * parse error.
3488 *
3489 * So the simplest way to avoid utter craziness is to simply require a signal which
3490 * says "yes, I intended to put this over multiple lines".
3491 */
3492 slen = fr_skip_condition(ptr, NULL, terminal_end_line, &eol);
3493 if (slen < 0) {
3494 return parse_error(stack, ptr + (-slen), fr_strerror());
3495 }
3496
3497 /*
3498 * We parsed until the end of the string, but the condition still needs more data.
3499 */
3500 if (eol) {
3501 return parse_error(stack, ptr + slen, "Expression is unfinished at end of line");
3502 }
3503
3504 /*
3505 * Keep a copy of the entire RHS.
3506 */
3507 memcpy(buff[2], ptr, slen);
3508 buff[2][slen] = '\0';
3509
3510 value = buff[2];
3511
3512 /*
3513 * Mark it up as an expression
3514 *
3515 * @todo - we should really just call cf_data_add() to add a flag, but this is good for
3516 * now. See map_afrom_cp()
3517 */
3518 value_token = T_HASH;
3519
3520 /*
3521 * Skip terminal characters
3522 */
3523 ptr += slen;
3524 if ((*ptr == ',') || (*ptr == ';')) ptr++;
3525
3526#if 0
3527 } else if ((parent->unlang != CF_UNLANG_ASSIGNMENT) &&
3528 ((*ptr == '`') || (*ptr == '%') || (*ptr == '('))) {
3529 /*
3530 * Config sections can't use backticks, xlat expansions, or expressions.
3531 *
3532 * Except module configurations can have key = %{...}
3533 */
3534 return parse_error(stack, ptr, "Invalid value for assignment in configuration file");
3535#endif
3536
3537 } else {
3538 if (cf_get_token(parent, &ptr, &value_token, buff[2], stack->bufsize,
3539 frame->filename, frame->lineno) < 0) {
3540 return -1;
3541 }
3542 value = buff[2];
3543 }
3544
3545 /*
3546 * We have an attribute assignment, which means that we no longer allow local variables to be
3547 * defined.
3548 */
3549 parent->allow_locals = false;
3550
3551alloc_pair:
3552 if (add_pair(parent, buff[1], value, name1_token, op_token, value_token, buff[3], frame->filename, frame->lineno) < 0) return -1;
3553
3554added_pair:
3555 fr_skip_whitespace(ptr);
3556
3557 /*
3558 * Skip semicolon if we see it after a
3559 * CONF_PAIR. Also allow comma for
3560 * backwards compatibility with secret
3561 * things in v3.
3562 */
3563 if ((*ptr == ';') || (*ptr == ',')) {
3564 ptr++;
3565 stack->ptr = ptr;
3566 return 1;
3567 }
3568
3569 /*
3570 * Closing brace is allowed after a CONF_PAIR
3571 * definition.
3572 */
3573 if (*ptr == '}') {
3574 stack->ptr = ptr;
3575 return 1;
3576 }
3577
3578 /*
3579 * Anything OTHER than EOL or comment is a syntax
3580 * error.
3581 */
3582 if (*ptr && (*ptr != '#')) {
3583 return parse_error(stack, ptr, "Unexpected text after configuration item");
3584 }
3585
3586 /*
3587 * Since we're at EOL or comment, just drop the
3588 * text, and go read another line of text.
3589 */
3590 return 0;
3591}
3592
3593
3595{
3596 cf_stack_frame_t *frame = &stack->frame[stack->depth];
3597 CONF_SECTION *parent = frame->current;
3598 cf_file_heap_t *h;
3599
3600 fr_heap_pop((void **)&h, &frame->heap);
3601 if (!h) {
3602 /*
3603 * Done reading the directory entry. Close it, and go
3604 * back up a stack frame.
3605 */
3606 talloc_free(frame->directory);
3607 stack->depth--;
3608 return 0;
3609 }
3610
3611 /*
3612 * Push the next filename onto the stack.
3613 */
3614 stack->depth++;
3615 frame = &stack->frame[stack->depth];
3616 memset(frame, 0, sizeof(*frame));
3617
3618 frame->type = CF_STACK_FILE;
3619 frame->fp = NULL;
3620 frame->parent = parent;
3621 frame->current = parent;
3622 frame->filename = h->filename;
3623 frame->lineno = 0;
3624 frame->from_dir = true;
3625 return 1;
3626}
3627
3628
3630
3631void cf_md5_init(void)
3632{
3634}
3635
3636
3637static void cf_md5_update(char const *p)
3638{
3639 if (!cf_md5_ctx) return;
3640
3641 fr_md5_update(cf_md5_ctx, (uint8_t const *)p, strlen(p));
3642}
3643
3645{
3646 if (!cf_md5_ctx) {
3647 memset(digest, 0, MD5_DIGEST_LENGTH);
3648 return;
3649 }
3650
3651 fr_md5_final(digest, cf_md5_ctx);
3653 cf_md5_ctx = NULL;
3654}
3655
3657{
3658 bool at_eof, has_spaces;
3659 size_t len;
3660 char const *ptr;
3661 cf_stack_frame_t *frame = &stack->frame[stack->depth];
3662
3663read_more:
3664 has_spaces = false;
3665
3666read_continuation:
3667 /*
3668 * Get data, and remember if we are at EOF.
3669 */
3670 at_eof = (fgets(stack->fill, stack->bufsize - (stack->fill - stack->buff[0]), frame->fp) == NULL);
3671 frame->lineno++;
3672
3673 /*
3674 * If fgets() returns NULL (i.e. EOF), then the buffer is not
3675 * terminated. Ensure that we do the EOF check before looking
3676 * at the buffer.
3677 */
3678 if (at_eof) {
3679 /*
3680 * A pending continuation would have advanced
3681 * stack->fill, so the file ends cleanly here.
3682 */
3683 if (stack->fill == stack->buff[0]) return 0;
3684
3685 ERROR("%s[%d]: Continuation at EOF is illegal", frame->filename, frame->lineno);
3686 return -1;
3687 }
3688
3689 cf_md5_update(stack->fill);
3690
3691 /*
3692 * We read the entire 8k worth of data: complain.
3693 * Note that we don't care if the last character
3694 * is \n: it's still forbidden. This means that
3695 * the maximum allowed length of text is 8k-1, which
3696 * should be plenty.
3697 */
3698 len = strlen(stack->fill);
3699 if ((stack->fill + len + 1) >= (stack->buff[0] + stack->bufsize)) {
3700 ERROR("%s[%d]: Line too long", frame->filename, frame->lineno);
3701 return -1;
3702 }
3703
3704 /*
3705 * Suppress leading whitespace after a
3706 * continuation line.
3707 */
3708 if (has_spaces) {
3709 ptr = stack->fill;
3710 fr_skip_whitespace(ptr);
3711
3712 if (ptr > stack->fill) {
3713 memmove(stack->fill, ptr, len - (ptr - stack->fill));
3714 len -= (ptr - stack->fill);
3715
3716 /*
3717 * The move copies the text but not the nul
3718 * terminator, which leaves a copy of the last
3719 * few characters after the new end of the
3720 * line. The CR/LF strip below and the
3721 * continuation check after it both write a
3722 * terminator, but only when the line ends with
3723 * CR/LF or with '\\'. A continuation line
3724 * which ends the file without a newline ends
3725 * here, so terminate the line now.
3726 */
3727 stack->fill[len] = '\0';
3728 }
3729 }
3730
3731 /*
3732 * Skip blank lines when we're at the start of
3733 * the read buffer.
3734 */
3735 if (stack->fill == stack->buff[0]) {
3736 ptr = stack->buff[0];
3737 fr_skip_whitespace(ptr);
3738
3739 if (!*ptr || (*ptr == '#')) goto read_more;
3740
3741 } else if (len == 0) {
3742 ERROR("%s[%d]: Continuation at EOF is illegal", frame->filename, frame->lineno);
3743 return -1;
3744 }
3745
3746 /*
3747 * See if there's a continuation.
3748 */
3749 while ((len > 0) &&
3750 ((stack->fill[len - 1] == '\n') || (stack->fill[len - 1] == '\r'))) {
3751 len--;
3752 stack->fill[len] = '\0';
3753 }
3754
3755 if ((len > 0) && (stack->fill[len - 1] == '\\')) {
3756 /*
3757 * Check for "suppress spaces" magic.
3758 */
3759 if (!has_spaces && (len > 2) && (stack->fill[len - 2] == '"')) {
3760 has_spaces = true;
3761 }
3762
3763 stack->fill[len - 1] = '\0';
3764 stack->fill += len - 1;
3765 goto read_continuation;
3766 }
3767
3768 ptr = stack->fill;
3769
3770 /*
3771 * We now have one full line of text in the input
3772 * buffer, without continuations.
3773 */
3774 fr_skip_whitespace(ptr);
3775
3776 /*
3777 * Nothing left, or just a comment. Go read
3778 * another line of text.
3779 *
3780 * If the caller asked us to preserve comments (utilities like
3781 * radconf2json round-trip them as CONF_COMMENT items), capture
3782 * the comment text on the current section before continuing.
3783 */
3784 if (!*ptr || (*ptr == '#')) {
3785 if (_cf_preserve_comments() && frame->current) {
3786 char const *text;
3787 CONF_COMMENT *c;
3788 char *p;
3789
3790 /*
3791 * `#` line: keep everything after the marker
3792 * verbatim (whitespace included; operators use
3793 * leading indent to format banners). Empty
3794 * line: emit a blank marker (NULL text) so the
3795 * writer round-trips the visual separator, and
3796 * downstream tooling can tell two comment blocks
3797 * separated by a blank line apart from one long
3798 * block.
3799 */
3800 text = (*ptr == '#') ? ptr + 1 : NULL;
3801 c = cf_comment_alloc(frame->current, text);
3802 if (c) {
3803 /* Trim trailing CR/LF off the talloc'd copy */
3804 p = UNCONST(char *, c->text);
3805 if (p) {
3806 size_t l = strlen(p);
3807 while (l > 0 && (p[l - 1] == '\n' || p[l - 1] == '\r')) {
3808 p[--l] = '\0';
3809 }
3810 }
3811 cf_filename_set(c, frame->filename);
3812 cf_lineno_set(c, frame->lineno);
3813 }
3814 }
3815 goto read_more;
3816 }
3817
3818 return 1;
3819}
3820
3821
3822/*
3823 * Read a configuration file or files.
3824 */
3826{
3828 char const *ptr;
3829
3830 cf_stack_frame_t *frame;
3831 int rcode;
3832
3833do_frame:
3834 frame = &stack->frame[stack->depth];
3835 parent = frame->current; /* add items here */
3836
3837 switch (frame->type) {
3838#ifdef HAVE_GLOB_H
3839 case CF_STACK_GLOB:
3840 if (frame->gl_current == frame->glob.gl_pathc) {
3841 globfree(&frame->glob);
3842 goto pop_stack;
3843 }
3844
3845 /*
3846 * Process the filename as an include.
3847 */
3848 if (process_include(stack, parent, frame->glob.gl_pathv[frame->gl_current++], frame->required, false) < 0) return -1;
3849
3850 /*
3851 * Run the correct frame. If the file is NOT
3852 * required, then the call to process_include()
3853 * may return 0, and we just process the next
3854 * glob. Otherwise, the call to
3855 * process_include() may return a directory or a
3856 * filename. Go handle that.
3857 */
3858 goto do_frame;
3859#endif
3860
3861#ifdef HAVE_DIRENT_H
3862 case CF_STACK_DIR:
3863 rcode = frame_readdir(stack);
3864 if (rcode == 0) goto do_frame;
3865 if (rcode < 0) return -1;
3866
3867 /*
3868 * Reset which frame we're looking at.
3869 */
3870 frame = &stack->frame[stack->depth];
3871 fr_assert(frame->type == CF_STACK_FILE);
3872 break;
3873#endif
3874
3875 case CF_STACK_FILE:
3876 break;
3877 }
3878
3879#ifndef NDEBUG
3880 /*
3881 * One last sanity check.
3882 */
3883 if (frame->type != CF_STACK_FILE) {
3884 cf_log_err(frame->current, "%s: Internal sanity check failed", __FUNCTION__);
3885 goto pop_stack;
3886 }
3887#endif
3888
3889 /*
3890 * Open the new file if necessary. It either came from
3891 * the first call to the function, or was pushed onto the
3892 * stack by another function.
3893 */
3894 if (!frame->fp) {
3895 rcode = cf_file_open(frame->parent, frame->filename, frame->from_dir, &frame->fp);
3896 if (rcode < 0) return -1;
3897
3898 /*
3899 * Ignore this file
3900 */
3901 if (rcode == 1) {
3902 cf_log_warn(frame->current, "Ignoring file %s - it was already read",
3903 frame->filename);
3904 goto pop_stack;
3905 }
3906 }
3907
3908 /*
3909 * Read, checking for line continuations ('\\' at EOL)
3910 */
3911 for (;;) {
3912 /*
3913 * Fill the buffers with data.
3914 */
3915 stack->fill = stack->buff[0];
3916 rcode = cf_file_fill(stack);
3917 if (rcode < 0) return -1;
3918 if (rcode == 0) break;
3919
3920 /*
3921 * The text here MUST be at the start of a line,
3922 * OR have only whitespace in front of it.
3923 */
3924 ptr = stack->buff[0];
3925 fr_skip_whitespace(ptr);
3926
3927 if (*ptr == '$') {
3928 /*
3929 * Allow for $INCLUDE files
3930 */
3931 if (strncasecmp(ptr, "$INCLUDE", 8) == 0) {
3932 ptr += 8;
3933
3934 stack->ptr = ptr;
3935 if (process_include(stack, parent, ptr, true, true) < 0) return -1;
3936 goto do_frame;
3937 }
3938
3939 if (strncasecmp(ptr, "$-INCLUDE", 9) == 0) {
3940 ptr += 9;
3941
3942 stack->ptr = ptr;
3943 rcode = process_include(stack, parent, ptr, false, true);
3944 if (rcode < 0) return -1;
3945 if (rcode == 0) continue;
3946 goto do_frame;
3947 }
3948
3949 /*
3950 * Allow for $TEMPLATE things
3951 */
3952 if (strncasecmp(ptr, "$TEMPLATE", 9) == 0) {
3953 ptr += 9;
3954 fr_skip_whitespace(ptr);
3955
3956 stack->ptr = ptr;
3957 if (process_template(stack) < 0) return -1;
3958 continue;
3959 }
3960
3961 stack->ptr = ptr;
3962 return parse_error(stack, ptr, "Unknown $... keyword");
3963 }
3964
3965 /*
3966 * All of the file handling code is done. Parse the input.
3967 */
3968 do {
3969 fr_skip_whitespace(ptr);
3970 if (!*ptr || (*ptr == '#')) break;
3971
3972 stack->ptr = ptr;
3973 rcode = parse_input(stack);
3974 ptr = stack->ptr;
3975
3976 if (rcode < 0) return -1;
3977 parent = frame->current;
3978 } while (rcode == 1);
3979 }
3980
3981 fr_assert(frame->fp != NULL);
3982
3983 /*
3984 * See if EOF was unexpected.
3985 */
3986 if (feof(frame->fp) && (parent != frame->parent)) {
3987 ERROR("%s[%d]: EOF reached without closing brace for section %s starting at line %d",
3989 return -1;
3990 }
3991
3992 fclose(frame->fp);
3993 frame->fp = NULL;
3994
3995pop_stack:
3996 /*
3997 * More things to read, go read them.
3998 */
3999 if (stack->depth > 0) {
4000 stack->depth--;
4001 goto do_frame;
4002 }
4003
4004 return 0;
4005}
4006
4008{
4009 cf_stack_frame_t *frame = &stack->frame[stack->depth];
4010
4011 while (stack->depth >= 0) {
4012 switch (frame->type) {
4013 case CF_STACK_FILE:
4014 if (frame->fp) fclose(frame->fp);
4015 frame->fp = NULL;
4016 break;
4017
4018#ifdef HAVE_DIRENT_H
4019 case CF_STACK_DIR:
4020 talloc_free(frame->directory);
4021 break;
4022#endif
4023
4024#ifdef HAVE_GLOB_H
4025 case CF_STACK_GLOB:
4026 globfree(&frame->glob);
4027 break;
4028#endif
4029 }
4030
4031 frame--;
4032 stack->depth--;
4033 }
4034
4035 talloc_free(stack->buff);
4036}
4037
4038/*
4039 * Bootstrap a config file.
4040 */
4041int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
4042{
4043 int i;
4044 fr_rb_tree_t *tree;
4046 cf_stack_frame_t *frame;
4047
4048 /*
4049 * Only add the default config directory if we're loading a top-level configuration file.
4050 */
4051 if (root) {
4052 char const *p;
4053 char *confdir = NULL;
4054 CONF_PAIR *cp;
4055
4056 /*
4057 * For compatibility, this goes first. And we don't care if there are too many '/'.
4058 */
4059 cp = cf_pair_alloc(cs, "raddbdir", filename, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
4060 if (!cp) return -1;
4061
4062 /*
4063 * This goes second, and we try to be nice about too many '/'.
4064 *
4065 * "confdir" is the directory portion of filename, so trim everything
4066 * from the final path separator onwards before storing it.
4067 */
4068 p = strrchr(filename, FR_DIR_SEP);
4069 if (p) {
4070 confdir = talloc_bstrndup(cs, filename, p - filename);
4071 cp = cf_pair_alloc(cs, "confdir", confdir, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
4072 talloc_free(confdir);
4073 } else {
4074 cp = cf_pair_alloc(cs, "confdir", filename, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
4075 }
4076 if (!cp) return -1;
4077 }
4078
4079 MEM(tree = fr_rb_inline_talloc_alloc(cs, cf_file_t, node, _inode_cmp, NULL));
4080
4081 cf_data_add(cs, tree, "filename", false);
4082
4083#ifndef NDEBUG
4084 memset(&stack, 0, sizeof(stack));
4085#endif
4086
4087 /*
4088 * Allocate temporary buffers on the heap (so we don't use *all* the stack space)
4089 */
4090 stack.buff = talloc_array(cs, char *, 4);
4091 for (i = 0; i < 4; i++) MEM(stack.buff[i] = talloc_array(stack.buff, char, 8192));
4092
4093 stack.depth = 0;
4094 stack.bufsize = 8192;
4095 frame = &stack.frame[stack.depth];
4096
4097 memset(frame, 0, sizeof(*frame));
4098 frame->parent = frame->current = cs;
4099
4100 frame->type = CF_STACK_FILE;
4101 frame->filename = talloc_strdup(frame->parent, filename);
4102 cs->item.filename = frame->filename;
4103
4104 if (cf_file_include(&stack) < 0) {
4106 return -1;
4107 }
4108
4109 talloc_free(stack.buff);
4110
4111 /*
4112 * Now that we've read the file, go back through it and
4113 * expand the variables.
4114 */
4115 if (cf_section_pass2(cs) < 0) {
4116 cf_log_err(cs, "Parsing config items failed");
4117 return -1;
4118 }
4119
4120 return 0;
4121}
4122
4123/** Bootstrap a configuration section from an in-memory buffer.
4124 *
4125 * Mirrors cf_file_read(), but reads the configuration text from a buffer via fmemopen() instead of from a
4126 * file on disk. The buffer is treated as if it were the contents of "filename", which is used in error
4127 * messages and stored as the section's source filename.
4128 *
4129 * $INCLUDE / $-INCLUDEs are taken relative to the directory portion of "filename", as with cf_file_read().
4130 *
4131 * Unlike cf_file_read(), this function never sets the "raddbdir" / "confdir" CONF_PAIRs (the buffer has no
4132 * canonical install path) and never inserts "filename" into the dedup tree.
4133 *
4134 * @param[in] cs Top-level configuration section to populate.
4135 * @param[in] buffer The configuration text. The caller retains ownership
4136 * and may free the buffer after this call returns.
4137 * @param[in] buflen Length of @p buffer in bytes (excluding any trailing NUL).
4138 * @param[in] filename Virtual filename for error reporting. May be a
4139 * placeholder like "<inline>" if there is no real file.
4140 * @return 0 on success, -1 on failure.
4141 */
4142int cf_file_read_buffer(CONF_SECTION *cs, char const *buffer, size_t buflen, char const *filename)
4143{
4144 int i;
4145 FILE *fp;
4146 fr_rb_tree_t *tree;
4148 cf_stack_frame_t *frame;
4149
4150 fp = fmemopen(UNCONST(char *, buffer), buflen, "r");
4151 if (!fp) {
4152 ERROR("Failed opening in-memory buffer for parsing: %s", fr_syserror(errno));
4153 return -1;
4154 }
4155
4156 /*
4157 * The dedup-by-inode filename tree may already exist if the caller
4158 * is reading more than one buffer / file into the same root section.
4159 */
4160 tree = cf_data_value(cf_data_find(cs, fr_rb_tree_t, "filename"));
4161 if (!tree) {
4162 MEM(tree = fr_rb_inline_talloc_alloc(cs, cf_file_t, node, _inode_cmp, NULL));
4163 cf_data_add(cs, tree, "filename", false);
4164 }
4165
4166#ifndef NDEBUG
4167 memset(&stack, 0, sizeof(stack));
4168#endif
4169
4170 /*
4171 * Allocate temporary buffers on the heap (so we don't use *all* the stack space)
4172 */
4173 stack.buff = talloc_array(cs, char *, 4);
4174 for (i = 0; i < 4; i++) MEM(stack.buff[i] = talloc_array(stack.buff, char, 8192));
4175
4176 stack.depth = 0;
4177 stack.bufsize = 8192;
4178 frame = &stack.frame[stack.depth];
4179
4180 memset(frame, 0, sizeof(*frame));
4181 frame->parent = frame->current = cs;
4182
4183 frame->type = CF_STACK_FILE;
4184 frame->filename = talloc_strdup(frame->parent, filename);
4185 cs->item.filename = frame->filename;
4186
4187 /*
4188 * Pre-set frame->fp so cf_file_include() skips its own cf_file_open()
4189 * call (which would try to fopen() a real path). cf_file_include()
4190 * fclose()s frame->fp on the way out, which for an fmemopen() handle
4191 * does not free the underlying buffer.
4192 */
4193 frame->fp = fp;
4194
4195 if (cf_file_include(&stack) < 0) {
4197 return -1;
4198 }
4199
4200 talloc_free(stack.buff);
4201
4202 /*
4203 * Now that we've read the buffer, go back through it and
4204 * expand the variables.
4205 */
4206 if (cf_section_pass2(cs) < 0) {
4207 cf_log_err(cs, "Parsing config items failed");
4208 return -1;
4209 }
4210
4211 return 0;
4212}
4213
4215{
4216 talloc_free(cs);
4217}
4218
4219static char const parse_tabs[] = " ";
4220
4221static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, fr_token_t t)
4222{
4223 size_t outlen;
4224 char c;
4225 char buffer[2048];
4226
4227 switch (t) {
4228 default:
4229 c = '\0';
4230 break;
4231
4233 c = '"';
4234 break;
4235
4237 c = '\'';
4238 break;
4239
4241 c = '`';
4242 break;
4243 }
4244
4245 if (c) fprintf(fp, "%c", c);
4246
4247 outlen = fr_snprint(buffer, sizeof(buffer), string, len, c);
4248 fwrite(buffer, outlen, 1, fp);
4249
4250 if (c) fprintf(fp, "%c", c);
4251 return 1;
4252}
4253
4254int cf_pair_write(FILE *fp, CONF_PAIR *cp)
4255{
4256 if (!cp->value) {
4257 fprintf(fp, "%s\n", cp->attr);
4258 return 0;
4259 }
4260
4261 cf_string_write(fp, cp->attr, strlen(cp->attr), cp->lhs_quote);
4262 fprintf(fp, " %s ", fr_table_str_by_value(fr_tokens_table, cp->op, "<INVALID>"));
4263 cf_string_write(fp, cp->value, strlen(cp->value), cp->rhs_quote);
4264 fprintf(fp, "\n");
4265
4266 return 1; /* FIXME */
4267}
4268
4269
4270int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
4271{
4272 if (!fp || !cs) return -1;
4273
4274 /*
4275 * Print the section name1, etc.
4276 */
4277 fwrite(parse_tabs, depth, 1, fp);
4278 cf_string_write(fp, cs->name1, strlen(cs->name1), T_BARE_WORD);
4279
4280 /*
4281 * FIXME: check for "if" or "elsif". And if so, print
4282 * out the parsed condition, instead of the input text
4283 *
4284 * cf_data_find(cs, CF_DATA_TYPE_UNLANG, "if");
4285 */
4286 if (cs->name2) {
4287 fputs(" ", fp);
4288
4289#if 0
4290 c = cf_data_value(cf_data_find(cs, fr_cond_t, NULL));
4291 if (c) {
4292 char buffer[1024];
4293
4294 cond_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), c);
4295 fprintf(fp, "(%s)", buffer);
4296 } else
4297#endif
4298 cf_string_write(fp, cs->name2, strlen(cs->name2), cs->name2_quote);
4299 }
4300
4301 fputs(" {\n", fp);
4302
4303 cf_section_write_children(fp, cs, depth + 1);
4304
4305 fwrite(parse_tabs, depth, 1, fp);
4306 fputs("}\n\n", fp);
4307
4308 return 1;
4309}
4310
4311/** Emit the children of a section at `depth` without an enclosing `{ ... }`.
4312 *
4313 * cf_section_write wraps a section in `name { ... }`; this helper writes only
4314 * the children at the requested indent, which is what tools like
4315 * `radjson2conf -r` need: rendering a synthetic-root section as a file-scope
4316 * fragment ready to be `$INCLUDE`d at any depth.
4317 *
4318 * Blank lines in the source come back through as NULL-text CONF_ITEM_COMMENT
4319 * markers, so the writer doesn't have to synthesise its own separators - just
4320 * emit what's there. Consecutive blank markers collapse to a single blank
4321 * line on output so artifacts from upstream tooling (deletes that left their
4322 * preceding blank behind, splits that introduced extra spacers) don't
4323 * accumulate as visible whitespace.
4324 */
4326{
4327 bool prev_was_blank = false;
4328
4329 if (!fp || !cs) return -1;
4330
4331 cf_item_foreach(&cs->item, ci) {
4332 switch (ci->type) {
4333 case CONF_ITEM_SECTION:
4335 /*
4336 * Sections close with `}\n\n` so the trailing
4337 * blank line is already in the stream; flag it
4338 * so a NULL-text comment immediately after
4339 * doesn't double it up.
4340 */
4341 prev_was_blank = true;
4342 break;
4343
4344 case CONF_ITEM_PAIR:
4345 /*
4346 * Ignore internal things.
4347 */
4348 if (!ci->filename || (ci->filename[0] == '<')) break;
4349
4350 fwrite(parse_tabs, depth, 1, fp);
4352 prev_was_blank = false;
4353 break;
4354
4355 case CONF_ITEM_COMMENT: {
4356 CONF_COMMENT const *c = cf_item_to_comment(ci);
4357
4358 /*
4359 * NULL text == blank line. Collapse
4360 * runs of blanks to a single one.
4361 */
4362 if (c->text == NULL) {
4363 if (!prev_was_blank) {
4364 fputc('\n', fp);
4365 prev_was_blank = true;
4366 }
4367 break;
4368 }
4369
4370 fwrite(parse_tabs, depth, 1, fp);
4371 fputc('#', fp);
4372 fputs(c->text, fp);
4373 fputc('\n', fp);
4374 prev_was_blank = false;
4375 } break;
4376
4377 default:
4378 break;
4379 }
4380 }
4381
4382 return 1;
4383}
4384
4385
4387 CONF_SECTION const *outer_cs,
4388 char const *ptr)
4389{
4390 CONF_PAIR *cp;
4391 CONF_SECTION *next;
4392 CONF_SECTION const *cs = outer_cs;
4393 char name[8192], *p;
4394 char const *name2;
4395
4396 if (!ptr || (!parent_cs && !outer_cs)) {
4397 fr_strerror_const("Invalid argument");
4398 return NULL;
4399 }
4400
4401 if (!*ptr) {
4402 fr_strerror_const("Empty string is invalid");
4403 return NULL;
4404 }
4405
4406 strlcpy(name, ptr, sizeof(name));
4407
4408 p = name;
4409
4410 /*
4411 * ".foo" means "foo from the current section"
4412 */
4413 if (*p == '.') {
4414 p++;
4415
4416 /*
4417 * Just '.' means the current section
4418 */
4419 if (*p == '\0') return cf_section_to_item(cs); /* const issues */
4420
4421 /*
4422 * ..foo means "foo from the section
4423 * enclosing this section" (etc.)
4424 */
4425 while (*p == '.') {
4426 if (!cs->item.parent) goto missing_parent;
4427
4428 cs = cf_item_to_section(cs->item.parent);
4429
4430 /*
4431 * .. means the section
4432 * enclosing this section
4433 */
4434 if (!*++p) return cf_section_to_item(cs); /* const issues */
4435 }
4436
4437 /*
4438 * "foo.bar.baz" means "from the given root"
4439 */
4440 } else if (strchr(p, '.') != NULL) {
4441 if (!parent_cs) {
4442 missing_parent:
4443 fr_strerror_const("Missing parent configuration section");
4444 return NULL;
4445 }
4446 cs = parent_cs;
4447
4448 /*
4449 * "foo" could be from the current section, either as a
4450 * section or as a pair.
4451 *
4452 * If that isn't found, search from the given root.
4453 */
4454 } else {
4455 next = cf_section_find(cs, p, NULL);
4456 if (!next && cs->template) next = cf_section_find(cs->template, p, NULL);
4457 if (next) return &(next->item);
4458
4459 cp = cf_pair_find(cs, p);
4460 if (!cp && cs->template) cp = cf_pair_find(cs->template, p);
4461 if (cp) return &(cp->item);
4462
4463 if (!parent_cs) goto missing_parent;
4464 cs = parent_cs;
4465 }
4466
4467 /*
4468 * Chop the string into pieces, and look up the pieces.
4469 */
4470 while (*p) {
4471 char *n1, *n2, *q;
4472
4473 n1 = p;
4474 n2 = NULL;
4475 q = p;
4476
4477 fr_assert(*q);
4478
4479 /*
4480 * Look for a terminating '.' or '[', to get name1 and possibly name2.
4481 */
4482 while (*q != '\0') {
4483 /*
4484 * foo.bar -> return "foo"
4485 */
4486 if (*q == '.') {
4487 *q++ = '\0'; /* leave 'q' after the '.' */
4488 break;
4489 }
4490
4491 /*
4492 * name1 is anything up to '[' or EOS.
4493 */
4494 if (*q != '[') {
4495 q++;
4496 continue;
4497 }
4498
4499 /*
4500 * Found "name1[", look for "name2]" or "name2]."
4501 */
4502 *q++ = '\0';
4503 n2 = q;
4504
4505 while (*q != '\0') {
4506 if (*q == '[') {
4507 fr_strerror_const("Invalid reference, '[' cannot be used inside of a '[...]' block");
4508 return NULL;
4509 }
4510
4511 if (*q != ']') {
4512 q++;
4513 continue;
4514 }
4515
4516 /*
4517 * We've found the trailing ']'
4518 */
4519 *q++ = '\0';
4520
4521 /*
4522 * "name2]"
4523 */
4524 if (!*q) break;
4525
4526 /*
4527 * Must be "name2]."
4528 */
4529 if (*q++ == '.') break;
4530
4531 fr_strerror_const("Invalid reference, ']' is not followed by '.'");
4532 return NULL;
4533 }
4534
4535 /*
4536 * "name1[name2", but not "name1[name2]"
4537 *
4538 * The inner loop exited because it found *q == '\0',
4539 * meaning that the closing ']' was never found.
4540 */
4541 if (!*q) {
4542 fr_strerror_printf("Invalid reference after '%s', missing close ']'", n1);
4543 return NULL;
4544 }
4545
4546 break;
4547 }
4548 p = q; /* get it ready for the next round */
4549
4550 /*
4551 * End of the string. The thing could be a section with
4552 * two names, a section with one name, or a pair.
4553 *
4554 * And if we don't find the thing we're looking for here,
4555 * check the template section.
4556 */
4557 if (!*p) {
4558 /*
4559 * Two names, must be a section.
4560 */
4561 if (n2) {
4562 next = cf_section_find(cs, n1, n2);
4563 if (!next && cs->template) next = cf_section_find(cs->template, n1, n2);
4564 if (next) return &(next->item);
4565
4566 fail:
4567 name2 = cf_section_name2(cs);
4568 fr_strerror_printf("Parent section %s%s%s { ... } does not contain a %s %s { ... } configuration section",
4569 cf_section_name1(cs),
4570 name2 ? " " : "", name2 ? name2 : "",
4571 n1, n2);
4572 return NULL;
4573 }
4574
4575 /*
4576 * One name, the final thing can be a section or a pair.
4577 */
4578 next = cf_section_find(cs, n1, NULL);
4579 if (!next && cs->template) next = cf_section_find(cs->template, n1, NULL);
4580
4581 if (next) return &(next->item);
4582
4583 cp = cf_pair_find(cs, n1);
4584 if (!cp && cs->template) cp = cf_pair_find(cs->template, n1);
4585 if (cp) return &(cp->item);
4586
4587 name2 = cf_section_name2(cs);
4588 fr_strerror_printf("Parent section %s%s%s { ... } does not contain a %s configuration item",
4589 cf_section_name1(cs),
4590 name2 ? " " : "", name2 ? name2 : "",
4591 n1);
4592 return NULL;
4593 }
4594
4595 /*
4596 * There's more to the string. The thing we're looking
4597 * for MUST be a configuration section.
4598 */
4599 next = cf_section_find(cs, n1, n2);
4600 if (!next && cs->template) next = cf_section_find(cs->template, n1, n2);
4601 if (next) {
4602 cs = next;
4603 continue;
4604 }
4605
4606 if (n2) goto fail;
4607
4608 name2 = cf_section_name2(cs);
4609 fr_strerror_printf("Parent section %s%s%s { ... } does not contain a %s { ... } configuration section",
4610 cf_section_name1(cs),
4611 name2 ? " " : "", name2 ? name2 : "",
4612 n1);
4613 return NULL;
4614 }
4615
4616 /*
4617 * We've fallen off of the end of the string. This should not have happened!
4618 */
4619 fr_strerror_const("Cannot parse reference");
4620 return NULL;
4621}
4622
4623/*
4624 * Only for unit_test_map
4625 */
4627{
4629 fr_assert(!cs->item.parent);
4630
4631 cs->unlang = CF_UNLANG_ALLOW;
4632}
static int const char char buffer[256]
Definition acutest.h:641
int const char * file
Definition acutest.h:855
strcpy(log_entry->msg, buffer)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define RCSID(id)
Definition build.h:603
#define DIAG_OFF_OPTIONAL(_x)
Definition build.h:577
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:422
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:139
#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:130
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
int at_reference_braces
braces when we found this thing
Definition cf_file.c:139
cf_stack_file_t
Definition cf_file.c:98
@ CF_STACK_FILE
Definition cf_file.c:99
CONF_SECTION * current
sub-section we're reading
Definition cf_file.c:137
cf_stack_file_t type
Definition cf_file.c:110
static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
Definition cf_file.c:631
static int parse_input(cf_stack_t *stack)
Definition cf_file.c:2614
int cf_section_write_children(FILE *fp, CONF_SECTION *cs, int depth)
Emit the children of a section at depth without an enclosing { ... }.
Definition cf_file.c:4325
char * fill
where we start filling the buffer from
Definition cf_file.c:156
void cf_section_set_unlang(CONF_SECTION *cs)
Definition cf_file.c:4626
cf_file_extension_t
Definition cf_file.c:1274
@ CF_EXTENSION_PKG
Definition cf_file.c:1276
@ CF_EXTENSION_READ
Definition cf_file.c:1275
@ CF_EXTENSION_TXT
Definition cf_file.c:1277
static int unlang_keywords_len
Definition cf_file.c:2590
static fr_table_num_sorted_t const server_unlang_section[]
Definition cf_file.c:77
int cf_file_read_buffer(CONF_SECTION *cs, char const *buffer, size_t buflen, char const *filename)
Bootstrap a configuration section from an in-memory buffer.
Definition cf_file.c:4142
bool check_config
Definition cf_file.c:61
fr_heap_index_t heap_id
Definition cf_file.c:1261
conf_property
Definition cf_file.c:65
@ CONF_PROPERTY_NAME
Definition cf_file.c:67
@ CONF_PROPERTY_INSTANCE
Definition cf_file.c:68
@ CONF_PROPERTY_INVALID
Definition cf_file.c:66
static int frame_readdir(cf_stack_t *stack)
Definition cf_file.c:3594
static CONF_ITEM * process_map(cf_stack_t *stack)
Definition cf_file.c:1873
static CONF_ITEM * process_foreach(cf_stack_t *stack)
Definition cf_file.c:2245
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:2430
static int cf_expand_file(char const *cf, int lineno, char name[static PATH_MAX], char **p_p, char const **ptr_p, char *output, size_t outsize, bool raw)
Definition cf_file.c:163
void cf_md5_init(void)
Definition cf_file.c:3631
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, bool soft_fail_env)
Definition cf_file.c:300
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:2194
static fr_cmp_ret_t filename_cmp(void const *one, void const *two)
Definition cf_file.c:1264
static const bool cf_name_char1[SBUFF_CHAR_CLASS]
Convert tokens back to a quoting character.
Definition cf_file.c:2603
static void cf_stack_cleanup(cf_stack_t *stack)
Definition cf_file.c:4007
int depth
stack depth
Definition cf_file.c:154
cf_file_check_err_t cf_file_check_unix_perm(char const *filename, UNUSED void *uctx)
Check if file exists, and is a socket.
Definition cf_file.c:975
static const bool terminal_end_line[SBUFF_CHAR_CLASS]
Definition cf_file.c:1710
static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
Definition cf_file.c:716
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition cf_file.c:4041
static fr_md5_ctx_t * cf_md5_ctx
Definition cf_file.c:3629
int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
Definition cf_file.c:4270
int lineno
line in that filename
Definition cf_file.c:113
static const bool terminal_end_section[SBUFF_CHAR_CLASS]
Definition cf_file.c:1706
static size_t conf_property_name_len
Definition cf_file.c:75
static fr_table_num_sorted_t const conf_property_name[]
Definition cf_file.c:71
int cf_section_pass2(CONF_SECTION *cs)
Definition cf_file.c:1141
bool from_dir
this file was read from $include foo/
Definition cf_file.c:142
static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, fr_token_t t)
Definition cf_file.c:4221
static char const parse_tabs[]
Definition cf_file.c:4219
static fr_cmp_ret_t _inode_cmp(void const *one, void const *two)
Definition cf_file.c:707
cf_file_check_err_t cf_file_check(CONF_PAIR *cp, bool check_perms)
Do some checks on the file as an "input" file.
Definition cf_file.c:1079
static int cf_file_include(cf_stack_t *stack)
Definition cf_file.c:3825
static uid_t conf_check_uid
Definition cf_file.c:62
static gid_t conf_check_gid
Definition cf_file.c:63
CONF_ITEM *(* cf_process_func_t)(cf_stack_t *)
Definition cf_file.c:2592
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:1210
CONF_SECTION * at_reference
was this thing an @foo ?
Definition cf_file.c:138
cf_file_check_err_t cf_file_check_open_read(char const *filename, void *uctx)
Callback for cf_file_check to open a file and check permissions.
Definition cf_file.c:1021
static int cf_file_fill(cf_stack_t *stack)
Definition cf_file.c:3656
static const size_t cf_file_extensions_len
Definition cf_file.c:1288
char const * ptr
current parse pointer
Definition cf_file.c:155
cf_file_check_err_t cf_file_check_effective(char const *filename, cf_file_check_err_t(*cb)(char const *filename, void *uctx), void *uctx)
Perform an operation with the effect/group set to conf_check_gid and conf_check_uid.
Definition cf_file.c:842
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:4386
char const * filename
Definition cf_file.c:1260
static CONF_ITEM * process_subrequest(cf_stack_t *stack)
Definition cf_file.c:1961
void cf_file_check_set_uid_gid(uid_t uid, gid_t gid)
Set the euid/egid used when performing file checks.
Definition cf_file.c:827
enum conf_property CONF_PROPERTY
static fr_table_ptr_sorted_t unlang_keywords[]
Definition cf_file.c:2581
char ** buff
buffers for reading / parsing
Definition cf_file.c:152
CONF_SECTION * parent
which started this file
Definition cf_file.c:136
static int process_template(cf_stack_t *stack)
Definition cf_file.c:1636
size_t bufsize
size of the buffers
Definition cf_file.c:153
static size_t server_unlang_section_len
Definition cf_file.c:96
void cf_md5_final(uint8_t *digest)
Definition cf_file.c:3644
static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *ptr, bool required, bool relative)
Definition cf_file.c:1291
static CONF_ITEM * process_if(cf_stack_t *stack)
Definition cf_file.c:1722
static void cf_md5_update(char const *p)
Definition cf_file.c:3637
void cf_file_free(CONF_SECTION *cs)
Definition cf_file.c:4214
static char const * cf_local_file(char const *base, char const *filename, char *buffer, size_t bufsize)
Definition cf_file.c:1181
#define MAX_STACK
Definition cf_file.c:108
static CONF_ITEM * process_catch(cf_stack_t *stack)
Definition cf_file.c:2082
int cf_pair_write(FILE *fp, CONF_PAIR *cp)
Definition cf_file.c:4254
cf_file_check_err_t cf_file_check_unix_connect(char const *filename, UNUSED void *uctx)
Check if we can connect to a unix socket.
Definition cf_file.c:902
char const * filename
filename we're reading
Definition cf_file.c:112
static CONF_ITEM * process_switch(cf_stack_t *stack)
Definition cf_file.c:2489
static int parse_error(cf_stack_t *stack, char const *ptr, char const *message)
Definition cf_file.c:2174
static fr_table_num_sorted_t const cf_file_extensions[]
Definition cf_file.c:1280
cf_file_check_err_t
Results of file checks.
Definition cf_file.h:45
@ CF_FILE_OK
File checks passed.
Definition cf_file.h:46
@ CF_FILE_NO_PERMISSION
Requested permissions not set.
Definition cf_file.h:47
@ CF_FILE_NO_UNIX_SOCKET
File is not a unix socket.
Definition cf_file.h:49
@ CF_FILE_OTHER_ERROR
Other error occurred checking permissions.
Definition cf_file.h:50
@ CF_FILE_NO_EXIST
File does not exist.
Definition cf_file.h:48
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:669
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
CONF_SECTION * cs
CONF_SECTION associated with the file.
Definition cf_priv.h:208
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:107
CONF_ITEM * parent
Parent.
Definition cf_priv.h:61
fr_token_t name2_quote
The type of quoting around name2.
Definition cf_priv.h:112
char const * name2
Second name token. Given foo bar {} would be bar.
Definition cf_priv.h:110
bool allow_locals
allow local variables
Definition cf_priv.h:121
int argc
number of additional arguments
Definition cf_priv.h:114
char const * attr
Attribute name.
Definition cf_priv.h:80
#define CONF_SECTION_MAX_DEPTH
Limit the nesting depth.
Definition cf_priv.h:132
@ CONF_ITEM_PAIR
Definition cf_priv.h:41
@ CONF_ITEM_SECTION
Definition cf_priv.h:42
@ CONF_ITEM_COMMENT
A # ... line preserved verbatim from the input - only created when the parser is asked to keep commen...
Definition cf_priv.h:44
bool referenced
Was this item referenced in the config?
Definition cf_priv.h:69
fr_token_t rhs_quote
Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition cf_priv.h:85
@ CF_UNLANG_MODULES
this section is in "modules", allow unlang 2 down
Definition cf_priv.h:96
@ CF_UNLANG_NONE
no unlang
Definition cf_priv.h:92
@ CF_UNLANG_CAN_HAVE_UPDATE
can have "update"
Definition cf_priv.h:100
@ CF_UNLANG_ALLOW
allow unlang in this section
Definition cf_priv.h:93
@ CF_UNLANG_POLICY
this section is a policy, allow unlang 2 down
Definition cf_priv.h:95
@ CF_UNLANG_ASSIGNMENT
only assignments inside of map / update
Definition cf_priv.h:98
@ CF_UNLANG_EDIT
only edit commands
Definition cf_priv.h:97
@ CF_UNLANG_DICTIONARY
only local variable definitions
Definition cf_priv.h:99
@ CF_UNLANG_SERVER
this section is a virtual server, allow unlang 2 down
Definition cf_priv.h:94
int depth
Definition cf_priv.h:119
char const * value
Attribute value.
Definition cf_priv.h:81
cf_unlang_t unlang
Definition cf_priv.h:120
char const * name1
First name token. Given foo bar {} would be foo.
Definition cf_priv.h:109
fr_token_t * argv_quote
Definition cf_priv.h:116
fr_token_t op
Operator e.g. =, :=.
Definition cf_priv.h:83
CONF_ITEM item
Common set of fields.
Definition cf_priv.h:78
bool pass2
do expansion in pass2.
Definition cf_priv.h:87
char const * filename
The file the config item was parsed from.
Definition cf_priv.h:71
struct stat buf
stat about the file
Definition cf_priv.h:209
bool at_reference
this thing was created from an ...
Definition cf_priv.h:122
bool _cf_expand_variables(void)
Definition cf_util.c:816
bool _cf_preserve_comments(void)
Definition cf_util.c:796
CONF_SECTION * template
Definition cf_priv.h:124
char const * filename
name of the file
Definition cf_priv.h:207
char const * text
Comment text, with the leading # and any surrounding whitespace stripped.
Definition cf_priv.h:188
char const ** argv
additional arguments
Definition cf_priv.h:115
fr_token_t lhs_quote
Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
Definition cf_priv.h:84
int lineno
The line number the config item began on.
Definition cf_priv.h:70
CONF_ITEM_TYPE type
Whether the config item is a config_pair, conf_section or cf_data.
Definition cf_priv.h:66
A # ... comment line preserved verbatim from the input.
Definition cf_priv.h:185
Internal data that is associated with a configuration section.
Definition cf_priv.h:195
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_PAIR * cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp, bool copy_meta)
Duplicate a CONF_PAIR.
Definition cf_util.c:1529
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1922
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:725
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:1487
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1391
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:1247
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:671
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:1640
CONF_COMMENT * cf_comment_alloc(CONF_SECTION *parent, char const *text)
Allocate a new comment item attached to parent.
Definition cf_util.c:821
CONF_COMMENT * cf_item_to_comment(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_COMMENT (asserts on type mismatch).
Definition cf_util.c:758
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:605
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:1052
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:651
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1758
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition cf_util.c:709
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_lineno(_cf)
Definition cf_util.h:118
#define cf_data_add(_cf, _data, _name, _free)
Definition cf_util.h:306
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:295
#define cf_lineno_set(_ci, _lineno)
Definition cf_util.h:183
#define cf_root(_cf)
Definition cf_util.h:112
#define cf_parent(_cf)
Definition cf_util.h:115
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition cf_util.h:418
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:198
#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_item_foreach(_parent, _iter)
Iterate over every child item of a CONF_SECTION (or any CONF_ITEM that has children).
Definition cf_util.h:106
#define cf_filename_set(_ci, _filename)
Definition cf_util.h:180
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:341
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:343
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
Test enumeration values.
Definition dict_test.h:92
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:149
int fr_heap_pop(void **out, fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:359
unsigned int fr_heap_index_t
Definition heap.h:82
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition heap.h:102
#define FR_HEAP_INDEX_INVALID
Definition heap.h:85
The main heap structure.
Definition heap.h:68
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition log.h:263
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:411
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:105
static char * stack[MAX_STACK]
Definition radmin.c:158
#define fr_md5_final(_out, _ctx)
Finalise the ctx, producing the digest.
Definition md5.h:90
#define fr_md5_ctx_alloc()
Allocation function for MD5 digest context.
Definition md5.h:68
void fr_md5_ctx_t
Definition md5.h:25
#define fr_md5_update(_ctx, _in, _inlen)
Ingest plaintext into the digest.
Definition md5.h:83
#define fr_md5_ctx_free(_ctx)
Free function for MD5 digest ctx.
Definition md5.h:75
#define MD5_DIGEST_LENGTH
#define SBUFF_CHAR_CLASS
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
ssize_t fr_slen_t
unsigned long int size_t
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:35
void fr_perm_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.
Definition perm.c:533
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:237
#define fr_assert(_expr)
Definition rad_assert.h:37
#define WARN(fmt,...)
static const char * spaces
Definition radict.c:185
static fr_token_t op_token(char const *s)
int fr_rb_find(void **found, fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:586
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:637
#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:244
The main red black tree structure.
Definition rb.h:71
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:57
static char const * name
#define FR_SBUFF_OUT(_start, _len_or_end)
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()
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
fr_slen_t fr_skip_xlat(char const *start, char const *end)
Skip an xlat expression.
Definition skip.c:296
fr_slen_t fr_skip_condition(char const *start, char const *end, bool const terminal[static SBUFF_CHAR_CLASS], bool *eol)
Skip a conditional expression.
Definition skip.c:317
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:36
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
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:764
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
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_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:693
#define talloc_strndup(_ctx, _str, _len)
Definition talloc.h:150
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:289
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
const bool fr_assignment_op[T_TOKEN_LAST]
Definition token.c:234
const bool fr_list_assignment_op[T_TOKEN_LAST]
Definition token.c:251
fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
Definition token.c:539
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:33
const bool fr_str_tok[T_TOKEN_LAST]
Definition token.c:297
int getword(char const **ptr, char *buf, int buflen, bool unescape)
Definition token.c:530
@ T_OP_SUB_EQ
Definition token.h:68
@ T_INVALID
Definition token.h:37
@ T_OP_DIV_EQ
Definition token.h:70
@ T_EOL
Definition token.h:38
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
@ T_OP_AND_EQ
Definition token.h:72
@ T_OP_CMP_TRUE
Definition token.h:102
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_OP_MUL_EQ
Definition token.h:69
@ T_BACK_QUOTED_STRING
Definition token.h:121
@ T_HASH
Definition token.h:117
@ T_OP_SET
Definition token.h:82
@ T_OP_NE
Definition token.h:95
@ T_OP_ADD_EQ
Definition token.h:67
@ T_OP_CMP_FALSE
Definition token.h:103
@ T_OP_LSHIFT_EQ
Definition token.h:75
@ T_OP_RSHIFT_EQ
Definition token.h:74
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
@ T_OP_CMP_EQ
Definition token.h:104
@ T_OP_LE
Definition token.h:98
@ T_OP_GE
Definition token.h:96
@ T_OP_GT
Definition token.h:97
@ T_OP_OR_EQ
Definition token.h:71
@ T_OP_LT
Definition token.h:99
@ T_OP_PREPEND
Definition token.h:83
enum fr_token fr_token_t
static fr_slen_t parent
Definition pair.h:864
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition strerror.h:84
#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:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
static fr_type_t fr_type_from_str(char const *type)
Return the constant value representing a type.
Definition types.h:479
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061