rlm_protocol_filter.c [plain text]
#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
typedef struct rlm_protocol_filter_t {
char *filename;
char *key;
CONF_SECTION *cs;
} rlm_protocol_filter_t;
static const CONF_PARSER module_config[] = {
{ "filename", PW_TYPE_FILENAME,
offsetof(rlm_protocol_filter_t,filename), NULL,
"${raddbdir}/protocol_filter.conf"},
{ "key", PW_TYPE_STRING_PTR,
offsetof(rlm_protocol_filter_t,key), NULL, "%{Realm:-DEFAULT}"},
{ NULL, -1, 0, NULL, NULL }
};
static int filter_detach(void *instance)
{
rlm_protocol_filter_t *inst = instance;
if (inst->cs) cf_section_free(&(inst->cs));
free(instance);
return 0;
}
static int filter_instantiate(CONF_SECTION *conf, void **instance)
{
rlm_protocol_filter_t *inst;
inst = rad_malloc(sizeof(*inst));
if (!inst) {
return -1;
}
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(conf, inst, module_config) < 0) {
filter_detach(inst);
return -1;
}
inst->cs = cf_file_read(inst->filename);
if (!inst->cs) {
filter_detach(inst);
return -1;
}
*instance = inst;
return 0;
}
static int str2sense(const char *str)
{
if (strcasecmp(str, "permit") == 0) return 1;
if (strcasecmp(str, "deny") == 0) return 0;
return -1;
}
static int apply_subsection(rlm_protocol_filter_t *inst, REQUEST *request,
CONF_SECTION *cs, const char *name)
{
int sense;
CONF_PAIR *cp;
const char *value;
char keybuf[256];
DEBUG2(" rlm_protocol_filter: Found subsection %s", name);
cp = cf_pair_find(cs, "key");
if (!cp) {
radlog(L_ERR, "rlm_protocol_filter: %s[%d]: No key defined in subsection %s",
inst->filename, cf_section_lineno(cs), name);
return RLM_MODULE_FAIL;
}
radius_xlat(keybuf, sizeof(keybuf),
cf_pair_value(cp), request, NULL);
if (!*keybuf) {
DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, key is empty, doing nothing.",
inst->filename, cf_section_lineno(cs), name);
return RLM_MODULE_NOOP;
}
DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, using key %s",
inst->filename, cf_section_lineno(cs), name, keybuf);
cp = cf_pair_find(cs, keybuf);
if (!cp) {
CONF_SECTION *subcs;
subcs = cf_section_sub_find(cs, keybuf);
if (subcs) {
return apply_subsection(inst, request, subcs, keybuf);
}
DEBUG2(" rlm_protocol_filter: %s[%d]: subsection %s, rule not found, doing nothing.",
inst->filename, cf_section_lineno(cs), name);
return RLM_MODULE_NOOP;
}
value = cf_pair_value(cp);
sense = str2sense(value);
if (sense < 0) {
radlog(L_ERR, "rlm_protocol_filter: %s[%d]: Unknwn directive %s",
inst->filename, cf_pair_lineno(cp), value);
return RLM_MODULE_FAIL;
}
if (!sense) return RLM_MODULE_REJECT;
return RLM_MODULE_OK;
}
static int filter_authorize(void *instance, REQUEST *request)
{
int sense;
VALUE_PAIR *vp;
CONF_SECTION *cs;
CONF_PAIR *cp;
char keybuf[1024];
rlm_protocol_filter_t *inst = instance;
radius_xlat(keybuf, sizeof(keybuf), inst->key, request, NULL);
if (!*keybuf) {
DEBUG2(" rlm_protocol_filter: key is empty");
return RLM_MODULE_NOOP;
}
DEBUG2(" rlm_protocol_filter: Using key %s", keybuf);
cs = cf_section_sub_find(inst->cs, keybuf);
if (!cs) {
DEBUG2(" rlm_protocol_filter: No such key in %s", inst->filename);
return RLM_MODULE_NOTFOUND;
}
for (vp = request->packet->vps; vp != NULL; vp = vp->next) {
const char *value;
CONF_SECTION *subcs;
cp = cf_pair_find(cs, vp->name);
if (cp) {
value = cf_pair_value(cp);
sense = str2sense(value);
if (sense < 0) {
radlog(L_ERR, "rlm_protocol_filter %s[%d]: Unknown directive %s",
inst->filename,
cf_pair_lineno(cp),
value);
return RLM_MODULE_FAIL;
}
if (!sense) return RLM_MODULE_REJECT;
continue;
}
subcs = cf_section_sub_find(cs, vp->name);
if (subcs) {
sense = apply_subsection(inst, request, subcs, vp->name);
if ((sense == RLM_MODULE_OK) ||
(sense == RLM_MODULE_NOOP)) {
continue;
}
return sense;
}
}
return RLM_MODULE_OK;
}
module_t rlm_protocol_filter = {
RLM_MODULE_INIT,
"protocol_filter",
RLM_TYPE_THREAD_SAFE,
filter_instantiate,
filter_detach,
{
NULL,
filter_authorize,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
},
};