Rework the internals of CONF_ITEMs, CONF_SECTIONs, CONF_DATA so they're simple/sane.
Allow nested CONF_DATA
Provide functions to iterate over CONF_DATA of the same type
Get CONF_DATA by type only
Get CONF_DATA by name only
*/
typedef struct cf_item CONF_ITEM; //!< Generic configuration element, extended to become
///< a #CONF_PAIR, a #CONF_SECTION or #CONF_DATA.
-typedef struct cf_pair CONF_PAIR; //!< #CONF_ITEM with an attribute, an operator and a value.
typedef struct cf_section CONF_SECTION; //!< #CONF_ITEM used to group multiple #CONF_PAIR and #CONF_SECTION, together.
+typedef struct cf_pair CONF_PAIR; //!< #CONF_ITEM with an attribute, an operator and a value.
typedef struct cf_data CONF_DATA; //!< #CONF_ITEM used to associate arbitrary data
///< with a #CONF_PAIR or #CONF_SECTION.
#define CONF_PARSER_PARTIAL_TERMINATOR { .name = NULL, .type = ~(UINT32_MAX - 1), \
.offset = 1, .data = NULL, .dflt = NULL, .quote = T_INVALID }
+#define CF_FILE_NONE (0)
+#define CF_FILE_ERROR (1)
+#define CF_FILE_CONFIG (1 << 2)
+#define CF_FILE_MODULE (1 << 3)
+
+/** Auto cast from the input type to CONF_ITEM (which is the base type)
+ *
+ * Automatically casts:
+ * - #CONF_SECTION
+ * - #CONF_PAIR
+ * - #CONF_DATA
+ *
+ * To a #CONF_ITEM, whilst performing talloc type checks.
+ */
+#define CF_TO_ITEM(_cf) \
+_Generic((_cf), \
+ CONF_SECTION *: cf_section_to_item((CONF_SECTION const *)_cf), \
+ CONF_SECTION const *: cf_section_to_item((CONF_SECTION const *)_cf), \
+ CONF_PAIR *: cf_pair_to_item((CONF_PAIR const *)_cf), \
+ CONF_PAIR const *: cf_pair_to_item((CONF_PAIR const *)_cf), \
+ CONF_DATA *: cf_data_to_item((CONF_DATA const *)_cf), \
+ CONF_DATA const *: cf_data_to_item((CONF_DATA const *)_cf), \
+ default: _cf \
+)
+
typedef int (*cf_walker_t)(void *data, void *ctx);
+extern char const *CF_IDENT_ANY;
+
+/*
+ * Config file parsing
+ */
+int cf_file_read(CONF_SECTION *cs, char const *file);
+void cf_file_free(CONF_SECTION *cs);
+
void cf_file_check_user(uid_t uid, gid_t gid);
+int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback);
-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);
-CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp);
-void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp);
+/*
+ * Config file writing
+ */
+#ifdef WITH_CONF_WRITE
+size_t cf_section_write(FILE *fp, CONF_SECTION *cs, int depth);
+#endif
-CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2);
-CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
- char const *name1, char const *name2, bool copy_meta);
-void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs);
-int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value);
-int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs, char const *name, unsigned int type, void *data,
- char const *dflt, FR_TOKEN dflt_quote);
+/*
+ * Type validation and conversion
+ */
+int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs, char const *name,
+ unsigned int type, void *data, char const *dflt, FR_TOKEN dflt_quote);
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, CONF_PARSER const *variables);
int cf_section_parse_pass2(void *base, CONF_SECTION *cs, CONF_PARSER const *variables);
-const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs);
-int cf_file_read(CONF_SECTION *cs, char const *file);
-void cf_file_free(CONF_SECTION *cs);
+CONF_PARSER const *cf_section_parse_table(CONF_SECTION *cs);
-CONF_PAIR *cf_pair_find(CONF_SECTION const *, char const *name);
-CONF_PAIR *cf_pair_find_next(CONF_SECTION const *, CONF_PAIR const *, char const *name);
-CONF_SECTION *cf_section_find_name2(CONF_SECTION const *section,
- char const *name1, char const *name2);
-CONF_SECTION *cf_subsection_find(CONF_SECTION const *, char const *name);
-CONF_SECTION *cf_subsection_find_name2(CONF_SECTION const *, char const *name1, char const *name2);
-char const *cf_section_value_find(CONF_SECTION const *, char const *attr);
-CONF_SECTION *cf_top_section(CONF_SECTION *cs);
+CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs, CONF_SECTION const *outercs, char const *ptr);
-#define cf_data_find(_cs, _type, _name) (_type *)_cf_data_find(_cs, #_type, _name)
-void *_cf_data_find(CONF_SECTION const *cs, char const *type, char const *name);
+/*
+ * Generic functions that apply to all types of #CONF_ITEM
+ */
+#define cf_item_add(_parent, _child) _cf_item_add(CF_TO_ITEM(_parent), _child)
+void _cf_item_add(CONF_ITEM *parent, CONF_ITEM *child);
-#define cf_data_add(_cs, _data, _name, _free) _cf_data_add(_cs, _data, _name, _free)
-int _cf_data_add(CONF_SECTION *cs, void const *data, char const *name, bool free);
+#define cf_item_next(_ci, _prev) _cf_item_next(CF_TO_ITEM(_ci), _prev)
+CONF_ITEM *_cf_item_next(CONF_ITEM const *ci, CONF_ITEM const *prev);
-#define cf_data_remove(_cs, _type, _name) (_type *)_cf_data_remove(_cs, #_type, _name)
-void *_cf_data_remove(CONF_SECTION *cs, char const *type, char const *name);
+#define cf_root(_cf) _cf_root(CF_TO_ITEM(_cf))
+CONF_SECTION *_cf_root(CONF_ITEM const *ci);
-#define cf_data_walk(_cs, _type, _cb, _ctx) _cf_data_walk(_cs, #_type, _cb, _ctx)
-int _cf_data_walk(CONF_SECTION *cs, char const *type, cf_walker_t cb, void *ctx);
+#define cf_parent(_cf) _cf_parent(CF_TO_ITEM(_cf))
+CONF_ITEM *_cf_parent(CONF_ITEM const *ci);
-char const *cf_pair_attr(CONF_PAIR const *pair);
-char const *cf_pair_value(CONF_PAIR const *pair);
-FR_TOKEN cf_pair_operator(CONF_PAIR const *pair);
-FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair);
-FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair);
+#define cf_lineno(_cf) _cf_lineno(CF_TO_ITEM(_cf))
+int _cf_lineno(CONF_ITEM const *ci);
+
+#define cf_filename(_cf) _cf_filename(CF_TO_ITEM(_cf))
+char const *_cf_filename(CONF_ITEM const *ci);
+
+bool cf_item_is_section(CONF_ITEM const *ci);
+bool cf_item_is_pair(CONF_ITEM const *ci);
+bool cf_item_is_data(CONF_ITEM const *ci);
+
+CONF_PAIR *cf_item_to_pair(CONF_ITEM const *ci);
+CONF_SECTION *cf_item_to_section(CONF_ITEM const *ci);
+CONF_DATA *cf_item_to_data(CONF_ITEM const *ci);
+
+CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp);
+CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs);
+CONF_ITEM *cf_data_to_item(CONF_DATA const *cs);
+
+/*
+ * Section manipulation and searching
+ */
+CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2);
+CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
+ char const *name1, char const *name2, bool copy_meta);
+void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs);
+CONF_SECTION *cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *prev);
+CONF_SECTION *cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2);
+CONF_SECTION *cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *subcs,
+ char const *name1, char const *name2);
+
+char const *cf_section_value_find(CONF_SECTION const *, char const *attr);
char const *cf_section_name1(CONF_SECTION const *cs);
char const *cf_section_name2(CONF_SECTION const *cs);
char const *cf_section_name(CONF_SECTION const *cs);
char const *cf_section_argv(CONF_SECTION const *cs, int argc);
-FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs);
-FR_TOKEN cf_section_argv_type(CONF_SECTION const *cs, int argc);
-
-CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
- CONF_SECTION const *subsection,
- char const *name1);
-CONF_SECTION *cf_section_find_next(CONF_SECTION const *section,
- CONF_SECTION const *subsection,
- char const *name1);
-
-int cf_section_lineno(CONF_SECTION const *section);
-int cf_pair_lineno(CONF_PAIR const *pair);
-char const *cf_pair_filename(CONF_PAIR const *pair);
-char const *cf_section_filename(CONF_SECTION const *section);
-CONF_ITEM *cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item);
+FR_TOKEN cf_section_name2_quote(CONF_SECTION const *cs);
+FR_TOKEN cf_section_argv_quote(CONF_SECTION const *cs, int argc);
+
+/*
+ * Pair manipulation and searching
+ */
+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);
+CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp);
+int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value);
+void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp);
+CONF_PAIR *cf_pair_next(CONF_SECTION const *cs, CONF_PAIR const *prev);
+CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *name);
+CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *name);
int cf_pair_count(CONF_SECTION const *cs);
-CONF_ITEM *cf_item_parent(CONF_ITEM const *ci);
-CONF_SECTION *cf_section_parent(CONF_SECTION const *cs);
-CONF_SECTION *cf_pair_parent(CONF_PAIR const *cp);
-CONF_SECTION *cf_item_root(CONF_ITEM const *ci);
+char const *cf_pair_attr(CONF_PAIR const *pair);
+char const *cf_pair_value(CONF_PAIR const *pair);
+FR_TOKEN cf_pair_operator(CONF_PAIR const *pair);
+
+FR_TOKEN cf_pair_attr_quote(CONF_PAIR const *pair);
+FR_TOKEN cf_pair_value_quote(CONF_PAIR const *pair);
-bool cf_item_is_section(CONF_ITEM const *item);
-bool cf_item_is_pair(CONF_ITEM const *item);
-CONF_PAIR *cf_item_to_pair(CONF_ITEM const *item);
-CONF_SECTION *cf_item_to_section(CONF_ITEM const *item);
-CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp);
-CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs);
+/*
+ * Data manipulation and searching
+ */
+#define cf_data_find(_cf, _type, _name) _cf_data_find(CF_TO_ITEM(_cf), #_type, _name)
+CONF_DATA const *_cf_data_find(CONF_ITEM const *ci, char const *type, char const *name);
+
+#define cf_data_find_next(_cf, _prev, _type, _name) _cf_data_find(CF_TO_ITEM(_cf), CF_TO_ITEM(_prev), #_type, _name)
+CONF_DATA const *_cf_data_find_next(CONF_ITEM const *ci, CONF_ITEM const *prev, char const *type, char const *name);
+
+void *cf_data_value(CONF_DATA const *cd);
+
+#define cf_data_add(_cf, _data, _name, _free) _cf_data_add(CF_TO_ITEM(_cf), _data, _name, _free)
+CONF_DATA const *_cf_data_add(CONF_ITEM *ci, void const *data, char const *name, bool free);
+
+#define cf_data_remove(_cf, _cd) _cf_data_remove(CF_TO_ITEM(_cf), _cd);
+void *_cf_data_remove(CONF_ITEM *ci, CONF_DATA const *_cd);
+
+#define cf_data_walk(_cf, _type, _cb, _ctx) _cf_data_walk(CF_TO_ITEM(_cf), #_type, _cb, _ctx)
+int _cf_data_walk(CONF_ITEM *ci, char const *type, cf_walker_t cb, void *ctx);
/*
- * Log an error related to a section
+ * Error logging
*/
-void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_perr_cs(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_perr_cp(CONF_PAIR const *cp, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_err_by_name(CONF_SECTION const *parent,
- char const *name, char const *fmt, ...) CC_HINT(format (printf, 3, 4));
-void cf_log_warn_cp(CONF_PAIR const *cp, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_warn(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+#define cf_log_err(_cf, _fmt, ...) _cf_log_err(CF_TO_ITEM(_cf), _fmt, ## __VA_ARGS__)
+void _cf_log_err(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci);
-CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
- CONF_SECTION const *outercs,
- char const *ptr);
+#define cf_log_perr(_cf, _fmt, ...) _cf_log_perr(CF_TO_ITEM(_cf), _fmt, ## __VA_ARGS__)
+void _cf_log_perr(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-#ifdef WITH_CONF_WRITE
-size_t cf_section_write(FILE *fp, CONF_SECTION *cs, int depth);
-#endif
+#define cf_log_warn(_cf, _fmt, ...) _cf_log_warn(CF_TO_ITEM(_cf), _fmt, ## __VA_ARGS__)
+void _cf_log_warn(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
-#define CF_FILE_NONE (0)
-#define CF_FILE_ERROR (1)
-#define CF_FILE_CONFIG (1 << 2)
-#define CF_FILE_MODULE (1 << 3)
-int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback);
+#define cf_log_info(_cf, _fmt, ...) _cf_log_info(CF_TO_ITEM(_cf), _fmt, ## __VA_ARGS__)
+void _cf_log_info(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+
+#define cf_log_debug(_cf, _fmt, ...) _cf_log_debug(CF_TO_ITEM(_cf), _fmt, ## __VA_ARGS__)
+void _cf_log_debug(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+
+void cf_log_err_by_name(CONF_SECTION const *parent,
+ char const *name, char const *fmt, ...) CC_HINT(format (printf, 3, 4));
+#define cf_debug(_cf) _cf_debug(CF_TO_ITEM(_cf))
+void _cf_debug(CONF_ITEM const *ci);
#ifdef __cplusplus
}
#endif
char const *type; //!< If set, used for explicit runtime type safety checks.
} fr_cursor_t;
-void fr_cursor_copy(fr_cursor_t *out, fr_cursor_t *in) CC_HINT(nonnull);
+void fr_cursor_copy(fr_cursor_t *out, fr_cursor_t const *in) CC_HINT(nonnull);
void *fr_cursor_head(fr_cursor_t *cursor) CC_HINT(nonnull);
rbtree_t *rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags);
void rbtree_node_talloc_free(void *data);
-bool rbtree_insert(rbtree_t *tree, void *data);
+bool rbtree_insert(rbtree_t *tree, void const *data);
rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data);
void rbtree_delete(rbtree_t *tree, rbnode_t *z);
bool rbtree_deletebydata(rbtree_t *tree, void const *data);
} FR_NAME_NUMBER;
extern const FR_NAME_NUMBER fr_tokens_table[];
+extern const FR_NAME_NUMBER fr_token_quotes_table[];
extern const char *fr_tokens[];
extern const char fr_token_quote[];
extern const bool fr_assignment_op[];
void xlat_unregister(void *mod_inst, char const *name, xlat_func_t func);
void xlat_unregister_module(void *instance);
-bool xlat_register_redundant(CONF_SECTION *cs);
+int xlat_register_redundant(CONF_SECTION *cs);
void xlat_free(void);
#ifdef __cplusplus
* @param[out] out Where to copy the cursor to.
* @param[in] in cursor to copy.
*/
-void fr_cursor_copy(fr_cursor_t *out, fr_cursor_t *in)
+void fr_cursor_copy(fr_cursor_t *out, fr_cursor_t const *in)
{
memcpy(out, in, sizeof(*out));
}
rbnode_t *current, *parent, *x;
if (!tree->root) return NULL;
-
if (tree->lock) pthread_mutex_lock(&tree->mutex);
/* find where node belongs */
return x;
}
-bool rbtree_insert(rbtree_t *tree, void *data)
+bool rbtree_insert(rbtree_t *tree, void const *data)
{
+ void *mutable;
+
if (!tree->root) return NULL;
- if (rbtree_insert_node(tree, data)) return true;
+ memcpy(&mutable, &data, sizeof(mutable));
+
+ if (rbtree_insert_node(tree, mutable)) return true;
return false;
}
{ NULL, 0, },
};
+const FR_NAME_NUMBER fr_token_quotes_table[] = {
+ { "", T_BARE_WORD },
+ { "'", T_SINGLE_QUOTED_STRING },
+ { "\"", T_DOUBLE_QUOTED_STRING },
+ { "`", T_BACK_QUOTED_STRING },
+ { NULL, 0 },
+};
/*
* This is a hack, and has to be kept in sync with tokens.h
CONF_SECTION *cs;
CONF_SECTION *subcs;
- cs = cf_subsection_find_name2(main_config.config, "server", client->server);
+ cs = cf_section_find(main_config.config, "server", client->server);
if (!cs) {
ERROR("Failed to find virtual server %s", client->server);
return false;
* If this server has no "listen" section, add the clients
* to the global client list.
*/
- subcs = cf_subsection_find(cs, "listen");
+ subcs = cf_section_find(cs, "listen", NULL);
if (!subcs) goto global_clients;
/*
* If the client list already exists, use that.
* Otherwise, create a new client list.
*/
- clients = cf_data_find(cs, RADCLIENT_LIST, NULL);
+ clients = cf_data_value(cf_data_find(cs, RADCLIENT_LIST, NULL));
if (!clients) {
clients = client_list_init(cs);
if (!clients) {
#endif
{
bool global = false;
- CONF_SECTION *cs;
+ CONF_SECTION *cs = NULL;
RADCLIENT *c = NULL;
RADCLIENT_LIST *clients = NULL;
CONF_SECTION *server_cs = NULL;
* Be forgiving. If there's already a clients, return
* it. Otherwise create a new one.
*/
- clients = cf_data_find(section, RADCLIENT_LIST, NULL);
+ clients = cf_data_value(cf_data_find(section, RADCLIENT_LIST, NULL));
if (clients) return clients;
/*
* the global client list, else it's virtual server
* specific client list.
*/
- if (cf_top_section(section) == section) global = true;
+ if (cf_root(section) == section) global = true;
if (strcmp("server", cf_section_name1(section)) == 0) server_cs = section;
* Iterate over all the clients in the section, adding
* them to the client list.
*/
- for (cs = cf_subsection_find_next(section, NULL, "client");
- cs;
- cs = cf_subsection_find_next(section, cs, "client")) {
+ while ((cs = cf_section_find_next(section, cs, "client", CF_IDENT_ANY))) {
c = client_afrom_cs(cs, cs, server_cs, false);
if (!c) {
error:
* non-TLS clients CANNOT use TLS listeners.
*/
if (tls_required != c->tls_required) {
- cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
+ cf_log_err(cs, "Client does not have the same TLS configuration as the listener");
goto error;
}
#endif
value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cs(cs, "The \"directory\" entry must not be empty");
+ cf_log_err(cs, "The \"directory\" entry must not be empty");
goto error;
}
dir = opendir(value);
if (!dir) {
- cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
+ cf_log_err(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
goto error;
}
dc = client_read(buf2, server_cs, true);
if (!dc) {
- cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2);
+ cf_log_err(cs, "Failed reading client file \"%s\"", buf2);
closedir(dir);
goto error;
}
add_client:
#endif /* WITH_DYNAMIC_CLIENTS */
if (!client_add(clients, c)) {
- cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs));
+ cf_log_err(cs, "Failed to add client %s", cf_section_name2(cs));
goto error;
}
* Associate the clients structure with the section.
*/
if (cf_data_add(section, clients, NULL, false) < 0) {
- cf_log_err_cs(section, "Failed to associate clients with section %s", cf_section_name1(section));
+ cf_log_err(section, "Failed to associate clients with section %s", cf_section_name1(section));
talloc_free(clients);
return NULL;
}
c->server_cs = master->server_cs;
} else if (c->server) {
- c->server_cs = cf_subsection_find_name2(main_config.config, "server", c->server);
+ c->server_cs = cf_section_find(main_config.config, "server", c->server);
if (!c->server_cs) {
ERROR("Failed to find virtual server %s", c->server);
goto error;
{
CONF_ITEM const *ci;
- for (ci = cf_item_find_next(map, NULL);
+ for (ci = cf_item_next(map, NULL);
ci != NULL;
- ci = cf_item_find_next(map, ci)) {
+ ci = cf_item_next(map, ci)) {
CONF_PAIR const *cp;
CONF_PAIR *old;
char *value;
/*
* Use pre-existing section or alloc a new one
*/
- cc = cf_subsection_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
+ cc = cf_section_find(out, cf_section_name1(cs), cf_section_name2(cs));
if (!cc) {
cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
cf_section_add(out, cc);
* Or return -1 in which case we error out.
*/
if (func(&value, cp, data) < 0) {
- cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
+ cf_log_err(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
return -1;
}
if (!value) continue;
*/
cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
if (!cp) {
- cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
+ cf_log_err(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
talloc_free(value);
return -1;
}
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs, "Missing client name");
+ cf_log_err(cs, "Missing client name");
return NULL;
}
memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
if (cf_section_parse(c, c, cs, client_config) < 0) {
- cf_log_err_cs(cs, "Error parsing client section");
+ cf_log_err(cs, "Error parsing client section");
error:
client_free(c);
#ifdef WITH_TCP
*/
if (c->server) {
if (server_cs) {
- cf_log_err_cs(cs, "Clients inside of a 'server' section cannot point to a server");
+ cf_log_err(cs, "Clients inside of a 'server' section cannot point to a server");
goto error;
}
- c->server_cs = cf_subsection_find_name2(main_config.config, "server", c->server);
+ c->server_cs = cf_section_find(main_config.config, "server", c->server);
if (!c->server_cs) {
- cf_log_err_cs(cs, "Failed to find virtual server %s", c->server);
+ cf_log_err(cs, "Failed to find virtual server %s", c->server);
goto error;
}
* No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
*/
} else {
- cf_log_err_cs(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
+ cf_log_err(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
"directive found in client %s", name2);
goto error;
}
c->proto = IPPROTO_IP; /* fake for dual */
#endif
} else {
- cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
+ cf_log_err(cs, "Unknown proto \"%s\".", hs_proto);
goto error;
}
}
switch (c->ipaddr.af) {
case AF_INET:
if (fr_inet_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
- cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ cf_log_err(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
goto error;
}
break;
case AF_INET6:
if (fr_inet_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
- cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ cf_log_err(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
goto error;
}
break;
if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
- cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
+ cf_log_err(cs, "Dynamic clients MUST be a network, not a single IP address");
goto error;
}
- c->client_server_cs = cf_subsection_find_name2(main_config.config, "server", c->client_server);
+ c->client_server_cs = cf_section_find(main_config.config, "server", c->client_server);
if (!c->client_server_cs) {
- cf_log_err_cs(cs, "Unknown virtual server '%s'", c->client_server);
+ cf_log_err(cs, "Unknown virtual server '%s'", c->client_server);
goto error;
}
#endif
{
- cf_log_err_cs(cs, "secret must be at least 1 character long");
+ cf_log_err(cs, "secret must be at least 1 character long");
goto error;
}
}
c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
}
if (!c->coa_pool && !c->coa_server) {
- cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
+ cf_log_err(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
goto error;
}
/*
* create a home server CONF_SECTION and then parse
* it into a home_server_t.
*/
- } else if (with_coa || cf_subsection_find(cs, "coa_server")) {
+ } else if (with_coa || cf_section_find(cs, "coa_server", NULL), NULL) {
CONF_SECTION *server;
home_server_t *home;
goto error;
}
- if (cf_pair_attr_type(cp) == T_SINGLE_QUOTED_STRING) {
+ if (cf_pair_attr_quote(cp) == T_SINGLE_QUOTED_STRING) {
RDEBUG2("%s = '%s'", cf_pair_attr(cp), cf_pair_value(cp));
} else {
RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
return NULL;
}
- cs = cf_subsection_find(cs, "client");
+ cs = cf_section_find(cs, "client", NULL);
if (!cs) {
ERROR("No \"client\" section found in client file");
return NULL;
return CMD_OK;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
instance = module_find(cs, argv[0]);
return CMD_FAIL;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
instance = module_find(cs, argv[0]);
return CMD_FAIL;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
instance = module_find(cs, argv[0]);
return CMD_FAIL;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
instance = module_find(cs, argv[0]);
return CMD_FAIL;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
instance = module_find(cs, argv[0]);
{
CONF_SECTION *cs, *subcs;
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return CMD_FAIL;
subcs = NULL;
- while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
+ while ((subcs = cf_section_next(cs, subcs)) != NULL) {
char const *name1 = cf_section_name1(subcs);
char const *name2 = cf_section_name2(subcs);
return 0;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return 0;
instance = module_find(cs, argv[0]);
return 0;
}
- cs = cf_subsection_find(main_config.config, "modules");
+ cs = cf_section_find(main_config.config, "modules", NULL);
if (!cs) return 0;
instance = module_find(cs, argv[0]);
#ifdef WITH_TLS
if (this->tls) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"TLS is not supported for control sockets");
return -1;
}
sock = this->data;
if (sock->proto != IPPROTO_TCP) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"UDP is not supported for control sockets");
return -1;
}
/*
- * conf_file.c Read the radiusd.conf file.
- *
- * Yep I should learn to use lex & yacc, or at least
- * write a decent parser. I know how to do that, really :)
- * miquels@cistron.nl
- *
- * Version: $Id$
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * Copyright 2000,2006 The FreeRADIUS server project
- * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
- * Copyright 2000 Alan DeKok <aland@ox.org>
*/
+/**
+ * $Id$
+ * @file conf_file.c
+ * @brief Read the radiusd.conf file.
+ *
+ * @note Yep I should learn to use lex & yacc, or at least
+ * write a decent parser. I know how to do that, really :)
+ * miquels@cistron.nl
+ *
+ * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/parser.h>
#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/cursor.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#ifdef HAVE_DIRENT_H
-#include <dirent.h>
+# include <dirent.h>
#endif
#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
+# include <sys/stat.h>
#endif
#include <ctype.h>
static gid_t conf_check_gid = (gid_t)-1;
static CONF_PARSER conf_term = CONF_PARSER_TERMINATOR;
+char const *CF_IDENT_ANY = "<any>";
+
typedef enum conf_property {
CONF_PROPERTY_INVALID = 0,
CONF_PROPERTY_NAME,
#endif
} CONF_ITEM_TYPE;
+/** Common header for all CONF_* types
+ *
+ */
struct cf_item {
- struct cf_item *next; //!< Sibling.
- struct cf_item *parent; //!< Parent.
+ CONF_ITEM_TYPE type; //!< Whether the config item is a config_pair, conf_section or cf_data.
+
+ CONF_ITEM *next; //!< Sibling.
+ CONF_ITEM *parent; //!< Parent.
+
+ CONF_ITEM *child; //!< The head of the ordered list of children.
+ fr_cursor_t cursor; //!< Cursor to iterate over children. Maintains a 'tail' pointer for
+ //!< efficient insertion.
+
+ rbtree_t *ident1; //!< Tree to store the first identifier (name1 || type || attr).
+ rbtree_t *ident2; //!< Tree to store the second identifier (name2 || name).
+
int lineno; //!< The line number the config item began on.
char const *filename; //!< The file the config item was parsed from.
- CONF_ITEM_TYPE type; //!< Whether the config item is a config_pair, conf_section or cf_data.
};
/** Configuration AVP similar to a VALUE_PAIR
char const *orig_value; /* original value */
#endif
char const *value; //!< Attribute value
+
FR_TOKEN op; //!< Operator e.g. =, :=
- FR_TOKEN lhs_type; //!< Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
- FR_TOKEN rhs_type; //!< Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
+ FR_TOKEN lhs_quote; //!< Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
+ FR_TOKEN rhs_quote; //!< Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
+
bool pass2; //!< do expansion in pass2.
bool parsed; //!< Was this item used during parsing?
};
char const *name1; //!< First name token. Given ``foo bar {}`` would be ``foo``.
char const *name2; //!< Second name token. Given ``foo bar {}`` would be ``bar``.
- FR_TOKEN name2_type; //!< The type of quoting around name2.
+ FR_TOKEN name2_quote; //!< The type of quoting around name2.
int argc; //!< number of additional arguments
char const **argv; //!< additional arguments
- FR_TOKEN *argv_type;
-
- CONF_ITEM *children;
- CONF_ITEM *tail; //!< For speed.
- CONF_SECTION *template;
-
- rbtree_t *pair_tree; //!< and a partridge..
- rbtree_t *section_tree; //!< no jokes here.
- rbtree_t *name2_tree; //!< for sections of the same name2
- rbtree_t *data_tree;
+ FR_TOKEN *argv_quote;
void *base;
int depth;
+ CONF_SECTION *template;
CONF_PARSER const *variables; //!< the section was parsed with.
};
char const *type; //!< C type of data being stored.
char const *name; //!< Additional qualification of type.
+
void const *data; //!< User data.
- bool free; //!< Free user data function.
+ bool free; //!< If true, free data with talloc if parent node is freed.
};
typedef enum cf_include_type {
#ifdef WITH_CONF_WRITE
typedef struct conf_comment {
- CONF_ITEM item;
- char const *comment;
+ CONF_ITEM item;
+ char const *comment;
} CONF_COMMENT;
typedef struct conf_include {
- CONF_ITEM item;
- char const *filename;
- CONF_INCLUDE_TYPE file_type;
+ CONF_ITEM item;
+ char const *filename;
+ CONF_INCLUDE_TYPE file_type;
} CONF_INCLUDE;
#endif
typedef struct cf_file_t {
- char const *filename;
- CONF_SECTION *cs;
- struct stat buf;
+ char const *filename;
+ CONF_SECTION *cs;
+ struct stat buf;
} cf_file_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);
+static inline int cf_ident2_cmp(void const *a, void const *b);
+static int _cf_ident1_cmp(void const *a, void const *b);
+static int _cf_ident2_cmp(void const *a, void const *b);
static int cf_file_include(CONF_SECTION *cs, char const *filename_in, CONF_INCLUDE_TYPE file_type, char *buff[7]);
-
-
/*
- * Isolate the scary casts in these tiny provably-safe functions
- */
-
-/** Cast a CONF_ITEM to a CONF_PAIR
- *
+ * Expand the variables in an input string.
*/
-CONF_PAIR *cf_item_to_pair(CONF_ITEM const *ci)
+static char const *cf_expand_variables(char const *cf, int *lineno,
+ CONF_SECTION *outer_cs,
+ char *output, size_t outsize,
+ char const *input, bool *soft_fail)
{
- CONF_PAIR *out;
-
- if (ci == NULL) return NULL;
+ char *p;
+ char const *end, *ptr;
+ CONF_SECTION const *parent_cs;
+ char name[8192];
- rad_assert(ci->type == CONF_ITEM_PAIR);
+ if (soft_fail) *soft_fail = false;
- memcpy(&out, &ci, sizeof(out));
- return out;
-}
+ /*
+ * Find the master parent conf section.
+ * We can't use main_config.config, because we're in the
+ * process of re-building it, and it isn't set up yet...
+ */
+ parent_cs = cf_root(outer_cs);
-/** Cast a CONF_ITEM to a CONF_SECTION
- *
- */
-CONF_SECTION *cf_item_to_section(CONF_ITEM const *ci)
-{
- CONF_SECTION *out;
+ p = output;
+ ptr = input;
+ while (*ptr) {
+ /*
+ * Ignore anything other than "${"
+ */
+ if ((*ptr == '$') && (ptr[1] == '{')) {
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+ char *q;
- if (ci == NULL) return NULL;
+ /*
+ * FIXME: Add support for ${foo:-bar},
+ * like in xlat.c
+ */
- rad_assert(ci->type == CONF_ITEM_SECTION);
+ /*
+ * Look for trailing '}', and log a
+ * warning for anything that doesn't match,
+ * and exit with a fatal error.
+ */
+ end = strchr(ptr, '}');
+ if (end == NULL) {
+ *p = '\0';
+ INFO("%s[%d]: Variable expansion missing }",
+ cf, *lineno);
+ return NULL;
+ }
- memcpy(&out, &ci, sizeof(out));
- return out;
-}
+ ptr += 2;
-/** Cast a CONF_PAIR to a CONF_ITEM
- *
- */
-CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp)
-{
- CONF_ITEM *out;
+ /*
+ * Can't really happen because input lines are
+ * capped at 8k, which is sizeof(name)
+ */
+ if ((size_t) (end - ptr) >= sizeof(name)) {
+ ERROR("%s[%d]: Reference string is too large",
+ cf, *lineno);
+ return NULL;
+ }
- if (cp == NULL) return NULL;
+ memcpy(name, ptr, end - ptr);
+ name[end - ptr] = '\0';
- memcpy(&out, &cp, sizeof(out));
- return out;
-}
+ q = strchr(name, ':');
+ if (q) {
+ *(q++) = '\0';
+ }
-/** Cast a CONF_SECTION to a CONF_ITEM
- *
- */
-CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs)
-{
- CONF_ITEM *out;
+ ci = cf_reference_item(parent_cs, outer_cs, name);
+ if (!ci) {
+ if (soft_fail) *soft_fail = true;
+ ERROR("%s[%d]: Reference \"${%s}\" not found", cf, *lineno, name);
+ return NULL;
+ }
- if (cs == NULL) return NULL;
+ /*
+ * The expansion doesn't refer to another item or section
+ * it's the property of a section.
+ */
+ if (q) {
+ CONF_SECTION *find = cf_item_to_section(ci);
- memcpy(&out, &cs, sizeof(out));
- return out;
-}
+ if (ci->type != CONF_ITEM_SECTION) {
+ ERROR("%s[%d]: Can only reference properties of sections", cf, *lineno);
+ return NULL;
+ }
-/** Cast CONF_DATA to a CONF_ITEM
- *
- */
-static CONF_ITEM *cf_data_to_item(CONF_DATA const *cd)
-{
- CONF_ITEM *out;
+ switch (fr_str2int(conf_property_name, q, CONF_PROPERTY_INVALID)) {
+ case CONF_PROPERTY_NAME:
+ strcpy(p, find->name1);
+ break;
- if (cd == NULL) {
- return NULL;
- }
+ case CONF_PROPERTY_INSTANCE:
+ strcpy(p, find->name2 ? find->name2 : find->name1);
+ break;
- memcpy(&out, &cd, sizeof(out));
- return out;
-}
+ default:
+ ERROR("%s[%d]: Invalid property '%s'", cf, *lineno, q);
+ return NULL;
+ }
+ p += strlen(p);
+ ptr = end + 1;
-static int _cd_free(CONF_DATA *cd)
-{
- void *to_free;
+ } else if (ci->type == CONF_ITEM_PAIR) {
+ /*
+ * Substitute the value of the variable.
+ */
+ cp = cf_item_to_pair(ci);
- memcpy(&to_free, cd->data, sizeof(to_free));
+ /*
+ * If the thing we reference is
+ * marked up as being expanded in
+ * pass2, don't expand it now.
+ * Let it be expanded in pass2.
+ */
+ if (cp->pass2) {
+ if (soft_fail) *soft_fail = true;
- if (cd->free) talloc_free(to_free);
+ ERROR("%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
+ cf, *lineno, input);
+ return NULL;
+ }
- return 0;
-}
+ if (!cp->value) {
+ ERROR("%s[%d]: Reference \"%s\" has no value",
+ cf, *lineno, input);
+ return NULL;
+ }
-/*
- * rbtree callback function
- */
-static int pair_cmp(void const *a, void const *b)
-{
- CONF_PAIR const *one = a;
- CONF_PAIR const *two = b;
+ if (p + strlen(cp->value) >= output + outsize) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
- return strcmp(one->attr, two->attr);
-}
+ strcpy(p, cp->value);
+ p += strlen(p);
+ ptr = end + 1;
+ } else if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs;
-/*
- * rbtree callback function
- */
-static int section_cmp(void const *a, void const *b)
-{
- CONF_SECTION const *one = a;
- CONF_SECTION const *two = b;
+ /*
+ * Adding an entry again to a
+ * section is wrong. We don't
+ * want an infinite loop.
+ */
+ if (cf_item_to_section(ci->parent) == outer_cs) {
+ ERROR("%s[%d]: Cannot reference different item in same section", cf, *lineno);
+ return NULL;
+ }
- return strcmp(one->name1, two->name1);
-}
+ /*
+ * Copy the section instead of
+ * referencing it.
+ */
+ subcs = cf_item_to_section(ci);
+ subcs = cf_section_dup(outer_cs, subcs,
+ cf_section_name1(subcs), cf_section_name2(subcs),
+ false);
+ if (!subcs) {
+ ERROR("%s[%d]: Failed copying reference %s", cf, *lineno, name);
+ return NULL;
+ }
+ subcs->item.filename = ci->filename;
+ subcs->item.lineno = ci->lineno;
+ cf_item_add(outer_cs, &(subcs->item));
-/*
- * rbtree callback function
- */
-static int name2_cmp(void const *a, void const *b)
-{
- CONF_SECTION const *one = a;
- CONF_SECTION const *two = b;
+ ptr = end + 1;
- rad_assert(strcmp(one->name1, two->name1) == 0);
+ } else {
+ ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, *lineno, input);
+ return NULL;
+ }
+ } else if (memcmp(ptr, "$ENV{", 5) == 0) {
+ char *env;
- if (!one->name2 && !two->name2) return 0;
- if (one->name2 && !two->name2) return -1;
- if (!one->name2 && two->name2) return +1;
+ ptr += 5;
- return strcmp(one->name2, two->name2);
-}
+ /*
+ * Look for trailing '}', and log a
+ * warning for anything that doesn't match,
+ * and exit with a fatal error.
+ */
+ end = strchr(ptr, '}');
+ if (end == NULL) {
+ *p = '\0';
+ INFO("%s[%d]: Environment variable expansion missing }",
+ cf, *lineno);
+ return NULL;
+ }
+ /*
+ * Can't really happen because input lines are
+ * capped at 8k, which is sizeof(name)
+ */
+ if ((size_t) (end - ptr) >= sizeof(name)) {
+ ERROR("%s[%d]: Environment variable name is too large",
+ cf, *lineno);
+ return NULL;
+ }
+
+ memcpy(name, ptr, end - ptr);
+ name[end - ptr] = '\0';
+
+ /*
+ * Get the environment variable.
+ * If none exists, then make it an empty string.
+ */
+ env = getenv(name);
+ if (env == NULL) {
+ *name = '\0';
+ env = name;
+ }
+
+ if (p + strlen(env) >= output + outsize) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
+
+ strcpy(p, env);
+ p += strlen(p);
+ ptr = end + 1;
+
+ } else {
+ /*
+ * Copy it over verbatim.
+ */
+ *(p++) = *(ptr++);
+ }
+
+
+ if (p >= (output + outsize)) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
+ } /* loop over all of the input string. */
+
+ *p = '\0';
+
+ return output;
+}
/*
- * rbtree callback function
+ * Merge the template so everyting else "just works".
*/
-static int data_cmp(void const *a, void const *b)
+static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
{
- CONF_DATA const *one = a;
- CONF_DATA const *two = b;
- int ret;
+ CONF_ITEM *ci;
+
+ if (!cs || !template) return true;
+
+ cs->template = NULL;
+
+ /*
+ * Walk over the template, adding its' entries to the
+ * current section. But only if the entries don't
+ * already exist in the current section.
+ */
+ for (ci = template->item.child; ci; ci = ci->next) {
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp1, *cp2;
+
+ /*
+ * It exists, don't over-write it.
+ */
+ cp1 = cf_item_to_pair(ci);
+ if (cf_pair_find(cs, cp1->attr)) {
+ continue;
+ }
+
+ /*
+ * Create a new pair with all of the data
+ * of the old one.
+ */
+ cp2 = cf_pair_dup(cs, cp1);
+ if (!cp2) return false;
+
+ cp2->item.filename = cp1->item.filename;
+ cp2->item.lineno = cp1->item.lineno;
+
+ cf_item_add(cs, &(cp2->item));
+ continue;
+ }
+
+ if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs1, *subcs2;
+
+ subcs1 = cf_item_to_section(ci);
+ rad_assert(subcs1 != NULL);
+
+ subcs2 = cf_section_find(cs, subcs1->name1, subcs1->name2);
+ if (subcs2) {
+ /*
+ * sub-sections get merged.
+ */
+ if (!cf_template_merge(subcs2, subcs1)) {
+ return false;
+ }
+ continue;
+ }
+
+ /*
+ * Our section doesn't have a matching
+ * sub-section. Copy it verbatim from
+ * the template.
+ */
+ subcs2 = cf_section_dup(cs, subcs1,
+ cf_section_name1(subcs1), cf_section_name2(subcs1),
+ false);
+ if (!subcs2) return false;
+
+ subcs2->item.filename = subcs1->item.filename;
+ subcs2->item.lineno = subcs1->item.lineno;
- if (one->type && !two->type) return +1;
- if (!one->type && two->type) return -1;
+ cf_item_add(cs, &(subcs2->item));
+ continue;
+ }
- if (one->type && two->type) {
- ret = strcmp(one->type, two->type);
- if (ret != 0) return ret;
+ /* ignore everything else */
}
- if (one->name && !two->name) return +1;
- if (!one->name && two->name) return -1;
+ return true;
+}
+
+static int _cd_free(CONF_DATA *cd)
+{
+ void *to_free;
+
+ memcpy(&to_free, cd->data, sizeof(to_free));
- if (one->name && two->name) return strcmp(one->name, two->name);
+ if (cd->free) talloc_free(to_free);
return 0;
}
/*
* Functions for tracking filenames.
*/
-static int filename_cmp(void const *a, void const *b)
+static int _filename_cmp(void const *a, void const *b)
{
cf_file_t const *one = a;
cf_file_t const *two = b;
int fd;
FILE *fp;
- top = cf_top_section(cs);
- tree = cf_data_find(top, rbtree_t, "filename");
- if (!tree) return NULL;
+ top = cf_root(cs);
+ tree = cf_data_value(cf_data_find(top, rbtree_t, "filename"));
+ rad_assert(tree);
fp = fopen(filename, "r");
if (!fp) {
- ERROR("Unable to open file \"%s\": %s",
- filename, fr_syserror(errno));
+ ERROR("Unable to open file \"%s\": %s", filename, fr_syserror(errno));
return NULL;
}
fd = fileno(fp);
- file = talloc(tree, cf_file_t);
- if (!file) {
- fclose(fp);
- return NULL;
- }
+ MEM(file = talloc(tree, cf_file_t));
file->filename = filename;
file->cs = cs;
*
* Though the admin should really use templates for that.
*/
- if (!rbtree_insert(tree, file)) {
- talloc_free(file);
- }
+ if (!rbtree_insert(tree, file)) talloc_free(file);
return fp;
}
-/** Set the euid/egid used when performing file checks
- *
- * Sets the euid, and egid used when cf_file_check is called to check
- * permissions on conf items of type #FR_TYPE_FILE_INPUT.
- *
- * @note This is probably only useful for the freeradius daemon itself.
- *
- * @param uid to set, (uid_t)-1 to use current euid.
- * @param gid to set, (gid_t)-1 to use current egid.
- */
-void cf_file_check_user(uid_t uid, gid_t gid)
-{
- if (uid != 0) conf_check_uid = uid;
- if (gid != 0) conf_check_gid = gid;
-}
-
/** Do some checks on the file as an "input" file. i.e. one read by a module.
*
* @note Must be called with super user privileges.
rbtree_t *tree;
int fd = -1;
- top = cf_top_section(cs);
- tree = cf_data_find(top, rbtree_t, "filename");
+ top = cf_root(cs);
+ tree = cf_data_value(cf_data_find(top, rbtree_t, "filename"));
if (!tree) return false;
file = talloc(tree, cf_file_t);
return true;
}
-
typedef struct cf_file_callback_t {
int rcode;
rb_walker_t callback;
CONF_SECTION *modules;
} cf_file_callback_t;
-
/*
* Return 0 for keep going, 1 for stop.
*/
-static int file_callback(void *ctx, void *data)
+static int _file_callback(void *ctx, void *data)
{
- cf_file_callback_t *cb = ctx;
- cf_file_t *file = data;
- struct stat buf;
+ cf_file_callback_t *cb = ctx;
+ cf_file_t *file = data;
+ struct stat buf;
/*
* The file doesn't exist or we can no longer read it.
* The file changed, we'll need to re-read it.
*/
if (buf.st_mtime != file->buf.st_mtime) {
-
if (cb->callback(cb->modules, file->cs)) {
cb->rcode |= CF_FILE_MODULE;
DEBUG3("HUP: Changed module file %s", file->filename);
return 0;
}
-
/*
- * See if any of the files have changed.
+ * Do variable expansion in pass2.
+ *
+ * This is a breadth-first expansion. "deep
*/
-int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback)
+static int cf_section_pass2(CONF_SECTION *cs)
{
- CONF_SECTION *top;
- cf_file_callback_t cb;
- rbtree_t *tree;
+ CONF_ITEM *ci;
- top = cf_top_section(cs);
- tree = cf_data_find(top, rbtree_t, "filename");
- if (!tree) return true;
+ for (ci = cs->item.child; ci; ci = ci->next) {
+ char const *value;
+ CONF_PAIR *cp;
+ char buffer[8192];
- cb.rcode = CF_FILE_NONE;
- cb.callback = callback;
- cb.modules = cf_subsection_find(cs, "modules");
+ if (ci->type != CONF_ITEM_PAIR) continue;
- (void) rbtree_walk(tree, RBTREE_IN_ORDER, file_callback, &cb);
+ cp = cf_item_to_pair(ci);
+ if (!cp->value || !cp->pass2) continue;
- return cb.rcode;
-}
+ rad_assert((cp->rhs_quote == T_BARE_WORD) ||
+ (cp->rhs_quote == T_DOUBLE_QUOTED_STRING) ||
+ (cp->rhs_quote == T_BACK_QUOTED_STRING));
-static int _cf_section_free(CONF_SECTION *cs)
-{
- /*
- * Name1 and name2 are allocated contiguous with
- * cs.
- */
- if (cs->pair_tree) {
- talloc_free(cs->pair_tree);
- cs->pair_tree = NULL;
- }
- if (cs->section_tree) {
- talloc_free(cs->section_tree);
- cs->section_tree = NULL;
- }
- if (cs->name2_tree) {
- talloc_free(cs->name2_tree);
- cs->name2_tree = NULL;
+ value = cf_expand_variables(ci->filename, &ci->lineno, cs, buffer, sizeof(buffer), cp->value, NULL);
+ if (!value) return -1;
+
+ talloc_const_free(cp->value);
+ cp->value = talloc_typed_strdup(cp, value);
}
- if (cs->data_tree) {
- talloc_free(cs->data_tree);
- cs->data_tree = NULL;
+
+ for (ci = cs->item.child; ci; ci = ci->next) {
+ if (ci->type != CONF_ITEM_SECTION) continue;
+
+ if (cf_section_pass2(cf_item_to_section(ci)) < 0) return -1;
}
return 0;
}
-/** Allocate a #CONF_PAIR
- *
- * @param parent #CONF_SECTION to hang this #CONF_PAIR off of.
- * @param attr name.
- * @param value of #CONF_PAIR.
- * @param op #T_OP_EQ, #T_OP_SET etc.
- * @param lhs_type #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING
- * @param rhs_type #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING
- * @return
- * - NULL on error.
- * - A new #CONF_SECTION parented by parent.
- */
-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)
+
+static char const *cf_local_file(char const *base, char const *filename,
+ char *buffer, size_t bufsize)
{
- CONF_PAIR *cp;
+ size_t dirsize;
+ char *p;
- rad_assert(fr_equality_op[op] || fr_assignment_op[op]);
- if (!attr) return NULL;
+ strlcpy(buffer, base, bufsize);
- cp = talloc_zero(parent, CONF_PAIR);
- if (!cp) return NULL;
+ p = strrchr(buffer, FR_DIR_SEP);
+ if (!p) return filename;
+ if (p[1]) { /* ./foo */
+ p[1] = '\0';
+ }
- cp->item.type = CONF_ITEM_PAIR;
- cp->item.parent = cf_section_to_item(parent);
- cp->lhs_type = lhs_type;
- cp->rhs_type = rhs_type;
- cp->op = op;
- cp->item.filename = "<internal>"; /* will be over-written if necessary */
+ dirsize = (p - buffer) + 1;
- cp->attr = talloc_typed_strdup(cp, attr);
- if (!cp->attr) {
- error:
- talloc_free(cp);
+ if ((dirsize + strlen(filename)) >= bufsize) {
return NULL;
}
- if (value) {
-#ifdef WITH_CONF_WRITE
- cp->orig_value = talloc_typed_strdup(cp, value);
-#endif
- cp->value = talloc_typed_strdup(cp, value);
- if (!cp->value) goto error;
- }
+ strlcpy(p + 1, filename, bufsize - dirsize);
- return cp;
+ return buffer;
}
-/** Duplicate a #CONF_PAIR
- *
- * @param parent to allocate new pair in.
- * @param cp to duplicate.
- * @return
- * - NULL on error.
- * - A duplicate of the input pair.
- */
-CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp)
+static bool invalid_location(CONF_SECTION *this, char const *name, char const *filename, int lineno)
{
- CONF_PAIR *new;
-
- rad_assert(parent);
- rad_assert(cp);
-
- new = cf_pair_alloc(parent, cp->attr, cf_pair_value(cp),
- cp->op, cp->lhs_type, cp->rhs_type);
- if (!new) return NULL;
-
- new->parsed = cp->parsed;
- new->item.lineno = cp->item.lineno;
- new->item.filename = cp->item.filename;
-
- return new;
-}
-
-/** Add a configuration pair to a section
- *
- * @param parent section to add pair to.
- * @param cp to add.
- */
-void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp)
-{
- cf_item_add(parent, cf_pair_to_item(cp));
-}
-
-/** Allocate a #CONF_SECTION
- *
- * @param parent #CONF_SECTION to hang this #CONF_SECTION off of.
- * @param name1 Primary name.
- * @param name2 Secondary name.
- * @return
- * - NULL on error.
- * - A new #CONF_SECTION parented by parent.
- */
-CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
-{
- CONF_SECTION *cs;
- char buffer[1024];
-
- if (!name1) return NULL;
-
- if (name2 && parent) {
- if (strchr(name2, '$')) {
- name2 = cf_expand_variables(parent->item.filename,
- &parent->item.lineno,
- parent,
- buffer, sizeof(buffer), name2, NULL);
- if (!name2) {
- ERROR("Failed expanding section name");
- return NULL;
- }
- }
- }
-
- cs = talloc_zero(parent, CONF_SECTION);
- if (!cs) return NULL;
-
- cs->item.type = CONF_ITEM_SECTION;
- cs->item.parent = cf_section_to_item(parent);
- cs->item.filename = "<internal>"; /* will be over-written if necessary */
-
- cs->name1 = talloc_typed_strdup(cs, name1);
- if (!cs->name1) {
- error:
- talloc_free(cs);
- return NULL;
- }
-
- if (name2) {
- cs->name2 = talloc_typed_strdup(cs, name2);
- if (!cs->name2) goto error;
- }
-
- cs->pair_tree = rbtree_create(cs, pair_cmp, NULL, 0);
- if (!cs->pair_tree) goto error;
-
- talloc_set_destructor(cs, _cf_section_free);
-
- /*
- * Don't create a data tree, it may not be needed.
- */
+ /*
+ * if / elsif MUST be inside of a
+ * processing section, which MUST in turn
+ * be inside of a "server" directive.
+ */
+ if (!this || !this->item.parent) {
+ invalid_location:
+ ERROR("%s[%d]: Invalid location for '%s'",
+ filename, lineno, name);
+ return true;
+ }
/*
- * Don't create the section tree here, it may not
- * be needed.
+ * Can only have "if" in 3 named sections.
*/
-
- if (parent) cs->depth = parent->depth + 1;
-
- return cs;
-}
-
-/** Duplicate a configuration section
- *
- * @note recursively duplicates any child sections.
- * @note does not duplicate any data associated with a section, or its child sections.
- *
- * @param parent section (may be NULL).
- * @param cs to duplicate.
- * @param name1 of new section.
- * @param name2 of new section.
- * @param copy_meta Copy additional meta data for a section (like template, base, depth and variables).
- * @return
- * - A duplicate of the existing section.
- * - NULL on error.
- */
-CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
- char const *name1, char const *name2, bool copy_meta)
-{
- CONF_SECTION *new, *subcs;
- CONF_PAIR *cp;
- CONF_ITEM *ci;
-
- new = cf_section_alloc(parent, name1, name2);
-
- if (copy_meta) {
- new->template = cs->template;
- new->base = cs->base;
- new->depth = cs->depth;
- new->variables = cs->variables;
+ this = cf_item_to_section(this->item.parent);
+ while ((strcmp(this->name1, "server") != 0) &&
+ (strcmp(this->name1, "policy") != 0) &&
+ (strcmp(this->name1, "instantiate") != 0)) {
+ this = cf_item_to_section(this->item.parent);
+ if (!this) goto invalid_location;
}
- new->item.lineno = cs->item.lineno;
- new->item.filename = cs->item.filename;
-
- for (ci = cs->children; ci; ci = ci->next) {
- switch (ci->type) {
- case CONF_ITEM_SECTION:
- subcs = cf_item_to_section(ci);
- subcs = cf_section_dup(new, subcs,
- cf_section_name1(subcs), cf_section_name2(subcs),
- copy_meta);
- if (!subcs) {
- talloc_free(new);
- return NULL;
- }
- cf_section_add(new, subcs);
- break;
-
- case CONF_ITEM_PAIR:
- cp = cf_pair_dup(new, cf_item_to_pair(ci));
- if (!cp) {
- talloc_free(new);
- return NULL;
- }
- cf_pair_add(new, cp);
- break;
+ return false;
+}
- case CONF_ITEM_DATA: /* Skip data */
#ifdef WITH_CONF_WRITE
- case CONF_ITEM_COMMENT:
- case CONF_ITEM_INCLUDE:
-#endif
- break;
+static void cf_comment_add(CONF_SECTION *cs, int lineno, char const *ptr)
+{
+ CONF_COMMENT *cc;
- case CONF_ITEM_INVALID:
- rad_assert(0);
- }
- }
+ cc = talloc_zero(cs, CONF_COMMENT);
+ cc->item.type = CONF_ITEM_COMMENT;
+ cc->item.parent = cs;
+ cc->item.filename = cs->item.filename;
+ cc->item.lineno = lineno;
+ cc->comment = talloc_typed_strdup(cc, ptr);
- return new;
-}
-void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs)
-{
- cf_item_add(parent, &(cs->item));
+ cf_item_add(cs, &(cc->item));
}
-/** Replace pair in a given section with a new pair, of the given value.
- *
- * @param cs to replace pair in.
- * @param cp to replace.
- * @param value New value to assign to cp.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
+static void cf_include_add(CONF_SECTION *cs, char const *filename, CONF_INCLUDE_TYPE file_type)
{
- CONF_PAIR *newp;
- CONF_ITEM *ci, *cn, **last;
-
- newp = cf_pair_alloc(cs, cp->attr, value, cp->op, cp->lhs_type, cp->rhs_type);
- if (!newp) return -1;
-
- ci = &(cp->item);
- cn = &(newp->item);
-
- /*
- * Find the old one from the linked list, and replace it
- * with the new one.
- */
- for (last = &cs->children; (*last) != NULL; last = &(*last)->next) {
- if (*last == ci) {
- cn->next = (*last)->next;
- *last = cn;
- ci->next = NULL;
- break;
- }
- }
-
- rbtree_deletebydata(cs->pair_tree, ci);
+ CONF_INCLUDE *cc;
- rbtree_insert(cs->pair_tree, cn);
+ cc = talloc_zero(cs, CONF_INCLUDE);
+ cc->item.type = CONF_ITEM_INCLUDE;
+ cc->item.parent = cs;
+ cc->item.filename = cs->item.filename;
+ cc->item.lineno = 0;
+ cc->filename = talloc_typed_strdup(cc, filename);
+ cc->file_type = file_type;
- return 0;
+ cf_item_add(cs, &(cc->item));
}
-
+#endif
/*
- * Add an item to a configuration section.
+ * Read a part of the config file.
*/
-void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
+static int cf_section_read(char const *filename, int *lineno, FILE *fp,
+ CONF_SECTION *current, char *buff[7])
+
{
-#ifndef NDEBUG
- CONF_ITEM *first = ci;
+ CONF_SECTION *this, *css;
+ CONF_PAIR *cpn;
+ char const *ptr;
+ char const *value;
+#ifdef WITH_CONF_WRITE
+ char const *orig_value = NULL;
#endif
- rad_assert((void *)cs != (void *)ci);
+ FR_TOKEN t1 = T_INVALID, t2, t3;
+ bool has_spaces = false;
+ bool pass2;
+ char *cbuff;
+ size_t len;
- if (!cs || !ci) return;
+ this = current; /* add items here */
- if (!cs->children) {
- rad_assert(cs->tail == NULL);
- cs->children = ci;
- } else {
- rad_assert(cs->tail != NULL);
- cs->tail->next = ci;
- }
+ cbuff = buff[0];
/*
- * Update the trees (and tail) for each item added.
+ * Read, checking for line continuations ('\\' at EOL)
*/
- for (/* nothing */; ci != NULL; ci = ci->next) {
- rad_assert(ci->next != first); /* simple cycle detection */
-
- cs->tail = ci;
+ for (;;) {
+ int at_eof;
+ css = NULL;
/*
- * For fast lookups, pairs and sections get
- * added to rbtree's.
+ * Get data, and remember if we are at EOF.
*/
- switch (ci->type) {
- case CONF_ITEM_PAIR:
- if (!rbtree_insert(cs->pair_tree, ci)) {
- CONF_PAIR *cp = cf_item_to_pair(ci);
+ at_eof = (fgets(cbuff, talloc_array_length(buff[0]) - (cbuff - buff[0]), fp) == NULL);
+ (*lineno)++;
- if (strcmp(cp->attr, "confdir") == 0) break;
- if (!cp->value) break; /* module name, "ok", etc. */
- }
- break;
+ /*
+ * We read the entire 8k worth of data: complain.
+ * Note that we don't care if the last character
+ * is \n: it's still forbidden. This means that
+ * the maximum allowed length of text is 8k-1, which
+ * should be plenty.
+ */
+ len = strlen(cbuff);
+ if ((cbuff + len + 1) >= (buff[0] + talloc_array_length(buff[0]))) {
+ ERROR("%s[%d]: Line too long", filename, *lineno);
+ error:
+ return -1;
+ }
- case CONF_ITEM_SECTION: {
- CONF_SECTION *cs_new = cf_item_to_section(ci);
- CONF_SECTION *name1_cs;
+ if (has_spaces) {
+ ptr = cbuff;
+ while (isspace((int) *ptr)) ptr++;
- if (!cs->section_tree) {
- cs->section_tree = rbtree_create(cs, section_cmp, NULL, 0);
- if (!cs->section_tree) {
- ERROR("Out of memory");
- fr_exit_now(1);
- }
+ if (ptr > cbuff) {
+ memmove(cbuff, ptr, len - (ptr - cbuff));
+ len -= (ptr - cbuff);
}
+ }
- name1_cs = rbtree_finddata(cs->section_tree, cs_new);
- if (!name1_cs) {
- if (!rbtree_insert(cs->section_tree, cs_new)) {
- ERROR("Failed inserting section into tree");
- fr_exit_now(1);
- }
- break;
- }
+ /*
+ * Not doing continuations: check for edge
+ * conditions.
+ */
+ if (cbuff == buff[0]) {
+ if (at_eof) break;
- /*
- * We already have a section of
- * this "name1". Add a new
- * sub-section based on name2.
- */
- if (!name1_cs->name2_tree) {
- name1_cs->name2_tree = rbtree_create(name1_cs, name2_cmp, NULL, 0);
- if (!name1_cs->name2_tree) {
- ERROR("Out of memory");
- fr_exit_now(1);
- }
- }
+ ptr = buff[0];
+ while (*ptr && isspace((int) *ptr)) ptr++;
+#ifdef WITH_CONF_WRITE
/*
- * We don't care if this fails.
- * If the user tries to create
- * two sections of the same
- * name1/name2, the duplicate
- * section is just silently
- * ignored.
+ * This is where all of the comments are handled
*/
- rbtree_insert(name1_cs->name2_tree, cs_new);
- break;
- } /* was a section */
-
- case CONF_ITEM_DATA:
- if (!cs->data_tree) {
- cs->data_tree = rbtree_create(cs, data_cmp, NULL, 0);
- }
- if (cs->data_tree) {
- rbtree_insert(cs->data_tree, ci);
+ if (*ptr == '#') {
+ cf_comment_add(this, *lineno, ptr + 1);
}
- break;
+#endif
- default: /* FIXME: assert & error! */
- break;
-
- } /* switch over conf types */
- } /* loop over ci */
-}
-
-
-CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
- CONF_SECTION const *outercs,
- char const *ptr)
-{
- CONF_PAIR *cp;
- CONF_SECTION *next;
- CONF_SECTION const *cs = outercs;
- char name[8192];
- char *p;
-
- if (!cs) goto no_such_item;
-
- strlcpy(name, ptr, sizeof(name));
- p = name;
-
- /*
- * ".foo" means "foo from the current section"
- */
- if (*p == '.') {
- p++;
+ if (!*ptr || (*ptr == '#')) continue;
- /*
- * Just '.' means the current section
- */
- if (*p == '\0') {
- return cf_section_to_item(cs);
+ } else if (at_eof || (len == 0)) {
+ ERROR("%s[%d]: Continuation at EOF is illegal", filename, *lineno);
+ goto error;
}
/*
- * ..foo means "foo from the section
- * enclosing this section" (etc.)
+ * See if there's a continuation.
*/
- while (*p == '.') {
- if (cs->item.parent) {
- cs = cf_item_to_section(cs->item.parent);
- }
+ while ((len > 0) &&
+ ((cbuff[len - 1] == '\n') || (cbuff[len - 1] == '\r'))) {
+ len--;
+ cbuff[len] = '\0';
+ }
+ if ((len > 0) && (cbuff[len - 1] == '\\')) {
/*
- * .. means the section
- * enclosing this section
+ * Check for "suppress spaces" magic.
*/
- if (!*++p) {
- return cf_section_to_item(cs);
+ if (!has_spaces && (len > 2) && (cbuff[len - 2] == '"')) {
+ has_spaces = true;
}
- }
-
- /*
- * "foo.bar.baz" means "from the root"
- */
- } else if (strchr(p, '.') != NULL) {
- if (!parentcs) goto no_such_item;
-
- cs = parentcs;
- }
- while (*p) {
- char *q, *r;
+ cbuff[len - 1] = '\0';
+ cbuff += len - 1;
+ continue;
+ }
- r = strchr(p, '[');
- q = strchr(p, '.');
- if (!r && !q) break;
+ ptr = cbuff = buff[0];
+ has_spaces = false;
- if (r && q > r) q = NULL;
- if (q && q < r) r = NULL;
+ get_more:
+ pass2 = false;
/*
- * Split off name2.
+ * The parser is getting to be evil.
*/
- if (r) {
- q = strchr(r + 1, ']');
- if (!q) return NULL; /* parse error */
-
- /*
- * Points to foo[bar]xx: parse error,
- * it should be foo[bar] or foo[bar].baz
- */
- if (q[1] && q[1] != '.') goto no_such_item;
+ while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
- *r = '\0';
- *q = '\0';
- next = cf_subsection_find_name2(cs, p, r + 1);
- *r = '[';
- *q = ']';
+ if (((ptr[0] == '%') && (ptr[1] == '{')) ||
+ (ptr[0] == '`')) {
+ ssize_t slen;
- /*
- * Points to a named instance of a section.
- */
- if (!q[1]) {
- if (!next) goto no_such_item;
- return &(next->item);
+ if (ptr[0] == '%') {
+ slen = rad_copy_variable(buff[1], ptr);
+ } else {
+ slen = rad_copy_string(buff[1], ptr);
}
+ if (slen <= 0) {
+ char *spaces, *text;
- q++; /* ensure we skip the ']' and '.' */
+ fr_canonicalize_error(current, &spaces, &text, slen, ptr);
- } else {
- *q = '\0';
- next = cf_subsection_find(cs, p);
- *q = '.';
- }
+ ERROR("%s[%d]: %s", filename, *lineno, text);
+ ERROR("%s[%d]: %s^ Invalid expansion", filename, *lineno, spaces);
- if (!next) break; /* it MAY be a pair in this section! */
+ talloc_free(spaces);
+ talloc_free(text);
- cs = next;
- p = q + 1;
- }
+ goto error;
+ }
- if (!*p) goto no_such_item;
+ ptr += slen;
- retry:
- /*
- * Find it in the current referenced
- * section.
- */
- cp = cf_pair_find(cs, p);
- if (cp) {
- cp->parsed = true; /* conf pairs which are referenced count as parsed */
- return &(cp->item);
- }
+ t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), true);
+ switch (t2) {
+ case T_HASH:
+ case T_EOL:
+ goto do_bare_word;
- next = cf_subsection_find(cs, p);
- if (next) return &(next->item);
+ default:
+ ERROR("%s[%d]: Invalid expansion: %s", filename, *lineno, ptr);
+ goto error;
+ }
+ } else {
+ t1 = gettoken(&ptr, buff[1], talloc_array_length(buff[1]), true);
+ }
- /*
- * "foo" is "in the current section, OR in main".
- */
- if ((p == name) && (parentcs != NULL) && (cs != parentcs)) {
- cs = parentcs;
- goto retry;
- }
+ /*
+ * The caller eats "name1 name2 {", and calls us
+ * for the data inside of the section. So if we
+ * receive a closing brace, then it must mean the
+ * end of the section.
+ */
+ if (t1 == T_RCBRACE) {
+ if (this == current) {
+ ERROR("%s[%d]: Too many closing braces", filename, *lineno);
+ goto error;
+ }
-no_such_item:
- return NULL;
-}
+ /*
+ * Merge the template into the existing
+ * section. This uses more memory, but
+ * means that templates now work with
+ * sub-sections, etc.
+ */
+ if (!cf_template_merge(this, this->template)) goto error;
+ this = cf_item_to_section(this->item.parent);
+ goto check_for_more;
+ }
-CONF_SECTION *cf_top_section(CONF_SECTION *cs)
-{
- if (!cs) return NULL;
+ if (t1 != T_BARE_WORD) goto skip_keywords;
- while (cs->item.parent != NULL) cs = cf_item_to_section(cs->item.parent);
+ /*
+ * Allow for $INCLUDE files
+ *
+ * This *SHOULD* work for any level include.
+ * I really really really hate this file. -cparker
+ */
+ if ((strcasecmp(buff[1], "$INCLUDE") == 0) ||
+ (strcasecmp(buff[1], "$-INCLUDE") == 0)) {
+ bool relative = true;
- return cs;
-}
+ t2 = getword(&ptr, buff[2], talloc_array_length(buff[2]), true);
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $INCLUDE", filename, *lineno);
+ goto error;
+ }
+ if (buff[2][0] == '$') relative = false;
-/*
- * Expand the variables in an input string.
- */
-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)
-{
- char *p;
- char const *end, *ptr;
- CONF_SECTION const *parentcs;
- char name[8192];
+ value = cf_expand_variables(filename, lineno, this, buff[4], talloc_array_length(buff[4]),
+ buff[2], NULL);
+ if (!value) goto error;
- if (soft_fail) *soft_fail = false;
+ if (!FR_DIR_IS_RELATIVE(value)) relative = false;
- /*
- * Find the master parent conf section.
- * We can't use main_config.config, because we're in the
- * process of re-building it, and it isn't set up yet...
- */
- parentcs = cf_top_section(outercs);
+ if (relative) {
+ value = cf_local_file(filename, value, buff[3], talloc_array_length(buff[3]));
+ if (!value) {
+ ERROR("%s[%d]: Directories too deep", filename, *lineno);
+ goto error;
+ }
+ }
- p = output;
- ptr = input;
- while (*ptr) {
- /*
- * Ignore anything other than "${"
- */
- if ((*ptr == '$') && (ptr[1] == '{')) {
- CONF_ITEM *ci;
- CONF_PAIR *cp;
- char *q;
+#ifdef HAVE_DIRENT_H
/*
- * FIXME: Add support for ${foo:-bar},
- * like in xlat.c
+ * $INCLUDE foo/
+ *
+ * Include ALL non-"dot" files in the directory.
+ * careful!
*/
+ if (value[strlen(value) - 1] == '/') {
+ DIR *dir;
+ struct dirent *dp;
+ struct stat stat_buf;
+ char *my_directory;
- /*
- * Look for trailing '}', and log a
- * warning for anything that doesn't match,
- * and exit with a fatal error.
- */
- end = strchr(ptr, '}');
- if (end == NULL) {
- *p = '\0';
- INFO("%s[%d]: Variable expansion missing }",
- cf, *lineno);
- return NULL;
- }
+ my_directory = talloc_strdup(this, value);
- ptr += 2;
+ cf_log_debug(current, "Including files in directory \"%s\"", my_directory);
- /*
- * Can't really happen because input lines are
- * capped at 8k, which is sizeof(name)
- */
- if ((size_t) (end - ptr) >= sizeof(name)) {
- ERROR("%s[%d]: Reference string is too large",
- cf, *lineno);
- return NULL;
- }
+#ifdef WITH_CONF_WRITE
+ /*
+ * We print this out, but don't
+ * actually open a file based on
+ * it.
+ */
+ cf_include_add(this, my_directory, CONF_INCLUDE_DIR);
+#endif
- memcpy(name, ptr, end - ptr);
- name[end - ptr] = '\0';
+#ifdef S_IWOTH
+ /*
+ * Security checks.
+ */
+ if (stat(my_directory, &stat_buf) < 0) {
+ ERROR("%s[%d]: Failed reading directory %s: %s", filename, *lineno,
+ my_directory, fr_syserror(errno));
+ talloc_free(my_directory);
+ goto error;
+ }
- q = strchr(name, ':');
- if (q) {
- *(q++) = '\0';
- }
+ if ((stat_buf.st_mode & S_IWOTH) != 0) {
+ ERROR("%s[%d]: Directory %s is globally writable. Refusing to start due to "
+ "insecure configuration", filename, *lineno, my_directory);
+ talloc_free(my_directory);
+ goto error;
+ }
+#endif
+ dir = opendir(my_directory);
+ if (!dir) {
+ ERROR("%s[%d]: Error reading directory %s: %s",
+ filename, *lineno, value,
+ fr_syserror(errno));
+ talloc_free(my_directory);
+ goto error;
+ }
- ci = cf_reference_item(parentcs, outercs, name);
- if (!ci) {
- if (soft_fail) *soft_fail = true;
- ERROR("%s[%d]: Reference \"${%s}\" not found", cf, *lineno, name);
- return NULL;
- }
+ /*
+ * Read the directory, ignoring "." files.
+ */
+ while ((dp = readdir(dir)) != NULL) {
+ char const *p;
- /*
- * The expansion doesn't refer to another item or section
- * it's the property of a section.
- */
- if (q) {
- CONF_SECTION *mycs = cf_item_to_section(ci);
+ if (dp->d_name[0] == '.') continue;
- if (ci->type != CONF_ITEM_SECTION) {
- ERROR("%s[%d]: Can only reference properties of sections", cf, *lineno);
- return NULL;
- }
+ /*
+ * Check for valid characters
+ */
+ for (p = dp->d_name; *p != '\0'; p++) {
+ if (isalpha((int)*p) ||
+ isdigit((int)*p) ||
+ (*p == '-') ||
+ (*p == '_') ||
+ (*p == '.')) continue;
+ break;
+ }
+ if (*p != '\0') continue;
- switch (fr_str2int(conf_property_name, q, CONF_PROPERTY_INVALID)) {
- case CONF_PROPERTY_NAME:
- strcpy(p, mycs->name1);
- break;
- case CONF_PROPERTY_INSTANCE:
- strcpy(p, mycs->name2 ? mycs->name2 : mycs->name1);
- break;
+ snprintf(buff[2], talloc_array_length(buff[2]), "%s%s",
+ my_directory, dp->d_name);
+ if ((stat(buff[2], &stat_buf) != 0) ||
+ S_ISDIR(stat_buf.st_mode)) continue;
- default:
- ERROR("%s[%d]: Invalid property '%s'", cf, *lineno, q);
- return NULL;
+ /*
+ * Read the file into the current
+ * configuration section.
+ */
+ if (cf_file_include(this, buff[2], CONF_INCLUDE_FROMDIR, buff) < 0) {
+ closedir(dir);
+ goto error;
+ }
}
- p += strlen(p);
- ptr = end + 1;
-
- } else if (ci->type == CONF_ITEM_PAIR) {
- /*
- * Substitute the value of the variable.
- */
- cp = cf_item_to_pair(ci);
+ closedir(dir);
+ talloc_free(my_directory);
- /*
- * If the thing we reference is
- * marked up as being expanded in
- * pass2, don't expand it now.
- * Let it be expanded in pass2.
- */
- if (cp->pass2) {
- if (soft_fail) *soft_fail = true;
+ } else
+#endif
+ { /* it was a normal file */
+ if (buff[1][1] == '-') {
+ struct stat statbuf;
- ERROR("%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
- cf, *lineno, input);
- return NULL;
+ if (stat(value, &statbuf) < 0) {
+ WARN("Not including file %s: %s", value, fr_syserror(errno));
+ continue;
+ }
}
- if (!cp->value) {
- ERROR("%s[%d]: Reference \"%s\" has no value",
- cf, *lineno, input);
- return NULL;
- }
+ if (cf_file_include(this, value, CONF_INCLUDE_FILE, buff) < 0) goto error;
+ }
+ continue;
+ } /* we were in an include */
- if (p + strlen(cp->value) >= output + outsize) {
- ERROR("%s[%d]: Reference \"%s\" is too long",
- cf, *lineno, input);
- return NULL;
- }
+ if (strcasecmp(buff[1], "$template") == 0) {
+ CONF_ITEM *ci;
+ CONF_SECTION *parent_cs, *templatecs;
+ t2 = getword(&ptr, buff[2], talloc_array_length(buff[2]), true);
- strcpy(p, cp->value);
- p += strlen(p);
- ptr = end + 1;
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $TEMPLATE", filename, *lineno);
+ goto error;
+ }
- } else if (ci->type == CONF_ITEM_SECTION) {
- CONF_SECTION *subcs;
+ parent_cs = cf_root(current);
- /*
- * Adding an entry again to a
- * section is wrong. We don't
- * want an infinite loop.
- */
- if (cf_item_to_section(ci->parent) == outercs) {
- ERROR("%s[%d]: Cannot reference different item in same section", cf, *lineno);
- return NULL;
- }
+ templatecs = cf_section_find(parent_cs, "templates", NULL);
+ if (!templatecs) {
+ ERROR("%s[%d]: No \"templates\" section for reference \"%s\"", filename, *lineno, buff[2]);
+ goto error;
+ }
- /*
- * Copy the section instead of
- * referencing it.
- */
- subcs = cf_item_to_section(ci);
- subcs = cf_section_dup(outercs, subcs,
- cf_section_name1(subcs), cf_section_name2(subcs),
- false);
- if (!subcs) {
- ERROR("%s[%d]: Failed copying reference %s", cf, *lineno, name);
- return NULL;
- }
+ ci = cf_reference_item(parent_cs, templatecs, buff[2]);
+ if (!ci || (ci->type != CONF_ITEM_SECTION)) {
+ ERROR("%s[%d]: Reference \"%s\" not found", filename, *lineno, buff[2]);
+ goto error;
+ }
- subcs->item.filename = ci->filename;
- subcs->item.lineno = ci->lineno;
- cf_item_add(outercs, &(subcs->item));
+ if (!this) {
+ ERROR("%s[%d]: Internal sanity check error in template reference", filename, *lineno);
+ goto error;
+ }
- ptr = end + 1;
+ if (this->template) {
+ ERROR("%s[%d]: Section already has a template", filename, *lineno);
+ goto error;
+ }
- } else {
- ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, *lineno, input);
- return NULL;
- }
- } else if (memcmp(ptr, "$ENV{", 5) == 0) {
- char *env;
+ this->template = cf_item_to_section(ci);
+ continue;
+ }
- ptr += 5;
+ /*
+ * Ensure that the user can't add CONF_PAIRs
+ * with 'internal' names;
+ */
+ if (buff[1][0] == '_') {
+ ERROR("%s[%d]: Illegal configuration pair name \"%s\"", filename, *lineno, buff[1]);
+ goto error;
+ }
+
+ /*
+ * Handle if/elsif specially.
+ */
+ if ((strcmp(buff[1], "if") == 0) || (strcmp(buff[1], "elsif") == 0)) {
+ ssize_t slen;
+ char const *error = NULL;
+ char *p;
+ fr_cond_t *cond = NULL;
+
+ if (invalid_location(this, buff[1], filename, *lineno)) goto error;
/*
- * Look for trailing '}', and log a
- * warning for anything that doesn't match,
- * and exit with a fatal error.
+ * Skip (...) to find the {
*/
- end = strchr(ptr, '}');
- if (end == NULL) {
- *p = '\0';
- INFO("%s[%d]: Environment variable expansion missing }",
- cf, *lineno);
- return NULL;
+ slen = fr_cond_tokenize(this, cf_section_to_item(this), ptr, &cond,
+ &error, FR_COND_TWO_PASS);
+ memcpy(&p, &ptr, sizeof(p));
+
+ if (slen < 0) {
+ if (p[-slen] != '{') goto cond_error;
+ slen = -slen;
}
+ TALLOC_FREE(cond);
/*
- * Can't really happen because input lines are
- * capped at 8k, which is sizeof(name)
+ * This hack is so that the NEXT stage
+ * doesn't go "too far" in expanding the
+ * variable. We can parse the conditions
+ * without expanding the ${...} stuff.
+ * BUT we don't want to expand all of the
+ * stuff AFTER the condition. So we do
+ * two passes.
+ *
+ * The first pass is to discover the end
+ * of the condition. We then expand THAT
+ * string, and do a second pass parsing
+ * the expanded condition.
*/
- if ((size_t) (end - ptr) >= sizeof(name)) {
- ERROR("%s[%d]: Environment variable name is too large",
- cf, *lineno);
- return NULL;
- }
-
- memcpy(name, ptr, end - ptr);
- name[end - ptr] = '\0';
+ p += slen;
+ *p = '\0';
/*
- * Get the environment variable.
- * If none exists, then make it an empty string.
+ * Nuke trailing spaces. This hack
+ * really belongs in the parser.
*/
- env = getenv(name);
- if (env == NULL) {
- *name = '\0';
- env = name;
- }
-
- if (p + strlen(env) >= output + outsize) {
- ERROR("%s[%d]: Reference \"%s\" is too long",
- cf, *lineno, input);
- return NULL;
+ while ((p > ptr) && (isspace((int) p[-1]))) {
+ p--;
+ *p = '\0';
}
- strcpy(p, env);
- p += strlen(p);
- ptr = end + 1;
-
- } else {
/*
- * Copy it over verbatim.
+ * If there's a ${...}. If so, expand it.
*/
- *(p++) = *(ptr++);
- }
+ if (strchr(ptr, '$') != NULL) {
+ ptr = cf_expand_variables(filename, lineno,
+ this,
+ buff[3], talloc_array_length(buff[3]),
+ ptr, NULL);
+ if (!ptr) {
+ ERROR("%s[%d]: Parse error expanding ${...} in condition",
+ filename, *lineno);
+ goto error;
+ }
+ } /* else leave it alone */
+ css = cf_section_alloc(this, buff[1], ptr);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section", filename, *lineno);
+ goto error;
+ }
+ css->item.filename = filename;
+ css->item.lineno = *lineno;
- if (p >= (output + outsize)) {
- ERROR("%s[%d]: Reference \"%s\" is too long",
- cf, *lineno, input);
- return NULL;
- }
- } /* loop over all of the input string. */
+ slen = fr_cond_tokenize(css, cf_section_to_item(css), ptr, &cond,
+ &error, FR_COND_TWO_PASS);
+ *p = '{'; /* put it back */
- *p = '\0';
+ cond_error:
+ if (slen < 0) {
+ char *spaces, *text;
- return output;
-}
+ fr_canonicalize_error(this, &spaces, &text, slen, ptr);
-static char const parse_spaces[] = " ";
+ ERROR("%s[%d]: Parse error in condition",
+ filename, *lineno);
+ ERROR("%s[%d]: %s", filename, *lineno, text);
+ ERROR("%s[%d]: %s^ %s", filename, *lineno, spaces, error);
-/** Validation function for ipaddr conf_file types
- *
- */
-static inline int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, fr_type_t type, char const *value,
- fr_ipaddr_t *ipaddr)
-{
- char ipbuf[128];
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(css);
+ goto error;
+ }
- if (strcmp(value, "*") == 0) {
- cf_log_info(cs, "%.*s\t%s = *", cs->depth, parse_spaces, name);
- } else if (strspn(value, ".0123456789abdefABCDEF:%[]/") == strlen(value)) {
- cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, name, value);
- } else {
- cf_log_info(cs, "%.*s\t%s = %s IPv%s address [%s]", cs->depth, parse_spaces, name, value,
- (ipaddr->af == AF_INET ? "4" : " 6"), fr_inet_ntoh(ipaddr, ipbuf, sizeof(ipbuf)));
- }
+ if ((size_t) slen >= (talloc_array_length(buff[2]) - 1)) {
+ talloc_free(css);
+ ERROR("%s[%d]: Condition is too large after \"%s\"", filename, *lineno, buff[1]);
+ goto error;
+ }
- switch (type) {
- case FR_TYPE_IPV4_ADDR:
- case FR_TYPE_IPV6_ADDR:
- case FR_TYPE_COMBO_IP_ADDR:
- switch (ipaddr->af) {
- case AF_INET:
- if (ipaddr->prefix != 32) {
- ERROR("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted for non-prefix types",
- ipaddr->prefix);
+ /*
+ * Copy the expanded and parsed condition
+ * into buff[2]. Then, parse the text after
+ * the condition, which now MUST be a '{.
+ *
+ * If it wasn't '{' it would have been
+ * caught in the first pass of
+ * conditional parsing, above.
+ */
+ memcpy(buff[2], ptr, slen);
+ buff[2][slen] = '\0';
+ ptr = p;
- return -1;
- }
- break;
+ if ((t3 = gettoken(&ptr, buff[3], talloc_array_length(buff[3]), true)) != T_LCBRACE) {
+ talloc_free(css);
+ ERROR("%s[%d]: Expected '{' %d", filename, *lineno, t3);
+ goto error;
+ }
- case AF_INET6:
- if (ipaddr->prefix != 128) {
- ERROR("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted for non-prefix types",
- ipaddr->prefix);
+ /*
+ * Swap the condition with trailing stuff for
+ * the final condition.
+ */
+ memcpy(&p, &css->name2, sizeof(css->name2));
+ talloc_free(p);
+ css->name2 = talloc_typed_strdup(css, buff[2]);
- return -1;
- }
- break;
+ cf_data_add(css, cond, NULL, false);
- default:
- return -1;
+ add_section:
+ cf_item_add(this, &(css->item));
+
+ /*
+ * The current section is now the child section.
+ */
+ this = css;
+ css = NULL;
+ goto check_for_more;
}
- default:
- return 0;
- }
-}
+ /*
+ * "map" sections have three arguments!
+ */
+ if (strcmp(buff[1], "map") == 0) {
+ char const *mod;
+ char const *exp = NULL;
+ char const *p;
-/** Fixup xlat expansions and attributes
- *
- * @note Despite the name, this is really the second phase of #cf_pair_parse.
- *
- * @param[out] base start of structure to write #vp_tmpl_t s to.
- * @param[in] cs CONF_SECTION to fixup.
- * @param[in] variables Array of CONF_PARSER structs to process.
- * @return
- * - 0 on success.
- * - -1 on failure (parse errors etc...).
- */
-int cf_section_parse_pass2(void *base, CONF_SECTION *cs, CONF_PARSER const variables[])
-{
+ t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), false);
- int i;
+ if (invalid_location(this, buff[1], filename, *lineno)) {
+ if (t2 != T_LCBRACE) {
+ ERROR("%s[%d]: Invalid syntax for 'map'", filename, *lineno);
+ goto error;
+ }
- /*
- * Handle the known configuration parameters.
- */
- for (i = 0; variables[i].name != NULL; i++) {
- bool attribute, multi, is_tmpl, is_xlat;
- CONF_PAIR *cp;
- void *data;
+ goto alloc_section;
+ }
- char const *name = variables[i].name;
- int type = variables[i].type;
+ if (t2 != T_BARE_WORD) {
+ ERROR("%s[%d]: Expected module name after 'map'", filename, *lineno);
+ goto error;
+ }
- is_tmpl = (type & FR_TYPE_TMPL);
- is_xlat = (type & FR_TYPE_XLAT);
- attribute = (type & FR_TYPE_ATTRIBUTE);
- multi = (type & FR_TYPE_MULTI);
+ mod = cf_expand_variables(filename, lineno,
+ this,
+ buff[3], talloc_array_length(buff[3]),
+ buff[2], NULL);
+ if (!mod) {
+ ERROR("%s[%d]: Parse error expanding ${...} in map module name",
+ filename, *lineno);
+ goto error;
+ }
- type = FR_BASE_TYPE(type); /* normal types are small */
+ p = ptr;
+ t3 = gettoken(&p, buff[4], talloc_array_length(buff[4]), false);
+ if (fr_str_tok[t3]) {
+ ptr = p;
- /*
- * It's a section, recurse!
- */
- if (type == FR_TYPE_SUBSECTION) {
- uint8_t *subcs_base;
- CONF_SECTION *subcs = cf_subsection_find(cs, name);
+ exp = cf_expand_variables(filename, lineno,
+ this,
+ buff[5], talloc_array_length(buff[5]),
+ buff[4], NULL);
+ if (!exp) {
+ ERROR("%s[%d]: Parse error expanding ${...} in map module name",
+ filename, *lineno);
+ goto error;
+ }
+ }
+
+ if (gettoken(&ptr, buff[6], talloc_array_length(buff[6]), false) != T_LCBRACE) {
+ ERROR("%s[%d]: Expecting section start brace '{' in 'map' definition",
+ filename, *lineno);
+ goto error;
+ }
/*
- * Select base by whether this is a nested struct,
- * or a pointer to another struct.
+ * Allocate the section
*/
- if (!base) {
- subcs_base = NULL;
- } else if (multi) {
- size_t j, len;
- uint8_t **array;
+ css = cf_section_alloc(this, buff[1], mod);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section", filename, *lineno);
+ goto error;
+ }
+ css->item.filename = filename;
+ css->item.lineno = *lineno;
+ css->name2_quote = T_BARE_WORD;
- array = (uint8_t **)((uint8_t *)base) + variables[i].offset;
- len = talloc_array_length(array);
+ css->argc = 0;
+ if (exp) {
+ css->argv = talloc_array(css, char const *, 1);
+ css->argv[0] = talloc_typed_strdup(css->argv, exp);
+ css->argv_quote = talloc_array(css, FR_TOKEN, 1);
+ css->argv_quote[0] = t3;
+ css->argc++;
+ }
- for (j = 0; j < len; j++) {
- if (cf_section_parse_pass2(array[j], subcs,
- (CONF_PARSER const *)variables[i].dflt) < 0) {
- return -1;
- }
- }
- continue;
- } else if (variables[i].subcs_size) {
- subcs_base = (*(uint8_t **)((uint8_t *)base) + variables[i].offset);
- } else {
- subcs_base = (uint8_t *)base + variables[i].offset;
- }
-
- if (cf_section_parse_pass2(subcs_base, subcs,
- (CONF_PARSER const *)variables[i].dflt) < 0) return -1;
-
- continue;
+ goto add_section;
}
+ skip_keywords:
/*
- * Find the CONF_PAIR, may still not exist if there was
- * no default set for the CONF_PARSER.
- */
- cp = cf_pair_find(cs, name);
- if (!cp) continue;
-
- /*
- * Figure out which data we need to fix.
- */
- data = variables[i].data; /* prefer this. */
- if (!data && base) data = ((char *)base) + variables[i].offset;
- if (!data) continue;
-
- /*
- * Non-xlat expansions shouldn't have xlat!
+ * Grab the next token.
*/
- if (!is_xlat && !is_tmpl) {
- /*
- * Ignore %{... in shared secrets.
- * They're never dynamically expanded.
- */
- if ((variables[i].type & FR_TYPE_SECRET) != 0) continue;
+ t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), false);
+ switch (t2) {
+ case T_HASH:
+ case T_EOL:
+ case T_COMMA:
+ do_bare_word:
+ t3 = t2;
+ t2 = T_OP_EQ;
+ value = NULL;
+ goto do_set;
- if (strstr(cp->value, "%{") != NULL) {
- cf_log_err(&cp->item, "Found dynamic expansion in string which "
- "will not be dynamically expanded");
- return -1;
+ case T_OP_INCRM:
+ case T_OP_ADD:
+ case T_OP_SUB:
+ case T_OP_NE:
+ case T_OP_GE:
+ case T_OP_GT:
+ case T_OP_LE:
+ case T_OP_LT:
+ case T_OP_CMP_EQ:
+ case T_OP_CMP_FALSE:
+ if (!this || ((strcmp(this->name1, "update") != 0) && (strcmp(this->name1, "map") != 0))) {
+ ERROR("%s[%d]: Invalid operator in assignment",
+ filename, *lineno);
+ goto error;
}
- continue;
- }
-
- /*
- * Parse (and throw away) the xlat string (for validation).
- *
- * FIXME: All of these should be converted from FR_TYPE_XLAT
- * to FR_TYPE_TMPL.
- */
- if (is_xlat) {
- char const *error;
- ssize_t slen;
- char *value;
- xlat_exp_t *xlat;
+ /* FALL-THROUGH */
- redo:
- xlat = NULL;
+ case T_OP_EQ:
+ case T_OP_SET:
+ while (isspace((int) *ptr)) ptr++;
/*
- * xlat expansions should be parseable.
+ * New parser: non-quoted strings are
+ * bare words, and we parse everything
+ * until the next newline, or the next
+ * comma. If they have { or } in a bare
+ * word, well... too bad.
*/
- value = talloc_strdup(cs, cp->value); /* modified by xlat_tokenize */
- slen = xlat_tokenize(cs, value, &xlat, &error);
- if (slen < 0) {
- char *spaces, *text;
+ switch (*ptr) {
+ case '"':
+ case '\'':
+ case '`':
+ case '/':
+ t3 = getstring(&ptr, buff[3], talloc_array_length(buff[3]), false);
+ break;
- fr_canonicalize_error(cs, &spaces, &text, slen, cp->value);
+ default:
+ {
+ const char *q = ptr;
- cf_log_err_cp(cp, "Failed parsing expanded string:");
- cf_log_err_cp(cp, "%s", text);
- cf_log_err_cp(cp, "%s^ %s", spaces, error);
+ t3 = T_BARE_WORD;
+ while (*q && (*q >= ' ') && (*q != ',') &&
+ !isspace(*q)) q++;
- talloc_free(spaces);
- talloc_free(text);
- talloc_free(value);
- talloc_free(xlat);
- return -1;
+ if ((size_t) (q - ptr) >= talloc_array_length(buff[3])) {
+ ERROR("%s[%d]: Parse error: value too long", filename, *lineno);
+ goto error;
+ }
+
+ memcpy(buff[3], ptr, (q - ptr));
+ buff[3][q - ptr] = '\0';
+ ptr = q;
+ }
}
- talloc_free(value);
- talloc_free(xlat);
+ if (t3 == T_INVALID) {
+ ERROR("%s[%d]: Parse error: %s", filename, *lineno, fr_strerror());
+ goto error;
+ }
/*
- * If the "multi" flag is set, check all of them.
+ * Allow "foo" by itself, or "foo = bar"
*/
- if (multi) {
- cp = cf_pair_find_next(cs, cp, cp->attr);
- if (cp) goto redo;
- }
- continue;
-
- /*
- * Parse the pair into a template
- */
- } else if (is_tmpl) {
- ssize_t slen;
-
- vp_tmpl_t **out = (vp_tmpl_t **)data;
- vp_tmpl_t *vpt;
+ switch (t3) {
+ bool soft_fail;
- slen = tmpl_afrom_str(cs, &vpt, cp->value, talloc_array_length(cp->value) - 1,
- cf_pair_value_type(cp),
- REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
- if (slen < 0) {
- char *spaces, *text;
+ case T_BARE_WORD:
+ case T_DOUBLE_QUOTED_STRING:
+ case T_BACK_QUOTED_STRING:
+#ifdef WITH_CONF_WRITE
+ orig_value = buff[3];
+#endif
+ value = cf_expand_variables(filename, lineno, this, buff[4], talloc_array_length(buff[4]), buff[3], &soft_fail);
+ if (!value) {
+ if (!soft_fail) goto error;
- fr_canonicalize_error(vpt, &spaces, &text, slen, cp->value);
+ /*
+ * References an item which doesn't exist,
+ * or which is already marked up as being
+ * expanded in pass2. Wait for pass2 to
+ * do the expansions.
+ */
+ pass2 = true;
+ value = buff[3];
+ }
+ break;
- cf_log_err_cp(cp, "%s", text);
- cf_log_err_cp(cp, "%s^ %s", spaces, fr_strerror());
+ case T_HASH:
+ case T_EOL:
+ value = NULL;
+ break;
- talloc_free(spaces);
- talloc_free(text);
- return -1;
+ default:
+ value = buff[3];
+ break;
}
- if (attribute && (vpt->type != TMPL_TYPE_ATTR)) {
- cf_log_err(&cp->item, "Expected attr got %s",
- fr_int2str(tmpl_names, vpt->type, "???"));
- return -1;
- }
+ /*
+ * Add this CONF_PAIR to our CONF_SECTION
+ */
+ do_set:
+ cpn = cf_pair_alloc(this, buff[1], value, t2, t1, t3);
+ if (!cpn) goto error;
+ cpn->item.filename = filename;
+ cpn->item.lineno = *lineno;
+ cpn->pass2 = pass2;
+ cf_item_add(this, &(cpn->item));
- switch (vpt->type) {
+#ifdef WITH_CONF_WRITE
+ if (orig_value) cpn->orig_value = talloc_typed_strdup(cpn, orig_value);
+ orig_value = NULL;
+#endif
/*
- * All attributes should have been defined by this point.
+ * Require a comma, unless there's a comment.
*/
- case TMPL_TYPE_ATTR_UNDEFINED:
- talloc_free(vpt);
- cf_log_err(&cp->item, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
- return -1;
+ while (isspace(*ptr)) ptr++;
- case TMPL_TYPE_UNPARSED:
- case TMPL_TYPE_ATTR:
- case TMPL_TYPE_LIST:
- case TMPL_TYPE_DATA:
- case TMPL_TYPE_EXEC:
- case TMPL_TYPE_XLAT:
- case TMPL_TYPE_XLAT_STRUCT:
+ if (*ptr == ',') {
+ ptr++;
break;
+ }
- case TMPL_TYPE_UNKNOWN:
- case TMPL_TYPE_REGEX:
- case TMPL_TYPE_REGEX_STRUCT:
- case TMPL_TYPE_NULL:
- rad_assert(0);
- /* Don't add default */
+ /*
+ * module # stuff!
+ * foo = bar # other stuff
+ */
+#ifdef WITH_CONF_WRITE
+ if (*ptr == '#') {
+ t3 = T_HASH;
+ ptr++;
}
/*
- * Free the old value if we're overwriting
+ * Allocate a CONF_COMMENT, and add it to the list of children.
*/
- TALLOC_FREE(*out);
- *(vp_tmpl_t **)out = vpt;
- }
- } /* for all variables in the configuration section */
+ if ((t3 == T_HASH) && (*ptr >= ' ')) {
+ cf_comment_add(this, *lineno, ptr);
+ }
+#endif
- return 0;
-}
+ if ((t3 == T_HASH) || (t3 == T_COMMA) || (t3 == T_EOL) || (*ptr == '#')) continue;
-/** Parses a #CONF_PAIR into a C data type
- *
- * @copybrief cf_pair_value
- * @see cf_pair_value
- *
- * @param[out] out Where to write the parsed value.
- * @param[in] ctx to allocate any dynamic buffers in.
- * @param[in] cs containing the cp.
- * @param[in] cp to parse.
- * @param[in] type to parse to. May contain flags.
- * @return
- * - 0 on success.
- * - -1 on failure.
- */
-static int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs, CONF_PAIR *cp, unsigned int type)
-{
- int rcode = 0;
- bool attribute, required, secret, file_input, cant_be_empty, tmpl, file_exists;
-
- fr_ipaddr_t *ipaddr;
- ssize_t slen;
+ if (!*ptr || (*ptr == '}')) break;
- if (!cs) return -1;
+ ERROR("%s[%d]: Syntax error: Expected comma after '%s': %s",
+ filename, *lineno, value, ptr);
+ goto error;
- attribute = (type & FR_TYPE_ATTRIBUTE);
- required = (type & FR_TYPE_REQUIRED);
- secret = (type & FR_TYPE_SECRET);
- file_input = (type == FR_TYPE_FILE_INPUT); /* check, not and */
- file_exists = (type == FR_TYPE_FILE_EXISTS); /* check, not and */
- cant_be_empty = (type & FR_TYPE_NOT_EMPTY);
- tmpl = (type & FR_TYPE_TMPL);
+ /*
+ * No '=', must be a section or sub-section.
+ */
+ case T_BARE_WORD:
+ case T_DOUBLE_QUOTED_STRING:
+ case T_SINGLE_QUOTED_STRING:
+ t3 = gettoken(&ptr, buff[3], talloc_array_length(buff[3]), true);
+ if (t3 != T_LCBRACE) {
+ ERROR("%s[%d]: Expecting section start brace '{' after \"%s %s\"",
+ filename, *lineno, buff[1], buff[2]);
+ goto error;
+ }
+ /* FALL-THROUGH */
- rad_assert(cp);
- rad_assert(!(type & FR_TYPE_ATTRIBUTE) || tmpl); /* Attribute flag only valid for templates */
+ alloc_section:
+ case T_LCBRACE:
+ css = cf_section_alloc(this, buff[1],
+ t2 == T_LCBRACE ? NULL : buff[2]);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section",
+ filename, *lineno);
+ goto error;
+ }
- if (required) cant_be_empty = true; /* May want to review this in the future... */
+ css->item.filename = filename;
+ css->item.lineno = *lineno;
+ cf_item_add(this, &(css->item));
- type = FR_BASE_TYPE(type); /* normal types are small */
+ /*
+ * There may not be a name2
+ */
+ css->name2_quote = (t2 == T_LCBRACE) ? T_INVALID : t2;
- /*
- * Everything except templates must have a base type.
- */
- if (!type && !tmpl) {
- cf_log_err_cp(cp, "Configuration pair \"%s\" must have a data type", cf_pair_attr(cp));
- return -1;
- }
+ /*
+ * The current section is now the child section.
+ */
+ this = css;
+ break;
- rad_assert(cp->value);
+ case T_INVALID:
+ ERROR("%s[%d]: Syntax error in '%s': %s", filename, *lineno, ptr, fr_strerror());
- /*
- * Check for zero length strings
- */
- if ((cp->value[0] == '\0') && cant_be_empty) {
- cf_log_err_cp(cp, "Configuration pair \"%s\" must not be empty (zero length)", cf_pair_attr(cp));
- if (!required) cf_log_err_cp(cp, "Comment item to silence this message");
- rcode = -1;
+ goto error;
- error:
- return rcode;
- }
+ default:
+ ERROR("%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
+ filename, *lineno, buff[1], fr_int2str(fr_tokens_table, t2, "<INVALID>"));
- if (tmpl) {
- vp_tmpl_t *vpt;
+ goto error;
+ }
+ check_for_more:
/*
- * This is so we produce TMPL_TYPE_ATTR_UNDEFINED template that
- * the bootstrap functions can use to create an attribute.
- *
- * For other types of template such as xlats, we don't bother.
- * There's no reason bootstrap functions need access to the raw
- * xlat strings.
+ * Done parsing one thing. Skip to EOL if possible.
*/
- if (attribute) {
- slen = tmpl_afrom_attr_str(cp, &vpt, cp->value, REQUEST_CURRENT, PAIR_LIST_REQUEST,
- true, true);
- if (slen < 0) {
- char *spaces, *text;
-
- fr_canonicalize_error(ctx, &spaces, &text, slen, cp->value);
+ while (isspace(*ptr)) ptr++;
- cf_log_err(&cp->item, "Failed parsing attribute reference:");
- cf_log_err(&cp->item, "%s", text);
- cf_log_err(&cp->item, "%s^ %s", spaces, fr_strerror());
+ if (*ptr == '#') continue;
- talloc_free(spaces);
- talloc_free(text);
- goto error;
- }
- *(vp_tmpl_t **)out = vpt;
+ if (*ptr) {
+ goto get_more;
}
- goto finish;
- }
- switch (type) {
- case FR_TYPE_BOOL:
- /*
- * Allow yes/no, true/false, and on/off
- */
- if ((strcasecmp(cp->value, "yes") == 0) ||
- (strcasecmp(cp->value, "true") == 0) ||
- (strcasecmp(cp->value, "on") == 0)) {
- *(bool *)out = true;
- } else if ((strcasecmp(cp->value, "no") == 0) ||
- (strcasecmp(cp->value, "false") == 0) ||
- (strcasecmp(cp->value, "off") == 0)) {
- *(bool *)out = false;
- } else {
- cf_log_err(&(cs->item), "Invalid value \"%s\" for boolean variable %s",
- cp->value, cf_pair_attr(cp));
- rcode = -1;
- goto error;
- }
- cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, cf_pair_attr(cp), cp->value);
- break;
+ }
- case FR_TYPE_UINT32:
- {
- unsigned long v = strtoul(cp->value, 0, 0);
+ /*
+ * See if EOF was unexpected ..
+ */
+ if (feof(fp) && (this != current)) {
+ ERROR("%s[%d]: EOF reached without closing brace for section %s starting at line %d",
+ filename, *lineno, cf_section_name1(this), cf_lineno(this));
+ goto error;
+ }
- /*
- * Restrict integer values to 0-INT32_MAX, this means
- * it will always be safe to cast them to a signed type
- * for comparisons, and imposes the same range limit as
- * before we switched to using an unsigned type to
- * represent config item integers.
- */
- if (v > INT32_MAX) {
- cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
- cf_pair_attr(cp), INT32_MAX);
- rcode = -1;
- goto error;
- }
+ return 0;
+}
- *(uint32_t *)out = v;
- cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint32_t *)out);
- }
- break;
+/*
+ * Include one config file in another.
+ */
+static int cf_file_include(CONF_SECTION *cs, char const *filename_in,
+#ifndef WITH_CONF_WRITE
+ UNUSED
+#endif
+ CONF_INCLUDE_TYPE file_type, char *buff[7])
+{
+ FILE *fp;
+ int lineno = 0;
+ char const *filename;
- case FR_TYPE_UINT8:
- {
- unsigned long v = strtoul(cp->value, 0, 0);
+ /*
+ * So we only need to do this once.
+ */
+ filename = talloc_strdup(cs, filename_in);
- if (v > UINT8_MAX) {
- cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
- cf_pair_attr(cp), UINT8_MAX);
- rcode = -1;
- goto error;
- }
- *(uint8_t *)out = (uint8_t) v;
- cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint8_t *)out);
- }
- break;
+ DEBUG2("Including configuration file \"%s\"", filename);
- case FR_TYPE_UINT16:
- {
- unsigned long v = strtoul(cp->value, 0, 0);
+ fp = cf_file_open(cs, filename);
+ if (!fp) return -1;
- if (v > UINT16_MAX) {
- cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
- cf_pair_attr(cp), UINT16_MAX);
- rcode = -1;
- goto error;
- }
- *(uint16_t *)out = (uint16_t) v;
- cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint16_t *)out);
- }
- break;
+ if (!cs->item.filename) cs->item.filename = filename;
- case FR_TYPE_UINT64:
- *(uint64_t *)out = strtoull(cp->value, NULL, 10);
- cf_log_info(cs, "%.*s\t%s = %" PRIu64, cs->depth, parse_spaces, cf_pair_attr(cp), *(uint64_t *)out);
- break;
+#ifdef WITH_CONF_WRITE
+ /*
+ * Instruct the parser that we've started to include a
+ * file at this point.
+ */
+ cf_include_add(cs, filename, file_type);
+#endif
- case FR_TYPE_SIZE:
- {
- if (fr_size_from_str((size_t *)out, cp->value) < 0) {
- cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s: %s", cp->value,
- cf_pair_attr(cp), fr_strerror());
- rcode = -1;
- goto error;
- }
- cf_log_info(cs, "%.*s\t%s = %zu", cs->depth, parse_spaces, cf_pair_attr(cp), *(size_t *)out);
- break;
+ /*
+ * Read the section. It's OK to have EOF without a
+ * matching close brace.
+ */
+ if (cf_section_read(filename, &lineno, fp, cs, buff) < 0) {
+ ERROR("Failed parsing configuration file \"%s\"", filename);
+ fclose(fp);
+ return -1;
}
- case FR_TYPE_INT32:
- *(int32_t *)out = strtol(cp->value, NULL, 10);
- cf_log_info(cs, "%.*s\t%s = %d", cs->depth, parse_spaces, cf_pair_attr(cp), *(int32_t *)out);
- break;
+#ifdef WITH_CONF_WRITE
+ /*
+ * Instruct the parser that we've finished including a
+ * file at this point.
+ */
+ cf_include_add(cs, NULL, file_type);
+#endif
- case FR_TYPE_STRING:
- {
- char **str = out;
+ fclose(fp);
+ return 0;
+}
- /*
- * Hide secrets when using "radiusd -X".
- */
- if (secret && (rad_debug_lvl < L_DBG_LVL_3)) {
- cf_log_info(cs, "%.*s\t%s = <<< secret >>>", cs->depth, parse_spaces, cf_pair_attr(cp));
- } else {
- cf_log_info(cs, "%.*s\t%s = \"%s\"", cs->depth, parse_spaces, cf_pair_attr(cp), cp->value);
- }
-
- /*
- * If there's out AND it's an input file, check
- * that we can read it. This check allows errors
- * to be caught as early as possible, during
- * server startup.
- */
- if (file_input && !cf_file_check(cs, cp->value, true)) {
- rcode = -1;
- goto error;
- }
-
- if (file_exists && !cf_file_check(cs, cp->value, false)) {
- rcode = -1;
- goto error;
- }
-
- /*
- * Free any existing buffers
- */
- talloc_free(*str);
- *str = talloc_typed_strdup(cs, cp->value);
- }
- break;
-
- case FR_TYPE_IPV4_ADDR:
- case FR_TYPE_IPV4_PREFIX:
- ipaddr = out;
+/*
+ * Bootstrap a config file.
+ */
+int cf_file_read(CONF_SECTION *cs, char const *filename)
+{
+ int i;
+ char *p;
+ CONF_PAIR *cp;
+ rbtree_t *tree;
+ char **buff;
- if (fr_inet_pton4(ipaddr, cp->value, -1, true, false, true) < 0) {
- cf_log_err(&(cp->item), "%s", fr_strerror());
- rcode = -1;
- goto error;
- }
- /* Also prints the IP to the log */
- if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
- rcode = -1;
- goto error;
- }
- break;
+ cp = cf_pair_alloc(cs, "confdir", filename, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (!cp) return -1;
- case FR_TYPE_IPV6_ADDR:
- case FR_TYPE_IPV6_PREFIX:
- ipaddr = out;
+ p = strrchr(cp->value, FR_DIR_SEP);
+ if (p) *p = '\0';
- if (fr_inet_pton6(ipaddr, cp->value, -1, true, false, true) < 0) {
- cf_log_err(&(cp->item), "%s", fr_strerror());
- rcode = -1;
- goto error;
- }
- /* Also prints the IP to the log */
- if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
- rcode = -1;
- goto error;
- }
- break;
+ cf_item_add(cs, &(cp->item));
- case FR_TYPE_COMBO_IP_ADDR:
- case FR_TYPE_COMBO_IP_PREFIX:
- ipaddr = out;
+ MEM(tree = rbtree_create(cs, _filename_cmp, NULL, 0));
- if (fr_inet_pton(ipaddr, cp->value, -1, AF_UNSPEC, true, true) < 0) {
- cf_log_err(&(cp->item), "%s", fr_strerror());
- rcode = -1;
- goto error;
- }
- /* Also prints the IP to the log */
- if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
- rcode = -1;
- goto error;
- }
- break;
+ cf_data_add(cs, tree, "filename", false);
- case FR_TYPE_TIMEVAL:
- {
- struct timeval tv;
+ /*
+ * Allocate temporary buffers on the heap (so we don't use *all* the stack space)
+ */
+ buff = talloc_array(cs, char *, 7);
+ for (i = 0; i < 7; i++) MEM(buff[i] = talloc_array(buff, char, 8192));
- if (fr_timeval_from_str(&tv, cp->value) < 0) {
- cf_log_err(&(cp->item), "%s", fr_strerror());
- rcode = -1;
- goto error;
- }
- cf_log_info(cs, "%.*s\t%s = %d.%06d", cs->depth, parse_spaces, cf_pair_attr(cp),
- (int)tv.tv_sec, (int)tv.tv_usec);
- memcpy(out, &tv, sizeof(tv));
+ if (cf_file_include(cs, filename, CONF_INCLUDE_FILE, buff) < 0) {
+ talloc_free(buff);
+ return -1;
}
- break;
- default:
- /*
- * If we get here, it's a sanity check error.
- * It's not an error parsing the configuration
- * file.
- */
- rad_assert(type > FR_TYPE_INVALID);
- rad_assert(type < FR_TYPE_MAX);
+ talloc_free(buff);
- cf_log_err(&(cp->item), "type '%s' (%i) is not supported in the configuration files",
- fr_int2str(dict_attr_types, type, "?Unknown?"), type);
- rcode = -1;
- goto error;
+ /*
+ * Now that we've read the file, go back through it and
+ * expand the variables.
+ */
+ if (cf_section_pass2(cs) < 0) {
+ cf_log_err(cs, "Parsing config items failed");
+ return -1;
}
-finish:
- cp->parsed = true;
+ return 0;
+}
- return rcode;
+void cf_file_free(CONF_SECTION *cs)
+{
+ talloc_free(cs);
}
-/** Allocate a pair using the dflt value and quotation
+/** Set the euid/egid used when performing file checks
*
- * The pair created by this function should fed to #cf_pair_parse for parsing.
+ * Sets the euid, and egid used when cf_file_check is called to check
+ * permissions on conf items of type #FR_TYPE_FILE_INPUT.
*
- * @param[out] out Where to write the CONF_PAIR we created with the default value.
- * @param[in] cs to parent the CONF_PAIR from.
- * @param[in] name of the CONF_PAIR to create.
- * @param[in] type of conf item being parsed (determines default quoting).
- * @param[in] dflt value to assign the CONF_PAIR.
- * @param[in] dflt_quote surrounding the CONF_PAIR.
- * @return
- * - 0 on success.
- * - -1 on failure.
+ * @note This is probably only useful for the freeradius daemon itself.
+ *
+ * @param uid to set, (uid_t)-1 to use current euid.
+ * @param gid to set, (gid_t)-1 to use current egid.
*/
-static int cf_pair_default(CONF_PAIR **out, CONF_SECTION *cs, char const *name,
- int type, char const *dflt, FR_TOKEN dflt_quote)
+void cf_file_check_user(uid_t uid, gid_t gid)
{
- int lineno = 0;
- char const *expanded;
- CONF_PAIR *cp;
- char buffer[8192];
+ if (uid != 0) conf_check_uid = uid;
+ if (gid != 0) conf_check_gid = gid;
+}
- rad_assert(dflt);
+/*
+ * See if any of the files have changed.
+ */
+int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback)
+{
+ CONF_SECTION *top;
+ cf_file_callback_t cb;
+ rbtree_t *tree;
- type = FR_BASE_TYPE(type);
+ top = cf_root(cs);
+ tree = cf_data_value(cf_data_find(top, rbtree_t, "filename"));
+ if (!tree) return true;
- /*
- * Defaults may need their values expanding
- */
- expanded = cf_expand_variables("<internal>", &lineno, cs, buffer, sizeof(buffer), dflt, NULL);
- if (!expanded) {
- cf_log_err(&(cs->item), "Failed expanding variable %s", name);
- return -1;
- }
+ cb.rcode = CF_FILE_NONE;
+ cb.callback = callback;
+ cb.modules = cf_section_find(cs, "modules", NULL);
- /*
- * If no default quote was set, determine it from the type
- */
- if (dflt_quote == T_INVALID) {
- switch (type) {
- case FR_TYPE_STRING:
- dflt_quote = T_DOUBLE_QUOTED_STRING;
- break;
+ (void) rbtree_walk(tree, RBTREE_IN_ORDER, _file_callback, &cb);
- case FR_TYPE_FILE_INPUT:
- case FR_TYPE_FILE_OUTPUT:
- dflt_quote = T_DOUBLE_QUOTED_STRING;
- break;
+ return cb.rcode;
+}
- default:
- dflt_quote = T_BARE_WORD;
- break;
- }
- }
+#ifdef WITH_CONF_WRITE
+static char const parse_tabs[] = " ";
- cp = cf_pair_alloc(cs, name, expanded, T_OP_EQ, T_BARE_WORD, dflt_quote);
- if (!cp) return -1;
+static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, FR_TOKEN t)
+{
+ size_t outlen;
+ char c;
+ char buffer[2048];
- cp->parsed = true;
+ switch (t) {
+ default:
+ c = '\0';
+ break;
- /*
- * Set the rcode to indicate we used a default value
- */
- *out = cp;
+ case T_DOUBLE_QUOTED_STRING:
+ c = '"';
+ break;
+
+ case T_SINGLE_QUOTED_STRING:
+ c = '\'';
+ break;
+
+ case T_BACK_QUOTED_STRING:
+ c = '`';
+ break;
+ }
+ if (c) fprintf(fp, "%c", c);
+
+ outlen = fr_snprint(buffer, sizeof(buffer), string, len, c);
+ fwrite(buffer, outlen, 1, fp);
+
+ if (c) fprintf(fp, "%c", c);
return 1;
}
-/** Parses a #CONF_PAIR into a C data type, with a default value.
- *
- * Takes fields from a #CONF_PARSER struct and uses them to parse the string value
- * of a #CONF_PAIR into a C data type matching the type argument.
- *
- * The format of the types are the same as #fr_value_box_t types.
- *
- * @note The dflt value will only be used if no matching #CONF_PAIR is found. Empty strings will not
- * result in the dflt value being used.
- *
- * **fr_type_t to data type mappings**
- * | fr_type_t | Data type | Dynamically allocated |
- * | ----------------------- | ------------------ | ---------------------- |
- * | FR_TYPE_TMPL | ``vp_tmpl_t`` | Yes |
- * | FR_TYPE_BOOL | ``bool`` | No |
- * | FR_TYPE_UINT32 | ``uint32_t`` | No |
- * | FR_TYPE_UINT16 | ``uint16_t`` | No |
- * | FR_TYPE_UINT64 | ``uint64_t`` | No |
- * | FR_TYPE_INT32 | ``int32_t`` | No |
- * | FR_TYPE_STRING | ``char const *`` | Yes |
- * | FR_TYPE_IPV4_ADDR | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_IPV4_PREFIX | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_IPV6_ADDR | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_IPV6_PREFIX | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_COMBO_IP_ADDR | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_COMBO_IP_PREFIX | ``fr_ipaddr_t`` | No |
- * | FR_TYPE_TIMEVAL | ``struct timeval`` | No |
- *
- * @param[in] ctx To allocate arrays and values in.
- * @param[in] cs to search for matching #CONF_PAIR in.
- * @param[in] name of #CONF_PAIR to search for.
- * @param[in] type Data type to parse #CONF_PAIR value as.
- * Should be one of the following ``data`` types,
- * and one or more of the following ``flag`` types or'd together:
- * - ``data`` #FR_TYPE_TMPL - @copybrief FR_TYPE_TMPL
- * Feeds the value into #tmpl_afrom_str. Value can be
- * obtained when processing requests, with #tmpl_expand or #tmpl_aexpand.
- * - ``data`` #FR_TYPE_BOOL - @copybrief FR_TYPE_BOOL
- * - ``data`` #FR_TYPE_UINT32 - @copybrief FR_TYPE_UINT32
- * - ``data`` #FR_TYPE_UINT16 - @copybrief FR_TYPE_UINT16
- * - ``data`` #FR_TYPE_UINT64 - @copybrief FR_TYPE_UINT64
- * - ``data`` #FR_TYPE_INT32 - @copybrief FR_TYPE_INT32
- * - ``data`` #FR_TYPE_STRING - @copybrief FR_TYPE_STRING
- * - ``data`` #FR_TYPE_IPV4_ADDR - @copybrief FR_TYPE_IPV4_ADDR (IPv4 address with prefix 32).
- * - ``data`` #FR_TYPE_IPV4_PREFIX - @copybrief FR_TYPE_IPV4_PREFIX (IPv4 address with variable prefix).
- * - ``data`` #FR_TYPE_IPV6_ADDR - @copybrief FR_TYPE_IPV6_ADDR (IPv6 address with prefix 128).
- * - ``data`` #FR_TYPE_IPV6_PREFIX - @copybrief FR_TYPE_IPV6_PREFIX (IPv6 address with variable prefix).
- * - ``data`` #FR_TYPE_COMBO_IP_ADDR - @copybrief FR_TYPE_COMBO_IP_ADDR (IPv4/IPv6 address with
- * prefix 32/128).
- * - ``data`` #FR_TYPE_COMBO_IP_PREFIX - @copybrief FR_TYPE_COMBO_IP_PREFIX (IPv4/IPv6 address with
- * variable prefix).
- * - ``data`` #FR_TYPE_TIMEVAL - @copybrief FR_TYPE_TIMEVAL
- * - ``flag`` #FR_TYPE_DEPRECATED - @copybrief FR_TYPE_DEPRECATED
- * - ``flag`` #FR_TYPE_REQUIRED - @copybrief FR_TYPE_REQUIRED
- * - ``flag`` #FR_TYPE_ATTRIBUTE - @copybrief FR_TYPE_ATTRIBUTE
- * - ``flag`` #FR_TYPE_SECRET - @copybrief FR_TYPE_SECRET
- * - ``flag`` #FR_TYPE_FILE_INPUT - @copybrief FR_TYPE_FILE_INPUT
- * - ``flag`` #FR_TYPE_NOT_EMPTY - @copybrief FR_TYPE_NOT_EMPTY
- * - ``flag`` #FR_TYPE_MULTI - @copybrief FR_TYPE_MULTI
- * - ``flag`` #FR_TYPE_IS_SET - @copybrief FR_TYPE_IS_SET
- * @param[out] out Pointer to a global variable, or pointer to a field in the struct being populated with values.
- * @param[in] dflt value to use, if no #CONF_PAIR is found.
- * @param[in] dflt_quote around the dflt value.
- * @return
- * - 1 if default value was used, or if there was no CONF_PAIR or dflt.
- * - 0 on success.
- * - -1 on error.
- * - -2 if deprecated.
- */
-int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs,
- char const *name, unsigned int type, void *out,
- char const *dflt, FR_TOKEN dflt_quote)
+static size_t cf_pair_write(FILE *fp, CONF_PAIR *cp)
{
- bool multi, required, deprecated;
- size_t count = 0;
- CONF_PAIR *cp, *dflt_cp = NULL;
+ if (!cp->value) {
+ fprintf(fp, "%s\n", cp->attr);
+ return 0;
+ }
- rad_assert(!(type & FR_TYPE_TMPL) || !dflt || (dflt_quote != T_INVALID)); /* We ALWAYS need a quoting type for templates */
+ cf_string_write(fp, cp->attr, strlen(cp->attr), cp->lhs_quote);
+ fprintf(fp, " %s ", fr_int2str(fr_tokens_table, cp->op, "<INVALID>"));
+ cf_string_write(fp, cp->orig_value, strlen(cp->orig_value), cp->rhs_quote);
+ fprintf(fp, "\n");
- multi = (type & FR_TYPE_MULTI);
- required = (type & FR_TYPE_REQUIRED);
- deprecated = (type & FR_TYPE_DEPRECATED);
+ return 1; /* FIXME */
+}
+
+static FILE *cf_file_write(CONF_SECTION *cs, char const *filename)
+{
+ FILE *fp;
+ char *p;
+ char const *q;
+ char buffer[8192];
+
+ q = filename;
+ if ((q[0] == '.') && (q[1] == '/')) q += 2;
+
+ snprintf(buffer, sizeof(buffer), "%s/%s", main_config.write_dir, q);
+
+ p = strrchr(buffer, '/');
+ *p = '\0';
+ if ((rad_mkdir(buffer, 0700, -1, -1) < 0) &&
+ (errno != EEXIST)) {
+ cf_log_err(cs, "Failed creating directory %s: %s",
+ buffer, strerror(errno));
+ return NULL;
+ }
/*
- * If the item is multi-valued we allocate an array
- * to hold the multiple values.
+ * And again, because rad_mkdir() butchers the buffer.
*/
- if (multi) {
- CONF_PAIR *first;
- void **array;
- size_t i;
+ snprintf(buffer, sizeof(buffer), "%s/%s", main_config.write_dir, q);
- /*
- * Easier than re-allocing
- */
- for (cp = first = cf_pair_find(cs, name);
- cp;
- cp = cf_pair_find_next(cs, cp, name)) count++;
+ fp = fopen(buffer, "a");
+ if (!fp) {
+ cf_log_err(cs, "Failed creating file %s: %s",
+ buffer, strerror(errno));
+ return NULL;
+ }
- /*
- * Multivalued, but there's no value, create a
- * default pair.
- */
- if (!count) {
- if (deprecated) return 0;
- if (!dflt) {
- if (required) {
- need_value:
- cf_log_err_cs(cs, "Configuration item \"%s\" must have a value", name);
- return -1;
- }
- return 1;
- }
+ return fp;
+}
- if (cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0) return -1;
- cp = dflt_cp;
- count = 1; /* Need one to hold the default */
- } else {
- cp = first; /* reset */
- }
+size_t cf_section_write(FILE *in_fp, CONF_SECTION *cs, int depth)
+{
+ bool prev = false;
+ CONF_ITEM *ci;
+ FILE *fp = NULL;
+ int fp_max = 0;
+ FILE *array[32];
- if (deprecated) {
- deprecated:
- cf_log_err_cp(cp, "Configuration pair \"%s\" is deprecated", cf_pair_attr(cp));
- return -2;
- }
+ /*
+ * Default to writing to the FP we're given.
+ */
+ fp = in_fp;
+ array[0] = fp;
+ fp_max = 0;
+
+ /*
+ * If we have somewhere to print, then print the section
+ * name1, etc.
+ */
+ if (fp) {
+ fwrite(parse_tabs, depth, 1, fp);
+ cf_string_write(fp, cs->name1, strlen(cs->name1), T_BARE_WORD);
/*
- * Tmpl is outside normal range
- */
- if (type & FR_TYPE_TMPL) {
- array = (void **)talloc_zero_array(ctx, vp_tmpl_t *, count);
- /*
- * Allocate an array of values.
+ * FIXME: check for "if" or "elsif". And if so, print
+ * out the parsed condition, instead of the input text
*
- * We don't NULL terminate. Consumer must use
- * talloc_array_length().
+ * cf_data_find(cs, CF_DATA_TYPE_UNLANG, "if");
*/
- } else switch (FR_BASE_TYPE(type)) {
- case FR_TYPE_BOOL:
- array = (void **)talloc_zero_array(ctx, bool, count);
- break;
- case FR_TYPE_UINT32:
- array = (void **)talloc_zero_array(ctx, uint32_t, count);
- break;
+ if (cs->name2) {
+ fr_cond_t *c;
- case FR_TYPE_UINT16:
- array = (void **)talloc_zero_array(ctx, uint16_t, count);
- break;
+ fputs(" ", fp);
- case FR_TYPE_UINT64:
- array = (void **)talloc_zero_array(ctx, uint64_t, count);
- break;
+ c = cf_data_value(cf_data_find(cs, fr_cond_t, NULL));
+ if (c) {
+ char buffer[1024];
- case FR_TYPE_INT32:
- array = (void **)talloc_zero_array(ctx, int32_t, count);
- break;
+ cond_snprint(buffer, sizeof(buffer), c);
+ fprintf(fp, "(%s)", buffer);
- case FR_TYPE_STRING:
- array = (void **)talloc_zero_array(ctx, char *, count);
+ } else { /* dump the string as-is */
+ cf_string_write(fp, cs->name2, strlen(cs->name2), cs->name2_quote);
+ }
+ }
+
+ fputs(" {\n", fp);
+ }
+
+ /*
+ * Loop over the children. Either recursing, or opening
+ * a new file.
+ */
+ for (ci = cs->item.child; ci; ci = ci->next) {
+ switch (ci->type) {
+ case CONF_ITEM_SECTION:
+ if (!fp) continue;
+
+ cf_section_write(fp, cf_item_to_section(ci), depth + 1);
break;
- case FR_TYPE_IPV4_ADDR:
- case FR_TYPE_IPV4_PREFIX:
- case FR_TYPE_IPV6_ADDR:
- case FR_TYPE_IPV6_PREFIX:
- case FR_TYPE_COMBO_IP_ADDR:
- case FR_TYPE_COMBO_IP_PREFIX:
- array = (void **)talloc_zero_array(ctx, fr_ipaddr_t, count);
+ case CONF_ITEM_PAIR:
+ if (!fp) continue;
+
+ /*
+ * Ignore internal things.
+ */
+ if (!ci->filename || (ci->filename[0] == '<')) break;
+
+ fwrite(parse_tabs, depth + 1, 1, fp);
+ cf_pair_write(fp, cf_item_to_pair(ci));
+ if (!prev) fputs("\n", fp);
+ prev = true;
break;
- case FR_TYPE_TIMEVAL:
- array = (void **)talloc_zero_array(ctx, struct timeval, count);
+ case CONF_ITEM_COMMENT:
+ rad_assert(fp != NULL);
+
+ prev = false;
+ fwrite(parse_tabs, depth + 1, 1, fp);
+ fprintf(fp, "#%s", ((CONF_COMMENT *)ci)->comment);
break;
- default:
- rad_assert(0); /* Unsupported type */
- return -1;
- }
+ case CONF_ITEM_INCLUDE:
+ /*
+ * Filename == open the new filename and use that.
+ *
+ * NULL == close the previous filename
+ */
+ if (((CONF_INCLUDE *) ci)->filename) {
+ CONF_INCLUDE *cc = (CONF_INCLUDE *) ci;
- for (i = 0; i < count; i++, cp = cf_pair_find_next(cs, cp, name)) {
- if (cf_pair_parse_value(array, &array[i], cs, cp, type) < 0) {
- talloc_free(array);
- talloc_free(dflt_cp);
- return -1;
- }
- }
+ /*
+ * Print out
+ *
+ * $INCLUDE foo.conf
+ * $INCLUDE foo/
+ *
+ * but not the files included from the last one.
+ */
+ if (fp && (cc->file_type != CONF_INCLUDE_FROMDIR)) {
+ fprintf(fp, "$INCLUDE %s\n", ((CONF_INCLUDE *)ci)->filename);
+ }
- *(void **)out = array;
- /*
- * Single valued config item gets written to
- * the data pointer directly.
- */
- } else {
- CONF_PAIR *next;
+ /*
+ * If it's a file, we write the
+ * file. We ignore the
+ * directories. They're just for printing.
+ */
+ if (cc->file_type != CONF_INCLUDE_DIR) {
+ fp = cf_file_write(cs, ((CONF_INCLUDE *) ci)->filename);
+ if (!fp) return 0;
+
+ fp_max++;
+ array[fp_max] = fp;
+ }
+ } else {
+ /*
+ * We're done the current file.
+ */
+ rad_assert(fp != NULL);
+ rad_assert(fp_max > 0);
+ fclose(fp);
+
+ fp_max--;
+ fp = array[fp_max];
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (fp) {
+ fwrite(parse_tabs, depth, 1, fp);
+ fputs("}\n\n", fp);
+ }
+
+ return 1;
+}
+#endif /* WITH_CONF_WRITE */
+
+static char const parse_spaces[] = " ";
+
+/** Validation function for ipaddr conf_file types
+ *
+ */
+static inline int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, fr_type_t type, char const *value,
+ fr_ipaddr_t *ipaddr)
+{
+ char ipbuf[128];
+
+ if (strcmp(value, "*") == 0) {
+ cf_log_info(cs, "%.*s\t%s = *", cs->depth, parse_spaces, name);
+ } else if (strspn(value, ".0123456789abdefABCDEF:%[]/") == strlen(value)) {
+ cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, name, value);
+ } else {
+ cf_log_info(cs, "%.*s\t%s = %s IPv%s address [%s]", cs->depth, parse_spaces, name, value,
+ (ipaddr->af == AF_INET ? "4" : " 6"), fr_inet_ntoh(ipaddr, ipbuf, sizeof(ipbuf)));
+ }
+
+ switch (type) {
+ case FR_TYPE_IPV4_ADDR:
+ case FR_TYPE_IPV6_ADDR:
+ case FR_TYPE_COMBO_IP_ADDR:
+ switch (ipaddr->af) {
+ case AF_INET:
+ if (ipaddr->prefix != 32) {
+ ERROR("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted for non-prefix types",
+ ipaddr->prefix);
+
+ return -1;
+ }
+ break;
+
+ case AF_INET6:
+ if (ipaddr->prefix != 128) {
+ ERROR("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted for non-prefix types",
+ ipaddr->prefix);
+
+ return -1;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ default:
+ return 0;
+ }
+}
+
+
+
+/** Parses a #CONF_PAIR into a C data type
+ *
+ * @copybrief cf_pair_value
+ * @see cf_pair_value
+ *
+ * @param[out] out Where to write the parsed value.
+ * @param[in] ctx to allocate any dynamic buffers in.
+ * @param[in] cs containing the cp.
+ * @param[in] cp to parse.
+ * @param[in] type to parse to. May contain flags.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+static int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs, CONF_PAIR *cp, unsigned int type)
+{
+ int rcode = 0;
+ bool attribute, required, secret, file_input, cant_be_empty, tmpl, file_exists;
+
+ fr_ipaddr_t *ipaddr;
+ ssize_t slen;
+
+ if (!cs) return -1;
+
+ attribute = (type & FR_TYPE_ATTRIBUTE);
+ required = (type & FR_TYPE_REQUIRED);
+ secret = (type & FR_TYPE_SECRET);
+ file_input = (type == FR_TYPE_FILE_INPUT); /* check, not and */
+ file_exists = (type == FR_TYPE_FILE_EXISTS); /* check, not and */
+ cant_be_empty = (type & FR_TYPE_NOT_EMPTY);
+ tmpl = (type & FR_TYPE_TMPL);
+
+ rad_assert(cp);
+ rad_assert(!(type & FR_TYPE_ATTRIBUTE) || tmpl); /* Attribute flag only valid for templates */
+
+ if (required) cant_be_empty = true; /* May want to review this in the future... */
+
+ type = FR_BASE_TYPE(type); /* normal types are small */
+
+ /*
+ * Everything except templates must have a base type.
+ */
+ if (!type && !tmpl) {
+ cf_log_err(cp, "Configuration pair \"%s\" must have a data type", cf_pair_attr(cp));
+ return -1;
+ }
+
+ rad_assert(cp->value);
+
+ /*
+ * Check for zero length strings
+ */
+ if ((cp->value[0] == '\0') && cant_be_empty) {
+ cf_log_err(cp, "Configuration pair \"%s\" must not be empty (zero length)", cf_pair_attr(cp));
+ if (!required) cf_log_err(cp, "Comment item to silence this message");
+ rcode = -1;
+
+ error:
+ return rcode;
+ }
+
+ if (tmpl) {
+ vp_tmpl_t *vpt;
+
+ /*
+ * This is so we produce TMPL_TYPE_ATTR_UNDEFINED template that
+ * the bootstrap functions can use to create an attribute.
+ *
+ * For other types of template such as xlats, we don't bother.
+ * There's no reason bootstrap functions need access to the raw
+ * xlat strings.
+ */
+ if (attribute) {
+ slen = tmpl_afrom_attr_str(cp, &vpt, cp->value, REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ true, true);
+ if (slen < 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(ctx, &spaces, &text, slen, cp->value);
+
+ cf_log_err(&cp->item, "Failed parsing attribute reference:");
+ cf_log_err(&cp->item, "%s", text);
+ cf_log_err(&cp->item, "%s^ %s", spaces, fr_strerror());
+
+ talloc_free(spaces);
+ talloc_free(text);
+ goto error;
+ }
+ *(vp_tmpl_t **)out = vpt;
+ }
+ goto finish;
+ }
+
+ switch (type) {
+ case FR_TYPE_BOOL:
+ /*
+ * Allow yes/no, true/false, and on/off
+ */
+ if ((strcasecmp(cp->value, "yes") == 0) ||
+ (strcasecmp(cp->value, "true") == 0) ||
+ (strcasecmp(cp->value, "on") == 0)) {
+ *(bool *)out = true;
+ } else if ((strcasecmp(cp->value, "no") == 0) ||
+ (strcasecmp(cp->value, "false") == 0) ||
+ (strcasecmp(cp->value, "off") == 0)) {
+ *(bool *)out = false;
+ } else {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for boolean variable %s",
+ cp->value, cf_pair_attr(cp));
+ rcode = -1;
+ goto error;
+ }
+ cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, cf_pair_attr(cp), cp->value);
+ break;
+
+ case FR_TYPE_UINT32:
+ {
+ unsigned long v = strtoul(cp->value, 0, 0);
+
+ /*
+ * Restrict integer values to 0-INT32_MAX, this means
+ * it will always be safe to cast them to a signed type
+ * for comparisons, and imposes the same range limit as
+ * before we switched to using an unsigned type to
+ * represent config item integers.
+ */
+ if (v > INT32_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
+ cf_pair_attr(cp), INT32_MAX);
+ rcode = -1;
+ goto error;
+ }
+
+ *(uint32_t *)out = v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint32_t *)out);
+ }
+ break;
+
+ case FR_TYPE_UINT8:
+ {
+ unsigned long v = strtoul(cp->value, 0, 0);
+
+ if (v > UINT8_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
+ cf_pair_attr(cp), UINT8_MAX);
+ rcode = -1;
+ goto error;
+ }
+ *(uint8_t *)out = (uint8_t) v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint8_t *)out);
+ }
+ break;
+
+ case FR_TYPE_UINT16:
+ {
+ unsigned long v = strtoul(cp->value, 0, 0);
+
+ if (v > UINT16_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", cp->value,
+ cf_pair_attr(cp), UINT16_MAX);
+ rcode = -1;
+ goto error;
+ }
+ *(uint16_t *)out = (uint16_t) v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, cf_pair_attr(cp), *(uint16_t *)out);
+ }
+ break;
+
+ case FR_TYPE_UINT64:
+ *(uint64_t *)out = strtoull(cp->value, NULL, 10);
+ cf_log_info(cs, "%.*s\t%s = %" PRIu64, cs->depth, parse_spaces, cf_pair_attr(cp), *(uint64_t *)out);
+ break;
+
+ case FR_TYPE_SIZE:
+ {
+ if (fr_size_from_str((size_t *)out, cp->value) < 0) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s: %s", cp->value,
+ cf_pair_attr(cp), fr_strerror());
+ rcode = -1;
+ goto error;
+ }
+ cf_log_info(cs, "%.*s\t%s = %zu", cs->depth, parse_spaces, cf_pair_attr(cp), *(size_t *)out);
+ break;
+ }
+
+ case FR_TYPE_INT32:
+ *(int32_t *)out = strtol(cp->value, NULL, 10);
+ cf_log_info(cs, "%.*s\t%s = %d", cs->depth, parse_spaces, cf_pair_attr(cp), *(int32_t *)out);
+ break;
+
+ case FR_TYPE_STRING:
+ {
+ char **str = out;
+
+ /*
+ * Hide secrets when using "radiusd -X".
+ */
+ if (secret && (rad_debug_lvl < L_DBG_LVL_3)) {
+ cf_log_info(cs, "%.*s\t%s = <<< secret >>>", cs->depth, parse_spaces, cf_pair_attr(cp));
+ } else {
+ cf_log_info(cs, "%.*s\t%s = \"%s\"", cs->depth, parse_spaces, cf_pair_attr(cp), cp->value);
+ }
+
+ /*
+ * If there's out AND it's an input file, check
+ * that we can read it. This check allows errors
+ * to be caught as early as possible, during
+ * server startup.
+ */
+ if (file_input && !cf_file_check(cs, cp->value, true)) {
+ rcode = -1;
+ goto error;
+ }
+
+ if (file_exists && !cf_file_check(cs, cp->value, false)) {
+ rcode = -1;
+ goto error;
+ }
+
+ /*
+ * Free any existing buffers
+ */
+ talloc_free(*str);
+ *str = talloc_typed_strdup(cs, cp->value);
+ }
+ break;
+
+ case FR_TYPE_IPV4_ADDR:
+ case FR_TYPE_IPV4_PREFIX:
+ ipaddr = out;
+
+ if (fr_inet_pton4(ipaddr, cp->value, -1, true, false, true) < 0) {
+ cf_log_err(&(cp->item), "%s", fr_strerror());
+ rcode = -1;
+ goto error;
+ }
+ /* Also prints the IP to the log */
+ if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
+ rcode = -1;
+ goto error;
+ }
+ break;
+
+ case FR_TYPE_IPV6_ADDR:
+ case FR_TYPE_IPV6_PREFIX:
+ ipaddr = out;
+
+ if (fr_inet_pton6(ipaddr, cp->value, -1, true, false, true) < 0) {
+ cf_log_err(&(cp->item), "%s", fr_strerror());
+ rcode = -1;
+ goto error;
+ }
+ /* Also prints the IP to the log */
+ if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
+ rcode = -1;
+ goto error;
+ }
+ break;
- cp = cf_pair_find(cs, name);
- if (!cp) {
- if (deprecated) return 0;
- if (!dflt) {
- if (required) goto need_value;
- return 1;
- }
+ case FR_TYPE_COMBO_IP_ADDR:
+ case FR_TYPE_COMBO_IP_PREFIX:
+ ipaddr = out;
- if (cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0) return -1;
- cp = dflt_cp;
+ if (fr_inet_pton(ipaddr, cp->value, -1, AF_UNSPEC, true, true) < 0) {
+ cf_log_err(&(cp->item), "%s", fr_strerror());
+ rcode = -1;
+ goto error;
}
-
- next = cf_pair_find_next(cs, cp, name);
- if (next) {
- cf_log_err(&(next->item), "Invalid duplicate configuration item '%s'", name);
- return -1;
+ /* Also prints the IP to the log */
+ if (fr_item_validate_ipaddr(cs, cf_pair_attr(cp), type, cp->value, ipaddr) < 0) {
+ rcode = -1;
+ goto error;
}
+ break;
- if (deprecated) goto deprecated;
+ case FR_TYPE_TIMEVAL:
+ {
+ struct timeval tv;
- if (cf_pair_parse_value(ctx, out, cs, cp, type) < 0) {
- talloc_free(dflt_cp);
- return -1;
+ if (fr_timeval_from_str(&tv, cp->value) < 0) {
+ cf_log_err(&(cp->item), "%s", fr_strerror());
+ rcode = -1;
+ goto error;
}
+ cf_log_info(cs, "%.*s\t%s = %d.%06d", cs->depth, parse_spaces, cf_pair_attr(cp),
+ (int)tv.tv_sec, (int)tv.tv_usec);
+ memcpy(out, &tv, sizeof(tv));
}
+ break;
- /*
- * If we created a default cp and succeeded
- * in parsing the dflt value, add the new
- * cp to the enclosing section.
- */
- if (dflt_cp) {
- cf_item_add(cs, &(dflt_cp->item));
- return 1;
+ default:
+ /*
+ * If we get here, it's a sanity check error.
+ * It's not an error parsing the configuration
+ * file.
+ */
+ rad_assert(type > FR_TYPE_INVALID);
+ rad_assert(type < FR_TYPE_MAX);
+
+ cf_log_err(&(cp->item), "type '%s' (%i) is not supported in the configuration files",
+ fr_int2str(dict_attr_types, type, "?Unknown?"), type);
+ rcode = -1;
+ goto error;
}
- return 0;
+finish:
+ cp->parsed = true;
+
+ return rcode;
}
-/** Pre-allocate a config section structure to allow defaults to be set
+/** Allocate a pair using the dflt value and quotation
*
- * @param cs The parent subsection.
- * @param base pointer or variable.
- * @param variables that may have defaults in this config section.
+ * The pair created by this function should fed to #cf_pair_parse for parsing.
+ *
+ * @param[out] out Where to write the CONF_PAIR we created with the default value.
+ * @param[in] cs to parent the CONF_PAIR from.
+ * @param[in] name of the CONF_PAIR to create.
+ * @param[in] type of conf item being parsed (determines default quoting).
+ * @param[in] dflt value to assign the CONF_PAIR.
+ * @param[in] dflt_quote surrounding the CONF_PAIR.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
*/
-static int cf_section_parse_init(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
+static int cf_pair_default(CONF_PAIR **out, CONF_SECTION *cs, char const *name,
+ int type, char const *dflt, FR_TOKEN dflt_quote)
{
- int i;
-
- for (i = 0; variables[i].name != NULL; i++) {
- if ((FR_BASE_TYPE(variables[i].type) == FR_TYPE_SUBSECTION)) {
- CONF_SECTION *subcs;
-
- if (!variables[i].dflt) continue;
-
- subcs = cf_subsection_find(cs, variables[i].name);
- if (!subcs && (variables[i].type & FR_TYPE_REQUIRED)) {
- cf_log_err_cs(cs, "Missing %s {} subsection", variables[i].name);
- return -1;
- }
-
- /*
- * Set the is_set field for the subsection.
- */
- if (variables[i].type & FR_TYPE_IS_SET) {
- bool *is_set;
+ int lineno = 0;
+ char const *expanded;
+ CONF_PAIR *cp;
+ char buffer[8192];
- is_set = variables[i].data ? variables[i].is_set_ptr :
- ((uint8_t *)base) + variables[i].is_set_offset;
- if (is_set) *is_set = !!subcs;
- }
+ rad_assert(dflt);
- /*
- * If there's no subsection in the
- * config, BUT the CONF_PARSER wants one,
- * then create an empty one. This is so
- * that we can track the strings,
- * etc. allocated in the subsection.
- */
- if (!subcs) {
- subcs = cf_section_alloc(cs, variables[i].name, NULL);
- if (!subcs) return -1;
+ type = FR_BASE_TYPE(type);
- cf_item_add(cs, &(subcs->item));
- }
+ /*
+ * Defaults may need their values expanding
+ */
+ expanded = cf_expand_variables("<internal>", &lineno, cs, buffer, sizeof(buffer), dflt, NULL);
+ if (!expanded) {
+ cf_log_err(&(cs->item), "Failed expanding variable %s", name);
+ return -1;
+ }
- continue;
- }
+ /*
+ * If no default quote was set, determine it from the type
+ */
+ if (dflt_quote == T_INVALID) {
+ switch (type) {
+ case FR_TYPE_STRING:
+ dflt_quote = T_DOUBLE_QUOTED_STRING;
+ break;
- if ((FR_BASE_TYPE(variables[i].type) != FR_TYPE_STRING) &&
- (variables[i].type != FR_TYPE_FILE_INPUT) &&
- (variables[i].type != FR_TYPE_FILE_OUTPUT)) {
- continue;
- }
+ case FR_TYPE_FILE_INPUT:
+ case FR_TYPE_FILE_OUTPUT:
+ dflt_quote = T_DOUBLE_QUOTED_STRING;
+ break;
- if (variables[i].data) {
- *(char **) variables[i].data = NULL;
- } else if (base) {
- *(char **) (((char *)base) + variables[i].offset) = NULL;
- } else {
- continue;
+ default:
+ dflt_quote = T_BARE_WORD;
+ break;
}
- } /* for all variables in the configuration section */
-
- return 0;
-}
-
-static void cf_section_parse_warn(CONF_SECTION *cs)
-{
- CONF_ITEM *ci;
+ }
- for (ci = cs->children; ci; ci = ci->next) {
- /*
- * Don't recurse on sections. We can only safely
- * check conf pairs at the same level as the
- * section that was just parsed.
- */
- if (ci->type == CONF_ITEM_SECTION) continue;
- if (ci->type == CONF_ITEM_PAIR) {
- CONF_PAIR *cp;
+ cp = cf_pair_alloc(cs, name, expanded, T_OP_EQ, T_BARE_WORD, dflt_quote);
+ if (!cp) return -1;
- cp = cf_item_to_pair(ci);
- if (cp->parsed || (ci->lineno < 0)) continue;
+ cp->parsed = true;
- WARN("%s[%d]: The item '%s' is defined, but is unused by the configuration",
- ci->filename, ci->lineno,
- cp->attr);
- }
+ /*
+ * Set the rcode to indicate we used a default value
+ */
+ *out = cp;
- /*
- * Skip everything else.
- */
- }
+ return 1;
}
-/** Parse a subsection
+/** Parses a #CONF_PAIR into a C data type, with a default value.
*
- * @note Turns out using nested structures (instead of pointers) for subsections, was actually
- * a pretty bad design decision, and will need to be fixed at some future point.
- * For now we have a horrible hack where only multi-subsections get an array of structures
- * of the appropriate size.
+ * Takes fields from a #CONF_PARSER struct and uses them to parse the string value
+ * of a #CONF_PAIR into a C data type matching the type argument.
*
- * @param[in] ctx to allocate any additional structures under.
- * @param[out] out pointer to a struct/pointer to fill with data.
- * @param[in] cs to parse.
- * @param[in] name of subsection to parse.
- * @param[in] type flags.
- * @param[in] subcs_vars CONF_PARSER definitions for the subsection.
- * @param[in] subcs_size size of subsection structures to allocate.
+ * The format of the types are the same as #fr_value_box_t types.
+ *
+ * @note The dflt value will only be used if no matching #CONF_PAIR is found. Empty strings will not
+ * result in the dflt value being used.
+ *
+ * **fr_type_t to data type mappings**
+ * | fr_type_t | Data type | Dynamically allocated |
+ * | ----------------------- | ------------------ | ---------------------- |
+ * | FR_TYPE_TMPL | ``vp_tmpl_t`` | Yes |
+ * | FR_TYPE_BOOL | ``bool`` | No |
+ * | FR_TYPE_UINT32 | ``uint32_t`` | No |
+ * | FR_TYPE_UINT16 | ``uint16_t`` | No |
+ * | FR_TYPE_UINT64 | ``uint64_t`` | No |
+ * | FR_TYPE_INT32 | ``int32_t`` | No |
+ * | FR_TYPE_STRING | ``char const *`` | Yes |
+ * | FR_TYPE_IPV4_ADDR | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_IPV4_PREFIX | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_IPV6_ADDR | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_IPV6_PREFIX | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_COMBO_IP_ADDR | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_COMBO_IP_PREFIX | ``fr_ipaddr_t`` | No |
+ * | FR_TYPE_TIMEVAL | ``struct timeval`` | No |
+ *
+ * @param[in] ctx To allocate arrays and values in.
+ * @param[in] cs to search for matching #CONF_PAIR in.
+ * @param[in] name of #CONF_PAIR to search for.
+ * @param[in] type Data type to parse #CONF_PAIR value as.
+ * Should be one of the following ``data`` types,
+ * and one or more of the following ``flag`` types or'd together:
+ * - ``data`` #FR_TYPE_TMPL - @copybrief FR_TYPE_TMPL
+ * Feeds the value into #tmpl_afrom_str. Value can be
+ * obtained when processing requests, with #tmpl_expand or #tmpl_aexpand.
+ * - ``data`` #FR_TYPE_BOOL - @copybrief FR_TYPE_BOOL
+ * - ``data`` #FR_TYPE_UINT32 - @copybrief FR_TYPE_UINT32
+ * - ``data`` #FR_TYPE_UINT16 - @copybrief FR_TYPE_UINT16
+ * - ``data`` #FR_TYPE_UINT64 - @copybrief FR_TYPE_UINT64
+ * - ``data`` #FR_TYPE_INT32 - @copybrief FR_TYPE_INT32
+ * - ``data`` #FR_TYPE_STRING - @copybrief FR_TYPE_STRING
+ * - ``data`` #FR_TYPE_IPV4_ADDR - @copybrief FR_TYPE_IPV4_ADDR (IPv4 address with prefix 32).
+ * - ``data`` #FR_TYPE_IPV4_PREFIX - @copybrief FR_TYPE_IPV4_PREFIX (IPv4 address with variable prefix).
+ * - ``data`` #FR_TYPE_IPV6_ADDR - @copybrief FR_TYPE_IPV6_ADDR (IPv6 address with prefix 128).
+ * - ``data`` #FR_TYPE_IPV6_PREFIX - @copybrief FR_TYPE_IPV6_PREFIX (IPv6 address with variable prefix).
+ * - ``data`` #FR_TYPE_COMBO_IP_ADDR - @copybrief FR_TYPE_COMBO_IP_ADDR (IPv4/IPv6 address with
+ * prefix 32/128).
+ * - ``data`` #FR_TYPE_COMBO_IP_PREFIX - @copybrief FR_TYPE_COMBO_IP_PREFIX (IPv4/IPv6 address with
+ * variable prefix).
+ * - ``data`` #FR_TYPE_TIMEVAL - @copybrief FR_TYPE_TIMEVAL
+ * - ``flag`` #FR_TYPE_DEPRECATED - @copybrief FR_TYPE_DEPRECATED
+ * - ``flag`` #FR_TYPE_REQUIRED - @copybrief FR_TYPE_REQUIRED
+ * - ``flag`` #FR_TYPE_ATTRIBUTE - @copybrief FR_TYPE_ATTRIBUTE
+ * - ``flag`` #FR_TYPE_SECRET - @copybrief FR_TYPE_SECRET
+ * - ``flag`` #FR_TYPE_FILE_INPUT - @copybrief FR_TYPE_FILE_INPUT
+ * - ``flag`` #FR_TYPE_NOT_EMPTY - @copybrief FR_TYPE_NOT_EMPTY
+ * - ``flag`` #FR_TYPE_MULTI - @copybrief FR_TYPE_MULTI
+ * - ``flag`` #FR_TYPE_IS_SET - @copybrief FR_TYPE_IS_SET
+ * @param[out] out Pointer to a global variable, or pointer to a field in the struct being populated with values.
+ * @param[in] dflt value to use, if no #CONF_PAIR is found.
+ * @param[in] dflt_quote around the dflt value.
* @return
+ * - 1 if default value was used, or if there was no CONF_PAIR or dflt.
* - 0 on success.
- * - -1 on general error.
- * - -2 if a deprecated #CONF_ITEM was found.
+ * - -1 on error.
+ * - -2 if deprecated.
*/
-static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs,
- char const *name, fr_type_t type, CONF_PARSER const *subcs_vars, size_t subcs_size)
+int cf_pair_parse(TALLOC_CTX *ctx, CONF_SECTION *cs,
+ char const *name, unsigned int type, void *out,
+ char const *dflt, FR_TOKEN dflt_quote)
{
- CONF_SECTION *subcs;
- int count, i, ret;
- uint8_t **array;
+ bool multi, required, deprecated;
+ size_t count = 0;
+ CONF_PAIR *cp, *dflt_cp = NULL;
- rad_assert(type & FR_TYPE_SUBSECTION);
+ rad_assert(!(type & FR_TYPE_TMPL) || !dflt || (dflt_quote != T_INVALID)); /* We ALWAYS need a quoting type for templates */
- subcs = cf_subsection_find(cs, name);
- rad_assert(subcs); /* should have been pre-allocated earlier */
+ multi = (type & FR_TYPE_MULTI);
+ required = (type & FR_TYPE_REQUIRED);
+ deprecated = (type & FR_TYPE_DEPRECATED);
/*
- * Handle the single subsection case (which is simple)
+ * If the item is multi-valued we allocate an array
+ * to hold the multiple values.
*/
- if (!(type & FR_TYPE_MULTI)) {
- uint8_t *buff;
+ if (multi) {
+ CONF_PAIR *first;
+ void **array;
+ size_t i;
/*
- * FIXME: We shouldn't allow nested structures like this.
- * Each subsection struct should be allocated separately so
- * we have a clean talloc hierarchy.
+ * Easier than re-allocing
*/
- if (!subcs_size) return cf_section_parse(ctx, out, subcs, subcs_vars);
-
- MEM(buff = talloc_array(ctx, uint8_t, subcs_size));
- ret = cf_section_parse(buff, buff, subcs, subcs_vars);
- if (ret < 0) {
- talloc_free(buff);
- return -1;
- }
-
- *((uint8_t **)out) = buff;
- }
-
- rad_assert(subcs_size);
-
- /*
- * Handle the multi subsection case (which is harder)
- */
- for (subcs = cf_subsection_find(cs, name), count = 0;
- subcs;
- subcs = cf_subsection_find_next(cs, subcs, name), count++);
-
- /*
- * Allocate an array to hold the subsections
- */
- MEM(array = talloc_array(ctx, uint8_t *, count));
+ for (cp = first = cf_pair_find(cs, name);
+ cp;
+ cp = cf_pair_find_next(cs, cp, name)) count++;
- /*
- * Start parsing...
- *
- * Note, we allocate each subsection structure individually
- * so that they can be used as talloc contexts and we can
- * keep the talloc hierarchy clean.
- */
- for (subcs = cf_subsection_find(cs, name), i = 0;
- subcs;
- subcs = cf_subsection_find_next(cs, subcs, name), i++) {
- uint8_t *buff;
+ /*
+ * Multivalued, but there's no value, create a
+ * default pair.
+ */
+ if (!count) {
+ if (deprecated) return 0;
+ if (!dflt) {
+ if (required) {
+ need_value:
+ cf_log_err(cs, "Configuration item \"%s\" must have a value", name);
+ return -1;
+ }
+ return 1;
+ }
- MEM(buff = talloc_zero_array(array, uint8_t, subcs_size));
- array[i] = buff;
+ if (cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0) return -1;
+ cp = dflt_cp;
+ count = 1; /* Need one to hold the default */
+ } else {
+ cp = first; /* reset */
+ }
- ret = cf_section_parse(buff, buff, subcs, subcs_vars);
- if (ret < 0) {
- talloc_free(array);
- return ret;
+ if (deprecated) {
+ deprecated:
+ cf_log_err(cp, "Configuration pair \"%s\" is deprecated", cf_pair_attr(cp));
+ return -2;
}
- }
- *((uint8_t ***)out) = array;
+ /*
+ * Tmpl is outside normal range
+ */
+ if (type & FR_TYPE_TMPL) {
+ array = (void **)talloc_zero_array(ctx, vp_tmpl_t *, count);
+ /*
+ * Allocate an array of values.
+ *
+ * We don't NULL terminate. Consumer must use
+ * talloc_array_length().
+ */
+ } else switch (FR_BASE_TYPE(type)) {
+ case FR_TYPE_BOOL:
+ array = (void **)talloc_zero_array(ctx, bool, count);
+ break;
- return 0;
-}
+ case FR_TYPE_UINT32:
+ array = (void **)talloc_zero_array(ctx, uint32_t, count);
+ break;
-/** Parse a configuration section into user-supplied variables
- *
- * @param[in] ctx to allocate any strings, or additional structures in.
- * Usually the same as base, unless base is a nested struct.
- * @param[out] base pointer to a struct to fill with data.
- * @param[in] cs to parse.
- * @param[in] variables mappings between struct fields and #CONF_ITEM s.
- * @return
- * - 0 on success.
- * - -1 on general error.
- * - -2 if a deprecated #CONF_ITEM was found.
- */
-int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, CONF_PARSER const *variables)
-{
- int ret = 0;
- int i;
- void *data;
- bool *is_set = NULL;
+ case FR_TYPE_UINT16:
+ array = (void **)talloc_zero_array(ctx, uint16_t, count);
+ break;
- /*
- * Hack for partially parsed sections.
- */
- if (!variables) {
- cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
- return 0;
- }
+ case FR_TYPE_UINT64:
+ array = (void **)talloc_zero_array(ctx, uint64_t, count);
+ break;
- cs->variables = variables; /* this doesn't hurt anything */
+ case FR_TYPE_INT32:
+ array = (void **)talloc_zero_array(ctx, int32_t, count);
+ break;
- if (!cs->name2) {
- cf_log_info(cs, "%.*s%s {", cs->depth, parse_spaces, cs->name1);
- } else {
- cf_log_info(cs, "%.*s%s %s {", cs->depth, parse_spaces, cs->name1, cs->name2);
- }
+ case FR_TYPE_STRING:
+ array = (void **)talloc_zero_array(ctx, char *, count);
+ break;
- if (cf_section_parse_init(cs, base, variables) < 0) return -1;
+ case FR_TYPE_IPV4_ADDR:
+ case FR_TYPE_IPV4_PREFIX:
+ case FR_TYPE_IPV6_ADDR:
+ case FR_TYPE_IPV6_PREFIX:
+ case FR_TYPE_COMBO_IP_ADDR:
+ case FR_TYPE_COMBO_IP_PREFIX:
+ array = (void **)talloc_zero_array(ctx, fr_ipaddr_t, count);
+ break;
- /*
- * Handle the known configuration parameters.
- */
- for (i = 0; variables[i].name != NULL; i++) {
- /*
- * Handle subsections specially
- */
- if (FR_BASE_TYPE(variables[i].type) == FR_TYPE_SUBSECTION) {
- if (cf_subsection_parse(ctx, (uint8_t *)base + variables[i].offset, cs,
- variables[i].name, variables[i].type,
- variables[i].subcs, variables[i].subcs_size) < 0) goto finish;
- continue;
- } /* else it's a CONF_PAIR */
+ case FR_TYPE_TIMEVAL:
+ array = (void **)talloc_zero_array(ctx, struct timeval, count);
+ break;
- if (variables[i].data) {
- data = variables[i].data; /* prefer this. */
- } else if (base) {
- data = ((uint8_t *)base) + variables[i].offset;
- } else if (!rad_cond_assert(0)) {
- ret = -1;
- goto finish;
+ default:
+ rad_assert(0); /* Unsupported type */
+ return -1;
}
- /*
- * Get pointer to where we need to write out
- * whether the pointer was set.
- */
- if (variables[i].type & FR_TYPE_IS_SET) {
- is_set = variables[i].data ? variables[i].is_set_ptr :
- ((uint8_t *)base) + variables[i].is_set_offset;
+ for (i = 0; i < count; i++, cp = cf_pair_find_next(cs, cp, name)) {
+ if (cf_pair_parse_value(array, &array[i], cs, cp, type) < 0) {
+ talloc_free(array);
+ talloc_free(dflt_cp);
+ return -1;
+ }
}
- /*
- * Parse the pair we found, or a default value.
- */
- ret = cf_pair_parse(ctx, cs, variables[i].name, variables[i].type, data,
- variables[i].dflt, variables[i].quote);
- switch (ret) {
- case 1: /* Used default (or not present) */
- if (is_set) *is_set = false;
- ret = 0;
- break;
-
- case 0: /* OK */
- if (is_set) *is_set = true;
- break;
-
- case -1: /* Parse error */
- goto finish;
+ *(void **)out = array;
+ /*
+ * Single valued config item gets written to
+ * the data pointer directly.
+ */
+ } else {
+ CONF_PAIR *next;
- case -2: /* Deprecated CONF ITEM */
- if ((variables[i + 1].offset && (variables[i + 1].offset == variables[i].offset)) ||
- (variables[i + 1].data && (variables[i + 1].data == variables[i].data))) {
- cf_log_err(&(cs->item), "Replace \"%s\" with \"%s\"", variables[i].name,
- variables[i + 1].name);
+ cp = cf_pair_find(cs, name);
+ if (!cp) {
+ if (deprecated) return 0;
+ if (!dflt) {
+ if (required) goto need_value;
+ return 1;
}
- goto finish;
+
+ if (cf_pair_default(&dflt_cp, cs, name, type, dflt, dflt_quote) < 0) return -1;
+ cp = dflt_cp;
}
- } /* for all variables in the configuration section */
- /*
- * Ensure we have a proper terminator, type so we catch
- * missing terminators reliably
- */
- rad_cond_assert(variables[i].type == conf_term.type);
+ next = cf_pair_find_next(cs, cp, name);
+ if (next) {
+ cf_log_err(&(next->item), "Invalid duplicate configuration item '%s'", name);
+ return -1;
+ }
- cs->base = base;
+ if (deprecated) goto deprecated;
- /*
- * Hack for partially parsed sections. We don't print
- * out the final "}", that will be printed out when the
- * caller re-calls us with 'variable=NULL'. And, we don't warn about unused
- */
- if (variables[i].offset == 1) return ret;
+ if (cf_pair_parse_value(ctx, out, cs, cp, type) < 0) {
+ talloc_free(dflt_cp);
+ return -1;
+ }
+ }
/*
- * Warn about items in the configuration which weren't
- * checked during parsing.
+ * If we created a default cp and succeeded
+ * in parsing the dflt value, add the new
+ * cp to the enclosing section.
*/
- if (rad_debug_lvl >= 3) cf_section_parse_warn(cs);
-
- cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
+ if (dflt_cp) {
+ cf_item_add(cs, &(dflt_cp->item));
+ return 1;
+ }
-finish:
- return ret;
+ return 0;
}
-/*
- * Merge the template so everyting else "just works".
+/** Pre-allocate a config section structure to allow defaults to be set
+ *
+ * @param cs The parent subsection.
+ * @param base pointer or variable.
+ * @param variables that may have defaults in this config section.
*/
-static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
+static int cf_section_parse_init(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
{
- CONF_ITEM *ci;
+ int i;
- if (!cs || !template) return true;
+ for (i = 0; variables[i].name != NULL; i++) {
+ if ((FR_BASE_TYPE(variables[i].type) == FR_TYPE_SUBSECTION)) {
+ CONF_SECTION *subcs;
- cs->template = NULL;
+ if (!variables[i].dflt) continue;
- /*
- * Walk over the template, adding its' entries to the
- * current section. But only if the entries don't
- * already exist in the current section.
- */
- for (ci = template->children; ci; ci = ci->next) {
- if (ci->type == CONF_ITEM_PAIR) {
- CONF_PAIR *cp1, *cp2;
+ subcs = cf_section_find(cs, variables[i].name, NULL);
+ if (!subcs && (variables[i].type & FR_TYPE_REQUIRED)) {
+ cf_log_err(cs, "Missing %s {} subsection", variables[i].name);
+ return -1;
+ }
/*
- * It exists, don't over-write it.
+ * Set the is_set field for the subsection.
*/
- cp1 = cf_item_to_pair(ci);
- if (cf_pair_find(cs, cp1->attr)) {
- continue;
+ if (variables[i].type & FR_TYPE_IS_SET) {
+ bool *is_set;
+
+ is_set = variables[i].data ? variables[i].is_set_ptr :
+ ((uint8_t *)base) + variables[i].is_set_offset;
+ if (is_set) *is_set = !!subcs;
}
/*
- * Create a new pair with all of the data
- * of the old one.
+ * If there's no subsection in the
+ * config, BUT the CONF_PARSER wants one,
+ * then create an empty one. This is so
+ * that we can track the strings,
+ * etc. allocated in the subsection.
*/
- cp2 = cf_pair_dup(cs, cp1);
- if (!cp2) return false;
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, variables[i].name, NULL);
+ if (!subcs) return -1;
- cp2->item.filename = cp1->item.filename;
- cp2->item.lineno = cp1->item.lineno;
+ cf_item_add(cs, &(subcs->item));
+ }
- cf_item_add(cs, &(cp2->item));
continue;
}
- if (ci->type == CONF_ITEM_SECTION) {
- CONF_SECTION *subcs1, *subcs2;
-
- subcs1 = cf_item_to_section(ci);
- rad_assert(subcs1 != NULL);
-
- subcs2 = cf_subsection_find_name2(cs, subcs1->name1, subcs1->name2);
- if (subcs2) {
- /*
- * sub-sections get merged.
- */
- if (!cf_template_merge(subcs2, subcs1)) {
- return false;
- }
- continue;
- }
-
- /*
- * Our section doesn't have a matching
- * sub-section. Copy it verbatim from
- * the template.
- */
- subcs2 = cf_section_dup(cs, subcs1,
- cf_section_name1(subcs1), cf_section_name2(subcs1),
- false);
- if (!subcs2) return false;
-
- subcs2->item.filename = subcs1->item.filename;
- subcs2->item.lineno = subcs1->item.lineno;
-
- cf_item_add(cs, &(subcs2->item));
+ if ((FR_BASE_TYPE(variables[i].type) != FR_TYPE_STRING) &&
+ (variables[i].type != FR_TYPE_FILE_INPUT) &&
+ (variables[i].type != FR_TYPE_FILE_OUTPUT)) {
continue;
}
- /* ignore everything else */
- }
+ if (variables[i].data) {
+ *(char **) variables[i].data = NULL;
+ } else if (base) {
+ *(char **) (((char *)base) + variables[i].offset) = NULL;
+ } else {
+ continue;
+ }
+ } /* for all variables in the configuration section */
- return true;
+ return 0;
}
-static char const *cf_local_file(char const *base, char const *filename,
- char *buffer, size_t bufsize)
+static void cf_section_parse_warn(CONF_SECTION *cs)
{
- size_t dirsize;
- char *p;
+ CONF_ITEM *ci;
- strlcpy(buffer, base, bufsize);
+ for (ci = cs->item.child; ci; ci = ci->next) {
+ /*
+ * Don't recurse on sections. We can only safely
+ * check conf pairs at the same level as the
+ * section that was just parsed.
+ */
+ if (ci->type == CONF_ITEM_SECTION) continue;
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp;
- p = strrchr(buffer, FR_DIR_SEP);
- if (!p) return filename;
- if (p[1]) { /* ./foo */
- p[1] = '\0';
- }
+ cp = cf_item_to_pair(ci);
+ if (cp->parsed || (ci->lineno < 0)) continue;
- dirsize = (p - buffer) + 1;
+ WARN("%s[%d]: The item '%s' is defined, but is unused by the configuration",
+ ci->filename, ci->lineno,
+ cp->attr);
+ }
- if ((dirsize + strlen(filename)) >= bufsize) {
- return NULL;
+ /*
+ * Skip everything else.
+ */
}
-
- strlcpy(p + 1, filename, bufsize - dirsize);
-
- return buffer;
}
-static bool invalid_location(CONF_SECTION *this, char const *name, char const *filename, int lineno)
+/** Parse a subsection
+ *
+ * @note Turns out using nested structures (instead of pointers) for subsections, was actually
+ * a pretty bad design decision, and will need to be fixed at some future point.
+ * For now we have a horrible hack where only multi-subsections get an array of structures
+ * of the appropriate size.
+ *
+ * @param[in] ctx to allocate any additional structures under.
+ * @param[out] out pointer to a struct/pointer to fill with data.
+ * @param[in] cs to parse.
+ * @param[in] name of subsection to parse.
+ * @param[in] type flags.
+ * @param[in] subcs_vars CONF_PARSER definitions for the subsection.
+ * @param[in] subcs_size size of subsection structures to allocate.
+ * @return
+ * - 0 on success.
+ * - -1 on general error.
+ * - -2 if a deprecated #CONF_ITEM was found.
+ */
+static int cf_subsection_parse(TALLOC_CTX *ctx, void *out, CONF_SECTION *cs,
+ char const *name, fr_type_t type, CONF_PARSER const *subcs_vars, size_t subcs_size)
{
- /*
- * if / elsif MUST be inside of a
- * processing section, which MUST in turn
- * be inside of a "server" directive.
- */
- if (!this || !this->item.parent) {
- invalid_location:
- ERROR("%s[%d]: Invalid location for '%s'",
- filename, lineno, name);
- return true;
- }
+ CONF_SECTION *subcs;
+ int count, i, ret;
+ uint8_t **array;
+
+ rad_assert(type & FR_TYPE_SUBSECTION);
+
+ subcs = cf_section_find(cs, name, NULL);
+ if (!subcs) return 0;
/*
- * Can only have "if" in 3 named sections.
+ * Handle the single subsection case (which is simple)
*/
- this = cf_item_to_section(this->item.parent);
- while ((strcmp(this->name1, "server") != 0) &&
- (strcmp(this->name1, "policy") != 0) &&
- (strcmp(this->name1, "instantiate") != 0)) {
- this = cf_item_to_section(this->item.parent);
- if (!this) goto invalid_location;
- }
+ if (!(type & FR_TYPE_MULTI)) {
+ uint8_t *buff;
- return false;
-}
+ /*
+ * FIXME: We shouldn't allow nested structures like this.
+ * Each subsection struct should be allocated separately so
+ * we have a clean talloc hierarchy.
+ */
+ if (!subcs_size) return cf_section_parse(ctx, out, subcs, subcs_vars);
-#ifdef WITH_CONF_WRITE
-static void cf_comment_add(CONF_SECTION *cs, int lineno, char const *ptr)
-{
- CONF_COMMENT *cc;
+ MEM(buff = talloc_array(ctx, uint8_t, subcs_size));
+ ret = cf_section_parse(buff, buff, subcs, subcs_vars);
+ if (ret < 0) {
+ talloc_free(buff);
+ return -1;
+ }
- cc = talloc_zero(cs, CONF_COMMENT);
- cc->item.type = CONF_ITEM_COMMENT;
- cc->item.parent = cs;
- cc->item.filename = cs->item.filename;
- cc->item.lineno = lineno;
- cc->comment = talloc_typed_strdup(cc, ptr);
+ *((uint8_t **)out) = buff;
+ }
+
+ rad_assert(subcs_size);
+
+ /*
+ * Handle the multi subsection case (which is harder)
+ */
+ for (subcs = cf_section_find(cs, name, NULL), count = 0;
+ subcs;
+ subcs = cf_section_find_next(cs, subcs, name, NULL), count++);
+ /*
+ * Allocate an array to hold the subsections
+ */
+ MEM(array = talloc_array(ctx, uint8_t *, count));
- cf_item_add(cs, &(cc->item));
-}
+ /*
+ * Start parsing...
+ *
+ * Note, we allocate each subsection structure individually
+ * so that they can be used as talloc contexts and we can
+ * keep the talloc hierarchy clean.
+ */
+ for (subcs = cf_section_find(cs, name, NULL), i = 0;
+ subcs;
+ subcs = cf_section_find_next(cs, subcs, name, NULL), i++) {
+ uint8_t *buff;
-static void cf_include_add(CONF_SECTION *cs, char const *filename, CONF_INCLUDE_TYPE file_type)
-{
- CONF_INCLUDE *cc;
+ MEM(buff = talloc_zero_array(array, uint8_t, subcs_size));
+ array[i] = buff;
- cc = talloc_zero(cs, CONF_INCLUDE);
- cc->item.type = CONF_ITEM_INCLUDE;
- cc->item.parent = cs;
- cc->item.filename = cs->item.filename;
- cc->item.lineno = 0;
- cc->filename = talloc_typed_strdup(cc, filename);
- cc->file_type = file_type;
+ ret = cf_section_parse(buff, buff, subcs, subcs_vars);
+ if (ret < 0) {
+ talloc_free(array);
+ return ret;
+ }
+ }
- cf_item_add(cs, &(cc->item));
-}
-#endif
+ *((uint8_t ***)out) = array;
+ return 0;
+}
-/*
- * Read a part of the config file.
+/** Parse a configuration section into user-supplied variables
+ *
+ * @param[in] ctx to allocate any strings, or additional structures in.
+ * Usually the same as base, unless base is a nested struct.
+ * @param[out] base pointer to a struct to fill with data.
+ * @param[in] cs to parse.
+ * @param[in] variables mappings between struct fields and #CONF_ITEM s.
+ * @return
+ * - 0 on success.
+ * - -1 on general error.
+ * - -2 if a deprecated #CONF_ITEM was found.
*/
-static int cf_section_read(char const *filename, int *lineno, FILE *fp,
- CONF_SECTION *current, char *buff[7])
-
+int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs, CONF_PARSER const *variables)
{
- CONF_SECTION *this, *css;
- CONF_PAIR *cpn;
- char const *ptr;
- char const *value;
-#ifdef WITH_CONF_WRITE
- char const *orig_value = NULL;
-#endif
+ int ret = 0;
+ int i;
+ void *data;
+ bool *is_set = NULL;
- FR_TOKEN t1 = T_INVALID, t2, t3;
- bool has_spaces = false;
- bool pass2;
- char *cbuff;
- size_t len;
+ /*
+ * Hack for partially parsed sections.
+ */
+ if (!variables) {
+ cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
+ return 0;
+ }
- this = current; /* add items here */
+ cs->variables = variables; /* this doesn't hurt anything */
- cbuff = buff[0];
+ if (!cs->name2) {
+ cf_log_info(cs, "%.*s%s {", cs->depth, parse_spaces, cs->name1);
+ } else {
+ cf_log_info(cs, "%.*s%s %s {", cs->depth, parse_spaces, cs->name1, cs->name2);
+ }
+
+ if (cf_section_parse_init(cs, base, variables) < 0) return -1;
/*
- * Read, checking for line continuations ('\\' at EOL)
+ * Handle the known configuration parameters.
*/
- for (;;) {
- int at_eof;
- css = NULL;
-
+ for (i = 0; variables[i].name != NULL; i++) {
/*
- * Get data, and remember if we are at EOF.
+ * Handle subsections specially
*/
- at_eof = (fgets(cbuff, talloc_array_length(buff[0]) - (cbuff - buff[0]), fp) == NULL);
- (*lineno)++;
+ if (FR_BASE_TYPE(variables[i].type) == FR_TYPE_SUBSECTION) {
+ if (cf_subsection_parse(ctx, (uint8_t *)base + variables[i].offset, cs,
+ variables[i].name, variables[i].type,
+ variables[i].subcs, variables[i].subcs_size) < 0) goto finish;
+ continue;
+ } /* else it's a CONF_PAIR */
+
+ if (variables[i].data) {
+ data = variables[i].data; /* prefer this. */
+ } else if (base) {
+ data = ((uint8_t *)base) + variables[i].offset;
+ } else if (!rad_cond_assert(0)) {
+ ret = -1;
+ goto finish;
+ }
/*
- * We read the entire 8k worth of data: complain.
- * Note that we don't care if the last character
- * is \n: it's still forbidden. This means that
- * the maximum allowed length of text is 8k-1, which
- * should be plenty.
+ * Get pointer to where we need to write out
+ * whether the pointer was set.
*/
- len = strlen(cbuff);
- if ((cbuff + len + 1) >= (buff[0] + talloc_array_length(buff[0]))) {
- ERROR("%s[%d]: Line too long", filename, *lineno);
- error:
- return -1;
+ if (variables[i].type & FR_TYPE_IS_SET) {
+ is_set = variables[i].data ? variables[i].is_set_ptr :
+ ((uint8_t *)base) + variables[i].is_set_offset;
}
- if (has_spaces) {
- ptr = cbuff;
- while (isspace((int) *ptr)) ptr++;
+ /*
+ * Parse the pair we found, or a default value.
+ */
+ ret = cf_pair_parse(ctx, cs, variables[i].name, variables[i].type, data,
+ variables[i].dflt, variables[i].quote);
+ switch (ret) {
+ case 1: /* Used default (or not present) */
+ if (is_set) *is_set = false;
+ ret = 0;
+ break;
- if (ptr > cbuff) {
- memmove(cbuff, ptr, len - (ptr - cbuff));
- len -= (ptr - cbuff);
+ case 0: /* OK */
+ if (is_set) *is_set = true;
+ break;
+
+ case -1: /* Parse error */
+ goto finish;
+
+ case -2: /* Deprecated CONF ITEM */
+ if ((variables[i + 1].offset && (variables[i + 1].offset == variables[i].offset)) ||
+ (variables[i + 1].data && (variables[i + 1].data == variables[i].data))) {
+ cf_log_err(&(cs->item), "Replace \"%s\" with \"%s\"", variables[i].name,
+ variables[i + 1].name);
}
+ goto finish;
}
+ } /* for all variables in the configuration section */
- /*
- * Not doing continuations: check for edge
- * conditions.
- */
- if (cbuff == buff[0]) {
- if (at_eof) break;
+ /*
+ * Ensure we have a proper terminator, type so we catch
+ * missing terminators reliably
+ */
+ rad_cond_assert(variables[i].type == conf_term.type);
- ptr = buff[0];
- while (*ptr && isspace((int) *ptr)) ptr++;
+ cs->base = base;
-#ifdef WITH_CONF_WRITE
- /*
- * This is where all of the comments are handled
- */
- if (*ptr == '#') {
- cf_comment_add(this, *lineno, ptr + 1);
- }
-#endif
+ /*
+ * Hack for partially parsed sections. We don't print
+ * out the final "}", that will be printed out when the
+ * caller re-calls us with 'variable=NULL'. And, we don't warn about unused
+ */
+ if (variables[i].offset == 1) return ret;
- if (!*ptr || (*ptr == '#')) continue;
+ /*
+ * Warn about items in the configuration which weren't
+ * checked during parsing.
+ */
+ if (rad_debug_lvl >= 3) cf_section_parse_warn(cs);
- } else if (at_eof || (len == 0)) {
- ERROR("%s[%d]: Continuation at EOF is illegal", filename, *lineno);
- goto error;
- }
+ cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
- /*
- * See if there's a continuation.
- */
- while ((len > 0) &&
- ((cbuff[len - 1] == '\n') || (cbuff[len - 1] == '\r'))) {
- len--;
- cbuff[len] = '\0';
- }
+finish:
+ return ret;
+}
- if ((len > 0) && (cbuff[len - 1] == '\\')) {
- /*
- * Check for "suppress spaces" magic.
- */
- if (!has_spaces && (len > 2) && (cbuff[len - 2] == '"')) {
- has_spaces = true;
- }
+/** Fixup xlat expansions and attributes
+ *
+ * @note Despite the name, this is really the second phase of #cf_pair_parse.
+ *
+ * @param[out] base start of structure to write #vp_tmpl_t s to.
+ * @param[in] cs CONF_SECTION to fixup.
+ * @param[in] variables Array of CONF_PARSER structs to process.
+ * @return
+ * - 0 on success.
+ * - -1 on failure (parse errors etc...).
+ */
+int cf_section_parse_pass2(void *base, CONF_SECTION *cs, CONF_PARSER const variables[])
+{
- cbuff[len - 1] = '\0';
- cbuff += len - 1;
- continue;
- }
+ int i;
- ptr = cbuff = buff[0];
- has_spaces = false;
+ /*
+ * Handle the known configuration parameters.
+ */
+ for (i = 0; variables[i].name != NULL; i++) {
+ bool attribute, multi, is_tmpl, is_xlat;
+ CONF_PAIR *cp;
+ void *data;
- get_more:
- pass2 = false;
+ char const *name = variables[i].name;
+ int type = variables[i].type;
+
+ is_tmpl = (type & FR_TYPE_TMPL);
+ is_xlat = (type & FR_TYPE_XLAT);
+ attribute = (type & FR_TYPE_ATTRIBUTE);
+ multi = (type & FR_TYPE_MULTI);
+
+ type = FR_BASE_TYPE(type); /* normal types are small */
/*
- * The parser is getting to be evil.
+ * It's a section, recurse!
*/
- while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
-
- if (((ptr[0] == '%') && (ptr[1] == '{')) ||
- (ptr[0] == '`')) {
- ssize_t slen;
-
- if (ptr[0] == '%') {
- slen = rad_copy_variable(buff[1], ptr);
- } else {
- slen = rad_copy_string(buff[1], ptr);
- }
- if (slen <= 0) {
- char *spaces, *text;
-
- fr_canonicalize_error(current, &spaces, &text, slen, ptr);
+ if (type == FR_TYPE_SUBSECTION) {
+ uint8_t *subcs_base;
+ CONF_SECTION *subcs = cf_section_find(cs, name, NULL);
- ERROR("%s[%d]: %s", filename, *lineno, text);
- ERROR("%s[%d]: %s^ Invalid expansion", filename, *lineno, spaces);
+ /*
+ * Select base by whether this is a nested struct,
+ * or a pointer to another struct.
+ */
+ if (!base) {
+ subcs_base = NULL;
+ } else if (multi) {
+ size_t j, len;
+ uint8_t **array;
- talloc_free(spaces);
- talloc_free(text);
+ array = (uint8_t **)((uint8_t *)base) + variables[i].offset;
+ len = talloc_array_length(array);
- goto error;
+ for (j = 0; j < len; j++) {
+ if (cf_section_parse_pass2(array[j], subcs,
+ (CONF_PARSER const *)variables[i].dflt) < 0) {
+ return -1;
+ }
+ }
+ continue;
+ } else if (variables[i].subcs_size) {
+ subcs_base = (*(uint8_t **)((uint8_t *)base) + variables[i].offset);
+ } else {
+ subcs_base = (uint8_t *)base + variables[i].offset;
}
- ptr += slen;
-
- t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), true);
- switch (t2) {
- case T_HASH:
- case T_EOL:
- goto do_bare_word;
+ if (cf_section_parse_pass2(subcs_base, subcs,
+ (CONF_PARSER const *)variables[i].dflt) < 0) return -1;
- default:
- ERROR("%s[%d]: Invalid expansion: %s", filename, *lineno, ptr);
- goto error;
- }
- } else {
- t1 = gettoken(&ptr, buff[1], talloc_array_length(buff[1]), true);
+ continue;
}
/*
- * The caller eats "name1 name2 {", and calls us
- * for the data inside of the section. So if we
- * receive a closing brace, then it must mean the
- * end of the section.
+ * Find the CONF_PAIR, may still not exist if there was
+ * no default set for the CONF_PARSER.
*/
- if (t1 == T_RCBRACE) {
- if (this == current) {
- ERROR("%s[%d]: Too many closing braces", filename, *lineno);
- goto error;
- }
+ cp = cf_pair_find(cs, name);
+ if (!cp) continue;
- /*
- * Merge the template into the existing
- * section. This uses more memory, but
- * means that templates now work with
- * sub-sections, etc.
- */
- if (!cf_template_merge(this, this->template)) goto error;
+ /*
+ * Figure out which data we need to fix.
+ */
+ data = variables[i].data; /* prefer this. */
+ if (!data && base) data = ((char *)base) + variables[i].offset;
+ if (!data) continue;
- this = cf_item_to_section(this->item.parent);
- goto check_for_more;
- }
+ /*
+ * Non-xlat expansions shouldn't have xlat!
+ */
+ if (!is_xlat && !is_tmpl) {
+ /*
+ * Ignore %{... in shared secrets.
+ * They're never dynamically expanded.
+ */
+ if ((variables[i].type & FR_TYPE_SECRET) != 0) continue;
- if (t1 != T_BARE_WORD) goto skip_keywords;
+ if (strstr(cp->value, "%{") != NULL) {
+ cf_log_err(&cp->item, "Found dynamic expansion in string which "
+ "will not be dynamically expanded");
+ return -1;
+ }
+ continue;
+ }
/*
- * Allow for $INCLUDE files
+ * Parse (and throw away) the xlat string (for validation).
*
- * This *SHOULD* work for any level include.
- * I really really really hate this file. -cparker
+ * FIXME: All of these should be converted from FR_TYPE_XLAT
+ * to FR_TYPE_TMPL.
*/
- if ((strcasecmp(buff[1], "$INCLUDE") == 0) ||
- (strcasecmp(buff[1], "$-INCLUDE") == 0)) {
- bool relative = true;
+ if (is_xlat) {
+ char const *error;
+ ssize_t slen;
+ char *value;
+ xlat_exp_t *xlat;
- t2 = getword(&ptr, buff[2], talloc_array_length(buff[2]), true);
- if (t2 != T_EOL) {
- ERROR("%s[%d]: Unexpected text after $INCLUDE", filename, *lineno);
- goto error;
- }
+ redo:
+ xlat = NULL;
- if (buff[2][0] == '$') relative = false;
+ /*
+ * xlat expansions should be parseable.
+ */
+ value = talloc_strdup(cs, cp->value); /* modified by xlat_tokenize */
+ slen = xlat_tokenize(cs, value, &xlat, &error);
+ if (slen < 0) {
+ char *spaces, *text;
- value = cf_expand_variables(filename, lineno, this, buff[4], talloc_array_length(buff[4]),
- buff[2], NULL);
- if (!value) goto error;
+ fr_canonicalize_error(cs, &spaces, &text, slen, cp->value);
- if (!FR_DIR_IS_RELATIVE(value)) relative = false;
+ cf_log_err(cp, "Failed parsing expanded string:");
+ cf_log_err(cp, "%s", text);
+ cf_log_err(cp, "%s^ %s", spaces, error);
- if (relative) {
- value = cf_local_file(filename, value, buff[3], talloc_array_length(buff[3]));
- if (!value) {
- ERROR("%s[%d]: Directories too deep", filename, *lineno);
- goto error;
- }
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(value);
+ talloc_free(xlat);
+ return -1;
}
+ talloc_free(value);
+ talloc_free(xlat);
-#ifdef HAVE_DIRENT_H
/*
- * $INCLUDE foo/
- *
- * Include ALL non-"dot" files in the directory.
- * careful!
+ * If the "multi" flag is set, check all of them.
*/
- if (value[strlen(value) - 1] == '/') {
- DIR *dir;
- struct dirent *dp;
- struct stat stat_buf;
- char *my_directory;
-
- my_directory = talloc_strdup(this, value);
-
- DEBUG2("including files in directory %s", my_directory);
-
-#ifdef WITH_CONF_WRITE
- /*
- * We print this out, but don't
- * actually open a file based on
- * it.
- */
- cf_include_add(this, my_directory, CONF_INCLUDE_DIR);
-#endif
-
-#ifdef S_IWOTH
- /*
- * Security checks.
- */
- if (stat(my_directory, &stat_buf) < 0) {
- ERROR("%s[%d]: Failed reading directory %s: %s",
- filename, *lineno,
- my_directory, fr_syserror(errno));
- talloc_free(my_directory);
- goto error;
- }
-
- if ((stat_buf.st_mode & S_IWOTH) != 0) {
- ERROR("%s[%d]: Directory %s is globally writable. Refusing to start due to "
- "insecure configuration", filename, *lineno, my_directory);
- talloc_free(my_directory);
- goto error;
- }
-#endif
- dir = opendir(my_directory);
- if (!dir) {
- ERROR("%s[%d]: Error reading directory %s: %s",
- filename, *lineno, value,
- fr_syserror(errno));
- talloc_free(my_directory);
- goto error;
- }
+ if (multi) {
+ cp = cf_pair_find_next(cs, cp, cp->attr);
+ if (cp) goto redo;
+ }
+ continue;
- /*
- * Read the directory, ignoring "." files.
- */
- while ((dp = readdir(dir)) != NULL) {
- char const *p;
+ /*
+ * Parse the pair into a template
+ */
+ } else if (is_tmpl) {
+ ssize_t slen;
- if (dp->d_name[0] == '.') continue;
+ vp_tmpl_t **out = (vp_tmpl_t **)data;
+ vp_tmpl_t *vpt;
- /*
- * Check for valid characters
- */
- for (p = dp->d_name; *p != '\0'; p++) {
- if (isalpha((int)*p) ||
- isdigit((int)*p) ||
- (*p == '-') ||
- (*p == '_') ||
- (*p == '.')) continue;
- break;
- }
- if (*p != '\0') continue;
+ slen = tmpl_afrom_str(cs, &vpt, cp->value, talloc_array_length(cp->value) - 1,
+ cf_pair_value_quote(cp),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) {
+ char *spaces, *text;
+ fr_canonicalize_error(vpt, &spaces, &text, slen, cp->value);
- snprintf(buff[2], talloc_array_length(buff[2]), "%s%s",
- my_directory, dp->d_name);
- if ((stat(buff[2], &stat_buf) != 0) ||
- S_ISDIR(stat_buf.st_mode)) continue;
+ cf_log_err(cp, "%s", text);
+ cf_log_err(cp, "%s^ %s", spaces, fr_strerror());
- /*
- * Read the file into the current
- * configuration section.
- */
- if (cf_file_include(this, buff[2], CONF_INCLUDE_FROMDIR, buff) < 0) {
- closedir(dir);
- goto error;
- }
- }
- closedir(dir);
- talloc_free(my_directory);
+ talloc_free(spaces);
+ talloc_free(text);
+ return -1;
+ }
- } else
-#endif
- { /* it was a normal file */
- if (buff[1][1] == '-') {
- struct stat statbuf;
+ if (attribute && (vpt->type != TMPL_TYPE_ATTR)) {
+ cf_log_err(&cp->item, "Expected attr got %s",
+ fr_int2str(tmpl_names, vpt->type, "???"));
+ return -1;
+ }
- if (stat(value, &statbuf) < 0) {
- WARN("Not including file %s: %s", value, fr_syserror(errno));
- continue;
- }
- }
+ switch (vpt->type) {
+ /*
+ * All attributes should have been defined by this point.
+ */
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ talloc_free(vpt);
+ cf_log_err(&cp->item, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
+ return -1;
- if (cf_file_include(this, value, CONF_INCLUDE_FILE, buff) < 0) goto error;
+ case TMPL_TYPE_UNPARSED:
+ case TMPL_TYPE_ATTR:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_DATA:
+ case TMPL_TYPE_EXEC:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ break;
+
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_REGEX_STRUCT:
+ case TMPL_TYPE_NULL:
+ rad_assert(0);
+ /* Don't add default */
}
- continue;
- } /* we were in an include */
- if (strcasecmp(buff[1], "$template") == 0) {
- CONF_ITEM *ci;
- CONF_SECTION *parentcs, *templatecs;
- t2 = getword(&ptr, buff[2], talloc_array_length(buff[2]), true);
+ /*
+ * Free the old value if we're overwriting
+ */
+ TALLOC_FREE(*out);
+ *(vp_tmpl_t **)out = vpt;
+ }
+ } /* for all variables in the configuration section */
- if (t2 != T_EOL) {
- ERROR("%s[%d]: Unexpected text after $TEMPLATE", filename, *lineno);
- goto error;
- }
+ return 0;
+}
- parentcs = cf_top_section(current);
+const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs)
+{
+ if (!cs) return NULL;
- templatecs = cf_subsection_find(parentcs, "templates");
- if (!templatecs) {
- ERROR("%s[%d]: No \"templates\" section for reference \"%s\"", filename, *lineno, buff[2]);
- goto error;
- }
+ return cs->variables;
+}
- ci = cf_reference_item(parentcs, templatecs, buff[2]);
- if (!ci || (ci->type != CONF_ITEM_SECTION)) {
- ERROR("%s[%d]: Reference \"%s\" not found", filename, *lineno, buff[2]);
- goto error;
- }
+CONF_ITEM *cf_reference_item(CONF_SECTION const *parent_cs,
+ CONF_SECTION const *outer_cs,
+ char const *ptr)
+{
+ CONF_PAIR *cp;
+ CONF_SECTION *next;
+ CONF_SECTION const *cs = outer_cs;
+ char name[8192];
+ char *p;
- if (!this) {
- ERROR("%s[%d]: Internal sanity check error in template reference", filename, *lineno);
- goto error;
- }
+ if (!cs) goto no_such_item;
- if (this->template) {
- ERROR("%s[%d]: Section already has a template", filename, *lineno);
- goto error;
- }
+ strlcpy(name, ptr, sizeof(name));
- this->template = cf_item_to_section(ci);
- continue;
- }
+ p = name;
+
+ /*
+ * ".foo" means "foo from the current section"
+ */
+ if (*p == '.') {
+ p++;
/*
- * Ensure that the user can't add CONF_PAIRs
- * with 'internal' names;
+ * Just '.' means the current section
*/
- if (buff[1][0] == '_') {
- ERROR("%s[%d]: Illegal configuration pair name \"%s\"", filename, *lineno, buff[1]);
- goto error;
- }
+ if (*p == '\0') return cf_section_to_item(cs);
/*
- * Handle if/elsif specially.
+ * ..foo means "foo from the section
+ * enclosing this section" (etc.)
*/
- if ((strcmp(buff[1], "if") == 0) || (strcmp(buff[1], "elsif") == 0)) {
- ssize_t slen;
- char const *error = NULL;
- char *p;
- fr_cond_t *cond = NULL;
-
- if (invalid_location(this, buff[1], filename, *lineno)) goto error;
+ while (*p == '.') {
+ if (cs->item.parent) cs = cf_item_to_section(cs->item.parent);
/*
- * Skip (...) to find the {
+ * .. means the section
+ * enclosing this section
*/
- slen = fr_cond_tokenize(this, cf_section_to_item(this), ptr, &cond,
- &error, FR_COND_TWO_PASS);
- memcpy(&p, &ptr, sizeof(p));
+ if (!*++p) return cf_section_to_item(cs);
+ }
- if (slen < 0) {
- if (p[-slen] != '{') goto cond_error;
- slen = -slen;
- }
- TALLOC_FREE(cond);
+ /*
+ * "foo.bar.baz" means "from the root"
+ */
+ } else if (strchr(p, '.') != NULL) {
+ if (!parent_cs) goto no_such_item;
+ cs = parent_cs;
+ }
- /*
- * This hack is so that the NEXT stage
- * doesn't go "too far" in expanding the
- * variable. We can parse the conditions
- * without expanding the ${...} stuff.
- * BUT we don't want to expand all of the
- * stuff AFTER the condition. So we do
- * two passes.
- *
- * The first pass is to discover the end
- * of the condition. We then expand THAT
- * string, and do a second pass parsing
- * the expanded condition.
- */
- p += slen;
- *p = '\0';
+ while (*p) {
+ char *q, *r;
+
+ r = strchr(p, '[');
+ q = strchr(p, '.');
+ if (!r && !q) break;
+
+ if (r && q > r) q = NULL;
+ if (q && q < r) r = NULL;
+
+ /*
+ * Split off name2.
+ */
+ if (r) {
+ q = strchr(r + 1, ']');
+ if (!q) return NULL; /* parse error */
/*
- * Nuke trailing spaces. This hack
- * really belongs in the parser.
+ * Points to foo[bar]xx: parse error,
+ * it should be foo[bar] or foo[bar].baz
*/
- while ((p > ptr) && (isspace((int) p[-1]))) {
- p--;
- *p = '\0';
- }
+ if (q[1] && q[1] != '.') goto no_such_item;
+
+ *r = '\0';
+ *q = '\0';
+ next = cf_section_find(cs, p, r + 1);
+ *r = '[';
+ *q = ']';
/*
- * If there's a ${...}. If so, expand it.
+ * Points to a named instance of a section.
*/
- if (strchr(ptr, '$') != NULL) {
- ptr = cf_expand_variables(filename, lineno,
- this,
- buff[3], talloc_array_length(buff[3]),
- ptr, NULL);
- if (!ptr) {
- ERROR("%s[%d]: Parse error expanding ${...} in condition",
- filename, *lineno);
- goto error;
- }
- } /* else leave it alone */
-
- css = cf_section_alloc(this, buff[1], ptr);
- if (!css) {
- ERROR("%s[%d]: Failed allocating memory for section", filename, *lineno);
- goto error;
+ if (!q[1]) {
+ if (!next) goto no_such_item;
+ return &(next->item);
}
- css->item.filename = filename;
- css->item.lineno = *lineno;
- slen = fr_cond_tokenize(css, cf_section_to_item(css), ptr, &cond,
- &error, FR_COND_TWO_PASS);
- *p = '{'; /* put it back */
+ q++; /* ensure we skip the ']' and '.' */
- cond_error:
- if (slen < 0) {
- char *spaces, *text;
+ } else {
+ *q = '\0';
+ next = cf_section_find(cs, p, NULL);
+ *q = '.';
+ }
- fr_canonicalize_error(this, &spaces, &text, slen, ptr);
+ if (!next) break; /* it MAY be a pair in this section! */
- ERROR("%s[%d]: Parse error in condition",
- filename, *lineno);
- ERROR("%s[%d]: %s", filename, *lineno, text);
- ERROR("%s[%d]: %s^ %s", filename, *lineno, spaces, error);
+ cs = next;
+ p = q + 1;
+ }
- talloc_free(spaces);
- talloc_free(text);
- talloc_free(css);
- goto error;
- }
+ if (!*p) goto no_such_item;
- if ((size_t) slen >= (talloc_array_length(buff[2]) - 1)) {
- talloc_free(css);
- ERROR("%s[%d]: Condition is too large after \"%s\"", filename, *lineno, buff[1]);
- goto error;
- }
+ retry:
+ /*
+ * Find it in the current referenced
+ * section.
+ */
+ cp = cf_pair_find(cs, p);
+ if (cp) {
+ cp->parsed = true; /* conf pairs which are referenced count as parsed */
+ return &(cp->item);
+ }
- /*
- * Copy the expanded and parsed condition
- * into buff[2]. Then, parse the text after
- * the condition, which now MUST be a '{.
- *
- * If it wasn't '{' it would have been
- * caught in the first pass of
- * conditional parsing, above.
- */
- memcpy(buff[2], ptr, slen);
- buff[2][slen] = '\0';
- ptr = p;
+ next = cf_section_find(cs, p, NULL);
+ if (next) return &(next->item);
+
+ /*
+ * "foo" is "in the current section, OR in main".
+ */
+ if ((p == name) && (parent_cs != NULL) && (cs != parent_cs)) {
+ cs = parent_cs;
+ goto retry;
+ }
- if ((t3 = gettoken(&ptr, buff[3], talloc_array_length(buff[3]), true)) != T_LCBRACE) {
- talloc_free(css);
- ERROR("%s[%d]: Expected '{' %d", filename, *lineno, t3);
- goto error;
- }
+no_such_item:
+ return NULL;
+}
- /*
- * Swap the condition with trailing stuff for
- * the final condition.
- */
- memcpy(&p, &css->name2, sizeof(css->name2));
- talloc_free(p);
- css->name2 = talloc_typed_strdup(css, buff[2]);
+/** Return the next child that's of the specified type
+ *
+ * @param[in] parent to return children from.
+ * @param[in] prev child to start searching from.
+ * @param[in] type to search for.
+ * @return
+ * - The next #CONF_ITEM that's a child of ci matching type.
+ * - NULL if no #CONF_ITEM matches that criteria.
+ */
+static CONF_ITEM *cf_next(CONF_ITEM const *parent, CONF_ITEM const *prev, CONF_ITEM_TYPE type)
+{
+ CONF_ITEM *ci;
- cf_data_add(css, cond, NULL, false);
+ for (ci = prev ? prev->next : parent->child;
+ ci;
+ ci = ci->next) {
+ if (ci->type == type) return ci;
+ }
- add_section:
- cf_item_add(this, &(css->item));
+ return NULL;
+}
- /*
- * The current section is now the child section.
- */
- this = css;
- css = NULL;
- goto check_for_more;
- }
+/** Return the next child that's of the specified type with the specified identifiers
+ *
+ * @param[in] parent The section we're searching in.
+ * @param[in] type of #CONF_ITEM we're searching for.
+ * @param[in] ident1 The first identifier.
+ * @param[in] ident2 The second identifier. Special value CF_IDENT_ANY
+ * can be used to match any ident2 value.
+ * @return
+ * - The first matching item.
+ * - NULL if no items matched.
+ */
+static CONF_ITEM *cf_find(CONF_ITEM const *parent, CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
+{
+ CONF_SECTION cs_find;
+ CONF_PAIR cp_find;
+ CONF_DATA cd_find;
+ CONF_ITEM *find;
- /*
- * "map" sections have three arguments!
- */
- if (strcmp(buff[1], "map") == 0) {
- char const *mod;
- char const *exp = NULL;
- char const *p;
+ if (!parent) return NULL;
+ if (!parent->child) return NULL; /* No children */
- t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), false);
+ if (!ident1) return cf_next(parent, NULL, type);
- if (invalid_location(this, buff[1], filename, *lineno)) {
- if (t2 != T_LCBRACE) {
- ERROR("%s[%d]: Invalid syntax for 'map'", filename, *lineno);
- goto error;
- }
+ switch (type) {
+ case CONF_ITEM_SECTION:
+ memset(&cs_find, 0, sizeof(cs_find));
+ cs_find.item.type = CONF_ITEM_SECTION;
+ cs_find.name1 = ident1;
+ if (ident2 != CF_IDENT_ANY) cs_find.name2 = ident2;
- goto alloc_section;
- }
+ find = (CONF_ITEM *)&cs_find;
+ break;
- if (t2 != T_BARE_WORD) {
- ERROR("%s[%d]: Expected module name after 'map'", filename, *lineno);
- goto error;
- }
+ case CONF_ITEM_PAIR:
+ rad_assert((ident2 == NULL) || (ident2 == CF_IDENT_ANY));
- mod = cf_expand_variables(filename, lineno,
- this,
- buff[3], talloc_array_length(buff[3]),
- buff[2], NULL);
- if (!mod) {
- ERROR("%s[%d]: Parse error expanding ${...} in map module name",
- filename, *lineno);
- goto error;
- }
+ memset(&cp_find, 0, sizeof(cp_find));
+ cp_find.item.type = CONF_ITEM_PAIR;
+ cp_find.attr = ident1;
- p = ptr;
- t3 = gettoken(&p, buff[4], talloc_array_length(buff[4]), false);
- if (fr_str_tok[t3]) {
- ptr = p;
+ find = (CONF_ITEM *)&cp_find;
+ break;
- exp = cf_expand_variables(filename, lineno,
- this,
- buff[5], talloc_array_length(buff[5]),
- buff[4], NULL);
- if (!exp) {
- ERROR("%s[%d]: Parse error expanding ${...} in map module name",
- filename, *lineno);
- goto error;
- }
- }
+ case CONF_ITEM_DATA:
+ memset(&cd_find, 0, sizeof(cd_find));
+ cd_find.item.type = CONF_ITEM_DATA;
+ cd_find.type = ident1;
+ if (ident2 != CF_IDENT_ANY) cd_find.name = ident2;
- if (gettoken(&ptr, buff[6], talloc_array_length(buff[6]), false) != T_LCBRACE) {
- ERROR("%s[%d]: Expecting section start brace '{' in 'map' definition",
- filename, *lineno);
- goto error;
- }
+ find = (CONF_ITEM *)&cd_find;
+ break;
- /*
- * Allocate the section
- */
- css = cf_section_alloc(this, buff[1], mod);
- if (!css) {
- ERROR("%s[%d]: Failed allocating memory for section", filename, *lineno);
- goto error;
- }
- css->item.filename = filename;
- css->item.lineno = *lineno;
- css->name2_type = T_BARE_WORD;
+ default:
+ rad_assert(0);
+ }
- css->argc = 0;
- if (exp) {
- css->argv = talloc_array(css, char const *, 1);
- css->argv[0] = talloc_typed_strdup(css->argv, exp);
- css->argv_type = talloc_array(css, FR_TOKEN, 1);
- css->argv_type[0] = t3;
- css->argc++;
- }
+ /*
+ * No ident1, iterate over the child list
+ */
+ if (ident1 == CF_IDENT_ANY) {
+ CONF_ITEM *ci;
- goto add_section;
- }
+ for (ci = parent->child;
+ ci && (cf_ident2_cmp(find, ci) != 0);
+ ci = ci->next);
- skip_keywords:
- /*
- * Grab the next token.
- */
- t2 = gettoken(&ptr, buff[2], talloc_array_length(buff[2]), false);
- switch (t2) {
- case T_HASH:
- case T_EOL:
- case T_COMMA:
- do_bare_word:
- t3 = t2;
- t2 = T_OP_EQ;
- value = NULL;
- goto do_set;
+ return ci;
+ }
- case T_OP_INCRM:
- case T_OP_ADD:
- case T_OP_SUB:
- case T_OP_NE:
- case T_OP_GE:
- case T_OP_GT:
- case T_OP_LE:
- case T_OP_LT:
- case T_OP_CMP_EQ:
- case T_OP_CMP_FALSE:
- if (!this || ((strcmp(this->name1, "update") != 0) && (strcmp(this->name1, "map") != 0))) {
- ERROR("%s[%d]: Invalid operator in assignment",
- filename, *lineno);
- goto error;
- }
- /* FALL-THROUGH */
+ /*
+ * No ident2, use the ident1 tree.
+ */
+ if (ident2 == CF_IDENT_ANY) return rbtree_finddata(parent->ident1, find);
- case T_OP_EQ:
- case T_OP_SET:
- while (isspace((int) *ptr)) ptr++;
+ /*
+ * Both ident1 and ident2 use the ident2 tree.
+ */
+ return rbtree_finddata(parent->ident2, find);
+}
- /*
- * New parser: non-quoted strings are
- * bare words, and we parse everything
- * until the next newline, or the next
- * comma. If they have { or } in a bare
- * word, well... too bad.
- */
- switch (*ptr) {
- case '"':
- case '\'':
- case '`':
- case '/':
- t3 = getstring(&ptr, buff[3], talloc_array_length(buff[3]), false);
- break;
+/** Return the next child that's of the specified type with the specified identifiers
+ *
+ * @param[in] parent The section we're searching in.
+ * @param[in] type of #CONF_ITEM we're searching for.
+ * @param[in] ident1 The first identifier.
+ * @param[in] ident2 The second identifier. Special value CF_IDENT_ANY
+ * can be used to match any ident2 value.
+ * @return
+ * - The first matching item.
+ * - NULL if no items matched.
+ */
+static CONF_ITEM *cf_find_next(CONF_ITEM const *parent, CONF_ITEM const *prev,
+ CONF_ITEM_TYPE type, char const *ident1, char const *ident2)
+{
+ CONF_SECTION cs_find;
+ CONF_PAIR cp_find;
+ CONF_DATA cd_find;
+ CONF_ITEM *find;
+ CONF_ITEM *ci;
- default:
- {
- const char *q = ptr;
+ if (!parent) return NULL;
- t3 = T_BARE_WORD;
- while (*q && (*q >= ' ') && (*q != ',') &&
- !isspace(*q)) q++;
+ if (!prev) {
+ if (!ident1) return cf_next(parent, NULL, type);
+ return cf_find(parent, type, ident1, ident2);
+ }
+ if (!ident1) return cf_next(parent, prev, type);
- if ((size_t) (q - ptr) >= talloc_array_length(buff[3])) {
- ERROR("%s[%d]: Parse error: value too long", filename, *lineno);
- goto error;
- }
+ switch (type) {
+ case CONF_ITEM_SECTION:
+ memset(&cs_find, 0, sizeof(cs_find));
+ cs_find.item.type = CONF_ITEM_SECTION;
+ cs_find.name1 = ident1;
+ if (ident2 != CF_IDENT_ANY) cs_find.name2 = ident2;
- memcpy(buff[3], ptr, (q - ptr));
- buff[3][q - ptr] = '\0';
- ptr = q;
- }
- }
+ find = (CONF_ITEM *)&cs_find;
+ break;
- if (t3 == T_INVALID) {
- ERROR("%s[%d]: Parse error: %s", filename, *lineno, fr_strerror());
- goto error;
- }
+ case CONF_ITEM_PAIR:
+ rad_assert((ident2 == NULL) || (ident2 == CF_IDENT_ANY));
- /*
- * Allow "foo" by itself, or "foo = bar"
- */
- switch (t3) {
- bool soft_fail;
+ memset(&cp_find, 0, sizeof(cp_find));
+ cp_find.item.type = CONF_ITEM_PAIR;
+ cp_find.attr = ident1;
- case T_BARE_WORD:
- case T_DOUBLE_QUOTED_STRING:
- case T_BACK_QUOTED_STRING:
-#ifdef WITH_CONF_WRITE
- orig_value = buff[3];
-#endif
- value = cf_expand_variables(filename, lineno, this, buff[4], talloc_array_length(buff[4]), buff[3], &soft_fail);
- if (!value) {
- if (!soft_fail) goto error;
+ find = (CONF_ITEM *)&cp_find;
+ break;
- /*
- * References an item which doesn't exist,
- * or which is already marked up as being
- * expanded in pass2. Wait for pass2 to
- * do the expansions.
- */
- pass2 = true;
- value = buff[3];
- }
- break;
+ case CONF_ITEM_DATA:
+ memset(&cd_find, 0, sizeof(cd_find));
+ cd_find.item.type = CONF_ITEM_DATA;
+ cd_find.type = ident1;
+ if (ident2 != CF_IDENT_ANY) cd_find.name = ident2;
- case T_HASH:
- case T_EOL:
- value = NULL;
- break;
+ find = (CONF_ITEM *)&cd_find;
+ break;
- default:
- value = buff[3];
- break;
- }
+ default:
+ rad_assert(0);
+ }
- /*
- * Add this CONF_PAIR to our CONF_SECTION
- */
- do_set:
- cpn = cf_pair_alloc(this, buff[1], value, t2, t1, t3);
- if (!cpn) goto error;
- cpn->item.filename = filename;
- cpn->item.lineno = *lineno;
- cpn->pass2 = pass2;
- cf_item_add(this, &(cpn->item));
+ if (ident1 == CF_IDENT_ANY) {
+ for (ci = prev->next;
+ ci && (cf_ident2_cmp(ci, find) != 0);
+ ci = ci->next);
-#ifdef WITH_CONF_WRITE
- if (orig_value) cpn->orig_value = talloc_typed_strdup(cpn, orig_value);
- orig_value = NULL;
-#endif
- /*
- * Require a comma, unless there's a comment.
- */
- while (isspace(*ptr)) ptr++;
+ return ci;
+ }
- if (*ptr == ',') {
- ptr++;
- break;
- }
+ if (ident2 == CF_IDENT_ANY) {
+ for (ci = prev->next;
+ ci && (_cf_ident1_cmp(ci, find) != 0);
+ ci = ci->next);
+
+ return ci;
+ }
+
+ for (ci = prev->next;
+ ci && (_cf_ident2_cmp(ci, find) != 0);
+ ci = ci->next);
+
+ return ci;
+}
- /*
- * module # stuff!
- * foo = bar # other stuff
- */
-#ifdef WITH_CONF_WRITE
- if (*ptr == '#') {
- t3 = T_HASH;
- ptr++;
- }
+/** Compare the first identifier of a child
+ *
+ * For CONF_ITEM_PAIR this is 'attr'.
+ * For CONF_ITEM_SECTION this is 'name1'.
+ * For CONF_ITEM_DATA this is 'type'.
+ *
+ * @param[in] a First CONF_ITEM to compare.
+ * @param[in] b Second CONF_ITEM to compare.
+ * @return
+ * - >0 if a > b.
+ * - <0 if a < b.
+ * - 0 if a == b.
+ */
+static inline int _cf_ident1_cmp(void const *a, void const *b)
+{
+ CONF_ITEM_TYPE type;
- /*
- * Allocate a CONF_COMMENT, and add it to the list of children.
- */
- if ((t3 == T_HASH) && (*ptr >= ' ')) {
- cf_comment_add(this, *lineno, ptr);
- }
-#endif
+ {
+ CONF_ITEM const *one = a;
+ CONF_ITEM const *two = b;
- if ((t3 == T_HASH) || (t3 == T_COMMA) || (t3 == T_EOL) || (*ptr == '#')) continue;
+ if (one->type > two->type) return +1;
+ if (one->type < two->type) return -1;
- if (!*ptr || (*ptr == '}')) break;
+ type = one->type;
+ }
- ERROR("%s[%d]: Syntax error: Expected comma after '%s': %s",
- filename, *lineno, value, ptr);
- goto error;
+ switch (type) {
+ case CONF_ITEM_PAIR:
+ {
+ CONF_PAIR const *one = a;
+ CONF_PAIR const *two = b;
- /*
- * No '=', must be a section or sub-section.
- */
- case T_BARE_WORD:
- case T_DOUBLE_QUOTED_STRING:
- case T_SINGLE_QUOTED_STRING:
- t3 = gettoken(&ptr, buff[3], talloc_array_length(buff[3]), true);
- if (t3 != T_LCBRACE) {
- ERROR("%s[%d]: Expecting section start brace '{' after \"%s %s\"",
- filename, *lineno, buff[1], buff[2]);
- goto error;
- }
- /* FALL-THROUGH */
+ return strcmp(one->attr, two->attr);
+ }
- alloc_section:
- case T_LCBRACE:
- css = cf_section_alloc(this, buff[1],
- t2 == T_LCBRACE ? NULL : buff[2]);
- if (!css) {
- ERROR("%s[%d]: Failed allocating memory for section",
- filename, *lineno);
- goto error;
- }
+ case CONF_ITEM_SECTION:
+ {
+ CONF_SECTION const *one = a;
+ CONF_SECTION const *two = b;
- css->item.filename = filename;
- css->item.lineno = *lineno;
- cf_item_add(this, &(css->item));
+ return strcmp(one->name1, two->name1);
+ }
- /*
- * There may not be a name2
- */
- css->name2_type = (t2 == T_LCBRACE) ? T_INVALID : t2;
+ case CONF_ITEM_DATA:
+ {
+ CONF_DATA const *one = a;
+ CONF_DATA const *two = b;
- /*
- * The current section is now the child section.
- */
- this = css;
- break;
+ return strcmp(one->type, two->type);
+ }
- case T_INVALID:
- ERROR("%s[%d]: Syntax error in '%s': %s", filename, *lineno, ptr, fr_strerror());
+ default:
+ rad_assert(0);
+ }
+}
- goto error;
+/** Compare only the second identifier of a child
+ *
+ * For CONF_ITEM_SECTION this is 'name2'.
+ * For CONF_ITEM_DATA this is 'name'.
+ *
+ * @param[in] a First CONF_ITEM to compare.
+ * @param[in] b Second CONF_ITEM to compare.
+ * @return
+ * - >0 if a > b.
+ * - <0 if a < b.
+ * - 0 if a == b.
+ */
+static inline int cf_ident2_cmp(void const *a, void const *b)
+{
+ CONF_ITEM const *ci = a;
- default:
- ERROR("%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
- filename, *lineno, buff[1], fr_int2str(fr_tokens_table, t2, "<INVALID>"));
+ switch (ci->type) {
+ case CONF_ITEM_PAIR:
+ return 0;
- goto error;
- }
+ case CONF_ITEM_SECTION:
+ {
+ CONF_SECTION const *one = a;
+ CONF_SECTION const *two = b;
- check_for_more:
- /*
- * Done parsing one thing. Skip to EOL if possible.
- */
- while (isspace(*ptr)) ptr++;
+ if (!two->name2 && one->name2) return +1;
+ if (two->name2 && !one->name2) return -1;
+ if (!two->name2 && !one->name2) return 0;
- if (*ptr == '#') continue;
+ return strcmp(one->name2, two->name2);
+ }
- if (*ptr) {
- goto get_more;
- }
+ case CONF_ITEM_DATA:
+ {
+ CONF_DATA const *one = a;
+ CONF_DATA const *two = b;
+
+ if (!two->name && one->name) return +1;
+ if (two->name && !one->name) return -1;
+ if (!two->name && !one->name) return 0;
+ return strcmp(one->name, two->name);
}
- /*
- * See if EOF was unexpected ..
- */
- if (feof(fp) && (this != current)) {
- ERROR("%s[%d]: EOF reached without closing brace for section %s starting at line %d",
- filename, *lineno, cf_section_name1(this), cf_section_lineno(this));
- goto error;
+ default:
+ rad_assert(0);
}
+}
- return 0;
+/** Compare the first and second identifiers of a child
+ *
+ * For CONF_ITEM_SECTION this is 'name2'.
+ * For CONF_ITEM_DATA this is 'name'.
+ *
+ * @param[in] a First CONF_ITEM to compare.
+ * @param[in] b Second CONF_ITEM to compare.
+ * @return
+ * - >0 if a > b.
+ * - <0 if a < b.
+ * - 0 if a == b.
+ */
+static int _cf_ident2_cmp(void const *a, void const *b)
+{
+ int ret;
+
+ ret = _cf_ident1_cmp(a, b);
+ if (ret != 0) return ret;
+
+ return cf_ident2_cmp(a, b);
}
-/*
- * Include one config file in another.
+/** Add a child
+ *
*/
-static int cf_file_include(CONF_SECTION *cs, char const *filename_in,
-#ifndef WITH_CONF_WRITE
- UNUSED
-#endif
- CONF_INCLUDE_TYPE file_type, char *buff[7])
+void _cf_item_add(CONF_ITEM *parent, CONF_ITEM *child)
{
- FILE *fp;
- int lineno = 0;
- char const *filename;
+ fr_cursor_t to_merge;
+ CONF_ITEM *ci;
+
+ rad_assert(parent != child);
+
+ if (!parent || !child) return;
/*
- * So we only need to do this once.
+ * New child, add child trees.
*/
- filename = talloc_strdup(cs, filename_in);
+ if (!parent->ident1) parent->ident1 = rbtree_create(parent, _cf_ident1_cmp, NULL, RBTREE_FLAG_NONE);
+ if (!parent->ident2) parent->ident2 = rbtree_create(parent, _cf_ident2_cmp, NULL, RBTREE_FLAG_NONE);
- DEBUG2("including configuration file %s", filename);
+ fr_cursor_init(&to_merge, &child);
- fp = cf_file_open(cs, filename);
- if (!fp) return -1;
+ for (ci = fr_cursor_head(&to_merge);
+ ci;
+ ci = fr_cursor_next(&to_merge)) {
+ rbtree_insert(parent->ident1, ci);
+ rbtree_insert(parent->ident2, ci); /* NULL ident2 is still a value */
+ fr_cursor_append(&parent->cursor, ci); /* Append to the list of children */
+ }
+}
- if (!cs->item.filename) cs->item.filename = filename;
+/** Remove item from parent and fixup trees
+ *
+ * @param[in] parent to remove child from.
+ * @param[in] child to remove.
+ * @return
+ * - The item removed.
+ * - NULL if the item wasn't set.
+ */
+static CONF_ITEM *cf_remove(CONF_ITEM *parent, CONF_ITEM *child)
+{
+ CONF_ITEM *found;
+ bool in_ident1, in_ident2;
-#ifdef WITH_CONF_WRITE
- /*
- * Instruct the parser that we've started to include a
- * file at this point.
- */
- cf_include_add(cs, filename, file_type);
-#endif
+ if (!parent || !parent->child) return NULL;
+ if (parent != child->parent) return NULL;
+
+ for (found = fr_cursor_head(&parent->cursor);
+ found && (child != found);
+ found = fr_cursor_next(&parent->cursor));
+
+ if (!found) return NULL;
/*
- * Read the section. It's OK to have EOF without a
- * matching close brace.
+ * Fixup the linked list
*/
- if (cf_section_read(filename, &lineno, fp, cs, buff) < 0) {
- fclose(fp);
- return -1;
+ found = fr_cursor_remove(&parent->cursor);
+ rad_assert(found == child);
+
+ in_ident1 = (rbtree_finddata(parent->ident1, child) == child);
+ if (in_ident1 && (!rbtree_deletebydata(parent->ident1, child))) {
+ rad_assert(0);
+ return NULL;
+ }
+
+ in_ident2 = (rbtree_finddata(parent->ident2, child) == child);
+ if (in_ident2 && (!rbtree_deletebydata(parent->ident2, child))) {
+ rad_assert(0);
+ return NULL;
}
-#ifdef WITH_CONF_WRITE
/*
- * Instruct the parser that we've finished including a
- * file at this point.
+ * Look for twins
*/
- cf_include_add(cs, NULL, file_type);
-#endif
+ for (found = fr_cursor_head(&parent->cursor);
+ found && (in_ident1 || in_ident2);
+ found = fr_cursor_next(&parent->cursor)) {
+ if (in_ident1 && (_cf_ident1_cmp(found, child) == 0)) {
+ rbtree_insert(parent->ident1, child);
+ in_ident1 = false;
+ }
- fclose(fp);
- return 0;
+ if (in_ident2 && (_cf_ident2_cmp(found, child) == 0)) {
+ rbtree_insert(parent->ident2, child);
+ in_ident2 = false;
+ }
+ }
+
+ return child;
+}
+
+/** Return the next child of cs
+ *
+ * @param[in] ci to return children from.
+ * @param[in] prev child to start searching from.
+ * @return
+ * - The next #CONF_ITEM that's a child of cs.
+ * - NULL if no more #CONF_ITEM.
+ */
+CONF_ITEM *_cf_item_next(CONF_ITEM const *ci, CONF_ITEM const *prev)
+{
+ return prev ? prev->next : ci->child;
+}
+
+CONF_SECTION *_cf_root(CONF_ITEM const *ci)
+{
+ CONF_ITEM const *ci_p;
+
+ if (!ci) return NULL;
+
+ for (ci_p = ci; ci_p->parent; ci_p = ci_p->parent);
+
+ return cf_item_to_section(ci_p);
+}
+
+CONF_ITEM *_cf_parent(CONF_ITEM const *ci)
+{
+ if (!ci) return NULL;
+
+ return ci->parent;
+}
+
+int _cf_lineno(CONF_ITEM const *ci)
+{
+ return ci->lineno;
+}
+
+char const *_cf_filename(CONF_ITEM const *ci)
+{
+ return ci->filename;
+}
+
+bool cf_item_is_section(CONF_ITEM const *ci)
+{
+ return ci->type == CONF_ITEM_SECTION;
+}
+
+bool cf_item_is_pair(CONF_ITEM const *ci)
+{
+ return ci->type == CONF_ITEM_PAIR;
+}
+
+bool cf_item_is_data(CONF_ITEM const *ci)
+{
+ return ci->type == CONF_ITEM_DATA;
+}
+
+/** Cast a CONF_ITEM to a CONF_PAIR
+ *
+ */
+CONF_PAIR *cf_item_to_pair(CONF_ITEM const *ci)
+{
+ CONF_PAIR *out;
+
+ if (ci == NULL) return NULL;
+
+ rad_assert(ci->type == CONF_ITEM_PAIR);
+
+ memcpy(&out, &ci, sizeof(out));
+ return out;
+}
+
+/** Cast a CONF_ITEM to a CONF_SECTION
+ *
+ */
+CONF_SECTION *cf_item_to_section(CONF_ITEM const *ci)
+{
+ CONF_SECTION *out;
+
+ if (ci == NULL) return NULL;
+
+ rad_assert(ci->type == CONF_ITEM_SECTION);
+
+ memcpy(&out, &ci, sizeof(out));
+ return out;
+}
+
+CONF_DATA *cf_item_to_data(CONF_ITEM const *ci)
+{
+ CONF_DATA *out;
+
+ if (ci == NULL) return NULL;
+
+ rad_assert(ci->type == CONF_ITEM_DATA);
+
+ memcpy(&out, &ci, sizeof(out));
+ return out;
}
+/** Cast a CONF_PAIR to a CONF_ITEM
+ *
+ */
+CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp)
+{
+ CONF_ITEM *out;
+
+ if (cp == NULL) return NULL;
+
+ memcpy(&out, &cp, sizeof(out));
+ return out;
+}
-/*
- * Do variable expansion in pass2.
+/** Cast a CONF_SECTION to a CONF_ITEM
*
- * This is a breadth-first expansion. "deep
*/
-static int cf_section_pass2(CONF_SECTION *cs)
+CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs)
{
- CONF_ITEM *ci;
-
- for (ci = cs->children; ci; ci = ci->next) {
- char const *value;
- CONF_PAIR *cp;
- char buffer[8192];
-
- if (ci->type != CONF_ITEM_PAIR) continue;
+ CONF_ITEM *out;
- cp = cf_item_to_pair(ci);
- if (!cp->value || !cp->pass2) continue;
+ if (cs == NULL) return NULL;
- rad_assert((cp->rhs_type == T_BARE_WORD) ||
- (cp->rhs_type == T_DOUBLE_QUOTED_STRING) ||
- (cp->rhs_type == T_BACK_QUOTED_STRING));
+ memcpy(&out, &cs, sizeof(out));
+ return out;
+}
- value = cf_expand_variables(ci->filename, &ci->lineno, cs, buffer, sizeof(buffer), cp->value, NULL);
- if (!value) return -1;
+/** Cast CONF_DATA to a CONF_ITEM
+ *
+ */
+CONF_ITEM *cf_data_to_item(CONF_DATA const *cd)
+{
+ CONF_ITEM *out;
- talloc_const_free(cp->value);
- cp->value = talloc_typed_strdup(cp, value);
- }
+ if (cd == NULL) return NULL;
- for (ci = cs->children; ci; ci = ci->next) {
- if (ci->type != CONF_ITEM_SECTION) continue;
+ memcpy(&out, &cd, sizeof(out));
+ return out;
+}
- if (cf_section_pass2(cf_item_to_section(ci)) < 0) return -1;
- }
+static int _cf_section_free(CONF_SECTION *cs)
+{
+ if (cs->item.ident1) TALLOC_FREE(cs->item.ident1);
+ if (cs->item.ident2) TALLOC_FREE(cs->item.ident2);
return 0;
}
-
-/*
- * Bootstrap a config file.
+/** Allocate a #CONF_SECTION
+ *
+ * @param parent #CONF_SECTION to hang this #CONF_SECTION off of.
+ * @param name1 Primary name.
+ * @param name2 Secondary name.
+ * @return
+ * - NULL on error.
+ * - A new #CONF_SECTION parented by parent.
*/
-int cf_file_read(CONF_SECTION *cs, char const *filename)
+CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
{
- int i;
- char *p;
- CONF_PAIR *cp;
- rbtree_t *tree;
- char **buff;
-
- cp = cf_pair_alloc(cs, "confdir", filename, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
- if (!cp) return -1;
+ CONF_SECTION *cs;
- p = strrchr(cp->value, FR_DIR_SEP);
- if (p) *p = '\0';
+ if (!name1) return NULL;
- cf_item_add(cs, &(cp->item));
+ if (name2 && parent) {
+ char buffer[1024];
- tree = rbtree_create(cs, filename_cmp, NULL, 0);
- if (!tree) return -1;
+ if (strchr(name2, '$')) {
+ name2 = cf_expand_variables(parent->item.filename,
+ &parent->item.lineno,
+ parent,
+ buffer, sizeof(buffer), name2, NULL);
+ if (!name2) {
+ ERROR("Failed expanding section name");
+ return NULL;
+ }
+ }
+ }
- cf_data_add(cs, tree, "filename", false);
+ cs = talloc_zero(parent, CONF_SECTION);
+ if (!cs) return NULL;
- /*
- * Allocate temporary buffers on the heap (so we don't use *all* the stack space)
- */
- buff = talloc_array(cs, char *, 7);
- for (i = 0; i < 7; i++) {
- buff[i] = talloc_array(buff, char, 8192);
- }
+ cs->item.type = CONF_ITEM_SECTION;
+ cs->item.parent = cf_section_to_item(parent);
+ fr_cursor_init(&cs->item.cursor, &cs->item.child);
- if (cf_file_include(cs, filename, CONF_INCLUDE_FILE, buff) < 0) {
- talloc_free(buff);
- return -1;
+ MEM(cs->name1 = talloc_typed_strdup(cs, name1));
+ if (name2) {
+ MEM(cs->name2 = talloc_typed_strdup(cs, name2));
+ cs->name2_quote = T_BARE_WORD;
}
+ talloc_set_destructor(cs, _cf_section_free);
- talloc_free(buff);
-
- /*
- * Now that we've read the file, go back through it and
- * expand the variables.
- */
- if (cf_section_pass2(cs) < 0) return -1;
+ if (parent) cs->depth = parent->depth + 1;
- return 0;
+ return cs;
}
-
-void cf_file_free(CONF_SECTION *cs)
+/** Duplicate a configuration section
+ *
+ * @note recursively duplicates any child sections.
+ * @note does not duplicate any data associated with a section, or its child sections.
+ *
+ * @param[in] parent section (may be NULL).
+ * @param[in] cs to duplicate.
+ * @param[in] name1 of new section.
+ * @param[in] name2 of new section.
+ * @param[in] copy_meta Copy additional meta data for a section
+ * (like template, base, depth and variables).
+ * @return
+ * - A duplicate of the existing section.
+ * - NULL on error.
+ */
+CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
+ char const *name1, char const *name2, bool copy_meta)
{
- talloc_free(cs);
-}
+ CONF_SECTION *new, *subcs;
+ CONF_PAIR *cp;
+ CONF_ITEM *ci;
+ fr_cursor_t cursor;
+ new = cf_section_alloc(parent, name1, name2);
-/*
- * Return a CONF_PAIR within a CONF_SECTION.
- */
-CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *name)
-{
- CONF_PAIR *cp, mycp;
+ if (copy_meta) {
+ new->template = cs->template;
+ new->base = cs->base;
+ new->depth = cs->depth;
+ new->variables = cs->variables;
+ }
+
+ new->item.lineno = cs->item.lineno;
+ new->item.filename = cs->item.filename;
+
+ fr_cursor_copy(&cursor, &cs->item.cursor); /* Mutable cursor */
+ for (ci = fr_cursor_head(&cursor);
+ ci;
+ ci = fr_cursor_next(&cursor)) {
+ switch (ci->type) {
+ case CONF_ITEM_SECTION:
+ subcs = cf_item_to_section(ci);
+ subcs = cf_section_dup(new, subcs,
+ cf_section_name1(subcs), cf_section_name2(subcs),
+ copy_meta);
+ if (!subcs) {
+ talloc_free(new);
+ return NULL;
+ }
+ cf_section_add(new, subcs);
+ break;
- if (!cs || !name) return NULL;
+ case CONF_ITEM_PAIR:
+ cp = cf_pair_dup(new, cf_item_to_pair(ci));
+ if (!cp) {
+ talloc_free(new);
+ return NULL;
+ }
+ cf_pair_add(new, cp);
+ break;
- mycp.attr = name;
- cp = rbtree_finddata(cs->pair_tree, &mycp);
- if (cp) return cp;
+ case CONF_ITEM_DATA: /* Skip data */
+#ifdef WITH_CONF_WRITE
+ case CONF_ITEM_COMMENT:
+ case CONF_ITEM_INCLUDE:
+#endif
+ break;
- if (!cs->template) return NULL;
+ case CONF_ITEM_INVALID:
+ rad_assert(0);
+ }
+ }
- return rbtree_finddata(cs->template->pair_tree, &mycp);
+ return new;
}
-/*
- * Return the attr of a CONF_PAIR
+/** Add a section as a child of another section
+ *
+ * @param[in] parent section we're adding to.
+ * @param[in] cs we're adding.
*/
-
-char const *cf_pair_attr(CONF_PAIR const *pair)
+void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs)
{
- return (pair ? pair->attr : NULL);
+ cf_item_add(parent, &(cs->item));
}
-/*
- * Return the value of a CONF_PAIR
+/** Return the next child that's a #CONF_SECTION
+ *
+ * @param[in] cs to return children from.
+ * @param[in] prev child to start searching from.
+ * @return
+ * - The next #CONF_ITEM that's a child of cs and a CONF_SECTION.
+ * - NULL if no #CONF_ITEM matches that criteria.
*/
-
-char const *cf_pair_value(CONF_PAIR const *pair)
+CONF_SECTION *cf_section_next(CONF_SECTION const *cs, CONF_SECTION const *prev)
{
- return (pair ? pair->value : NULL);
+ return cf_item_to_section(cf_next(cf_section_to_item(cs), cf_section_to_item(prev), CONF_ITEM_SECTION));
}
-FR_TOKEN cf_pair_operator(CONF_PAIR const *pair)
+/** Find a CONF_SECTION with name1 and optionally name2.
+ *
+ * @param[in] cs The section we're searching in.
+ * @param[in] name1 The first section identifier.
+ * @param[in] name2 The second section identifier. Special value CF_IDENT_ANY
+ * can be used to match any name2 value.
+ * @return
+ * - The first matching subsection.
+ * - NULL if no subsections match.
+ */
+CONF_SECTION *cf_section_find(CONF_SECTION const *cs,
+ char const *name1, char const *name2)
{
- return (pair ? pair->op : T_INVALID);
+ return cf_item_to_section(cf_find(cf_section_to_item(cs), CONF_ITEM_SECTION, name1, name2));
}
-/** Return the value (lhs) type
+/** Return the next matching section
*
- * @param pair to extract value type from.
+ * @param[in] cs The section we're searching in.
+ * @param[in] prev section we found. May be NULL in which case
+ * we just return the next section after prev.
+ * @param[in] name1 of the section we're searching for.
+ * @param[in] name2 of the section we're searching for. Special value CF_IDENT_ANY
+ * can be used to match any name2 value.
* @return
- * - #T_BARE_WORD.
- * - #T_SINGLE_QUOTED_STRING.
- * - #T_BACK_QUOTED_STRING.
- * - #T_DOUBLE_QUOTED_STRING.
- * - #T_INVALID if the pair is NULL.
+ * - The next CONF_SECTION.
+ * - NULL if there are no more CONF_SECTIONs
*/
-FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair)
+CONF_SECTION *cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev,
+ char const *name1, char const *name2)
{
- return (pair ? pair->lhs_type : T_INVALID);
+ return cf_item_to_section(cf_find_next(cf_section_to_item(cs), cf_section_to_item(prev),
+ CONF_ITEM_SECTION, name1, name2));
}
-/** Return the value (rhs) type
+/** Find a value in a CONF_SECTION
*
- * @param pair to extract value type from.
- * @return
- * - #T_BARE_WORD.
- * - #T_SINGLE_QUOTED_STRING.
- * - #T_BACK_QUOTED_STRING.
- * - #T_DOUBLE_QUOTED_STRING.
- * - #T_INVALID if the pair is NULL.
*/
-FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair)
+char const *cf_section_value_find(CONF_SECTION const *cs, char const *attr)
{
- return (pair ? pair->rhs_type : T_INVALID);
+ CONF_PAIR *cp;
+
+ cp = cf_pair_find(cs, attr);
+
+ return (cp ? cp->value : NULL);
}
-/*
- * Return the first label of a CONF_SECTION
+/** Return the first label of a CONF_SECTION
+ *
*/
-
char const *cf_section_name1(CONF_SECTION const *cs)
{
return (cs ? cs->name1 : NULL);
}
-/*
- * Return the second label of a CONF_SECTION
+/** Return the second label of a CONF_SECTION
+ *
*/
-
char const *cf_section_name2(CONF_SECTION const *cs)
{
return (cs ? cs->name2 : NULL);
return cf_section_name1(cs);
}
-char const *cf_section_argv(CONF_SECTION const *cs, int argc)
-{
- if (!cs || !cs->argv || (argc < 0) || (argc > cs->argc)) return NULL;
-
- return cs->argv[argc];
-}
-
-/*
- * Find a value in a CONF_SECTION
- */
-char const *cf_section_value_find(CONF_SECTION const *cs, char const *attr)
-{
- CONF_PAIR *cp;
-
- cp = cf_pair_find(cs, attr);
-
- return (cp ? cp->value : NULL);
-}
-
-
-CONF_SECTION *cf_section_find_name2(CONF_SECTION const *cs,
- char const *name1, char const *name2)
-{
- char const *their2;
- CONF_ITEM const *ci;
-
- if (!cs || !name1) return NULL;
-
- for (ci = &(cs->item); ci; ci = ci->next) {
- if (ci->type != CONF_ITEM_SECTION)
- continue;
-
- if (strcmp(cf_item_to_section(ci)->name1, name1) != 0) {
- continue;
- }
-
- their2 = cf_item_to_section(ci)->name2;
-
- if ((!name2 && !their2) ||
- (name2 && their2 && (strcmp(name2, their2) == 0))) {
- return cf_item_to_section(ci);
- }
- }
-
- return NULL;
-}
-
-/** Find a pair with a name matching attr, after specified pair.
- *
- * @param cs to search in.
- * @param pair to search from (may be NULL).
- * @param attr to find (may be NULL in which case any attribute matches).
- * @return the next matching #CONF_PAIR or NULL if none matched.
- */
-CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs,
- CONF_PAIR const *pair, char const *attr)
-{
- CONF_ITEM *ci;
-
- if (!cs) return NULL;
-
- /*
- * If pair is NULL and we're trying to find a specific
- * attribute this must be a first time run.
- *
- * Find the pair with correct name.
- */
- if (!pair && attr) return cf_pair_find(cs, attr);
-
- /*
- * Start searching from the next child, or from the head
- * of the list of children (if no pair was provided).
- */
- for (ci = pair ? pair->item.next : cs->children;
- ci;
- ci = ci->next) {
- if (ci->type != CONF_ITEM_PAIR) continue;
-
- if (!attr || strcmp(cf_item_to_pair(ci)->attr, attr) == 0) break;
- }
+char const *cf_section_argv(CONF_SECTION const *cs, int argc)
+{
+ if (!cs || !cs->argv || (argc < 0) || (argc > cs->argc)) return NULL;
- return cf_item_to_pair(ci);
+ return cs->argv[argc];
}
-/** Find a sub-section in a section
- *
- * This finds ANY section having the same first name.
- * The second name is ignored.
+/*
+ * For "switch" and "case" statements.
*/
-CONF_SECTION *cf_subsection_find(CONF_SECTION const *cs, char const *name)
+FR_TOKEN cf_section_name2_quote(CONF_SECTION const *cs)
{
- CONF_SECTION mycs;
+ if (!cs) return T_INVALID;
- if (!cs || !name) return NULL; /* can't find an un-named section */
+ return cs->name2_quote;
+}
- /*
- * No sub-sections have been defined, so none exist.
- */
- if (!cs->section_tree) return NULL;
+FR_TOKEN cf_section_argv_quote(CONF_SECTION const *cs, int argc)
+{
+ if (!cs || !cs->argv_quote || (argc < 0) || (argc > cs->argc)) return T_INVALID;
- mycs.name1 = name;
- mycs.name2 = NULL;
- return rbtree_finddata(cs->section_tree, &mycs);
+ return cs->argv_quote[argc];
}
-
-/** Find a CONF_SECTION with both names.
+/** Allocate a #CONF_PAIR
*
+ * @param[in] parent #CONF_SECTION to hang this #CONF_PAIR off of.
+ * @param[in] attr name.
+ * @param[in] value of #CONF_PAIR.
+ * @param[in] op #T_OP_EQ, #T_OP_SET etc.
+ * @param[in] lhs_quote #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
+ * @param[in] rhs_quote #T_BARE_WORD, #T_DOUBLE_QUOTED_STRING, #T_BACK_QUOTED_STRING.
+ * @return
+ * - NULL on error.
+ * - A new #CONF_SECTION parented by parent.
*/
-CONF_SECTION *cf_subsection_find_name2(CONF_SECTION const *cs,
- char const *name1, char const *name2)
+CONF_PAIR *cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
+ FR_TOKEN op, FR_TOKEN lhs_quote, FR_TOKEN rhs_quote)
{
- CONF_ITEM *ci;
-
- if (!cs) return NULL;
-
- if (name1) {
- CONF_SECTION mycs, *master_cs;
-
- if (!cs->section_tree) return NULL;
+ CONF_PAIR *cp;
- mycs.name1 = name1;
- mycs.name2 = name2;
+ rad_assert(fr_equality_op[op] || fr_assignment_op[op]);
+ if (!attr) return NULL;
- master_cs = rbtree_finddata(cs->section_tree, &mycs);
- if (!master_cs) return NULL;
+ cp = talloc_zero(parent, CONF_PAIR);
+ if (!cp) return NULL;
- /*
- * Look it up in the name2 tree. If it's there,
- * return it.
- */
- if (master_cs->name2_tree) {
- CONF_SECTION *subcs;
+ cp->item.type = CONF_ITEM_PAIR;
+ cp->item.parent = cf_section_to_item(parent);
+ cp->lhs_quote = lhs_quote;
+ cp->rhs_quote = rhs_quote;
+ cp->op = op;
+ cp->item.filename = "<internal>"; /* will be over-written if necessary */
+ fr_cursor_init(&cp->item.cursor, &cp->item.child);
- subcs = rbtree_finddata(master_cs->name2_tree, &mycs);
- if (subcs) return subcs;
- }
+ cp->attr = talloc_typed_strdup(cp, attr);
+ if (!cp->attr) {
+ error:
+ talloc_free(cp);
+ return NULL;
+ }
- /*
- * We don't insert ourselves into the name2 tree.
- * So if there's nothing in the name2 tree, maybe
- * *we* are the answer.
- */
- if (!master_cs->name2 && name2) return NULL;
- if (master_cs->name2 && !name2) return NULL;
- if (!master_cs->name2 && !name2) return master_cs;
+ if (value) {
+#ifdef WITH_CONF_WRITE
+ cp->orig_value = talloc_typed_strdup(cp, value);
+#endif
+ cp->value = talloc_typed_strdup(cp, value);
+ if (!cp->value) goto error;
+ }
- if (strcmp(master_cs->name2, name2) == 0) {
- return master_cs;
- }
+ return cp;
+}
- return NULL;
- }
+/** Duplicate a #CONF_PAIR
+ *
+ * @param parent to allocate new pair in.
+ * @param cp to duplicate.
+ * @return
+ * - NULL on error.
+ * - A duplicate of the input pair.
+ */
+CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp)
+{
+ CONF_PAIR *new;
- /*
- * Else do it the old-fashioned way.
- */
- for (ci = cs->children; ci; ci = ci->next) {
- CONF_SECTION *subcs;
+ rad_assert(parent);
+ rad_assert(cp);
- if (ci->type != CONF_ITEM_SECTION)
- continue;
+ new = cf_pair_alloc(parent, cp->attr, cf_pair_value(cp),
+ cp->op, cp->lhs_quote, cp->rhs_quote);
+ if (!new) return NULL;
- subcs = cf_item_to_section(ci);
- if (!subcs->name2) {
- if (strcmp(subcs->name1, name2) == 0) break;
- } else {
- if (strcmp(subcs->name2, name2) == 0) break;
- }
- }
+ new->parsed = cp->parsed;
+ new->item.lineno = cp->item.lineno;
+ new->item.filename = cp->item.filename;
- return cf_item_to_section(ci);
+ return new;
}
-/*
- * Return the next subsection after a CONF_SECTION
- * with a certain name1 (char *name1). If the requested
- * name1 is NULL, any name1 matches.
+/** Replace pair in a given section with a new pair, of the given value.
+ *
+ * @param[in] cs to replace pair in.
+ * @param[in] cp to replace.
+ * @param[in] value New value to assign to cp.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
*/
-
-CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
- CONF_SECTION const *subsection,
- char const *name1)
+int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
{
- CONF_ITEM *ci;
+ CONF_PAIR *new_cp;
+ CONF_ITEM *ci;
+
+ if (!cs || !cp || !value) return -1;
- if (!section) return NULL;
+ MEM(new_cp = cf_pair_alloc(cs, cp->attr, value, cp->op, cp->lhs_quote, cp->rhs_quote));
/*
- * If subsection is NULL this must be a first time run
- * Find the subsection with correct name
+ * Remove the old CONF_PAIR
*/
+ ci = cf_remove(cf_section_to_item(cs), cf_pair_to_item(cp));
+ rad_assert(!ci || (ci == cf_pair_to_item(cp)));
- if (!subsection) {
- ci = section->children;
- } else {
- ci = subsection->item.next;
- }
+ /*
+ * Add the new CONF_PAIR
+ */
+ cf_item_add(cf_section_to_item(cs), cf_pair_to_item(new_cp));
- for (; ci; ci = ci->next) {
- if (ci->type != CONF_ITEM_SECTION)
- continue;
- if ((name1 == NULL) ||
- (strcmp(cf_item_to_section(ci)->name1, name1) == 0))
- break;
- }
+ cp = cf_pair_find(cs, cp->attr);
+ rad_assert(cp == new_cp);
- return cf_item_to_section(ci);
-}
+ talloc_free(ci);
+ return 0;
+}
-/*
- * Return the next section after a CONF_SECTION
- * with a certain name1 (char *name1). If the requested
- * name1 is NULL, any name1 matches.
+/** Add a configuration pair to a section
+ *
+ * @param[in] parent section to add pair to.
+ * @param[in] cp to add.
*/
-
-CONF_SECTION *cf_section_find_next(CONF_SECTION const *section,
- CONF_SECTION const *subsection,
- char const *name1)
+void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp)
{
- if (!section) return NULL;
-
- if (!section->item.parent) return NULL;
+ cf_item_add(parent, cf_pair_to_item(cp));
+}
- return cf_subsection_find_next(cf_item_to_section(section->item.parent), subsection, name1);
+/** Return the next child that's a #CONF_PAIR
+ *
+ * @param[in] cs to return children from.
+ * @param[in] prev child to start searching from.
+ * @return
+ * - The next #CONF_ITEM that's a child of cs and a CONF_PAIR.
+ * - NULL if no #CONF_ITEM matches that criteria.
+ */
+CONF_PAIR *cf_pair_next(CONF_SECTION const *cs, CONF_PAIR const *prev)
+{
+ return cf_item_to_pair(cf_next(cf_section_to_item(cs), cf_pair_to_item(prev), CONF_ITEM_PAIR));
}
-/** Return the next item after a CONF_ITEM.
+/** Search for a #CONF_PAIR with a specific name
*
+ * @param[in] cs to search in.
+ * @param[in] attr to find.
+ * @return
+ * - The next matching #CONF_PAIR.
+ * - NULL if none matched.
*/
-CONF_ITEM *cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
+CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *attr)
{
- if (!section) return NULL;
+ return cf_item_to_pair(cf_find(cf_section_to_item(cs), CONF_ITEM_PAIR, attr, NULL));
+}
- /*
- * If item is NULL this must be a first time run
- * Return the first item
- */
- if (item == NULL) {
- return section->children;
- } else {
- return item->next;
- }
+/** Find a pair with a name matching attr, after specified pair.
+ *
+ * @param[in] cs to search in.
+ * @param[in] prev Pair to search from (may be NULL).
+ * @param[in] attr to find (may be NULL in which case any attribute matches).
+ * @return
+ * - The next matching #CONF_PAIR
+ * - NULL if none matched.
+ */
+CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
+{
+ return cf_item_to_pair(cf_find_next(cf_section_to_item(cs), cf_pair_to_item(prev), CONF_ITEM_PAIR, attr, NULL));
}
+/** Callback to determine the number of pairs in a section
+ *
+ */
static void _pair_count(int *count, CONF_SECTION const *cs)
{
- CONF_ITEM const *ci;
-
- for (ci = cf_item_find_next(cs, NULL);
- ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ CONF_ITEM const *ci = NULL;
+ while ((ci = cf_item_next(cs, ci))) {
if (cf_item_is_section(ci)) {
_pair_count(count, cf_item_to_section(ci));
continue;
/** Count the number of conf pairs beneath a section
*
* @param[in] cs to search for items in.
- * @return number of pairs nested within section.
+ * @return The number of pairs nested within section.
*/
int cf_pair_count(CONF_SECTION const *cs)
{
return count;
}
-CONF_ITEM *cf_item_parent(CONF_ITEM const *ci)
-{
- if (!ci) return NULL;
-
- return ci->parent;
-}
-
-CONF_SECTION *cf_section_parent(CONF_SECTION const *cs)
-{
- if (!cs) return NULL;
-
- return cf_item_to_section(cs->item.parent);
-}
-
-CONF_SECTION *cf_pair_parent(CONF_PAIR const *cp)
-{
- if (!cp) return NULL;
-
- return cf_item_to_section(cp->item.parent);
-}
-
-CONF_SECTION *cf_item_root(CONF_ITEM const *ci)
-{
- CONF_ITEM *ci_p;
-
- if (!ci) return NULL;
-
- for (ci_p = ci->parent; ci_p->parent; ci_p = ci_p->parent);
-
- return cf_item_to_section(ci_p);
-}
-
-int cf_section_lineno(CONF_SECTION const *section)
-{
- return section->item.lineno;
-}
-
-char const *cf_pair_filename(CONF_PAIR const *pair)
+/** Return the attr of a CONF_PAIR
+ *
+ */
+char const *cf_pair_attr(CONF_PAIR const *pair)
{
- return pair->item.filename;
+ return (pair ? pair->attr : NULL);
}
-char const *cf_section_filename(CONF_SECTION const *section)
+/** Return the value of a CONF_PAIR
+ *
+ */
+char const *cf_pair_value(CONF_PAIR const *pair)
{
- return section->item.filename;
+ return (pair ? pair->value : NULL);
}
-int cf_pair_lineno(CONF_PAIR const *pair)
+FR_TOKEN cf_pair_operator(CONF_PAIR const *pair)
{
- return pair->item.lineno;
+ return (pair ? pair->op : T_INVALID);
}
-bool cf_item_is_section(CONF_ITEM const *item)
+/** Return the value (lhs) type
+ *
+ * @param pair to extract value type from.
+ * @return
+ * - #T_BARE_WORD.
+ * - #T_SINGLE_QUOTED_STRING.
+ * - #T_BACK_QUOTED_STRING.
+ * - #T_DOUBLE_QUOTED_STRING.
+ * - #T_INVALID if the pair is NULL.
+ */
+FR_TOKEN cf_pair_attr_quote(CONF_PAIR const *pair)
{
- return item->type == CONF_ITEM_SECTION;
+ return (pair ? pair->lhs_quote : T_INVALID);
}
-bool cf_item_is_pair(CONF_ITEM const *item)
+/** Return the value (rhs) type
+ *
+ * @param pair to extract value type from.
+ * @return
+ * - #T_BARE_WORD.
+ * - #T_SINGLE_QUOTED_STRING.
+ * - #T_BACK_QUOTED_STRING.
+ * - #T_DOUBLE_QUOTED_STRING.
+ * - #T_INVALID if the pair is NULL.
+ */
+FR_TOKEN cf_pair_value_quote(CONF_PAIR const *pair)
{
- return item->type == CONF_ITEM_PAIR;
+ return (pair ? pair->rhs_quote : T_INVALID);
}
/** Allocate a new user data container
cd->item.type = CONF_ITEM_DATA;
cd->item.parent = parent;
+ fr_cursor_init(&cd->item.cursor, &cd->item.child);
/*
* strdup so if the data is freed, we can
/** Find user data in a config section
*
- * @param[in] cs to add data to.
+ * @param[in] ci to add data to.
* @param[in] type of user data. Used for name spacing and walking over a specific
* type of user data.
- * @param[in] name String identifier of the user data.
+ * @param[in] name String identifier of the user data. Special value CF_IDENT_ANY
+ * may be used to match on type only.
* @return
* - The user data.
* - NULL if no user data exists.
*/
-void *_cf_data_find(CONF_SECTION const *cs, char const *type, char const *name)
+CONF_DATA const *_cf_data_find(CONF_ITEM const *ci, char const *type, char const *name)
{
- if (!cs || (!type && !name)) {
- cf_log_err_cs(cs, "Invalid arguments");
- return NULL;
- }
+ return cf_item_to_data(cf_find(ci, CONF_ITEM_DATA, type, name));
+}
- /*
- * Find the name in the tree, for speed.
- */
- if (cs->data_tree) {
- CONF_DATA mycd, *cd;
+/** Return the next matching section
+ *
+ * @param[in] ci The section we're searching in.
+ * @param[in] prev section we found. May be NULL in which case
+ * we just return the next section after prev.
+ * @param[in] type of user data. Used for name spacing and walking over a specific
+ * type of user data.
+ * @param[in] name String identifier of the user data. Special value CF_IDENT_ANY
+ * can be used to match any name2 value.
+ * @return
+ * - The next CONF_SECTION.
+ * - NULL if there are no more CONF_SECTIONs
+ */
+CONF_DATA const *_cf_data_find_next(CONF_ITEM const *ci, CONF_ITEM const *prev, char const *type, char const *name)
+{
+ return cf_item_to_data(cf_find_next(ci, prev, CONF_ITEM_DATA, type, name));
+}
- mycd.type = type;
- mycd.name = name;
- cd = rbtree_finddata(cs->data_tree, &mycd);
- if (cd) {
- void *to_return;
- memcpy(&to_return, &cd->data, sizeof(to_return));
+/** Return the user assigned value of #CONF_DATA
+ *
+ */
+void *cf_data_value(CONF_DATA const *cd)
+{
+ void *to_return;
- return to_return;
- }
- }
+ if (!cd) return NULL;
- return NULL;
+ memcpy(&to_return, &cd->data, sizeof(to_return));
+
+ return to_return;
}
/** Add user data to a config section
*
- * @param[in] cs to add data to.
+ * @param[in] ci to add data to.
* @param[in] data to add.
* @param[in] name String identifier of the user data.
* @param[in] do_free Function to free user data when the CONF_SECTION is freed.
* @return
- * - 0 on success.
- * - -1 on error.
+ * - #CONF_DATA - opaque handle to the stored data - on success.
+ * - NULL error.
*/
-int _cf_data_add(CONF_SECTION *cs, void const *data, char const *name, bool do_free)
+CONF_DATA const *_cf_data_add(CONF_ITEM *ci, void const *data, char const *name, bool do_free)
{
CONF_DATA *cd;
char const *type = NULL;
- if (!cs || (!data && !name)) {
- cf_log_err_cs(cs, "Invalid arguments");
- return -1;
- }
+ if (!ci) return NULL;
if (data) type = talloc_get_name(data);
/*
* Already exists. Can't add it.
*/
- if (_cf_data_find(cs, type, name)) {
- cf_log_err_cs(cs, "Data of type %s with name %s already exists", type, name);
- return -1;
+ if (_cf_data_find(ci, type, name)) {
+ cf_log_err(ci, "Data of type %s with name %s already exists", type, name);
+ return NULL;
}
- cd = cf_data_alloc(cf_section_to_item(cs), data, name, do_free);
+ cd = cf_data_alloc(ci, data, name, do_free);
if (!cd) {
- cf_log_err_cs(cs, "Failed allocating data");
- return -1;
+ cf_log_err(ci, "Failed allocating data");
+ return NULL;
}
- cf_item_add(cs, cf_data_to_item(cd));
+ cf_item_add(ci, cf_data_to_item(cd));
- return 0;
+ return cd;
}
/** Remove named data from a configuration section
*
- * @param[in] cs to remove data from.
- * @param[in] type of user data. Used for name spacing and walking over a specific
- * type of user data.
- * @param[in] name String identifier of the user data.
+ * @param[in] parent to remove data from.
+ * @param[in] cd opaque handle of the stored data.
* @return
- * - The user data.
- * - NULL if no matching data is found.
+ * - The value stored within the data (if cd is valid and was found and removed).
+ * - NULL if not found.
*/
-void *_cf_data_remove(CONF_SECTION *cs, char const *type, char const *name)
+void *_cf_data_remove(CONF_ITEM *parent, CONF_DATA const *cd)
{
- CONF_DATA mycd;
- CONF_DATA *cd;
- CONF_ITEM *ci, *it;
void *data;
+ CONF_ITEM *ci;
- if (!cs || !name) return NULL;
- if (!cs->data_tree) return NULL;
-
- /*
- * Find the name in the tree, for speed.
- */
- mycd.type = type;
- mycd.name = name;
-
- cd = rbtree_finddata(cs->data_tree, &mycd);
- if (!cd) return NULL;
-
- ci = cf_data_to_item(cd);
- if (cs->children == ci) {
- cs->children = ci->next;
- if (cs->tail == ci) cs->tail = NULL;
- } else {
- for (it = cs->children; it; it = it->next) {
- if (it->next == ci) {
- it->next = ci->next;
- if (cs->tail == ci) cs->tail = it;
- break;
- }
- }
- }
+ ci = cf_remove(parent, cf_data_to_item(cd));
+ rad_assert(!ci || (ci == cf_data_to_item(cd)));
+ if (!ci) return NULL;
talloc_set_destructor(cd, NULL); /* Disarm the destructor */
- rbtree_deletebydata(cs->data_tree, &mycd);
-
memcpy(&data, &cd->data, sizeof(data));
- talloc_free(cd);
+ talloc_const_free(cd);
return data;
}
{
cf_data_walk_ctx_t *cd_ctx = ctx;
CONF_DATA *cd = data;
+ CONF_ITEM *ci = data;
void *mutable;
int ret;
+ /*
+ * We're walking ident2, not all of the items will be data
+ */
+ if (ci->type != CONF_ITEM_DATA) return 0;
+
if ((cd->type != cd_ctx->type) && (strcmp(cd->type, cd_ctx->type) != 0)) return 0;
memcpy(&mutable, &cd->data, sizeof(data));
/** Walk over a specific type of CONF_DATA
*
- * @param[in] cs containing the CONF_DATA to walk over.
+ * @param[in] ci containing the CONF_DATA to walk over.
* @param[in] type of CONF_DATA to walk over.
* @param[in] cb to call when we find CONF_DATA of the specified type.
* @param[in] ctx to pass to cb.
* - 0 on success.
* - -1 on failure.
*/
-int _cf_data_walk(CONF_SECTION *cs, char const *type, cf_walker_t cb, void *ctx)
+int _cf_data_walk(CONF_ITEM *ci, char const *type, cf_walker_t cb, void *ctx)
{
cf_data_walk_ctx_t cd_ctx = {
.type = type,
.ctx = ctx
};
- if (!cs->data_tree) return 0;
-
- return rbtree_walk(cs->data_tree, RBTREE_IN_ORDER, _cf_data_walk_cb, &cd_ctx);
-}
-
-/*
- * This is here to make the rest of the code easier to read. It
- * ties conf_file.c to log.c, but it means we don't have to
- * pollute every other function with the knowledge of the
- * configuration internals.
- */
-void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...)
-{
- va_list ap;
- char buffer[256];
-
- va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- va_end(ap);
-
- if (ci) {
- ERROR("%s[%d]: %s",
- ci->filename, ci->lineno,
- buffer);
- } else {
- ERROR("<unknown>[*]: %s", buffer);
- }
-}
-
-void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...)
-{
- va_list ap;
- char buffer[256];
-
- va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- va_end(ap);
-
- rad_assert(cs != NULL);
+ if (!ci->ident2) return 0;
- ERROR("%s[%d]: %s",
- cs->item.filename, cs->item.lineno,
- buffer);
+ return rbtree_walk(ci->ident2, RBTREE_IN_ORDER, _cf_data_walk_cb, &cd_ctx);
}
-void cf_log_perr_cs(CONF_SECTION const *cs, char const *fmt, ...)
+/** Log an error message relating to a #CONF_ITEM
+ *
+ * @param[in] ci #CONF_ITEM to print file/lineno for.
+ * @param[in] fmt Msg format string.
+ * @param[in] ... Format args.
+ */
+void _cf_log_err(CONF_ITEM const *ci, char const *fmt, ...)
{
- va_list ap;
- char buffer[256];
+ va_list ap;
+ char *msg;
va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
- rad_assert(cs != NULL);
+ if (!ci || !ci->filename) {
+ ERROR("%s", msg);
+ } else {
+ ERROR("%s[%d]: %s", ci->filename, ci->lineno, msg);
+ }
- PERROR("%s[%d]: %s", cs->item.filename, cs->item.lineno, buffer);
+ talloc_free(msg);
}
-void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...)
+/** Log an error message relating to a #CONF_ITEM
+ *
+ * Drains the fr_strerror() stack emitting one or more error messages.
+ *
+ * @param[in] ci #CONF_ITEM to print file/lineno for.
+ * @param[in] fmt Msg format string.
+ * @param[in] ... Format args.
+ */
+void _cf_log_perr(CONF_ITEM const *ci, char const *fmt, ...)
{
- va_list ap;
- char buffer[256];
+ va_list ap;
+ char *msg;
va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
- rad_assert(cp != NULL);
+ if (!ci || !ci->filename) {
+ PERROR("%s", msg);
+ } else {
+ PERROR("%s[%d]: %s", ci->filename, ci->lineno, msg);
+ }
- ERROR("%s[%d]: %s", cp->item.filename, cp->item.lineno, buffer);
+ talloc_free(msg);
}
-void cf_log_perr_cp(CONF_PAIR const *cp, char const *fmt, ...)
+/** Log a warning message relating to a #CONF_ITEM
+ *
+ * @param[in] ci #CONF_ITEM to print file/lineno for.
+ * @param[in] fmt Msg format string.
+ * @param[in] ... Format args.
+ */
+void _cf_log_warn(CONF_ITEM const *ci, char const *fmt, ...)
{
- va_list ap;
- char buffer[256];
+ va_list ap;
+ char *msg;
va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
- rad_assert(cp != NULL);
+ if (!ci || !ci->filename) {
+ WARN("%s", msg);
+ } else {
+ WARN("%s[%d]: %s", ci->filename, ci->lineno, msg);
+ }
- PERROR("%s[%d]: %s", cp->item.filename, cp->item.lineno, buffer);
+ talloc_free(msg);
}
-void cf_log_err_by_name(CONF_SECTION const *parent, char const *name, char const *fmt, ...)
+/** Log a info message relating to a #CONF_ITEM
+ *
+ * @param[in] ci #CONF_ITEM to print file/lineno for.
+ * @param[in] fmt Msg format string.
+ * @param[in] ... Format args.
+ */
+void _cf_log_info(CONF_ITEM const *ci, char const *fmt, ...)
{
- va_list ap;
- CONF_PAIR const *cp;
- char buffer[256];
+ va_list ap;
+ char *msg;
va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
- cp = cf_pair_find(parent, name);
- if (cp) {
- ERROR("%s[%d]: %s",
- cp->item.filename, cp->item.lineno,
- buffer);
+ if (!ci || !ci->filename || !DEBUG_ENABLED3) {
+ INFO("%s", msg);
} else {
- ERROR("%s[%d]: %s",
- parent->item.filename, parent->item.lineno,
- buffer);
+ INFO("%s[%d]: %s", ci->filename, ci->lineno, msg);
}
+ talloc_free(msg);
}
-void cf_log_warn_cp(CONF_PAIR const *cp, char const *fmt, ...)
+/** Log a debug message relating to a #CONF_ITEM
+ *
+ * @param[in] ci #CONF_ITEM to print file/lineno for.
+ * @param[in] fmt Msg format string.
+ * @param[in] ... Format args.
+ */
+void _cf_log_debug(CONF_ITEM const *ci, char const *fmt, ...)
{
- va_list ap;
- char buffer[256];
-
- va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- va_end(ap);
-
- rad_assert(cp != NULL);
+ va_list ap;
+ char *msg;
- WARN("%s[%d]: %s",
- cp->item.filename, cp->item.lineno,
- buffer);
-}
-
-void cf_log_warn(CONF_SECTION const *cs, char const *fmt, ...)
-{
- va_list ap;
+ if (rad_debug_lvl < 1) return;
va_start(ap, fmt);
- if (cs) fr_vlog(&default_log, L_WARN, fmt, ap);
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
-}
-void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...)
-{
- va_list ap;
+ if (!ci || !ci->filename || !DEBUG_ENABLED4) {
+ DEBUG("%s", msg);
+ } else {
+ DEBUG("%s[%d]: %s", ci->filename, ci->lineno, msg);
+ }
- va_start(ap, fmt);
- if ((rad_debug_lvl > 1) && cs) fr_vlog(&default_log, L_DBG, fmt, ap);
- va_end(ap);
+ talloc_free(msg);
}
-/*
- * Wrapper to simplify the code.
- */
-void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...)
+void cf_log_err_by_name(CONF_SECTION const *parent, char const *name, char const *fmt, ...)
{
- va_list ap;
- char buffer[256];
+ va_list ap;
+ char *msg;
+ CONF_PAIR const *cp;
va_start(ap, fmt);
- if (rad_debug_lvl > 1 && cs) {
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
-
- DEBUG("%.*s# %s", cs->depth, parse_spaces, buffer);
- }
+ msg = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
-}
-const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs)
-{
- if (!cs) return NULL;
+ cp = cf_pair_find(parent, name);
+ if (cp) {
+ ERROR("%s[%d]: %s", cp->item.filename, cp->item.lineno, msg);
+ } else {
+ CONF_ITEM const *ci;
- return cs->variables;
+ ci = cf_section_to_item(parent);
+ ERROR("%s[%d]: %s", ci->filename, ci->lineno, msg);
+ }
+ talloc_free(msg);
}
-/*
- * For "switch" and "case" statements.
+/** Print out debugging information about a CONFIG_ITEM
+ *
+ * @param[in] ci being debugged.
*/
-FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs)
-{
- if (!cs) return T_INVALID;
-
- return cs->name2_type;
-}
-
-FR_TOKEN cf_section_argv_type(CONF_SECTION const *cs, int argc)
-{
- if (!cs || !cs->argv_type || (argc < 0) || (argc > cs->argc)) return T_INVALID;
-
- return cs->argv_type[argc];
-}
-
-#ifdef WITH_CONF_WRITE
-static char const parse_tabs[] = " ";
-
-static ssize_t cf_string_write(FILE *fp, char const *string, size_t len, FR_TOKEN t)
+void _cf_debug(CONF_ITEM const *ci)
{
- size_t outlen;
- char c;
- char buffer[2048];
-
- switch (t) {
- default:
- c = '\0';
- break;
-
- case T_DOUBLE_QUOTED_STRING:
- c = '"';
- break;
+ fr_cursor_t cursor;
+ CONF_ITEM const *child;
- case T_SINGLE_QUOTED_STRING:
- c = '\'';
- break;
-
- case T_BACK_QUOTED_STRING:
- c = '`';
- break;
+ /*
+ * Print summary of the item
+ */
+ switch (ci->type) {
+ case CONF_ITEM_SECTION:
+ {
+ CONF_SECTION const *cs = cf_item_to_section(ci);
+ int i;
+
+ DEBUG("SECTION - %p", cs);
+ DEBUG(" name1 : %s", cs->name1);
+ DEBUG(" name2 : %s", cs->name2 ? cs->name2 : "<none>");
+ DEBUG(" name2_quote : %s", fr_int2str(fr_token_quotes_table, cs->name2_quote, "<INVALID>"));
+ DEBUG(" argc : %u", cs->argc);
+
+ for (i = 0; i < cs->argc; i++) {
+ char const *quote = fr_int2str(fr_token_quotes_table, cs->argv_quote[i], "<INVALID>");
+ DEBUG(" argv[%i] : %s%s%s", i, quote, cs->argv[i], quote);
+ }
}
+ break;
- if (c) fprintf(fp, "%c", c);
-
- outlen = fr_snprint(buffer, sizeof(buffer), string, len, c);
- fwrite(buffer, outlen, 1, fp);
-
- if (c) fprintf(fp, "%c", c);
- return 1;
-}
-
-
-static size_t cf_pair_write(FILE *fp, CONF_PAIR *cp)
-{
- if (!cp->value) {
- fprintf(fp, "%s\n", cp->attr);
- return 0;
+ case CONF_ITEM_PAIR:
+ {
+ CONF_PAIR const *cp = cf_item_to_pair(ci);
+
+ DEBUG("PAIR - %p", cp);
+ DEBUG(" attr : %s", cp->attr);
+ DEBUG(" value : %s", cp->value);
+ DEBUG(" operator : %s", fr_int2str(fr_tokens_table, cp->op, "<INVALID>"));
+ DEBUG(" lhs_quote : %s", fr_int2str(fr_token_quotes_table, cp->lhs_quote, "<INVALID>"));
+ DEBUG(" rhs_quote : %s", fr_int2str(fr_token_quotes_table, cp->rhs_quote, "<INVALID>"));
+ DEBUG(" pass2 : %s", cp->pass2 ? "yes" : "no");
+ DEBUG(" parsed : %s", cp->parsed ? "yes" : "no");
}
+ break;
- cf_string_write(fp, cp->attr, strlen(cp->attr), cp->lhs_type);
- fprintf(fp, " %s ", fr_int2str(fr_tokens_table, cp->op, "<INVALID>"));
- cf_string_write(fp, cp->orig_value, strlen(cp->orig_value), cp->rhs_type);
- fprintf(fp, "\n");
-
- return 1; /* FIXME */
-}
-
-
-static FILE *cf_file_write(CONF_SECTION *cs, char const *filename)
-{
- FILE *fp;
- char *p;
- char const *q;
- char buffer[8192];
-
- q = filename;
- if ((q[0] == '.') && (q[1] == '/')) q += 2;
-
- snprintf(buffer, sizeof(buffer), "%s/%s", main_config.write_dir, q);
+ case CONF_ITEM_DATA:
+ {
+ CONF_DATA const *cd = cf_item_to_data(ci);
- p = strrchr(buffer, '/');
- *p = '\0';
- if ((rad_mkdir(buffer, 0700, -1, -1) < 0) &&
- (errno != EEXIST)) {
- cf_log_err_cs(cs, "Failed creating directory %s: %s",
- buffer, strerror(errno));
- return NULL;
+ DEBUG("DATA - %p", cd);
+ DEBUG(" type : %s", cd->type);
+ DEBUG(" name : %s", cd->name);
+ DEBUG(" data : %p", cd->data);
+ DEBUG(" free wth prnt : %s", cd->free ? "yes" : "no");
}
+ break;
- /*
- * And again, because rad_mkdir() butchers the buffer.
- */
- snprintf(buffer, sizeof(buffer), "%s/%s", main_config.write_dir, q);
-
- fp = fopen(buffer, "a");
- if (!fp) {
- cf_log_err_cs(cs, "Failed creating file %s: %s",
- buffer, strerror(errno));
- return NULL;
+ default:
+ DEBUG("INVALID - %p", ci);
+ return;
}
- return fp;
-}
-
-size_t cf_section_write(FILE *in_fp, CONF_SECTION *cs, int depth)
-{
- bool prev = false;
- CONF_ITEM *ci;
- FILE *fp = NULL;
- int fp_max = 0;
- FILE *array[32];
+ DEBUG(" filename : %s", ci->filename);
+ DEBUG(" line : %i", ci->lineno);
+ DEBUG(" next : %p", ci->next);
+ DEBUG(" parent : %p", ci->parent);
+ DEBUG(" children : %s", ci->child ? "yes" : "no");
+ DEBUG(" ident1 tree : %p (%u entries)", ci->ident1, ci->ident1 ? rbtree_num_elements(ci->ident1) : 0);
+ DEBUG(" ident2 tree : %p (%u entries)", ci->ident2, ci->ident2 ? rbtree_num_elements(ci->ident2) : 0);
- /*
- * Default to writing to the FP we're given.
- */
- fp = in_fp;
- array[0] = fp;
- fp_max = 0;
+ if (!ci->child) return;
/*
- * If we have somewhere to print, then print the section
- * name1, etc.
+ * Print summary of the item's children
*/
- if (fp) {
- fwrite(parse_tabs, depth, 1, fp);
- cf_string_write(fp, cs->name1, strlen(cs->name1), T_BARE_WORD);
-
- /*
- * FIXME: check for "if" or "elsif". And if so, print
- * out the parsed condition, instead of the input text
- *
- * cf_data_find(cs, CF_DATA_TYPE_UNLANG, "if");
- */
-
- if (cs->name2) {
- fr_cond_t *c;
-
- fputs(" ", fp);
-
- c = cf_data_find(cs, fr_cond_t, NULL);
- if (c) {
- char buffer[1024];
-
- cond_snprint(buffer, sizeof(buffer), c);
- fprintf(fp, "(%s)", buffer);
+ DEBUG("CHILDREN");
+ fr_cursor_copy(&cursor, &ci->cursor);
- } else { /* dump the string as-is */
- cf_string_write(fp, cs->name2, strlen(cs->name2), cs->name2_type);
- }
- }
+ for (child = fr_cursor_head(&cursor);
+ child;
+ child = fr_cursor_next(&cursor)) {
+ char const *in_ident1, *in_ident2;
- fputs(" {\n", fp);
- }
+ in_ident1 = rbtree_finddata(ci->ident1, child) == child? "in ident1 " : "";
+ in_ident2 = rbtree_finddata(ci->ident2, child) == child? "in ident2 " : "";
- /*
- * Loop over the children. Either recursing, or opening
- * a new file.
- */
- for (ci = cs->children; ci; ci = ci->next) {
- switch (ci->type) {
+ switch (child->type) {
case CONF_ITEM_SECTION:
- if (!fp) continue;
+ {
+ CONF_SECTION const *cs = cf_item_to_section(child);
- cf_section_write(fp, cf_item_to_section(ci), depth + 1);
+ DEBUG(" SECTION %p (%s %s) %s%s", child, cs->name1, cs->name2 ? cs->name2 : "<none>",
+ in_ident1, in_ident2);
+ }
break;
case CONF_ITEM_PAIR:
- if (!fp) continue;
-
- /*
- * Ignore internal things.
- */
- if (!ci->filename || (ci->filename[0] == '<')) break;
-
- fwrite(parse_tabs, depth + 1, 1, fp);
- cf_pair_write(fp, cf_item_to_pair(ci));
- if (!prev) fputs("\n", fp);
- prev = true;
- break;
-
- case CONF_ITEM_COMMENT:
- rad_assert(fp != NULL);
-
- prev = false;
- fwrite(parse_tabs, depth + 1, 1, fp);
- fprintf(fp, "#%s", ((CONF_COMMENT *)ci)->comment);
+ {
+ CONF_PAIR const *cp = cf_item_to_pair(child);
+ char const *lhs_quote = fr_int2str(fr_token_quotes_table, cp->lhs_quote, "<INVALID>");
+ char const *rhs_quote = fr_int2str(fr_token_quotes_table, cp->rhs_quote, "<INVALID>");
+
+ DEBUG(" PAIR %p (%s%s%s %s %s%s%s) %s%s", child,
+ lhs_quote, cp->attr, lhs_quote,
+ fr_int2str(fr_tokens_table, cp->op, "<INVALID>"),
+ rhs_quote, cp->value, rhs_quote,
+ in_ident1, in_ident2);
+ }
break;
- case CONF_ITEM_INCLUDE:
- /*
- * Filename == open the new filename and use that.
- *
- * NULL == close the previous filename
- */
- if (((CONF_INCLUDE *) ci)->filename) {
- CONF_INCLUDE *cc = (CONF_INCLUDE *) ci;
-
- /*
- * Print out
- *
- * $INCLUDE foo.conf
- * $INCLUDE foo/
- *
- * but not the files included from the last one.
- */
- if (fp && (cc->file_type != CONF_INCLUDE_FROMDIR)) {
- fprintf(fp, "$INCLUDE %s\n", ((CONF_INCLUDE *)ci)->filename);
- }
-
- /*
- * If it's a file, we write the
- * file. We ignore the
- * directories. They're just for printing.
- */
- if (cc->file_type != CONF_INCLUDE_DIR) {
- fp = cf_file_write(cs, ((CONF_INCLUDE *) ci)->filename);
- if (!fp) return 0;
-
- fp_max++;
- array[fp_max] = fp;
- }
- } else {
- /*
- * We're done the current file.
- */
- rad_assert(fp != NULL);
- rad_assert(fp_max > 0);
- fclose(fp);
+ case CONF_ITEM_DATA:
+ {
+ CONF_DATA const *cd = cf_item_to_data(child);
- fp_max--;
- fp = array[fp_max];
- }
+ DEBUG(" DATA %p (%s *)%s = %p %s%s", child,
+ cd->type, cd->name ? cd->name : "", cd->data,
+ in_ident1, in_ident2);
break;
+ }
default:
+ DEBUG(" INVALID - %p", child);
break;
}
}
-
- if (fp) {
- fwrite(parse_tabs, depth, 1, fp);
- fputs("}\n\n", fp);
- }
-
- return 1;
}
-#endif /* WITH_CONF_WRITE */
if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
- cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+ cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
- cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
+ cf_log_err(cs, "Application and rlm_%s magic number (prefix) mismatch."
" application: %x module: %x", module->name,
MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
MAGIC_PREFIX(module->magic));
if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
- cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+ cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
- cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
+ cf_log_err(cs, "Application and rlm_%s magic number (version) mismatch."
" application: %lx module: %lx", module->name,
(unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
(unsigned long) MAGIC_VERSION(module->magic));
if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
#ifdef HAVE_DLADDR
- cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+ cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
#endif
- cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
+ cf_log_err(cs, "Application and rlm_%s magic number (commit) mismatch."
" application: %lx module: %lx", module->name,
(unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
(unsigned long) MAGIC_COMMIT(module->magic));
talloc_set_name(*data, "%s", module->common->inst_type);
}
if (module->common->config && (cf_section_parse(*data, *data, cs, module->common->config) < 0)) {
- cf_log_err_cs(cs, "Invalid configuration for module \"%s\"", module->name);
+ cf_log_err(cs, "Invalid configuration for module \"%s\"", module->name);
talloc_free(*data);
return -1;
}
*/
handle = dl_by_name(module_name);
if (!handle) {
- cf_log_err_cs(conf, "Failed to link to module \"%s\": %s", module_name, fr_strerror());
- cf_log_err_cs(conf, "Make sure it (and all its dependent libraries!) are in the search path"
+ cf_log_err(conf, "Failed to link to module \"%s\": %s", module_name, fr_strerror());
+ cf_log_err(conf, "Make sure it (and all its dependent libraries!) are in the search path"
" of your system's ld");
error:
talloc_free(module_name);
module = dlsym(handle, module_name);
if (!module) {
- cf_log_err_cs(conf, "Failed linking to \"%s\" structure: %s", module_name, dlerror());
+ cf_log_err(conf, "Failed linking to \"%s\" structure: %s", module_name, dlerror());
goto error;
}
* Call initialisation functions
*/
if (dl_symbol_init_walk(dl_module) < 0) {
- cf_log_err_cs(conf, "Module initialisation failed \"%s\"", module_name);
+ cf_log_err(conf, "Module initialisation failed \"%s\"", module_name);
goto error;
}
- cf_log_module(conf, "Loaded module \"%s\"", module_name);
+ cf_log_debug(conf, "Loaded module \"%s\"", module_name);
/*
* Add the module to the dlhandle cache
*/
if (!rbtree_insert(dl->tree, dl_module) || !rbtree_insert(dl->sym_tree, dl_module)) {
- cf_log_err_cs(conf, "Failed to cache module \"%s\"", module_name);
+ cf_log_err(conf, "Failed to cache module \"%s\"", module_name);
goto error;
}
rad_protocol_t const *proto;
dl_t *module;
- module = cf_data_find(cs, dl_t, "proto");
+ module = cf_data_value(cf_data_find(cs, dl_t, "proto"));
if (!module) return 0;
proto = (rad_protocol_t const *)module->common;
if (!proto->compile) return 0;
if (proto->compile(server, cs) < 0) {
- cf_log_err_cs(server, "Failed compiling unlang policies for listen type '%s'", proto->name);
+ cf_log_err(server, "Failed compiling unlang policies for listen type '%s'", proto->name);
return -1;
}
cp = cf_pair_find(cs, "type");
if (!cp) {
- cf_log_err_cs(cs, "No 'type' specified in listen section");
+ cf_log_err(cs, "No 'type' specified in listen section");
return -1;
}
type = cf_pair_value(cp);
if (!type) {
- cf_log_err_cs(cs, "Invalid 'type' specified in listen section");
+ cf_log_err(cs, "Invalid 'type' specified in listen section");
return -1;
}
if (!server_name) {
if ((strcmp(type, "control") != 0) &&
(strcmp(type, "proxy") != 0)) {
- cf_log_err_cs(cs, "Listeners of type '%s' MUST be defined in a server", type);
+ cf_log_err(cs, "Listeners of type '%s' MUST be defined in a server", type);
return -1;
}
} else {
if ((strcmp(type, "control") == 0) ||
(strcmp(type, "proxy") == 0)) {
- cf_log_err_cs(cs, "Listeners of type '%s' MUST NOT be defined in a server", type);
+ cf_log_err(cs, "Listeners of type '%s' MUST NOT be defined in a server", type);
return -1;
}
}
}
if (fr_dict_enum_add_alias(da, type, fr_box_uint32(max_listener), true, false) < 0) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Failed adding dictionary entry for protocol %s: %s",
type, fr_strerror());
talloc_const_free(module);
* the protocol-specific processing sections.
*/
if (proto->bootstrap && (proto->bootstrap(server, cs) < 0)) {
- cf_log_err_cs(cs, "Failed loading protocol %s", type);
+ cf_log_err(cs, "Failed loading protocol %s", type);
talloc_const_free(module);
return -1;
}
if (cf_data_find(cs, dl_t, "proto") != NULL) {
- cf_log_err_cs(cs, "Virtual server cannot have two protocols");
+ cf_log_err(cs, "Virtual server cannot have two protocols");
talloc_const_free(module);
return -1;
}
*/
dv = fr_dict_enum_by_alias(NULL, fr_dict_attr_by_num(NULL, 0, FR_LISTEN_SOCKET_TYPE), type);
if (!dv) {
- cf_log_err_cs(cs, "Failed finding dictionary entry for protocol %s", type);
+ cf_log_err(cs, "Failed finding dictionary entry for protocol %s", type);
talloc_const_free(module);
return -1;
}
} else {
type = cf_pair_value(cp);
if (!type) {
- cf_log_err_cs(cs, "No value for 'proto'");
+ cf_log_err(cs, "No value for 'proto'");
return -1;
}
transports = TRANSPORT_TCP;
} else {
- cf_log_err_cs(cs, "Unknown transport protocol 'proto = %s'", type);
+ cf_log_err(cs, "Unknown transport protocol 'proto = %s'", type);
return -1;
}
}
* Asked for UDP and required TCP, or require UDP and asked for TCP.
*/
if ((transports & proto->transports) == 0) {
- cf_log_err_cs(cs, "Invalid transport 'proto = %s' for listeners of 'type = %s'",
+ cf_log_err(cs, "Invalid transport 'proto = %s' for listeners of 'type = %s'",
type, proto->name);
return -1;
}
* address unless we know the destination.
*/
if ((strcmp(proto->name, "proxy") == 0) && (transports == TRANSPORT_TCP)) {
- cf_log_err_cs(cs, "Invalid transport 'proto = %s' for listeners of 'type = %s'",
+ cf_log_err(cs, "Invalid transport 'proto = %s' for listeners of 'type = %s'",
type, proto->name);
return -1;
}
*
* If there's no "tls" section, that's fine, too.
*/
- tls = cf_subsection_find(cs, "tls");
+ tls = cf_section_find(cs, "tls", NULL);
#ifndef WITH_TCP
if (tls) {
- cf_log_err_cs(cs, "TLS transport is not available in this executable");
+ cf_log_err(cs, "TLS transport is not available in this executable");
return -1;
}
#else
if (tls) {
if (!proto->tls) {
- cf_log_err_cs(cs, "TLS transport is not available for listeners with 'type = %s",
+ cf_log_err(cs, "TLS transport is not available for listeners with 'type = %s",
proto->name);
return -1;
}
if (transports == TRANSPORT_UDP) {
- cf_log_err_cs(cs, "TLS transport is not available for listeners with 'proto = udp'");
+ cf_log_err(cs, "TLS transport is not available for listeners with 'proto = udp'");
return -1;
}
}
* We don't need to re-load the same information.
*/
if (client->cs &&
- (filename = cf_section_filename(client->cs)) != NULL) {
+ (filename = cf_filename(client->cs)) != NULL) {
struct stat buf;
if ((stat(filename, &buf) >= 0) &&
if (cf_pair_find(cs, "proto")) {
#ifndef WITH_TCP
- cf_log_err_cs(cs, "System does not support the TCP protocol. "
+ cf_log_err(cs, "System does not support the TCP protocol. "
"Delete this line from the configuration file");
return -1;
#else
*/
if ((this->type == RAD_LISTEN_PROXY) &&
(sock->my_port != 0)) {
- cf_log_err_cs(this->cs, "You must not specify a source port for proxy sockets over TCP");
+ cf_log_err(this->cs, "You must not specify a source port for proxy sockets over TCP");
return -1;
}
#endif
} else {
- cf_log_err_cs(cs, "Unknown proto name \"%s\"", proto);
+ cf_log_err(cs, "Unknown proto name \"%s\"", proto);
return -1;
}
# ifdef WITH_TLS
- tls = cf_subsection_find(cs, "tls");
+ tls = cf_section_find(cs, "tls", NULL);
if (tls) {
/*
* If unset, set to default.
/*
* Magical tuning methods!
*/
- subcs = cf_subsection_find(cs, "performance");
+ subcs = cf_section_find(cs, "performance", NULL);
if (subcs) {
rcode = cf_section_parse(this, this, subcs, performance_config);
if (rcode < 0) return -1;
}
- subcs = cf_subsection_find(cs, "limit");
+ subcs = cf_section_find(cs, "limit", NULL);
if (subcs) {
rcode = cf_section_parse(sock, sock, subcs, limit_config);
if (rcode < 0) return -1;
if (sock->max_rate && ((sock->max_rate < 10) || (sock->max_rate > 1000000))) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Invalid value for \"max_pps\"");
return -1;
}
if (cp) {
char const *value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"No interface name given");
return -1;
}
* (i.e. if SO_BINDTODEVICE is available).
*/
# if defined(SO_BINDTODEVICE) && !defined(SO_BROADCAST)
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"System does not support broadcast sockets. Delete this line from the configuration file");
return -1;
# else
if (this->type != RAD_LISTEN_DHCP) {
- cf_log_err_cp(cp,
+ cf_log_err(cp,
"Broadcast can only be set for DHCP listeners. Delete this line from the configuration file");
return -1;
}
char const *value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"No broadcast value given");
return -1;
}
* generic ones.
*/
clients_cs = NULL;
- parent_cs = cf_top_section(cs);
+ parent_cs = cf_root(cs);
rcode = cf_pair_parse(NULL, cs, "clients", FR_ITEM_POINTER(FR_TYPE_STRING, §ion_name), NULL, T_INVALID);
if (rcode < 0) return -1; /* bad string */
if (rcode == 0) {
/*
* Explicit list given: use it.
*/
- clients_cs = cf_subsection_find_name2(parent_cs, "clients", section_name);
- if (!clients_cs) clients_cs = cf_subsection_find(main_config.config, section_name);
+ clients_cs = cf_section_find(parent_cs, "clients", section_name);
+ if (!clients_cs) clients_cs = cf_section_find(main_config.config, section_name, NULL);
if (!clients_cs) {
- cf_log_err_cs(cs, "Failed to find clients %s {...}", section_name);
+ cf_log_err(cs, "Failed to find clients %s {...}", section_name);
return -1;
}
} /* else there was no "clients = " entry. */
/*
* Always cache the CONF_SECTION of the server.
*/
- this->server_cs = cf_subsection_find_name2(parent_cs, "server", this->server);
+ this->server_cs = cf_section_find(parent_cs, "server", this->server);
if (!this->server_cs) {
- cf_log_err_cs(cs, "Failed to find virtual server '%s'", this->server);
+ cf_log_err(cs, "Failed to find virtual server '%s'", this->server);
return -1;
}
* choose the global list of clients.
*/
if (!clients_cs) {
- if (cf_subsection_find(this->server_cs, "client") != NULL) {
+ if (cf_section_find(this->server_cs, "client", NULL) != NULL) {
clients_cs = this->server_cs;
} else {
clients_cs = parent_cs;
sock->clients = client_list_parse_section(clients_cs, false);
#endif
if (!sock->clients) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Failed to load clients for this listen section");
return -1;
}
this->children = rbtree_create(this, listener_cmp, NULL, 0);
if (!this->children) {
- cf_log_err_cs(cs, "Failed to create child list for TCP socket.");
+ cf_log_err(cs, "Failed to create child list for TCP socket.");
return -1;
}
}
/* Only use libpcap if pcap_type has a value. Otherwise, use socket with SO_BINDTODEVICE */
if (sock->interface && sock->pcap_type) {
if (init_pcap(this) < 0) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Error initializing pcap.");
return -1;
}
*/
if (listen_bind(this) < 0) {
char buffer[128];
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Error binding to port for %s port %d",
fr_inet_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)),
sock->my_port);
for (this = *head; this != NULL; this = this->next) {
#ifdef WITH_TLS
if (!spawn_workers && this->tls) {
- cf_log_err_cs(this->cs, "Threading must be enabled for TLS sockets to function properly");
- cf_log_err_cs(this->cs, "You probably need to do '%s -fxx -l stdout' for debugging",
+ cf_log_err(this->cs, "Threading must be enabled for TLS sockets to function properly");
+ cf_log_err(this->cs, "You probably need to do '%s -fxx -l stdout' for debugging",
main_config.name);
return -1;
}
* Read the distribution dictionaries first, then
* the ones in raddb.
*/
- DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, FR_DICTIONARY_FILE);
+ DEBUG2("Including dictionary file \"%s/%s\"", main_config.dictionary_dir, FR_DICTIONARY_FILE);
if (fr_dict_from_file(NULL, &main_config.dict, main_config.dictionary_dir, FR_DICTIONARY_FILE, "radius") != 0) {
ERROR("Errors reading dictionary: %s",
fr_strerror());
ERROR("Error reading %s/%s: %s", _d, _n, fr_strerror());\
return -1;\
case 0:\
- DEBUG2("including dictionary file %s/%s", _d,_n);\
+ DEBUG2("Including dictionary file \"%s/%s\"", _d,_n);\
break;\
default:\
break;\
* to manually override the ones set by modules
* or the server.
*/
- subcs = cf_subsection_find(cs, "feature");
+ subcs = cf_section_find(cs, "feature", NULL);
if (!subcs) {
subcs = cf_section_alloc(cs, "feature", NULL);
if (!subcs) return -1;
* We check if it's defined first, this is for
* backwards compatibility.
*/
- subcs = cf_subsection_find(cs, "version");
+ subcs = cf_section_find(cs, "version", NULL);
if (!subcs) {
subcs = cf_section_alloc(cs, "version", NULL);
if (!subcs) return -1;
attr = cf_pair_attr(cp);
value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cp(cp, "Missing attribute value");
+ cf_log_err(cp, "Missing attribute value");
goto error;
}
* LHS may be an expansion (that expands to an attribute reference)
* or an attribute reference. Quoting determines which it is.
*/
- type = cf_pair_attr_type(cp);
+ type = cf_pair_attr_quote(cp);
switch (type) {
case T_DOUBLE_QUOTED_STRING:
case T_BACK_QUOTED_STRING:
marker:
fr_canonicalize_error(ctx, &spaces, &text, slen, attr);
- cf_log_err_cp(cp, "%s", text);
- cf_log_err_cp(cp, "%s^ %s", spaces, fr_strerror());
+ cf_log_err(cp, "%s", text);
+ cf_log_err(cp, "%s^ %s", spaces, fr_strerror());
talloc_free(spaces);
talloc_free(text);
default:
slen = tmpl_afrom_attr_str(ctx, &map->lhs, attr, dst_request_def, dst_list_def, true, true);
if (slen <= 0) {
- cf_log_err_cp(cp, "Failed parsing attribute reference");
+ cf_log_err(cp, "Failed parsing attribute reference");
goto marker;
}
if (tmpl_define_unknown_attr(map->lhs) < 0) {
- cf_log_err_cp(cp, "Failed creating attribute %s: %s",
+ cf_log_err(cp, "Failed creating attribute %s: %s",
map->lhs->name, fr_strerror());
goto error;
}
/*
* RHS might be an attribute reference.
*/
- type = cf_pair_value_type(cp);
+ type = cf_pair_value_quote(cp);
if ((type == T_BARE_WORD) && (value[0] == '0') && (tolower((int)value[1]) == 'x') &&
(map->lhs->type == TMPL_TYPE_ATTR) &&
slen = tmpl_afrom_str(map, &map->rhs, value, strlen(value), type, src_request_def, src_list_def, true);
if (slen < 0) goto marker;
if (tmpl_define_unknown_attr(map->rhs) < 0) {
- cf_log_err_cp(cp, "Failed creating attribute %s: %s", map->rhs->name, fr_strerror());
+ cf_log_err(cp, "Failed creating attribute %s: %s", map->rhs->name, fr_strerror());
goto error;
}
}
if (!map->rhs) {
- cf_log_err_cp(cp, "%s", fr_strerror());
+ cf_log_err(cp, "%s", fr_strerror());
goto error;
}
*/
if ((map->rhs->type == TMPL_TYPE_ATTR) &&
(map->rhs->tmpl_num == NUM_COUNT)) {
- cf_log_err_cp(cp, "Cannot assign from a count");
+ cf_log_err(cp, "Cannot assign from a count");
goto error;
}
}
}
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
if (total++ == max) {
cf_log_err(ci, "Map size exceeded");
error:
* Ordered by component
*/
const section_type_value_t section_type_value[MOD_COUNT] = {
- { "authenticate", "Auth-Type", FR_AUTH_TYPE },
- { "authorize", "Autz-Type", FR_AUTZ_TYPE },
- { "preacct", "Pre-Acct-Type", FR_PRE_ACCT_TYPE },
- { "accounting", "Acct-Type", FR_ACCT_TYPE },
- { "session", "Session-Type", FR_SESSION_TYPE },
- { "pre-proxy", "Pre-Proxy-Type", FR_PRE_PROXY_TYPE },
- { "post-proxy", "Post-Proxy-Type", FR_POST_PROXY_TYPE },
- { "post-auth", "Post-Auth-Type", FR_POST_AUTH_TYPE }
+ { "authenticate", "Auth-Type", FR_AUTH_TYPE },
+ { "authorize", "Autz-Type", FR_AUTZ_TYPE },
+ { "preacct", "Pre-Acct-Type", FR_PRE_ACCT_TYPE },
+ { "accounting", "Acct-Type", FR_ACCT_TYPE },
+ { "session", "Session-Type", FR_SESSION_TYPE },
+ { "pre-proxy", "Pre-Proxy-Type", FR_PRE_PROXY_TYPE },
+ { "post-proxy", "Post-Proxy-Type", FR_POST_PROXY_TYPE },
+ { "post-auth", "Post-Auth-Type", FR_POST_AUTH_TYPE }
#ifdef WITH_COA
,
- { "recv-coa", "Recv-CoA-Type", FR_RECV_COA_TYPE },
- { "send-coa", "Send-CoA-Type", FR_SEND_COA_TYPE }
+ { "recv-coa", "Recv-CoA-Type", FR_RECV_COA_TYPE },
+ { "send-coa", "Send-CoA-Type", FR_SEND_COA_TYPE }
#endif
};
handle = exfile_init(ctx, max_entries, max_idle, locking);
if (!handle) return NULL;
- exfile_enable_triggers(handle, cf_subsection_find(module, "file"), trigger_prefix, trigger_args);
+ exfile_enable_triggers(handle, cf_section_find(module, "file", NULL), trigger_prefix, trigger_args);
return handle;
}
{
CONF_PAIR *cp;
CONF_SECTION *cs;
+ CONF_DATA const *cd;
module_instance_t *inst;
/*
* Is a real section (not referencing sibling module).
*/
- cs = cf_subsection_find(module, name);
+ cs = cf_section_find(module, name, NULL);
if (cs) {
*out = cs;
if (!cp) return 0;
if (cf_data_find(module, CONF_SECTION, FIND_SIBLING_CF_KEY)) {
- cf_log_err_cp(cp, "Module reference loop found");
+ cf_log_err(cp, "Module reference loop found");
return -1;
}
- cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
+ cd = cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
/*
* Item found, resolve it to a module instance.
* instantiation order issues.
*/
inst_name = cf_pair_value(cp);
- inst = module_find(cf_section_parent(module), inst_name);
+ inst = module_find(cf_item_to_section(cf_parent(module)), inst_name);
if (!inst) {
- cf_log_err_cp(cp, "Unknown module instance \"%s\"", inst_name);
+ cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
return -1;
}
do {
CONF_SECTION *tmp;
- tmp = cf_section_parent(parent);
+ tmp = cf_item_to_section(cf_parent(parent));
if (!tmp) break;
parent = tmp;
* Remove the config data we added for loop
* detection.
*/
- cf_data_remove(module, CONF_SECTION, FIND_SIBLING_CF_KEY);
+ cf_data_remove(module, cd);
/*
* Check the module instances are of the same type.
*/
if (strcmp(cf_section_name1(inst->cs), cf_section_name1(module)) != 0) {
- cf_log_err_cp(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
+ cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
cf_section_name1(inst->cs), cf_section_name1(module));
return -1;
}
- *out = cf_subsection_find(inst->cs, name);
+ *out = cf_section_find(inst->cs, name, NULL);
return 1;
}
* - NULL on error.
*/
fr_pool_t *module_connection_pool_init(CONF_SECTION *module,
- void *opaque,
- fr_pool_connection_create_t c,
- fr_pool_connection_alive_t a,
- char const *log_prefix,
- char const *trigger_prefix,
- VALUE_PAIR *trigger_args)
+ void *opaque,
+ fr_pool_connection_create_t c,
+ fr_pool_connection_alive_t a,
+ char const *log_prefix,
+ char const *trigger_prefix,
+ VALUE_PAIR *trigger_args)
{
CONF_SECTION *cs, *mycs;
char log_prefix_buff[128];
int ret;
-#define parent_name(_x) cf_section_name(cf_section_parent(_x))
+#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))
cs_name1 = cf_section_name1(module);
cs_name2 = cf_section_name2(module);
/*
* Get our pool config section
*/
- mycs = cf_subsection_find(module, "pool");
+ mycs = cf_section_find(module, "pool", NULL);
if (!mycs) {
DEBUG4("%s: Adding pool section to config item \"%s\" to store pool references", log_prefix,
cf_section_name(module));
* This allows modules to pass in the config sections
* they would like to use the connection pool from.
*/
- pool = cf_data_find(cs, fr_pool_t, NULL);
+ pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
if (!pool) {
DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
instance_name = asked_name;
if (instance_name[0] == '-') instance_name++;
- inst = cf_data_find(modules, module_instance_t, instance_name);
+ inst = cf_data_value(cf_data_find(modules, module_instance_t, instance_name));
if (!inst) return NULL;
return talloc_get_type_abort(inst, module_instance_t);
* the specified method.
*/
if (!inst->module->methods[i]) {
- cf_log_module(modules, "%s does not implement method \"%s\"", inst->name, p + 1);
+ cf_log_debug(modules, "%s does not implement method \"%s\"", inst->name, p + 1);
return NULL;
}
if (method) *method = i;
rbtree_t *thread_inst_tree;
_thread_intantiate_ctx_t ctx;
- modules = cf_subsection_find(root, "modules");
+ modules = cf_section_find(root, "modules", NULL);
if (!modules) return 0;
thread_inst_tree = module_thread_inst_tree;
* Call the instantiate method, if any.
*/
if (inst->module->instantiate) {
- cf_log_module(inst->cs, "Instantiating module \"%s\" from file %s", inst->name,
- cf_section_filename(inst->cs));
+ cf_log_debug(inst->cs, "Instantiating module \"%s\" from file %s", inst->name,
+ cf_filename(inst->cs));
/*
* Call the module's instantiation routine.
*/
if ((inst->module->instantiate)(inst->cs, inst->data) < 0) {
- cf_log_err_cs(inst->cs, "Instantiation failed for module \"%s\"", inst->name);
+ cf_log_err(inst->cs, "Instantiation failed for module \"%s\"", inst->name);
return -1;
}
module_instance_t *inst;
CONF_SECTION *modules;
- modules = cf_subsection_find(root, "modules");
+ modules = cf_section_find(root, "modules", NULL);
if (!modules) return 0;
- inst = cf_data_find(modules, module_instance_t, name);
+ inst = cf_data_value(cf_data_find(modules, module_instance_t, name));
if (!inst) return -1;
return _module_instantiate(inst, NULL);
{
CONF_SECTION *modules;
- modules = cf_subsection_find(root, "modules");
+ modules = cf_section_find(root, "modules", NULL);
if (!modules) return 0;
if (cf_data_walk(modules, module_instance_t, _module_instantiate, NULL) < 0) return -1;
int i;
char const *name1, *instance_name;
module_instance_t *instance;
- dl_t const *module;
+ dl_t const *module;
/*
* Figure out which module we want to load.
if (instance) {
ERROR("Duplicate module \"%s\", in file %s:%d and file %s:%d",
instance_name,
- cf_section_filename(cs),
- cf_section_lineno(cs),
- cf_section_filename(instance->cs),
- cf_section_lineno(instance->cs));
+ cf_filename(cs),
+ cf_lineno(cs),
+ cf_filename(instance->cs),
+ cf_lineno(instance->cs));
return NULL;
}
return NULL;
}
- cf_log_module(cs, "Loading module \"%s\" from file %s", instance->name,
- cf_section_filename(cs));
+ cf_log_debug(cs, "Loading module \"%s\" from file %s", instance->name,
+ cf_filename(cs));
/*
* Parse the modules configuration.
*/
if (instance->module->bootstrap &&
((instance->module->bootstrap)(cs, instance->data) < 0)) {
- cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", instance->name);
+ cf_log_err(cs, "Instantiation failed for module \"%s\"", instance->name);
talloc_free(instance);
return NULL;
}
char const *name;
bool all_same = true;
rad_module_t const *last = NULL;
- CONF_ITEM *sub_ci;
+ CONF_ITEM *sub_ci = NULL;
CONF_PAIR *cp;
module_instance_t *instance;
(strcmp(name, "load-balance") == 0)) {
name = cf_section_name2(vm_cs);
if (!name) {
- cf_log_err_cs(vm_cs, "Subsection must have a name");
+ cf_log_err(vm_cs, "Subsection must have a name");
return -1;
}
if (is_reserved_word(name)) {
is_reserved:
- cf_log_err_cs(vm_cs, "Virtual modules cannot overload unlang keywords");
+ cf_log_err(vm_cs, "Virtual modules cannot overload unlang keywords");
return -1;
}
} else {
/*
* Ensure that the modules we reference here exist.
*/
- for (sub_ci = cf_item_find_next(vm_cs, NULL);
- sub_ci != NULL;
- sub_ci = cf_item_find_next(vm_cs, sub_ci)) {
+ while ((sub_ci = cf_item_next(vm_cs, sub_ci))) {
if (cf_item_is_pair(sub_ci)) {
cp = cf_item_to_pair(sub_ci);
if (cf_pair_value(cp)) {
/*
* Register a redundant xlat
*/
- if (all_same) {
- if (!xlat_register_redundant(vm_cs)) {
- WARN("%s[%d] Not registering expansions for %s",
- cf_section_filename(vm_cs), cf_section_lineno(vm_cs),
- cf_section_name2(vm_cs));
- }
- }
+ if (all_same && (xlat_register_redundant(vm_cs) < 0)) return -1;
return 0;
}
/*
* Remember where the modules were stored.
*/
- modules = cf_subsection_find(root, "modules");
- if (!modules) WARN("Cannot find a \"modules\" section in the rooturation file!");
+ modules = cf_section_find(root, "modules", NULL);
+ if (!modules) {
+ WARN("Cannot find a \"modules\" section in the configuration file!");
+ return 0;
+ }
DEBUG2("%s: #### Loading modules ####", main_config.name);
* This is O(N^2) in the number of modules, but most
* systems should have less than 100 modules.
*/
- for (ci = cf_item_find_next(modules, NULL);
+ for (ci = cf_item_next(modules, NULL);
ci != NULL;
ci = next) {
char const *name1;
CONF_SECTION *subcs;
module_instance_t *instance;
- next = cf_item_find_next(modules, ci);
+ next = cf_item_next(modules, ci);
if (!cf_item_is_section(ci)) continue;
name1 = cf_section_name1(subcs);
if (is_reserved_word(name1)) {
- cf_log_err_cs(subcs, "Modules cannot overload unlang keywords");
+ cf_log_err(subcs, "Modules cannot overload unlang keywords");
return -1;
}
}
* us to load modules with no authorize/authenticate/etc.
* sections.
*/
- cs = cf_subsection_find(root, "instantiate");
+ cs = cf_section_find(root, "instantiate", NULL);
if (cs) {
cf_log_info(cs, " instantiate {");
+ ci = NULL;
/*
* Loop over the items in the 'instantiate' section.
*/
- for (ci = cf_item_find_next(cs, NULL);
- ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ while ((ci = cf_item_next(cs, ci))) {
+ CONF_SECTION *vm_cs;
+
/*
* Skip sections and "other" stuff.
* Sections will be handled later, if
* they're referenced at all...
*/
if (cf_item_is_pair(ci)) {
- cf_log_warn_cp(cf_item_to_pair(ci), "Only virtual modules can be instantiated "
- "with the instantiate section");
+ cf_log_warn(ci, "Only virtual modules can be instantiated "
+ "with the instantiate section");
continue;
}
+ /*
+ * Skip section
+ */
+ if (!cf_item_is_section(ci)) continue;
+
+ vm_cs = cf_item_to_section(ci);
+ cf_log_debug(ci, "Instantiating virtual module \"%s %s\"",
+ cf_section_name1(vm_cs), cf_section_name2(vm_cs));
+
/*
* Can only be "redundant" or
* "load-balance" or
* "redundant-load-balance"
*/
- if (cf_item_is_section(ci) &&
- (virtual_module_bootstrap(modules, cf_item_to_section(ci)) < 0)) return -1;
+ if (virtual_module_bootstrap(modules, cf_item_to_section(ci)) < 0) return -1;
}
cf_log_info(cs, " }");
* Some simple limits
*/
if (pool->max == 0) {
- cf_log_err_cs(cs, "Cannot set 'max' to zero");
+ cf_log_err(cs, "Cannot set 'max' to zero");
goto error;
}
pool->pending_window = (pool->max_pending > 0) ? pool->max_pending : pool->max;
if (pool->min > pool->max) {
- cf_log_err_cs(cs, "Cannot set 'min' to more than 'max'");
+ cf_log_err(cs, "Cannot set 'min' to more than 'max'");
goto error;
}
gid = getgid();
subcs = NULL;
- while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) {
+ while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL)) != NULL) {
char const *value;
CONF_PAIR *cp = cf_pair_find(subcs, "type");
* Log the commands we've run.
*/
if (!radmin_log.file) {
- subcs = cf_subsection_find(cs, "log");
+ subcs = cf_section_find(cs, "log", NULL);
if (subcs) {
CONF_PAIR *cp = cf_pair_find(subcs, "radmin");
if (cp) {
exit(1);
}
- cs = cf_subsection_find(maincs, "modules");
+ cs = cf_section_find(maincs, "modules", NULL);
if (!cs) {
fprintf(stderr, "%s: No modules section found in radiusd.conf\n", argv[0]);
exit(1);
}
/* Read the radutmp section of radiusd.conf */
- cs = cf_subsection_find_name2(cs, "radutmp", NULL);
+ cs = cf_section_find(cs, "radutmp", NULL);
if (!cs) {
fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]);
exit(1);
home->src_ipaddr.af = home->ipaddr.af;
}
- parent = cf_section_parent(cs);
+ parent = cf_item_to_section(cf_parent(cs));
if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
home->parent_server = cf_section_name2(parent);
}
static bool home_server_insert(home_server_t *home, CONF_SECTION *cs)
{
if (home->name && !rbtree_insert(home_servers_byname, home)) {
- cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ cf_log_err(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
return false;
}
if (!home->server && !rbtree_insert(home_servers_byaddr, home)) {
rbtree_deletebydata(home_servers_byname, home);
- cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ cf_log_err(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
return false;
}
if (home->ipaddr.af != AF_UNSPEC) {
rbtree_deletebydata(home_servers_byname, home);
}
- cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ cf_log_err(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
return false;
}
#endif
}
if (home->name && (rbtree_finddata(home_servers_byname, home) != NULL)) {
- cf_log_err_cs(home->cs, "Duplicate home server name %s", home->name);
+ cf_log_err(home->cs, "Duplicate home server name %s", home->name);
return false;
}
inet_ntop(home->ipaddr.af, &home->ipaddr.addr, buffer, sizeof(buffer));
- cf_log_err_cs(home->cs, "Duplicate home server address%s%s%s: %s:%s%s/%i",
+ cf_log_err(home->cs, "Duplicate home server address%s%s%s: %s:%s%s/%i",
home->name ? " (already in use by " : "",
home->name ? home->name : "",
home->name ? ")" : "",
*/
if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
if (fr_ipaddr_is_inaddr_any(&home->ipaddr) == 1) {
- cf_log_err_cs(cs, "Wildcard '*' addresses are not permitted for home servers");
+ cf_log_err(cs, "Wildcard '*' addresses are not permitted for home servers");
goto error;
}
home->ipaddr.af = AF_UNSPEC; /* mark ipaddr as unused */
if (!home->server) {
- cf_log_err_cs(cs, "Invalid value for virtual_server");
+ cf_log_err(cs, "Invalid value for virtual_server");
goto error;
}
* the config with a name that matches the
* virtual_server.
*/
- if (!cf_subsection_find_name2(rc->cs, "server", home->server)) {
- cf_log_err_cs(cs, "No such server %s", home->server);
+ if (!cf_section_find(rc->cs, "server", home->server)) {
+ cf_log_err(cs, "No such server %s", home->server);
goto error;
}
* raise an error.
*/
} else {
- cf_log_err_cs(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined "
+ cf_log_err(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined "
"for home server");
error:
talloc_free(home);
/*
* Check the TLS configuration.
*/
- tls = cf_subsection_find(cs, "tls");
+ tls = cf_section_find(cs, "tls", NULL);
if (tls && home->ipaddr.af == AF_UNSPEC) {
- cf_log_err_cs(cs, "TLS transport cannot be used for home servers with 'virtual_server' set");
+ cf_log_err(cs, "TLS transport cannot be used for home servers with 'virtual_server' set");
goto error;
}
#ifndef WITH_TLS
if (tls) {
- cf_log_err_cs(cs, "TLS transport is not available in this executable");
+ cf_log_err(cs, "TLS transport is not available in this executable");
goto error;
}
#endif
case HOME_PING_CHECK_REQUEST:
if (!home->ping_user_name) {
- cf_log_err_cs(cs, "You must supply a 'username' to enable status_check=request");
+ cf_log_err(cs, "You must supply a 'username' to enable status_check=request");
goto error;
}
if (((home->type == HOME_TYPE_AUTH) ||
(home->type == HOME_TYPE_AUTH_ACCT)) && !home->ping_user_password) {
- cf_log_err_cs(cs, "You must supply a 'password' to enable status_check=request");
+ cf_log_err(cs, "You must supply a 'password' to enable status_check=request");
goto error;
}
break;
case HOME_PING_CHECK_INVALID:
- cf_log_err_cs(cs, "Invalid status_check \"%s\" for home server %s",
+ cf_log_err(cs, "Invalid status_check \"%s\" for home server %s",
home->ping_check_str, home->log_name);
goto error;
}
if (home->ipaddr.af == AF_UNSPEC) {
if (home->proto_str) {
- cf_log_err_cs(cs, "The 'proto' configuration cannot be used for home servers with "
+ cf_log_err(cs, "The 'proto' configuration cannot be used for home servers with "
"'virtual_server' set");
goto error;
}
case IPPROTO_TCP:
#ifndef WITH_TCP
- cf_log_err_cs(cs, "Server not built with support for RADIUS over TCP");
+ cf_log_err(cs, "Server not built with support for RADIUS over TCP");
goto error;
#endif
if (home->ping_check != HOME_PING_CHECK_NONE) {
- cf_log_err_cs(cs, "Only 'status_check = none' is allowed for home "
+ cf_log_err(cs, "Only 'status_check = none' is allowed for home "
"servers with 'proto = tcp'");
goto error;
}
break;
default:
- cf_log_err_cs(cs, "Unknown proto \"%s\"", home->proto_str);
+ cf_log_err(cs, "Unknown proto \"%s\"", home->proto_str);
goto error;
}
#ifdef WITH_COA
case HOME_TYPE_COA:
if (home->server != NULL) {
- cf_log_err_cs(cs, "Home servers of type \"coa\" cannot point to a virtual server");
+ cf_log_err(cs, "Home servers of type \"coa\" cannot point to a virtual server");
goto error;
}
break;
#endif
case HOME_TYPE_INVALID:
- cf_log_err_cs(cs, "Invalid type \"%s\" for home server %s", home->type_str, home->log_name);
+ cf_log_err(cs, "Invalid type \"%s\" for home server %s", home->type_str, home->log_name);
goto error;
}
}
if (!home->server && rbtree_finddata(home_servers_byaddr, home)) {
- cf_log_err_cs(cs, "Duplicate home server");
+ cf_log_err(cs, "Duplicate home server");
goto error;
}
} else
#endif
{
- cf_log_err_cs(cs, "No shared secret defined for home server %s", home->log_name);
+ cf_log_err(cs, "No shared secret defined for home server %s", home->log_name);
goto error;
}
}
*/
if (home->server) {
if (tls) {
- cf_log_err_cs(cs, "Virtual home_servers cannot have a \"tls\" subsection");
+ cf_log_err(cs, "Virtual home_servers cannot have a \"tls\" subsection");
goto error;
}
} else {
#ifdef WITH_TLS
if (tls && (home->proto != IPPROTO_TCP)) {
- cf_log_err_cs(cs, "TLS transport is not available for UDP sockets");
+ cf_log_err(cs, "TLS transport is not available for UDP sockets");
goto error;
}
#endif
*/
if (home->src_ipaddr_str) {
if (fr_inet_hton(&home->src_ipaddr, home->ipaddr.af, home->src_ipaddr_str, false) < 0) {
- cf_log_err_cs(cs, "Failed parsing src_ipaddr");
+ cf_log_err(cs, "Failed parsing src_ipaddr");
goto error;
}
/*
* Duplicate the server section, so we don't mangle
* the client CONF_SECTION we were passed.
*/
- cs = cf_subsection_find(client, "coa_server");
+ cs = cf_section_find(client, "coa_server", CF_IDENT_ANY);
if (cs) {
server = cf_section_dup(client, cs, "home_server", NULL, true);
} else {
if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
} else if (strcmp(cf_pair_value(cp), "coa") != 0) {
talloc_free(server);
- cf_log_err_cs(server, "server.type must be \"coa\"");
+ cf_log_err(server, "server.type must be \"coa\"");
return NULL;
}
home_server_t myhome, *home;
if (!name) {
- cf_log_err_cp(cp,
+ cf_log_err(cp,
"No value given for home_server");
return 0;
}
break;
}
- cf_log_err_cp(cp, "Unknown home_server \"%s\".", name);
+ cf_log_err(cp, "Unknown home_server \"%s\".", name);
return 0;
}
name2 = cf_section_name1(cs);
if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
(strcasecmp(name2, "home_server_pool") != 0))) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Section is not a home_server_pool");
return 0;
}
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Server pool section is missing a name");
return 0;
}
}
if (num_home_servers == 0) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"No home servers defined in pool %s",
name2);
goto error;
if (cp) {
#ifdef WITH_COA
if (server_type == HOME_TYPE_COA) {
- cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
+ cf_log_err(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
goto error;
}
#endif
}
if (!pool->fallback->server) {
- cf_log_err_cs(cs, "Fallback home_server %s does NOT contain a virtual_server directive",
+ cf_log_err(cs, "Fallback home_server %s does NOT contain a virtual_server directive",
pool->fallback->log_name);
goto error;
}
value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cp(cp,
+ cf_log_err(cp,
"No value given for type");
goto error;
}
pool->type = fr_str2int(pool_types, value, 0);
if (!pool->type) {
- cf_log_err_cp(cp,
+ cf_log_err(cp,
"Unknown type \"%s\".",
value);
goto error;
if (cp) {
pool->virtual_server = cf_pair_value(cp);
if (!pool->virtual_server) {
- cf_log_err_cp(cp, "No value given for virtual_server");
+ cf_log_err(cp, "No value given for virtual_server");
goto error;
}
cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
}
- if (!cf_subsection_find_name2(rc->cs, "server", pool->virtual_server)) {
- cf_log_err_cp(cp, "No such server %s", pool->virtual_server);
+ if (!cf_section_find(rc->cs, "server", pool->virtual_server)) {
+ cf_log_err(cp, "No such server %s", pool->virtual_server);
goto error;
}
int i, insert_point, num_home_servers;
home_server_t myhome, *home;
home_pool_t mypool, *pool;
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
#else
(void) rc; /* -Wunused */
(void) realm;
*/
if (strcmp(name, "LOCAL") == 0) {
if (*pool_p) {
- cf_log_err_cs(cs, "Realm \"%s\" cannot be both LOCAL and remote", name);
+ cf_log_err(cs, "Realm \"%s\" cannot be both LOCAL and remote", name);
return 0;
}
return 1;
pool = rbtree_finddata(home_pools_byname, &mypool);
if (pool) {
if (pool->type != ldflag) {
- cf_log_err_cs(cs, "Inconsistent ldflag for server pool \"%s\"", name);
+ cf_log_err(cs, "Inconsistent ldflag for server pool \"%s\"", name);
return 0;
}
if (pool->server_type != type) {
- cf_log_err_cs(cs, "Inconsistent home server type for server pool \"%s\"", name);
+ cf_log_err(cs, "Inconsistent home server type for server pool \"%s\"", name);
return 0;
}
}
home = rbtree_finddata(home_servers_byname, &myhome);
if (home) {
if (secret && (strcmp(home->secret, secret) != 0)) {
- cf_log_err_cs(cs, "Inconsistent shared secret for home server \"%s\"", name);
+ cf_log_err(cs, "Inconsistent shared secret for home server \"%s\"", name);
return 0;
}
if (home->type != type) {
- cf_log_err_cs(cs, "Inconsistent type for home server \"%s\"", name);
+ cf_log_err(cs, "Inconsistent type for home server \"%s\"", name);
return 0;
}
* in the pool. If so, do nothing else.
*/
if (pool) for (i = 0; i < pool->num_home_servers; i++) {
- if (pool->servers[i] == home) {
- return 1;
- }
+ if (pool->servers[i] == home) return 1;
}
}
}
if (insert_point < 0) {
- cf_log_err_cs(cs, "No room in pool to add home server \"%s\". Please update the realm configuration to use the new-style home servers and server pools.", name);
+ cf_log_err(cs, "No room in pool to add home server \"%s\". Please update the realm configuration to use the new-style home servers and server pools.", name);
return 0;
}
}
q = NULL;
} else if (p == name) {
- cf_log_err_cs(cs, "Invalid hostname %s", name);
+ cf_log_err(cs, "Invalid hostname %s", name);
talloc_free(home);
return 0;
} else {
unsigned long port = strtoul(p + 1, NULL, 0);
if ((port == 0) || (port > 65535)) {
- cf_log_err_cs(cs, "Invalid port %s", p + 1);
+ cf_log_err(cs, "Invalid port %s", p + 1);
talloc_free(home);
return 0;
}
if (!server) {
if (fr_inet_hton(&home->ipaddr, AF_UNSPEC, p, false) < 0) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Failed looking up hostname %s.",
p);
talloc_free(home);
home->revive_interval = rc->dead_time;
if (rbtree_finddata(home_servers_byaddr, home)) {
- cf_log_err_cs(cs, "Home server %s has the same IP address and/or port as another home server.", name);
+ cf_log_err(cs, "Home server %s has the same IP address and/or port as another home server.", name);
talloc_free(home);
return 0;
}
if (!rbtree_insert(home_servers_byname, home)) {
- cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
+ cf_log_err(cs, "Internal error %d adding home server %s.", __LINE__, name);
talloc_free(home);
return 0;
}
if (!rbtree_insert(home_servers_byaddr, home)) {
rbtree_deletebydata(home_servers_byname, home);
- cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
+ cf_log_err(cs, "Internal error %d adding home server %s.", __LINE__, name);
talloc_free(home);
return 0;
}
if (home->ipaddr.af != AF_UNSPEC) {
rbtree_deletebydata(home_servers_byname, home);
}
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"Internal error %d adding home server %s.",
__LINE__, name);
talloc_free(home);
* Count the old-style realms of this name.
*/
num_home_servers = 0;
- for (subcs = cf_section_find_next(cs, NULL, "realm");
- subcs != NULL;
- subcs = cf_section_find_next(cs, subcs, "realm")) {
+ while ((subcs = cf_section_find_next(cs, subcs, "realm", CF_IDENT_ANY))) {
char const *this = cf_section_name2(subcs);
if (!this || (strcmp(this, realm) != 0)) continue;
}
if (num_home_servers == 0) {
- cf_log_err_cs(cs, "Internal error counting pools for home server %s.", name);
+ cf_log_err(cs, "Internal error counting pools for home server %s.", name);
talloc_free(home);
return 0;
}
pool = server_pool_alloc(rc, realm, ldflag, type, num_home_servers);
if (!pool) {
- cf_log_err_cs(cs, "Out of memory");
+ cf_log_err(cs, "Out of memory");
return 0;
}
if (cp) {
host = cf_pair_value(cp);
if (!host) {
- cf_log_err_cp(cp, "No value specified for ldflag");
+ cf_log_err(cp, "No value specified for ldflag");
return 0;
}
cf_log_info(cs, "\tldflag = round_robin");
} else {
- cf_log_err_cs(cs, "Unknown value \"%s\" for ldflag", host);
+ cf_log_err(cs, "Unknown value \"%s\" for ldflag", host);
return 0;
}
} /* else don't print it. */
if (cp) {
host = cf_pair_value(cp);
if (!host) {
- cf_log_err_cp(cp, "No value specified for authhost");
+ cf_log_err(cp, "No value specified for authhost");
return 0;
}
if (strcmp(host, "LOCAL") != 0) {
cp = cf_pair_find(cs, "secret");
if (!cp) {
- cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
+ cf_log_err(cs, "No shared secret supplied for realm: %s", r->name);
return 0;
}
secret = cf_pair_value(cp);
if (!secret) {
- cf_log_err_cp(cp, "No value specified for secret");
+ cf_log_err(cp, "No value specified for secret");
return 0;
}
}
if (cp) {
host = cf_pair_value(cp);
if (!host) {
- cf_log_err_cp(cp, "No value specified for accthost");
+ cf_log_err(cp, "No value specified for accthost");
return 0;
}
if ((strcmp(host, "LOCAL") != 0) && !secret) {
cp = cf_pair_find(cs, "secret");
if (!cp) {
- cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
+ cf_log_err(cs, "No shared secret supplied for realm: %s", r->name);
return 0;
}
secret = cf_pair_value(cp);
if (!secret) {
- cf_log_err_cp(cp, "No value specified for secret");
+ cf_log_err(cp, "No value specified for secret");
return 0;
}
}
if (cp) {
host = cf_pair_value(cp);
if (!host) {
- cf_log_err_cp(cp, "No value specified for virtual_server");
+ cf_log_err(cp, "No value specified for virtual_server");
return 0;
}
if (!pool) {
CONF_SECTION *pool_cs;
- pool_cs = cf_subsection_find_name2(rc->cs,
- "home_server_pool",
- name);
- if (!pool_cs) {
- pool_cs = cf_subsection_find_name2(rc->cs,
- "server_pool",
- name);
- }
+ pool_cs = cf_section_find(rc->cs, "home_server_pool", name);
+ if (!pool_cs) pool_cs = cf_section_find(rc->cs, "server_pool", name);
if (!pool_cs) {
- cf_log_err_cs(cs, "Failed to find home_server_pool \"%s\"", name);
+ cf_log_err(cs, "Failed to find home_server_pool \"%s\"", name);
return 0;
}
}
if (pool->server_type != server_type) {
- cf_log_err_cs(cs, "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
+ cf_log_err(cs, "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
return 0;
}
name2 = cf_section_name1(cs);
if (!name2 || (strcasecmp(name2, "realm") != 0)) {
- cf_log_err_cs(cs, "Section is not a realm");
+ cf_log_err(cs, "Section is not a realm");
return 0;
}
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs, "Realm section is missing the realm name");
+ cf_log_err(cs, "Realm section is missing the realm name");
return 0;
}
if (cp) auth_pool_name = cf_pair_value(cp);
if (cp && auth_pool_name) {
if (auth_pool) {
- cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
+ cf_log_err(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
return 0;
}
if (!add_pool_to_realm(rc, cs,
bool do_print = true;
if (acct_pool) {
- cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
+ cf_log_err(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
return 0;
}
if (r && (strcmp(r->name, name2) == 0)) {
if (cf_pair_find(cs, "auth_pool") ||
cf_pair_find(cs, "acct_pool")) {
- cf_log_err_cs(cs, "Duplicate realm \"%s\"", name2);
+ cf_log_err(cs, "Duplicate realm \"%s\"", name2);
goto error;
}
goto error;
}
- if (!realm_realm_add(r, cs)) {
- goto error;
- }
+ if (!realm_realm_add(r, cs)) goto error;
cf_log_info(cs, " }");
fr_canonicalize_error(r, &spaces, &text, slen, r->name + 1);
- cf_log_err_cs(cs, "Invalid regular expression:");
- cf_log_err_cs(cs, "%s", text);
- cf_log_err_cs(cs, "%s^ %s", spaces, fr_strerror());
+ cf_log_err(cs, "Invalid regular expression:");
+ cf_log_err(cs, "%s", text);
+ cf_log_err(cs, "%s^ %s", spaces, fr_strerror());
talloc_free(spaces);
talloc_free(text);
cp = cf_pair_find(cs, "home_server");
if (!cp) {
- cf_log_err_cs(cs, "Pool does not contain a \"home_server\" entry");
+ cf_log_err(cs, "Pool does not contain a \"home_server\" entry");
return HOME_TYPE_INVALID;
}
name = cf_pair_value(cp);
if (!name) {
- cf_log_err_cp(cp, "home_server entry does not reference a home server");
+ cf_log_err(cp, "home_server entry does not reference a home server");
return HOME_TYPE_INVALID;
}
- server_cs = cf_subsection_find_name2(config, "home_server", name);
+ server_cs = cf_section_find(config, "home_server", name);
if (!server_cs) {
- cf_log_err_cp(cp, "home_server \"%s\" does not exist", name);
+ cf_log_err(cp, "home_server \"%s\" does not exist", name);
return HOME_TYPE_INVALID;
}
cp = cf_pair_find(server_cs, "type");
if (!cp) {
- cf_log_err_cs(server_cs, "home_server %s does not contain a \"type\" entry", name);
+ cf_log_err(server_cs, "home_server %s does not contain a \"type\" entry", name);
return HOME_TYPE_INVALID;
}
type = cf_pair_value(cp);
if (!type) {
- cf_log_err_cs(server_cs, "home_server %s contains an empty \"type\" entry", name);
+ cf_log_err(server_cs, "home_server %s contains an empty \"type\" entry", name);
return HOME_TYPE_INVALID;
}
home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
if (home == HOME_TYPE_INVALID) {
- cf_log_err_cs(server_cs, "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
+ cf_log_err(server_cs, "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
return HOME_TYPE_INVALID;
}
CONF_SECTION *cs;
int flags = 0;
#ifdef WITH_PROXY
- CONF_SECTION *server_cs;
+ CONF_SECTION *server_cs = NULL;
#endif
realm_config_t *rc;
rc->cs = config;
#ifdef WITH_PROXY
- cs = cf_subsection_find_next(config, NULL, "proxy");
+ cs = cf_section_find(config, "proxy", NULL);
if (cs) {
if (cf_section_parse(rc, rc, cs, proxy_config) < 0) {
ERROR("Failed parsing proxy section");
home_pools_byname = rbtree_create(NULL, home_pool_name_cmp, NULL, flags);
if (!home_pools_byname) goto error;
- for (cs = cf_subsection_find_next(config, NULL, "home_server");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "home_server")) {
+ cs = NULL;
+ while ((cs = cf_section_find_next(config, cs, "home_server", CF_IDENT_ANY))) {
home_server_t *home;
home = home_server_afrom_cs(rc, rc, cs);
* Loop over virtual servers to find home servers which
* are defined in them.
*/
- for (server_cs = cf_subsection_find_next(config, NULL, "server");
- server_cs != NULL;
- server_cs = cf_subsection_find_next(config, server_cs, "server")) {
- for (cs = cf_subsection_find_next(server_cs, NULL, "home_server");
- cs != NULL;
- cs = cf_subsection_find_next(server_cs, cs, "home_server")) {
+ while ((server_cs = cf_section_find_next(config, server_cs, "server", CF_IDENT_ANY))) {
+ cs = NULL;
+ while ((cs = cf_section_find_next(server_cs, cs, "home_server", CF_IDENT_ANY))) {
home_server_t *home;
home = home_server_afrom_cs(rc, rc, cs);
realms_byname = rbtree_create(NULL, realm_name_cmp, NULL, flags);
if (!realms_byname) goto error;
- for (cs = cf_subsection_find_next(config, NULL, "realm");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "realm")) {
+ cs = NULL;
+ while ((cs = cf_section_find_next(config, cs, "realm", CF_IDENT_ANY))) {
if (!realm_add(rc, cs)) {
error:
realms_free();
/*
* CoA pools aren't necessarily tied to realms.
*/
- for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
+ cs = NULL;
+ while ((cs = cf_section_find_next(config, cs, "home_server_pool", CF_IDENT_ANY))) {
int type;
/*
memset(&thread_pool, 0, sizeof(THREAD_POOL));
thread_pool.spawn_workers = *spawn_workers;
- pool_cf = cf_subsection_find_next(cs, NULL, "thread");
+ pool_cf = cf_section_find(cs, "thread", NULL);
#ifdef WITH_GCD
if (pool_cf) {
WARN("Built with Grand Central Dispatch. Ignoring 'thread' subsection");
* If cs has already been parsed there should be a cached copy
* of conf already stored, so just return that.
*/
- conf = cf_data_find(cs, fr_tls_conf_t, NULL);
+ conf = cf_data_value(cf_data_find(cs, fr_tls_conf_t, NULL));
if (conf) {
DEBUG("Using cached TLS configuration from previous invocation");
return conf;
}
if (conf->session_cache_server &&
- !cf_subsection_find_name2(main_config.config, "server", conf->session_cache_server)) {
+ !cf_section_find(main_config.config, "server", conf->session_cache_server)) {
ERROR("No such virtual server '%s'", conf->session_cache_server);
goto error;
}
if (conf->ocsp.cache_server &&
- !cf_subsection_find_name2(main_config.config, "server", conf->ocsp.cache_server)) {
+ !cf_section_find(main_config.config, "server", conf->ocsp.cache_server)) {
ERROR("No such virtual server '%s'", conf->ocsp.cache_server);
goto error;
}
if (conf->staple.cache_server &&
- !cf_subsection_find_name2(main_config.config, "server", conf->staple.cache_server)) {
+ !cf_section_find(main_config.config, "server", conf->staple.cache_server)) {
ERROR("No such virtual server '%s'", conf->staple.cache_server);
goto error;
}
fr_tls_conf_t *conf;
uint32_t i;
- conf = cf_data_find(cs, fr_tls_conf_t, NULL);
+ conf = cf_data_value(cf_data_find(cs, fr_tls_conf_t, NULL));
if (conf) {
DEBUG2("Using cached TLS configuration from previous invocation");
return conf;
void trigger_exec_init(CONF_SECTION const *cs)
{
trigger_exec_main = cs;
- trigger_exec_subcs = cf_subsection_find(cs, "trigger");
+ trigger_exec_subcs = cf_section_find(cs, "trigger", NULL);
MEM(trigger_last_fired_tree = rbtree_create(talloc_null_ctx(),
_trigger_last_fired_cmp, _trigger_last_fired_free, 0));
* try using the global "trigger" section, and reset the
* reference to the full path, rather than the sub-path.
*/
- subcs = cf_subsection_find(cs, "trigger");
+ subcs = cf_section_find(cs, "trigger", NULL);
if (!subcs && trigger_exec_main && (cs != trigger_exec_main)) {
subcs = trigger_exec_subcs;
attr = name;
/*
* Always has to be an "update" section.
*/
- cs = cf_subsection_find(main_config.config, "update");
+ cs = cf_section_find(main_config.config, "update", CF_IDENT_ANY);
if (!cs) {
talloc_free(main_config.config);
return -1;
rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, unlang_fixup_update, NULL, 128);
if (rcode < 0) return -1; /* message already printed */
if (!head) {
- cf_log_err_cs(cs, "'update' sections cannot be empty");
+ cf_log_err(cs, "'update' sections cannot be empty");
return -1;
}
UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
REQUEST *request, char const *fmt)
{
- int i;
- void *data, *base;
- char *p, *q;
- module_instance_t *instance;
- char *buffer;
- CONF_SECTION *modules;
- CONF_PAIR *cp;
- CONF_PARSER const *variables;
- size_t len;
+ int i;
+ void *data, *base;
+ char *p, *q;
+ module_instance_t *instance;
+ char *buffer;
+ CONF_SECTION *modules;
+ CONF_PAIR *cp;
+ CONF_PARSER const *variables;
+ size_t len;
rad_assert(outlen > 1);
rad_assert(request != NULL);
rad_assert(out != NULL);
rad_assert(*out);
- modules = cf_subsection_find(request->root->config, "modules");
+ modules = cf_section_find(request->root->config, "modules", NULL);
if (!modules) return 0;
buffer = talloc_strdup(request, fmt);
* Handle the known configuration parameters.
*/
for (i = 0; variables[i].name != NULL; i++) {
- int ret;
+ int ret;
+ char const *quote;
if (FR_BASE_TYPE(variables[i].type) == FR_TYPE_SUBSECTION) continue;
/* else it's a CONF_PAIR */
DEBUG2("Failed inserting new value into module instance data");
goto fail;
}
+
+ quote = fr_int2str(fr_token_quotes_table, variables[i].quote, "<INVALID>");
+
+ DEBUG2("Setting config item to %s = %s%s%s", variables[i].name, quote, q, quote);
+
break; /* we found it, don't do any more */
}
vp_tmpl_t const *src, UNUSED vp_map_t const *maps)
{
if (!src) {
- cf_log_err_cs(cs, "Missing source");
+ cf_log_err(cs, "Missing source");
return -1;
}
CONF_PAIR *cp = cf_item_to_pair(ci);
WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
- cf_pair_filename(cp), cf_pair_lineno(cp),
+ cf_filename(cp), cf_lineno(cp),
attr->name, attr->name);
} else {
CONF_SECTION *cs = cf_item_to_section(ci);
WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
- cf_section_filename(cs), cf_section_lineno(cs),
+ cf_filename(cs), cf_lineno(cs),
attr->name, attr->name);
}
TALLOC_FREE(*pvpt);
c->negate = !c->negate;
WARN("%s[%d]: Please change (\"%%{%s}\" %s '') to %c&%s",
- cf_section_filename(cf_item_to_section(c->ci)),
- cf_section_lineno(cf_item_to_section(c->ci)),
+ cf_filename(cf_item_to_section(c->ci)),
+ cf_lineno(cf_item_to_section(c->ci)),
vpt->name, c->negate ? "==" : "!=",
c->negate ? '!' : ' ', vpt->name);
if (DEBUG_ENABLED3) {
if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
- cf_pair_filename(cp), cf_pair_lineno(cp),
+ cf_filename(cp), cf_lineno(cp),
map->lhs->name, fr_int2str(fr_tokens_table, map->op, "<INVALID>"));
}
if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
- cf_pair_filename(cp), cf_pair_lineno(cp),
+ cf_filename(cp), cf_lineno(cp),
fr_int2str(fr_tokens_table, map->op, "<INVALID>"), map->rhs->name);
}
}
if (DEBUG_ENABLED3) {
if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
- cf_pair_filename(cp), cf_pair_lineno(cp),
+ cf_filename(cp), cf_lineno(cp),
map->lhs->name, fr_int2str(fr_tokens_table, map->op, "<INVALID>"));
}
if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
- cf_pair_filename(cp), cf_pair_lineno(cp),
+ cf_filename(cp), cf_lineno(cp),
fr_int2str(fr_tokens_table, map->op, "<INVALID>"), map->rhs->name);
}
}
if (map->op == T_OP_CMP_FALSE) {
if ((map->rhs->type != TMPL_TYPE_UNPARSED) || (strcmp(map->rhs->name, "ANY") != 0)) {
WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
- cf_pair_filename(cp), cf_pair_lineno(cp));
+ cf_filename(cp), cf_lineno(cp));
}
TALLOC_FREE(map->rhs);
case T_OP_SET:
if (map->rhs->type == TMPL_TYPE_EXEC) {
WARN("%s[%d]: Please change ':=' to '=' for list assignment",
- cf_pair_filename(cp), cf_pair_lineno(cp));
+ cf_filename(cp), cf_lineno(cp));
}
if (map->rhs->type != TMPL_TYPE_LIST) {
size_t quoted_len;
char *quoted_str;
- switch (cf_section_argv_type(g->cs, 0)) {
+ switch (cf_section_argv_quote(g->cs, 0)) {
case T_DOUBLE_QUOTED_STRING:
quote = '"';
break;
char const *name2 = cf_section_name2(cs);
- modules = cf_subsection_find(main_config.config, "modules");
+ modules = cf_section_find(main_config.config, "modules", NULL);
if (!modules) {
- cf_log_err_cs(cs, "'map' sections require a 'modules' section");
+ cf_log_err(cs, "'map' sections require a 'modules' section");
return NULL;
}
proc = map_proc_find(name2);
if (!proc) {
- cf_log_err_cs(cs, "Failed to find map processor '%s'", name2);
+ cf_log_err(cs, "Failed to find map processor '%s'", name2);
return NULL;
}
if (tmpl_str) {
FR_TOKEN type;
- type = cf_section_argv_type(cs, 0);
+ type = cf_section_argv_quote(cs, 0);
/*
* Try to parse the template.
slen = tmpl_afrom_str(cs, &vpt, tmpl_str, talloc_array_length(tmpl_str) - 1,
type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if (slen < 0) {
- cf_log_err_cs(cs, "Failed parsing map: %s", fr_strerror());
+ cf_log_err(cs, "Failed parsing map: %s", fr_strerror());
return NULL;
}
default:
talloc_free(vpt);
- cf_log_err_cs(cs, "Invalid third argument for map");
+ cf_log_err(cs, "Invalid third argument for map");
return NULL;
}
}
rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_map, NULL, 256);
if (rcode < 0) return NULL; /* message already printed */
if (!head) {
- cf_log_err_cs(cs, "'map' sections cannot be empty");
+ cf_log_err(cs, "'map' sections cannot be empty");
return NULL;
}
proc_inst = map_proc_instantiate(g, proc, cs, vpt, head);
if (!proc_inst) {
talloc_free(g);
- cf_log_err_cs(cs, "Failed instantiating map function '%s'", name2);
+ cf_log_err(cs, "Failed instantiating map function '%s'", name2);
return NULL;
}
c = unlang_group_to_generic(g);
rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, unlang_fixup_update, NULL, 128);
if (rcode < 0) return NULL; /* message already printed */
if (!head) {
- cf_log_err_cs(cs, "'update' sections cannot be empty");
+ cf_log_err(cs, "'update' sections cannot be empty");
return NULL;
}
action = atoi(value);
if (!action || (action > MOD_PRIORITY_MAX)) {
- cf_log_err_cp(cp, "Priorities MUST be between 1 and 64.");
+ cf_log_err(cp, "Priorities MUST be between 1 and 64.");
return 0;
}
} else {
- cf_log_err_cp(cp, "Unknown action '%s'.\n",
+ cf_log_err(cp, "Unknown action '%s'.\n",
value);
return 0;
}
rcode = fr_str2int(mod_rcode_table, attr, -1);
if (rcode < 0) {
- cf_log_err_cp(cp,
+ cf_log_err(cp,
"Unknown module rcode '%s'.",
attr);
return 0;
* Over-ride the default return codes of the module.
*/
cs = cf_item_to_section(ci);
- for (csi=cf_item_find_next(cs, NULL);
+ for (csi=cf_item_next(cs, NULL);
csi != NULL;
- csi=cf_item_find_next(cs, csi)) {
+ csi=cf_item_next(cs, csi)) {
if (cf_item_is_section(csi)) {
cf_log_err(csi, "Invalid subsection. Expected 'action = value'");
ci = cf_section_to_item(subcs);
- next = cf_item_find_next(cs, ci);
+ next = cf_item_next(cs, ci);
if (next && (cf_item_is_pair(next) || cf_item_is_section(next))) {
cf_log_err(ci, "'actions' MUST be the last block in a section");
return false;
static unlang_t *compile_children(unlang_group_t *g, UNUSED unlang_t *parent, unlang_compile_t *unlang_ctx,
- unlang_group_type_t group_type, unlang_group_type_t parentgroup_type)
+ unlang_group_type_t group_type, unlang_group_type_t parentgroup_type)
{
- CONF_ITEM *ci;
+ CONF_ITEM *ci = NULL;
unlang_t *c;
c = unlang_group_to_generic(g);
/*
* Loop over the children of this group.
*/
- for (ci = cf_item_find_next(g->cs, NULL);
- ci != NULL;
- ci = cf_item_find_next(g->cs, ci)) {
-
+ while ((ci = cf_item_next(g->cs, ci))) {
/*
* Sections are references to other groups, or
* to modules with updated return codes.
*/
single = compile_item(c, unlang_ctx, ci, group_type, &name1);
if (!single) {
- cf_log_err(ci, "Failed to parse \"%s\" subsection.",
- cf_section_name1(subcs));
+ cf_log_err(ci, "Failed to parse \"%s\" subsection", cf_section_name1(subcs));
talloc_free(c);
return NULL;
}
add_child(g, single);
-
- } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
- continue;
-
- } else {
+ } else if (cf_item_is_pair(ci)) {
char const *attr, *value;
CONF_PAIR *cp = cf_item_to_pair(ci);
name = cf_pair_attr(cp);
if (name[0] == '-') {
WARN("%s[%d]: Ignoring \"%s\" (see raddb/mods-available/README.rst)",
- cf_pair_filename(cp), cf_pair_lineno(cp), name + 1);
+ cf_filename(cp), cf_lineno(cp), name + 1);
continue;
}
talloc_free(c);
return NULL;
} /* else it worked */
+ } else if (cf_item_is_data(ci)) {
+ continue;
+ } else {
+ rad_assert(0);
}
}
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
+ cf_log_err(cs, "You must specify a variable to switch over for 'switch'");
return NULL;
}
* Create the template. All attributes and xlats are
* defined by now.
*/
- type = cf_section_name2_type(cs);
+ type = cf_section_name2_quote(cs);
slen = tmpl_afrom_str(g, &g->vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if (slen < 0) {
char *spaces, *text;
fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
- cf_log_err_cs(cs, "Syntax error");
- cf_log_err_cs(cs, "%s", name2);
- cf_log_err_cs(cs, "%s^ %s", spaces, text);
+ cf_log_err(cs, "Syntax error");
+ cf_log_err(cs, "%s", name2);
+ cf_log_err(cs, "%s^ %s", spaces, text);
talloc_free(g);
talloc_free(spaces);
* Walk through the children of the switch section,
* ensuring that they're all 'case' statements
*/
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
CONF_SECTION *subcs;
char const *name1;
vp_tmpl_t *vpt = NULL;
if (!parent || (parent->type != UNLANG_TYPE_SWITCH)) {
- cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
+ cf_log_err(cs, "\"case\" statements may only appear within a \"switch\" section");
return NULL;
}
FR_TOKEN type;
unlang_group_t *f;
- type = cf_section_name2_type(cs);
+ type = cf_section_name2_quote(cs);
slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if (slen < 0) {
fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
- cf_log_err_cs(cs, "Syntax error");
- cf_log_err_cs(cs, "%s", name2);
- cf_log_err_cs(cs, "%s^ %s", spaces, text);
+ cf_log_err(cs, "Syntax error");
+ cf_log_err(cs, "%s", name2);
+ cf_log_err(cs, "%s^ %s", spaces, text);
talloc_free(spaces);
talloc_free(text);
rad_assert(f->vpt->tmpl_da != NULL);
if (tmpl_cast_in_place(vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da) < 0) {
- cf_log_err_cs(cs, "Invalid argument for case statement: %s",
+ cf_log_err(cs, "Invalid argument for case statement: %s",
fr_strerror());
talloc_free(vpt);
return NULL;
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs,
+ cf_log_err(cs,
"You must specify an attribute to loop over in 'foreach'");
return NULL;
}
* module. Allow it for now. The pass2 checks below
* will fix it up.
*/
- type = cf_section_name2_type(cs);
+ type = cf_section_name2_quote(cs);
slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
char *spaces, *text;
fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
- cf_log_err_cs(cs, "Syntax error");
- cf_log_err_cs(cs, "%s", name2);
- cf_log_err_cs(cs, "%s^ %s", spaces, text);
+ cf_log_err(cs, "Syntax error");
+ cf_log_err(cs, "%s", name2);
+ cf_log_err(cs, "%s^ %s", spaces, text);
talloc_free(spaces);
talloc_free(text);
rad_assert(vpt);
if ((vpt->type != TMPL_TYPE_ATTR) && (vpt->type != TMPL_TYPE_LIST)) {
- cf_log_err_cs(cs, "MUST use attribute or list reference in 'foreach'");
+ cf_log_err(cs, "MUST use attribute or list reference in 'foreach'");
talloc_free(vpt);
return NULL;
}
if ((vpt->tmpl_num != NUM_ALL) && (vpt->tmpl_num != NUM_ANY)) {
- cf_log_err_cs(cs, "MUST NOT use instance selectors in 'foreach'");
+ cf_log_err(cs, "MUST NOT use instance selectors in 'foreach'");
talloc_free(vpt);
return NULL;
}
fr_cond_t *cond;
if (!cf_section_name2(cs)) {
- cf_log_err_cs(cs, "'%s' without condition", unlang_ops[mod_type].name);
+ cf_log_err(cs, "'%s' without condition", unlang_ops[mod_type].name);
return NULL;
}
- cond = cf_data_find(cs, fr_cond_t, NULL);
+ cond = cf_data_value(cf_data_find(cs, fr_cond_t, NULL));
rad_assert(cond != NULL);
if (cond->type == COND_TYPE_FALSE) {
INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
unlang_ops[mod_type].name,
- cf_section_filename(cs), cf_section_lineno(cs));
+ cf_filename(cs), cf_lineno(cs));
return compile_empty(parent, unlang_ctx, cs, group_type, parentgroup_type, mod_type, COND_TYPE_FALSE);
}
f = unlang_generic_to_group(p->tail);
if ((f->self.type != UNLANG_TYPE_IF) && (f->self.type != UNLANG_TYPE_ELSIF)) {
else_fail:
- cf_log_err_cs(cs, "Invalid location for '%s'. There is no preceding 'if' or 'elsif' statement",
+ cf_log_err(cs, "Invalid location for '%s'. There is no preceding 'if' or 'elsif' statement",
unlang_ops[mod_type].name);
return -1;
}
INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
unlang_ops[mod_type].name,
unlang_ops[f->self.type].name,
- cf_section_filename(cs), cf_section_lineno(cs));
+ cf_filename(cs), cf_lineno(cs));
return 0;
}
* This is always a syntax error.
*/
if (!cf_section_name2(cs)) {
- cf_log_err_cs(cs, "'%s' without condition", unlang_ops[mod_type].name);
+ cf_log_err(cs, "'%s' without condition", unlang_ops[mod_type].name);
return NULL;
}
unlang_t *c;
if (cf_section_name2(cs)) {
- cf_log_err_cs(cs, "'%s' cannot have a condition", unlang_ops[mod_type].name);
+ cf_log_err(cs, "'%s' cannot have a condition", unlang_ops[mod_type].name);
return NULL;
}
{
CONF_ITEM *ci;
- for (ci=cf_item_find_next(cs, NULL);
+ for (ci=cf_item_next(cs, NULL);
ci != NULL;
- ci=cf_item_find_next(cs, ci)) {
+ ci=cf_item_next(cs, ci)) {
/*
* If we're a redundant, etc. group, then the
* intention is to call modules, rather than
/*
* No children? Die!
*/
- if (!cf_item_find_next(cs, NULL)) {
- cf_log_err_cs(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
+ if (!cf_item_next(cs, NULL)) {
+ cf_log_err(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
return NULL;
}
* For backwards compatibility.
*/
if (name2 &&
- (strcmp(cf_section_name1(cf_section_parent(cs)), "instantiate") != 0)) {
- cf_log_err_cs(cs, "%s sections cannot have a name", unlang_ops[mod_type].name);
+ (strcmp(cf_section_name1(cf_item_to_section(cf_parent(cs))), "instantiate") != 0)) {
+ cf_log_err(cs, "%s sections cannot have a name", unlang_ops[mod_type].name);
return NULL;
}
/*
* No children? Die!
*/
- if (!cf_item_find_next(cs, NULL)) {
- cf_log_err_cs(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
+ if (!cf_item_next(cs, NULL)) {
+ cf_log_err(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
return NULL;
}
* Inside of the "instantiate" section, the name is a name, not a key.
*/
if (name2) {
- if (strcmp(cf_section_name1(cf_section_parent(cs)), "instantiate") == 0) name2 = NULL;
+ if (strcmp(cf_section_name1(cf_item_to_section(cf_parent(cs))), "instantiate") == 0) name2 = NULL;
}
if (name2) {
* Create the template. All attributes and xlats are
* defined by now.
*/
- type = cf_section_name2_type(cs);
+ type = cf_section_name2_quote(cs);
slen = tmpl_afrom_str(g, &g->vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if (slen < 0) {
char *spaces, *text;
fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
- cf_log_err_cs(cs, "Syntax error");
- cf_log_err_cs(cs, "%s", name2);
- cf_log_err_cs(cs, "%s^ %s", spaces, text);
+ cf_log_err(cs, "Syntax error");
+ cf_log_err(cs, "%s", name2);
+ cf_log_err(cs, "%s^ %s", spaces, text);
talloc_free(g);
talloc_free(spaces);
switch (g->vpt->type) {
default:
- cf_log_err_cs(cs, "Invalid type in '%s': data will not result in a load-balance key", name2);
+ cf_log_err(cs, "Invalid type in '%s': data will not result in a load-balance key", name2);
talloc_free(g);
return NULL;
/*
* No children? Die!
*/
- if (!cf_item_find_next(cs, NULL)) {
- cf_log_err_cs(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
+ if (!cf_item_next(cs, NULL)) {
+ cf_log_err(cs, "%s sections cannot be empty", unlang_ops[mod_type].name);
return NULL;
}
if (cf_section_name2(cs) != NULL) {
- cf_log_err_cs(cs, "%s sections cannot have an argument", unlang_ops[mod_type].name);
+ cf_log_err(cs, "%s sections cannot have an argument", unlang_ops[mod_type].name);
return NULL;
}
*
* Return it to the caller, with the updated method.
*/
- cs = cf_subsection_find(main_config.config, "instantiate");
+ cs = cf_section_find(main_config.config, "instantiate", NULL);
if (cs) {
/*
* Found "foo". Load it as "foo", or "foo.method".
*/
- subcs = cf_subsection_find_name2(cs, NULL, virtual_name);
+ subcs = cf_section_find(cs, CF_IDENT_ANY, virtual_name);
if (subcs) {
*pcomponent = method;
return subcs;
*
* If there's no policy section, we can't do anything else.
*/
- cs = cf_subsection_find(main_config.config, "policy");
+ cs = cf_section_find(main_config.config, "policy", NULL);
if (!cs) return NULL;
/*
* And bail out if there's no policy "foo".
*/
if (method_name) {
- subcs = cf_subsection_find_name2(cs, NULL, virtual_name);
+ subcs = cf_section_find(cs, virtual_name, NULL);
if (subcs) *pcomponent = method;
return subcs;
* a policy "foo".
*
*/
- snprintf(buffer, sizeof(buffer), "%s.%s",
- virtual_name, comp2str[method]);
- subcs = cf_subsection_find_name2(cs, NULL, buffer);
+ snprintf(buffer, sizeof(buffer), "%s.%s", virtual_name, comp2str[method]);
+ subcs = cf_section_find(cs, buffer, NULL);
if (subcs) return subcs;
- return cf_subsection_find_name2(cs, NULL, virtual_name);
+ return cf_section_find(cs, virtual_name, NULL);
}
* Compile one entry of a module call.
*/
static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM *ci,
- unlang_group_type_t parent_group_type, char const **modname)
+ unlang_group_type_t parent_group_type, char const **modname)
{
- char const *modrefname, *p;
- unlang_t *c;
- module_instance_t *this;
- CONF_SECTION *cs, *subcs, *modules;
- CONF_ITEM *loop;
- char const *realname;
- rlm_components_t component = unlang_ctx->component;
- unlang_compile_t unlang_ctx2;
+ char const *modrefname, *p;
+ unlang_t *c;
+ module_instance_t *this;
+ CONF_SECTION *cs, *subcs, *modules;
+ CONF_ITEM *loop;
+ char const *realname;
+ rlm_components_t component = unlang_ctx->component;
+ unlang_compile_t unlang_ctx2;
if (cf_item_is_section(ci)) {
int i;
* Some blocks can be empty. The rest need
* to have contents.
*/
- if (!cf_item_find_next(cs, NULL) &&
+ if (!cf_item_next(cs, NULL) &&
!((compile_table[i].mod_type == UNLANG_TYPE_CASE) ||
(compile_table[i].mod_type == UNLANG_TYPE_IF) ||
(compile_table[i].mod_type == UNLANG_TYPE_ELSIF))) {
* of an "sql" policy. If so, we allow the
* second "sql" to refer to the module.
*/
- for (loop = cf_item_parent(ci);
+ for (loop = cf_parent(ci);
loop && subcs;
- loop = cf_item_parent(loop)) {
+ loop = cf_parent(loop)) {
if (loop == cf_section_to_item(subcs)) {
subcs = NULL;
}
/*
* Not a virtual module. It must be a real module.
*/
- modules = cf_subsection_find(main_config.config, "modules");
+ modules = cf_section_find(main_config.config, "modules", NULL);
if (!modules) goto fail;
this = NULL;
* associated with sections.
*/
if (cs) {
- instruction = (unlang_t *)cf_data_find(cs, unlang_group_t, NULL);
+ instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
if (!instruction) {
RPEDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
cf_section_name1(cs), cf_section_name2(cs));
DEBUG2("Server was built with: ");
- for (ci = cf_item_find_next(features, NULL);
+ for (ci = cf_item_next(features, NULL);
ci;
- ci = cf_item_find_next(features, ci)) {
+ ci = cf_item_next(features, ci)) {
len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
if (max < len) max = len;
}
- for (ci = cf_item_find_next(versions, NULL);
+ for (ci = cf_item_next(versions, NULL);
ci;
- ci = cf_item_find_next(versions, ci)) {
+ ci = cf_item_next(versions, ci)) {
len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
if (max < len) max = len;
}
}
#endif
- for (ci = cf_item_find_next(features, NULL);
+ for (ci = cf_item_next(features, NULL);
ci;
- ci = cf_item_find_next(features, ci)) {
+ ci = cf_item_next(features, ci)) {
char const *attr;
cp = cf_item_to_pair(ci);
DEBUG2("Server core libs:");
- for (ci = cf_item_find_next(versions, NULL);
+ for (ci = cf_item_next(versions, NULL);
ci;
- ci = cf_item_find_next(versions, ci)) {
+ ci = cf_item_next(versions, ci)) {
char const *attr;
cp = cf_item_to_pair(ci);
RLM_MODULE_NOOP /* POST_AUTH */
#ifdef WITH_COA
,
- RLM_MODULE_NOOP, /* RECV_COA_TYPE */
+ RLM_MODULE_NOOP, /* RECV_COA_TYPE */
RLM_MODULE_NOOP /* SEND_COA_TYPE */
#endif
};
*/
server_cs = request->server_cs;
if (!server_cs || (strcmp(request->server, cf_section_name2(server_cs)) != 0)) {
- request->server_cs = cf_subsection_find_name2(main_config.config, "server", request->server);
+ request->server_cs = cf_section_find(main_config.config, "server", request->server);
}
- cs = cf_subsection_find(request->server_cs, section_type_value[comp].section);
+ cs = cf_section_find(request->server_cs, section_type_value[comp].section, NULL);
if (!cs) {
RDEBUG2("Empty %s section in virtual server \"%s\". Using default return value %s.",
section_type_value[comp].section, request->server,
*/
if (!idx) {
RDEBUG("Running section %s from file %s",
- section_type_value[comp].section, cf_section_filename(cs));
+ section_type_value[comp].section, cf_filename(cs));
} else {
fr_dict_attr_t const *da;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32((uint32_t)idx));
if (!dv) return RLM_MODULE_FAIL;
- subcs = cf_subsection_find_name2(cs, da->name, dv->alias);
+ subcs = cf_section_find(cs, da->name, dv->alias);
if (!subcs) {
RDEBUG2("%s %s sub-section not found. Using default return values.",
da->name, dv->alias);
}
RDEBUG("Running %s %s from file %s",
- da->name, dv->alias, cf_section_filename(subcs));
+ da->name, dv->alias, cf_filename(subcs));
cs = subcs;
}
}
#endif
-static bool define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *name)
+static int define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *name)
{
fr_value_box_t value = { .type = FR_TYPE_UINT32 };
fr_dict_enum_t *dval;
dval = fr_dict_enum_by_alias(NULL, da, name);
if (dval) {
if (dval->value == 0) {
- ERROR("The dictionaries must not define VALUE %s %s 0",
- da->name, name);
- return false;
+ ERROR("The dictionaries must not define VALUE %s %s 0", da->name, name);
+ return -1;
}
- return true;
+ return 0;
}
/*
value.vb_uint32 = (fr_rand() & 0x00ffffff) + 1;
} while (fr_dict_enum_by_value(NULL, da, &value));
- cf_log_module(cs, "Creating %s = %s", da->name, name);
+ cf_log_debug(cs, "Creating %s = %s", da->name, name);
if (fr_dict_enum_add_alias(da, name, &value, true, false) < 0) {
ERROR("%s", fr_strerror());
- return false;
+ return -1;
}
- return true;
+ return 0;
}
/*
*/
dval = fr_dict_enum_by_alias(NULL, da, name2);
if (!dval) {
- cf_log_err_cs(cs,
- "The %s attribute has no VALUE defined for %s",
- section_type_value[comp].typename, name2);
+ cf_log_err(cs,
+ "The %s attribute has no VALUE defined for %s",
+ section_type_value[comp].typename, name2);
return false;
}
/*
* Compile the group.
*/
- if (unlang_compile(cs, comp) < 0) {
- return false;
- }
+ if (unlang_compile(cs, comp) < 0) return false;
return true;
}
static int load_component_section(CONF_SECTION *cs, rlm_components_t comp)
{
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
fr_dict_attr_t const *da;
/*
*/
da = fr_dict_attr_by_num(NULL, 0, section_type_value[comp].attr);
if (!da) {
- cf_log_err_cs(cs,
- "No such attribute %s",
- section_type_value[comp].typename);
+ cf_log_err(cs,
+ "No such attribute %s",
+ section_type_value[comp].typename);
return -1;
}
* The results will be cached, so that the next
* compilation will skip these sections.
*/
- for (subcs = cf_subsection_find_next(cs, NULL, section_type_value[comp].typename);
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, subcs, section_type_value[comp].typename)) {
+ while ((subcs = cf_section_find_next(cs, subcs, section_type_value[comp].typename, CF_IDENT_ANY))) {
if (!load_subcomponent_section(subcs, da, comp)) {
return -1; /* FIXME: memleak? */
}
* Compile the section.
*/
if (unlang_compile(cs, comp) < 0) {
- cf_log_err_cs(cs, "Errors parsing %s section.\n",
+ cf_log_err(cs, "Errors parsing %s section.\n",
cf_section_name1(cs));
return -1;
}
CONF_PAIR *cp;
cf_log_info(cs, "server %s { # from file %s",
- name, cf_section_filename(cs));
+ name, cf_filename(cs));
cp = cf_pair_find(cs, "namespace");
if (cp) {
for (comp = 0; comp < MOD_COUNT; ++comp) {
CONF_SECTION *subcs;
- subcs = cf_subsection_find(cs,
- section_type_value[comp].section);
+ subcs = cf_section_find(cs, section_type_value[comp].section, NULL);
if (!subcs) continue;
if (cp) {
return -1;
}
- if (cf_item_find_next(subcs, NULL) == NULL) continue;
+ if (cf_item_next(subcs, NULL) == NULL) continue;
/*
* Skip pre/post-proxy sections if we're not
*/
if (!found)
do {
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
/*
* Compile the listeners.
*/
- for (subcs = cf_subsection_find_next(cs, NULL, "listen");
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, subcs, "listen")) {
+ while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL))) {
if (listen_compile(cs, subcs) < 0) return -1;
}
*/
da = fr_dict_attr_by_num(NULL, 0, section_type_value[comp].attr);
if (!da) {
- cf_log_err_cs(cs,
- "No such attribute %s",
- section_type_value[comp].typename);
+ cf_log_err(cs,
+ "No such attribute %s",
+ section_type_value[comp].typename);
return false;
}
* bare words in them. Fix those up to be sections.
*/
if (comp == MOD_AUTHENTICATE) {
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
CONF_PAIR *cp;
if (!cf_item_is_pair(ci)) continue;
/*
* Define the Autz-Type, etc. based on the subsections.
*/
- for (subcs = cf_subsection_find_next(cs, NULL, section_type_value[comp].typename);
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, subcs, section_type_value[comp].typename)) {
+ subcs = NULL;
+ while ((subcs = cf_section_find_next(cs, subcs, section_type_value[comp].typename, CF_IDENT_ANY))) {
char const *name2;
CONF_SECTION *cs2;
name2 = cf_section_name2(subcs);
- cs2 = cf_subsection_find_name2(cs, section_type_value[comp].typename, name2);
+ cs2 = cf_section_find(cs, section_type_value[comp].typename, name2);
if (cs2 != subcs) {
- cf_log_err_cs(cs2, "Duplicate configuration section %s %s",
- section_type_value[comp].typename, name2);
+ cf_log_err(cs2, "Duplicate configuration section %s %s",
+ section_type_value[comp].typename, name2);
return false;
}
- if (!define_type(cs, da, name2)) {
- return false;
- }
+ if (define_type(cs, da, name2) < 0) return false;
}
return true;
*/
int virtual_servers_bootstrap(CONF_SECTION *config)
{
- CONF_SECTION *cs;
+ CONF_SECTION *cs = NULL;
char const *server_name;
- if (!cf_subsection_find_next(config, NULL, "server")) {
+ if (!cf_section_find(config, "server", CF_IDENT_ANY)) {
ERROR("No virtual servers found");
return -1;
}
/*
* Bootstrap global listeners.
*/
- for (cs = cf_subsection_find_next(config, NULL, "listen");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "listen")) {
+ while ((cs = cf_section_find_next(config, cs, "listen", NULL))) {
if (cf_pair_find(cs, "namespace") != NULL) {
main_config.namespace = true;
continue;
if (listen_bootstrap(config, cs, NULL) < 0) return -1;
}
- for (cs = cf_subsection_find_next(config, NULL, "server");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "server")) {
+ cs = NULL;
+ while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) {
CONF_ITEM *ci;
CONF_SECTION *subcs;
CONF_PAIR *cp;
server_name = cf_section_name2(cs);
if (!server_name) {
- cf_log_err_cs(cs, "server sections must have a name");
+ cf_log_err(cs, "server sections must have a name");
return -1;
}
/*
* Check for duplicates.
*/
- subcs = cf_subsection_find_name2(config, "server", server_name);
+ subcs = cf_section_find(config, "server", server_name);
if (subcs && (subcs != cs)) {
ERROR("Duplicate virtual server \"%s\", in file %s:%d and file %s:%d",
server_name,
- cf_section_filename(cs),
- cf_section_lineno(cs),
- cf_section_filename(subcs),
- cf_section_lineno(subcs));
+ cf_filename(cs),
+ cf_lineno(cs),
+ cf_filename(subcs),
+ cf_lineno(subcs));
return -1;
}
value = cf_pair_value(cp);
if (!value) {
- cf_log_err_cs(cs, "Cannot have empty namespace");
+ cf_log_err(cs, "Cannot have empty namespace");
return -1;
}
if (strcmp(value, "radius") != 0) {
- cf_log_err_cs(cs, "Unknown namespace '%s'", value);
+ cf_log_err(cs, "Unknown namespace '%s'", value);
return -1;
}
module = dl_module(cs, NULL, value, DL_TYPE_PROTO);
if (!module) {
- cf_log_err_cs(cs, "Failed to find library for 'namespace = %s'", value);
+ cf_log_err(cs, "Failed to find library for 'namespace = %s'", value);
return -1;
}
app = (fr_app_t const *) module->common;
if (app->bootstrap && (app->bootstrap(cs) < 0)) {
- cf_log_err_cs(cs, "Failed to bootstrap library for 'namespace = %s'", value);
+ cf_log_err(cs, "Failed to bootstrap library for 'namespace = %s'", value);
return -1;
}
if (!app->instantiate) {
- cf_log_err_cs(cs, "Failed to find initialization function for 'transport = %s'",
+ cf_log_err(cs, "Failed to find initialization function for 'transport = %s'",
value);
return -1;
}
continue;
}
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
rlm_components_t comp;
char const *name1;
*/
int virtual_servers_init(fr_schedule_t *sc, CONF_SECTION *config)
{
- CONF_SECTION *cs;
+ CONF_SECTION *cs = NULL;
DEBUG2("%s: #### Loading Virtual Servers ####", main_config.name);
/*
* Load all of the virtual servers.
*/
- for (cs = cf_subsection_find_next(config, NULL, "server");
- cs != NULL;
- cs = cf_subsection_find_next(config, cs, "server")) {
+ while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) {
char const *name2;
name2 = cf_section_name2(cs);
if (!sc) continue;
- module = cf_data_find(cs, dl_t, "app");
+ module = cf_data_value(cf_data_find(cs, dl_t, "app"));
if (!module) continue;
app = (fr_app_t const *) module->common;
*/
cf_log_info(cs, "server %s { # from file %s",
- name2, cf_section_filename(cs));
+ name2, cf_filename(cs));
cf_log_info(cs, " namespace = %s", app->name);
if (app->instantiate(sc, cs, check_config) < 0) {
- cf_log_err_cs(cs, "Failed loading virtual server %s", name2);
+ cf_log_err(cs, "Failed loading virtual server %s", name2);
return -1;
}
rbnode_t *node;
if (!name || !*name) {
- DEBUG("xlat_register: Invalid xlat name");
+ ERROR("%s: Invalid xlat name", __FUNCTION__);
return -1;
}
xlat_root = rbtree_create(NULL, xlat_cmp, NULL, RBTREE_FLAG_REPLACE);
if (!xlat_root) {
- DEBUG("xlat_register: Failed to create tree");
+ ERROR("%s: Failed to create tree", __FUNCTION__);
return -1;
}
c = rbtree_finddata(xlat_root, &my_xlat);
if (c) {
if (c->internal) {
- DEBUG("xlat_register: Cannot re-define internal xlat");
+ ERROR("%s: Cannot re-define internal xlat", __FUNCTION__);
return -1;
}
c->instantiate = instantiate;
c->inst_size = inst_size;
- DEBUG3("xlat_register: %s", c->name);
+ DEBUG3("%s: %s", c->name, __FUNCTION__);
- node = rbtree_insert_node(xlat_root, c);
- if (!node) {
- talloc_free(c);
- return -1;
- }
+ MEM(node = rbtree_insert_node(xlat_root, c));
return 0;
}
/*
* Pick the first xlat which succeeds
*/
- for (ci = cf_item_find_next(xr->cs, NULL);
+ for (ci = cf_item_next(xr->cs, NULL);
ci != NULL;
- ci = cf_item_find_next(xr->cs, ci)) {
+ ci = cf_item_next(xr->cs, ci)) {
ssize_t rcode;
if (!cf_item_is_pair(ci)) continue;
/*
* Choose a child at random.
*/
- for (ci = cf_item_find_next(xr->cs, NULL);
+ for (ci = cf_item_next(xr->cs, NULL);
ci != NULL;
- ci = cf_item_find_next(xr->cs, ci)) {
+ ci = cf_item_next(xr->cs, ci)) {
if (!cf_item_is_pair(ci)) continue;
count++;
/*
* Go to the next one, wrapping around at the end.
*/
- ci = cf_item_find_next(xr->cs, ci);
- if (!ci) ci = cf_item_find_next(xr->cs, NULL);
+ ci = cf_item_next(xr->cs, ci);
+ if (!ci) ci = cf_item_next(xr->cs, NULL);
} while (ci != found);
return -1;
}
-
-bool xlat_register_redundant(CONF_SECTION *cs)
+/** Registers a redundant xlat
+ *
+ * These xlats wrap the xlat methods of the modules in a redundant section,
+ * emulating the behaviour of a redundant section, but over xlats.
+ *
+ * @return
+ * - 0 on success.
+ * - -1 on error.
+ * - 1 if the modules in the section do not have an xlat method.
+ */
+int xlat_register_redundant(CONF_SECTION *cs)
{
char const *name1, *name2;
xlat_redundant_t *xr;
name2 = cf_section_name2(cs);
if (xlat_find(name2)) {
- cf_log_err_cs(cs, "An expansion is already registered for this name");
- return false;
+ cf_log_err(cs, "An expansion is already registered for this name");
+ return -1;
}
- xr = talloc_zero(cs, xlat_redundant_t);
- if (!xr) return false;
+ MEM(xr = talloc_zero(cs, xlat_redundant_t));
if (strcmp(name1, "redundant") == 0) {
xr->type = XLAT_REDUNDANT;
-
} else if (strcmp(name1, "redundant-load-balance") == 0) {
xr->type = XLAT_REDUNDANT_LOAD_BALANCE;
-
} else if (strcmp(name1, "load-balance") == 0) {
xr->type = XLAT_LOAD_BALANCE;
-
} else {
- return false;
+ rad_assert(0);
}
xr->cs = cs;
*/
if (xr->type == XLAT_REDUNDANT) {
if (xlat_register(xr, name2, xlat_redundant, NULL, NULL, 0, 0) < 0) {
+ ERROR("Registering xlat for redundant section failed");
talloc_free(xr);
- return false;
+ return -1;
}
} else {
- CONF_ITEM *ci;
+ CONF_ITEM *ci = NULL;
+
+ while ((ci = cf_item_next(cs, ci))) {
+ char const *attr;
- for (ci = cf_item_find_next(cs, NULL);
- ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
if (!cf_item_is_pair(ci)) continue;
- if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
+ attr = cf_pair_attr(cf_item_to_pair(ci));
+
+ /*
+ * This is ok, it just means the module
+ * doesn't have an xlat method.
+ */
+ if (!xlat_find(attr)) {
talloc_free(xr);
- return false;
+ return 1;
}
xr->count++;
}
if (xlat_register(xr, name2, xlat_load_balance, NULL, NULL, 0, 0) < 0) {
+ ERROR("Registering xlat for load-balance section failed");
talloc_free(xr);
- return false;
+ return -1;
}
}
- return true;
+ return 0;
}
request->server = request->listener->server;
request->server_cs = request->listener->server_cs;
- unlang = cf_subsection_find(request->server_cs, "arp");
+ unlang = cf_section_find(request->server_cs, "arp", NULL);
request->component = "arp";
if (rcode != 0) return rcode;
if (!sock->lsock.interface) {
- cf_log_err_cs(cs, "'interface' is required for arp");
+ cf_log_err(cs, "'interface' is required for arp");
return -1;
}
{
CONF_SECTION *cs;
- cs = cf_subsection_find(server_cs, "arp");
+ cs = cf_section_find(server_cs, "arp", NULL);
if (!cs) {
- cf_log_err_cs(server_cs, "No 'arp' sub-section found");
+ cf_log_err(server_cs, "No 'arp' sub-section found");
return -1;
}
{
CONF_SECTION *cs;
- cs = cf_subsection_find(server_cs, "arp");
+ cs = cf_section_find(server_cs, "arp", NULL);
if (!cs) {
- cf_log_err_cs(server_cs, "No 'arp' sub-section found");
+ cf_log_err(server_cs, "No 'arp' sub-section found");
return -1;
}
- cf_log_module(cs, "Loading arp {...}");
+ cf_log_debug(cs, "Loading arp {...}");
if (unlang_compile(cs, MOD_POST_AUTH) < 0) {
- cf_log_err_cs(cs, "Failed compiling 'arp' section");
+ cf_log_err(cs, "Failed compiling 'arp' section");
return -1;
}
uint16_t port;
fr_ipaddr_t ipaddr;
- for (ci=cf_item_find_next(cs, NULL);
+ for (ci=cf_item_next(cs, NULL);
ci != NULL;
- ci=cf_item_find_next(cs, ci)) {
+ ci=cf_item_next(cs, ci)) {
bfd_state_t *session, my_session;
if (!cf_item_is_section(ci)) continue;
/*
* Find the sibling "bfd" section of the "listen" section.
*/
- server = cf_section_parent(cs);
- sock->unlang = cf_subsection_find(server, "bfd");
+ server = cf_item_to_section(cf_parent(cs));
+ sock->unlang = cf_section_find(server, "bfd", NULL);
return 0;
}
{
CONF_SECTION *cs;
- cs = cf_subsection_find(server_cs, "bfd");
+ cs = cf_section_find(server_cs, "bfd", NULL);
if (!cs) {
- cf_log_err_cs(server_cs, "No 'bfd' sub-section found");
+ cf_log_err(server_cs, "No 'bfd' sub-section found");
return -1;
}
{
CONF_SECTION *cs;
- cs = cf_subsection_find(server_cs, "bfd");
+ cs = cf_section_find(server_cs, "bfd", NULL);
if (!cs) {
- cf_log_err_cs(server_cs, "No 'bfd' sub-section found");
+ cf_log_err(server_cs, "No 'bfd' sub-section found");
return -1;
}
- cf_log_module(cs, "Loading bfd {...}");
+ cf_log_debug(cs, "Loading bfd {...}");
if (unlang_compile(cs, MOD_AUTHORIZE) < 0) {
- cf_log_err_cs(cs, "Failed compiling 'bfd' section");
+ cf_log_err(cs, "Failed compiling 'bfd' section");
return -1;
}
rcode = cf_section_parse(data, data, cs, detail_config);
if (rcode < 0) {
- cf_log_err_cs(cs, "Failed parsing listen section");
+ cf_log_err(cs, "Failed parsing listen section");
return -1;
}
this->nodup = true;
if (!data->filename) {
- cf_log_err_cs(cs, "No detail file specified in listen section");
+ cf_log_err(cs, "No detail file specified in listen section");
return -1;
}
*/
if ((strchr(buffer, '*') != NULL) ||
(strchr(buffer, '[') != NULL)) {
- cf_log_err_cs(cs, "Wildcard directories are not supported");
+ cf_log_err(cs, "Wildcard directories are not supported");
return -1;
}
client->secret = client->shortname;
client->nas_type = talloc_strdup(data, "none"); /* Part of 'data' not dynamically allocated */
- this->server_cs = cf_section_parent(this->cs);
+ this->server_cs = cf_item_to_section(cf_parent(this->cs));
client->server_cs = this->server_cs;
return 0;
RDEBUG("Trying sub-section dhcp %s {...}", dv->alias);
- server = cf_section_parent(request->listener->cs);
+ server = cf_item_to_section(cf_parent(request->listener->cs));
- unlang = cf_subsection_find_name2(server, "dhcp", dv->alias);
+ unlang = cf_section_find(server, "dhcp", dv->alias);
rcode = unlang_interpret(request, unlang, RLM_MODULE_NOOP);
} else {
REDEBUG("Unknown DHCP-Message-Type %d", vp->vp_uint8);
*/
static int dhcp_listen_compile(CONF_SECTION *server_cs, CONF_SECTION *listen_cs)
{
- CONF_SECTION *cs;
+ CONF_SECTION *subcs = NULL;
fr_dict_attr_t const *da;
fr_dict_enum_t const *dv;
da = fr_dict_attr_by_name(NULL, "DHCP-Message-Type");
if (!da) {
- cf_log_err_cs(listen_cs, "No DHCP-Message-Type attribute found");
+ cf_log_err(listen_cs, "No DHCP-Message-Type attribute found");
return -1;
}
- for (cs = cf_subsection_find_next(server_cs, NULL, "dhcp");
- cs != NULL;
- cs = cf_subsection_find_next(server_cs, cs, "dhcp")) {
- char const *name2 = cf_section_name2(cs);
+ while ((subcs = cf_section_find_next(server_cs, subcs, "dhcp", NULL))) {
+ char const *name2 = cf_section_name2(subcs);
if (name2) {
- cf_log_module(cs, "Loading dhcp %s {...}", name2);
+ cf_log_debug(subcs, "Loading dhcp %s {...}", name2);
} else {
- cf_log_module(cs, "Loading dhcp {...}");
+ cf_log_debug(subcs, "Loading dhcp {...}");
}
dv = fr_dict_enum_by_alias(NULL, da, name2);
if (!dv) {
- cf_log_err_cs(cs, "Server contains 'dhcp %s {...}, but there is no such value for DHCP-Message-Type",
- name2);
+ cf_log_err(subcs, "Server contains 'dhcp %s {...}, but there is no such value for "
+ "DHCP-Message-Type", name2);
return -1;
}
- if (unlang_compile(cs, MOD_POST_AUTH) < 0) {
- cf_log_err_cs(cs, "Failed compiling 'dhcp %s' section", name2);
+ if (unlang_compile(subcs, MOD_POST_AUTH) < 0) {
+ cf_log_err(subcs, "Failed compiling 'dhcp %s' section", name2);
return -1;
}
}
rad_assert(0);
return;
}
- unlang = cf_subsection_find_name2(request->server_cs, verb, state);
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, verb, state);
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
RDEBUG2("Ignoring %s operation. Add \"%s %s {}\" to virtual-server \"%s\""
" to handle", fr_int2str(ldap_sync_code_table, request->packet->code, "<INVALID>"),
}
RDEBUG("Running '%s %s' from file %s", cf_section_name1(unlang),
- cf_section_name2(unlang), cf_section_filename(unlang));
+ cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_RECV;
{
rad_listen_t *listen = talloc_get_type_abort(user_ctx, rad_listen_t);
- if (!cf_subsection_find_name2(listen->server_cs, "recv", "Present")) {
+ if (!cf_section_find(listen->server_cs, "recv", "Present")) {
DEBUG2("Present phase is not supported, reinitialising sync");
return _proto_ldap_refresh_required(conn, config, sync_id, phase, user_ctx);
proto_ldap_attributes_add(request, config);
request->packet->code = LDAP_SYNC_CODE_COOKIE_STORE;
- unlang = cf_subsection_find_name2(request->server_cs, "load", "Cookie");
+ unlang = cf_section_find(request->server_cs, "load", "Cookie");
if (!unlang) {
RDEBUG2("Ignoring %s operation. Add \"load Cookie {}\" to virtual-server \"%s\""
" to handle", fr_int2str(ldap_sync_code_table, request->packet->code, "<INVALID>"),
/*
* Always cache the CONF_SECTION of the server.
*/
- parent_cs = cf_top_section(cs);
- listen->server_cs = cf_subsection_find_name2(parent_cs, "server", listen->server);
+ parent_cs = cf_root(cs);
+ listen->server_cs = cf_section_find(parent_cs, "server", listen->server);
if (!listen->server_cs) {
- cf_log_err_cs(cs, "Failed to find virtual server '%s'", listen->server);
+ cf_log_err(cs, "Failed to find virtual server '%s'", listen->server);
return -1;
}
/*
* Convert scope strings to enumerated constants
*/
- for (sync_cs = cf_subsection_find(cs, "sync"), i = 0;
+ for (sync_cs = cf_section_find(cs, "sync", NULL), i = 0;
sync_cs;
- sync_cs = cf_subsection_find_next(cs, sync_cs, "sync"), i++) {
+ sync_cs = cf_section_find_next(cs, sync_cs, "sync", NULL), i++) {
int scope;
void **tmp;
CONF_SECTION *map_cs;
scope = fr_str2int(fr_ldap_scope, inst->sync_config[i]->scope_str, -1);
if (scope < 0) {
- cf_log_err_cs(cs, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
+ cf_log_err(cs, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
", 'base' or 'children'"
#else
/*
* Parse and validate any maps
*/
- map_cs = cf_subsection_find(sync_cs, "update");
+ map_cs = cf_section_find(sync_cs, "update", NULL);
if (map_cs && map_afrom_cs(&inst->sync_config[i]->entry_map, map_cs,
PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, fr_ldap_map_verify, NULL,
LDAP_MAX_ATTRMAP) < 0) {
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, component) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
if (rcode > 0) found++;
if (found == 0) {
- cf_log_err_cs(server_cs, "At least one of 'recv [Present|Add|Delete|Modify] { ... }' "
+ cf_log_err(server_cs, "At least one of 'recv [Present|Add|Delete|Modify] { ... }' "
"sections must be present in virtual server %s", cf_section_name2(server_cs));
return -1;
fr_app_subtype_t const *app;
if (!value || !*value) {
- cf_log_err_cs(cs, "Must specify a value for 'type'");
+ cf_log_err(cs, "Must specify a value for 'type'");
return -1;
}
}
if (!code) {
- cf_log_err_cs(cs, "Unknown 'type = %s'", value);
+ cf_log_err(cs, "Unknown 'type = %s'", value);
return -1;
}
if (ctx->process[i]) {
- cf_log_err_cs(cs, "Duplicate 'type = %s'", value);
+ cf_log_err(cs, "Duplicate 'type = %s'", value);
return -1;
}
}
if (!lib) {
- cf_log_err_cs(cs, "Unknown 'type = %s'", value);
+ cf_log_err(cs, "Unknown 'type = %s'", value);
return -1;
}
cp = cf_pair_alloc(cs, "port_name", port_name,
T_OP_SET, T_BARE_WORD, T_BARE_WORD);
if (!cp) {
- cf_log_err_cs(cs, "Out of memory");
+ cf_log_err(cs, "Out of memory");
return -1;
}
*/
module = dl_module(server, NULL, lib, DL_TYPE_PROTO);
if (!module) {
- cf_log_err_cs(cs, "Failed finding submodule library for 'type = %s'", value);
+ cf_log_err(cs, "Failed finding submodule library for 'type = %s'", value);
return -1;
}
char buffer[256];
if (!value || !*value) {
- cf_log_err_cs(cs, "Must specify a value for 'transport'");
+ cf_log_err(cs, "Must specify a value for 'transport'");
return -1;
}
module = dl_module(server, NULL, buffer, DL_TYPE_PROTO);
if (!module) {
- cf_log_err_cs(cs, "Failed finding submodule library for 'transport = %s'", value);
+ cf_log_err(cs, "Failed finding submodule library for 'transport = %s'", value);
return -1;
}
/*
* Lookup io section.
*/
- io_cs = cf_subsection_find(cs, value);
+ io_cs = cf_section_find(cs, value, NULL);
if (!io_cs) {
- cf_log_err_cs(cs, "Must contain a '%s' section", value);
+ cf_log_err(cs, "Must contain a '%s' section", value);
return -1;
}
if (dl_instance_data_alloc(&io_ctx, NULL, module, io_cs) < 0) {
- cf_log_perr_cs(cs, "Failed io_ctx data");
+ cf_log_perr(cs, "Failed io_ctx data");
return -1;
}
cp = cf_pair_alloc(io_cs, "port_name", cf_pair_value(cp),
T_OP_SET, T_BARE_WORD, T_BARE_WORD);
if (!cp) {
- cf_log_err_cs(cs, "Out of memory");
+ cf_log_err(cs, "Out of memory");
return -1;
}
app_io = (fr_app_io_t const *) module->common;
if (app_io->instantiate(io_cs, io_ctx) < 0) {
- cf_log_err_cs(cs, "Failed instantiating 'transport = %s'", value);
+ cf_log_err(cs, "Failed instantiating 'transport = %s'", value);
talloc_free(io_ctx);
return -1;
}
if (verify_config) return 0;
if (app_io->op.open(io_ctx) < 0) {
- cf_log_err_cs(cs, "Failed opening I/O interface '%s'", value);
+ cf_log_err(cs, "Failed opening I/O interface '%s'", value);
return -1;
}
if ((cf_section_parse(cs, &config, cs, mod_config) < 0) ||
(cf_section_parse_pass2(&config, cs, mod_config) < 0)) {
- cf_log_err_cs(cs, "Failed parsing listen { ...}");
+ cf_log_err(cs, "Failed parsing listen { ...}");
return -1;
}
if (!config.types) {
- cf_log_err_cs(cs, "type MUST be specified");
+ cf_log_err(cs, "type MUST be specified");
return -1;
}
if (!config.transport) {
- cf_log_err_cs(cs, "transport MUST be specified");
+ cf_log_err(cs, "transport MUST be specified");
return -1;
}
ctx = talloc_zero(NULL, proto_radius_ctx_t);
if (!ctx) {
- cf_log_err_cs(cs, "Failed allocating memory");
+ cf_log_err(cs, "Failed allocating memory");
return -1;
}
*/
for (i = 0; i < talloc_array_length(config.types); i++) {
if (compile_type(ctx, server, cs, config.types[i]) < 0) {
- cf_log_err_cs(server, "Failed compiling unlang for 'type = %s'",
+ cf_log_err(server, "Failed compiling unlang for 'type = %s'",
config.types[i]);
return -1;
}
* Call transport-specific library to open the socket.
*/
if (open_transport(ctx, handle, server, cs, config.transport, verify_config) < 0) {
- cf_log_err_cs(server, "Failed opening connection for 'transport = %s'",
+ cf_log_err(server, "Failed opening connection for 'transport = %s'",
config.transport);
return -1;
}
*/
static int mod_parse(fr_schedule_t *handle, CONF_SECTION *cs, bool verify_config)
{
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
/*
* Load all of the listen sections. They do all of the
* dirty work.
*/
- for (subcs = cf_subsection_find_next(cs, NULL, "listen");
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, cs, "listen")) {
+ while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL))) {
if (open_listen(handle, cs, subcs, verify_config) < 0) {
return -1;
}
}
+ subcs = NULL;
+
/*
* Compile the sub-sections AFTER parsing all of the
* listen sections. This is mainly for nice debugging
* output. It's inefficient as heck, but it's pretty.
*/
- for (subcs = cf_subsection_find_next(cs, NULL, "listen");
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, cs, "listen")) {
+ while ((subcs = cf_section_find_next(cs, subcs, "listen", NULL))) {
CONF_PAIR *cp;
for (cp = cf_pair_find(subcs, "type");
value = cf_pair_value(cp);
- module = cf_data_find(cs, dl_t, value);
+ module = cf_data_value(cf_data_find(cs, dl_t, value));
if (!module) {
- cf_log_err_cs(cs, "Section missing module data");
+ cf_log_err(cs, "Section missing module data");
return -1;
}
if (cf_data_find(cs, char const *, value)) continue;
app = (fr_app_subtype_t const *) module->common;
if (app->instantiate(cs) < 0) {
- cf_log_err_cs(cs, "Failed compiling unlang for 'type = %s'", value);
+ cf_log_err(cs, "Failed compiling unlang for 'type = %s'", value);
return -1;
}
return FR_IO_FAIL;
}
- unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, "recv", dv->alias);
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
return FR_IO_FAIL;
}
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_RECV;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->reply->code));
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (!unlang) goto send_reply;
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_SEND;
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, component) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
}
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'recv Accounting-Request { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv Accounting-Request { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
goto setup_send;
}
- unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, "recv", dv->alias);
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
request->reply->code = FR_CODE_ACCESS_REJECT;
/*
* Push the conf section into the unlang stack.
*/
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_REJECT);
request->request_state = REQUEST_RECV;
goto setup_send;
}
- unlang = cf_subsection_find_name2(request->server_cs, "process", dv->alias);
+ unlang = cf_section_find(request->server_cs, "process", dv->alias);
if (!unlang) {
REDEBUG2("No 'process %s' section found: rejecting the user", dv->alias);
request->reply->code = FR_CODE_ACCESS_REJECT;
goto setup_send;
}
- RDEBUG("Running 'process %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'process %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOTFOUND);
request->request_state = REQUEST_PROCESS;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->reply->code));
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (!unlang) goto send_reply;
rerun_nak:
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_SEND;
unlang = NULL;
if (!dv) goto send_reply;
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
if (unlang) goto rerun_nak;
RWDEBUG("Not running 'send %s' section as it does not exist", dv->alias);
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, component) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
static int auth_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *listen_cs)
{
int rcode;
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
rcode = auth_compile_section(server_cs, "recv", "Access-Request", MOD_AUTHORIZE);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'recv Access-Request { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv Access-Request { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
rcode = auth_compile_section(server_cs, "send", "Access-Accept", MOD_POST_AUTH);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'send Access-Accept { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'send Access-Accept { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
rcode = auth_compile_section(server_cs, "send", "Access-Reject", MOD_POST_AUTH);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'send Access-Reject { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'send Access-Reject { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
rcode = auth_compile_section(server_cs, "send", "Access-Challenge", MOD_POST_AUTH);
if (rcode < 0) return rcode;
- for (subcs = cf_subsection_find_next(server_cs, NULL, "process");
- subcs != NULL;
- subcs = cf_subsection_find_next(server_cs, subcs, "process")) {
+ while ((subcs = cf_section_find_next(server_cs, subcs, "process", NULL))) {
char const *name2;
name2 = cf_section_name2(subcs);
if (!name2) {
- cf_log_err_cs(subcs, "Cannot compile 'process { ... }' section");
+ cf_log_err(subcs, "Cannot compile 'process { ... }' section");
return -1;
}
- cf_log_module(subcs, "Loading process %s {...}", name2);
+ cf_log_debug(subcs, "Loading process %s {...}", name2);
if (unlang_compile(subcs, MOD_AUTHENTICATE) < 0) {
- cf_log_err_cs(subcs, "Failed compiling 'process %s { ... }' section", name2);
+ cf_log_err(subcs, "Failed compiling 'process %s { ... }' section", name2);
return -1;
}
}
static int auth_listen_bootstrap(CONF_SECTION *server_cs, UNUSED CONF_SECTION *listen_cs)
{
- CONF_SECTION *subcs;
- fr_dict_attr_t const *da;
+ CONF_SECTION *subcs = NULL;;
+ fr_dict_attr_t const *da;
da = fr_dict_attr_by_num(NULL, 0, FR_AUTH_TYPE);
if (!da) {
- cf_log_err_cs(server_cs, "Failed finding dictionary definition for Auth-Type");
+ cf_log_err(server_cs, "Failed finding dictionary definition for Auth-Type");
return -1;
}
- for (subcs = cf_subsection_find_next(server_cs, NULL, "process");
- subcs != NULL;
- subcs = cf_subsection_find_next(server_cs, subcs, "process")) {
+ while ((subcs = cf_section_find_next(server_cs, subcs, "process", NULL))) {
char const *name2;
fr_value_box_t value = { .type = FR_TYPE_UINT32 };
fr_dict_enum_t *dv;
name2 = cf_section_name2(subcs);
if (!name2) {
- cf_log_err_cs(subcs, "Invalid 'process { ... }' section, it must have a name");
+ cf_log_err(subcs, "Invalid 'process { ... }' section, it must have a name");
return -1;
}
value.vb_uint32 = (fr_rand() & 0x00ffffff) + 1;
} while (fr_dict_enum_by_value(NULL, da, &value));
- cf_log_module(subcs, "Creating %s = %s", da->name, name2);
+ cf_log_debug(subcs, "Creating %s = %s", da->name, name2);
if (fr_dict_enum_add_alias(da, name2, &value, true, false) < 0) {
ERROR("%s", fr_strerror());
return -1;
return FR_IO_FAIL;
}
- unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, "recv", dv->alias);
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
return FR_IO_FAIL;
}
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_RECV;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->reply->code));
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (!unlang) goto send_reply;
* server as quickly as possible.
*/
rerun_nak:
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->log.unlang_indent = 0;
unlang = NULL;
if (!dv) goto send_reply;
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
if (unlang) goto rerun_nak;
RWDEBUG("Not running 'send %s' section as it does not exist", dv->alias);
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, component) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
if (rcode == 0) {
if (!coa_found) {
- cf_log_err_cs(server_cs, "Failed finding 'recv CoA-Request { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv CoA-Request { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
- cf_log_err_cs(server_cs, "Failed finding 'recv Disconnect-Request { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv Disconnect-Request { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
return FR_IO_FAIL;
}
- unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
+ unlang = cf_section_find(request->server_cs, "recv", dv->alias);
if (!unlang) {
RWDEBUG("Failed to find 'recv' section");
request->reply->code = FR_CODE_ACCESS_REJECT;
goto send_reply;
}
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_RECV;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->reply->code));
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (!unlang) goto send_reply;
rerun_nak:
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_SEND;
unlang = NULL;
if (!dv) goto send_reply;
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
if (unlang) goto rerun_nak;
RWDEBUG("Not running 'send %s' section as it does not exist", dv->alias);
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Compiling policies - %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Compiling policies - %s %s {...}", name1, name2);
/*
* FIXME: check if it's already compiled?
*/
if (unlang_compile(cs, component) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
rcode = mod_compile_section(server_cs, "recv", "Status-Server", MOD_AUTHORIZE);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'recv Status-Server { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv Status-Server { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
rcode = mod_compile_section(server_cs, "send", "Access-Accept", MOD_POST_AUTH);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'send Access-Accept { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'send Access-Accept { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
rcode = mod_compile_section(server_cs, "send", "Access-Reject", MOD_POST_AUTH);
if (rcode < 0) return rcode;
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'send Access-Reject { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'send Access-Reject { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
struct servent *s;
if (!inst->port_name) {
- cf_log_err_cs(cs, "No 'port' specified in 'udp' section");
+ cf_log_err(cs, "No 'port' specified in 'udp' section");
return -1;
}
s = getservbyname(inst->port_name, "udp");
if (!s) {
- cf_log_err_cs(cs, "Unknown value for 'port_name = %s", inst->port_name);
+ cf_log_err(cs, "Unknown value for 'port_name = %s", inst->port_name);
return -1;
}
request->server_cs = request->listener->server_cs;
request->component = "tacacs";
- unlang = cf_subsection_find_name2(request->server_cs, "recv", tacacs_lookup_packet_code(request->packet));
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, "recv", tacacs_lookup_packet_code(request->packet));
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
REDEBUG("Failed to find 'recv' section");
goto setup_send;
fr_state_to_request(global_state, request, request->packet);
}
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_REJECT);
request->request_state = REQUEST_RECV;
goto setup_send;
}
- unlang = cf_subsection_find_name2(request->server_cs, "process", dv->alias);
+ unlang = cf_section_find(request->server_cs, "process", dv->alias);
if (!unlang) {
REDEBUG2("No 'process %s' section found: rejecting the user.", dv->alias);
tacacs_status(request, RLM_MODULE_FAIL);
goto setup_send;
}
- RDEBUG("Running 'process %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'process %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOTFOUND);
request->request_state = REQUEST_PROCESS;
setup_send:
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", tacacs_lookup_packet_code(request->packet));
+ unlang = cf_section_find(request->server_cs, "send", tacacs_lookup_packet_code(request->packet));
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (!unlang) goto send_reply;
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(request, unlang, RLM_MODULE_NOOP);
request->request_state = REQUEST_SEND;
CONF_SECTION *cs;
int ret;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) {
- cf_log_err_cs(server_cs, "Failed finding '%s %s { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding '%s %s { ... }' section of virtual server %s",
name1, name2, cf_section_name2(server_cs));
return -1;
}
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
ret = unlang_compile(cs, component);
if (ret < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
static int tacacs_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *listen_cs)
{
int rcode;
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
rcode = tacacs_compile_section(server_cs, "recv", "Authentication", MOD_AUTHORIZE);
if (rcode < 0) return rcode;
rcode = tacacs_compile_section(server_cs, "send", "Accounting", MOD_ACCOUNTING);
if (rcode < 0) return rcode;
- for (subcs = cf_subsection_find_next(server_cs, NULL, "process");
- subcs != NULL;
- subcs = cf_subsection_find_next(server_cs, subcs, "process")) {
+ while ((subcs = cf_section_find_next(server_cs, subcs, "process", NULL))) {
char const *name2;
name2 = cf_section_name2(subcs);
goto done;
}
- unlang = cf_subsection_find_name2(request->server_cs, "recv", dv->alias);
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "recv", "*");
+ unlang = cf_section_find(request->server_cs, "recv", dv->alias);
+ if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*");
if (!unlang) {
RPEDEBUG("Failed to find 'recv' section");
goto done;
}
- RDEBUG("Running recv %s from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running recv %s from file %s", cf_section_name2(unlang), cf_filename(unlang));
rcode = unlang_interpret(request, unlang, RLM_MODULE_NOOP);
if (request->master_state == REQUEST_STOP_PROCESSING) goto done;
dv = fr_dict_enum_by_value(NULL, da, fr_box_uint32(request->reply->code));
unlang = NULL;
if (dv) {
- unlang = cf_subsection_find_name2(request->server_cs, "send", dv->alias);
+ unlang = cf_section_find(request->server_cs, "send", dv->alias);
}
- if (!unlang) unlang = cf_subsection_find_name2(request->server_cs, "send", "*");
+ if (!unlang) unlang = cf_section_find(request->server_cs, "send", "*");
if (unlang) {
- RDEBUG("Running send %s from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running send %s from file %s", cf_section_name2(unlang), cf_filename(unlang));
(void) unlang_interpret(request, unlang, RLM_MODULE_NOOP);
if (request->master_state == REQUEST_STOP_PROCESSING) goto done;
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, MOD_POST_AUTH) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
}
if (rcode == 0) {
- cf_log_err_cs(server_cs, "Failed finding 'recv VMPS-Join-Request { ... }' section of virtual server %s",
+ cf_log_err(server_cs, "Failed finding 'recv VMPS-Join-Request { ... }' section of virtual server %s",
cf_section_name2(server_cs));
return -1;
}
*/
inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
if (inst->rcode == RLM_MODULE_UNKNOWN) {
- cf_log_err_cs(conf, "rcode value \"%s\" is invalid", inst->rcode_str);
+ cf_log_err(conf, "rcode value \"%s\" is invalid", inst->rcode_str);
return -1;
}
inst->rcode_old = NULL; /* Hack - forces the compiler not to optimise away rcode_old */
* Sanity check for crazy people.
*/
if (strncmp(inst->config.driver_name, "rlm_cache_", 8) != 0) {
- cf_log_err_cs(conf, "\"%s\" is NOT an Cache driver!", inst->config.driver_name);
+ cf_log_err(conf, "\"%s\" is NOT an Cache driver!", inst->config.driver_name);
return -1;
}
name++;
}
- driver_cs = cf_subsection_find(conf, name);
+ driver_cs = cf_section_find(conf, name, NULL);
if (!driver_cs) {
driver_cs = cf_section_alloc(conf, name, NULL);
if (!driver_cs) return -1;
#endif
if (inst->config.ttl == 0) {
- cf_log_err_cs(conf, "Must set 'ttl' to non-zero");
+ cf_log_err(conf, "Must set 'ttl' to non-zero");
return -1;
}
if (inst->config.epoch != 0) {
- cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files");
+ cf_log_err(conf, "Must not set 'epoch' in the configuration files");
return -1;
}
- update = cf_subsection_find(inst->cs, "update");
+ update = cf_section_find(inst->cs, "update", CF_IDENT_ANY);
if (!update) {
- cf_log_err_cs(conf, "Must have an 'update' section in order to cache anything");
+ cf_log_err(conf, "Must have an 'update' section in order to cache anything");
return -1;
}
}
if (!inst->maps) {
- cf_log_err_cs(inst->cs, "Cache config must contain an update section, and "
+ cf_log_err(inst->cs, "Cache config must contain an update section, and "
"that section must not be empty");
return -1;
}
RDEBUG("No client found with IP \"%s\"", client_str);
return 0;
}
+
+ if (client->cs) {
+ char const *filename;
+ int line;
+
+ filename = cf_filename(client->cs);
+ line = cf_lineno(client->cs);
+
+ if (filename) {
+ RDEBUG2("Found client matching \"%s\". Defined in \"%s\" line %i",
+ client_str, filename, line);
+ } else {
+ RDEBUG2("Found client matching \"%s\"", client_str);
+ }
+ }
+
talloc_free(client_str);
} else {
client = request->client;
const char *attribute, *element; /* attribute and element names */
/* find update section */
- cs = cf_subsection_find(conf, "update");
+ cs = cf_section_find(conf, "update", NULL);
/* backwards compatibility */
if (!cs) {
- cs = cf_subsection_find(conf, "map");
+ cs = cf_section_find(conf, "map", NULL);
WARN("found deprecated 'map' section - please change to 'update'");
}
inst->map = json_object_new_object();
/* parse update section */
- for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
+ for (ci = cf_item_next(cs, NULL); ci != NULL; ci = cf_item_next(cs, ci)) {
/* validate item */
if (!cf_item_is_pair(ci)) {
ERROR("failed to parse invalid item in 'update' section");
CONF_SECTION *cs, *map, *tmpl; /* conf section */
/* attempt to find client section */
- cs = cf_subsection_find(conf, "client");
+ cs = cf_section_find(conf, "client", NULL);
if (!cs) {
ERROR("failed to find client section while loading clients");
/* fail */
}
/* attempt to find attribute subsection */
- map = cf_subsection_find(cs, "attribute");
+ map = cf_section_find(cs, "attribute", NULL);
if (!map) {
ERROR("failed to find attribute subsection while loading clients");
/* fail */
return -1;
}
- tmpl = cf_subsection_find(cs, "template");
+ tmpl = cf_section_find(cs, "template", NULL);
/* debugging */
DEBUG("preparing to load client documents");
for (p = buffer, i = 0; p != NULL; p = q, i++) {
if (!buf2entry(inst, p, &q)) {
- cf_log_err_cs(conf, "Malformed entry in file %s line %d", inst->filename, lineno);
+ cf_log_err(conf, "Malformed entry in file %s line %d", inst->filename, lineno);
return NULL;
}
if (q) *(q++) = '\0';
if (i >= inst->num_fields) {
- cf_log_err_cs(conf, "Too many fields at file %s line %d", inst->filename, lineno);
+ cf_log_err(conf, "Too many fields at file %s line %d", inst->filename, lineno);
return NULL;
}
}
if (i < inst->num_fields) {
- cf_log_err_cs(conf, "Too few fields at file %s line %d (%d < %d)", inst->filename, lineno, i, inst->num_fields);
+ cf_log_err(conf, "Too few fields at file %s line %d (%d < %d)", inst->filename, lineno, i, inst->num_fields);
return NULL;
}
* FIXME: Allow duplicate keys later.
*/
if (!rbtree_insert(inst->tree, e)) {
- cf_log_err_cs(conf, "Failed inserting entry for filename %s line %d: duplicate entry",
+ cf_log_err(conf, "Failed inserting entry for filename %s line %d: duplicate entry",
inst->filename, lineno);
return NULL;
}
vp_map_t const *map;
if (!src) {
- cf_log_err_cs(cs, "Missing file name");
+ cf_log_err(cs, "Missing file name");
return -1;
}
if (!inst->name) inst->name = cf_section_name1(conf);
if (inst->delimiter[1]) {
- cf_log_err_cs(conf, "'delimiter' must be one character long");
+ cf_log_err(conf, "'delimiter' must be one character long");
return -1;
}
}
if (inst->num_fields < 2) {
- cf_log_err_cs(conf, "Must have at least a key field and data field");
+ cf_log_err(conf, "Must have at least a key field and data field");
return -1;
}
inst->field_names = talloc_array(inst, const char *, inst->num_fields);
if (!inst->field_names) {
oom:
- cf_log_err_cs(conf, "Out of memory");
+ cf_log_err(conf, "Out of memory");
return -1;
}
}
if (inst->key_field < 0) {
- cf_log_err_cs(conf, "Key field '%s' does not appear in header", inst->key);
+ cf_log_err(conf, "Key field '%s' does not appear in header", inst->key);
return -1;
}
*/
fp = fopen(inst->filename, "r");
if (!fp) {
- cf_log_err_cs(conf, "Error opening filename %s: %s", inst->filename, strerror(errno));
+ cf_log_err(conf, "Error opening filename %s: %s", inst->filename, strerror(errno));
return -1;
}
inst->ef = module_exfile_init(inst, conf, 256, 30, inst->locking, NULL, NULL);
if (!inst->ef) {
- cf_log_err_cs(conf, "Failed creating log file context");
+ cf_log_err(conf, "Failed creating log file context");
return -1;
}
/*
* Suppress certain attributes.
*/
- cs = cf_subsection_find(conf, "suppress");
+ cs = cf_section_find(conf, "suppress", NULL);
if (cs) {
CONF_ITEM *ci;
inst->ht = fr_hash_table_create(NULL, detail_hash, detail_cmp, NULL);
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
char const *attr;
fr_dict_attr_t const *da;
da = fr_dict_attr_by_name(NULL, attr);
if (!da) {
- cf_log_err_cs(conf, "No such attribute '%s'", attr);
+ cf_log_err(conf, "No such attribute '%s'", attr);
return -1;
}
CONF_SECTION *tls_cs;
fr_tls_conf_t *tls_conf;
- parent = cf_section_parent(cs);
+ parent = cf_item_to_section(cf_parent(cs));
cp = cf_pair_find(cs, attr);
if (cp) {
tls_conf_name = cf_pair_value(cp);
- tls_cs = cf_subsection_find_name2(parent, TLS_CONFIG_SECTION, tls_conf_name);
+ tls_cs = cf_section_find(parent, TLS_CONFIG_SECTION, tls_conf_name);
if (!tls_cs) {
ERROR("Cannot find tls config \"%s\"", tls_conf_name);
return NULL;
* find the section - that is just a config error.
*/
INFO("TLS section \"%s\" missing, trying to use legacy configuration", attr);
- tls_cs = cf_subsection_find(parent, "tls");
+ tls_cs = cf_section_find(parent, "tls", NULL);
}
if (!tls_cs) return NULL;
int i, ret;
eap_type_t method;
int num_methods;
- CONF_SECTION *scs;
+ CONF_SECTION *scs = NULL;
rlm_eap_t *inst = instance;
/*
/* Load all the configured EAP-Types */
num_methods = 0;
- for (scs = cf_subsection_find_next(cs, NULL, NULL);
- scs != NULL;
- scs = cf_subsection_find_next(cs, scs, NULL)) {
-
+ while ((scs = cf_section_next(cs, scs))) {
char const *name;
name = cf_section_name1(scs);
method = eap_name2type(name);
if (method == FR_EAP_INVALID) {
- cf_log_err_cs(cs, "Unknown EAP type %s", name);
+ cf_log_err(cs, "Unknown EAP type %s", name);
return -1;
}
if ((method < FR_EAP_MD5) || (method >= FR_EAP_MAX_TYPES)) {
- cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name);
+ cf_log_err(cs, "Invalid EAP method %s (unsupported)", name);
return -1;
}
}
if (num_methods == 0) {
- cf_log_err_cs(cs, "No EAP method configured, module cannot do anything");
+ cf_log_err(cs, "No EAP method configured, module cannot do anything");
return -1;
}
}
if (!inst->methods[method]) {
- cf_log_err_cs(cs, "No such sub-type for default EAP method %s",
+ cf_log_err(cs, "No such sub-type for default EAP method %s",
inst->config.default_method_name);
return -1;
}
{
rlm_eap_fast_t *inst = talloc_get_type_abort(instance, rlm_eap_fast_t);
- if (!cf_subsection_find_name2(main_config.config, "server", inst->virtual_server)) {
+ if (!cf_section_find(main_config.config, "server", inst->virtual_server)) {
cf_log_err_by_name(cs, "virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
return -1;
}
*/
request->password = vp;
- unlang = cf_subsection_find_name2(request->server_cs, "process", inst->auth_type_name);
+ unlang = cf_section_find(request->server_cs, "process", inst->auth_type_name);
if (!unlang) {
/*
* Call the authenticate section of the *current* virtual server.
fr_dict_enum_t const *dv;
if (inst->identity && (strlen(inst->identity) > 255)) {
- cf_log_err_cs(cs, "identity is too long");
+ cf_log_err(cs, "identity is too long");
return -1;
}
dv = fr_dict_enum_by_alias(NULL, fr_dict_attr_by_num(NULL, 0, FR_AUTH_TYPE), "MS-CHAP");
if (!dv) dv = fr_dict_enum_by_alias(NULL, fr_dict_attr_by_num(NULL, 0, FR_AUTH_TYPE), "MSCHAP");
if (!dv) {
- cf_log_err_cs(cs, "Failed to find 'Auth-Type MS-CHAP' section. Cannot authenticate users.");
+ cf_log_err(cs, "Failed to find 'Auth-Type MS-CHAP' section. Cannot authenticate users.");
return -1;
}
inst->auth_type_mschap = dv->value->vb_uint32;
rlm_eap_peap_t *inst = talloc_get_type_abort(instance, rlm_eap_peap_t);
fr_dict_enum_t *dv;
- if (!cf_subsection_find_name2(main_config.config, "server", inst->virtual_server)) {
+ if (!cf_section_find(main_config.config, "server", inst->virtual_server)) {
cf_log_err_by_name(cs, "virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
return -1;
}
if (inst->soh_virtual_server) {
- if (!cf_subsection_find_name2(main_config.config, "server", inst->soh_virtual_server)) {
+ if (!cf_section_find(main_config.config, "server", inst->soh_virtual_server)) {
cf_log_err_by_name(cs, "soh_virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
return -1;
}
rlm_eap_pwd_t *inst = talloc_get_type_abort(instance, rlm_eap_pwd_t);
if (inst->fragment_size < 100) {
- cf_log_err_cs(cs, "Fragment size is too small");
+ cf_log_err(cs, "Fragment size is too small");
return -1;
}
static int mod_instantiate(UNUSED rlm_eap_config_t const *config, UNUSED void *instance, CONF_SECTION *cs)
{
fr_dict_attr_t const *da;
- CONF_SECTION *subcs;
+ CONF_SECTION *subcs = NULL;
da = fr_dict_attr_child_by_num(dict_sim_root, FR_EAP_SIM_SUBTYPE);
if (!da) {
- cf_log_err_cs(cs, "Failed to find EAP-Sim-Subtype attribute");
+ cf_log_err(cs, "Failed to find EAP-Sim-Subtype attribute");
return -1;
}
- for (subcs = cf_subsection_find_next(cs, NULL, "process");
- subcs != NULL;
- subcs = cf_subsection_find_next(cs, subcs, "process")) {
+ while ((subcs = cf_section_find_next(cs, subcs, "process", NULL))) {
char const *name2;
fr_dict_enum_t *dv;
name2 = cf_section_name2(subcs);
if (!name2) {
- cf_log_err_cs(subcs, "Cannot compile 'process { ... }' section");
+ cf_log_err(subcs, "Cannot compile 'process { ... }' section");
return -1;
}
dv = fr_dict_enum_by_alias(NULL, da, name2);
if (!dv) {
- cf_log_err_cs(subcs, "Unknown EAP-SIM-Subtype %s", name2);
+ cf_log_err(subcs, "Unknown EAP-SIM-Subtype %s", name2);
return -1;
}
- cf_log_module(subcs, "Loading process %s {...}", name2);
+ cf_log_debug(subcs, "Loading process %s {...}", name2);
if (unlang_compile(subcs, MOD_AUTHORIZE) < 0) {
- cf_log_err_cs(subcs, "Failed compiling 'process %s { ... }' section", name2);
+ cf_log_err(subcs, "Failed compiling 'process %s { ... }' section", name2);
return -1;
}
}
{
rlm_eap_ttls_t *inst = talloc_get_type_abort(instance, rlm_eap_ttls_t);
- if (!cf_subsection_find_name2(main_config.config, "server", inst->virtual_server)) {
+ if (!cf_section_find(main_config.config, "server", inst->virtual_server)) {
cf_log_err_by_name(cs, "virtual_server", "Unknown virtual server '%s'", inst->virtual_server);
return -1;
}
* Do more work here
*/
if (!inst->boolean) {
- cf_log_err_cs(conf, "Boolean is false: forcing error!");
+ cf_log_err(conf, "Boolean is false: forcing error!");
return -1;
}
p = inst->input;
p += radius_list_name(&inst->input_list, p, PAIR_LIST_UNKNOWN);
if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
- cf_log_err_cs(conf, "Invalid input list '%s'", inst->input);
+ cf_log_err(conf, "Invalid input list '%s'", inst->input);
return -1;
}
}
p = inst->output;
p += radius_list_name(&inst->output_list, p, PAIR_LIST_UNKNOWN);
if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
- cf_log_err_cs(conf, "Invalid output list '%s'", inst->output);
+ cf_log_err(conf, "Invalid output list '%s'", inst->output);
return -1;
}
}
* then the output pairs must not be defined.
*/
if (!inst->wait && (inst->output != NULL)) {
- cf_log_err_cs(conf, "Cannot read output pairs if wait = no");
+ cf_log_err(conf, "Cannot read output pairs if wait = no");
return -1;
}
dval = fr_dict_enum_by_alias(NULL, fr_dict_attr_by_num(NULL, 0, FR_PACKET_TYPE), inst->packet_type);
if (!dval) {
- cf_log_err_cs(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
+ cf_log_err(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
"share/dictionary", inst->packet_type);
return -1;
}
inst->timeout = EXEC_TIMEOUT;
}
if (inst->timeout < 1) {
- cf_log_err_cs(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
+ cf_log_err(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
return -1;
}
/*
* Blocking a request longer than max_request_time isn't going to help anyone.
*/
if (inst->timeout > main_config.max_request_time) {
- cf_log_err_cs(conf, "Timeout '%d' is too large (maximum: %d)", inst->timeout, main_config.max_request_time);
+ cf_log_err(conf, "Timeout '%d' is too large (maximum: %d)", inst->timeout, main_config.max_request_time);
return -1;
}
rlm_json_jpath_cache_t *cache = cache_inst, **tail = &cache->next;
if (!src) {
- cf_log_err_cs(cs, "Missing JSON source");
+ cf_log_err(cs, "Missing JSON source");
return -1;
}
#ifndef HAVE_JSON_OBJECT_GET_INT64
if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->tmpl_da->type == FR_TYPE_UINT64)) {
- cf_log_err_cp(cp, "64bit integers are not supported by linked json-c. "
+ cf_log_err(cp, "64bit integers are not supported by linked json-c. "
"Upgrade to json-c >= 0.10 to use this feature");
return -1;
}
error:
fr_canonicalize_error(cache, &spaces, &text, slen, fr_strerror());
- cf_log_err_cp(cp, "Syntax error");
- cf_log_err_cp(cp, "%s", p);
- cf_log_err_cp(cp, "%s^ %s", spaces, text);
+ cf_log_err(cp, "Syntax error");
+ cf_log_err(cp, "%s", p);
+ cf_log_err(cp, "%s^ %s", spaces, text);
talloc_free(spaces);
talloc_free(text);
case TMPL_TYPE_DATA:
if (map->rhs->tmpl_value_type != FR_TYPE_STRING) {
- cf_log_err_cp(cp, "Right side of map must be a string");
+ cf_log_err(cp, "Right side of map must be a string");
return -1;
}
p = map->rhs->tmpl_value.vb_strvalue;
{
CONF_ITEM const *ci;
- for (ci = cf_item_find_next(cs, NULL);
+ for (ci = cf_item_next(cs, NULL);
ci != NULL;
- ci = cf_item_find_next(cs, ci)) {
+ ci = cf_item_next(cs, ci)) {
char const *value;
if (cf_item_is_section(ci)) {
vp_tmpl_t const *src, UNUSED vp_map_t const *maps)
{
if (!src) {
- cf_log_err_cs(cs, "Missing LDAP URI");
+ cf_log_err(cs, "Missing LDAP URI");
return -1;
}
goto error;
}
- cs = cf_subsection_find(cf_item_to_section(ci), "update");
+ cs = cf_section_find(cf_item_to_section(ci), "update", NULL);
if (!cs) {
REDEBUG("Section must contain 'update' subsection");
/*
* Iterate over all the pairs, building our mods array
*/
- for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
+ for (ci = cf_item_next(cs, NULL); ci != NULL; ci = cf_item_next(cs, ci)) {
bool do_xlat = false;
if (total == LDAP_MAX_ATTRMAP) {
continue;
}
- switch (cf_pair_value_type(cp)) {
+ switch (cf_pair_value_quote(cp)) {
case T_BARE_WORD:
case T_SINGLE_QUOTED_STRING:
break;
char const *name = section_type_value[comp].section;
- cs = cf_subsection_find(parent, name);
+ cs = cf_section_find(parent, name, NULL);
if (!cs) {
DEBUG2("rlm_ldap (%s) - Couldn't find configuration for %s, will return NOOP for calls "
"from this section", inst->name, name);
inst->cs = conf;
- options = cf_subsection_find(conf, "options");
+ options = cf_section_find(conf, "options", NULL);
if (!options || !cf_pair_find(options, "chase_referrals")) {
inst->handle_config.chase_referrals_unset = true; /* use OpenLDAP defaults */
}
*/
if ((parse_sub_section(inst, conf, &inst->accounting, MOD_ACCOUNTING) < 0) ||
(parse_sub_section(inst, conf, &inst->postauth, MOD_POST_AUTH) < 0)) {
- cf_log_err_cs(conf, "Failed parsing configuration");
+ cf_log_err(conf, "Failed parsing configuration");
goto error;
}
*/
if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
if (!inst->groupobj_name_attr) {
- cf_log_err_cs(conf, "Configuration item 'group.name_attribute' must be set if cacheable "
+ cf_log_err(conf, "Configuration item 'group.name_attribute' must be set if cacheable "
"group names are enabled");
goto error;
*/
if (!cf_pair_find(conf, "pool")) {
if (!inst->handle_config.server_str) {
- cf_log_err_cs(conf, "Configuration item 'server' must have a value");
+ cf_log_err(conf, "Configuration item 'server' must have a value");
goto error;
}
}
#ifndef WITH_SASL
if (inst->user_sasl.mech) {
- cf_log_err_cs(conf, "Configuration item 'user.sasl.mech' not supported. "
+ cf_log_err(conf, "Configuration item 'user.sasl.mech' not supported. "
"Linked libldap does not provide fr_ldap_sasl_bind( function");
goto error;
}
if (inst->handle_config.admin_sasl.mech) {
- cf_log_err_cs(conf, "Configuration item 'sasl.mech' not supported. "
+ cf_log_err(conf, "Configuration item 'sasl.mech' not supported. "
"Linked libldap does not provide fr_ldap_sasl_interactive_bind function");
goto error;
}
#ifndef HAVE_LDAP_CREATE_SORT_CONTROL
if (inst->userobj_sort_by) {
- cf_log_err_cs(conf, "Configuration item 'sort_by' not supported. "
+ cf_log_err(conf, "Configuration item 'sort_by' not supported. "
"Linked libldap does not provide ldap_create_sort_control function");
goto error;
}
#ifndef HAVE_LDAP_URL_PARSE
if (inst->use_referral_credentials) {
- cf_log_err_cs(conf, "Configuration item 'use_referral_credentials' not supported. "
+ cf_log_err(conf, "Configuration item 'use_referral_credentials' not supported. "
"Linked libldap does not support URL parsing");
goto error;
}
case ' ':
case ',':
case ';':
- cf_log_err_cs(conf, "Invalid character '%c' found in 'server' configuration item",
+ cf_log_err(conf, "Invalid character '%c' found in 'server' configuration item",
value[j]);
goto error;
char *p;
if (ldap_url_parse(value, &ldap_url)){
- cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", value);
+ cf_log_err(conf, "Parsing LDAP URL \"%s\" failed", value);
ldap_url_error:
ldap_free_urldesc(ldap_url);
return -1;
}
if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
- cf_log_err_cs(conf, "Base DN cannot be specified via server URL");
+ cf_log_err(conf, "Base DN cannot be specified via server URL");
goto ldap_url_error;
}
if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
- cf_log_err_cs(conf, "Attribute list cannot be specified via server URL");
+ cf_log_err(conf, "Attribute list cannot be specified via server URL");
goto ldap_url_error;
}
* ldap_url_parse sets this to base by default.
*/
if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
- cf_log_err_cs(conf, "Scope cannot be specified via server URL");
+ cf_log_err(conf, "Scope cannot be specified via server URL");
goto ldap_url_error;
}
ldap_url->lud_scope = -1; /* Otherwise LDAP adds ?base */
if (ldap_url->lud_scheme) {
if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) {
if (inst->handle_config.start_tls == true) {
- cf_log_err_cs(conf, "ldaps:// scheme is not compatible "
+ cf_log_err(conf, "ldaps:// scheme is not compatible "
"with 'start_tls'");
goto ldap_url_error;
}
url = ldap_url_desc2str(ldap_url);
if (!url) {
- cf_log_err_cs(conf, "Failed recombining URL components");
+ cf_log_err(conf, "Failed recombining URL components");
goto ldap_url_error;
}
inst->handle_config.server = talloc_asprintf_append(inst->handle_config.server, "%s ", url);
((strcmp(ldap_url->lud_scheme, "ldaps") == 0) ||
(strcmp(ldap_url->lud_scheme, "ldapi") == 0) ||
(strcmp(ldap_url->lud_scheme, "cldap") == 0))) {
- cf_log_err_cs(conf, "%s is not supported by linked libldap",
+ cf_log_err(conf, "%s is not supported by linked libldap",
ldap_url->lud_scheme);
return -1;
}
if (strchr(value, '/')) {
bad_server_fmt:
#ifdef LDAP_CAN_PARSE_URLS
- cf_log_err_cs(conf, "Invalid 'server' entry, must be in format <server>[:<port>] or "
+ cf_log_err(conf, "Invalid 'server' entry, must be in format <server>[:<port>] or "
"an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
#else
- cf_log_err_cs(conf, "Invalid 'server' entry, must be in format <server>[:<port>]");
+ cf_log_err(conf, "Invalid 'server' entry, must be in format <server>[:<port>]");
#endif
return -1;
}
inst->handle_config.dereference = fr_str2int(fr_ldap_dereference,
inst->handle_config.dereference_str, -1);
if (inst->handle_config.dereference < 0) {
- cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
+ cf_log_err(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
"'finding' or 'always'", inst->handle_config.dereference_str);
goto error;
}
* variable for the username, password, etc.
*/
if (inst->rebind == true) {
- cf_log_err_cs(conf, "Cannot use 'rebind' configuration item as this version of libldap "
+ cf_log_err(conf, "Cannot use 'rebind' configuration item as this version of libldap "
"does not support the API that we need");
goto error;
*/
inst->userobj_scope = fr_str2int(fr_ldap_scope, inst->userobj_scope_str, -1);
if (inst->userobj_scope < 0) {
- cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
+ cf_log_err(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
", 'base' or 'children'"
#else
inst->groupobj_scope = fr_str2int(fr_ldap_scope, inst->groupobj_scope_str, -1);
if (inst->groupobj_scope < 0) {
- cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
+ cf_log_err(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
", 'base' or 'children'"
#else
inst->clientobj_scope = fr_str2int(fr_ldap_scope, inst->clientobj_scope_str, -1);
if (inst->clientobj_scope < 0) {
- cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
+ cf_log_err(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
#ifdef LDAP_SCOPE_CHILDREN
", 'base' or 'children'"
#else
ret = ldap_create_sort_keylist(&keys, p);
if (ret != LDAP_SUCCESS) {
- cf_log_err_cs(conf, "Invalid user.sort_by value \"%s\": %s",
+ cf_log_err(conf, "Invalid user.sort_by value \"%s\": %s",
inst->userobj_sort_by, ldap_err2string(ret));
goto error;
}
inst->handle_config.tls_require_cert = fr_str2int(fr_ldap_tls_require_cert,
inst->handle_config.tls_require_cert_str, -1);
if (inst->handle_config.tls_require_cert < 0) {
- cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
+ cf_log_err(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
"'demand', 'allow', 'try' or 'hard'", inst->handle_config.tls_require_cert_str);
goto error;
}
#else
- cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
+ cf_log_err(conf, "Modifying 'tls.require_cert' is not supported by current "
"version of libldap. Please upgrade or substitute current libldap and "
"rebuild this module");
/*
* Build the attribute map
*/
- update = cf_subsection_find(inst->cs, "update");
+ update = cf_section_find(inst->cs, "update", NULL);
if (update && (map_afrom_cs(&inst->user_map, update,
PAIR_LIST_REPLY, PAIR_LIST_REQUEST, fr_ldap_map_verify, NULL,
LDAP_MAX_ATTRMAP) < 0)) {
if (inst->do_clients) {
CONF_SECTION *cs, *map, *tmpl;
- cs = cf_subsection_find(inst->cs, "client");
+ cs = cf_section_find(inst->cs, "client", NULL);
if (!cs) {
- cf_log_err_cs(conf, "Told to load clients but no client section found");
+ cf_log_err(conf, "Told to load clients but no client section found");
goto error;
}
- map = cf_subsection_find(cs, "attribute");
+ map = cf_section_find(cs, "attribute", NULL);
if (!map) {
- cf_log_err_cs(cs, "Told to load clients but no attribute section found");
+ cf_log_err(cs, "Told to load clients but no attribute section found");
goto error;
}
- tmpl = cf_subsection_find(cs, "template");
+ tmpl = cf_section_find(cs, "template", NULL);
if (rlm_ldap_client_load(inst, tmpl, map) < 0) {
- cf_log_err_cs(cs, "Error loading clients");
+ cf_log_err(cs, "Error loading clients");
return -1;
}
inst->log_dst = fr_str2int(linefr_log_dst_table, inst->log_dst_str, LINELOG_DST_INVALID);
if (inst->log_dst == LINELOG_DST_INVALID) {
- cf_log_err_cs(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
+ cf_log_err(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
return -1;
}
if (!inst->log_src && !inst->log_ref) {
- cf_log_err_cs(conf, "Must specify a log format, or reference");
+ cf_log_err(conf, "Must specify a log format, or reference");
return -1;
}
case LINELOG_DST_FILE:
{
if (!inst->file.name) {
- cf_log_err_cs(conf, "No value provided for 'filename'");
+ cf_log_err(conf, "No value provided for 'filename'");
return -1;
}
inst->file.ef = module_exfile_init(inst, conf, 256, 30, true, NULL, NULL);
if (!inst->file.ef) {
- cf_log_err_cs(conf, "Failed creating log file context");
+ cf_log_err(conf, "Failed creating log file context");
return -1;
}
inst->file.group = strtol(inst->file.group_str, &endptr, 10);
if (*endptr != '\0') {
if (rad_getgid(inst, &(inst->file.group), inst->file.group_str) < 0) {
- cf_log_err_cs(conf, "Unable to find system group \"%s\"",
+ cf_log_err(conf, "Unable to find system group \"%s\"",
inst->file.group_str);
return -1;
}
int num;
#ifndef HAVE_SYSLOG_H
- cf_log_err_cs(conf, "Syslog output is not supported on this system");
+ cf_log_err(conf, "Syslog output is not supported on this system");
return -1;
#else
if (inst->syslog.facility) {
num = fr_str2int(syslog_facility_table, inst->syslog.facility, -1);
if (num < 0) {
- cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog.facility);
+ cf_log_err(conf, "Invalid syslog facility \"%s\"", inst->syslog.facility);
return -1;
}
inst->syslog.priority |= num;
num = fr_str2int(syslog_severity_table, inst->syslog.severity, -1);
if (num < 0) {
- cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog.severity);
+ cf_log_err(conf, "Invalid syslog severity \"%s\"", inst->syslog.severity);
return -1;
}
inst->syslog.priority |= num;
case LINELOG_DST_UNIX:
#ifndef HAVE_SYS_UN_H
- cf_log_err_cs(conf, "Unix sockets are not supported on this sytem");
+ cf_log_err(conf, "Unix sockets are not supported on this sytem");
return -1;
#else
- inst->pool = module_connection_pool_init(cf_subsection_find(conf, "unix"),
+ inst->pool = module_connection_pool_init(cf_section_find(conf, "unix", NULL),
inst, mod_conn_create, NULL, prefix, NULL, NULL);
if (!inst->pool) return -1;
#endif
break;
case LINELOG_DST_UDP:
- inst->pool = module_connection_pool_init(cf_subsection_find(conf, "udp"),
+ inst->pool = module_connection_pool_init(cf_section_find(conf, "udp", NULL),
inst, mod_conn_create, NULL, prefix, NULL, NULL);
if (!inst->pool) return -1;
break;
case LINELOG_DST_TCP:
- inst->pool = module_connection_pool_init(cf_subsection_find(conf, "tcp"),
+ inst->pool = module_connection_pool_init(cf_section_find(conf, "tcp", NULL),
inst, mod_conn_create, NULL, prefix, NULL, NULL);
if (!inst->pool) return -1;
break;
* using request as the context (which will hopefully avoid an alloc).
*/
slen = tmpl_afrom_str(request, &vpt, tmpl_str, talloc_array_length(tmpl_str) - 1,
- cf_pair_value_type(cp), REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ cf_pair_value_quote(cp), REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
if (slen <= 0) {
REMARKER(tmpl_str, -slen, fr_strerror());
return RLM_MODULE_FAIL;
rlm_logintime_t *inst = instance;
if (inst->min_time == 0) {
- cf_log_err_cs(conf, "Invalid value '0' for minimum_timeout");
+ cf_log_err(conf, "Invalid value '0' for minimum_timeout");
return -1;
}
inst->log_dst = fr_str2int(logtee_dst_table, inst->log_dst_str, LOGTEE_DST_INVALID);
if (inst->log_dst == LOGTEE_DST_INVALID) {
- cf_log_err_cs(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
+ cf_log_err(conf, "Invalid log destination \"%s\"", inst->log_dst_str);
return -1;
}
*/
switch (inst->log_dst) {
case LOGTEE_DST_FILE:
- cf_log_err_cs(conf, "Teeing to files NYI");
+ cf_log_err(conf, "Teeing to files NYI");
return -1;
case LOGTEE_DST_UNIX:
#ifndef HAVE_SYS_UN_H
- cf_log_err_cs(conf, "Unix sockets are not supported on this sytem");
+ cf_log_err(conf, "Unix sockets are not supported on this sytem");
return -1;
#endif
DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
- while ((ci = cf_item_find_next(cs, ci))) {
+ while ((ci = cf_item_next(cs, ci))) {
if (cf_item_is_section(ci)) {
CONF_SECTION *sub_cs = cf_item_to_section(ci);
char const *key = cf_section_name1(sub_cs);
/* Convert a FreeRADIUS config structure into a mruby hash */
inst->mrubyconf_hash = mrb_hash_new(mrb);
- cs = cf_subsection_find(conf, "config");
+ cs = cf_section_find(conf, "config", NULL);
if (cs) mruby_parse_config(mrb, cs, 0, inst->mrubyconf_hash);
/* Define the Request class */
inst->wb_pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
if (!inst->wb_pool) {
- cf_log_err_cs(conf, "Unable to initialise winbind connection pool");
+ cf_log_err(conf, "Unable to initialise winbind connection pool");
return -1;
}
#else
- cf_log_err_cs(conf, "'winbind' auth not enabled at compiled time");
+ cf_log_err(conf, "'winbind' auth not enabled at compiled time");
return -1;
#endif
}
inst->ntlm_auth_timeout = EXEC_TIMEOUT;
}
if (inst->ntlm_auth_timeout < 1) {
- cf_log_err_cs(conf, "ntml_auth_timeout '%d' is too small (minimum: 1)",
+ cf_log_err(conf, "ntml_auth_timeout '%d' is too small (minimum: 1)",
inst->ntlm_auth_timeout);
return -1;
}
if (inst->ntlm_auth_timeout > 10) {
- cf_log_err_cs(conf, "ntlm_auth_timeout '%d' is too large (maximum: 10)",
+ cf_log_err(conf, "ntlm_auth_timeout '%d' is too large (maximum: 10)",
inst->ntlm_auth_timeout);
return -1;
}
rad_assert(inst->format && *inst->format);
if (inst->hash_size == 0) {
- cf_log_err_cs(conf, "Invalid value '0' for hash_size");
+ cf_log_err(conf, "Invalid value '0' for hash_size");
return -1;
}
s++;
}while(*s);
if(keyfield < 0) {
- cf_log_err_cs(conf, "no field marked as key in format: %s",
+ cf_log_err(conf, "no field marked as key in format: %s",
inst->format);
return -1;
}
if (*inst->pwdfmt->field[i] == '~') inst->pwdfmt->field[i]++;
}
if (!*inst->pwdfmt->field[keyfield]) {
- cf_log_err_cs(conf, "key field is empty");
+ cf_log_err(conf, "key field is empty");
release_ht(inst->ht);
inst->ht = NULL;
return -1;
CONF_ITEM *ci = NULL;
- while ((ci = cf_item_find_next(cs, ci))) {
+ while ((ci = cf_item_next(cs, ci))) {
/*
* This is a section.
* Create a new HV, store it as a reference in current HV,
}
/* parse perl configuration sub-section */
- cs = cf_subsection_find(conf, "config");
+ cs = cf_section_find(conf, "config", NULL);
if (cs) {
inst->rad_perlconf_hv = get_hv("RAD_PERLCONF", 1);
perl_parse_config(cs, 0, inst->rad_perlconf_hv);
DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
- while ((ci = cf_item_find_next(cs, ci))) {
+ while ((ci = cf_item_next(cs, ci))) {
/*
* This is a section.
* Create a new dict, store it in current dict,
*/
if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0) goto error;
- cs = cf_subsection_find(conf, "config");
+ cs = cf_section_find(conf, "config", NULL);
if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
} else {
inst->module = main_module;
}
if (child->reply) {
- unlang = cf_subsection_find_name2(inst->server_cs, "recv", fr_packet_codes[child->reply->code]);
+ unlang = cf_section_find(inst->server_cs, "recv", fr_packet_codes[child->reply->code]);
} else {
- unlang = cf_subsection_find_name2(inst->server_cs, "recv", "timeout");
+ unlang = cf_section_find(inst->server_cs, "recv", "timeout");
}
if (!unlang) goto done;
- RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(child, unlang, RLM_MODULE_NOOP);
child->request_state = REQUEST_RECV;
*/
if (!inst->server_cs) return mod_wait_for_reply(request, inst, ccr);
- unlang = cf_subsection_find_name2(inst->server_cs, "send", fr_packet_codes[packet->code]);
+ unlang = cf_section_find(inst->server_cs, "send", fr_packet_codes[packet->code]);
if (!unlang) return mod_wait_for_reply(request, inst, ccr);
- RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_section_filename(unlang));
+ RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
unlang_push_section(child, unlang, RLM_MODULE_NOOP);
child->request_state = REQUEST_SEND;
{
CONF_SECTION *cs;
- cs = cf_subsection_find_name2(server_cs, name1, name2);
+ cs = cf_section_find(server_cs, name1, name2);
if (!cs) return 0;
- cf_log_module(cs, "Loading %s %s {...}", name1, name2);
+ cf_log_debug(cs, "Loading %s %s {...}", name1, name2);
if (unlang_compile(cs, MOD_AUTHORIZE) < 0) {
- cf_log_err_cs(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
+ cf_log_err(cs, "Failed compiling '%s %s { ... }' section", name1, name2);
return -1;
}
inst->name = cf_section_name2(config);
if (!inst->name) inst->name = cf_section_name1(config);
- cs = cf_subsection_find_next(config, NULL, "home_server");
+ cs = cf_section_find(config, "home_server", NULL);
if (!cs) {
- cf_log_err_cs(config, "You must specify at least one home server");
+ cf_log_err(config, "You must specify at least one home server");
return -1;
}
- if (cf_subsection_find_next(config, cs, "home_server") != NULL) {
- cf_log_err_cs(config, "Too many home servers were given.");
+ if (cf_section_find_next(config, cs, "home_server", NULL) != NULL) {
+ cf_log_err(config, "Too many home servers were given.");
return -1;
}
home = home_server_afrom_cs(config, NULL, cs);
if (!home) {
- cf_log_err_cs(config, "Failed parsing home server");
+ cf_log_err(config, "Failed parsing home server");
return -1;
}
#ifdef WITH_TCP
if (home->proto != IPPROTO_UDP) {
- cf_log_err_cs(config, "Only home servers of 'proto = udp' are allowed.");
+ cf_log_err(config, "Only home servers of 'proto = udp' are allowed.");
return -1;
}
#endif
if (home->ping_check != HOME_PING_CHECK_NONE) {
- cf_log_err_cs(config, "Only home servers of 'status_check = none' is allowed.");
+ cf_log_err(config, "Only home servers of 'status_check = none' is allowed.");
return -1;
}
if (!inst->virtual_server) return RLM_MODULE_OK;
- cs = cf_subsection_find_name2(main_config.config, "server", inst->virtual_server);
+ cs = cf_section_find(main_config.config, "server", inst->virtual_server);
if (!cs) {
- cf_log_err_cs(config, "Unknown virtual server '%s'.", inst->virtual_server);
+ cf_log_err(config, "Unknown virtual server '%s'.", inst->virtual_server);
return RLM_MODULE_FAIL;
}
break;
default:
- cf_log_err_cs(config, "Internal sanity check error");
+ cf_log_err(config, "Internal sanity check error");
return -1;
}
inst->format = REALM_FORMAT_PREFIX;
} else {
- cf_log_err_cs(conf, "Invalid value \"%s\" for format",
+ cf_log_err(conf, "Invalid value \"%s\" for format",
inst->format_string);
return -1;
}
if (strcmp(inst->delim, "\\\\") == 0) {
/* it's OK */
} else if (strlen(inst->delim) != 1) {
- cf_log_err_cs(conf, "Invalid value \"%s\" for delimiter",
+ cf_log_err(conf, "Invalid value \"%s\" for delimiter",
inst->delim);
return -1;
}
snprintf(buffer, sizeof(buffer), "%s [%i]", cluster->log_prefix, node->id);
node->addr = node->pending_addr;
- node->pool = fr_pool_init(cluster, cf_subsection_find(cluster->module, "pool"), node,
+ node->pool = fr_pool_init(cluster, cf_section_find(cluster->module, "pool", NULL), node,
fr_redis_cluster_conn_create, NULL, buffer);
if (!node->pool) return CLUSTER_OP_FAILED;
fr_pool_reconnect_func(node->pool, _cluster_node_conf_apply);
/*
* Ensure we always have a pool section (even if it's empty)
*/
- mycs = cf_subsection_find(module, "pool");
+ mycs = cf_section_find(module, "pool", NULL);
if (!mycs) {
mycs = cf_section_alloc(module, "pool", NULL);
cf_section_add(module, mycs);
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
static bool done_hash = false;
- CONF_SECTION *subcs = cf_subsection_find_next(conf, NULL, "redis");
+ CONF_SECTION *subcs = cf_section_find(conf, "redis", NULL);
rlm_redis_ippool_t *inst = instance;
/*
* Set some alternative default pool settings
*/
- pool_cs = cf_subsection_find(conf->cs, "pool");
+ pool_cs = cf_section_find(conf->cs, "pool", NULL);
if (!pool_cs) {
pool_cs = cf_section_alloc(conf->cs, "pool", NULL);
cf_section_add(conf->cs, pool_cs);
return RLM_MODULE_NOOP;
}
- cs = cf_subsection_find(inst->cs, dv->alias);
+ cs = cf_section_find(inst->cs, dv->alias, NULL);
if (!cs) {
RDEBUG("No subsection %s", dv->alias);
return RLM_MODULE_NOOP;
{
CONF_SECTION *cs;
- cs = cf_subsection_find(parent, name);
+ cs = cf_section_find(parent, name, NULL);
if (!cs) {
config->name = NULL;
return 0;
* Sanity check
*/
if ((config->username && !config->password) || (!config->username && config->password)) {
- cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");
+ cf_log_err(cs, "'username' and 'password' must both be set or both be absent");
return -1;
}
*/
config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
if (config->auth == HTTP_AUTH_UNKNOWN) {
- cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
+ cf_log_err(cs, "Unknown HTTP auth type '%s'", config->auth_str);
return -1;
} else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
- cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
+ cf_log_err(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
"configuration, then recompile this module", config->auth_str);
return -1;
}
if (config->body == HTTP_BODY_UNKNOWN) {
- cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str);
+ cf_log_err(cs, "Unknown HTTP body type '%s'", config->body_str);
return -1;
}
switch (http_body_type_supported[config->body]) {
case HTTP_BODY_UNSUPPORTED:
- cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\", please submit patches",
+ cf_log_err(cs, "Unsupported HTTP body type \"%s\", please submit patches",
config->body_str);
return -1;
case HTTP_BODY_INVALID:
- cf_log_err_cs(cs, "Invalid HTTP body type. \"%s\" is not a valid web API data "
+ cf_log_err(cs, "Invalid HTTP body type. \"%s\" is not a valid web API data "
"markup format", config->body_str);
return -1;
case HTTP_BODY_UNAVAILABLE:
- cf_log_err_cs(cs, "Unavailable HTTP body type. \"%s\" is not available in this "
+ cf_log_err(cs, "Unavailable HTTP body type. \"%s\" is not available in this "
"build", config->body_str);
return -1;
}
if (config->force_to == HTTP_BODY_UNKNOWN) {
- cf_log_err_cs(cs, "Unknown forced response body type '%s'", config->force_to_str);
+ cf_log_err(cs, "Unknown forced response body type '%s'", config->force_to_str);
return -1;
}
switch (http_body_type_supported[config->force_to]) {
case HTTP_BODY_UNSUPPORTED:
- cf_log_err_cs(cs, "Unsupported forced response body type \"%s\", please submit patches",
+ cf_log_err(cs, "Unsupported forced response body type \"%s\", please submit patches",
config->force_to_str);
return -1;
case HTTP_BODY_INVALID:
- cf_log_err_cs(cs, "Invalid HTTP forced response body type. \"%s\" is not a valid web API data "
+ cf_log_err(cs, "Invalid HTTP forced response body type. \"%s\" is not a valid web API data "
"markup format", config->force_to_str);
return -1;
* Fixme should be conf->gt_is_set
*/
if (!conf->ssn_is_set && !conf->pc_is_set && !conf->gt.address) {
- cf_log_err_cs(cs, "At least one of 'pc', 'ssn', or 'gt', must be set");
+ cf_log_err(cs, "At least one of 'pc', 'ssn', or 'gt', must be set");
return -1;
}
if (conf->ssn_is_set) out->ssn = conf->ssn;
if (conf->pc_is_set) {
if (conf->pc > 16777215) {
- cf_log_err_cs(cs, "Invalid value \"%d\" for 'pc', must be between 0-"
+ cf_log_err(cs, "Invalid value \"%d\" for 'pc', must be between 0-"
STRINGIFY(16777215), conf->pc);
return -1;
}
size_t len = talloc_array_length(conf->gt.address) - 1;
if (conf->gt.nai_is_set && (conf->gt.nai & 0x80)) {
- cf_log_err_cs(cs, "Global title 'nai' must be between 0-127");
+ cf_log_err(cs, "Global title 'nai' must be between 0-127");
return -1;
}
if (conf->gt.tt_is_set) {
if ((conf->gt.np_is_set && !conf->gt.es_is_set) ||
(!conf->gt.np_is_set && conf->gt.np_is_set)) {
- cf_log_err_cs(cs, "Global title 'np' and 'es' must be "
+ cf_log_err(cs, "Global title 'np' and 'es' must be "
"specified together");
return -1;
}
if (conf->gt.np) {
- cf_log_err_cs(cs, "Global title 'np' must be between 0-15");
+ cf_log_err(cs, "Global title 'np' must be between 0-15");
return -1;
}
if (conf->gt.es > 0x0f) {
- cf_log_err_cs(cs, "Global title 'es' must be between 0-15");
+ cf_log_err(cs, "Global title 'es' must be between 0-15");
return -1;
}
for (i = 0; i < len; i++) {
if (!is_char_tbcd[(uint8_t)conf->gt.address[i]]) {
- cf_log_err_cs(cs, "Global title address contains invalid digit \"%c\". "
+ cf_log_err(cs, "Global title address contains invalid digit \"%c\". "
"Valid digits are [0-9#*a-c]", conf->gt.address[i]);
return -1;
}
inst->conn_conf.m3ua_traffic_mode = fr_str2int(m3ua_traffic_mode_table,
inst->conn_conf.m3ua_traffic_mode_str, -1);
if (inst->conn_conf.m3ua_traffic_mode < 0) {
- cf_log_err_cs(conf, "Invalid 'm3ua_traffic_mode' value \"%s\", expected 'override', "
+ cf_log_err(conf, "Invalid 'm3ua_traffic_mode' value \"%s\", expected 'override', "
"'loadshare' or 'broadcast'", inst->conn_conf.m3ua_traffic_mode_str);
return -1;
}
#define MTP3_PC_CHECK(_x) \
do { \
if (inst->conn_conf.mtp3_##_x > 16777215) { \
- cf_log_err_cs(conf, "Invalid value \"%d\" for '#_x', must be between 0-16777215", \
+ cf_log_err(conf, "Invalid value \"%d\" for '#_x', must be between 0-16777215", \
inst->conn_conf.mtp3_##_x); \
return -1; \
} \
*/
inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
if (inst->rcode == RLM_MODULE_UNKNOWN) {
- cf_log_err_cs(conf, "Unknown module return code '%s'", inst->rcode_str);
+ cf_log_err(conf, "Unknown module return code '%s'", inst->rcode_str);
return -1;
}
* This has to be done before we call cf_section_parse
* as it sets default values, and creates the section.
*/
- if (cf_subsection_find(cs, "tls")) do_tls = true;
- if (cf_subsection_find(cs, "latency_aware_routing")) do_latency_aware_routing = true;
+ if (cf_section_find(cs, "tls"), NULL) do_tls = true;
+ if (cf_section_find(cs, "latency_aware_routing"), NULL) do_latency_aware_routing = true;
DEBUG4("Configuring CassCluster structure");
cluster = inst->cluster = cass_cluster_new();
CONF_SECTION *cs;
char const *name;
- cs = cf_section_parent(conf);
+ cs = cf_item_to_section(cf_parent(conf));
name = cf_section_name2(cs);
if (!name) name = cf_section_name1(cs);
vp_tmpl_t const *src, UNUSED vp_map_t const *maps)
{
if (!src) {
- cf_log_err_cs(cs, "Missing SQL query");
+ cf_log_err(cs, "Missing SQL query");
return -1;
}
/*
* Get the module's subsection or allocate one
*/
- driver_cs = cf_subsection_find(conf, name);
+ driver_cs = cf_section_find(conf, name, NULL);
if (!driver_cs) {
driver_cs = cf_section_alloc(conf, name, NULL);
if (!driver_cs) return -1;
* configuration. So if that doesn't exist, we ignore
* the whole subsection.
*/
- inst->config->accounting.cs = cf_subsection_find(conf, "accounting");
+ inst->config->accounting.cs = cf_section_find(conf, "accounting", NULL);
inst->config->accounting.reference_cp = (cf_pair_find(inst->config->accounting.cs, "reference") != NULL);
- inst->config->postauth.cs = cf_subsection_find(conf, "post-auth");
+ inst->config->postauth.cs = cf_section_find(conf, "post-auth", NULL);
inst->config->postauth.reference_cp = (cf_pair_find(inst->config->postauth.cs, "reference") != NULL);
/*
inst->ef = module_exfile_init(inst, conf, 256, 30, true, NULL, NULL);
if (!inst->ef) {
- cf_log_err_cs(conf, "Failed creating log file context");
+ cf_log_err(conf, "Failed creating log file context");
return -1;
}
inst->reset_time = 0;
if (find_next_reset(inst, now) == -1) {
- cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
+ cf_log_err(conf, "Invalid reset '%s'", inst->reset);
return -1;
}
inst->last_reset = 0;
if (find_prev_reset(inst, now) < 0) {
- cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
+ cf_log_err(conf, "Invalid reset '%s'", inst->reset);
return -1;
}
memset(&flags, 0, sizeof(flags));
flags.compare = 1; /* ugly hack */
if (tmpl_define_undefined_attr(inst->paircmp_attr, FR_TYPE_UINT64, &flags) < 0) {
- cf_log_err_cs(conf, "Failed defining counter attribute: %s", fr_strerror());
+ cf_log_err(conf, "Failed defining counter attribute: %s", fr_strerror());
return -1;
}
flags.compare = 0;
if (tmpl_define_undefined_attr(inst->limit_attr, FR_TYPE_UINT64, &flags) < 0) {
- cf_log_err_cs(conf, "Failed defining check attribute: %s", fr_strerror());
+ cf_log_err(conf, "Failed defining check attribute: %s", fr_strerror());
return -1;
}
if (inst->paircmp_attr->tmpl_da->type != FR_TYPE_UINT64) {
- cf_log_err_cs(conf, "Counter attribute %s MUST be uint64",
+ cf_log_err(conf, "Counter attribute %s MUST be uint64",
inst->paircmp_attr->tmpl_da->name);
return -1;
}
if (paircompare_register_byname(inst->paircmp_attr->tmpl_da->name, NULL, true,
counter_cmp, inst) < 0) {
- cf_log_err_cs(conf, "Failed registering comparison function for counter attribute %s: %s",
+ cf_log_err(conf, "Failed registering comparison function for counter attribute %s: %s",
inst->paircmp_attr->tmpl_da->name, fr_strerror());
return -1;
}
if (inst->limit_attr->tmpl_da->type != FR_TYPE_UINT64) {
- cf_log_err_cs(conf, "Check attribute %s MUST be uint64",
+ cf_log_err(conf, "Check attribute %s MUST be uint64",
inst->limit_attr->tmpl_da->name);
return -1;
}
inst->sincesync = 0;
- sql_inst = module_find(cf_subsection_find(main_config.config, "modules"), inst->sql_instance_name);
+ sql_inst = module_find(cf_section_find(main_config.config, "modules", NULL), inst->sql_instance_name);
if (!sql_inst) {
- cf_log_err_cs(conf, "Cannot find SQL module instance named \"%s\"",
+ cf_log_err(conf, "Cannot find SQL module instance named \"%s\"",
inst->sql_instance_name);
return -1;
}
/* check if the given instance is really a rlm_sql instance */
if (strcmp(inst->sql_inst->driver->name, "sql") != 0) {
- cf_log_err_cs(conf, "Module \"%s\" is not an instance of the rlm_sql module",
+ cf_log_err(conf, "Module \"%s\" is not an instance of the rlm_sql module",
inst->sql_instance_name);
return -1;
}
} else {
inst->pool_name = talloc_typed_strdup(inst, "ippool");
}
- sql_inst = module_find(cf_subsection_find(main_config.config, "modules"), inst->sql_instance_name);
+ sql_inst = module_find(cf_section_find(main_config.config, "modules", NULL), inst->sql_instance_name);
if (!sql_inst) {
- cf_log_err_cs(conf, "failed to find sql instance named %s",
+ cf_log_err(conf, "failed to find sql instance named %s",
inst->sql_instance_name);
return -1;
}
inst->sql_inst = (rlm_sql_t *) sql_inst->data;
if (strcmp(inst->sql_inst->driver->name, "sql") != 0) {
- cf_log_err_cs(conf, "Module \"%s\" is not an instance of the rlm_sql module",
+ cf_log_err(conf, "Module \"%s\" is not an instance of the rlm_sql module",
inst->sql_instance_name);
return -1;
}
if (!inst->name) inst->name = cf_section_name1(conf);
if (inst->timeout > 10000) {
- cf_log_err_cs(conf, "timeout must be 0 to 10000");
+ cf_log_err(conf, "timeout must be 0 to 10000");
return -1;
}
if (xlat_register(inst, inst->xlat_a_name, xlat_a, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) ||
xlat_register(inst, inst->xlat_aaaa_name, xlat_aaaa, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) ||
xlat_register(inst, inst->xlat_ptr_name, xlat_ptr, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN)) {
- cf_log_err_cs(conf, "Failed registering xlats");
+ cf_log_err(conf, "Failed registering xlats");
return -1;
}
inst->ub = ub_ctx_create();
if (!inst->ub) {
- cf_log_err_cs(conf, "ub_ctx_create failed");
+ cf_log_err(conf, "ub_ctx_create failed");
return -1;
}
* dup it so libunbound doesn't close it on us.
*/
if (log_fd == -1) {
- cf_log_err_cs(conf, "Could not dup fd");
+ cf_log_err(conf, "Could not dup fd");
goto error_nores;
}
inst->log_stream = fdopen(log_fd, "w");
if (!inst->log_stream) {
- cf_log_err_cs(conf, "error setting up log stream");
+ cf_log_err(conf, "error setting up log stream");
goto error_nores;
}
inst->log_fd = ub_fd(inst->ub);
if (inst->log_fd >= 0) {
if (fr_event_fd_insert(inst->el, inst->log_fd, ub_fd_handler, NULL, NULL, inst) < 0) {
- cf_log_err_cs(conf, "could not insert async fd");
+ cf_log_err(conf, "could not insert async fd");
inst->log_fd = -1;
goto error_nores;
}
return 0;
error:
- cf_log_err_cs(conf, "%s", ub_strerror(res));
+ cf_log_err(conf, "%s", ub_strerror(res));
error_nores:
if (log_fd > -1) close(log_fd);
struct wbcInterfaceDetails *wb_info = NULL;
if (!inst->wb_username) {
- cf_log_err_cs(conf, "winbind_username must be defined to use rlm_winbind");
+ cf_log_err(conf, "winbind_username must be defined to use rlm_winbind");
return -1;
}
inst->wb_pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
if (!inst->wb_pool) {
- cf_log_err_cs(conf, "Unable to initialise winbind connection pool");
+ cf_log_err(conf, "Unable to initialise winbind connection pool");
return -1;
}
wbcErr err;
struct wbcContext *wb_ctx;
- cf_log_err_cs(conf, "winbind_domain unspecified; trying to get it from winbind");
+ cf_log_err(conf, "winbind_domain unspecified; trying to get it from winbind");
wb_ctx = wbcCtxCreate();
if (!wb_ctx) {
/* this should be very unusual */
- cf_log_err_cs(conf, "Unable to get libwbclient context, cannot get domain");
+ cf_log_err(conf, "Unable to get libwbclient context, cannot get domain");
goto no_domain;
}
wbcCtxFree(wb_ctx);
if (err != WBC_ERR_SUCCESS) {
- cf_log_err_cs(conf, "libwbclient returned wbcErr code %d; unable to get domain name.", err);
- cf_log_err_cs(conf, "Is winbind running and does the winbind_privileged socket have");
- cf_log_err_cs(conf, "the correct permissions?");
+ cf_log_err(conf, "libwbclient returned wbcErr code %d; unable to get domain name.", err);
+ cf_log_err(conf, "Is winbind running and does the winbind_privileged socket have");
+ cf_log_err(conf, "the correct permissions?");
goto no_domain;
}
if (!wb_info->netbios_domain) {
- cf_log_err_cs(conf, "winbind returned blank domain name");
+ cf_log_err(conf, "winbind returned blank domain name");
goto no_domain;
}
strlen(wb_info->netbios_domain), T_SINGLE_QUOTED_STRING,
REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
- cf_log_err_cs(conf, "Using winbind_domain '%s'", inst->wb_domain->name);
+ cf_log_err(conf, "Using winbind_domain '%s'", inst->wb_domain->name);
no_domain:
wbcFreeMemory(wb_info);
#ifndef HAVE_YUBIKEY
if (inst->decrypt) {
- cf_log_err_cs(conf, "Requires libyubikey for OTP decryption");
+ cf_log_err(conf, "Requires libyubikey for OTP decryption");
return -1;
}
#endif
#ifdef HAVE_YKCLIENT
CONF_SECTION *cs;
- cs = cf_subsection_find(conf, "validation");
+ cs = cf_section_find(conf, "validation", CF_IDENT_ANY);
if (!cs) {
- cf_log_err_cs(conf, "Missing validation section");
+ cf_log_err(conf, "Missing validation section");
return -1;
}
return -1;
}
#else
- cf_log_err_cs(conf, "Requires libykclient for OTP validation against Yubicloud servers");
+ cf_log_err(conf, "Requires libykclient for OTP validation against Yubicloud servers");
return -1;
#endif
}
status = ykclient_init(&inst->ykc);
if (status != YKCLIENT_OK) goto yk_error;
- servers = cf_subsection_find(conf, "servers");
+ servers = cf_section_find(conf, "servers", CF_IDENT_ANY);
if (servers) {
CONF_PAIR *uri, *first;
/*
allow_vulnerable_openssl = yes
}
+home_server test.example.com {
+ ipaddr = 127.0.0.1
+ port = ${test_port}
+ secret = testing123
+}
+
+home_server_pool test.example.com {
+ home_server = test.example.com
+}
+
realm test.example.com {
- authhost = 127.0.0.1:${test_port}
- secret = testing123
+ auth_pool = test.example.com
}
policy {
--- /dev/null
+User-Name := bob
+User-Password := bob