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