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