31RCSID(
"$Id: a1ee38f160ea7d6a8d1862baa87205fb54fc6d91 $")
 
   35#include <freeradius-devel/server/cf_file.h> 
   36#include <freeradius-devel/server/cf_priv.h> 
   37#include <freeradius-devel/server/cf_util.h> 
   38#include <freeradius-devel/server/log.h> 
   39#include <freeradius-devel/server/tmpl.h> 
   40#include <freeradius-devel/server/util.h> 
   41#include <freeradius-devel/server/virtual_servers.h> 
   42#include <freeradius-devel/util/debug.h> 
   43#include <freeradius-devel/util/file.h> 
   44#include <freeradius-devel/util/misc.h> 
   45#include <freeradius-devel/util/perm.h> 
   46#include <freeradius-devel/util/strerror.h> 
   47#include <freeradius-devel/util/skip.h> 
   48#include <freeradius-devel/util/md5.h> 
   64#include <freeradius-devel/server/main_config.h> 
   83        { 
L(
"accounting"),      
true },
 
   85        { 
L(
"authenticate"),    
true },
 
   89        { 
L(
"establish"),       
true },
 
   90        { 
L(
"finally"),         
true },
 
   96        { 
L(
"verify"),          
true },
 
 
  110#define MAX_STACK (32) 
  166                                        "Protocol dictionary must be NULL not %s",
 
 
  180#define RULES_VERIFY(_cs, _rules) if (cf_tmpl_rules_verify(_cs, _rules) < 0) return NULL 
  190                                char *output, 
size_t outsize,
 
  194        char const *end, *next, *ptr;
 
  198        if (soft_fail) *soft_fail = 
false;
 
  221        while (*ptr && (!end || (ptr < end))) {
 
  225                if ((*ptr == 
'$') && (ptr[1] == 
'{')) {
 
  233                                ERROR(
"%s[%d]: Failed parsing variable expansion '%s''",
 
  245                        if ((
size_t) len >= 
sizeof(
name)) {
 
  246                                ERROR(
"%s[%d]: Reference string is too large",
 
  251                        memcpy(
name, ptr, len - 3);
 
  252                        name[len - 3] = 
'\0';
 
  260                        if (
name[0] == 
'/') {
 
  261                                int fd = open(
name, O_RDONLY);
 
  265                                        ERROR(
"%s[%d]: Reference \"${%s}\" failed opening file - %s", cf, lineno, 
name, 
fr_syserror(errno));
 
  269                                if (fstat(fd, &buf) < 0) {
 
  272                                        ERROR(
"%s[%d]: Reference \"${%s}\" failed reading file - %s", cf, lineno, 
name, 
fr_syserror(errno));
 
  276                                if (buf.st_size >= ((output + outsize) - p)) {
 
  278                                        ERROR(
"%s[%d]: Reference \"${%s}\" file is too large (%zu >= %zu)", cf, lineno, 
name,
 
  279                                              (
size_t) buf.st_size, (
size_t) ((output + outsize) - p));
 
  283                                len = read(fd, p, (output + outsize) - p);
 
  284                                if (len < 0) 
goto fail_fd;
 
  293                        q = strchr(
name, 
':');
 
  300                                if (soft_fail) *soft_fail = 
true;
 
  301                                PERROR(
"%s[%d]: Failed finding reference \"${%s}\"", cf, lineno, 
name);
 
  313                                        ERROR(
"%s[%d]: Can only reference properties of sections", cf, lineno);
 
  327                                        ERROR(
"%s[%d]: Invalid property '%s'", cf, lineno, q);
 
  346                                        if (soft_fail) *soft_fail = 
true;
 
  348                                        ERROR(
"%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
 
  354                                        ERROR(
"%s[%d]: Reference \"%s\" has no value",
 
  359                                if (p + strlen(cp->
value) >= output + outsize) {
 
  360                                        ERROR(
"%s[%d]: Reference \"%s\" is too long",
 
  378                                        ERROR(
"%s[%d]: Cannot reference different item in same section", cf, lineno);
 
  391                                        ERROR(
"%s[%d]: Failed copying reference %s", cf, lineno, 
name);
 
  401                                ERROR(
"%s[%d]: Reference \"%s\" type is invalid", cf, lineno, input);
 
  404                } 
else if (strncmp(ptr, 
"$ENV{", 5) == 0) {
 
  414                        next = strchr(ptr, 
'}');
 
  417                                ERROR(
"%s[%d]: Environment variable expansion missing }",
 
  426                        if ((
size_t) (next - ptr) >= 
sizeof(
name)) {
 
  427                                ERROR(
"%s[%d]: Environment variable name is too large",
 
  432                        memcpy(
name, ptr, next - ptr);
 
  433                        name[next - ptr] = 
'\0';
 
  445                        if (p + strlen(env) >= output + outsize) {
 
  446                                ERROR(
"%s[%d]: Reference \"%s\" is too long",
 
  463                if (p >= (output + outsize)) {
 
  464                        ERROR(
"%s[%d]: Reference \"%s\" is too long",
 
 
  480        if (!cs || !
template) 
return true;
 
  506                        if (!cp2) 
return false;
 
  538                        if (!subcs2) 
return false;
 
 
  560        return CMP(a->
buf.st_ino, b->buf.st_ino);
 
 
  592                if (
fr_dirfd(&my_fd, &r, filename) < 0) {
 
  593                        ERROR(
"Failed to open directory containing %s", filename);
 
  597                if (fstatat(my_fd, r, &my_file.
buf, 0) < 0) 
goto error;
 
  611                        if (my_fd != AT_FDCWD) 
close(my_fd);
 
  614                fd = openat(my_fd, r, O_RDONLY, 0);
 
  615                fp = (fd < 0) ? NULL : fdopen(fd, 
"r");
 
  616                if (my_fd != AT_FDCWD) 
close(my_fd);
 
  618                fp = fopen(filename, 
"r");
 
  619                if (fp) fd = fileno(fp);
 
  622        DEBUG2(
"including configuration file %s", filename);
 
  632        file->filename = talloc_strdup(
file, filename); 
 
  634        file->from_dir = from_dir;
 
  636        if (fstat(fd, &
file->buf) == 0) {
 
  638                if ((
file->buf.st_mode & S_IWOTH) != 0) {
 
  639                        ERROR(
"Configuration file %s is globally writable.  " 
  640                              "Refusing to start due to insecure configuration.", filename);
 
 
  691        uid_t euid = (uid_t)-1;
 
  692        gid_t egid = (gid_t)-1;
 
  708        ret = cb(filename, uctx);
 
  710                if (seteuid(euid) < 0) {
 
  717                if (setegid(egid) < 0) {
 
 
  743        struct sockaddr_un addr = { .sun_family = AF_UNIX };
 
  752        strncpy(addr.sun_path, filename, 
sizeof(addr.sun_path) - 1);
 
  754        fd = socket(AF_UNIX, SOCK_STREAM, 0);
 
  760        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
 
  767        if (connect(fd, (
struct sockaddr *)&addr, 
sizeof(addr)) < 0) {
 
 
  817        if (stat(filename, &buf) < 0) {
 
  836        if (!S_ISSOCK(buf.st_mode)) {
 
 
  864        fd = open(filename, O_RDONLY);
 
  867                if (fd >= 0) 
close(fd);
 
  888        if (
file && fstat(fd, &
file->buf) < 0) 
goto error;
 
 
  917        if (!tree) 
return false;
 
  920        if (!
file) 
return false;
 
  922        file->filename = talloc_strdup(
file, filename); 
 
  926                if (stat(filename, &
file->buf) < 0) {
 
  928                        cf_log_perr(cp, 
"Unable to open file \"%s\"", filename);
 
  948        if ((
file->buf.st_mode & S_IWOTH) != 0) {
 
  949                cf_log_perr(cp, 
"Configuration file %s is globally writable.  " 
  950                            "Refusing to start due to insecure configuration.", filename);
 
 
  987                if (!
value) 
return -1;
 
 
 1004                                 char *
buffer, 
size_t bufsize)
 
 1011        p = strrchr(
buffer, FR_DIR_SEP);
 
 1012        if (!p) 
return filename;
 
 1017        dirsize = (p - 
buffer) + 1;
 
 1019        if ((dirsize + strlen(filename)) >= bufsize) {
 
 1023        strlcpy(p + 1, filename, bufsize - dirsize);
 
 
 1033                        char const *filename, 
int lineno)
 
 1035        char const *ptr = *ptr_p;
 
 1053                ERROR(
"%s[%d]: %s", filename, lineno, text);
 
 1061        if ((
size_t) slen >= buflen) {
 
 1062                ERROR(
"%s[%d]: Name is too long", filename, lineno);
 
 1070                                 out, outlen, NULL)) {
 
 
 1106                ERROR(
"%s[%d]: Parse error: Invalid location for $INCLUDE",
 
 1117        while (*ptr && !isspace((
uint8_t) *ptr)) ptr++;
 
 1135        if (*
value == 
'$') relative = 
false;
 
 1139        if (!
value) 
return -1;
 
 1141        if (!FR_DIR_IS_RELATIVE(
value)) relative = 
false;
 
 1151        if (strchr(
value, 
'*') != 0) {
 
 1158                memset(frame, 0, 
sizeof(*frame));
 
 1160                frame->
type = CF_STACK_GLOB;
 
 1161                frame->required = required;
 
 1171                if (glob(
value, GLOB_ERR | GLOB_NOESCAPE, NULL, &frame->glob) < 0) {
 
 1181                if (frame->glob.gl_pathc == 0) {
 
 1187                        ERROR(
"%s[%d]: Failed expanding '%s' - No matching files", frame->
filename, frame->
lineno,
 
 1200                struct stat statbuf;
 
 1202                if (stat(
value, &statbuf) < 0) {
 
 1219                memset(frame, 0, 
sizeof(*frame));
 
 1240                struct stat     stat_buf;
 
 1254                dir = opendir(directory);
 
 1256                        ERROR(
"%s[%d]: Error reading directory %s: %s",
 
 1271                if (fstat(my_fd, &stat_buf) < 0) {
 
 1277                if ((stat_buf.st_mode & S_IWOTH) != 0) {
 
 1278                        ERROR(
"%s[%d]: Directory %s is globally writable.  Refusing to start due to " 
 1279                              "insecure configuration", frame->
filename, frame->
lineno, directory);
 
 1295                        .
type = CF_STACK_DIR,
 
 1296                        .directory = directory,
 
 1310                while ((dp = readdir(dir)) != NULL) {
 
 1314                        if (dp->d_name[0] == 
'.') 
continue;
 
 1319                        for (p = dp->d_name; *p != 
'\0'; p++) {
 
 1324                                    (*p == 
'.')) 
continue;
 
 1327                        if (*p != 
'\0') 
continue;
 
 1332                        len = strlen(dp->d_name);
 
 1333                        if ((len > 10) && (strncmp(&dp->d_name[len - 10], 
".dpkg-dist", 10) == 0)) {
 
 1335                                WARN(
"Ignoring packaging system produced file %s%s", frame->directory, dp->d_name);
 
 1338                        if ((len > 9) && (strncmp(&dp->d_name[len - 9], 
".dpkg-old", 9) == 0)) 
goto pkg_file;
 
 1339                        if ((len > 7) && (strncmp(&dp->d_name[len - 7], 
".rpmnew", 9) == 0)) 
goto pkg_file;
 
 1340                        if ((len > 8) && (strncmp(&dp->d_name[len - 8], 
".rpmsave", 10) == 0)) 
goto pkg_file;
 
 1343                                 frame->directory, dp->d_name);
 
 1345                        if (stat(
stack->buff[1], &stat_buf) != 0) {
 
 1346                                ERROR(
"%s[%d]: Failed checking file %s: %s",
 
 1347                                      (frame - 1)->filename, (frame - 1)->lineno,
 
 1352                        if (S_ISDIR(stat_buf.st_mode)) {
 
 1353                                WARN(
"%s[%d]: Ignoring directory %s",
 
 1354                                     (frame - 1)->filename, (frame - 1)->lineno,
 
 1368        ERROR(
"%s[%d]: Error including %s: No support for directories!",
 
 
 1384        if (token != 
T_EOL) {
 
 1390                ERROR(
"%s[%d]: Internal sanity check error in template reference", frame->
filename, frame->
lineno);
 
 1404                parent->template = templatecs;
 
 1412                ERROR(
"%s[%d]: Cannot find template \"%s\", as no 'templates' section exists.",
 
 1419                PERROR(
"%s[%d]: Failed finding item \"%s\" in the 'templates' section.",
 
 
 1454        char const      *ptr = 
stack->ptr;
 
 1473                        .allow_unresolved = 
true,
 
 1474                        .allow_unknown = 
true 
 1510                if (slen > 0) 
break;
 
 1527                p = (
uint8_t const *) ptr + (-slen);
 
 1533                if (*p && (*p < 
' ')) {
 
 1534                        while ((*p == 
'\r') || (*p == 
'\n')) {
 
 1576                cf_log_err(cs, 
"Expected '{' instead of %s", ptr);
 
 1587        buff[2][slen] = 
'\0';
 
 1592                buff[2][slen] = 
'\0';
 
 
 1618        char const *
value = NULL;
 
 1621        char const      *ptr = 
stack->ptr;
 
 1638                ERROR(
"%s[%d]: Invalid syntax for 'map' - module name must not be a quoted string",
 
 1661                ERROR(
"%s[%d]: Expecting string expansions in 'map' definition",
 
 1667                ERROR(
"%s[%d]: Expecting section start brace '{' in 'map' definition",
 
 1680                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 1690                css->
argv = talloc_array(css, 
char const *, 1);
 
 
 1705        char const *mod = NULL;
 
 1708        char const      *ptr = 
stack->ptr;
 
 1757                ERROR(
"%s[%d]: The second argument to 'subrequest' must be an attribute reference",
 
 1777                ERROR(
"%s[%d]: The third argument to 'subrequest' must be an attribute reference",
 
 1784                ERROR(
"%s[%d]: Expecting section start brace '{' in 'subrequest' definition",
 
 1796                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 1808                css->
argv = talloc_array(css, 
char const *, values);
 
 1811                for (i = 0; i < values; i++) {
 
 
 1828        char const      *ptr = 
stack->ptr;
 
 1852                while (isalpha((
uint8_t) *ptr)) ptr++;
 
 1856                        ERROR(
"%s[%d]: Invalid syntax for 'catch' - unknown rcode '%s'",
 
 1861                if ((*ptr != 
'{') && !isspace((
uint8_t) *ptr)) {
 
 1862                        ERROR(
"%s[%d]: Invalid syntax for 'catch' - unexpected text at '%s'",
 
 1868                        name2 = talloc_strndup(NULL, p, len);
 
 1873                        ERROR(
"%s[%d]: Invalid syntax for 'catch' - too many arguments at'%s'",
 
 1878                argv[argc++] = talloc_strndup(name2, p, len);
 
 1884                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 1897                css->
argv = talloc_array(css, 
char const *, argc + 1);
 
 1901                for (i = 0; i < argc; i++) {
 
 1906                css->
argv[argc] = NULL;
 
 
 1920        if (!ptr) ptr = 
stack->ptr;
 
 
 1939        char const *ptr = *ptr_p;
 
 1954                (void) 
parse_error(
stack, type_ptr, 
"Unknown or invalid variable type in 'foreach'");
 
 1966                (void) 
parse_error(
stack, ptr2, 
"Invalid variable name for key in 'foreach'");
 
 
 1991        char const      *ptr = 
stack->ptr, *ptr2, *type_ptr;
 
 1997                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 2037                cf_log_warn(css, 
"Using deprecated syntax.  Please use new the new 'foreach' syntax.");
 
 2061        if (*ptr == 
'(') 
goto alloc_argc_2;
 
 2076                css->
argv = talloc_array(css, 
char const *, css->
argc);
 
 2098                        (void) 
parse_error(
stack, type_ptr, 
"Invalid data type for 'key' variable");
 
 2107                (void) 
parse_error(
stack, ptr, 
"Expected (...) after 'foreach' variable definition");
 
 2111        goto parse_expression;
 
 2115        css->
argv = talloc_array(css, 
char const *, css->
argc);
 
 
 2173                    char *
buff, 
char const *filename, 
int lineno)
 
 2186                char const      *expanded;
 
 2192                } 
else if (!soft_fail) {
 
 
 2235        char const      *ptr = 
stack->ptr;
 
 2246                while (isalpha(*ptr)) ptr++;
 
 2249                        ERROR(
"%s[%d]: Missing ')' in cast",
 
 2257                        ERROR(
"%s[%d]: Unknown data type '%.*s' in cast",
 
 2263                        ERROR(
"%s[%d]: Invalid data type '%.*s' in cast",
 
 2282                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 2307                css->
argv = talloc_array(css, 
char const *, css->
argc);
 
 
 2336        fr_token_t      name1_token, name2_token, value_token, op_token;
 
 2339        char const      *ptr = 
stack->ptr;
 
 2374                if (frame->
braces == 0) {
 
 2415        switch (
parent->unlang) {
 
 2421                if (name1_token == 
T_EOL) 
return 0;
 
 2467                        ci = process(
stack);
 
 2472                                parent->allow_locals = 
false;
 
 2487                if (!isalnum((
int) *ptr)) 
goto check_for_eol;
 
 2499                        parent->allow_locals = 
false;
 
 2523                        return parse_error(
stack, ptr2, 
"Invalid data type for local variable.  Must be 'tlv' or else a non-structrul type");
 
 2557                if (*ptr != 
'{') 
goto alloc_pair;
 
 2569        if (!*ptr || (*ptr == 
'#') || (*ptr == 
',') || (*ptr == 
';') || (*ptr == 
'}')) {
 
 2577                parent->allow_locals = 
false;
 
 2599        switch (
parent->unlang) {
 
 2606                if (*ptr == 
'=') 
goto operator;
 
 2618                                return parse_error(
stack, ptr2, 
"Unexpected operator, was expecting a configuration section.  Is there a missing '}' somewhere?");
 
 2621                        return parse_error(
stack, ptr2, 
"Invalid second name for configuration section");
 
 2630                        return parse_error(
stack, ptr2, 
"Unexpected quoted string after section name");
 
 2662                if ((strcmp(
buff[1], 
"case") == 0) ||
 
 2663                    (strcmp(
buff[1], 
"limit") == 0) ||
 
 2664                    (strcmp(
buff[1], 
"timeout") == 0)) {
 
 2671                if (!((*ptr == 
'"') || (*ptr == 
'`') || (*ptr == 
'\'') || ((*ptr == 
'&') && (ptr[1] != 
'=')) ||
 
 2693        parent->allow_locals = 
false;
 
 2712        if (
buff[1][0] == 
'@') {
 
 2726                        if (
name[1] == 
'.') {
 
 2765                                ERROR(
"%s[%d]: Reference \"%s\" already contains a \"%s\" section at %s[%d]",
 
 2797                ERROR(
"%s[%d]: Failed allocating memory for section",
 
 2814        switch (
parent->unlang) {
 
 2816                if (!
parent->item.parent) {
 
 2823                           (strcmp(css->
name1, 
"update") == 0)) {
 
 2856                if (strcmp(css->
name1, 
"dictionary") == 0) {
 
 2865                if (strcmp(css->
name1, 
"listen") == 0) {
 
 2874                if ((strcmp(css->
name1, 
"group") == 0) ||
 
 2875                    (strcmp(css->
name1, 
"load-balance") == 0) ||
 
 2876                    (strcmp(css->
name1, 
"redundant") == 0) ||
 
 2877                    (strcmp(css->
name1, 
"redundant-load-balance") == 0)) {
 
 2927                if (strcmp(css->
name1, 
"update") == 0) {
 
 2953        switch (name2_token) {
 
 2982                op_token = name2_token;
 
 2986                return parse_error(
stack, ptr2, 
"Syntax error, the input should be an assignment operator");
 
 2992        if (!*ptr || (*ptr == 
'#') || (*ptr == 
',') || (*ptr == 
';')) {
 
 3009                        return parse_error(
stack, ptr, 
"Invalid location for nested attribute assignment");
 
 3050                if ((*ptr == 
'(') || (*ptr == 
'%')) {
 
 3060                                parent->allow_locals = 
false;
 
 3092                        return parse_error(
stack, ptr + slen, 
"Expression is unfinished at end of line");
 
 3098                memcpy(
buff[2], ptr, slen);
 
 3099                buff[2][slen] = 
'\0';
 
 3115                if ((*ptr == 
',') || (*ptr == 
';')) ptr++;
 
 3119                   ((*ptr == 
'`') || (*ptr == 
'%') || (*ptr == 
'('))) {
 
 3125                return parse_error(
stack, ptr, 
"Invalid value for assignment in configuration file");
 
 3140        parent->allow_locals = 
false;
 
 3154        if ((*ptr == 
';') || (*ptr == 
',')) {
 
 3173        if (*ptr && (*ptr != 
'#')) {
 
 3174                return parse_error(
stack, ptr, 
"Unexpected text after configuration item");
 
 
 3207        memset(frame, 0, 
sizeof(*frame));
 
 
 3249        bool at_eof, has_spaces;
 
 3261        at_eof = (fgets(
stack->fill, 
stack->bufsize - (
stack->fill - 
stack->buff[0]), frame->fp) == NULL);
 
 3272        len = strlen(
stack->fill);
 
 3286                if (ptr > 
stack->fill) {
 
 3287                        memmove(
stack->fill, ptr, len - (ptr - 
stack->fill));
 
 3288                        len -= (ptr - 
stack->fill);
 
 3297                if (at_eof) 
return 0;
 
 3299                ptr = 
stack->buff[0];
 
 3302                if (!*ptr || (*ptr == 
'#')) 
goto read_more;
 
 3304        } 
else if (at_eof || (len == 0)) {
 
 3313               ((
stack->fill[len - 1] == 
'\n') || (
stack->fill[len - 1] == 
'\r'))) {
 
 3315                stack->fill[len] = 
'\0';
 
 3318        if ((len > 0) && (
stack->fill[len - 1] == 
'\\')) {
 
 3322                if (!has_spaces && (len > 2) && (
stack->fill[len - 2] == 
'"')) {
 
 3326                stack->fill[len - 1] = 
'\0';
 
 3327                stack->fill += len - 1;
 
 3328                goto read_continuation;
 
 3343        if (!*ptr || (*ptr == 
'#')) 
goto read_more;
 
 
 3364        switch (frame->
type) {
 
 3367                if (frame->gl_current == frame->glob.gl_pathc) {
 
 3368                        globfree(&frame->glob);
 
 3391                if (rcode == 0) 
goto do_frame;
 
 3392                if (rcode < 0) 
return -1;
 
 3423                if (rcode < 0) 
return -1;
 
 3444                if (rcode < 0) 
return -1;
 
 3445                if (rcode == 0) 
break;
 
 3451                ptr = 
stack->buff[0];
 
 3469                                if (rcode < 0) 
return -1;
 
 3470                                if (rcode == 0) 
continue;
 
 3494                        if (!*ptr || (*ptr == 
'#')) 
break;
 
 3500                        if (rcode < 0) 
return -1;
 
 3502                } 
while (rcode == 1);
 
 3511                ERROR(
"%s[%d]: EOF reached without closing brace for section %s starting at line %d",
 
 3523        if (
stack->depth > 0) {
 
 
 3535        while (
stack->depth >= 0) {
 
 3536                switch (frame->
type) {
 
 3538                        if (frame->fp) fclose(frame->fp);
 
 3550                        globfree(&frame->glob);
 
 
 3577        p = strrchr(cp->
value, FR_DIR_SEP);
 
 3591        stack.buff = talloc_array(cs, 
char *, 4);
 
 3592        for (i = 0; i < 4; i++) 
MEM(
stack.buff[i] = talloc_array(
stack.buff, 
char, 8192));
 
 3595        stack.bufsize = 8192;
 
 3598        memset(frame, 0, 
sizeof(*frame));
 
 3617                cf_log_err(cs, 
"Parsing config items failed");
 
 
 3655        if (c) fprintf(fp, 
"%c", c);
 
 3658        fwrite(
buffer, outlen, 1, fp);
 
 3660        if (c) fprintf(fp, 
"%c", c);
 
 
 3667                fprintf(fp, 
"%s\n", cp->
attr);
 
 
 3682        if (!fp || !cs) 
return -1;
 
 3705                        fprintf(fp, 
"(%s)", 
buffer);
 
 3727                        if (!ci->filename || (ci->filename[0] == 
'<')) 
break;
 
 
 3752        char                    name[8192], *p;
 
 3755        if (!ptr || (!parent_cs && !outer_cs)) {
 
 3797        } 
else if (strchr(p, 
'.') != NULL) {
 
 3814                if (next) 
return &(next->
item);
 
 3818                if (cp) 
return &(cp->
item);
 
 3820                if (!parent_cs) 
goto missing_parent;
 
 3839                while (*q != 
'\0') {
 
 3862                        while (*q != 
'\0') {
 
 3864                                        fr_strerror_const(
"Invalid reference, '[' cannot be used inside of a '[...]' block");
 
 3886                                if (*q++ == 
'.') 
break;
 
 3916                                if (next) 
return &(next->
item);
 
 3920                                fr_strerror_printf(
"Parent section %s%s%s { ... } does not contain a %s %s { ... } configuration section",
 
 3922                                                   name2 ? 
" " : 
"", name2 ? name2 : 
"",
 
 3933                        if (next) 
return &(next->
item);
 
 3937                        if (cp) 
return &(cp->
item);
 
 3940                        fr_strerror_printf(
"Parent section %s%s%s  { ... } does not contain a %s configuration item",
 
 3942                                           name2 ? 
" " : 
"", name2 ? name2 : 
"",
 
 3961                fr_strerror_printf(
"Parent section %s%s%s { ... } does not contain a %s { ... } configuration section",
 
 3963                                   name2 ? 
" " : 
"", name2 ? name2 : 
"",
 
 
static int const char char buffer[256]
strcpy(log_entry->msg, buffer)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define L(_str)
Helper for initialising arrays of string literals.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
CONF_SECTION * current
sub-section we're reading
static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
static int parse_input(cf_stack_t *stack)
char * fill
where we start filling the buffer from
void cf_section_set_unlang(CONF_SECTION *cs)
static int unlang_keywords_len
static fr_table_num_sorted_t const server_unlang_section[]
static int frame_readdir(cf_stack_t *stack)
static CONF_ITEM * process_map(cf_stack_t *stack)
static CONF_ITEM * process_foreach(cf_stack_t *stack)
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)
#define RULES_VERIFY(_cs, _rules)
static int parse_type_name(cf_stack_t *stack, char const **ptr_p, char const *type_ptr, fr_type_t *type_p)
static void cf_stack_cleanup(cf_stack_t *stack)
static int cf_tmpl_rules_verify(CONF_SECTION *cs, tmpl_rules_t const *rules)
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)
cf_file_check_err_t cf_file_check_unix_perm(char const *filename, UNUSED void *uctx)
Check if file exists, and is a socket.
static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
static fr_md5_ctx_t * cf_md5_ctx
static int8_t filename_cmp(void const *one, void const *two)
int cf_section_write(FILE *fp, CONF_SECTION *cs, int depth)
int lineno
line in that filename
int cf_file_read(CONF_SECTION *cs, char const *filename)
static const bool terminal_end_section[UINT8_MAX+1]
static size_t conf_property_name_len
static fr_table_num_sorted_t const conf_property_name[]
int cf_section_pass2(CONF_SECTION *cs)
bool from_dir
this file was read from $include foo/
static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, fr_token_t t)
static char const parse_tabs[]
cf_file_check_err_t cf_file_check(CONF_PAIR *cp, bool check_perms)
Do some checks on the file as an "input" file.
static int cf_file_include(cf_stack_t *stack)
static uid_t conf_check_uid
static gid_t conf_check_gid
CONF_ITEM *(* cf_process_func_t)(cf_stack_t *)
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)
static int8_t _inode_cmp(void const *one, void const *two)
CONF_SECTION * at_reference
was this thing an @foo ?
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.
static int cf_file_fill(cf_stack_t *stack)
char const  * ptr
current parse pointer
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.
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
static CONF_ITEM * process_subrequest(cf_stack_t *stack)
void cf_file_check_set_uid_gid(uid_t uid, gid_t gid)
Set the euid/egid used when performing file checks.
enum conf_property CONF_PROPERTY
static fr_table_ptr_sorted_t unlang_keywords[]
char ** buff
buffers for reading / parsing
CONF_SECTION * parent
which started this file
static int process_template(cf_stack_t *stack)
size_t bufsize
size of the buffers
static int cf_pair_write(FILE *fp, CONF_PAIR *cp)
static size_t server_unlang_section_len
void cf_md5_final(uint8_t *digest)
static int process_include(cf_stack_t *stack, CONF_SECTION *parent, char const *ptr, bool required, bool relative)
static CONF_ITEM * process_if(cf_stack_t *stack)
static void cf_md5_update(char const *p)
void cf_file_free(CONF_SECTION *cs)
static char const * cf_local_file(char const *base, char const *filename, char *buffer, size_t bufsize)
static CONF_ITEM * process_catch(cf_stack_t *stack)
static const bool terminal_end_line[UINT8_MAX+1]
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.
char const  * filename
filename we're reading
static CONF_ITEM * process_switch(cf_stack_t *stack)
static int parse_error(cf_stack_t *stack, char const *ptr, char const *message)
cf_file_check_err_t
Results of file checks.
@ CF_FILE_OK
File checks passed.
@ CF_FILE_NO_PERMISSION
Requested permissions not set.
@ CF_FILE_NO_UNIX_SOCKET
File is not a unix socket.
@ CF_FILE_OTHER_ERROR
Other error occurred checking permissions.
@ CF_FILE_NO_EXIST
File does not exist.
cf_parse_t on_read
Function to call as the item is being read, just after it has been allocated and initialized.
Defines a CONF_PAIR to C data type mapping.
CONF_SECTION * cs
CONF_SECTION associated with the file.
CONF_ITEM item
Common set of fields.
CONF_ITEM * parent
Parent.
fr_token_t name2_quote
The type of quoting around name2.
char const  * name2
Second name token. Given foo bar {} would be bar.
bool allow_locals
allow local variables
int argc
number of additional arguments
char const  * attr
Attribute name.
fr_token_t rhs_quote
Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
char const  * value
Attribute value.
#define cf_item_foreach(_ci, _iter)
Iterate over the contents of a list.
char const  * name1
First name token. Given foo bar {} would be foo.
@ CF_UNLANG_MODULES
this section is in "modules", allow unlang 2 down
@ CF_UNLANG_NONE
no unlang
@ CF_UNLANG_CAN_HAVE_UPDATE
can have "update"
@ CF_UNLANG_ALLOW
allow unlang in this section
@ CF_UNLANG_POLICY
this section is a policy, allow unlang 2 down
@ CF_UNLANG_ASSIGNMENT
only assignments inside of map / update
@ CF_UNLANG_EDIT
only edit commands
@ CF_UNLANG_DICTIONARY
only local variable definitions
@ CF_UNLANG_SERVER
this section is a virtual server, allow unlang 2 down
fr_token_t op
Operator e.g. =, :=.
CONF_ITEM item
Common set of fields.
bool pass2
do expansion in pass2.
char const  * filename
The file the config item was parsed from.
struct stat buf
stat about the file
bool at_reference
this thing was created from an ...
char const  * filename
name of the file
char const  ** argv
additional arguments
fr_token_t lhs_quote
Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
int lineno
The line number the config item began on.
CONF_ITEM_TYPE type
Whether the config item is a config_pair, conf_section or cf_data.
Internal data that is associated with a configuration section.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
CONF_PAIR * cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp, bool copy_meta)
Duplicate a CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
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.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
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.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
#define cf_log_err(_cf, _fmt,...)
#define cf_data_add(_cf, _data, _name, _free)
#define cf_data_find(_cf, _type, _name)
#define cf_lineno_set(_ci, _lineno)
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
#define cf_log_perr(_cf, _fmt,...)
#define cf_section_find_parent(_cf, _name1, _name2)
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
#define cf_filename_set(_ci, _filename)
#define cf_log_warn(_cf, _fmt,...)
#define cf_log_debug(_cf, _fmt,...)
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
static char const  * spaces
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_t const * fr_dict_internal(void)
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
unsigned int fr_heap_index_t
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
#define FR_HEAP_INDEX_INVALID
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.
static char * stack[MAX_STACK]
#define fr_md5_final(_out, _ctx)
Finalise the ctx, producing the digest.
#define fr_md5_ctx_alloc()
Allocation function for MD5 digest context.
#define fr_md5_update(_ctx, _in, _inlen)
Ingest plaintext into the digest.
#define fr_md5_ctx_free(_ctx)
Free function for MD5 digest ctx.
#define MD5_DIGEST_LENGTH
@ 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_GROUP
A grouping of other attributes.
static uint8_t depth(fr_minmax_heap_index_t i)
int strncasecmp(char *s1, char *s2, int n)
void fr_perm_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.
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.
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.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
#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.
The main red black tree structure.
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
fr_dict_attr_t const  * request_attr_request
#define FR_SBUFF_OUT(_start, _len_or_end)
bool at_runtime
Produce an ephemeral/runtime tmpl.
ssize_t tmpl_preparse(char const **out, size_t *outlen, char const *in, size_t inlen, fr_token_t *type))
Preparse a string in preparation for passing it to tmpl_afrom_substr()
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
struct tmpl_rules_s tmpl_rules_t
Optional arguments passed to vp_tmpl functions.
static char buff[sizeof("18446744073709551615")+3]
ssize_t fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX+1], bool *eol)
Skip a conditional expression.
ssize_t fr_skip_xlat(char const *start, char const *end)
Skip an xlat expression.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
fr_aka_sim_id_type_t type
size_t strlcpy(char *dst, char const *src, size_t siz)
uint8_t allow_foreign
Allow arguments not found in dict_def.
fr_dict_t const  * dict_def
Default dictionary to use with unqualified attribute references.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#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.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
An element in a lexicographically sorted array of name to ptr mappings.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
static int talloc_const_free(void const *ptr)
Free const'd memory.
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
const bool fr_assignment_op[T_TOKEN_LAST]
const bool fr_list_assignment_op[T_TOKEN_LAST]
fr_token_t gettoken(char const **ptr, char *buf, int buflen, bool unescape)
fr_table_num_ordered_t const fr_tokens_table[]
const bool fr_str_tok[T_TOKEN_LAST]
int getword(char const **ptr, char *buf, int buflen, bool unescape)
char const * fr_strerror(void)
Get the last library error.
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out
#define FR_VALUE_BOX_SAFE_FOR_ANY
fr_dict_t const * virtual_server_dict_by_child_ci(CONF_ITEM const *ci)
Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server.