]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Remove many type specific functions from the conf_file api
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 13 Jun 2017 14:12:46 +0000 (10:12 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 13 Jun 2017 14:12:58 +0000 (10:12 -0400)
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

93 files changed:
src/include/conf_file.h
src/include/cursor.h
src/include/rbtree.h
src/include/token.h
src/include/xlat.h
src/lib/util/cursor.c
src/lib/util/rbtree.c
src/lib/util/token.c
src/main/client.c
src/main/command.c
src/main/conf_file.c
src/main/dl.c
src/main/listen.c
src/main/mainconfig.c
src/main/map.c
src/main/modules.c
src/main/pool.c
src/main/radmin.c
src/main/radwho.c
src/main/realms.c
src/main/threads.c
src/main/tls/conf.c
src/main/trigger.c
src/main/unit_test_map.c
src/main/unit_test_module.c
src/main/unlang_compile.c
src/main/unlang_interpret.c
src/main/version.c
src/main/virtual_servers.c
src/main/xlat_func.c
src/modules/proto_arp/proto_arp.c
src/modules/proto_bfd/proto_bfd.c
src/modules/proto_detail/proto_detail.c
src/modules/proto_dhcp/proto_dhcp.c
src/modules/proto_ldap_sync/proto_ldap_sync.c
src/modules/proto_radius/proto_radius.c
src/modules/proto_radius/proto_radius_acct.c
src/modules/proto_radius/proto_radius_auth.c
src/modules/proto_radius/proto_radius_coa.c
src/modules/proto_radius/proto_radius_status.c
src/modules/proto_radius/proto_radius_udp.c
src/modules/proto_tacacs/proto_tacacs.c
src/modules/proto_vmps/proto_vmps.c
src/modules/rlm_always/rlm_always.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_client/rlm_client.c
src/modules/rlm_couchbase/mod.c
src/modules/rlm_couchbase/rlm_couchbase.c
src/modules/rlm_csv/rlm_csv.c
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_eap/lib/base/eap_tls.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c
src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c
src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c
src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
src/modules/rlm_example/rlm_example.c
src/modules/rlm_exec/rlm_exec.c
src/modules/rlm_json/rlm_json.c
src/modules/rlm_ldap/clients.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_logintime/rlm_logintime.c
src/modules/rlm_logtee/rlm_logtee.c
src/modules/rlm_mruby/rlm_mruby.c
src/modules/rlm_mschap/rlm_mschap.c
src/modules/rlm_passwd/rlm_passwd.c
src/modules/rlm_perl/rlm_perl.c
src/modules/rlm_python/rlm_python.c
src/modules/rlm_radius_client/rlm_radius_client.c
src/modules/rlm_realm/rlm_realm.c
src/modules/rlm_redis/cluster.c
src/modules/rlm_redis_ippool/rlm_redis_ippool.c
src/modules/rlm_redis_ippool/rlm_redis_ippool_tool.c
src/modules/rlm_rediswho/rlm_rediswho.c
src/modules/rlm_rest/rlm_rest.c
src/modules/rlm_sigtran/rlm_sigtran.c
src/modules/rlm_sometimes/rlm_sometimes.c
src/modules/rlm_sql/drivers/rlm_sql_cassandra/rlm_sql_cassandra.c
src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sqlcounter/rlm_sqlcounter.c
src/modules/rlm_sqlhpwippool/rlm_sqlhpwippool.c
src/modules/rlm_sqlippool/rlm_sqlippool.c
src/modules/rlm_unbound/rlm_unbound.c
src/modules/rlm_winbind/rlm_winbind.c
src/modules/rlm_yubikey/rlm_yubikey.c
src/modules/rlm_yubikey/validate.c
src/tests/config/test.conf
user_password [new file with mode: 0644]

index 1ac9d50ed98dc910a79e9af68115fbebf0387c6d..31e830713920b8ecfeee51f74e780722a248fbd6 100644 (file)
@@ -43,8 +43,8 @@ extern "C" {
  */
 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.
 
@@ -426,118 +426,179 @@ typedef struct CONF_PARSER {
 #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
index 7f1b48d96cca47a609f4477d9eff12df153e774a..bdc01e212363b5e7709d94b697d08a184f22d899 100644 (file)
@@ -49,7 +49,7 @@ typedef struct fr_cursor_s {
        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);
 
index eea96d6a2feb400c4917a6bf98a14e18fb58e0f7..adf03acef8aa1491bf35c7aa86aa9aa9bb92b635 100644 (file)
@@ -51,7 +51,7 @@ typedef void (*rb_free_t)(void *data);
 
 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);
index c2faccc63b3ed948cd768d902f2d0119750b3638..07bccdf50261b3c15dcb62929ebb4794fe112e6a 100644 (file)
@@ -71,6 +71,7 @@ typedef struct FR_NAME_NUMBER {
 } 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[];
index f46d9113a5d704acfe7783000dd8d5559ac20725..a346a3eb49023b5c7c00c370a5646bf4dce0c9f0 100644 (file)
@@ -97,7 +97,7 @@ int           xlat_register(void *mod_inst, char const *name,
 
 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
index ad6e6a505421f29bc10ee8e980cb7db525a0fb19..02b69ab829d06315808195cfba9e73216a53b8fb 100644 (file)
@@ -117,7 +117,7 @@ static inline void *cursor_tail(void **prev, fr_cursor_t *cursor, void *current)
  * @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));
 }
index 0a0664849b773d922598e56a136909dbc4629cc3..9998f642b439abbca3a2d27175902afe60f594ce 100644 (file)
@@ -279,7 +279,6 @@ rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data)
        rbnode_t *current, *parent, *x;
 
        if (!tree->root) return NULL;
-
        if (tree->lock) pthread_mutex_lock(&tree->mutex);
 
        /* find where node belongs */
@@ -347,11 +346,15 @@ rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data)
        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;
 }
 
index f6542c54034647ce6a0e1c4aa86cc2d57359a064..28709f13cf9213ad3b5cb8910fa906d0cc162872 100644 (file)
@@ -53,6 +53,13 @@ const FR_NAME_NUMBER fr_tokens_table[] = {
        { 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
index c2b408b39bf4457f2e00942a9801d5d19cb466e2..6a9cdb2a095575784df7a5baa93e0c06ef2a1824 100644 (file)
@@ -219,7 +219,7 @@ bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
                        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;
@@ -229,14 +229,14 @@ bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
                         *      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) {
@@ -519,7 +519,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
 #endif
 {
        bool            global = false;
-       CONF_SECTION    *cs;
+       CONF_SECTION    *cs = NULL;
        RADCLIENT       *c = NULL;
        RADCLIENT_LIST  *clients = NULL;
        CONF_SECTION    *server_cs = NULL;
@@ -528,7 +528,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
         *      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;
 
        /*
@@ -542,7 +542,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
         *      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;
 
@@ -550,9 +550,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
         *      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:
@@ -567,7 +565,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
                 *      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
@@ -596,7 +594,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
 
                        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;
                        }
 
@@ -604,7 +602,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
 
                        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;
                        }
 
@@ -635,7 +633,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
 
                                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;
                                }
@@ -655,7 +653,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
        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;
                }
 
@@ -665,7 +663,7 @@ RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls
         *      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;
        }
@@ -734,7 +732,7 @@ bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c
                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;
@@ -788,9 +786,9 @@ int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_
 {
        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;
@@ -806,7 +804,7 @@ int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_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);
@@ -827,7 +825,7 @@ int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_
                 *      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;
@@ -847,7 +845,7 @@ int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_
                 */
                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;
                }
@@ -874,7 +872,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
 
        name2 = cf_section_name2(cs);
        if (!name2) {
-               cf_log_err_cs(cs, "Missing client name");
+               cf_log_err(cs, "Missing client name");
                return NULL;
        }
 
@@ -886,7 +884,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
 
        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
@@ -902,13 +900,13 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
         */
        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;
                }
 
@@ -944,7 +942,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
         *      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;
        }
@@ -974,7 +972,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
                        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;
                }
        }
@@ -989,14 +987,14 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
                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;
@@ -1029,13 +1027,13 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
 
                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;
                }
 
@@ -1068,7 +1066,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
 #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;
                }
        }
@@ -1090,7 +1088,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
                                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;
                        }
                /*
@@ -1099,7 +1097,7 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *serv
                 *      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;
 
@@ -1379,7 +1377,7 @@ RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
                        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));
@@ -1492,7 +1490,7 @@ RADCLIENT *client_read(char const *filename, CONF_SECTION *server_cs, bool check
                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;
index e96c37723960f6d71232455d7d2760377792e02e..26ca46071e951657cb738876d6c5a2c7f7e68ee3 100644 (file)
@@ -842,7 +842,7 @@ static int command_hup(rad_listen_t *listener, int argc, char *argv[])
                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]);
@@ -1009,7 +1009,7 @@ static int command_show_module_config(rad_listen_t *listener, int argc, char *ar
                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]);
@@ -1046,7 +1046,7 @@ static int command_show_module_methods(rad_listen_t *listener, int argc, char *a
                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]);
@@ -1073,7 +1073,7 @@ static int command_show_module_flags(rad_listen_t *listener, int argc, char *arg
                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]);
@@ -1097,7 +1097,7 @@ static int command_show_module_status(rad_listen_t *listener, int argc, char *ar
                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]);
@@ -1124,11 +1124,11 @@ static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED
 {
        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);
 
@@ -2482,7 +2482,7 @@ static int command_set_module_config(rad_listen_t *listener, int argc, char *arg
                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]);
@@ -2560,7 +2560,7 @@ static int command_set_module_status(rad_listen_t *listener, int argc, char *arg
                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]);
@@ -3243,7 +3243,7 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
 
 #ifdef WITH_TLS
        if (this->tls) {
-               cf_log_err_cs(cs,
+               cf_log_err(cs,
                           "TLS is not supported for control sockets");
                return -1;
        }
@@ -3251,7 +3251,7 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
 
        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;
        }
index e6cfa280335ca01c27746a1f74f8bc61f3c48040..cdb5af6a37308e114cb332b68642f2fbfb4154e6 100644 (file)
@@ -1,12 +1,4 @@
 /*
- * 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>
@@ -48,6 +55,8 @@ static uid_t conf_check_uid = (uid_t)-1;
 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,
@@ -72,12 +81,24 @@ typedef enum conf_type {
 #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
@@ -91,9 +112,11 @@ struct cf_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?
 };
@@ -107,24 +130,16 @@ struct cf_section {
        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.
 };
 
@@ -136,8 +151,9 @@ struct cf_data {
 
        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 {
@@ -148,182 +164,367 @@ 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;
 }
@@ -331,7 +532,7 @@ static int data_cmp(void const *a, void const *b)
 /*
  *     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;
@@ -353,24 +554,19 @@ static FILE *cf_file_open(CONF_SECTION *cs, char const *filename)
        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;
@@ -394,29 +590,11 @@ static FILE *cf_file_open(CONF_SECTION *cs, char const *filename)
         *
         *      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.
@@ -436,8 +614,8 @@ static bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_per
        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);
@@ -519,22 +697,20 @@ static bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_per
        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.
@@ -548,7 +724,6 @@ static int file_callback(void *ctx, void *data)
         *      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);
@@ -561,3263 +736,3435 @@ static int file_callback(void *ctx, void *data)
        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);
@@ -3836,260 +4183,200 @@ char const *cf_section_name(CONF_SECTION const *cs)
        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;
@@ -4102,7 +4389,7 @@ static void _pair_count(int *count, CONF_SECTION const *cs)
 /** 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)
 {
@@ -4113,66 +4400,55 @@ 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
@@ -4194,6 +4470,7 @@ static CONF_DATA *cf_data_alloc(CONF_ITEM *parent, void const *data, char const
 
        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
@@ -4216,130 +4493,110 @@ static CONF_DATA *cf_data_alloc(CONF_ITEM *parent, void const *data, char const
 
 /** 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;
 }
@@ -4362,9 +4619,15 @@ static int _cf_data_walk_cb(void *ctx, void *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));
@@ -4375,7 +4638,7 @@ static int _cf_data_walk_cb(void *ctx, void *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.
@@ -4383,7 +4646,7 @@ static int _cf_data_walk_cb(void *ctx, void *data)
  *     - 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,
@@ -4391,420 +4654,281 @@ int _cf_data_walk(CONF_SECTION *cs, char const *type, cf_walker_t cb, void *ctx)
                .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 */
index f76d8a12050ab995b637d3e231d41fa31a9fc17e..e9dbef72a7cb1999606b81938ba08b17376c7aa3 100644 (file)
@@ -224,9 +224,9 @@ static int dl_magic_verify(CONF_SECTION const *cs, dl_common_t const *module)
 
        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));
@@ -235,9 +235,9 @@ static int dl_magic_verify(CONF_SECTION const *cs, dl_common_t const *module)
 
        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));
@@ -246,9 +246,9 @@ static int dl_magic_verify(CONF_SECTION const *cs, dl_common_t const *module)
 
        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));
@@ -416,7 +416,7 @@ int dl_instance_data_alloc(void **data, TALLOC_CTX *ctx, dl_t const *module, CON
                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;
        }
@@ -707,8 +707,8 @@ dl_t const *dl_module(CONF_SECTION *conf, dl_t const *parent, char const *name,
         */
        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);
@@ -721,7 +721,7 @@ dl_t const *dl_module(CONF_SECTION *conf, dl_t const *parent, char const *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;
        }
 
@@ -744,17 +744,17 @@ dl_t const *dl_module(CONF_SECTION *conf, dl_t const *parent, char const *name,
         *      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;
        }
 
index 1a428616f5e4d2cf6b96618830d85d4abce24630..45b2e1bce411af49661fa4110451f5c8a7369345 100644 (file)
@@ -100,14 +100,14 @@ int listen_compile(CONF_SECTION *server, CONF_SECTION *cs)
        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;
        }
 
@@ -137,13 +137,13 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
 
        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;
        }
 
@@ -154,14 +154,14 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
        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;
                }
        }
@@ -199,7 +199,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                        }
 
                        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);
@@ -213,13 +213,13 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                 *      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;
                }
@@ -232,7 +232,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
         */
        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;
        }
@@ -254,7 +254,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                } 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;
                        }
 
@@ -265,7 +265,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                                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;
                        }
                }
@@ -274,7 +274,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                 *      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;
                }
@@ -287,7 +287,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
                 *      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;
                }
@@ -300,23 +300,23 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_
         *
         *      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;
                }
        }
@@ -457,7 +457,7 @@ RADCLIENT *client_listener_find(rad_listen_t *listener,
                 *      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) &&
@@ -1328,7 +1328,7 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
 
        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
@@ -1354,18 +1354,18 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
                         */
                        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.
@@ -1393,19 +1393,19 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        /*
         *      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;
                }
@@ -1472,7 +1472,7 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        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;
                }
@@ -1491,19 +1491,19 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
         *      (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;
                }
@@ -1528,17 +1528,17 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
         *      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, &section_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. */
@@ -1547,9 +1547,9 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        /*
         *      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;
        }
 
@@ -1560,7 +1560,7 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
         *      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;
@@ -1573,7 +1573,7 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        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;
        }
@@ -1588,7 +1588,7 @@ int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
 
                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;
                }
        }
@@ -1609,7 +1609,7 @@ int common_socket_open(CONF_SECTION *cs, rad_listen_t *this)
        /* 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;
                }
@@ -1623,7 +1623,7 @@ int common_socket_open(CONF_SECTION *cs, rad_listen_t *this)
         */
        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);
@@ -3211,8 +3211,8 @@ int listen_init(rad_listen_t **head,
        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;
                }
index 64b4c5cca260fff7c76af3c22b79b4bf05a72d56..472e8d3de6ae7facc3792b2a862e9dd610da1586 100644 (file)
@@ -729,7 +729,7 @@ int main_config_init(void)
         *      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());
@@ -743,7 +743,7 @@ do {\
                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;\
@@ -765,7 +765,7 @@ do {\
         *      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;
@@ -779,7 +779,7 @@ do {\
         *      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;
index 7193c44c696d3859b5bf9c60e6a11ad8bc00f7e8..59abc862ba82ee0d1936f512e2d88484aa75580c 100644 (file)
@@ -209,7 +209,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
        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;
        }
 
@@ -217,7 +217,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
         *      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:
@@ -228,8 +228,8 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
 
                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);
@@ -240,13 +240,13 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
        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;
                }
@@ -257,7 +257,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
        /*
         *      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) &&
@@ -267,12 +267,12 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
                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;
        }
 
@@ -282,7 +282,7 @@ int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
         */
        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;
        }
 
@@ -360,9 +360,9 @@ int map_afrom_cs(vp_map_t **out, CONF_SECTION *cs,
                }
        }
 
-       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:
index 6042bdd5b6ac79243b8e607d78f2d9e70ff3fd7e..52166de30b7fafa9d4f3eecf854b7075c1b60c4c 100644 (file)
@@ -41,18 +41,18 @@ static TALLOC_CTX *instance_ctx = NULL;
  *     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
 };
 
@@ -105,7 +105,7 @@ exfile_t *module_exfile_init(TALLOC_CTX *ctx,
        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;
 }
@@ -142,6 +142,7 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
 {
        CONF_PAIR               *cp;
        CONF_SECTION            *cs;
+       CONF_DATA const         *cd;
 
 
        module_instance_t       *inst;
@@ -154,7 +155,7 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
        /*
         *      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;
 
@@ -168,11 +169,11 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
        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.
@@ -180,9 +181,9 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
         *      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;
        }
@@ -196,7 +197,7 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
                do {
                        CONF_SECTION *tmp;
 
-                       tmp = cf_section_parent(parent);
+                       tmp = cf_item_to_section(cf_parent(parent));
                        if (!tmp) break;
 
                        parent = tmp;
@@ -209,19 +210,19 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
         *      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;
 }
@@ -242,12 +243,12 @@ int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char c
  *     - 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];
@@ -258,7 +259,7 @@ fr_pool_t *module_connection_pool_init(CONF_SECTION *module,
 
        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);
@@ -294,7 +295,7 @@ fr_pool_t *module_connection_pool_init(CONF_SECTION *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));
@@ -320,7 +321,7 @@ fr_pool_t *module_connection_pool_init(CONF_SECTION *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);
@@ -396,7 +397,7 @@ module_instance_t *module_find(CONF_SECTION *modules, char const *asked_name)
        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);
@@ -466,7 +467,7 @@ module_instance_t *module_find_with_method(rlm_components_t *method, CONF_SECTIO
                         *      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;
@@ -611,7 +612,7 @@ int modules_thread_instantiate(CONF_SECTION *root, fr_event_list_t *el)
        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;
@@ -661,14 +662,14 @@ static int _module_instantiate(void *instance, UNUSED void *ctx)
         *      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;
                }
@@ -718,10 +719,10 @@ static int module_instantiate(CONF_SECTION *root, char const *name)
        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);
@@ -741,7 +742,7 @@ int modules_instantiate(CONF_SECTION *root)
 {
        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;
@@ -831,7 +832,7 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION *
        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.
@@ -858,10 +859,10 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION *
        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;
        }
 
@@ -887,8 +888,8 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION *
                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.
@@ -903,7 +904,7 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION *
         */
        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;
        }
@@ -929,7 +930,7 @@ static int virtual_module_bootstrap(CONF_SECTION *modules, CONF_SECTION *vm_cs)
        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;
 
@@ -944,13 +945,13 @@ static int virtual_module_bootstrap(CONF_SECTION *modules, CONF_SECTION *vm_cs)
            (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 {
@@ -960,9 +961,7 @@ static int virtual_module_bootstrap(CONF_SECTION *modules, CONF_SECTION *vm_cs)
        /*
         *      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)) {
@@ -1000,13 +999,7 @@ static int virtual_module_bootstrap(CONF_SECTION *modules, CONF_SECTION *vm_cs)
        /*
         *      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;
 }
@@ -1030,8 +1023,11 @@ int modules_bootstrap(CONF_SECTION *root)
        /*
         *      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);
 
@@ -1043,14 +1039,14 @@ int modules_bootstrap(CONF_SECTION *root)
         *      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;
 
@@ -1064,7 +1060,7 @@ int modules_bootstrap(CONF_SECTION *root)
                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;
                }
        }
@@ -1075,34 +1071,43 @@ int modules_bootstrap(CONF_SECTION *root)
         *      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, "  }");
index a955b948a4471b89ff8ff99571a8a59db1b45886..103d740255b9f4a0e3581363f7a7bdd9358b923a 100644 (file)
@@ -1054,7 +1054,7 @@ fr_pool_t *fr_pool_init(TALLOC_CTX *ctx,
         *      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;
        }
 
@@ -1062,7 +1062,7 @@ fr_pool_t *fr_pool_init(TALLOC_CTX *ctx,
        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;
        }
 
index bf6333a5b45b3294bb3b8c46f2ccbcfd16b9cab4..126b823bd931798f4da1f3c00deded22eb04364c 100644 (file)
@@ -556,7 +556,7 @@ int main(int argc, char **argv)
                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");
 
@@ -637,7 +637,7 @@ int main(int argc, char **argv)
                 *      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) {
index 4ffb95985868966cfd0fdc413beffcd0f76f9ffa..c35fe3cb3fccad0ecae812ff47b2ffdf599b0d04 100644 (file)
@@ -333,13 +333,13 @@ int main(int argc, char **argv)
                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);
index ce360c62755794e5ccf1d6819845f240e0bcc4ba..7d4cb792c7227f1b7a44dbbb229c902583932fd9 100644 (file)
@@ -470,7 +470,7 @@ void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs)
                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);
        }
@@ -487,13 +487,13 @@ void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs)
 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;
        }
 
@@ -504,7 +504,7 @@ static bool home_server_insert(home_server_t *home, CONF_SECTION *cs)
                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
@@ -531,7 +531,7 @@ bool realm_home_server_add(home_server_t *home)
        }
 
        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;
        }
 
@@ -540,7 +540,7 @@ bool realm_home_server_add(home_server_t *home)
 
                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 ? ")" : "",
@@ -630,7 +630,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
         */
        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;
                }
 
@@ -649,7 +649,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
                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;
                }
 
@@ -658,8 +658,8 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
                 *      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;
                }
 
@@ -670,7 +670,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
         *      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);
@@ -680,15 +680,15 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
        /*
         *      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
@@ -710,20 +710,20 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
 
                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;
                }
@@ -733,7 +733,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
 
        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;
                }
@@ -750,18 +750,18 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
 
                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;
                }
 
@@ -790,20 +790,20 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
 #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;
        }
 
@@ -818,7 +818,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
                } 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;
                }
        }
@@ -828,7 +828,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
         */
        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 {
@@ -840,7 +840,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
 
 #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
@@ -897,7 +897,7 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
                 */
                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;
                        }
                /*
@@ -963,7 +963,7 @@ CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
         *      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 {
@@ -993,7 +993,7 @@ CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
                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;
        }
 
@@ -1035,7 +1035,7 @@ static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
        home_server_t myhome, *home;
 
        if (!name) {
-               cf_log_err_cp(cp,
+               cf_log_err(cp,
                           "No value given for home_server");
                return 0;
        }
@@ -1063,7 +1063,7 @@ static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
                break;
        }
 
-       cf_log_err_cp(cp, "Unknown home_server \"%s\".", name);
+       cf_log_err(cp, "Unknown home_server \"%s\".", name);
        return 0;
 }
 
@@ -1191,14 +1191,14 @@ static int server_pool_add(realm_config_t *rc,
        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;
        }
@@ -1219,7 +1219,7 @@ static int server_pool_add(realm_config_t *rc,
        }
 
        if (num_home_servers == 0) {
-               cf_log_err_cs(cs,
+               cf_log_err(cs,
                           "No home servers defined in pool %s",
                           name2);
                goto error;
@@ -1238,7 +1238,7 @@ static int server_pool_add(realm_config_t *rc,
        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
@@ -1248,7 +1248,7 @@ static int server_pool_add(realm_config_t *rc,
                }
 
                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;
                }
@@ -1275,14 +1275,14 @@ static int server_pool_add(realm_config_t *rc,
 
                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;
@@ -1295,7 +1295,7 @@ static int server_pool_add(realm_config_t *rc,
        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;
                }
 
@@ -1303,8 +1303,8 @@ static int server_pool_add(realm_config_t *rc,
                        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;
                }
 
@@ -1377,7 +1377,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
        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;
@@ -1392,7 +1392,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
         */
        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;
@@ -1407,12 +1407,12 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
        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;
                }
        }
@@ -1422,12 +1422,12 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
        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;
                }
 
@@ -1436,9 +1436,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
                 *      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;
                }
        }
 
@@ -1462,7 +1460,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
                }
 
                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;
                }
        }
@@ -1494,14 +1492,14 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
                        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;
                        }
@@ -1515,7 +1513,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
 
                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);
@@ -1542,20 +1540,20 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
                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;
                }
@@ -1567,7 +1565,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
                        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);
@@ -1593,9 +1591,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
         *      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;
@@ -1603,14 +1599,14 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
        }
 
        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;
        }
 
@@ -1641,7 +1637,7 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
        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;
                }
 
@@ -1653,7 +1649,7 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
                        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. */
@@ -1666,20 +1662,20 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
        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;
                        }
                }
@@ -1696,7 +1692,7 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
        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;
                }
 
@@ -1707,13 +1703,13 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
                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;
                        }
                }
@@ -1730,7 +1726,7 @@ static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
        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;
                }
 
@@ -1773,16 +1769,10 @@ static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
        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;
                }
 
@@ -1798,7 +1788,7 @@ static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
        }
 
        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;
        }
 
@@ -1825,13 +1815,13 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
 
        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;
        }
 
@@ -1867,7 +1857,7 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
        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,
@@ -1883,7 +1873,7 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *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;
                }
 
@@ -1926,7 +1916,7 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
        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;
                }
 
@@ -1991,9 +1981,7 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
                goto error;
        }
 
-       if (!realm_realm_add(r, cs)) {
-               goto error;
-       }
+       if (!realm_realm_add(r, cs)) goto error;
 
        cf_log_info(cs, " }");
 
@@ -2039,9 +2027,9 @@ int realm_realm_add(REALM *r, UNUSED CONF_SECTION *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);
@@ -2080,37 +2068,37 @@ static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
 
        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;
        }
 
@@ -2123,7 +2111,7 @@ int realms_init(CONF_SECTION *config)
        CONF_SECTION *cs;
        int flags = 0;
 #ifdef WITH_PROXY
-       CONF_SECTION *server_cs;
+       CONF_SECTION *server_cs = NULL;
 #endif
        realm_config_t *rc;
 
@@ -2133,7 +2121,7 @@ int realms_init(CONF_SECTION *config)
        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");
@@ -2166,9 +2154,8 @@ int realms_init(CONF_SECTION *config)
        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);
@@ -2180,12 +2167,9 @@ int realms_init(CONF_SECTION *config)
         *      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);
@@ -2202,9 +2186,8 @@ int realms_init(CONF_SECTION *config)
        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();
@@ -2221,9 +2204,8 @@ int realms_init(CONF_SECTION *config)
        /*
         *      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;
 
                /*
index 00a71701d67a80599038587147f76d0c194892db..e542d0203976fc823cee7c75ba1ff6299cc20765 100644 (file)
@@ -762,7 +762,7 @@ int thread_pool_bootstrap(CONF_SECTION *cs, bool *spawn_workers)
        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");
index add17fe55abed3a6a8d9843ee65f8a684b98d579..7ed2649317c0133c592327510d70435e9aeaf585 100644 (file)
@@ -311,7 +311,7 @@ fr_tls_conf_t *tls_conf_parse_server(CONF_SECTION *cs)
         *      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;
@@ -387,19 +387,19 @@ fr_tls_conf_t *tls_conf_parse_server(CONF_SECTION *cs)
        }
 
        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;
        }
@@ -428,7 +428,7 @@ fr_tls_conf_t *tls_conf_parse_client(CONF_SECTION *cs)
        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;
index 5ccd8d44c6fa47d157c8d3a2d3fae91e36471ca6..7b4918f339323f581a02ef90240b9206380e3e9c 100644 (file)
@@ -123,7 +123,7 @@ static int _trigger_last_fired_cmp(void const *a, void const *b)
 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));
@@ -196,7 +196,7 @@ int trigger_exec(REQUEST *request, CONF_SECTION const *cs, char const *name, boo
         *      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;
index bd405ab19e8ff68a020f9dab203eea904e2097e4..cdebcfe5d111fceb629b3cdc11bf5079f9a2c430 100644 (file)
@@ -91,7 +91,7 @@ static int process_file(char const *filename)
        /*
         *      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;
@@ -103,7 +103,7 @@ static int process_file(char const *filename)
        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;
        }
 
index 4416110c7f6a2c8c41ed3dd392a1a800ba2bdf2e..5bd98d7f44ade8b926de6e64372526607e74fce6 100644 (file)
@@ -444,15 +444,15 @@ static ssize_t xlat_poke(TALLOC_CTX *ctx, char **out, size_t outlen,
                         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);
@@ -460,7 +460,7 @@ static ssize_t xlat_poke(TALLOC_CTX *ctx, char **out, size_t outlen,
        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);
@@ -516,7 +516,8 @@ static ssize_t xlat_poke(TALLOC_CTX *ctx, char **out, size_t outlen,
         *      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 */
@@ -544,6 +545,11 @@ static ssize_t xlat_poke(TALLOC_CTX *ctx, char **out, size_t outlen,
                        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 */
        }
 
@@ -664,7 +670,7 @@ static int map_proc_verify(CONF_SECTION *cs, UNUSED void *mod_inst, UNUSED void
                           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;
        }
index eeb4fcc299e9a2a8c685f9c2a86ef1d8468bd403..7944de240fc28d115c24cd9341d166c5012df942 100644 (file)
@@ -498,13 +498,13 @@ static bool pass2_fixup_xlat(CONF_ITEM const *ci, vp_tmpl_t **pvpt, bool convert
                                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);
@@ -747,8 +747,8 @@ static bool pass2_cond_callback(void *ctx, fr_cond_t *c)
                                        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);
 
@@ -1068,13 +1068,13 @@ static int modcall_fixup_map(vp_map_t *map, UNUSED void *ctx)
        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);
                }
        }
@@ -1134,13 +1134,13 @@ int unlang_fixup_update(vp_map_t *map, UNUSED void *ctx)
        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);
                }
        }
@@ -1153,7 +1153,7 @@ int unlang_fixup_update(vp_map_t *map, UNUSED void *ctx)
        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);
@@ -1222,7 +1222,7 @@ int unlang_fixup_update(vp_map_t *map, UNUSED void *ctx)
                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) {
@@ -1349,7 +1349,7 @@ static int compile_map_name(unlang_group_t *g)
                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;
@@ -1403,15 +1403,15 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
 
        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;
        }
 
@@ -1424,7 +1424,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
        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.
@@ -1432,7 +1432,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
                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;
                }
 
@@ -1449,7 +1449,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
 
                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;
                }
        }
@@ -1460,7 +1460,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
        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;
        }
 
@@ -1474,7 +1474,7 @@ static unlang_t *compile_map(unlang_t *parent, unlang_compile_t *unlang_ctx,
        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);
@@ -1519,7 +1519,7 @@ static unlang_t *compile_update(unlang_t *parent, unlang_compile_t *unlang_ctx,
        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;
        }
 
@@ -1577,12 +1577,12 @@ static int compile_action_pair(unlang_t *c, CONF_PAIR *cp)
                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;
        }
@@ -1592,7 +1592,7 @@ static int compile_action_pair(unlang_t *c, CONF_PAIR *cp)
 
                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;
@@ -1621,9 +1621,9 @@ static bool compile_action_section(unlang_t *c, CONF_ITEM *ci)
         *      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'");
@@ -1709,7 +1709,7 @@ static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTIO
 
        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;
@@ -1735,9 +1735,9 @@ static bool compile_action_subsection(unlang_t *c, CONF_SECTION *cs, CONF_SECTIO
 
 
 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);
@@ -1745,10 +1745,7 @@ static unlang_t *compile_children(unlang_group_t *g, UNUSED unlang_t *parent, un
        /*
         *      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.
@@ -1782,17 +1779,12 @@ static unlang_t *compile_children(unlang_group_t *g, UNUSED unlang_t *parent, un
                         */
                        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);
 
@@ -1816,7 +1808,7 @@ static unlang_t *compile_children(unlang_group_t *g, UNUSED unlang_t *parent, un
                                        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;
                                        }
 
@@ -1835,6 +1827,10 @@ static unlang_t *compile_children(unlang_group_t *g, UNUSED unlang_t *parent, un
                                talloc_free(c);
                                return NULL;
                        } /* else it worked */
+               } else if (cf_item_is_data(ci)) {
+                       continue;
+               } else {
+                       rad_assert(0);
                }
        }
 
@@ -1881,7 +1877,7 @@ static unlang_t *compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx,
 
        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;
        }
 
@@ -1892,16 +1888,16 @@ static unlang_t *compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx,
         *      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);
@@ -1914,9 +1910,9 @@ static unlang_t *compile_switch(unlang_t *parent, unlang_compile_t *unlang_ctx,
         *      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;
 
@@ -1977,7 +1973,7 @@ static unlang_t *compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
        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;
        }
 
@@ -1991,7 +1987,7 @@ static unlang_t *compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
                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) {
@@ -1999,9 +1995,9 @@ static unlang_t *compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
 
                        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);
@@ -2033,7 +2029,7 @@ static unlang_t *compile_case(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
                        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;
@@ -2105,7 +2101,7 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
 
        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;
        }
@@ -2116,16 +2112,16 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
         *      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);
@@ -2140,13 +2136,13 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
        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;
        }
@@ -2231,17 +2227,17 @@ static unlang_t *compile_if(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF
        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);
        }
 
@@ -2277,7 +2273,7 @@ static int previous_if(CONF_SECTION *cs, unlang_t *parent, unlang_type_t mod_typ
        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;
        }
@@ -2286,7 +2282,7 @@ static int previous_if(CONF_SECTION *cs, unlang_t *parent, unlang_type_t mod_typ
                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;
        }
 
@@ -2302,7 +2298,7 @@ static unlang_t *compile_elsif(unlang_t *parent, unlang_compile_t *unlang_ctx, C
         *      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;
        }
 
@@ -2322,7 +2318,7 @@ static unlang_t *compile_else(unlang_t *parent,
        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;
        }
 
@@ -2350,9 +2346,9 @@ static int all_children_are_modules(CONF_SECTION *cs, char const *name)
 {
        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
@@ -2400,8 +2396,8 @@ static unlang_t *compile_redundant(unlang_t *parent, unlang_compile_t *unlang_ct
        /*
         *      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;
        }
 
@@ -2425,8 +2421,8 @@ static unlang_t *compile_redundant(unlang_t *parent, unlang_compile_t *unlang_ct
         *      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;
        }
 
@@ -2446,8 +2442,8 @@ static unlang_t *compile_load_balance(unlang_t *parent, unlang_compile_t *unlang
        /*
         *      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;
        }
 
@@ -2469,7 +2465,7 @@ static unlang_t *compile_load_balance(unlang_t *parent, unlang_compile_t *unlang
         *      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) {
@@ -2480,16 +2476,16 @@ static unlang_t *compile_load_balance(unlang_t *parent, unlang_compile_t *unlang
                 *      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);
@@ -2511,7 +2507,7 @@ static unlang_t *compile_load_balance(unlang_t *parent, unlang_compile_t *unlang
 
                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;
 
@@ -2541,13 +2537,13 @@ static unlang_t *compile_parallel(unlang_t *parent, unlang_compile_t *unlang_ctx
        /*
         *      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;
        }
 
@@ -2603,12 +2599,12 @@ static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
         *
         *      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;
@@ -2620,7 +2616,7 @@ static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
         *
         *      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;
 
        /*
@@ -2629,7 +2625,7 @@ static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
         *      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;
@@ -2641,12 +2637,11 @@ static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
         *      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);
 }
 
 
@@ -2737,16 +2732,16 @@ static modcall_compile_t compile_table[] = {
  *     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;
@@ -2765,7 +2760,7 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
                                 *      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))) {
@@ -2892,9 +2887,9 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
         *      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;
                }
@@ -2963,7 +2958,7 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
        /*
         *      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;
index a8a437e47a6def47e847cb6b08f92a7bcb0e8f92..aa4a76b5ddfbadffb99534e76608b9390d173964 100644 (file)
@@ -1412,7 +1412,7 @@ void unlang_push_section(REQUEST *request, CONF_SECTION *cs, rlm_rcode_t action)
         *      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));
index c42b2686c17b546f82ad9e78ec516073b70a4d00..f8ea703cdb1e407ffbde3d1c2dfbd6b70f24c329 100644 (file)
@@ -530,16 +530,16 @@ void version_print(void)
 
                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;
                }
@@ -553,9 +553,9 @@ void version_print(void)
                }
 #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);
@@ -569,9 +569,9 @@ void version_print(void)
 
                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);
index c7e7614afa4670cd403c1f20dcb01bb09e4389af..fda4a27b11dffa089f5253eb99edd2402cb0c71d 100644 (file)
@@ -44,7 +44,7 @@ static int default_component_results[MOD_COUNT] = {
        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
 };
@@ -71,10 +71,10 @@ static rlm_rcode_t module_method_call(rlm_components_t comp, int idx, REQUEST *r
         */
        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,
@@ -87,7 +87,7 @@ static rlm_rcode_t module_method_call(rlm_components_t comp, int idx, REQUEST *r
         */
        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;
@@ -100,7 +100,7 @@ static rlm_rcode_t module_method_call(rlm_components_t comp, int idx, REQUEST *r
                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);
@@ -108,7 +108,7 @@ static rlm_rcode_t module_method_call(rlm_components_t comp, int idx, REQUEST *r
                }
 
                RDEBUG("Running %s %s from file %s",
-                      da->name, dv->alias, cf_section_filename(subcs));
+                      da->name, dv->alias, cf_filename(subcs));
                cs = subcs;
        }
 
@@ -236,7 +236,7 @@ rlm_rcode_t process_send_coa(int send_coa_type, REQUEST *request)
 }
 #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;
@@ -248,11 +248,10 @@ static bool define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *
        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;
        }
 
        /*
@@ -266,13 +265,13 @@ static bool define_type(CONF_SECTION *cs, fr_dict_attr_t const *da, char const *
                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;
 }
 
 /*
@@ -298,25 +297,23 @@ static bool load_subcomponent_section(CONF_SECTION *cs,
         */
        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;
 
        /*
@@ -324,9 +321,9 @@ static int load_component_section(CONF_SECTION *cs, rlm_components_t comp)
         */
        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;
        }
 
@@ -336,9 +333,7 @@ static int load_component_section(CONF_SECTION *cs, rlm_components_t comp)
         *      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? */
                }
@@ -348,7 +343,7 @@ static int load_component_section(CONF_SECTION *cs, rlm_components_t comp)
         *      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;
        }
@@ -364,7 +359,7 @@ static int virtual_servers_compile(CONF_SECTION *cs)
        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) {
@@ -380,8 +375,7 @@ static int virtual_servers_compile(CONF_SECTION *cs)
        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) {
@@ -390,7 +384,7 @@ static int virtual_servers_compile(CONF_SECTION *cs)
                        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
@@ -429,14 +423,12 @@ static int virtual_servers_compile(CONF_SECTION *cs)
         */
        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;
                        }
 
@@ -462,9 +454,9 @@ static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
         */
        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;
        }
 
@@ -473,9 +465,9 @@ static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
         *      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;
@@ -492,23 +484,20 @@ static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
        /*
         *      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;
@@ -520,10 +509,10 @@ static bool virtual_server_define_types(CONF_SECTION *cs, rlm_components_t comp)
  */
 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;
        }
@@ -531,9 +520,7 @@ int virtual_servers_bootstrap(CONF_SECTION *config)
        /*
         *      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;
@@ -542,30 +529,29 @@ int virtual_servers_bootstrap(CONF_SECTION *config)
                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;
                }
 
@@ -580,30 +566,30 @@ int virtual_servers_bootstrap(CONF_SECTION *config)
 
                        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;
                        }
@@ -612,9 +598,9 @@ int virtual_servers_bootstrap(CONF_SECTION *config)
                        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;
 
@@ -652,16 +638,14 @@ int virtual_servers_bootstrap(CONF_SECTION *config)
  */
 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);
@@ -675,7 +659,7 @@ int virtual_servers_init(fr_schedule_t *sc, CONF_SECTION *config)
 
                        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;
@@ -685,11 +669,11 @@ int virtual_servers_init(fr_schedule_t *sc, CONF_SECTION *config)
                         */
 
                        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;
                        }
 
index 69f1a63d5696e440a47e4cf2e24b013b43e18e51..11dad2ebcf1f36c9e4d0c6758286b9f05fa8d10f 100644 (file)
@@ -693,7 +693,7 @@ int xlat_register(void *mod_inst, char const *name,
        rbnode_t *node;
 
        if (!name || !*name) {
-               DEBUG("xlat_register: Invalid xlat name");
+               ERROR("%s: Invalid xlat name", __FUNCTION__);
                return -1;
        }
 
@@ -710,7 +710,7 @@ int xlat_register(void *mod_inst, char const *name,
 
                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;
                }
 
@@ -760,7 +760,7 @@ int xlat_register(void *mod_inst, char const *name,
        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;
                }
 
@@ -786,13 +786,9 @@ int xlat_register(void *mod_inst, char const *name,
        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;
 }
@@ -872,9 +868,9 @@ static ssize_t xlat_redundant(TALLOC_CTX *ctx, char **out, NDEBUG_UNUSED size_t
        /*
         *      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;
@@ -924,9 +920,9 @@ static ssize_t xlat_load_balance(TALLOC_CTX *ctx, char **out, NDEBUG_UNUSED size
        /*
         *      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++;
 
@@ -991,15 +987,24 @@ static ssize_t xlat_load_balance(TALLOC_CTX *ctx, char **out, NDEBUG_UNUSED size
                /*
                 *      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;
@@ -1008,24 +1013,20 @@ bool xlat_register_redundant(CONF_SECTION *cs)
        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;
@@ -1035,33 +1036,41 @@ bool xlat_register_redundant(CONF_SECTION *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;
 }
 
 
index 09aa46ef7cfd6da9a779b14d3ee19625f8f3fe98..aa6663c1838ffbfcbc1917522aae5a84e27bcfea 100644 (file)
@@ -55,7 +55,7 @@ static rlm_rcode_t arp_process(REQUEST *request)
 
        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";
 
@@ -236,7 +236,7 @@ static int arp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        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;
        }
 
@@ -272,9 +272,9 @@ static int arp_socket_bootstrap(CONF_SECTION *server_cs, UNUSED CONF_SECTION *li
 {
        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;
        }
 
@@ -288,16 +288,16 @@ static int arp_socket_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *list
 {
        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;
        }
 
index 1a82ca158ebcb39933f5caeb715e5cb46f964545..b56b0b0625374af6ca5eede08641730d461fdfc4 100644 (file)
@@ -1581,9 +1581,9 @@ static int bfd_init_sessions(CONF_SECTION *cs, bfd_socket_t *sock, int sockfd)
        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;
@@ -1733,8 +1733,8 @@ static int bfd_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
        /*
         *      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;
 }
@@ -1815,9 +1815,9 @@ static int bfd_socket_bootstrap(CONF_SECTION *server_cs, UNUSED CONF_SECTION *li
 {
        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;
        }
 
@@ -1831,16 +1831,16 @@ static int bfd_socket_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *list
 {
        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;
        }
 
index 08b58f75f5792175b245bce407f4411d5a93c652..d4b18bf1b35e5b844cfd8fa191f799e553f93017 100644 (file)
@@ -1039,7 +1039,7 @@ static int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
 
        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;
        }
 
@@ -1052,7 +1052,7 @@ static int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
        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;
        }
 
@@ -1095,7 +1095,7 @@ static int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
                 */
                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;
                }
 
@@ -1128,7 +1128,7 @@ static int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
        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;
index a7c5d8a5b1d52d3ce5a08e8b98a7e800590f25bc..dc5a5ba54b010c06b745abc44cc300c038008139 100644 (file)
@@ -322,9 +322,9 @@ static rlm_rcode_t dhcp_process(REQUEST *request)
 
                        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);
@@ -1006,37 +1006,35 @@ static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
  */
 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;
                }
        }
index 3684ff29a3fd4ae01ae7471b4325323bc6b10ac4..12d7e98193d9f41ac61b24c46174986087ad456b 100644 (file)
@@ -363,8 +363,8 @@ static void request_running(REQUEST *request, fr_state_action_t action)
                        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>"),
@@ -374,7 +374,7 @@ static void request_running(REQUEST *request, fr_state_action_t action)
                }
 
                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;
@@ -607,7 +607,7 @@ static int _proto_ldap_present(fr_ldap_conn_t *conn, sync_config_t const *config
 {
        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);
@@ -784,7 +784,7 @@ static int proto_ldap_cookie_load(TALLOC_CTX *ctx, uint8_t **cookie, rad_listen_
        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>"),
@@ -1053,10 +1053,10 @@ static int proto_ldap_socket_parse(CONF_SECTION *cs, rad_listen_t *listen)
        /*
         *      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;
        }
 
@@ -1073,9 +1073,9 @@ static int proto_ldap_socket_parse(CONF_SECTION *cs, rad_listen_t *listen)
        /*
         *      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;
@@ -1084,7 +1084,7 @@ static int proto_ldap_socket_parse(CONF_SECTION *cs, rad_listen_t *listen)
 
                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
@@ -1114,7 +1114,7 @@ static int proto_ldap_socket_parse(CONF_SECTION *cs, rad_listen_t *listen)
                /*
                 *      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) {
@@ -1145,13 +1145,13 @@ static int ldap_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -1193,7 +1193,7 @@ static int proto_ldap_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTIO
        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;
index fc64e62ea2beac3d7775d197d91fce6a4f577bfa..247d7fe7cca4f26673f4e36d2ff77b8a58c8c782 100644 (file)
@@ -114,7 +114,7 @@ static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECT
        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;
        }
 
@@ -127,12 +127,12 @@ static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECT
        }
 
        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;
        }
 
@@ -155,7 +155,7 @@ static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECT
        }
 
        if (!lib) {
-               cf_log_err_cs(cs, "Unknown 'type = %s'", value);
+               cf_log_err(cs, "Unknown 'type = %s'", value);
                return -1;
        }
 
@@ -170,7 +170,7 @@ static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECT
                        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;
                        }
 
@@ -184,7 +184,7 @@ static int compile_type(proto_radius_ctx_t *ctx, CONF_SECTION *server, CONF_SECT
         */
        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;
        }
 
@@ -212,7 +212,7 @@ static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
        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;
        }
 
@@ -220,21 +220,21 @@ static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
 
        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;
        }
 
@@ -243,7 +243,7 @@ static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
                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;
                }
 
@@ -252,7 +252,7 @@ static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
 
        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;
        }
@@ -260,7 +260,7 @@ static int open_transport(proto_radius_ctx_t *ctx, fr_schedule_t *handle,
        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;
        }
 
@@ -303,23 +303,23 @@ static int open_listen(fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION
 
        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;
        }
 
@@ -328,7 +328,7 @@ static int open_listen(fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION
         */
        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;
                }
@@ -338,7 +338,7 @@ static int open_listen(fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION
         *      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;
        }
@@ -357,28 +357,26 @@ static int open_listen(fr_schedule_t *handle, CONF_SECTION *server, CONF_SECTION
  */
 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");
@@ -390,16 +388,16 @@ static int mod_parse(fr_schedule_t *handle, CONF_SECTION *cs, bool verify_config
 
                        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;
                        }
 
index 2e832aa2c7faace65a7c967aa023d3fe7d3004e6..22b7cec980d40e1be9622220db52dfa9646fb5a6 100644 (file)
@@ -65,14 +65,14 @@ static fr_io_final_t acct_process(REQUEST *request)
                        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;
@@ -131,12 +131,12 @@ static fr_io_final_t acct_process(REQUEST *request)
                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;
@@ -361,13 +361,13 @@ static int acct_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -391,7 +391,7 @@ static int acct_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *lis
        }
 
        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;
        }
index 1b5fb45feedc0ee9f3adfeafe16d62098b56e9e9..1e67086df12d3cc8173a091fa8646b3dd1920c6b 100644 (file)
@@ -314,8 +314,8 @@ static fr_io_final_t auth_process(REQUEST *request)
                        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;
@@ -336,7 +336,7 @@ static fr_io_final_t auth_process(REQUEST *request)
                /*
                 *      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;
@@ -430,14 +430,14 @@ static fr_io_final_t auth_process(REQUEST *request)
                        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;
@@ -544,14 +544,14 @@ static fr_io_final_t auth_process(REQUEST *request)
                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;
@@ -595,7 +595,7 @@ static fr_io_final_t auth_process(REQUEST *request)
                                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);
@@ -952,13 +952,13 @@ static int auth_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -972,13 +972,13 @@ static int auth_compile_section(CONF_SECTION *server_cs, char const *name1, char
 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;
        }
@@ -986,7 +986,7 @@ static int auth_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *lis
        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;
        }
@@ -994,7 +994,7 @@ static int auth_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *lis
        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;
        }
@@ -1005,21 +1005,19 @@ static int auth_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *lis
        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;
                }
        }
@@ -1029,25 +1027,23 @@ static int auth_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *lis
 
 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;
                }
 
@@ -1068,7 +1064,7 @@ static int auth_listen_bootstrap(CONF_SECTION *server_cs, UNUSED CONF_SECTION *l
                        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;
index 187fba7ee4b4ee2f4790dcd0ae7f4701caaf4419..b72fdd6ce2fd3a2303115df525db8b7ba928b843 100644 (file)
@@ -66,14 +66,14 @@ static fr_io_final_t coa_process(REQUEST *request)
                        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;
@@ -127,9 +127,9 @@ static fr_io_final_t coa_process(REQUEST *request)
                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;
 
@@ -140,7 +140,7 @@ static fr_io_final_t coa_process(REQUEST *request)
                 *      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;
 
@@ -185,7 +185,7 @@ static fr_io_final_t coa_process(REQUEST *request)
                                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);
@@ -403,13 +403,13 @@ static int coa_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -443,12 +443,12 @@ static int coa_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *list
 
        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;
        }
index 0062e2360cc600c874afd4fa3f96c778c482ba4d..eef289bee6ba3928daf21587604a4be04f626617 100644 (file)
@@ -55,14 +55,14 @@ static fr_io_final_t mod_process(REQUEST *request, UNUSED fr_io_action_t action)
                        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;
@@ -100,13 +100,13 @@ static fr_io_final_t mod_process(REQUEST *request, UNUSED fr_io_action_t action)
                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;
@@ -147,7 +147,7 @@ static fr_io_final_t mod_process(REQUEST *request, UNUSED fr_io_action_t action)
                                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);
@@ -201,10 +201,10 @@ static int mod_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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?
@@ -216,7 +216,7 @@ static int mod_compile_section(CONF_SECTION *server_cs, char const *name1, char
         */
 
        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;
        }
 
@@ -234,7 +234,7 @@ static int mod_compile(CONF_SECTION *server_cs)
        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;
        }
@@ -242,7 +242,7 @@ static int mod_compile(CONF_SECTION *server_cs)
        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;
        }
@@ -250,7 +250,7 @@ static int mod_compile(CONF_SECTION *server_cs)
        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;
        }
index a3c1c32878c8b718bcee0773534a7a22fe6e2798..7794dc37659da68fa4cb5ac369330fa69e1c606d 100644 (file)
@@ -149,13 +149,13 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
                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;
                }
 
index eee0c5f95fda888548f2648ccfa8f1ffa14e4fe7..063ded499cd3564fc116a4daa1068f1bda85af16 100644 (file)
@@ -183,8 +183,8 @@ static void tacacs_running(REQUEST *request, fr_state_action_t action)
                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;
@@ -196,7 +196,7 @@ static void tacacs_running(REQUEST *request, fr_state_action_t action)
                        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;
@@ -285,14 +285,14 @@ stop_processing:
                        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;
@@ -337,12 +337,12 @@ stop_processing:
 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;
@@ -529,18 +529,18 @@ static int tacacs_compile_section(CONF_SECTION *server_cs, char const *name1, ch
        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;
        }
 
@@ -550,7 +550,7 @@ static int tacacs_compile_section(CONF_SECTION *server_cs, char const *name1, ch
 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;
@@ -570,9 +570,7 @@ static int tacacs_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *l
        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);
index 3ddbe67fd81bc408ea88552240237395a114ef95..edfb156903bf3592a758aa8a9224d85a71db1e27 100644 (file)
@@ -67,14 +67,14 @@ static void vmps_running(REQUEST *request, fr_state_action_t action)
                        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;
@@ -104,12 +104,12 @@ static void vmps_running(REQUEST *request, fr_state_action_t action)
                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;
@@ -243,13 +243,13 @@ static int vqp_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -273,7 +273,7 @@ static int vqp_listen_compile(CONF_SECTION *server_cs, UNUSED CONF_SECTION *list
        }
 
        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;
        }
index 22a7e6cef51889023e85a360a4c198b38972f503..91291932097ac23ba128d206825e694915f425bc 100644 (file)
@@ -65,7 +65,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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 */
index 0fa4be47eff1eb6c4899e75abccb4f2ecb9ab51e..6b1b9003c95d40d514154cfa51603c782550f29c 100644 (file)
@@ -921,7 +921,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      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;
        }
 
@@ -932,7 +932,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
@@ -964,18 +964,18 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 #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;
        }
 
@@ -988,7 +988,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        }
 
        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;
        }
index 9100688e8f88b4940ca8c81224f25f48d42faa46..43ebbf2b10f3a340efd3f80b6981b01bf4357771 100644 (file)
@@ -140,6 +140,22 @@ static rlm_rcode_t map_proc_client(UNUSED void *mod_inst, UNUSED void *proc_inst
                        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;
index 56010f93c9ce070f3026f888d167cb57e100370f..52f92d98b97e3349f0310aff4a35e355ba401ddc 100644 (file)
@@ -157,11 +157,11 @@ int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance)
        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'");
        }
 
@@ -176,7 +176,7 @@ int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance)
        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");
index de4f1eb16e5363dc207a040dcd860ff8cafbe6ad..c72aaa654609f62a1c8451859e802d57b714b0cf 100644 (file)
@@ -823,7 +823,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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 */
@@ -831,14 +831,14 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                }
 
                /* 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");
index 8bc72e42a5966fd5eb3f84046180feb51834cf34..9601418b430a7dba862e8e6d337c7a85b5a5260d 100644 (file)
@@ -166,14 +166,14 @@ static rlm_csv_entry_t *file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno
 
        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;
                }
 
@@ -194,7 +194,7 @@ static rlm_csv_entry_t *file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno
        }
 
        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;
        }
 
@@ -202,7 +202,7 @@ static rlm_csv_entry_t *file2csv(CONF_SECTION *conf, rlm_csv_t *inst, int lineno
         *      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;
        }
@@ -240,7 +240,7 @@ static int csv_map_verify(CONF_SECTION *cs, void *mod_inst, UNUSED void *proc_in
        vp_map_t const  *map;
 
        if (!src) {
-               cf_log_err_cs(cs, "Missing file name");
+               cf_log_err(cs, "Missing file name");
 
                return -1;
        }
@@ -284,7 +284,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -293,14 +293,14 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        }
 
        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;
        }
 
@@ -361,7 +361,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        }
 
        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;
        }
 
@@ -373,7 +373,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
         */
        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;
        }
 
index cff5b15c250dd7ec61cc6ac9820a7cb5e590e3fd..5ea71e00adab9926268f95d0b4b2265ddf43ad23 100644 (file)
@@ -134,22 +134,22 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
 
@@ -160,7 +160,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
                        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;
                        }
 
index 7ad6f832d41d1b430194279ccad14362cdfa1401..87513ed3c5cb91d52026ef12367028c576ba04fc 100644 (file)
@@ -1097,13 +1097,13 @@ fr_tls_conf_t *eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
        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;
@@ -1118,7 +1118,7 @@ fr_tls_conf_t *eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
                 *      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;
index 83a781fe2f6520e1f904c6729a66a53cf1feedc8..cdc6a3158f08d406183e1dc3144b377d8a293c0f 100644 (file)
@@ -133,7 +133,7 @@ static int mod_bootstrap(CONF_SECTION *cs, void *instance)
        int             i, ret;
        eap_type_t      method;
        int             num_methods;
-       CONF_SECTION    *scs;
+       CONF_SECTION    *scs = NULL;
        rlm_eap_t       *inst = instance;
 
        /*
@@ -148,10 +148,7 @@ static int mod_bootstrap(CONF_SECTION *cs, void *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);
@@ -161,12 +158,12 @@ static int mod_bootstrap(CONF_SECTION *cs, void *instance)
 
                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;
                }
 
@@ -207,7 +204,7 @@ static int mod_bootstrap(CONF_SECTION *cs, void *instance)
        }
 
        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;
        }
 
@@ -222,7 +219,7 @@ static int mod_bootstrap(CONF_SECTION *cs, void *instance)
        }
 
        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;
        }
index c7bea5b60898e7743aae304ac17f051b57d37944..a2905d558c0b0a87e5ab7732ee7203c90ed3c42d 100644 (file)
@@ -78,7 +78,7 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
 {
        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;
        }
index 48bb208fa3451a447e83609936a44807b7db4b1f..1ad58730f6fecafcc48a2c00219f375088e3527d 100644 (file)
@@ -126,7 +126,7 @@ static rlm_rcode_t mod_process(void *instance, eap_session_t *eap_session)
         */
        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.
index 6da908908f3b028a07f082c01045d8bbba6b1a24..c606d28f1198a502d0901700e915dbb4a2a9f2a6 100644 (file)
@@ -748,7 +748,7 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
        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;
        }
 
@@ -757,7 +757,7 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
        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;
index 8b3edc787b1673dd700148578ff110bb33e74078..183e12cac1db045c5a312d037d5acbd59ea56ec2 100644 (file)
@@ -286,13 +286,13 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
        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;
                }
index 41b53f816039db5c651f0a659fc531bf33f8c6b6..639f55d02992d7e6004806799cf2ff548eafbde6 100644 (file)
@@ -512,7 +512,7 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
        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;
        }
 
index bbda33fa7874900ba9c5deeaed5556e050781d42..6297eea5c780e43dd5bae552122efc50f66fbce5 100644 (file)
@@ -548,36 +548,34 @@ static rlm_rcode_t mod_session_init(UNUSED void *instance, eap_session_t *eap_se
 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;
                }
        }
index 1de9b860c015c88b4af1e9c0c6e66933f3b3667c..b853822df0bf7e63e9d6c16448289f10ba577a70 100644 (file)
@@ -267,7 +267,7 @@ static int mod_instantiate(UNUSED rlm_eap_config_t const *config, void *instance
 {
        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;
        }
index 5acbecb64b88d31b25e0d25d81c1cf3b93a68f1b..8e3ef5fb63033d61af38a38259d8f9d081d4c726 100644 (file)
@@ -78,7 +78,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      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;
        }
 
index 2880f749ae5280a63165143e3ea20c74f954f293..1d6914cc4752606662bfdafd2e636e8b8ecd430c 100644 (file)
@@ -211,7 +211,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
                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;
                }
        }
@@ -220,7 +220,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
                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;
                }
        }
@@ -230,7 +230,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
         *      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;
        }
 
@@ -244,7 +244,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
 
                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;
                }
@@ -258,14 +258,14 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
                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;
        }
 
index 3f7c481ed27838b815e35029ae55c4d623bf381d..d56ab51f1f1396c8fb187749246b7fe80371c790 100644 (file)
@@ -125,7 +125,7 @@ static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, voi
        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;
        }
@@ -136,7 +136,7 @@ static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, voi
 
 #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;
                }
@@ -152,9 +152,9 @@ static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, voi
                        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);
@@ -164,7 +164,7 @@ static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, voi
 
                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;
index a581c22ef4f29dfeaaa130c374fbec1b11478abd..3a6c5e101a2012a3f2a991756b51c2a9edfdb146 100644 (file)
@@ -49,9 +49,9 @@ static int rlm_ldap_client_get_attrs(char const **values, int *idx, CONF_SECTION
 {
        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)) {
index bac2016259686b627bbd251c94ee57c7fcc9079d..6c76f97b40423af4ff40fbf8fc01cc8a1827f012 100644 (file)
@@ -358,7 +358,7 @@ static int ldap_map_verify(CONF_SECTION *cs, UNUSED void *mod_inst, UNUSED void
                           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;
        }
@@ -1165,7 +1165,7 @@ static rlm_rcode_t user_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_ac
                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");
 
@@ -1175,7 +1175,7 @@ static rlm_rcode_t user_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_ac
        /*
         *      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) {
@@ -1204,7 +1204,7 @@ static rlm_rcode_t user_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_ac
                        continue;
                }
 
-               switch (cf_pair_value_type(cp)) {
+               switch (cf_pair_value_quote(cp)) {
                case T_BARE_WORD:
                case T_SINGLE_QUOTED_STRING:
                        break;
@@ -1389,7 +1389,7 @@ static int parse_sub_section(rlm_ldap_t *inst, CONF_SECTION *parent, ldap_acct_s
 
        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);
@@ -1493,7 +1493,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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 */
        }
@@ -1503,7 +1503,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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;
        }
@@ -1513,7 +1513,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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;
@@ -1527,20 +1527,20 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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;
        }
@@ -1548,7 +1548,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
 #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;
        }
@@ -1556,7 +1556,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
 #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;
        }
@@ -1578,7 +1578,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                        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;
 
@@ -1600,19 +1600,19 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                        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;
                        }
 
@@ -1620,7 +1620,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                         *      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 */
@@ -1648,7 +1648,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                                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;
                                                }
@@ -1675,7 +1675,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
                                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);
@@ -1689,7 +1689,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                            ((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;
                        }
@@ -1740,10 +1740,10 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                        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;
                        }
@@ -1795,7 +1795,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
                }
@@ -1807,7 +1807,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      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;
@@ -1819,7 +1819,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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
@@ -1831,7 +1831,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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
@@ -1843,7 +1843,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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
@@ -1866,7 +1866,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
                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;
                }
@@ -1892,12 +1892,12 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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");
 
@@ -1908,7 +1908,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        /*
         *      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)) {
@@ -1933,22 +1933,22 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
                }
index 571a391e5e52c12f8ed02bc6d59564e4f2509ccf..5701f17ee7c2805f7b5d1bdb658f5856d62114d4 100644 (file)
@@ -311,12 +311,12 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
        }
 
@@ -332,13 +332,13 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
                }
 
@@ -348,7 +348,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                        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;
                                }
@@ -362,13 +362,13 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
@@ -376,7 +376,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
                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;
@@ -386,23 +386,23 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
@@ -535,7 +535,7 @@ static rlm_rcode_t mod_do_linelog(void *instance, UNUSED void *thread, REQUEST *
                 *      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;
index 5a2db521cad21a15c62aef4eb40ec208b572f46e..d468c1df365f2c7a1036ad7058cd803a8ce5e063 100644 (file)
@@ -206,7 +206,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
 
index f7b63231e1278671ddfe2547b34cea2611655be4..343e35aab6c5c362ffebabf67075e84a882b394c 100644 (file)
@@ -551,7 +551,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
        }
 
@@ -568,12 +568,12 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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
 
index d176dffdf8967cbe4537edb3f0e26aa6ff41b68e..155757ab489c342ee9c66f710a0995464d995e8e 100644 (file)
@@ -78,7 +78,7 @@ static void mruby_parse_config(mrb_state *mrb, CONF_SECTION *cs, int lvl, mrb_va
 
        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);
@@ -183,7 +183,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        /* 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 */
index a1507fcd805da160de849f528ca11ae7bb8cb8b5..84693e55b1d36a1b45cac45af9706442fb8506b5 100644 (file)
@@ -617,11 +617,11 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
                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
        }
@@ -652,12 +652,12 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
        }
index cc0d5c1ef17443f3ae7c2ac1885ead0dbb2dc001..68f03a0ecccd67ca8255c0ef89bed9ee9deaed38 100644 (file)
@@ -394,7 +394,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -429,7 +429,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
        }
@@ -465,7 +465,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
index 0ab56af6d7bbd1b942ac86ea2d4042ab387917b9..fd00b009fdd661508c6610ecce70b95c4a980acf 100644 (file)
@@ -443,7 +443,7 @@ static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
 
        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,
@@ -603,7 +603,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        }
 
        /* 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);
index 3cbef4939dc70f93d62bd9d5e2411d855f26d061..a79a02411757420b0f7ecdcbf130b47b17aada38 100644 (file)
@@ -796,7 +796,7 @@ static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
 
        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,
@@ -984,7 +984,7 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
                 */
                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;
index ee5a6badb4425c236c4c981bc49ba5da50f6cb44..47199c47efa3574eaed27715e95e5db2c595cce4 100644 (file)
@@ -235,14 +235,14 @@ static rlm_rcode_t mod_resume_continue(REQUEST *request, void *instance, void *t
        }
 
        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;
@@ -592,11 +592,11 @@ static rlm_rcode_t CC_HINT(nonnull) mod_process(void *instance, void *thread, RE
         */
        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;
@@ -634,13 +634,13 @@ static int mod_compile_section(CONF_SECTION *server_cs, char const *name1, char
 {
        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;
        }
 
@@ -657,32 +657,32 @@ static int mod_bootstrap(CONF_SECTION *config, void *instance)
        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;
        }
 
@@ -692,9 +692,9 @@ static int mod_bootstrap(CONF_SECTION *config, void *instance)
 
        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;
        }
 
@@ -730,7 +730,7 @@ static int mod_bootstrap(CONF_SECTION *config, void *instance)
                break;
 
        default:
-               cf_log_err_cs(config, "Internal sanity check error");
+               cf_log_err(config, "Internal sanity check error");
                return -1;
        }
 
index 88012df732cde32bf0558c5206602c57e8fc97c1..0dc0db221aafeaddd168f6cd310e218146017716 100644 (file)
@@ -370,7 +370,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
        }
@@ -378,7 +378,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
index 57e7c84d0ec0060886f7804bff7e3509d5f22ac9..4810948fc86d846d83722beb98463ce181c3efd1 100644 (file)
@@ -381,7 +381,7 @@ static cluster_rcode_t cluster_node_connect(fr_redis_cluster_t *cluster, cluster
                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);
@@ -2240,7 +2240,7 @@ fr_redis_cluster_t *fr_redis_cluster_alloc(TALLOC_CTX *ctx,
        /*
         *      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);
index 3faa8a5ea48248b430e1d0c4bc5d862193de5d20..a11bc47adaa00961bb5b719c7ce9a895039838f4 100644 (file)
@@ -1292,7 +1292,7 @@ static rlm_rcode_t mod_post_auth(void *instance, UNUSED void *thread, REQUEST *r
 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;
 
index 068a2a8872027cf84766c73788e1843ae157c72b..d5309a0efaca90f3742b91186145f46bdc7d317e 100644 (file)
@@ -1515,7 +1515,7 @@ do { \
        /*
         *      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);
index 108d1052db540ff981d30f7cd40a312219af77d4..9232b2ead3f58b5a2769bc2d605f284d2c47b6b8 100644 (file)
@@ -186,7 +186,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, UNUSED void *
                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;
index 5e02e278db3df840da49b67e0554ec6443a9904b..303d415a2eced43d807a3c079fca990621b417e0 100644 (file)
@@ -755,7 +755,7 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER
 {
        CONF_SECTION *cs;
 
-       cs = cf_subsection_find(parent, name);
+       cs = cf_section_find(parent, name, NULL);
        if (!cs) {
                config->name = NULL;
                return 0;
@@ -775,7 +775,7 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER
         *  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;
         }
@@ -785,11 +785,11 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER
         */
        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;
@@ -811,23 +811,23 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER
                }
 
                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;
 
@@ -857,18 +857,18 @@ static int parse_sub_section(rlm_rest_t *inst, CONF_SECTION *parent, CONF_PARSER
                }
 
                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;
 
index 94a104a0a3931419924557c22c2bba19facb7b4f..1536be542fb0c0967049796bcecd9acd3845b535 100644 (file)
@@ -213,14 +213,14 @@ static int sigtran_sccp_sockaddr_from_conf(TALLOC_CTX *ctx, rlm_sigtran_t *inst,
         *      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;
                }
@@ -239,25 +239,25 @@ static int sigtran_sccp_sockaddr_from_conf(TALLOC_CTX *ctx, rlm_sigtran_t *inst,
                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;
                        }
 
@@ -273,7 +273,7 @@ static int sigtran_sccp_sockaddr_from_conf(TALLOC_CTX *ctx, rlm_sigtran_t *inst,
 
                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;
                        }
@@ -313,7 +313,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
@@ -321,7 +321,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 #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; \
                } \
index 82cbff89c45e0ee11e9ab8ac598b167df6ce705b..50a1b5a130f88562b5c8b82405584b84dc71e01e 100644 (file)
@@ -56,7 +56,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         */
        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;
        }
 
index afbc05da03b5cde5d32b323e7d9496977daeb0c2..ebf369428180e48654929e6d722dbe473cb72c6c 100644 (file)
@@ -714,8 +714,8 @@ do {\
         *      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();
index 60fc55c717e783fbe2ed6759a782b40cd673d27c..f52a6ba4ed3c6168faeaf864f8a767e4e39497fb 100644 (file)
@@ -440,7 +440,7 @@ static int mod_instantiate(rlm_sql_config_t const *config, void *instance, CONF_
                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);
index ef1be0b768df9696c898bbe01f44a2cba45bddd5..b16b87e4e29e154977bc3886b98be27358e91a50 100644 (file)
@@ -284,7 +284,7 @@ static int sql_map_verify(CONF_SECTION *cs, UNUSED void *mod_inst, UNUSED void *
                          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;
        }
@@ -1074,7 +1074,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        /*
         *      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;
@@ -1203,10 +1203,10 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      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);
 
        /*
@@ -1236,7 +1236,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
        }
 
index 8d10ed171f49dcdd5d9a96bc502b211a82592142..44c1e113f4eff08300bcd350557e2821bf9ca5eb 100644 (file)
@@ -546,7 +546,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -556,7 +556,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -577,30 +577,30 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        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;
        }
index 36d7f81a7d36164e125fe89e7188cf8c797f5377..f4056fe08122e56dc22cf9eeb77bf07b17b71dc4 100644 (file)
@@ -268,9 +268,9 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
        }
@@ -281,7 +281,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        /* 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;
        }
index 7a914ec34985f473b826240355edd6b5171d39f2..44848225bc9ea3987b7f1efcaa260014d568ebd5 100644 (file)
@@ -384,9 +384,9 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        } 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;
        }
@@ -400,7 +400,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
index f081e7f4616847fbbce8772f0c33abb3cdf591c7..b3103d5de8ad4e92b52767c1f7b7e7832ac92f09 100644 (file)
@@ -376,7 +376,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -387,7 +387,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -414,7 +414,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 
        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;
        }
 
@@ -588,13 +588,13 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                 * 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;
                }
 
@@ -639,7 +639,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
                }
@@ -649,7 +649,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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);
index d1cdafd830e42b5f4012186b764fa445f8a64a8a..45a3930a0ae360f29ffe3fbfe38853f6cd538144 100644 (file)
@@ -350,13 +350,13 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        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;
        }
 
@@ -368,12 +368,12 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
                }
 
@@ -381,14 +381,14 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                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;
                }
 
@@ -396,7 +396,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                               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);
index 85411a7e012a4ecb0848085dbdaeb78f61b0863b..51995dcde4b66696c42bd06f5665408913890778 100644 (file)
@@ -126,7 +126,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
 
 #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
@@ -156,9 +156,9 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
 #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;
                }
 
@@ -166,7 +166,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                        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
        }
index 9b6ca315d6ac152ac613a98ab88d04e5b51fc977..8165d4a2260784040359cf1183f528e2794e8734 100644 (file)
@@ -88,7 +88,7 @@ yk_error:
        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;
                /*
index f212d0c9ac059b88827493fac5e58b80da4cdb94..3300be509a0205507ce651a227ba03734873059c 100644 (file)
@@ -13,9 +13,18 @@ security {
        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 {
diff --git a/user_password b/user_password
new file mode 100644 (file)
index 0000000..a0124c8
--- /dev/null
@@ -0,0 +1,2 @@
+User-Name := bob
+User-Password := bob