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