# 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
+}
#define RADIUS_HINTS "hints"
#define RADIUS_HUNTGROUPS "huntgroups"
#define RADIUS_REALMS "realms"
-#define RADIUS_MODULES "modules"
#define RADUTMP LOGDIR "/radutmp"
#define RADWTMP LOGDIR "/radwtmp"
CONF_PAIR *cps;
struct conf_part *sub;
struct conf_part *next;
+ struct conf_part *parent;
} CONF_SECTION;
/*
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);
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,
*
*/
+#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
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 {
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);
#include "radiusd.h"
-char *progname;
+const char *progname;
int debug_flag;
char *radius_dir;
char *radlog_dir;
/*
* 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;
memset(cs, 0, sizeof(CONF_SECTION));
cs->name1 = xstrdup(name1);
cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
+ cs->parent = parent;
return cs;
}
* 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];
/*
* Allocate new section.
*/
- cs = cf_section_alloc(name1, name2);
+ cs = cf_section_alloc(name1, name2, parent);
cs->lineno = *lineno;
/*
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;
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);
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;
}
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
*/
/*
* 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)
}
for (; cp; cp = cp->next)
- if (strcmp(cp->attr, attr) == 0)
+ if (attr == NULL || strcmp(cp->attr, attr) == 0)
break;
return cp;
/*
* 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,
}
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
*
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;
}
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;
*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.
*
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 */
/*
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;
}
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;
}
}
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);
}
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;
}
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;
}
* 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];
0 /* end of array */
};
+ instance = instance; /* -Wunused */
+
/*
* If there is no Acct-Session-Start-Time, then go add one.
*/
"Acct-Unique-Session-Id",
0, /* type: reserved */
NULL, /* initialization */
+ NULL, /* instantiation */
NULL, /* authorization */
NULL, /* authentication */
NULL, /* preaccounting */
unique_accounting, /* accounting */
NULL, /* detach */
+ NULL, /* destroy */
};
* 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",
"dictionary",
0, /* type: reserved */
radius_init, /* initialization */
+ NULL, /* instantiation */
NULL, /* authorization */
NULL, /* authentication */
NULL, /* preaccounting */
NULL, /* accounting */
NULL, /* detach */
+ NULL /* destroy */
};
* 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;
} 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;
* 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.
*/
}
/*
+ * 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;
/*
* 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;
/*
* 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;
/*
* 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 */
};
#include <time.h>
#include <ctype.h>
#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
#if HAVE_MALLOC_H
# include <malloc.h>
# 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)
/*
* 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;
}
-/*
- * (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;
}
/*
* 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;
char buffer[256];
#endif
const char *name;
+ struct file_instance *inst = instance;
request_pairs = request->packet->vps;
/*
* 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",
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)) {
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;
*/
#endif
- for(pl = users; pl; pl = pl->next) {
+ for(pl = inst->users; pl; pl = pl->next) {
/*
* If the current entry is NOT a default,
/*
* Authentication - unused.
*/
-static int file_authenticate(REQUEST *request)
+static int file_authenticate(void *instance, REQUEST *request)
{
+ instance = instance;
request = request;
return RLM_MODULE_OK;
}
if (fn[y] == '|') {
f = popen(&fn[y+1],logcfg[x].mode);
} else {
+ /* FIXME: permissions? */
f = fopen(fn,logcfg[x].mode);
}
if (f) {
*
* 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;
int i, r;
char buffer[256];
#endif
+ struct file_instance *inst = instance;
namepair = request->username;
name = namepair ? (char *) namepair->strvalue : "NONE";
/*
* 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",
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)) {
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;
*/
#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;
/*
* 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;
int ret = RLM_MODULE_OK;
struct stat st;
+ struct file_instance *inst = instance;
+
/*
* See if we have an accounting directory. If not,
* return.
* 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;
}
/*
* 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;
/*
* 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;
}
"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 */
};
* 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;
* 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;
"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 */
};
}
/* 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.
"Pam",
0, /* type: reserved */
NULL, /* initialize */
+ NULL, /* instantiation */
NULL, /* authorize */
pam_auth, /* authenticate */
NULL, /* pre-accounting */
NULL, /* accounting */
NULL, /* detach */
+ NULL, /* destroy */
};
#include "modules.h"
+/* FIXME: should this stuff be instance data? */
static PAIR_LIST *huntgroups;
static PAIR_LIST *hints;
/*
* 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);
/*
* 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;
/*
* 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.
/*
* Clean up.
*/
-static int preprocess_detach(void)
+static int preprocess_destroy(void)
{
paircompare_unregister(PW_HUNTGROUP_NAME, huntgroup_cmp);
pairlist_free(&huntgroups);
"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 */
};
*
* 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 */
/*
* 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;
"Realm",
0, /* type: reserved */
NULL, /* initialization */
+ NULL, /* instantiation */
realm_authorize, /* authorization */
NULL, /* authentication */
realm_preacct, /* preaccounting */
NULL, /* accounting */
NULL, /* detach */
+ NULL, /* destroy */
};
* 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;
return 0;
}
-static int rlm_sql_detach(void) {
+static int rlm_sql_destroy(void) {
return 0;
}
"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 */
};
* 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...");
}
}
+ 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
* 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;
#ifdef HAVE_GETUSERSHELL
char *shell;
#endif
+ instance = instance;
/*
* We can only authenticate user requests which HAVE
/*
* 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;
int port_seen = 0;
int nas_port_type = 0;
+ instance = instance;
+
/*
* Which type is this.
*/
"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 */
};