Patches from "Alan Curry" <pacman-radius@cqc.com>
authoraland <aland>
Fri, 25 Aug 2000 14:48:14 +0000 (14:48 +0000)
committeraland <aland>
Fri, 25 Aug 2000 14:48:14 +0000 (14:48 +0000)
Move the module auth/acct/autz decisions from raddb/modules
to raddb/radiusd.conf.

Add module instantiation, to have future allowances for
multiple versions of the same module, with different configurations.

Associated minor cleanups

19 files changed:
raddb/modules [deleted file]
raddb/radiusd.conf.in
src/include/conf.h
src/include/conffile.h
src/include/modules.h
src/main/builddbm.c
src/main/conffile.c
src/main/files.c
src/main/modules.c
src/modules/rlm_acct_unique/rlm_acct_unique.c
src/modules/rlm_dictionary/rlm_dictionary.c
src/modules/rlm_example/rlm_example.c
src/modules/rlm_files/rlm_files.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_pam/rlm_pam.c
src/modules/rlm_preprocess/rlm_preprocess.c
src/modules/rlm_realm/rlm_realm.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_unix/rlm_unix.c

diff --git a/raddb/modules b/raddb/modules
deleted file mode 100644 (file)
index e69de29..0000000
index 492f8c2..b7dde18 100644 (file)
@@ -355,121 +355,197 @@ client 10.10.10.10 {
 #      secret          = testing123
 #}
 
-#######################################################################
-#
-#  Configuration for the Unix module
-#
-
-module unix {
-
-#
-#  Cache /etc/passwd, /etc/shadow, and /etc/group
-#
-#  The default is to NOT cache them.  However, caching them can
-#  speed up system authentications by a substantial amount.
-#
-# allowed values: {no, yes}
-       cache           = no
-
-#
-#  Define the locations of the normal passwd, shadow, and group files.
-#
-#  'shadow' is commented out by default, because not all systems have
-#  shadow passwords.
-#
-       passwd          = /etc/passwd
-#      shadow          = /etc/shadow
-       group           = /etc/group
-}
+modules {
+       pam {
+               # No config options for this yet
+       }
+       unix {
+               #
+               #  Cache /etc/passwd, /etc/shadow, and /etc/group
+               #
+               #  The default is to NOT cache them.  However, caching them can
+               #  speed up system authentications by a substantial amount.
+               #
+               # allowed values: {no, yes}
+               cache           = no
+
+               #
+               #  Define the locations of the normal passwd, shadow, and
+               #  group files.
+               #
+               #  'shadow' is commented out by default, because not all
+               #  systems have shadow passwords.
+               #
+               passwd          = /etc/passwd
+               #       shadow          = /etc/shadow
+               group           = /etc/group
+       }
 
-#######################################################################
-#
-#  Configuration for the LDAP module.
-#
-module ldap {
-       server   = localhost
-       login    = "cn=admin,o=My Org,c=US"
-       password = mypass
-       basedn   = "o=My Org,c=US"
-       filter   = "(uid=%u)"
-}
+# Uncomment this if you want to use ldap (Auth-Type = LDAP)
+# Also uncomment it in the authenticate{} block below
+#      ldap {
+#              server   = localhost
+#              login    = "cn=admin,o=My Org,c=US"
+#              password = mypass
+#              basedn   = "o=My Org,c=US"
+#              filter   = "(uid=%u)"
+#      }
+
+       realm {
+               # No config options for this yet
+       }
+       preprocess {
+               # No config options for this yet
+       }
+       files {
+               usersfile = ${confdir}/users
+               acctusersfile = ${confdir}/acct_users
+               detailperm = 0600
+       }
 
-#######################################################################
 #
 #  Configuration for the SQL module.
 #
-module sql {
-
-       # Connect info
-       server          = "localhost"
-       login           = "root"
-       password        = "rootpass"
+       sql {
        
-       # Database table configuration
-       radius_db       = "radius"
-       acct_table      = "radacct"
+               # Connect info
+               server          = "localhost"
+               login           = "root"
+               password        = "rootpass"
+               
+               # Database table configuration
+               radius_db       = "radius"
+               acct_table      = "radacct"
+               
+               authcheck_table = "radcheck"
+               authreply_table = "radreply"
+               
+               groupcheck_table = "radgroupcheck"
+               groupreply_table = "radgroupreply"
+               
+               usergroup_table = "usergroup"
+               
+               realms_table    = "realms"
+               realmgroup_table = "realmgroup"
+               
+               # Check case on usernames
+               sensitiveusername = no
        
-       authcheck_table = "radcheck"
-       authreply_table = "radreply"
+               # Remove stale session if checkrad does not see a double login
+               deletestalesessions = yes
        
-       groupcheck_table = "radgroupcheck"
-       groupreply_table = "radgroupreply"
+               # Print all SQL statements when in debug mode (-x)
+               sqltrace        = no
+       }
+
+#
+#  A second instance of the same module, with the name "sql2" to identify it
+#
+       sql sql2 {
        
-       usergroup_table = "usergroup"
+               # Connect info
+               server          = "myothersever"
+               login           = "root"
+               password        = "rootpass"
+               
+               # Database table configuration
+               radius_db       = "radius"
+               acct_table      = "radacct"
+               
+               authcheck_table = "radcheck"
+               authreply_table = "radreply"
+               
+               groupcheck_table = "radgroupcheck"
+               groupreply_table = "radgroupreply"
+               
+               usergroup_table = "usergroup"
+               
+               realms_table    = "realms"
+               realmgroup_table = "realmgroup"
+               
+               # Check case on usernames
+               sensitiveusername = no
        
-       realms_table    = "realms"
-       realmgroup_table = "realmgroup"
+               # Remove stale session if checkrad does not see a double login
+               deletestalesessions = yes
        
-       # Check case on usernames
-       sensitiveusername = no
-
-       # Remove stale session if checkrad does not see a double login
-       deletestalesessions = yes
-
-       # Print all SQL statements when in debug mode (-x)
-       sqltrace        = no
-}
+               # Print all SQL statements when in debug mode (-x)
+               sqltrace        = no
+       }
 
 #######################################################################
 #
-#      Configuration for the example module.  Changing these values
-#      won't affect anything.
-#
-module example {
-#
-#  Boolean variable.
-#
-# allowed values: {no, yes}
-#
-       boolean         = yes
-
-#
-#  An integer, of any value.
-#
-       integer         = 16
-
-#
-#  A string.
-#
-       string          = "This is an example configuration string"
+#      Configuration for the example module.  Uncommenting it will cause it
+#      to get loaded and initialized, but should have no real effect as long
+#      it is not referencened in one of the autz/auth/preacct/acct sections
+#
+       example {
+       #
+       #  Boolean variable.
+       #
+       # allowed values: {no, yes}
+       #
+               boolean         = yes
+
+       #
+       #  An integer, of any value.
+       #
+               integer         = 16
+
+       #
+       #  A string.
+       #
+               string          = "This is an example configuration string"
+
+       #
+       # An IP address, either in dotted quad (1.2.3.4) or hostname
+       # (example.com)
+       #
+               ipaddr          = 127.0.0.1
+
+       #
+       # A subsection
+       #
+               mysubsection {
+                       anotherinteger = 1000
+       #
+       # They nest
+       #
+                       deeply nested {
+                               string = "This is a different string"
+                       }
+               }
+       }
+}
 
-#
-# An IP address, either in dotted quad (1.2.3.4) or hostname (example.com)
-#
-       ipaddr          = 127.0.0.1
+# Authentication types, Auth-Type = System and PAM for now.
+authenticate {
+       pam
+       unix
+#       sql
+#       sql2
+# Uncomment this if you want to use ldap (Auth-Type = LDAP)
+#      ldap
+}
 
-#
-# A subsection
-#
-       mysubsection {
-               anotherinteger = 1000
-#
-# They nest
-#
-               deeply nested {
-                       string = "This is a different string"
-               }
-       }
+# Authorization. First preprocess (hints and huntgroups files),
+# then look in the "users" file.
+authorize {
+       realm
+       preprocess
+       files
 }
 
+# Pre-accounting. Look for proxy realm, first with the @suffix rule, then the
+# acct_users file, then preprocess (hints file).
+preacct {
+       realm
+       files
+       preprocess
+}
 
+# Accounting. Log to detail file, and to the radwtmp file.
+accounting {
+       files
+       unix
+}
index 7472f73..5191d3d 100644 (file)
@@ -14,7 +14,6 @@
 #define RADIUS_HINTS           "hints"
 #define RADIUS_HUNTGROUPS      "huntgroups"
 #define RADIUS_REALMS          "realms"
-#define RADIUS_MODULES         "modules"
 
 #define RADUTMP                        LOGDIR "/radutmp"
 #define RADWTMP                        LOGDIR "/radwtmp"
index be2c50f..cb9ce18 100644 (file)
@@ -25,6 +25,7 @@ typedef struct conf_part {
        CONF_PAIR               *cps;
        struct conf_part        *sub;
        struct conf_part        *next;
+       struct conf_part        *parent;
 } CONF_SECTION;
 
 /*
@@ -50,7 +51,6 @@ CONF_SECTION  *conf_read(const char *conffile);
 CONF_PAIR      *cf_pair_alloc(const char *attr, const char *value, int operator);
 void           cf_pair_add(CONF_SECTION *cs, CONF_PAIR *cp_new);
 void           cf_pair_free(CONF_PAIR *cp);
-CONF_SECTION   *cf_section_alloc(const char *name1, const char *name2);
 void           cf_section_free(CONF_SECTION *cp);
 void           cf_section_free_all(CONF_SECTION *cp);
 int            cf_section_parse(CONF_SECTION *cs, const CONF_PARSER *variables);
@@ -61,11 +61,11 @@ CONF_PAIR   *cf_pair_find(CONF_SECTION *section, const char *name);
 CONF_PAIR      *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *name);
 CONF_SECTION   *cf_section_find(const char *name);
 CONF_SECTION   *cf_section_sub_find(CONF_SECTION *section, const char *name);
-CONF_SECTION   *cf_module_config_find(const char *modulename);
 char           *cf_section_value_find(CONF_SECTION *section, const char *attr);
 
 int            read_radius_conf_file(void);
 
+char *cf_pair_attr(CONF_PAIR *pair);
 char *cf_pair_value(CONF_PAIR *pair);
 int dump_config(void);
 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
index 32b7ab0..5ce9529 100644 (file)
@@ -5,6 +5,8 @@
  *
  */
 
+#include "conffile.h"
+
 /*
  *     The types of the functions which are supported by each module.
  *     The functional parameters are defined here, so we don't have to
@@ -19,16 +21,25 @@ typedef int (*RLM_POST_AUTHENTICATE_FUNCP)(REQUEST *request);
 typedef int (*RLM_PRE_ACCOUNTING_FUNCP)(REQUEST *request);
 typedef int (*RLM_ACCOUNTING_FUNCP)(REQUEST *request);
 
+/* Shouldn't need these anymore */
+#define RLM_COMPONENT_AUTZ 0
+#define RLM_COMPONENT_AUTH 1
+#define RLM_COMPONENT_PREACCT 2
+#define RLM_COMPONENT_ACCT 3
+#define RLM_COMPONENT_COUNT 4 /* How many components are there */
+
 typedef struct module_t {
        const char      *name;
        int     type;                   /* reserved */
-       int     (*init)(int argc, char **argv);
-       int     (*authorize)(REQUEST *request, 
+       int     (*init)(void);
+       int     (*instantiate)(CONF_SECTION *mod_cs, void **instance);
+       int     (*authorize)(void *instance, REQUEST *request, 
                        VALUE_PAIR **check_items, VALUE_PAIR **reply_items);
-       int     (*authenticate)(REQUEST *request);
-       int     (*preaccounting)(REQUEST *request);
-       int     (*accounting)(REQUEST *request);
-       int     (*detach)(void);
+       int     (*authenticate)(void *instance, REQUEST *request);
+       int     (*preaccounting)(void *instance, REQUEST *request);
+       int     (*accounting)(void *instance, REQUEST *request);
+       int     (*detach)(void *instance);
+       int     (*destroy)(void);
 } module_t;
 
 enum {
@@ -38,7 +49,7 @@ enum {
        RLM_MODULE_HANDLED = 1  /* the module handled the request, so stop. */
 };
 
-int read_modules_file(char *filename);
+int setup_modules(void);
 int module_authorize(REQUEST *request, 
        VALUE_PAIR **check_items, VALUE_PAIR **reply_items);
 int module_authenticate(int type, REQUEST *request);
index adf6c37..67e3f8d 100644 (file)
@@ -26,7 +26,7 @@ char sccsid[] =
 
 #include       "radiusd.h"
 
-char           *progname;
+const char     *progname;
 int            debug_flag;
 char           *radius_dir;
 char           *radlog_dir;
index 4803300..f99a929 100644 (file)
@@ -87,7 +87,8 @@ void cf_pair_free(CONF_PAIR *cp)
 /*
  *     Allocate a CONF_SECTION
  */
-CONF_SECTION *cf_section_alloc(const char *name1, const char *name2)
+static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
+                                      CONF_SECTION *parent)
 {
        CONF_SECTION    *cs;
 
@@ -97,6 +98,7 @@ CONF_SECTION *cf_section_alloc(const char *name1, const char *name2)
        memset(cs, 0, sizeof(CONF_SECTION));
        cs->name1 = xstrdup(name1);
        cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
+        cs->parent = parent;
 
        return cs;
 }
@@ -234,9 +236,10 @@ int cf_section_parse(CONF_SECTION *cs, const CONF_PARSER *variables)
  *     Read a part of the config file.
  */
 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
-                                    const char *name1, const char *name2)
+                                    const char *name1, const char *name2,
+                                     CONF_SECTION *parent)
 {
-       CONF_SECTION    *cs, *csp, *css;
+       CONF_SECTION    *cs, *csp, *css, *outercs;
        CONF_PAIR       *cpn;
        char            *ptr, *p, *q;
        char            buf[8192];
@@ -269,7 +272,7 @@ static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
        /*
         *      Allocate new section.
         */
-       cs = cf_section_alloc(name1, name2);
+       cs = cf_section_alloc(name1, name2, parent);
        cs->lineno = *lineno;
 
        /*
@@ -317,7 +320,7 @@ static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
 
                if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
                        css = cf_section_read(cf, lineno, fp, buf1,
-                                               t2==T_LCBRACE ? NULL : buf2);
+                                             t2==T_LCBRACE ? NULL : buf2, cs);
                        if (css == NULL) {
                                cf_section_free(cs);
                                return NULL;
@@ -384,6 +387,15 @@ static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
                        memcpy(buf2, ptr + 2, q - ptr - 2);
                        buf2[q - ptr - 2] = '\0';
                        cpn = cf_pair_find(cs, buf2);
+                        /* Also look recursively up the section tree,
+                         * so things like ${confdir} can be defined
+                         * there and used inside the module config
+                         * sections */
+                       for (outercs=cs->parent
+                             ; !cpn && outercs ;
+                             outercs=outercs->parent) {
+                               cpn = cf_pair_find(outercs, buf2);
+                       }
                        if (!cpn) {
                                log(L_ERR, "%s[%d]: Unknown variable \"%s\"",
                                    cf, *lineno, buf2);
@@ -431,7 +443,7 @@ CONF_SECTION *conf_read(const char *conffile)
                return NULL;
        }
 
-       cs = cf_section_read(conffile, &lineno, fp, NULL, NULL);
+       cs = cf_section_read(conffile, &lineno, fp, NULL, NULL, NULL);
        fclose(fp);
 
        return cs;
@@ -655,13 +667,22 @@ CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
        }
 
        for (cp = section->cps; cp; cp = cp->next)
-               if (strcmp(cp->attr, name) == 0)
+               if (name == NULL || strcmp(cp->attr, name) == 0)
                        break;
 
        return cp;
 }
 
 /*
+ * Return the attr of a CONF_PAIR
+ */
+
+char *cf_pair_attr(CONF_PAIR *pair)
+{
+       return (pair ? pair->attr : NULL);
+}
+
+/*
  * Return the value of a CONF_PAIR
  */
 
@@ -685,7 +706,8 @@ char *cf_section_value_find(CONF_SECTION *section, const char *attr)
 
 /*
  * Return the next pair after a CONF_PAIR
- * with a certain name (char *attr)
+ * with a certain name (char *attr) If the requested
+ * attr is NULL, any attr matches.
  */
 
 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
@@ -704,7 +726,7 @@ CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char
        }
 
        for (; cp; cp = cp->next)
-               if (strcmp(cp->attr, attr) == 0)
+               if (attr == NULL || strcmp(cp->attr, attr) == 0)
                        break;
 
        return cp;
@@ -740,7 +762,8 @@ CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
 
 /*
  * Return the next subsection after a CONF_SECTION
- * with a certain name1 (char *name1)
+ * with a certain name1 (char *name1). If the requested
+ * name1 is NULL, any name1 matches.
  */
 
 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
@@ -761,28 +784,12 @@ CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
        }
 
        for (; cp; cp = cp->next)
-               if (strcmp(cp->name1, name1) == 0)
+               if (name1 == NULL || strcmp(cp->name1, name1) == 0)
                        break;
 
        return cp;
 }
 
-/*
- * Find the configuration section for a module
- */
-
-CONF_SECTION *cf_module_config_find(const char *modulename)
-{
-       CONF_SECTION *cs;
-
-       for (cs = config->sub; cs; cs = cs->next)
-               if ((strcmp(cs->name1, "module") == 0)
-                       && (strcmp(cs->name2, modulename) == 0))
-                       break;
-
-       return cs;
-}
-
 /* 
  * JMG dump_config tries to dump the config structure in a readable format
  * 
index d89b934..3939217 100644 (file)
@@ -674,9 +674,8 @@ int read_config_files()
                return -1;
        }
 
-       sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_MODULES);
-       if (read_modules_file(buffer) < 0) {
-               log(L_ERR|L_CONS, "Errors reading modules");
+       if (setup_modules() < 0) {
+               log(L_ERR|L_CONS, "Errors setting up modules");
                return -1;
        }
 
index e5f734e..3d7988e 100644 (file)
@@ -37,8 +37,17 @@ typedef struct module_list_t {
 
 static module_list_t *module_list = NULL;
 
-typedef struct config_module_t {
+typedef struct module_instance_t {
        module_list_t           *entry;
+       char                    name[MAX_STRING_LEN];
+        void                    *insthandle;
+       struct module_instance_t *next;
+} module_instance_t;
+
+static module_instance_t *module_instance_list = NULL;
+
+typedef struct config_module_t {
+       module_instance_t       *instance;
        struct config_module_t  *next;
 } config_module_t;
 
@@ -60,64 +69,45 @@ static void config_list_free(config_module_t **cf)
        *cf = NULL;
 }
 
+static void instance_list_free(module_instance_t **i)
+{
+       module_instance_t       *c, *next;
+
+       c = *i;
+       while (c) {
+               next = c->next;
+               if(c->entry->module->detach)
+                       (c->entry->module->detach)(c->insthandle);
+               free(c);
+               c = next;
+       }
+       *i = NULL;
+}
+
 static void module_list_free(void)
 {
        module_list_t *ml, *next;
 
+       config_list_free(&authenticate);
+       config_list_free(&authorize);
+       config_list_free(&preacct);
+       config_list_free(&accounting);
+
+       instance_list_free(&module_instance_list);
+
        ml = module_list;
        while (ml) {
                next = ml->next;
-               if (ml->module->detach)
-                       (ml->module->detach)();
+               if (ml->module->destroy)
+                       (ml->module->destroy)();
                lt_dlclose(ml->handle); /* ignore any errors */
                free(ml);
                ml = next;
        }
 
        module_list = NULL;
-       config_list_free(&authenticate);
-       config_list_free(&authorize);
-       config_list_free(&preacct);
-       config_list_free(&accounting);
-}
-
-
-static module_list_t *find_module(module_list_t *head, char *filename)
-{
-       while (head) {
-               if (strcmp(head->filename, filename) == 0)
-                       return head;
-               head = head->next;
-       }
-       return NULL;
-}
-
-
-/*
- *     Add one entry at the end of the config_module_t list.
- */
-static void add_to_list(config_module_t **head, module_list_t *entry)
-{
-       config_module_t *node = *head;
-       config_module_t **last = head;
-
-       while (node) {
-               last = &node->next;
-               node = node->next;
-       }
-
-       node = (config_module_t *) malloc(sizeof(config_module_t));
-       if (!node) {
-               fprintf(stderr, "Out of memory\n");
-               exit(1);
-       }
-
-       node->next = NULL;
-       node->entry = entry;
-       *last = node;
 }
 
-
 /*
  *  New Auth-Type's start at a large number, and go up from there.
  *
@@ -161,36 +151,212 @@ static int new_authtype_value(const char *name)
   return new_value->value;
 }
 
+static module_list_t *find_module(module_list_t *head, const char *filename,
+                                 const char *module_name,
+                                 const char *cffilename, int cflineno)
+{
+       module_list_t   **last, *node;
+       module_list_t   *new;
+       void            *handle;
+       const char      *error;
+
+       while (head) {
+               if (strcmp(head->filename, filename) == 0)
+                       return head;
+               head = head->next;
+       }
+
+       last = &module_list;
+       node = module_list;
+       while (node) {
+               last = &node->next;
+               node = node->next;
+       }
+
+       /*
+        * Keep the handle around so we can dlclose() it.
+        * Also ensure that any further dependencies are exported,
+        * so that PAM can work.
+        *
+        * i.e. rlm_pam.so links to libpam.so, which in turn dlopen()'s
+        * pam_foo.so.  Without RTLD_GLOBAL, the functions in libpam.so
+        * won't get exported to pam_foo.so.
+        */
+       handle = lt_dlopenext(filename);
+       if (handle == NULL) {
+               fprintf(stderr, "%s[%d] Failed to link to module %s:"
+                       " %s\n", cffilename, cflineno, filename, lt_dlerror());
+               return NULL;
+       }
+
+       /* make room for the module type */
+       new = (module_list_t *) malloc(sizeof(module_list_t));
+       if (new == NULL) {
+               fprintf(stderr, "%s[%d] Failed to allocate memory.\n",
+                       cffilename, cflineno);
+               lt_dlclose(handle);     /* ignore any errors */
+               return NULL;
+       }
+
+       /* fill in the module structure */
+       new->next = NULL;
+       new->handle = handle;
+       strNcpy(new->filename, filename, sizeof(new->filename));
+
+       new->module = (module_t *) lt_dlsym(new->handle, module_name);
+       error = lt_dlerror();
+       if (!new->module) {
+               fprintf(stderr, "%s[%d] Failed linking to "
+                               "%s structure in %s: %s\n",
+                               cffilename, cflineno,
+                               module_name, cffilename, error);
+               lt_dlclose(new->handle);        /* ignore any errors */
+               free(new);
+               return NULL;
+       }
+
+       /* If there's an authentication method, add a new Auth-Type */
+       if (new->module->authenticate)
+               new->auth_type =
+                       new_authtype_value(new->module->name);
+
+       /* call the modules initialization */
+       if (new->module->init &&
+           (new->module->init)() < 0) {
+               fprintf(stderr,
+                  "%s[%d] Module initialization failed.\n",
+                       cffilename, cflineno);
+               lt_dlclose(new->handle);        /* ignore any errors */
+               free(new);
+               return NULL;
+       }
+
+       DEBUG("Module: Loaded %s ", new->module->name);
+
+       *last = new;
+
+       return new;
+}
+
+static module_instance_t *find_module_instance(module_instance_t *head,
+                                              const char *instname)
+{
+       CONF_SECTION *cs, *inst_cs;
+       module_instance_t *new;
+       char library[256];
+       char module_name[256];
+
+       while (head) {
+               if (strcmp(head->name, instname) == 0)
+                       return head;
+               head = head->next;
+       }
+
+       /* Instance doesn't exist yet. Try to find the corresponding config
+        * section and create it. */
+
+       new = malloc(sizeof *new);
+       if (!new) {
+               fprintf(stderr, "Out of memory\n");
+               exit(1);
+       }
+
+       cs = cf_section_find("modules");
+       if (!cs) {
+               return NULL;
+       }
+
+       /* Module instances are declared in the modules{} block and referenced
+        * later by their name, which is the name2 from the config section,
+        * or name1 if there was no name2. */
+
+       for(inst_cs=cf_subsection_find_next(cs, NULL, NULL)
+           ; inst_cs ;
+           inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) {
+               if ( (inst_cs->name2 && !strcmp(inst_cs->name2, instname)) ||
+                    (!inst_cs->name2 && !strcmp(inst_cs->name1, instname)) )
+                       break;
+       }
+       if (!inst_cs)
+               return NULL;
+
+       snprintf(library, sizeof library, "rlm_%s.so", inst_cs->name1);
+       snprintf(module_name, sizeof module_name, "rlm_%s", inst_cs->name1);
+       new->entry = find_module(module_list, library, module_name,
+                                "radiusd.conf", inst_cs->lineno);
+       if(!new->entry) {
+               free(new);
+               return NULL;
+       }
+
+       if(!new->entry->module->instantiate) {
+               new->insthandle = 0;
+       } else if((new->entry->module->instantiate)(inst_cs,
+                                                   &new->insthandle) < 0) {
+               fprintf(stderr,
+                       "radiusd.conf[%d]: %s: Module instantiation failed.\n",
+                       inst_cs->lineno, instname);
+               free(new);
+               return NULL;
+       }
+
+       strNcpy(new->name, instname, sizeof(new->name));
+       new->next = module_instance_list;
+       module_instance_list = new;
+
+       DEBUG("Module: Instantiated %s (%s) ", inst_cs->name1, new->name);
+
+       return new;
+}
+
+/*
+ *     Add one entry at the end of the config_module_t list.
+ */
+static void add_to_list(config_module_t **head, module_instance_t *instance)
+{
+       config_module_t *node = *head;
+       config_module_t **last = head;
+
+       while (node) {
+               last = &node->next;
+               node = node->next;
+       }
+
+       node = (config_module_t *) malloc(sizeof(config_module_t));
+       if (!node) {
+               fprintf(stderr, "Out of memory\n");
+               exit(1);
+       }
+
+       node->next = NULL;
+       node->instance = instance;
+       *last = node;
+}
+
+
 /* Why is this both here and in radiusd.c:server_config? --Pac. */
 static CONF_PARSER module_config[] = {
-  { "lib_dir",            PW_TYPE_STRING_PTR, &radlib_dir,        LIBDIR },
+  { "libdir",            PW_TYPE_STRING_PTR, &radlib_dir,        LIBDIR },
 
   { NULL, -1, NULL, NULL }
 };
 
 /*
- *     Read the modules file, parse the structure into memory,
+ *     Parse the module config sections, and load
  *     and call each module's init() function.
  *
  *     Libtool makes your life a LOT easier, especially with libltdl.
  *     see: http://www.gnu.org/software/libtool/
  */
-int read_modules_file(char *filename)
+int setup_modules(void)
 {
-       FILE            *fp;
-       module_list_t   *this;
-       module_list_t   **last;
-       char            *p, *q;
-       char            buffer[1024];
-       char            control[256];
-       char            library[256];
-       char            module_name[256];
-       int             lineno = 0;
-       void            *handle;
-       const char      *error;
-       int             argc;                   /* for calling the modules */
-       char            *argv[32];
+       module_instance_t *this;
+       const char      *control;
+       int             comp;
        CONF_SECTION    *cs;
+       CONF_PAIR       *modref;
+        const char *filename="radiusd.conf";
+
        this = NULL; /* Shut up stupid gcc */
 
        /*
@@ -240,163 +406,85 @@ int read_modules_file(char *filename)
                module_list_free();
        }
 
-       /* read the modules file */
-       fp = fopen(filename, "r");
-       if (!fp)
-               return 0;                       /* no modules file, it's OK */
+       for (comp=0; comp<RLM_COMPONENT_COUNT; ++comp) {
+       switch(comp) {
+               case RLM_COMPONENT_AUTZ: control="authorize"; break;
+               case RLM_COMPONENT_AUTH: control="authenticate"; break;
+               case RLM_COMPONENT_PREACCT: control="preacct"; break;
+               case RLM_COMPONENT_ACCT: control="accounting"; break;
+               default: control="unknown";
+       }
 
-       last = &module_list;
+       cs = cf_section_find(control);
+       if (!cs)
+               continue;
 
-       while (fgets(buffer, sizeof(buffer), fp)) {
+       /* These need to be subsections instead of attr/value pairs if we're
+        * going to do failover config here. I will wait until I've figured
+        * out the shorthand empty-subsection syntax first though.
+        * --Pac */
+       for(modref=cf_pair_find_next(cs, NULL, NULL)
+           ; modref ;
+           modref=cf_pair_find_next(cs, modref, NULL)) {
 
        /*
-        *      Yes, we're missing one indenting TAB here.
+        *      Yes, we're missing two indents here.
         *      It's yucky but otherwise it doesn't fit. That
         *      ofcourse means that this function should
         *      be split up....
         */
-       lineno++;
-       if ((*buffer == '#') || (*buffer <= ' ')) 
-               continue;
-
-       /* split it up */
-       if (sscanf(buffer, "%255s%255s", control, library) != 2) {
-               fprintf(stderr, "%s[%d] Parse error.\n",
-                       filename, lineno);
-               exit(1); /* FIXME */
-       }
-
-       this = find_module(module_list, library);
+       this = find_module_instance(module_instance_list, cf_pair_attr(modref));
        if (this == NULL) {
-               /*
-                * Keep the handle around so we can dlclose() it.
-                * Also ensure that any further dependencies are exported,
-                * so that PAM can work.
-                *
-                * i.e. rlm_pam.so links to libpam.so, which in turn dlopen()'s
-                * pam_foo.so.  Without RTLD_GLOBAL, the functions in libpam.so
-                * won't get exported to pam_foo.so.
-                */
-               handle = lt_dlopenext(library);
-               if (handle == NULL) {
-                       fprintf(stderr, "%s[%d] Failed to link to module %s:"
-                               " %s\n", filename, lineno, library, lt_dlerror());
-                       exit(1); /* FIXME */
-               }
-
-               /* make room for the module type */
-               this = (module_list_t *) malloc(sizeof(module_list_t));
-               if (this == NULL) {
-                       fprintf(stderr, "%s[%d] Failed to allocate memory.\n",
-                               filename, lineno);
-                       exit(1);
-               }
-
-               /* fill in the module structure */
-               this->next = NULL;
-               this->handle = handle;
-               strNcpy(this->filename, library, sizeof(this->filename));
-
-               /* find the structure name from the library name */
-               p = strrchr(library, '/');
-               q = module_name;
-               if (p)
-                       strNcpy(q, p + 1, sizeof(module_name) - 1);
-               else
-                       strNcpy(q, library, sizeof(module_name) - 1);
-               p = strchr(module_name, '.');
-               if (p) *p = '\0';
-
-               this->module = (module_t *) lt_dlsym(this->handle, module_name);
-               error = lt_dlerror();
-               if (!this->module) {
-                       fprintf(stderr, "%s[%d] Failed linking to "
-                                       "%s structure in %s: %s\n",
-                                       filename, lineno, q,
-                                       library, error);
-                       exit(1);
-               }
-
-               /* If there's an authentication method, add a new Auth-Type */
-               if (this->module->authenticate)
-                       this->auth_type =
-                               new_authtype_value(this->module->name);
-
-               /* split up the rest of the string into argv */
-               p = strtok(buffer, " \t");  /* find name */
-               if (p) p = strtok(NULL, " \t\r\n"); /* find library name */
-               if (p) p = strtok(NULL, " \t\r\n"); /* find trailing stuff */
-
-               argc = 0;
-               while (p) {
-                       argv[argc++] = p;
-                       p = strtok(NULL, " \t\r\n");
-
-                       if (argc > 31) {
-                               fprintf(stderr, "%s[%d]  Too many arguments "
-                                               "to module.\n",
-                                               filename, lineno);
-                               exit(1);
-                       }
-               }
-               argv[argc] = NULL;
-
-               /* call the modules initialization */
-               if (this->module->init &&
-                   (this->module->init)(argc, argv) < 0) {
-                       fprintf(stderr,
-                          "%s[%d] Module initialization failed.\n",
-                               filename, lineno);
-                       exit(1);
-               }
-      
-               DEBUG("Module: Loaded %s ", this->module->name);
-
-               *last = this;
-               last = &this->next;
+               exit(1); /* FIXME */
        }
 
        if (strcmp(control, "authorize") == 0) {
-               if (!this->module->authorize) {
+               if (!this->entry->module->authorize) {
                        fprintf(stderr, "%s[%d] Module %s does not contain "
                                        "an 'authorize' entry\n",
-                                       filename, lineno, this->module->name);
+                                       filename, modref->lineno,
+                                       this->entry->module->name);
                        exit(1);
                }
+
                add_to_list(&authorize, this);
        } else if (strcmp(control, "authenticate") == 0) {
-               if (!this->module->authenticate) {
+               if (!this->entry->module->authenticate) {
                        fprintf(stderr, "%s[%d] Module %s does not contain "
                                        "an 'authenticate' entry\n",
-                                       filename, lineno, this->module->name);
+                                       filename, modref->lineno,
+                                       this->entry->module->name);
                        exit(1);
                }
+
                add_to_list(&authenticate, this);
        } else if (strcmp(control, "preacct") == 0) {
-               if (!this->module->preaccounting) {
+               if (!this->entry->module->preaccounting) {
                        fprintf(stderr, "%s[%d] Module %s does not contain "
                                        "a 'preacct' entry\n",
-                                       filename, lineno, this->module->name);
+                                       filename, modref->lineno,
+                                       this->entry->module->name);
                        exit(1);
                }
                add_to_list(&preacct, this);
        } else if (strcmp(control, "accounting") == 0) {
-               if (!this->module->accounting) {
+               if (!this->entry->module->accounting) {
                        fprintf(stderr, "%s[%d] Module %s does not contain "
                                        "an 'accounting' entry\n",
-                                       filename, lineno, this->module->name);
+                                       filename, modref->lineno,
+                                       this->entry->module->name);
                        exit(1);
                }
+
                add_to_list(&accounting, this);
        } else {
                fprintf(stderr, "%s[%d] Unknown control \"%s\".\n",
-                       filename, lineno, control);
+                       filename, modref->lineno, control);
                exit(1);
        }
 
-       } /* YUCK */
-
-       fclose(fp);
+       }
+       } /* YUCK */
 
        return 0;
 }
@@ -451,9 +539,10 @@ int module_authorize(REQUEST *request,
        rcode = RLM_MODULE_OK;
 
        while (this && rcode == RLM_MODULE_OK) {
-               DEBUG2("  authorize: %s", this->entry->module->name);
-               rcode = (this->entry->module->authorize)
-                       (request, check_items, reply_items);
+               DEBUG2("  authorize: %s", this->instance->entry->module->name);
+               rcode = (this->instance->entry->module->authorize)(
+                        this->instance->insthandle, request, check_items,
+                        reply_items);
                this = this->next;
        }
 
@@ -523,18 +612,19 @@ int module_authenticate(int auth_type, REQUEST *request)
        }
 
        this = authenticate;
-       while (this && this->entry->auth_type != auth_type)
+       while (this && this->instance->entry->auth_type != auth_type)
                this = this->next;
 
-       if (!this || !this->entry->module->authenticate) {
+       if (!this || !this->instance->entry->module->authenticate) {
                /*
                 *      No such auth_type, or module auth_type not defined
                 */
                return RLM_MODULE_FAIL;
        }
 
-       DEBUG2("  authenticate: %s", this->entry->module->name);
-       return (this->entry->module->authenticate)(request);
+       DEBUG2("  authenticate: %s", this->instance->entry->module->name);
+       return (this->instance->entry->module->authenticate)(
+               this->instance->insthandle, request);
 }
 
 
@@ -550,8 +640,9 @@ int module_preacct(REQUEST *request)
        rcode = RLM_MODULE_OK;
 
        while (this && (rcode == RLM_MODULE_OK)) {
-               DEBUG2("  preacct: %s", this->entry->module->name);
-               rcode = (this->entry->module->preaccounting)(request);
+               DEBUG2("  preacct: %s", this->instance->entry->module->name);
+               rcode = (this->instance->entry->module->preaccounting)
+                               (this->instance->insthandle, request);
                this = this->next;
        }
 
@@ -570,8 +661,9 @@ int module_accounting(REQUEST *request)
        rcode = RLM_MODULE_OK;
 
        while (this && (rcode == RLM_MODULE_OK)) {
-               DEBUG2("  accounting: %s", this->entry->module->name);
-               rcode = (this->entry->module->accounting)(request);
+               DEBUG2("  accounting: %s", this->instance->entry->module->name);
+               rcode = (this->instance->entry->module->accounting)
+                               (this->instance->insthandle, request);
                this = this->next;
        }
 
index e8f881d..04b2d49 100644 (file)
@@ -17,7 +17,7 @@ static const char rcsid[] = "$Id$";
  * Of course, this RELIES on the NAS to send the SAME information
  * in ALL Accounting packets.
  */
-static int unique_accounting(REQUEST *request)
+static int unique_accounting(void *instance, REQUEST *request)
 {
   char buffer[2048];
   u_char md5_buf[16];
@@ -41,6 +41,8 @@ static int unique_accounting(REQUEST *request)
     0                          /* end of array */
   };
 
+  instance = instance; /* -Wunused */
+
   /*
    *  If there is no Acct-Session-Start-Time, then go add one.
    */
@@ -118,9 +120,11 @@ module_t rlm_acct_unique = {
   "Acct-Unique-Session-Id",
   0,                           /* type: reserved */
   NULL,                                /* initialization */
+  NULL,                                /* instantiation */
   NULL,                                /* authorization */
   NULL,                                /* authentication */
   NULL,                                /* preaccounting */
   unique_accounting,           /* accounting */
   NULL,                                /* detach */
+  NULL,                                /* destroy */
 };
index 11ebff3..d822e2e 100644 (file)
@@ -15,16 +15,8 @@ static const char rcsid[] = "$Id$";
  *     dictionary entries, etc.
  *
  */
-static int radius_init(int argc, char **argv)
+static int radius_init(void)
 {
-       /*
-        *      Quiet the compiler,  This is ONLY needed if the functions
-        *      parameters are not used anywhere in the function.  If there
-        *      were code here, we wouldn't need these two "fake" code lines.
-        */
-       argc = argc;
-       argv = argv;
-       
         /* Initialize the dictionary */
        if (dict_init(radius_dir, RADIUS_DICTIONARY) != 0) {
                log(L_ERR|L_CONS, "Errors reading dictionary %s/%s: %s",
@@ -43,9 +35,11 @@ module_t rlm_dictionary = {
        "dictionary",
        0,                              /* type: reserved */
        radius_init,                    /* initialization */
+       NULL,                           /* instantiation */
        NULL,                           /* authorization */
        NULL,                           /* authentication */
        NULL,                           /* preaccounting */
        NULL,                           /* accounting */
        NULL,                           /* detach */
+       NULL                            /* destroy */
 };
index ac867aa..a8bb098 100644 (file)
@@ -13,7 +13,8 @@ static const char rcsid[] = "$Id$";
  *     Define a structure for our module configuration.
  *
  *     These variables do not need to be in a structure, but it's
- *     a lot cleaner to do so.
+ *     a lot cleaner to do so, and a pointer to the structure can
+ *     be used as the instance handle.
  */
 typedef struct example_config_t {
        int             boolean;
@@ -23,8 +24,8 @@ typedef struct example_config_t {
 } example_config_t;
 
 /*
- *     Define the local copy of our example configuration.
- *     Initialization will be done by the CONF_PARSER.
+ *     A temporary holding area for config values to be extracted
+ *     into, before they are copied into the instance data
  */
 static example_config_t config;
 
@@ -51,36 +52,11 @@ static CONF_PARSER module_config[] = {
  *     to external databases, read configuration files, set up
  *     dictionary entries, etc.
  *
+ *     Try to avoid putting too much stuff in here - it's better to
+ *     do it in instantiate() where it is not global.
  */
-static int radius_init(int argc, char **argv)
+static int radius_init(void)
 {
-       CONF_SECTION *example_cs;
-
-       /*
-        *      Quiet the compiler,  This is ONLY needed if the functions
-        *      parameters are not used anywhere in the function.  If there
-        *      were code here, we wouldn't need these two "fake" code lines.
-        */
-       argc = argc;
-       argv = argv;
-       
-       /*
-        *      Look for the module's configuration.  If it doesn't
-        *      exists, exit quietly (and use the defaults).
-        */
-       example_cs = cf_module_config_find("example");
-       if (!example_cs) {
-               return 0;
-       }
-
-       /*
-        *      If the configuration parameters can't be parsed, then
-        *      fail.
-        */
-       if (cf_section_parse(example_cs, module_config) < 0) {
-               return -1;
-       }
-
        /*
         *      Everything's OK, return without an error.
         */
@@ -88,15 +64,59 @@ static int radius_init(int argc, char **argv)
 }
 
 /*
+ *     Do any per-module initialization that is separate to each
+ *     configured instance of the module.  e.g. set up connections
+ *     to external databases, read configuration files, set up
+ *     dictionary entries, etc.
+ *
+ *     If configuration information is given in the config section
+ *     that must be referenced in later calls, store a handle to it
+ *     in *instance otherwise put a null pointer there.
+ */
+static int radius_instantiate(CONF_SECTION *conf, void **instance)
+{
+  /*
+   *   Set up a storage area for instance data
+   */
+  *instance = malloc(sizeof(struct example_config_t));
+  if(!*instance) {
+       return -1;
+  }
+
+  /*
+   *   If the configuration parameters can't be parsed, then
+   *   fail.
+   */
+  if (cf_section_parse(conf, module_config) < 0) {
+         free(*instance);
+         return -1;
+  }
+
+  /*
+   *   Copy the configuration into the instance data
+   */
+#define inst ((struct example_config_t *)*instance)
+  inst->boolean = config.boolean;
+  inst->value = config.value;
+  inst->string = config.string;
+  inst->ipaddr = config.ipaddr;
+#undef inst
+  config.string = 0; /* So cf_section_parse won't free it next time */
+
+  return 0;
+}
+
+/*
  *     Find the named user in this modules database.  Create the set
  *     of attribute-value pairs to check and reply with for this user
  *     from the database. The authentication code only needs to check
  *     the password, the rest is done here.
  */
-static int radius_authorize(REQUEST *request,
+static int radius_authorize(void *instance, REQUEST *request,
                            VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
 {
        /* quiet the compiler */
+       instance = instance;
        request = request;
        check_pairs = check_pairs;
        reply_pairs = reply_pairs;
@@ -107,9 +127,10 @@ static int radius_authorize(REQUEST *request,
 /*
  *     Authenticate the user with the given password.
  */
-static int radius_authenticate(REQUEST *request)
+static int radius_authenticate(void *instance, REQUEST *request)
 {
        /* quiet the compiler */
+       instance = instance;
        request = request;
        
        return RLM_MODULE_OK;
@@ -118,9 +139,10 @@ static int radius_authenticate(REQUEST *request)
 /*
  *     Massage the request before recording it or proxying it
  */
-static int radius_preacct(REQUEST *request)
+static int radius_preacct(void *instance, REQUEST *request)
 {
        /* quiet the compiler */
+       instance = instance;
        request = request;
        
        return RLM_MODULE_OK;
@@ -129,22 +151,32 @@ static int radius_preacct(REQUEST *request)
 /*
  *     Write accounting information to this modules database.
  */
-static int radius_accounting(REQUEST *request)
+static int radius_accounting(void *instance, REQUEST *request)
 {
        /* quiet the compiler */
+       instance = instance;
        request = request;
        
        return RLM_MODULE_OK;
 }
 
+static int radius_detach(void *instance)
+{
+       free(((struct example_config_t *)instance)->string);
+       free(instance);
+       return 0;
+}
+
 /* globally exported name */
 module_t rlm_example = {
        "example",
        0,                              /* type: reserved */
        radius_init,                    /* initialization */
+       radius_instantiate,             /* instantiation */
        radius_authorize,               /* authorization */
        radius_authenticate,            /* authentication */
        radius_preacct,                 /* preaccounting */
        radius_accounting,              /* accounting */
-       NULL,                           /* detach */
+       radius_detach,                  /* detach */
+       NULL,                           /* destroy */
 };
index e090646..d82037c 100644 (file)
@@ -26,6 +26,8 @@ static const char rcsid[] = "$Id$";
 #include       <time.h>
 #include       <ctype.h>
 #include       <fcntl.h>
+#include       <unistd.h>
+#include        <limits.h>
 
 #if HAVE_MALLOC_H
 #  include     <malloc.h>
@@ -41,12 +43,16 @@ static const char rcsid[] = "$Id$";
 #  include     <ndbm.h>
 #endif
 
-#ifdef WITH_NDBM
-static DBM     *dbmfile;
-#endif
-
-static PAIR_LIST       *users = NULL;
-static PAIR_LIST       *acct_users = NULL;
+struct file_instance {
+        /* autz */
+        char *usersfile;
+        PAIR_LIST *users;
+        /* preacct */
+        char *acctusersfile;
+        PAIR_LIST *acctusers;
+        /*acct*/
+        int detailperm;
+};
 
 #if defined(WITH_DBM) || defined(WITH_NDBM)
 /*
@@ -69,7 +75,7 @@ static int checkdbm(char *users, char *ext)
  *               0 found but doesn't match.
  *               1 found and matches.
  */
-static int dbm_find(char *name, VALUE_PAIR *request_pairs,
+static int dbm_find(DBM *dbmfile, char *name, VALUE_PAIR *request_pairs,
                VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
 {
        datum           named;
@@ -225,119 +231,163 @@ static void file_dynamic_log_init(void)
 
 
 }
-/*
- *     (Re-)read the "users" file into memory.
- */
-static int file_init(int argc, char **argv)
-{
-       char            fn[1024];
-       char            acct_fn[1024];
-       const char      *ptr;
 
-       argc = argc; /* -Wunused */
+
+static int file_init(void)
+{
        file_dynamic_log_init();
 
-       /*
-        *  This really should be fixed to do something better...
-        */
-       ptr = argv[0] ? argv[0] : RADIUS_USERS;
-       sprintf(fn, "%s/%s", radius_dir, ptr);
-       ptr = (argv[0] && argv[1]) ? argv[1] : RADIUS_ACCT_USERS;
-       sprintf(acct_fn, "%s/%s", radius_dir, ptr);
+       return 0;
+}
+
 
+/*
+ *     A temporary holding area for config values to be extracted
+ *     into, before they are copied into the instance data
+ */
+static struct file_instance config;
+
+static CONF_PARSER module_config[] = {
+        { "usersfile",     PW_TYPE_STRING_PTR,
+          &config.usersfile, RADIUS_USERS },
+        { "acctusersfile", PW_TYPE_STRING_PTR,
+          &config.acctusersfile, RADIUS_ACCT_USERS },
+        { "detailperm",    PW_TYPE_INTEGER,
+          &config.detailperm, "0600" },
+       { NULL, -1, NULL, NULL }
+};
+
+static PAIR_LIST *getusersfile(const char *filename)
+{
+        PAIR_LIST *users = NULL;
 #if defined(WITH_DBM) || defined(WITH_NDBM)
-       if (!use_dbm &&
-           (checkdbm(ptr, ".dir") == 0 ||
-            checkdbm(ptr, ".db") == 0)) {
-               log(L_INFO|L_CONS, "DBM files found but no -b flag "
-                       "given - NOT using DBM");
-       }
+        if (!use_dbm &&
+            (checkdbm(filename, ".dir") == 0 ||
+             checkdbm(filename, ".db") == 0)) {
+                log(L_INFO|L_CONS, "DBM files found but no -b flag " "given - NOT using DBM");
+        }
 #endif
 
-       if (!use_dbm) {
-               users = pairlist_read(fn, 1);
-               acct_users = pairlist_read(acct_fn, 1);
-       }
-
-       /*
-        *      Walk through the 'users' file list, sanity checking it.
-        */
-       if (debug_flag) {
-               int acctfile=0;
-               PAIR_LIST *entry;
-               VALUE_PAIR *vp;
-               
-               entry = users;
-               while (entry) {
-                       /*
-                        *      Look for improper use of '=' in the
-                        *      check items.  They should be using
-                        *      '==' for on-the-wire RADIUS attributes,
-                        *      and probably ':=' for server configuration
-                        *      items.
-                        */
-                       for (vp = entry->check; vp != NULL; vp = vp->next) {
-                               /*
-                                *      Ignore attributes which are set
-                                *      properly.
-                                */
-                               if (vp->operator != T_OP_EQ) {
-                                       continue;
-                               }
+        if (!use_dbm) users = pairlist_read(filename, 1);
+
+        /*
+         *     Walk through the 'users' file list, sanity checking it.
+         */
+        if (debug_flag) {
+                PAIR_LIST *entry;
+                VALUE_PAIR *vp;
+        
+                entry = users;
+                while (entry) {
+                        /*
+                         *     Look for improper use of '=' in the
+                         *     check items.  They should be using
+                         *     '==' for on-the-wire RADIUS attributes,
+                         *     and probably ':=' for server
+                         *     configuration items.
+                         */
+                        for (vp = entry->check; vp != NULL; vp = vp->next) {
+                                /*
+                                 *     Ignore attributes which are set
+                                 *     properly.
+                                 */
+                                if (vp->operator != T_OP_EQ) {
+                                        continue;
+                                }
+
+                                /*
+                                 *     If it's a vendor attribute,
+                                 *     or it's a wire protocol, 
+                                 *     ensure it has '=='.
+                                 */
+                                if (((vp->attribute & ~0xffff) != 0) ||
+                                    (vp->attribute < 0x100)) {
+                                        log_debug("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
+                                                  filename, entry->lineno,
+                                                  vp->name, vp->name,
+                                                  entry->name);
+                                        continue;
+                                }
+                        }
+                
+                
+                        /*
+                         *     Look for server configuration items
+                         *     in the reply list.
+                         *
+                         *     It's a common enough mistake, that it's
+                         *     worth doing.
+                         */
+                        for (vp = entry->reply; vp != NULL; vp = vp->next) {
+                                /*
+                                 *     If it's NOT a vendor attribute,
+                                 *     and it's NOT a wire protocol
+                                 *     and we ignore Fall-Through,
+                                 *     then bitch about it, giving a
+                                 *     good warning message.
+                                 */
+                                if (!(vp->attribute & ~0xffff) &&
+                                    (vp->attribute > 0xff) &&
+                                    (vp->attribute > 1000)) {
+                                        log_debug("[%s]:%d WARNING! Check item \"%s\"\n"
+                                                  "\tfound in reply item list for user \"%s\".\n"
+                                                  "\tThis attribute MUST go on the first line"
+                                                  " with the other check items", 
+                                                  filename, entry->lineno, vp->name,
+                                                  entry->name);
+                                }
+                        }
+                
+                        entry = entry->next;
+                }
+        
+        }
+        return users;
+}
 
-                               /*
-                                *      If it's a vendor attribute,
-                                *      or it's a wire protocol, 
-                                *      ensure it has '=='.
-                                */
-                               if (((vp->attribute & ~0xffff) != 0) ||
-                                   (vp->attribute < 0x100)) {
-                                       log_debug("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
-                                                 acctfile?acct_fn:fn, entry->lineno,
-                                                 vp->name, vp->name,
-                                                 entry->name);
-                                       continue;
-                               }
-                       }
-                       
-                       
-                       /*
-                        *      Look for server configuration items
-                        *      in the reply list.
-                        *
-                        *      It's a common enough mistake, that it's
-                        *      worth doing.
-                        */
-                       for (vp = entry->reply; vp != NULL; vp = vp->next) {
-                               /*
-                                *      If it's NOT a vendor attribute,
-                                *      and it's NOT a wire protocol
-                                *      and we ignore Fall-Through,
-                                *      then bitch about it, giving a
-                                *      good warning message.
-                                */
-                               if (!(vp->attribute & ~0xffff) &&
-                                   (vp->attribute > 0xff) &&
-                                   (vp->attribute > 1000)) {
-                                       log_debug("[%s]:%d WARNING! Check item \"%s\"\n"
-                                                 "\tfound in reply item list for user \"%s\".\n"
-                                                 "\tThis attribute MUST go on the first line"
-                                                 " with the other check items", 
-                                                 acctfile?acct_fn:fn, entry->lineno, vp->name,
-                                                 entry->name);
-                               }
-                       }
-                       
-                       entry = entry->next;
-                       if(!entry && !acctfile) {
-                               entry=acct_users;
-                               acctfile=1;
-                       }
-               }
-               
-       }
-       
-       return users ? 0 : -1;
+/*
+ *     (Re-)read the "users" file into memory.
+ */
+static int file_instantiate(CONF_SECTION *conf, void **instance)
+{
+        struct file_instance *inst;
+
+        inst=malloc(sizeof *inst);
+        if(!inst) {
+                log(L_ERR|L_CONS, "Out of memory\n");
+                return -1;
+        }
+
+        if (cf_section_parse(conf, module_config) < 0) {
+                free(inst);
+                return -1;
+        }
+
+        inst->detailperm = config.detailperm;
+        inst->usersfile = config.usersfile;
+        inst->acctusersfile = config.acctusersfile;
+        config.usersfile = NULL;
+        config.acctusersfile = NULL;
+
+       inst->users=getusersfile(inst->usersfile);
+        if(!inst->users) {
+                log(L_ERR|L_CONS, "Errors reading %s", inst->usersfile);
+                free(inst->usersfile);
+                free(inst->acctusersfile);
+                free(inst);
+                return -1;
+        }
+       inst->acctusers=getusersfile(inst->acctusersfile);
+        if(!inst->acctusers) {
+                log(L_ERR|L_CONS, "Errors reading %s", inst->acctusersfile);
+                pairlist_free(&inst->users);
+                free(inst->usersfile);
+                free(inst->acctusersfile);
+                free(inst);
+                return -1;
+        }
+        *instance = inst;
+        return 0;
 }
 
 /*
@@ -346,7 +396,7 @@ static int file_init(int argc, char **argv)
  *     for this user from the database. The main code only
  *     needs to check the password, the rest is done here.
  */
-static int file_authorize(REQUEST *request,
+static int file_authorize(void *instance, REQUEST *request,
                VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
 {
        int             nas_port = 0;
@@ -362,6 +412,7 @@ static int file_authorize(REQUEST *request,
        char            buffer[256];
 #endif
        const char      *name;
+       struct file_instance *inst = instance;
 
        request_pairs = request->packet->vps;
 
@@ -388,12 +439,11 @@ static int file_authorize(REQUEST *request,
                /*
                 *      FIXME: No Prefix / Suffix support for DBM.
                 */
-               sprintf(buffer, "%s/%s", radius_dir, RADIUS_USERS);
 #ifdef WITH_DBM
-               if (dbminit(buffer) != 0)
+               if (dbminit(inst->usersfile) != 0)
 #endif
 #ifdef WITH_NDBM
-               if ((dbmfile = dbm_open(buffer, O_RDONLY, 0)) == NULL)
+               if ((dbmfile = dbm_open(inst->usersfile, O_RDONLY, 0)) == NULL)
 #endif
                {
                        log(L_ERR|L_CONS, "cannot open dbm file %s",
@@ -401,7 +451,8 @@ static int file_authorize(REQUEST *request,
                        return RLM_MODULE_FAIL;
                }
 
-               r = dbm_find(name, request_pairs, check_pairs, reply_pairs);
+               r = dbm_find(dbmfile, name, request_pairs, check_pairs,
+                            reply_pairs);
                if (r > 0) found = 1;
                if (r <= 0 || fallthrough(*reply_pairs)) {
 
@@ -409,7 +460,7 @@ static int file_authorize(REQUEST *request,
 
                        sprintf(buffer, "DEFAULT");
                        i = 0;
-                       while ((r = dbm_find(buffer, request_pairs,
+                       while ((r = dbm_find(dbmfile, buffer, request_pairs,
                               check_pairs, reply_pairs)) >= 0 || i < 2) {
                                if (r > 0) {
                                        found = 1;
@@ -432,7 +483,7 @@ static int file_authorize(REQUEST *request,
         */
 #endif
 
-       for(pl = users; pl; pl = pl->next) {
+       for(pl = inst->users; pl; pl = pl->next) {
 
                /*
                 *      If the current entry is NOT a default,
@@ -501,8 +552,9 @@ static int file_authorize(REQUEST *request,
 /*
  *     Authentication - unused.
  */
-static int file_authenticate(REQUEST *request)
+static int file_authenticate(void *instance, REQUEST *request)
 {
+       instance = instance;
        request = request;
        return RLM_MODULE_OK;
 }
@@ -537,6 +589,7 @@ static void file_write_dynamic_log(REQUEST * request)
                                if (fn[y] == '|') {
                                        f = popen(&fn[y+1],logcfg[x].mode);
                                } else {
+                                       /* FIXME: permissions? */
                                        f = fopen(fn,logcfg[x].mode);
                                }
                                if (f) {
@@ -569,13 +622,13 @@ static void file_write_dynamic_log(REQUEST * request)
  *
  *     This function is mostly a copy of file_authorize
  */
-static int file_preacct(REQUEST *request)
+static int file_preacct(void *instance, REQUEST *request)
 {
        VALUE_PAIR      *namepair;
        const char      *name;
        VALUE_PAIR      *request_pairs;
        VALUE_PAIR      **config_pairs;
-       VALUE_PAIR      *reply_pairs=0;
+       VALUE_PAIR      *reply_pairs = NULL;
        VALUE_PAIR      *check_tmp;
        VALUE_PAIR      *reply_tmp;
        PAIR_LIST       *pl;
@@ -584,6 +637,7 @@ static int file_preacct(REQUEST *request)
        int             i, r;
        char            buffer[256];
 #endif
+       struct file_instance *inst = instance;
 
        namepair = request->username;
        name = namepair ? (char *) namepair->strvalue : "NONE";
@@ -601,12 +655,11 @@ static int file_preacct(REQUEST *request)
                /*
                 *      FIXME: No Prefix / Suffix support for DBM.
                 */
-               sprintf(buffer, "%s/%s", radius_dir, RADIUS_ACCT_USERS);
 #ifdef WITH_DBM
-               if (dbminit(buffer) != 0)
+               if (dbminit(inst->acctusersfile) != 0)
 #endif
 #ifdef WITH_NDBM
-               if ((dbmfile = dbm_open(buffer, O_RDONLY, 0)) == NULL)
+               if ((dbmfile = dbm_open(inst->acctusersfile, O_RDONLY, 0)) == NULL)
 #endif
                {
                        log(L_ERR|L_CONS, "cannot open dbm file %s",
@@ -614,7 +667,8 @@ static int file_preacct(REQUEST *request)
                        return RLM_MODULE_FAIL;
                }
 
-               r = dbm_find(name, request_pairs, config_pairs, &reply_pairs);
+               r = dbm_find(dbmfile, name, request_pairs, config_pairs,
+                            &reply_pairs);
                if (r > 0) found = 1;
                if (r <= 0 || fallthrough(*reply_pairs)) {
 
@@ -622,7 +676,7 @@ static int file_preacct(REQUEST *request)
 
                        sprintf(buffer, "DEFAULT");
                        i = 0;
-                       while ((r = dbm_find(buffer, request_pairs,
+                       while ((r = dbm_find(dbmfile, buffer, request_pairs,
                               config_pairs, &reply_pairs)) >= 0 || i < 2) {
                                if (r > 0) {
                                        found = 1;
@@ -645,7 +699,7 @@ static int file_preacct(REQUEST *request)
         */
 #endif
 
-       for(pl = acct_users; pl; pl = pl->next) {
+       for(pl = inst->acctusers; pl; pl = pl->next) {
 
                if (strcmp(name, pl->name) && strcmp(pl->name, "DEFAULT"))
                        continue;
@@ -686,9 +740,10 @@ static int file_preacct(REQUEST *request)
 /*
  *     Accounting - write the detail files.
  */
-static int file_accounting(REQUEST *request)
+static int file_accounting(void *instance, REQUEST *request)
 {
-       FILE            *outfd;
+       int             outfd;
+       FILE            *outfp;
        char            nasname[128];
        char            buffer[512];
        VALUE_PAIR      *pair;
@@ -698,6 +753,8 @@ static int file_accounting(REQUEST *request)
        int             ret = RLM_MODULE_OK;
        struct stat     st;
 
+       struct file_instance *inst = instance;
+
        /*
         *      See if we have an accounting directory. If not,
         *      return.
@@ -742,22 +799,27 @@ static int file_accounting(REQUEST *request)
         *      Write Detail file.
         */
        sprintf(buffer, "%s/%s/%s", radacct_dir, nasname, "detail");
-       if ((outfd = fopen(buffer, "a")) == NULL) {
+       if ((outfd = open(buffer, O_WRONLY|O_APPEND|O_CREAT,
+                         inst->detailperm)) < 0) {
+               log(L_ERR, "Acct: Couldn't open file %s", buffer);
+               ret = RLM_MODULE_FAIL;
+       } else if ((outfp = fdopen(outfd, "a")) == NULL) {
                log(L_ERR, "Acct: Couldn't open file %s: %s",
                    buffer, strerror(errno));
                ret = RLM_MODULE_FAIL;
+               close(outfd);
        } else {
 
                /* Post a timestamp */
-               fputs(ctime(&curtime), outfd);
+               fputs(ctime(&curtime), outfp);
 
                /* Write each attribute/value to the log file */
                pair = request->packet->vps;
                while (pair) {
                        if (pair->attribute != PW_PASSWORD) {
-                               fputs("\t", outfd);
-                               fprint_attr_val(outfd, pair);
-                               fputs("\n", outfd);
+                               fputs("\t", outfp);
+                               fprint_attr_val(outfp, pair);
+                               fputs("\n", outfp);
                        }
                        pair = pair->next;
                }
@@ -765,13 +827,13 @@ static int file_accounting(REQUEST *request)
                /*
                 *      Add non-protocol attibutes.
                 */
-               fprintf(outfd, "\tTimestamp = %ld\n", curtime);
+               fprintf(outfp, "\tTimestamp = %ld\n", curtime);
                if (request->packet->verified)
-                       fputs("\tRequest-Authenticator = Verified\n", outfd);
+                       fputs("\tRequest-Authenticator = Verified\n", outfp);
                else
-                       fputs("\tRequest-Authenticator = None\n", outfd);
-               fputs("\n", outfd);
-               fclose(outfd);
+                       fputs("\tRequest-Authenticator = None\n", outfp);
+               fputs("\n", outfp);
+               fclose(outfp);
        }
        file_write_dynamic_log(request);
        return ret;
@@ -781,10 +843,14 @@ static int file_accounting(REQUEST *request)
 /*
  *     Clean up.
  */
-static int file_detach(void)
+static int file_detach(void *instance)
 {
-       pairlist_free(&users);
-       pairlist_free(&acct_users);
+        struct file_instance *inst = instance;
+        pairlist_free(&inst->users);
+        pairlist_free(&inst->acctusers);
+        free(inst->usersfile);
+        free(inst->acctusersfile);
+        free(inst);
        return 0;
 }
 
@@ -794,10 +860,12 @@ module_t rlm_files = {
        "files",
        0,                              /* type: reserved */
        file_init,                      /* initialization */
+       file_instantiate,               /* instantiation */
        file_authorize,                 /* authorization */
        file_authenticate,              /* authentication */
        file_preacct,                   /* preaccounting */
        file_accounting,                /* accounting */
        file_detach,                    /* detach */
+       NULL                            /* destroy */
 };
 
index 5550fef..2ace951 100644 (file)
@@ -192,7 +192,7 @@ static TLDAP_RADIUS reply_item_map[] = {
  *              and performs initialization of the modue.
  *
  *************************************************************************/
-static int rlm_ldap_init (int argc, char **argv)
+static int rlm_ldap_init (void)
 {
   CONF_SECTION *conf_ldap;
   int i;
@@ -648,7 +648,7 @@ static LDAP *rlm_ldap_connect(const char *dn, const char *password, int auth, in
  *     Detach from the LDAP server and cleanup internal state.
  *     
  *****************************************************************************/
-static int rlm_ldap_detach(void)
+static int rlm_ldap_destroy(void)
 {
   pthread_mutex_lock(&sig_mutex);
   cleanup = 1;
@@ -830,9 +830,11 @@ module_t rlm_ldap = {
   "LDAP",
   0,                           /* type: reserved */
   rlm_ldap_init,               /* initialization */
+  NULL,                                /* instantiation */
   rlm_ldap_authorize,           /* authorization */
   rlm_ldap_authenticate,        /* authentication */
   NULL,                                /* preaccounting */
   NULL,                                /* accounting */
-  rlm_ldap_detach,              /* detach */
+  NULL,                        /* detach */
+  rlm_ldap_destroy,             /* destroy */
 };
index bd492f2..f463a0f 100644 (file)
@@ -165,12 +165,14 @@ static int pam_pass(const char *name, const char *passwd, const char *pamauth)
 }
 
 /* translate between function declarations */
-static int pam_auth(REQUEST *request)
+static int pam_auth(void *instance, REQUEST *request)
 {
        int     r;
        VALUE_PAIR *pair;
        const char *pam_auth_string = "radiusd";
 
+       instance = instance;
+
        /*
         *      We can only authenticate user requests which HAVE
         *      a User-Name attribute.
@@ -214,10 +216,12 @@ module_t rlm_pam = {
   "Pam",
   0,                           /* type: reserved */
   NULL,                                /* initialize */
+  NULL,                                /* instantiation */
   NULL,                                /* authorize */
   pam_auth,                    /* authenticate */
   NULL,                                /* pre-accounting */
   NULL,                                /* accounting */
   NULL,                                /* detach */
+  NULL,                                /* destroy */
 };
 
index a543bc1..268b2da 100644 (file)
@@ -29,6 +29,7 @@ static const char rcsid[] = "$Id$";
 #include       "modules.h"
 
 
+/* FIXME: should this stuff be instance data? */
 static PAIR_LIST       *huntgroups;
 static PAIR_LIST       *hints;
 
@@ -479,13 +480,10 @@ static void add_nas_attr(REQUEST *request)
 /*
  *     Initialize.
  */
-static int preprocess_init(int argc, char **argv)
+static int preprocess_init(void)
 {
        char    buffer[256];
 
-       argc = argc;            /* shut the compiler up */
-       argv = argv;
-
        pairlist_free(&huntgroups);
        pairlist_free(&hints);
 
@@ -502,11 +500,13 @@ static int preprocess_init(int argc, char **argv)
 /*
  *     Preprocess a request.
  */
-static int preprocess_authorize(REQUEST *request,
+static int preprocess_authorize(void *instance, REQUEST *request,
        VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
 {
        char buf[1024];
 
+       instance = instance;
+
        check_pairs = check_pairs; /* shut the compiler up */
        reply_pairs = reply_pairs;
 
@@ -548,8 +548,9 @@ static int preprocess_authorize(REQUEST *request,
 /*
  *     Preprocess a request before accounting
  */
-static int preprocess_preaccounting(REQUEST *request)
+static int preprocess_preaccounting(void *instance, REQUEST *request)
 {
+       instance = instance;
        /*
         *  Ensure that we have the SAME user name for both
         *  authentication && accounting.
@@ -568,7 +569,7 @@ static int preprocess_preaccounting(REQUEST *request)
 /*
  *      Clean up.
  */
-static int preprocess_detach(void)
+static int preprocess_destroy(void)
 {
        paircompare_unregister(PW_HUNTGROUP_NAME, huntgroup_cmp);
        pairlist_free(&huntgroups);
@@ -582,10 +583,12 @@ module_t rlm_preprocess = {
        "preprocess",
        0,                              /* type: reserved */
        preprocess_init,                /* initialization */
+       NULL,                           /* instantiation */
        preprocess_authorize,           /* authorization */
        NULL,                           /* authentication */
        preprocess_preaccounting,       /* pre-accounting */
        NULL,                           /* accounting */
-       preprocess_detach,              /* detach */
+       NULL,                           /* detach */
+       preprocess_destroy,             /* destroy */
 };
 
index fe3b33d..b25afc8 100644 (file)
@@ -150,11 +150,12 @@ static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm)
  *
  *  This should very nearly duplicate the old proxy_send() code
  */
-static int realm_authorize(REQUEST *request,
+static int realm_authorize(void *instance, REQUEST *request,
                           VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
 {
        REALM *realm;
 
+       instance = instance;
        reply_pairs = reply_pairs; /* -Wunused */
        
        /*
@@ -179,10 +180,12 @@ static int realm_authorize(REQUEST *request,
  * This does the exact same thing as the realm_authorize, it's just called
  * differently.
  */
-static int realm_preacct(REQUEST *request)
+static int realm_preacct(void *instance, REQUEST *request)
 {
        const char *name = (char *)request->username->strvalue;
        REALM *realm;
+
+       instance = instance; /* -Wunused */
        
        if (!name)
          return RLM_MODULE_OK;
@@ -212,9 +215,11 @@ module_t rlm_realm = {
   "Realm",
   0,                           /* type: reserved */
   NULL,                                /* initialization */
+  NULL,                                /* instantiation */
   realm_authorize,             /* authorization */
   NULL,                                /* authentication */
   realm_preacct,               /* preaccounting */
   NULL,                                /* accounting */
   NULL,                                /* detach */
+  NULL,                                /* destroy */
 };
index 2fb87aa..c0aeb17 100644 (file)
@@ -95,7 +95,7 @@ static CONF_PARSER module_config[] = {
  * start of main routines
  ***********************************************************************/
 
-static int rlm_sql_init(int argc, char **argv) {
+static int rlm_sql_init(void) {
 
        /* Where is the flag that tells us about a HUP?*/
        int     reload = 0;
@@ -119,7 +119,7 @@ static int rlm_sql_init(int argc, char **argv) {
        return 0;
 }
 
-static int rlm_sql_detach(void) {
+static int rlm_sql_destroy(void) {
 
   return 0;
 }
@@ -401,9 +401,11 @@ module_t rlm_sql = {
   "SQL",
   0,                   /* type: reserved */
   rlm_sql_init,                /* initialization */
+  NULL,                        /* instantiation */
   rlm_sql_authorize,   /* authorization */
   rlm_sql_authenticate,        /* authentication */
   NULL,                        /* preaccounting */
   rlm_sql_accounting,  /* accounting */
-  rlm_sql_detach,      /* detach */
+  NULL,                        /* detach */
+  rlm_sql_destroy,     /* destroy */
 };
index 8ff88ce..d4cb1ae 100644 (file)
@@ -104,26 +104,32 @@ static int groupcmp(VALUE_PAIR *request, VALUE_PAIR *check,
  *     FIXME:  We really should have an 'init' which makes
  *     System auth == Unix
  */
-static int unix_init(int argc, char **argv)
+static int unix_init(void)
 {
-       CONF_SECTION *unix_cs;
-       argc = argc; argv = argv;
+       paircompare_register(PW_GROUP, PW_USER_NAME, groupcmp);
+#ifdef PW_GROUP_NAME /* compat */
+       paircompare_register(PW_GROUP_NAME, PW_USER_NAME, groupcmp);
+#endif
+       return 0;
+}
 
+static int unix_instantiate(CONF_SECTION *conf, void **instance)
+{
        /*
-        *      Look for the module's configuration.
-        *
-        *      If it exists, go parse it, and die if the parse fails.
+        *      Not yet multiple-instance-aware. groupcmp is a real
+        *      obstacle.
         */
-       unix_cs = cf_module_config_find("unix");
-       if (unix_cs &&
-           (cf_section_parse(unix_cs, module_config) < 0)) {
+       static int alreadydone=0;
+
+       if (alreadydone) {
+               log(L_ERR,
+                   "rlm_unix: can't handle multiple authentication instances");
                return -1;
        }
-       
-       paircompare_register(PW_GROUP, PW_USER_NAME, groupcmp);
-#ifdef PW_GROUP_NAME /* compat */
-       paircompare_register(PW_GROUP_NAME, PW_USER_NAME, groupcmp);
-#endif
+       if (cf_section_parse(conf, module_config) < 0) {
+               return -1;
+       }
+
        if (cache_passwd) {
                log(L_INFO, "HASH:  Reinitializing hash structures "
                        "and lists for caching...");
@@ -139,14 +145,15 @@ static int unix_init(int argc, char **argv)
                }
        }
 
+       alreadydone = 1;
+       *instance = 0;
        return 0;
 }
 
-
 /*
  *     Detach.
  */
-static int unix_detach(void)
+static int unix_destroy(void)
 {
        paircompare_unregister(PW_GROUP, groupcmp);
 #ifdef PW_GROUP_NAME
@@ -160,7 +167,7 @@ static int unix_detach(void)
  *     Check the users password against the standard UNIX
  *     password table.
  */
-static int unix_authenticate(REQUEST *request)
+static int unix_authenticate(void *instance, REQUEST *request)
 {
        char *name, *passwd;
        struct passwd   *pwd;
@@ -180,6 +187,7 @@ static int unix_authenticate(REQUEST *request)
 #ifdef HAVE_GETUSERSHELL
        char            *shell;
 #endif
+       instance = instance;
 
        /*
         *      We can only authenticate user requests which HAVE
@@ -346,7 +354,7 @@ static char *uue(void *in)
 /*
  *     Unix accounting - write a wtmp file.
  */
-static int unix_accounting(REQUEST *request)
+static int unix_accounting(void *instance, REQUEST *request)
 {
        VALUE_PAIR      *vp;
        NAS             *cl;
@@ -364,6 +372,8 @@ static int unix_accounting(REQUEST *request)
        int             port_seen = 0;
        int             nas_port_type = 0;
 
+       instance = instance;
+
        /*
         *      Which type is this.
         */
@@ -502,10 +512,12 @@ module_t rlm_unix = {
   "System",
   0,                            /* type: reserved */
   unix_init,                    /* initialization */
+  unix_instantiate,            /* instantiation */
   NULL,                         /* authorization */
   unix_authenticate,            /* authentication */
   NULL,                         /* preaccounting */
   unix_accounting,              /* accounting */
-  unix_detach,                  /* detach */
+  NULL,                        /* detach */
+  unix_destroy,                  /* destroy */
 };