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