Update the GPL boilerplate with the new address of the FSF.
[freeradius.git] / src / main / modules.c
index 74400da..4e1eca9 100644 (file)
  *
  *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000  The FreeRADIUS server project
+ * Copyright 2003  The FreeRADIUS server project
  * Copyright 2000  Alan DeKok <aland@ox.org>
  * Copyright 2000  Alan Curry <pacman@world.std.com>
  */
 
 static const char rcsid[] = "$Id$";
 
-#include "autoconf.h"
-#include "libradius.h"
+#include <freeradius-devel/autoconf.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "radiusd.h"
-#include "modpriv.h"
-#include "modules.h"
-#include "modcall.h"
-#include "conffile.h"
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/conffile.h>
 #include "ltdl.h"
-#include "rad_assert.h"
-
-/*
- *     Internal list of all of the modules we have loaded.
- */
-static module_list_t *module_list = NULL;
-
-/*
- *     Internal list of each module instance.
- */
-static module_instance_t *module_instance_list = NULL;
+#include <freeradius-devel/rad_assert.h>
 
 typedef struct indexed_modcallable {
        struct indexed_modcallable *next;
@@ -60,36 +49,44 @@ typedef struct indexed_modcallable {
  */
 static indexed_modcallable *components[RLM_COMPONENT_COUNT];
 
+static rbtree_t *module_tree = NULL;
+
+typedef struct section_type_value_t {
+       const char      *section;
+       const char      *typename;
+       int             attr;
+} section_type_value_t;
+
+
 /*
- *     The component names.
- *
- *     Hmm... we probably should be getting these from the configuration
- *     file, too.
+ *     Ordered by component
  */
-const char *component_names[RLM_COMPONENT_COUNT] =
-{
-       "authenticate",
-       "authorize",
-       "preacct",
-       "accounting",
-       "session",
-       "pre-proxy",
-       "post-proxy",
-       "post-auth"
+static const section_type_value_t section_type_value[RLM_COMPONENT_COUNT] = {
+       { "authenticate", "Auth-Type",       PW_AUTH_TYPE },
+       { "authorize",    "Autz-Type",       PW_AUTZ_TYPE },
+       { "preacct",      "Pre-Acct-Type",   PW_PRE_ACCT_TYPE },
+       { "accounting",   "Acct-Type",       PW_ACCT_TYPE },
+       { "session",      "Session-Type",    PW_SESSION_TYPE },
+       { "pre-proxy",    "Pre-Proxy-Type",  PW_PRE_PROXY_TYPE },
+       { "post-proxy",   "Post-Proxy-Type", PW_POST_PROXY_TYPE },
+       { "post-auth",    "Post-Auth-Type",  PW_POST_AUTH_TYPE },
 };
 
-static const char *subcomponent_names[RLM_COMPONENT_COUNT] =
-{
-       "authtype",
-       "autztype",
-       "preacctype",
-       "acctype",
-       "sesstype",
-       "pre-proxytype",
-       "post-proxytype",
-       "post-authtype"
+/*
+ *     Delete ASAP.
+ */
+static const section_type_value_t old_section_type_value[] = {
+       { "authenticate", "authtype", PW_AUTH_TYPE },
+       { "authorize",    "autztype", PW_AUTZ_TYPE },
+       { "preacct",      "Pre-Acct-Type",   PW_PRE_ACCT_TYPE },/* unused */
+       { "accounting",   "acctype", PW_ACCT_TYPE },
+       { "session",      "sesstype", PW_SESSION_TYPE },
+       { "pre-proxy",    "Pre-Proxy-Type",  PW_PRE_PROXY_TYPE }, /* unused */
+       { "post-proxy",   "Post-Proxy-Type", PW_POST_PROXY_TYPE }, /* unused */
+       { "post-auth",    "post-authtype", PW_POST_AUTH_TYPE }
 };
 
+
 static void indexed_modcallable_free(indexed_modcallable **cf)
 {
        indexed_modcallable     *c, *next;
@@ -104,38 +101,58 @@ static void indexed_modcallable_free(indexed_modcallable **cf)
        *cf = NULL;
 }
 
-static void instance_list_free(module_instance_t **i)
+/*
+ *     Free a module instance.
+ */
+static void module_instance_free(void *data)
 {
-       module_instance_t       *c, *next;
+       module_instance_t *this = data;
 
-       c = *i;
-       while (c) {
-               next = c->next;
-               if(c->entry->module->detach)
-                       (c->entry->module->detach)(c->insthandle);
-#if HAVE_PTHREAD_H
-               if (c->mutex) {
-                       /*
-                        *      FIXME
-                        *      The mutex MIGHT be locked...
-                        *      we'll check for that later, I guess.
-                        */
-                       pthread_mutex_destroy(c->mutex);
-                       free(c->mutex);
-               }
-#endif
-               free(c);
-               c = next;
+       if (this->entry->module->detach)
+               (this->entry->module->detach)(this->insthandle);
+#ifdef HAVE_PTHREAD_H
+       if (this->mutex) {
+               /*
+                *      FIXME
+                *      The mutex MIGHT be locked...
+                *      we'll check for that later, I guess.
+                */
+               pthread_mutex_destroy(this->mutex);
+               free(this->mutex);
        }
-       *i = NULL;
+#endif
+       free(this);
+}
+
+
+/*
+ *     Compare two module entries
+ */
+static int module_entry_cmp(const void *one, const void *two)
+{
+       const module_entry_t *a = one;
+       const module_entry_t *b = two;
+
+       return strcmp(a->name, b->name);
 }
 
 /*
- *     Remove all of the modules.
+ *     Free a module entry.
+ */
+static void module_entry_free(void *data)
+{
+       module_entry_t *this = data;
+
+       lt_dlclose(this->handle);       /* ignore any errors */
+       free(this);
+}
+
+
+/*
+ *     Remove the module lists.
  */
 int detach_modules(void)
 {
-       module_list_t *ml, *next;
        int i;
 
        /*
@@ -145,46 +162,25 @@ int detach_modules(void)
                indexed_modcallable_free(&components[i]);
        }
 
-       instance_list_free(&module_instance_list);
-
-       ml = module_list;
-       while (ml) {
-               next = ml->next;
-               if (ml->module->destroy)
-                       (ml->module->destroy)();
-               lt_dlclose(ml->handle); /* ignore any errors */
-               free(ml);
-               ml = next;
-       }
-
-       module_list = NULL;
-
        return 0;
 }
 
 /*
  *     Find a module on disk or in memory, and link to it.
  */
-static module_list_t *linkto_module(const char *module_name,
-               const char *cffilename, int cflineno)
+static module_entry_t *linkto_module(const char *module_name,
+                                    const char *cffilename, int cflineno)
 {
-       module_list_t *node;
+       module_entry_t myentry;
+       module_entry_t *node;
        lt_dlhandle handle;
        char module_struct[256];
        char *p;
+       const void *module;
 
-       /*
-        *      Look through the global module library list for the
-        *      named module.
-        */
-       for (node = module_list; node != NULL; node = node->next) {
-               /*
-                *      Found the named module.  Return it.
-                */
-               if (strcmp(node->name, module_name) == 0)
-                       return node;
-
-       }
+       strNcpy(myentry.name, module_name, sizeof(myentry.name));
+       node = rbtree_finddata(module_tree, &myentry);
+       if (node) return node;
 
        /*
         *      Keep the handle around so we can dlclose() it.
@@ -192,50 +188,65 @@ static module_list_t *linkto_module(const char *module_name,
        handle = lt_dlopenext(module_name);
        if (handle == NULL) {
                radlog(L_ERR|L_CONS, "%s[%d] Failed to link to module '%s':"
-                               " %s\n", cffilename, cflineno, module_name, lt_dlerror());
+                      " %s\n", cffilename, cflineno, module_name, lt_dlerror());
                return NULL;
        }
 
-       /* make room for the module type */
-       node = (module_list_t *) rad_malloc(sizeof(module_list_t));
-
-       /* fill in the module structure */
-       node->next = NULL;
-       node->handle = handle;
-       strNcpy(node->name, module_name, sizeof(node->name));
-       
        /*
         *      Link to the module's rlm_FOO{} module structure.
+        *
+        *      The module_name variable has the version number
+        *      embedded in it, and we don't want that here.
         */
-       /* module_name has the version embedded; strip it. */
        strcpy(module_struct, module_name);
        p = strrchr(module_struct, '-');
-       if (p)
-               *p = '\0';
-       node->module = (module_t *) lt_dlsym(node->handle, module_struct);
-       if (!node->module) {
+       if (p) *p = '\0';
+
+       DEBUG3("    (Loaded %s, checking if it's valid)", module_name);
+
+       /*
+        *      libltld MAY core here, if the handle it gives us contains
+        *      garbage data.
+        */
+       module = lt_dlsym(handle, module_struct);
+       if (!module) {
                radlog(L_ERR|L_CONS, "%s[%d] Failed linking to "
                                "%s structure in %s: %s\n",
                                cffilename, cflineno,
                                module_name, cffilename, lt_dlerror());
-               lt_dlclose(node->handle);       /* ignore any errors */
-               free(node);
+               lt_dlclose(handle);
                return NULL;
        }
-       
-       /* call the modules initialization */
-       if (node->module->init && (node->module->init)() < 0) {
-               radlog(L_ERR|L_CONS, "%s[%d] Module initialization failed.\n",
-                               cffilename, cflineno);
-               lt_dlclose(node->handle);       /* ignore any errors */
-               free(node);
+       /*
+        *      Before doing anything else, check if it's sane.
+        */
+       if ((*(const uint32_t *) module) != RLM_MODULE_MAGIC_NUMBER) {
+               lt_dlclose(handle);
+               radlog(L_ERR|L_CONS, "%s[%d] Invalid version in module '%s'",
+                      cffilename, cflineno, module_name);
                return NULL;
+               
        }
 
+       /* make room for the module type */
+       node = rad_malloc(sizeof(*node));
+       memset(node, 0, sizeof(*node));
+       strNcpy(node->name, module_name, sizeof(node->name));
+       node->module = module;
+       node->handle = handle;
+
        DEBUG("Module: Loaded %s ", node->module->name);
 
-       node->next = module_list;
-       module_list = node;
+       /*
+        *      Add the module as "rlm_foo-version" to the configuration
+        *      section.
+        */
+       if (!rbtree_insert(module_tree, node)) {
+               radlog(L_ERR, "Failed to cache module %s", module_name);
+               lt_dlclose(handle);
+               free(node);
+               return NULL;
+       }
 
        return node;
 }
@@ -243,44 +254,15 @@ static module_list_t *linkto_module(const char *module_name,
 /*
  *     Find a module instance.
  */
-module_instance_t *find_module_instance(const char *instname)
+module_instance_t *find_module_instance(CONF_SECTION *modules,
+                                       const char *instname)
 {
-       CONF_SECTION *cs, *inst_cs;
+       CONF_SECTION *cs;
        const char *name1, *name2;
-       module_instance_t *node, **last;
+       module_instance_t *node;
        char module_name[256];
 
-       /*
-        *      Look through the global module instance list for the
-        *      named module.
-        */
-       last = &module_instance_list;
-       for (node = module_instance_list; node != NULL; node = node->next) {
-               /*
-                *      Found the named instance.  Return it.
-                */
-               if (strcmp(node->name, instname) == 0)
-                       return node;
-
-               /*
-                *      Keep a pointer to the last entry to update...
-                */
-               last = &node->next;
-       }
-
-       /*
-        *      Instance doesn't exist yet. Try to find the
-        *      corresponding configuration section and create it.
-        */
-
-       /*
-        *      Look for the 'modules' configuration section.
-        */
-       cs = cf_section_find("modules");
-       if (cs == NULL) {
-               radlog(L_ERR|L_CONS, "ERROR: Cannot find a 'modules' section in the configuration file.\n");
-               return NULL;
-       }
+       if (!modules) return NULL;
 
        /*
         *      Module instances are declared in the modules{} block
@@ -288,64 +270,53 @@ module_instance_t *find_module_instance(const char *instname)
         *      name2 from the config section, or name1 if there was
         *      no name2.
         */
-       name1 = name2 = NULL;
-       for(inst_cs=cf_subsection_find_next(cs, NULL, NULL); 
-                       inst_cs != NULL;
-                       inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) {
-               name1 = cf_section_name1(inst_cs);
-               name2 = cf_section_name2(inst_cs);
-               if ( (name2 && !strcmp(name2, instname)) ||
-                    (!name2 && !strcmp(name1, instname)) )
-                       break;
-       }
-       if (inst_cs == NULL) {
+       cs = cf_section_sub_find_name2(modules, NULL, instname);
+       if (cs == NULL) {
                radlog(L_ERR|L_CONS, "ERROR: Cannot find a configuration entry for module \"%s\".\n", instname);
                return NULL;
        }
 
        /*
-        *      Found the configuration entry.
+        *      If there's already a module instance, return it.
         */
-       node = rad_malloc(sizeof(*node));
-       node->next = NULL;
-       node->insthandle = NULL;
-       
+       node = cf_data_find(cs, "instance");
+       if (node) return node;
+
+       name1 = cf_section_name1(cs);
+       name2 = cf_section_name2(cs);
+
        /*
-        *      Link to the module by name: rlm_FOO-major.minor
+        *      Found the configuration entry.
         */
-       if (strncmp(name1, "rlm_", 4)) {
-#if 0
-               snprintf(module_name, sizeof(module_name), "rlm_%s-%d.%d",
-                        name1, RADIUSD_MAJOR_VERSION, RADIUSD_MINOR_VERSION);
-#else
-               snprintf(module_name, sizeof(module_name), "rlm_%s",
-                        name1);
-#endif
-       } else {
-               strNcpy(module_name, name1, sizeof(module_name));
+       node = rad_malloc(sizeof(*node));
+       memset(node, 0, sizeof(*node));
 
-       }
+       node->insthandle = NULL;
 
        /*
-        *  FIXME: "radiusd.conf" is wrong here; must find cf filename
+        *      Names in the "modules" section aren't prefixed
+        *      with "rlm_", so we add it here.
         */
-       node->entry = linkto_module(module_name, "radiusd.conf",
-                                   cf_section_lineno(inst_cs));
+       snprintf(module_name, sizeof(module_name), "rlm_%s", name1);
+
+       node->entry = linkto_module(module_name,
+                                   mainconfig.radiusd_conf,
+                                   cf_section_lineno(cs));
        if (!node->entry) {
                free(node);
                /* linkto_module logs any errors */
                return NULL;
        }
-       
+
        /*
         *      Call the module's instantiation routine.
         */
        if ((node->entry->module->instantiate) &&
-           ((node->entry->module->instantiate)(inst_cs,
-                       &node->insthandle) < 0)) {
+           ((node->entry->module->instantiate)(cs, &node->insthandle) < 0)) {
                radlog(L_ERR|L_CONS,
-                               "radiusd.conf[%d]: %s: Module instantiation failed.\n",
-                               cf_section_lineno(inst_cs), instname);
+                               "%s[%d]: %s: Module instantiation failed.\n",
+                      mainconfig.radiusd_conf, cf_section_lineno(cs),
+                      instname);
                free(node);
                return NULL;
        }
@@ -356,7 +327,7 @@ module_instance_t *find_module_instance(const char *instname)
         */
        strNcpy(node->name, instname, sizeof(node->name));
 
-#if HAVE_PTHREAD_H
+#ifdef HAVE_PTHREAD_H
        /*
         *      If we're threaded, check if the module is thread-safe.
         *
@@ -375,11 +346,11 @@ module_instance_t *find_module_instance(const char *instname)
                node->mutex = NULL;
        }
 
-#endif 
-       *last = node;
+#endif
+       cf_data_add(cs, "instance", node, module_instance_free);
 
        DEBUG("Module: Instantiated %s (%s) ", name1, node->name);
-       
+
        return node;
 }
 
@@ -394,6 +365,9 @@ static indexed_modcallable *lookup_by_index(indexed_modcallable *head, int idx)
        return NULL;
 }
 
+/*
+ *     Create a new sublist.
+ */
 static indexed_modcallable *new_sublist(int comp, int idx)
 {
        indexed_modcallable **head = &components[comp];
@@ -404,7 +378,7 @@ static indexed_modcallable *new_sublist(int comp, int idx)
                /* It is an error to try to create a sublist that already
                 * exists. It would almost certainly be caused by accidental
                 * duplication in the config file.
-                * 
+                *
                 * index 0 is the exception, because it is used when we want
                 * to collect _all_ listed modules under a single index by
                 * default, which is currently the case in all components
@@ -433,6 +407,8 @@ static int indexed_modcall(int comp, int idx, REQUEST *request)
 
        this = lookup_by_index(components[comp], idx);
        if (!this) {
+               if (idx != 0) DEBUG2("  ERROR: Unknown value specified for %s.  Cannot perform requested action.",
+                                    section_type_value[comp].typename);
                /* Return a default value appropriate for the component */
                switch(comp) {
                        case RLM_COMPONENT_AUTZ:    return RLM_MODULE_NOTFOUND;
@@ -446,98 +422,158 @@ static int indexed_modcall(int comp, int idx, REQUEST *request)
                        default:                    return RLM_MODULE_FAIL;
                }
        }
+
+       DEBUG2("  Processing the %s section of %s",
+              section_type_value[comp].section, mainconfig.radiusd_conf);
        return modcall(comp, this->modulelist, request);
 }
 
-/* Load a flat module list, as found inside an authtype{} block */
-static void load_subcomponent_section(CONF_SECTION *cs, int comp, const char *filename)
+/*
+ *     Load a sub-module list, as found inside an Auth-Type foo {}
+ *     block
+ */
+static int load_subcomponent_section(CONF_SECTION *cs, int comp,
+                                    const char *filename)
 {
-       int idx;
        indexed_modcallable *subcomp;
        modcallable *ml;
        DICT_VALUE *dval;
+       const char *name2 = cf_section_name2(cs);
 
-       static int meaningless_counter = 1;
+       rad_assert(comp >= RLM_COMPONENT_AUTH);
+       rad_assert(comp <= RLM_COMPONENT_COUNT);
 
-       ml = compile_modgroup(comp, cs, filename);
-
-       /* We must assign a numeric index to this subcomponent. For
-        * auth, it is generated and placed in the dictionary by
-        * new_sectiontype_value(). The others are just numbers that are pulled
-        * out of thin air, and the names are neither put into the dictionary
-        * nor checked for uniqueness, but all that could be fixed in a few
-        * minutes, if anyone finds a real use for indexed config of
-        * components other than auth. */
-       dval = NULL;
-       if (comp==RLM_COMPONENT_AUTH) {
-               dval = dict_valbyname(PW_AUTHTYPE, cf_section_name2(cs));
-       } else if (comp == RLM_COMPONENT_AUTZ) {
-               dval = dict_valbyname(PW_AUTZTYPE, cf_section_name2(cs));
-       } else if (comp == RLM_COMPONENT_ACCT) {
-               dval = dict_valbyname(PW_ACCTTYPE, cf_section_name2(cs));
-       } else if (comp == RLM_COMPONENT_SESS) {
-               dval = dict_valbyname(PW_SESSTYPE, cf_section_name2(cs));
-       } else if (comp == RLM_COMPONENT_POST_AUTH) {
-               dval = dict_valbyname(PW_POSTAUTHTYPE, cf_section_name2(cs));
+       /*
+        *      Sanity check.
+        */
+       if (!name2) {
+               radlog(L_ERR|L_CONS,
+                      "%s[%d]: No name specified for %s block",
+                      filename, cf_section_lineno(cs),
+                      section_type_value[comp].typename);
+               return 1;
        }
 
-       if (dval) {
-               idx = dval->value;
-       } else {
-               idx = meaningless_counter++;
+       /*
+        *      Compile the group.
+        */
+       ml = compile_modgroup(comp, cs, filename);
+       if (!ml) {
+               return 0;
+       }       
+
+       /*
+        *      We must assign a numeric index to this subcomponent.
+        *      It is generated and placed in the dictionary by
+        *      setup_modules(), when it loads the sections.  If it
+        *      isn't found, it's a serious error.
+        */
+       dval = dict_valbyname(section_type_value[comp].attr, name2);
+       if (!dval) {
+               radlog(L_ERR|L_CONS,
+                      "%s[%d] %s %s Not previously configured",
+                      filename, cf_section_lineno(cs),
+                      section_type_value[comp].typename, name2);
+               modcallable_free(&ml);
+               return 0;
        }
 
-       subcomp = new_sublist(comp, idx);
+       subcomp = new_sublist(comp, dval->value);
        if (!subcomp) {
                radlog(L_ERR|L_CONS,
-                               "%s[%d] %s %s already configured - skipping",
-                               filename, cf_section_lineno(cs),
-                               subcomponent_names[comp], cf_section_name2(cs));
+                      "%s[%d] %s %s already configured - skipping",
+                      filename, cf_section_lineno(cs),
+                      section_type_value[comp].typename, name2);
                modcallable_free(&ml);
-               return;
+               return 1;
        }
 
        subcomp->modulelist = ml;
+       return 1;               /* OK */
 }
 
-static void load_component_section(CONF_SECTION *cs, int comp, const char *filename)
+static int load_component_section(CONF_SECTION *cs, int comp,
+                                 const char *filename)
 {
        modcallable *this;
        CONF_ITEM *modref;
-       int modreflineno;
        int idx;
        indexed_modcallable *subcomp;
        const char *modname;
-       char *visiblename;
-
-       for (modref=cf_item_find_next(cs, NULL); 
-                       modref != NULL;
-                       modref=cf_item_find_next(cs, modref)) {
+       const char *visiblename;
 
+       /*
+        *      Loop over the entries in the named section.
+        */
+       for (modref = cf_item_find_next(cs, NULL);
+            modref != NULL;
+            modref = cf_item_find_next(cs, modref)) {
+               /*
+                *      Look for Auth-Type foo {}, which are special
+                *      cases of named sections, and allowable ONLY
+                *      at the top-level.
+                *
+                *      i.e. They're not allowed in a "group" or "redundant"
+                *      subsection.
+                */
                if (cf_item_is_section(modref)) {
+                       const char *sec_name;
                        CONF_SECTION *scs;
                        scs = cf_itemtosection(modref);
 
-                       if (strcmp(cf_section_name1(scs),
-                                  subcomponent_names[comp]) == 0) {
-                               load_subcomponent_section(scs, comp, filename);
+                       sec_name = cf_section_name1(scs);
+
+                       if (strcmp(sec_name,
+                                  section_type_value[comp].typename) == 0) {
+                               if (!load_subcomponent_section(scs, comp,
+                                                              filename)) {
+                                       return -1; /* FIXME: memleak? */
+                               }
                                continue;
                        }
 
-                       modreflineno = cf_section_lineno(scs);
+                       /*
+                        *      Allow old names, too.
+                        */
+                       if (strcmp(sec_name,
+                                  old_section_type_value[comp].typename) == 0) {
+                               if (!load_subcomponent_section(scs, comp,
+                                                              filename)) {
+                                       return -1; /* FIXME: memleak? */
+                               }
+                               continue;
+                       }
                } else {
                        CONF_PAIR *cp;
                        cp = cf_itemtopair(modref);
-                       modreflineno = cf_pair_lineno(cp);
                }
 
+               /*
+                *      Try to compile one entry.
+                */
                this = compile_modsingle(comp, modref, filename, &modname);
+               if (!this) {
+                       radlog(L_ERR|L_CONS,
+                              "%s[%d] Failed to parse %s section.\n",
+                              filename, cf_section_lineno(cs),
+                              cf_section_name1(cs));
+                       return -1;
+               }
 
                if (comp == RLM_COMPONENT_AUTH) {
                        DICT_VALUE *dval;
 
-                       dval = dict_valbyname(PW_AUTHTYPE, modname);
-                       rad_assert(dval != NULL);
+                       dval = dict_valbyname(PW_AUTH_TYPE, modname);
+                       if (!dval) {
+                               /*
+                                *      It's a section, but nothing we
+                                *      recognize.  Die!
+                                */
+                               radlog(L_ERR|L_CONS, "%s[%d] Unknown Auth-Type \"%s\" in %s section.",
+                                      filename, cf_section_lineno(cs),
+                                      modname, section_type_value[comp].section);
+                               return -1;
+                       }
                        idx = dval->value;
                } else {
                        /* See the comment in new_sublist() for explanation
@@ -547,9 +583,9 @@ static void load_component_section(CONF_SECTION *cs, int comp, const char *filen
 
                subcomp = new_sublist(comp, idx);
                if (subcomp == NULL) {
-                       radlog(L_ERR|L_CONS,
+                       radlog(L_INFO|L_CONS,
                                        "%s %s %s already configured - skipping",
-                                       filename, subcomponent_names[comp],
+                                       filename, section_type_value[comp].typename,
                                        modname);
                        modcallable_free(&this);
                        continue;
@@ -561,24 +597,12 @@ static void load_component_section(CONF_SECTION *cs, int comp, const char *filen
                if (visiblename == NULL)
                        visiblename = cf_section_name1(cs);
                add_to_modcallable(&subcomp->modulelist, this,
-                               comp, visiblename);
+                                  comp, visiblename);
        }
-}
 
-typedef struct section_type_value_t {
-       const char      *section;
-       const char      *typename;
-       int             attr;
-} section_type_value_t;
+       return 0;
+}
 
-static const section_type_value_t section_type_value[] = {
-       { "authorize",    "autztype", PW_AUTZTYPE },
-       { "authenticate", "authtype", PW_AUTHTYPE },
-       { "accounting",   "accttype", PW_ACCTTYPE },
-       { "session",     "sesstype", PW_SESSTYPE },
-       { "post-auth",  "post-authtype", PW_POSTAUTHTYPE },
-       { NULL, NULL, 0 }
-};
 
 /*
  *     Parse the module config sections, and load
@@ -587,24 +611,21 @@ static const section_type_value_t section_type_value[] = {
  *     Libtool makes your life a LOT easier, especially with libltdl.
  *     see: http://www.gnu.org/software/libtool/
  */
-int setup_modules(void)
+int setup_modules(int reload)
 {
-       int comp;
-       CONF_SECTION *cs;
-
-       /*
-        *  FIXME: This should be pulled from somewhere else.
-        */
-       const char *filename="radiusd.conf";
+       int             comp;
+       CONF_SECTION    *cs, *modules;
+       int             do_component[RLM_COMPONENT_COUNT];
+       rad_listen_t    *listener;
 
        /*
-        *      No current list of modules: Go initialize libltdl.
+        *      If necessary, initialize libltdl.
         */
-       if (!module_list) {
+       if (!reload) {
                /*
                 *      Set the default list of preloaded symbols.
                 *      This is used to initialize libltdl's list of
-                *      preloaded modules. 
+                *      preloaded modules.
                 *
                 *      i.e. Static modules.
                 */
@@ -613,8 +634,7 @@ int setup_modules(void)
                if (lt_dlinit() != 0) {
                        radlog(L_ERR|L_CONS, "Failed to initialize libraries: %s\n",
                                        lt_dlerror());
-                       exit(1); /* FIXME */
-                       
+                       return -1;
                }
 
                /*
@@ -623,7 +643,7 @@ int setup_modules(void)
                 *      any location on the disk.
                 */
                lt_dlsetsearchpath(radlib_dir);
-               
+
                DEBUG2("Module: Library search path is %s",
                                lt_dlgetsearchpath());
 
@@ -634,29 +654,86 @@ int setup_modules(void)
                        components[comp] = NULL;
                }
 
+               /*
+                *      Set up the internal module struct.
+                */
+               module_tree = rbtree_create(module_entry_cmp,
+                                           module_entry_free, 0);
+               if (!module_tree) {
+                       radlog(L_ERR|L_CONS, "Failed to initialize modules\n");
+                       return -1;
+               }
+               
+
        } else {
                detach_modules();
        }
 
        /*
+        *      Figure out which sections to load.
+        */
+       memset(do_component, 0, sizeof(do_component));
+       for (listener = mainconfig.listen;
+            listener != NULL;
+            listener = listener->next) {
+               switch (listener->type) {
+               case RAD_LISTEN_AUTH:
+                       do_component[RLM_COMPONENT_AUTZ] = 1;
+                       do_component[RLM_COMPONENT_AUTH] = 1;
+                       do_component[RLM_COMPONENT_POST_AUTH] = 1;
+                       do_component[RLM_COMPONENT_SESS] = 1;
+                       break;
+
+               case RAD_LISTEN_DETAIL: /* just like acct */
+               case RAD_LISTEN_ACCT:
+                       do_component[RLM_COMPONENT_PREACCT] = 1;
+                       do_component[RLM_COMPONENT_ACCT] = 1;
+                       break;
+
+               case RAD_LISTEN_PROXY:
+                       do_component[RLM_COMPONENT_PRE_PROXY] = 1;
+                       do_component[RLM_COMPONENT_POST_PROXY] = 1;
+                       break;
+
+               default:
+                       rad_assert(0 == 1);
+                       break;
+               }
+       }
+
+       for (comp = RLM_COMPONENT_AUTH; comp < RLM_COMPONENT_COUNT; comp++) {
+               /*
+                *      Have the debugging messages all in one place.
+                */
+               if (!do_component[comp]) {
+                       DEBUG2("modules: Not loading %s{} section",
+                              section_type_value[comp].section);
+               }
+       }
+
+       /*
         *      Create any DICT_VALUE's for the types.  See
         *      'doc/configurable_failover' for examples of 'authtype'
         *      used to create new Auth-Type values.  In order to
         *      let the user create new names, we've got to look for
         *      those names, and create DICT_VALUE's for them.
         */
-       for (comp = 0; section_type_value[comp].section != NULL; comp++) {
+       for (comp = RLM_COMPONENT_AUTH; comp < RLM_COMPONENT_COUNT; comp++) {
+               int             value;
                const char      *name2;
                DICT_ATTR       *dattr;
                DICT_VALUE      *dval;
-               CONF_SECTION    *sub;
+               CONF_SECTION    *sub, *next;
+               CONF_PAIR       *cp;
 
                /*
-                *  Big-time YUCK
+                *      Not needed, don't load it.
                 */
-               static int my_value = 32767;
-
+               if (!do_component[comp]) {
+                       continue;
+               }
                cs = cf_section_find(section_type_value[comp].section);
+
                if (!cs) continue;
 
                sub = NULL;
@@ -665,9 +742,17 @@ int setup_modules(void)
                         *      See if there's a sub-section by that
                         *      name.
                         */
-                       sub = cf_subsection_find_next(cs, sub,
-                                                     section_type_value[comp].typename);
-                       if (!sub) continue;
+                       next = cf_subsection_find_next(cs, sub,
+                                                      section_type_value[comp].typename);
+
+                       /*
+                        *      Allow some old names, too.
+                        */
+                       if (!next && (comp <= 4)) {
+                               next = cf_subsection_find_next(cs, sub,
+                                                              old_section_type_value[comp].typename);
+                       }
+                       sub = next;
 
                        /*
                         *      If so, look for it to define a new
@@ -676,6 +761,7 @@ int setup_modules(void)
                        name2 = cf_section_name2(sub);
                        if (!name2) continue;
 
+
                        /*
                         *      If the value already exists, don't
                         *      create it again.
@@ -688,19 +774,88 @@ int setup_modules(void)
                                 *      Find the attribute for the value.
                         */
                        dattr = dict_attrbyvalue(section_type_value[comp].attr);
-                       if (!dattr) continue;
+                       if (!dattr) {
+                               radlog(L_ERR, "%s[%d]: No such attribute %s",
+                                      mainconfig.radiusd_conf,
+                                      cf_section_lineno(sub),
+                                      section_type_value[comp].typename);
+                               continue;
+                       }
 
                        /*
-                        *      Finally, create the new attribute.
+                        *      Create a new unique value with a
+                        *      meaningless number.  You can't look at
+                        *      it from outside of this code, so it
+                        *      doesn't matter.  The only requirement
+                        *      is that it's unique.
                         */
-                       if (dict_addvalue(name2, dattr->name, my_value++) < 0) {
+                       do {
+                               value = lrad_rand() & 0x00ffffff;
+                       } while (dict_valbyattr(dattr->attr, value));
+
+                       if (dict_addvalue(name2, dattr->name, value) < 0) {
                                radlog(L_ERR, "%s", librad_errstr);
-                               exit(1);
+                               return -1;
                        }
                } while (sub != NULL);
+
+               /*
+                *      Loop over the non-sub-sections, too.
+                */
+               cp = NULL;
+               do {
+                       /*
+                        *      See if there's a conf-pair by that
+                        *      name.
+                        */
+                       cp = cf_pair_find_next(cs, cp, NULL);
+                       if (!cp) break;
+
+
+                       /*
+                        *      If the value already exists, don't
+                        *      create it again.
+                        */
+                       name2 = cf_pair_attr(cp);
+                       dval = dict_valbyname(section_type_value[comp].attr,
+                                             name2);
+                       if (dval) continue;
+
+                       /*
+                                *      Find the attribute for the value.
+                        */
+                       dattr = dict_attrbyvalue(section_type_value[comp].attr);
+                       if (!dattr) {
+                               radlog(L_ERR, "%s[%d]: No such attribute %s",
+                                      mainconfig.radiusd_conf,
+                                      cf_section_lineno(sub),
+                                      section_type_value[comp].typename);
+                               continue;
+                       }
+
+                       /*
+                        *      Finally, create the new attribute.
+                        */
+                       do {
+                               value = lrad_rand() & 0x00ffffff;
+                       } while (dict_valbyattr(dattr->attr, value));
+                       if (dict_addvalue(name2, dattr->name, value) < 0) {
+                               radlog(L_ERR, "%s", librad_errstr);
+                               return -1;
+                       }
+               } while (cp != NULL);
        } /* over the sections which can have redundent sub-sections */
 
        /*
+        *      Remember where the modules were stored.
+        */
+       modules = cf_section_find("modules");
+       if (!modules) {
+               radlog(L_ERR, "Cannot find a \"modules\" section in the configuration file!");
+               return -1;
+       }
+
+       /*
         *  Look for the 'instantiate' section, which tells us
         *  the instantiation order of the modules, and also allows
         *  us to load modules with no authorize/authenticate/etc.
@@ -716,20 +871,23 @@ int setup_modules(void)
                /*
                 *  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)) {
+               for (ci=cf_item_find_next(cs, NULL);
+                    ci != NULL;
+                    ci=cf_item_find_next(cs, ci)) {
+
+                       /*
+                        *      Skip sections.  They'll be handled
+                        *      later, if they're referenced at all...
+                        */
                        if (cf_item_is_section(ci)) {
-                               radlog(L_ERR|L_CONS,
-                                      "%s[%d] Subsection for module instantiate is not allowed\n", filename,
-                                      
-                                      cf_section_lineno(cf_itemtosection(ci)));
-                               exit(1);
+                               continue;
                        }
-       
+
                        cp = cf_itemtopair(ci);
                        name = cf_pair_attr(cp);
-                       module = find_module_instance(name);
+                       module = find_module_instance(modules, name);
                        if (!module) {
-                               exit(1);
+                               return -1;
                        }
                } /* loop over items in the subsection */
        } /* if there's an 'instantiate' section. */
@@ -739,11 +897,17 @@ int setup_modules(void)
         *      configuration section, and loading it.
         */
        for (comp = 0; comp < RLM_COMPONENT_COUNT; ++comp) {
-               cs = cf_section_find(component_names[comp]);
-               if (cs == NULL) 
+               cs = cf_section_find(section_type_value[comp].section);
+               if (cs == NULL)
                        continue;
-               
-               load_component_section(cs, comp, filename);
+
+               if (!do_component[comp]) {
+                       continue;
+               }
+
+               if (load_component_section(cs, comp, mainconfig.radiusd_conf) < 0) {
+                       return -1;
+               }
        }
 
        return 0;
@@ -756,12 +920,15 @@ int setup_modules(void)
 int module_authorize(int autz_type, REQUEST *request)
 {
        /*
-        *      We have a proxied packet, and we've been told
-        *      to NOT pass proxied packets through 'authorize'
-        *      a second time.  So stop.
+        *      Older versions of the server would pass proxy requests
+        *      through the 'authorize' sections twice; once when the
+        *      packet was received from the NAS, and again after the
+        *      reply was received from the home server.  Now that we
+        *      have a 'post_proxy' section, the replies from the home
+        *      server should be sent through that, instead of through
+        *      the 'authorize' section again.
         */
-       if ((request->proxy != NULL &&
-            mainconfig.post_proxy_authorize == FALSE)) {
+       if (request->proxy != NULL) {
                DEBUG2(" authorize: Skipping authorize in post-proxy stage");
                return RLM_MODULE_NOOP;
        }
@@ -825,17 +992,17 @@ int module_checksimul(int sess_type, REQUEST *request, int maxsimul)
 /*
  *     Do pre-proxying for ALL configured sessions
  */
-int module_pre_proxy(REQUEST *request)
+int module_pre_proxy(int type, REQUEST *request)
 {
-       return indexed_modcall(RLM_COMPONENT_PRE_PROXY, 0, request);
+       return indexed_modcall(RLM_COMPONENT_PRE_PROXY, type, request);
 }
 
 /*
  *     Do post-proxying for ALL configured sessions
  */
-int module_post_proxy(REQUEST *request)
+int module_post_proxy(int type, REQUEST *request)
 {
-       return indexed_modcall(RLM_COMPONENT_POST_PROXY, 0, request);
+       return indexed_modcall(RLM_COMPONENT_POST_PROXY, type, request);
 }
 
 /*