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