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