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