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