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