29 RCSID(
"$Id: 4dc42faea7749314bbae06bb19913910339c2583 $")
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/parser.h>
33 #include <freeradius-devel/rad_assert.h>
39 #ifdef HAVE_SYS_STAT_H
65 #ifdef WITH_CONF_WRITE
85 #ifdef WITH_CONF_WRITE
86 char const *orig_value;
139 #ifdef WITH_CONF_WRITE
140 typedef struct conf_comment {
145 typedef struct conf_include {
147 char const *filename;
161 void (*data_free)(
void *),
int flag);
167 char *output,
size_t outsize,
168 char const *input,
bool *soft_fail);
185 if (ci == NULL)
return NULL;
189 memcpy(&out, &ci,
sizeof(out));
200 if (ci == NULL)
return NULL;
204 memcpy(&out, &ci,
sizeof(out));
215 if (cp == NULL)
return NULL;
217 memcpy(&out, &cp,
sizeof(out));
228 if (cs == NULL)
return NULL;
230 memcpy(&out, &cs,
sizeof(out));
245 memcpy(&out, &cd,
sizeof(out));
264 return strcmp(one->
attr, two->
attr);
309 if (rcode != 0)
return rcode;
311 return strcmp(one->
name, two->
name);
322 if (one->
buf.st_dev < two->
buf.st_dev)
return -1;
323 if (one->
buf.st_dev > two->
buf.st_dev)
return +1;
325 if (one->
buf.st_ino < two->
buf.st_ino)
return -1;
326 if (one->
buf.st_ino > two->
buf.st_ino)
return +1;
342 if (!cd)
return NULL;
346 fp = fopen(filename,
"r");
348 ERROR(
"Unable to open file \"%s\": %s",
365 if (fstat(fd, &file->
buf) == 0) {
367 if ((file->
buf.st_mode & S_IWOTH) != 0) {
368 ERROR(
"Configuration file %s is globally writable. "
369 "Refusing to start due to insecure configuration.", filename);
404 if (!cd)
return false;
409 if (!file)
return false;
415 if (stat(filename, &file->
buf) < 0) {
423 if ((file->
buf.st_mode & S_IWOTH) != 0) {
424 ERROR(
"Configuration file %s is globally writable. "
425 "Refusing to start due to insecure configuration.", filename);
462 if (stat(file->
filename, &buf) < 0) {
470 if (buf.st_mtime != file->
buf.st_mtime) {
495 if (!cd)
return true;
552 if (!attr)
return NULL;
555 if (!cp)
return NULL;
571 #ifdef WITH_CONF_WRITE
575 if (!cp->
value)
goto error;
598 if (!
new)
return NULL;
631 if (!name1)
return NULL;
633 if (name2 && parent) {
634 if (strchr(name2,
'$')) {
638 buffer,
sizeof(buffer), name2, NULL);
640 ERROR(
"Failed expanding section name");
647 if (!cs)
return NULL;
661 if (!cs->
name2)
goto error;
698 char const *name1,
char const *name2,
bool copy_meta)
709 new->depth = cs->
depth;
740 #ifdef WITH_CONF_WRITE
741 case CONF_ITEM_COMMENT:
742 case CONF_ITEM_INCLUDE:
774 if (!newp)
return -1;
783 for (last = &cs->
children; (*last) != NULL; last = &(*last)->
next) {
811 if (!cs || !ci)
return;
824 for (; ci != NULL; ci = ci->
next) {
838 if (strcmp(cp->
attr,
"confdir") == 0)
break;
839 if (!cp->
value)
break;
850 ERROR(
"Out of memory");
858 ERROR(
"Failed inserting section into tree");
872 ERROR(
"Out of memory");
916 if (!cs)
goto no_such_item;
918 strlcpy(name, ptr,
sizeof(name));
955 }
else if (strchr(p,
'.') != NULL) {
956 if (!parentcs)
goto no_such_item;
968 if (r && q > r) q = NULL;
969 if (q && q < r) r = NULL;
975 q = strchr(r + 1,
']');
982 if (q[1] && q[1] !=
'.')
goto no_such_item;
994 if (!next)
goto no_such_item;
995 return &(next->
item);
1012 if (!*p)
goto no_such_item;
1026 if (next)
return &(next->
item);
1031 if ((p == name) && (parentcs != NULL) && (cs != parentcs)) {
1043 if (!cs)
return NULL;
1058 char *output,
size_t outsize,
1059 char const *input,
bool *soft_fail)
1062 char const *end, *ptr;
1066 if (soft_fail) *soft_fail =
false;
1081 if ((*ptr ==
'$') && (ptr[1] ==
'{')) {
1096 end = strchr(ptr,
'}');
1099 INFO(
"%s[%d]: Variable expansion missing }",
1110 if ((
size_t) (end - ptr) >=
sizeof(name)) {
1111 ERROR(
"%s[%d]: Reference string is too large",
1116 memcpy(name, ptr, end - ptr);
1117 name[end - ptr] =
'\0';
1119 q = strchr(name,
':');
1126 if (soft_fail) *soft_fail =
true;
1127 ERROR(
"%s[%d]: Reference \"${%s}\" not found", cf, *lineno, name);
1139 ERROR(
"%s[%d]: Can only reference properties of sections", cf, *lineno);
1145 strcpy(p, mycs->
name1);
1153 ERROR(
"%s[%d]: Invalid property '%s'", cf, *lineno, q);
1172 if (soft_fail) *soft_fail =
true;
1174 ERROR(
"%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
1175 cf, *lineno, input);
1180 ERROR(
"%s[%d]: Reference \"%s\" has no value",
1181 cf, *lineno, input);
1185 if (p + strlen(cp->
value) >= output + outsize) {
1186 ERROR(
"%s[%d]: Reference \"%s\" is too long",
1187 cf, *lineno, input);
1191 strcpy(p, cp->
value);
1203 if (ci->
parent == outercs) {
1204 ERROR(
"%s[%d]: Cannot reference different item in same section", cf, *lineno);
1217 ERROR(
"%s[%d]: Failed copying reference %s", cf, *lineno, name);
1228 ERROR(
"%s[%d]: Reference \"%s\" type is invalid", cf, *lineno, input);
1231 }
else if (memcmp(ptr,
"$ENV{", 5) == 0) {
1241 end = strchr(ptr,
'}');
1244 INFO(
"%s[%d]: Environment variable expansion missing }",
1253 if ((
size_t) (end - ptr) >=
sizeof(name)) {
1254 ERROR(
"%s[%d]: Environment variable name is too large",
1259 memcpy(name, ptr, end - ptr);
1260 name[end - ptr] =
'\0';
1272 if (p + strlen(env) >= output + outsize) {
1273 ERROR(
"%s[%d]: Reference \"%s\" is too long",
1274 cf, *lineno, input);
1290 if (p >= (output + outsize)) {
1291 ERROR(
"%s[%d]: Reference \"%s\" is too long",
1292 cf, *lineno, input);
1312 if (strcmp(value,
"*") == 0) {
1314 }
else if (strspn(value,
".0123456789abdefABCDEF:%[]/") == strlen(value)) {
1317 cf_log_info(cs,
"%.*s\t%s = %s IPv%s address [%s]", cs->
depth, parse_spaces, name, value,
1318 (ipaddr->
af == AF_INET ?
"4" :
" 6"),
fr_inet_ntoh(ipaddr, ipbuf,
sizeof(ipbuf)));
1325 switch (ipaddr->
af) {
1327 if (ipaddr->
prefix != 32) {
1328 ERROR(
"Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted for non-prefix types",
1336 if (ipaddr->
prefix != 128) {
1337 ERROR(
"Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted for non-prefix types",
1372 for (i = 0; variables[i].
name != NULL; i++) {
1373 bool attribute, multi, is_tmpl, is_xlat;
1377 char const *name = variables[i].
name;
1378 int type = variables[i].
type;
1394 (
CONF_PARSER const *)variables[i].dflt) < 0)
return -1;
1408 data = variables[i].
data;
1409 if (!data && base) data = ((
char *)base) + variables[i].
offset;
1410 if (!data)
continue;
1415 if (!is_xlat && !is_tmpl) {
1422 if (strstr(cp->
value,
"%{") != NULL) {
1424 "will not be dynamically expanded");
1448 value = talloc_strdup(cs, cp->
value);
1459 talloc_free(spaces);
1481 }
else if (is_tmpl) {
1498 talloc_free(spaces);
1509 switch (vpt->
type) {
1515 cf_log_err(&cp->
item,
"Unknown attribute '%s'", vpt->tmpl_unknown_name);
1563 bool attribute, required,
secret, file_input, cant_be_empty, tmpl;
1580 if (required) cant_be_empty =
true;
1587 if (!type && !tmpl) {
1597 if ((cp->
value[0] ==
'\0') && cant_be_empty) {
1599 if (!required)
cf_log_err_cp(cp,
"Comment item to silence this message");
1629 talloc_free(spaces);
1646 *(
bool *)out =
true;
1650 *(
bool *)out =
false;
1652 cf_log_err(&(cs->
item),
"Invalid value \"%s\" for boolean variable %s",
1662 unsigned long v = strtoul(cp->
value, 0, 0);
1671 if (v > INT32_MAX) {
1672 cf_log_err(&(cs->
item),
"Invalid value \"%s\" for variable %s, must be between 0-%u", cp->
value,
1678 *(uint32_t *)out = v;
1685 unsigned long v = strtoul(cp->
value, 0, 0);
1687 if (v > UINT8_MAX) {
1688 cf_log_err(&(cs->
item),
"Invalid value \"%s\" for variable %s, must be between 0-%u", cp->
value,
1693 *(uint8_t *)out = (uint8_t) v;
1700 unsigned long v = strtoul(cp->
value, 0, 0);
1702 if (v > UINT16_MAX) {
1703 cf_log_err(&(cs->
item),
"Invalid value \"%s\" for variable %s, must be between 0-%u", cp->
value,
1708 *(uint16_t *)out = (uint16_t) v;
1714 *(uint64_t *)out = strtoull(cp->
value, 0, 0);
1719 *(int32_t *)out = strtol(cp->
value, 0, 0);
1813 (
int)tv.tv_sec, (
int)tv.tv_usec);
1814 memcpy(out, &tv,
sizeof(tv));
1827 cf_log_err(&(cp->
item),
"type '%s' is not supported in the configuration files",
1854 int type,
char const *dflt,
FR_TOKEN dflt_quote)
1857 char const *expanded;
1866 expanded =
cf_expand_variables(
"<internal>", &lineno, cs, buffer,
sizeof(buffer), dflt, NULL);
1969 char const *dflt,
FR_TOKEN dflt_quote)
1971 bool multi, required, deprecated;
2002 if (deprecated)
return 0;
2006 cf_log_err_cs(cs,
"Configuration item \"%s\" must have a value", name);
2012 if (
cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0)
return -1;
2028 if (type & PW_TYPE_TMPL) {
2029 array = (
void **)talloc_zero_array(cs,
vp_tmpl_t *, count);
2036 }
else switch (type & 0xff) {
2038 array = (
void **)talloc_zero_array(cs,
bool, count);
2042 array = (
void **)talloc_zero_array(cs, uint32_t, count);
2046 array = (
void **)talloc_zero_array(cs, uint16_t, count);
2050 array = (
void **)talloc_zero_array(cs, uint64_t, count);
2054 array = (
void **)talloc_zero_array(cs, int32_t, count);
2058 array = (
void **)talloc_zero_array(cs,
char *, count);
2062 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2066 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2070 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2074 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2078 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2082 array = (
void **)talloc_zero_array(cs,
fr_ipaddr_t, count);
2086 array = (
void **)talloc_zero_array(cs,
struct timeval, count);
2097 talloc_free(dflt_cp);
2102 *(
void **)data = array;
2110 if (deprecated)
return 0;
2112 if (required)
goto need_value;
2116 if (
cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0)
return -1;
2120 if (deprecated)
goto deprecated;
2123 talloc_free(dflt_cp);
2149 for (i = 0; variables[i].
name != NULL; i++) {
2153 if (!variables[i].dflt)
continue;
2184 if (variables[i].data) {
2185 *(
char **) variables[i].data = NULL;
2187 *(
char **) (((
char *)base) + variables[i].offset) = NULL;
2209 if (cp->
parsed)
continue;
2211 WARN(
"%s[%d]: The item '%s' is defined, but is unused by the configuration",
2253 for (i = 0; variables[i].
name != NULL; i++) {
2265 if (!variables[i].dflt || !subcs) {
2266 ERROR(
"Internal sanity check 1 failed in cf_section_parse %s", variables[i].name);
2273 if (ret < 0)
goto finish;
2277 if (variables[i].data) {
2278 data = variables[i].
data;
2280 data = ((
char *)base) + variables[i].
offset;
2282 ERROR(
"Internal sanity check 2 failed in cf_section_parse");
2290 ret =
cf_pair_parse(cs, variables[i].name, variables[i].type, data,
2291 variables[i].dflt, variables[i].quote);
2304 if ((variables[i + 1].offset == variables[i].offset) &&
2305 (variables[i + 1].data == variables[i].data)) {
2307 variables[i + 1].
name);
2340 if (!cs || !
template)
return true;
2349 for (ci = template->children; ci; ci = ci->
next) {
2366 if (!cp2)
return false;
2400 if (!subcs2)
return false;
2416 char *buffer,
size_t bufsize)
2421 strlcpy(buffer, base, bufsize);
2423 p = strrchr(buffer, FR_DIR_SEP);
2424 if (!p)
return filename;
2429 dirsize = (p - buffer) + 1;
2431 if ((dirsize + strlen(filename)) >= bufsize) {
2435 strlcpy(p + 1, filename, bufsize - dirsize);
2447 if (!
this || !this->item.parent) {
2449 ERROR(
"%s[%d]: Invalid location for '%s'",
2450 filename, lineno, name);
2457 this = this->item.parent;
2458 while ((strcmp(this->name1,
"server") != 0) &&
2459 (strcmp(this->name1,
"policy") != 0) &&
2460 (strcmp(this->name1,
"instantiate") != 0)) {
2461 this = this->item.parent;
2468 #ifdef WITH_CONF_WRITE
2469 static void cf_comment_add(
CONF_SECTION *cs,
int lineno,
char const *ptr)
2473 cc = talloc_zero(cs, CONF_COMMENT);
2474 cc->item.type = CONF_ITEM_COMMENT;
2475 cc->item.parent = cs;
2477 cc->item.lineno = lineno;
2488 cc = talloc_zero(cs, CONF_INCLUDE);
2489 cc->item.type = CONF_ITEM_INCLUDE;
2490 cc->item.parent = cs;
2492 cc->item.lineno = 0;
2494 cc->file_type = file_type;
2512 #ifdef WITH_CONF_WRITE
2513 char const *orig_value = NULL;
2517 bool has_spaces =
false;
2536 at_eof = (fgets(cbuff, talloc_array_length(buff[0]) - (cbuff - buff[0]), fp) == NULL);
2546 len = strlen(cbuff);
2547 if ((cbuff + len + 1) >= (buff[0] + talloc_array_length(buff[0]))) {
2548 ERROR(
"%s[%d]: Line too long", filename, *lineno);
2555 while (isspace((
int) *ptr)) ptr++;
2558 memmove(cbuff, ptr, len - (ptr - cbuff));
2559 len -= (ptr - cbuff);
2567 if (cbuff == buff[0]) {
2571 while (*ptr && isspace((
int) *ptr)) ptr++;
2573 #ifdef WITH_CONF_WRITE
2578 cf_comment_add(
this, *lineno, ptr + 1);
2582 if (!*ptr || (*ptr ==
'#'))
continue;
2584 }
else if (at_eof || (len == 0)) {
2585 ERROR(
"%s[%d]: Continuation at EOF is illegal", filename, *lineno);
2593 ((cbuff[len - 1] ==
'\n') || (cbuff[len - 1] ==
'\r'))) {
2598 if ((len > 0) && (cbuff[len - 1] ==
'\\')) {
2602 if (!has_spaces && (len > 2) && (cbuff[len - 2] ==
'"')) {
2606 cbuff[len - 1] =
'\0';
2611 ptr = cbuff = buff[0];
2620 while ((*ptr ==
' ') || (*ptr ==
'\t')) ptr++;
2622 if (((ptr[0] ==
'%') && (ptr[1] ==
'{')) ||
2626 if (ptr[0] ==
'%') {
2636 ERROR(
"%s[%d]: %s", filename, *lineno, text);
2637 ERROR(
"%s[%d]: %s^ Invalid expansion", filename, *lineno, spaces);
2639 talloc_free(spaces);
2647 t2 =
gettoken(&ptr, buff[2], talloc_array_length(buff[2]),
true);
2654 ERROR(
"%s[%d]: Invalid expansion: %s", filename, *lineno, ptr);
2658 t1 =
gettoken(&ptr, buff[1], talloc_array_length(buff[1]),
true);
2668 if (
this == current) {
2669 ERROR(
"%s[%d]: Too many closing braces", filename, *lineno);
2681 this = this->item.parent;
2682 goto check_for_more;
2693 if ((
strcasecmp(buff[1],
"$INCLUDE") == 0) ||
2695 bool relative =
true;
2697 t2 =
getword(&ptr, buff[2], talloc_array_length(buff[2]),
true);
2699 ERROR(
"%s[%d]: Unexpected text after $INCLUDE", filename, *lineno);
2703 if (buff[2][0] ==
'$') relative =
false;
2705 value =
cf_expand_variables(filename, lineno,
this, buff[4], talloc_array_length(buff[4]),
2707 if (!value)
goto error;
2709 if (!FR_DIR_IS_RELATIVE(value)) relative =
false;
2712 value =
cf_local_file(filename, value, buff[3], talloc_array_length(buff[3]));
2714 ERROR(
"%s[%d]: Directories too deep", filename, *lineno);
2720 #ifdef HAVE_DIRENT_H
2727 if (value[strlen(value) - 1] ==
'/') {
2730 struct stat stat_buf;
2733 my_directory = talloc_strdup(
this, value);
2735 DEBUG2(
"including files in directory %s", my_directory);
2737 #ifdef WITH_CONF_WRITE
2750 if (stat(my_directory, &stat_buf) < 0) {
2751 ERROR(
"%s[%d]: Failed reading directory %s: %s",
2754 talloc_free(my_directory);
2758 if ((stat_buf.st_mode & S_IWOTH) != 0) {
2759 ERROR(
"%s[%d]: Directory %s is globally writable. Refusing to start due to "
2760 "insecure configuration", filename, *lineno, my_directory);
2761 talloc_free(my_directory);
2765 dir = opendir(my_directory);
2767 ERROR(
"%s[%d]: Error reading directory %s: %s",
2768 filename, *lineno, value,
2770 talloc_free(my_directory);
2777 while ((dp = readdir(dir)) != NULL) {
2780 if (dp->d_name[0] ==
'.')
continue;
2785 for (p = dp->d_name; *p !=
'\0'; p++) {
2786 if (isalpha((
int)*p) ||
2790 (*p ==
'.'))
continue;
2793 if (*p !=
'\0')
continue;
2796 snprintf(buff[2], talloc_array_length(buff[2]),
"%s%s",
2797 my_directory, dp->d_name);
2798 if ((stat(buff[2], &stat_buf) != 0) ||
2799 S_ISDIR(stat_buf.st_mode))
continue;
2811 talloc_free(my_directory);
2816 if (buff[1][1] ==
'-') {
2817 struct stat statbuf;
2819 if (stat(value, &statbuf) < 0) {
2833 t2 =
getword(&ptr, buff[2], talloc_array_length(buff[2]),
true);
2836 ERROR(
"%s[%d]: Unexpected text after $TEMPLATE", filename, *lineno);
2844 ERROR(
"%s[%d]: No \"templates\" section for reference \"%s\"", filename, *lineno, buff[2]);
2850 ERROR(
"%s[%d]: Reference \"%s\" not found", filename, *lineno, buff[2]);
2855 ERROR(
"%s[%d]: Internal sanity check error in template reference", filename, *lineno);
2859 if (this->
template) {
2860 ERROR(
"%s[%d]: Section already has a template", filename, *lineno);
2872 if (buff[1][0] ==
'_') {
2873 ERROR(
"%s[%d]: Illegal configuration pair name \"%s\"", filename, *lineno, buff[1]);
2880 if ((strcmp(buff[1],
"if") == 0) || (strcmp(buff[1],
"elsif") == 0)) {
2882 char const *error = NULL;
2893 memcpy(&p, &ptr,
sizeof(p));
2896 if (p[-slen] !=
'{')
goto cond_error;
2922 while ((p > ptr) && (isspace((
int) p[-1]))) {
2930 if (strchr(ptr,
'$') != NULL) {
2933 buff[3], talloc_array_length(buff[3]),
2936 ERROR(
"%s[%d]: Parse error expanding ${...} in condition",
2944 ERROR(
"%s[%d]: Failed allocating memory for section", filename, *lineno);
2960 ERROR(
"%s[%d]: Parse error in condition",
2962 ERROR(
"%s[%d]: %s", filename, *lineno, text);
2963 ERROR(
"%s[%d]: %s^ %s", filename, *lineno, spaces, error);
2965 talloc_free(spaces);
2971 if ((
size_t) slen >= (talloc_array_length(buff[2]) - 1)) {
2973 ERROR(
"%s[%d]: Condition is too large after \"%s\"", filename, *lineno, buff[1]);
2986 memcpy(buff[2], ptr, slen);
2987 buff[2][slen] =
'\0';
2990 if ((t3 =
gettoken(&ptr, buff[3], talloc_array_length(buff[3]),
true)) !=
T_LCBRACE) {
2992 ERROR(
"%s[%d]: Expected '{' %d", filename, *lineno, t3);
3014 goto check_for_more;
3020 if (strcmp(buff[1],
"map") == 0) {
3026 t2 =
gettoken(&ptr, buff[2], talloc_array_length(buff[2]),
false);
3028 ERROR(
"%s[%d]: Expected module name after 'map'", filename, *lineno);
3034 buff[3], talloc_array_length(buff[3]),
3037 ERROR(
"%s[%d]: Parse error expanding ${...} in map module name",
3042 t3 =
gettoken(&ptr, buff[4], talloc_array_length(buff[4]),
false);
3044 ERROR(
"%s[%d]: Expected map string after '%s'",
3045 filename, *lineno, buff[2]);
3051 buff[5], talloc_array_length(buff[5]),
3054 ERROR(
"%s[%d]: Parse error expanding ${...} in map module name",
3059 if (
gettoken(&ptr, buff[6], talloc_array_length(buff[6]),
false) !=
T_LCBRACE) {
3060 ERROR(
"%s[%d]: Expecting section start brace '{' in 'map' definition",
3070 ERROR(
"%s[%d]: Failed allocating memory for section", filename, *lineno);
3078 css->
argv = talloc_array(css,
char const *, 1);
3091 t2 =
gettoken(&ptr, buff[2], talloc_array_length(buff[2]),
false);
3109 if (!
this || ((strcmp(this->name1,
"update") != 0) && (strcmp(this->name1,
"map") != 0))) {
3110 ERROR(
"%s[%d]: Invalid operator in assignment",
3118 while (isspace((
int) *ptr)) ptr++;
3132 t3 =
getstring(&ptr, buff[3], talloc_array_length(buff[3]),
false);
3137 const char *q = ptr;
3140 while (*q && (*q >=
' ') && (*q !=
',') &&
3143 if ((
size_t) (q - ptr) >= talloc_array_length(buff[3])) {
3144 ERROR(
"%s[%d]: Parse error: value too long", filename, *lineno);
3148 memcpy(buff[3], ptr, (q - ptr));
3149 buff[3][q - ptr] =
'\0';
3168 #ifdef WITH_CONF_WRITE
3169 orig_value = buff[3];
3171 value =
cf_expand_variables(filename, lineno,
this, buff[4], talloc_array_length(buff[4]), buff[3], &soft_fail);
3173 if (!soft_fail)
goto error;
3201 if (!cpn)
goto error;
3207 #ifdef WITH_CONF_WRITE
3214 while (isspace(*ptr)) ptr++;
3225 #ifdef WITH_CONF_WRITE
3234 if ((t3 ==
T_HASH) && (*ptr >=
' ')) {
3235 cf_comment_add(
this, *lineno, ptr);
3241 if (!*ptr || (*ptr ==
'}'))
break;
3243 ERROR(
"%s[%d]: Syntax error: Expected comma after '%s': %s",
3244 filename, *lineno, value, ptr);
3253 t3 =
gettoken(&ptr, buff[3], talloc_array_length(buff[3]),
true);
3255 ERROR(
"%s[%d]: Expecting section start brace '{' after \"%s %s\"",
3256 filename, *lineno, buff[1], buff[2]);
3265 ERROR(
"%s[%d]: Failed allocating memory for section",
3286 ERROR(
"%s[%d]: Syntax error in '%s': %s", filename, *lineno, ptr,
fr_strerror());
3291 ERROR(
"%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
3301 while (isspace(*ptr)) ptr++;
3303 if (*ptr ==
'#')
continue;
3314 if (feof(fp) && (
this != current)) {
3315 ERROR(
"%s[%d]: EOF reached without closing brace for section %s starting at line %d",
3327 #ifndef WITH_CONF_WRITE
3334 char const *filename;
3339 filename = talloc_strdup(cs, filename_in);
3341 DEBUG2(
"including configuration file %s", filename);
3348 #ifdef WITH_CONF_WRITE
3353 cf_include_add(cs, filename, file_type);
3365 #ifdef WITH_CONF_WRITE
3370 cf_include_add(cs, NULL, file_type);
3402 if (!value)
return -1;
3432 p = strrchr(cp->
value, FR_DIR_SEP);
3440 if (!tree)
return -1;
3447 buff = talloc_array(cs,
char *, 7);
3448 for (i = 0; i < 7; i++) {
3449 buff[i] = talloc_array(buff,
char, 8192);
3482 if (!cs || !name)
return NULL;
3499 return (pair ? pair->
attr : NULL);
3508 return (pair ? pair->
value : NULL);
3594 return (cs ? cs->
name1 : NULL);
3603 return (cs ? cs->
name2 : NULL);
3614 if (name)
return name;
3621 if (!cs || !cs->
argv || (argc < 0) || (argc > cs->
argc))
return NULL;
3623 return cs->
argv[argc];
3635 return (cp ? cp->
value : NULL);
3640 char const *name1,
char const *name2)
3645 if (!cs || !name1)
return NULL;
3647 for (ci = &(cs->
item); ci; ci = ci->
next) {
3657 if ((!name2 && !their2) ||
3658 (name2 && their2 && (strcmp(name2, their2) == 0))) {
3674 CONF_PAIR const *pair,
char const *attr)
3678 if (!cs)
return NULL;
3712 if (!cs || !name)
return NULL;
3729 char const *name1,
char const *name2)
3733 if (!cs)
return NULL;
3744 if (!master_cs)
return NULL;
3754 if (subcs)
return subcs;
3762 if (!master_cs->
name2 && name2)
return NULL;
3763 if (master_cs->
name2 && !name2)
return NULL;
3764 if (!master_cs->
name2 && !name2)
return master_cs;
3766 if (strcmp(master_cs->
name2, name2) == 0) {
3783 if (!subcs->
name2) {
3784 if (strcmp(subcs->
name1, name2) == 0)
break;
3786 if (strcmp(subcs->
name2, name2) == 0)
break;
3805 if (!section)
return NULL;
3818 for (; ci; ci = ci->
next) {
3821 if ((name1 == NULL) ||
3840 if (!section)
return NULL;
3852 if (!section)
return NULL;
3898 if (!ci)
return NULL;
3935 void *data,
void (*data_free)(
void *))
3940 if (!cd)
return NULL;
3951 cd->
free = data_free;
3962 if (!cs || !name)
return NULL;
3985 if (cd)
return cd->
data;
3994 void *data,
void (*data_free)(
void *),
3999 if (!cs || !name)
return -1;
4019 void *data,
void (*data_free)(
void *))
4033 if (!cs || !name)
return NULL;
4042 if (!cd)
return NULL;
4044 talloc_set_destructor(cd, NULL);
4065 vsnprintf(buffer,
sizeof(buffer), fmt, ap);
4074 ERROR(
"<unknown>[*]: %s", buffer);
4084 vsnprintf(buffer,
sizeof(buffer), fmt, ap);
4101 vsnprintf(buffer,
sizeof(buffer), fmt, ap);
4131 vsnprintf(buffer,
sizeof(buffer), fmt, ap);
4133 DEBUG(
"%.*s# %s", cs->
depth, parse_spaces, buffer);
4140 if (!cs)
return NULL;
4162 #ifdef WITH_CONF_WRITE
4163 static char const parse_tabs[] =
" ";
4165 static ssize_t cf_string_write(FILE *fp,
char const *
string,
size_t len,
FR_TOKEN t)
4189 if (c) fprintf(fp,
"%c", c);
4191 outlen =
fr_snprint(buffer,
sizeof(buffer),
string, len, c);
4192 fwrite(buffer, outlen, 1, fp);
4194 if (c) fprintf(fp,
"%c", c);
4199 static size_t cf_pair_write(FILE *fp,
CONF_PAIR *cp)
4202 fprintf(fp,
"%s\n", cp->
attr);
4208 cf_string_write(fp, cp->orig_value, strlen(cp->orig_value), cp->
rhs_type);
4215 static FILE *cf_file_write(
CONF_SECTION *cs,
char const *filename)
4223 if ((q[0] ==
'.') && (q[1] ==
'/')) q += 2;
4227 p = strrchr(buffer,
'/');
4229 if ((
rad_mkdir(buffer, 0700, -1, -1) < 0) &&
4230 (errno != EEXIST)) {
4232 buffer, strerror(errno));
4241 fp = fopen(buffer,
"a");
4244 buffer, strerror(errno));
4251 size_t cf_section_write(FILE *in_fp,
CONF_SECTION *cs,
int depth)
4271 fwrite(parse_tabs, depth, 1, fp);
4291 fprintf(fp,
"(%s)", buffer);
4321 fwrite(parse_tabs, depth + 1, 1, fp);
4323 if (!prev) fputs(
"\n", fp);
4327 case CONF_ITEM_COMMENT:
4331 fwrite(parse_tabs, depth + 1, 1, fp);
4332 fprintf(fp,
"#%s", ((CONF_COMMENT *)ci)->comment);
4335 case CONF_ITEM_INCLUDE:
4341 if (((CONF_INCLUDE *) ci)->filename) {
4342 CONF_INCLUDE *cc = (CONF_INCLUDE *) ci;
4353 fprintf(fp,
"$INCLUDE %s\n", ((CONF_INCLUDE *)ci)->filename);
4362 fp = cf_file_write(cs, ((CONF_INCLUDE *) ci)->filename);
4387 fwrite(parse_tabs, depth, 1, fp);
static char const parse_spaces[]
PUBLIC int vsnprintf(char *string, size_t length, char *format, va_list args)
#define PW_TYPE_FILE_INPUT
File matching value must exist, and must be readable.
static int cf_section_read(char const *filename, int *lineno, FILE *fp, CONF_SECTION *current, char *buff[7])
int cf_section_parse(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, size_t inlen, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def, bool do_escape)
Convert an arbitrary string into a vp_tmpl_t.
CONF_ITEM * tail
For speed.
FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
void rbtree_free(rbtree_t *tree)
void * data
Pointer to a static variable to write the parsed value to.
static int data_cmp(void const *a, void const *b)
Only displayed when debugging is enabled.
CONF_SECTION * cf_item_parent(CONF_ITEM const *ci)
Time value (struct timeval), only for config items.
char const * cf_section_filename(CONF_SECTION const *section)
Main server configuration.
CONF_ITEM_TYPE type
Whether the config item is a config_pair, conf_section or conf_data.
char const * value
Attribute value.
static void _pair_count(int *count, CONF_SECTION const *cs)
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
static int _cf_data_free(CONF_DATA *cd)
char const * name
Name of the CONF_ITEM to parse.
static CONF_ITEM * cf_data_to_item(CONF_DATA const *cd)
Cast CONF_DATA to a CONF_ITEM.
CONF_SECTION * cf_top_section(CONF_SECTION *cs)
static int file_callback(void *ctx, void *data)
int type
A PW_TYPE value, may be or'd with one or more PW_TYPE_* flags.
FR_TOKEN cf_pair_operator(CONF_PAIR const *pair)
3rd highest priority debug messages (-xxx | -Xx).
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
WiMAX IPv4 or IPv6 address depending on length.
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *pair, char const *attr)
Find a pair with a name matching attr, after specified pair.
rbtree_t * name2_tree
for sections of the same name2
Pre-parsed XLAT expansion.
struct conf_part * parent
Parent.
int cf_pair_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt, FR_TOKEN dflt_quote)
Parses a CONF_PAIR into a C data type, with a default value.
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
const FR_NAME_NUMBER fr_tokens_table[]
char const * cf_section_name1(CONF_SECTION const *cs)
void * cf_data_remove(CONF_SECTION *cs, char const *name)
Remove named data from a configuration section.
char const * cf_section_name(CONF_SECTION const *cs)
Return name2 if set, else name1.
static int cf_data_add_internal(CONF_SECTION *cs, char const *name, void *data, void(*data_free)(void *), int flag)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
static char const * cf_local_file(char const *base, char const *filename, char *buffer, size_t bufsize)
Number of defined data types.
void rad_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.
#define PW_TYPE_SECRET
Only print value if debug level >= 3.
size_t offset
Relative offset of field or structure to write the parsed value to.
FR_TOKEN cf_section_argv_type(CONF_SECTION const *cs, int argc)
#define PW_TYPE_DEPRECATED
If a matching CONF_PAIR is found, error out with a deprecated message.
void * rbtree_finddata(rbtree_t *tree, void const *data)
Find the user data.
FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs)
static CONF_DATA * cf_data_alloc(CONF_SECTION *parent, char const *name, void *data, void(*data_free)(void *))
int rad_mkdir(char *directory, mode_t mode, uid_t uid, gid_t gid)
Create possibly many directories.
CONF_SECTION * cf_section_find_next(CONF_SECTION const *section, CONF_SECTION const *subsection, char const *name1)
char const ** argv
additional arguments
#define PW_TYPE_SUBSECTION
enum conf_include_type CONF_INCLUDE_TYPE
Defines a CONF_PAIR to C data type mapping.
void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs)
int cf_file_read(CONF_SECTION *cs, char const *filename)
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.
WiMAX IPv4 or IPv6 address prefix depending on length.
static int cf_section_pass2(CONF_SECTION *cs)
static bool invalid_location(CONF_SECTION *this, char const *name, char const *filename, int lineno)
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
const bool fr_equality_op[]
void cf_log_err(CONF_ITEM const *ci, char const *fmt,...)
static void * cf_data_find_internal(CONF_SECTION const *cs, char const *name, int flag)
Attribute not found in the global dictionary.
static int _cf_section_free(CONF_SECTION *cs)
Pre-parsed regular expression.
void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
static int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, PW_TYPE type, char const *value, fr_ipaddr_t *ipaddr)
Validation function for ipaddr conffile types.
static int pair_cmp(void const *a, void const *b)
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
bool cf_item_is_section(CONF_ITEM const *item)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static void cf_section_parse_warn(CONF_SECTION *cs)
CONF_SECTION * cf_section_find_name2(CONF_SECTION const *cs, char const *name1, char const *name2)
FR_TOKEN name2_type
The type of quoting around name2.
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser...
CONF_SECTION * cf_subsection_find_next(CONF_SECTION const *section, CONF_SECTION const *subsection, char const *name1)
int lineno
The line number the config item began on.
void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp)
Add a configuration pair to a section.
char const * attr
Attribute name.
void cf_log_info(CONF_SECTION const *cs, char const *fmt,...)
void(* free)(void *)
Free user data function.
rbtree_t * rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
Create a new RED-BLACK tree.
bool cf_item_is_pair(CONF_ITEM const *item)
const CONF_PARSER * cf_section_parse_table(CONF_SECTION *cs)
char const * name1
First name token. Given foo bar {} would be foo.
void cf_file_free(CONF_SECTION *cs)
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair in a given section with a new pair, of the given value.
int fr_pair_mark_xlat(VALUE_PAIR *vp, char const *value)
Mark a valuepair for xlat expansion.
const bool fr_assignment_op[]
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
CONF_SECTION * cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
#define PW_TYPE_XLAT
string will be dynamically expanded.
int cf_pair_count(CONF_SECTION const *cs)
Count the number of conf pairs beneath a section.
int getword(char const **ptr, char *buf, int buflen, bool unescape)
Attributes in incoming or internally proxied request.
int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback)
static int cf_pair_default(CONF_PAIR **out, CONF_SECTION *cs, char const *name, int type, char const *dflt, FR_TOKEN dflt_quote)
Allocate a pair using the dflt value and quotation.
FR_TOKEN rhs_type
Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
rbtree_t * section_tree
no jokes here.
int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
static const FR_NAME_NUMBER conf_property_name[]
int cf_section_parse_pass2(CONF_SECTION *cs, void *base, CONF_PARSER const variables[])
Fixup xlat expansions and attributes.
enum conf_type CONF_ITEM_TYPE
char const * name2
Second name token. Given foo bar {} would be bar.
Stores an attribute, a value and various bits of other data.
void rad_const_free(void const *ptr)
int cf_data_add(CONF_SECTION *cs, char const *name, void *data, void(*data_free)(void *))
static FILE * cf_file_open(CONF_SECTION *cs, char const *filename)
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv4 address or IPv4 prefix in presentation format (and others)
char const * cf_pair_attr(CONF_PAIR const *pair)
char const * cf_pair_value(CONF_PAIR const *pair)
CONF_PARSER const * variables
char const * cf_section_name2(CONF_SECTION const *cs)
Invalid (uninitialised) attribute type.
VALUE_PAIR * cf_pairtovp(CONF_PAIR *pair)
CONF_ITEM * cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
Return the next item after a CONF_ITEM.
Configuration AVP similar to a VALUE_PAIR.
void * cf_data_find(CONF_SECTION const *cs, char const *name)
tmpl_type_t type
What type of value tmpl refers to.
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *cs, char const *name)
Find a sub-section in a section.
char const * fr_strerror(void)
Get the last library error.
enum conf_property CONF_PROPERTY
int strcasecmp(char *s1, char *s2)
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
int(* rb_walker_t)(void *ctx, void *data)
#define PW_TYPE_MULTI
CONF_PAIR can have multiple copies.
struct conf_item * next
Sibling.
Internal data that is associated with a configuration section.
int cf_pair_lineno(CONF_PAIR const *pair)
CONF_SECTION * cf_section_sub_find_name2(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with both names.
static int name2_cmp(void const *a, void const *b)
#define PW_TYPE_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
char const * cf_section_value_find(CONF_SECTION const *cs, char const *attr)
Callout to an external script or program.
static void cf_section_parse_init(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
#define PW_TYPE_FILE_OUTPUT
File matching value must exist, and must be writeable.
size_t fr_cond_snprint(char *buffer, size_t bufsize, fr_cond_t const *c)
log_lvl_t rad_debug_lvl
Global debugging level.
FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape)
rbtree_t * pair_tree
and a partridge..
void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt,...)
bool rbtree_insert(rbtree_t *tree, void *data)
char const * filename
The file the config item was parsed from.
void void void fr_canonicalize_error(TALLOC_CTX *ctx, char **spaces, char **text, ssize_t slen, char const *msg)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
ssize_t ssize_t ssize_t ssize_t ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error)
ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flag)
Tokenize a conditional check.
static char const * secret
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
struct cf_file_callback_t cf_file_callback_t
static char const * cf_expand_variables(char const *cf, int *lineno, CONF_SECTION *outercs, char *output, size_t outsize, char const *input, bool *soft_fail)
FR_TOKEN lhs_type
Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair)
Return the value (rhs) type.
bool parsed
Was this item used during parsing?
static int cf_pair_parse_value(void *out, TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_PAIR *cp, unsigned int type)
Parses a CONF_PAIR into a C data type.
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
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 *name)
void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...)
size_t strlcpy(char *dst, char const *src, size_t siz)
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type)
Allocate a CONF_PAIR.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
bool pass2
do expansion in pass2.
#define PW_TYPE_ATTRIBUTE
Value must resolve to attribute in dict (deprecated, use PW_TYPE_TMPL).
static int cf_file_include(CONF_SECTION *cs, char const *filename_in, CONF_INCLUDE_TYPE file_type, char *buff[7])
char const * cf_pair_filename(CONF_PAIR const *pair)
String of printable characters.
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
#define PW_TYPE_TMPL
CONF_PAIR should be parsed as a template.
struct cf_file_t cf_file_t
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
static bool cf_file_input(CONF_SECTION *cs, char const *filename)
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
CONF_PAIR * cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp)
Duplicate a CONF_PAIR.
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
A source or sink of value data.
int fr_timeval_from_str(struct timeval *out, char const *in)
Create timeval from a string.
const FR_NAME_NUMBER tmpl_names[]
Map tmpl_type_t values to descriptive strings.
int rad_copy_variable(char *dst, char const *from)
static int section_cmp(void const *a, void const *b)
CONF_ITEM * cf_reference_item(CONF_SECTION const *parentcs, CONF_SECTION *outercs, char const *ptr)
int cf_section_lineno(CONF_SECTION const *section)
int argc
number of additional arguments
void cf_log_module(CONF_SECTION const *cs, char const *fmt,...)
int rad_copy_string(char *dst, char const *src)
int vradlog(log_type_t lvl, char const *fmt, va_list ap) CC_HINT(format(printf
PW_TYPE
Internal data types used within libfreeradius.
CONF_SECTION * cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
Allocate a CONF_SECTION.
FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair)
Return the value (lhs) type.
FR_TOKEN op
Operator e.g. =, :=.
static int filename_cmp(void const *a, void const *b)