6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2003,2006 The FreeRADIUS server project
21 * Copyright 2003 Kostas Kalevras <kkalev@noc.ntua.gr>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/autoconf.h>
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/modules.h>
39 #define REG_EXTENDED (0)
46 * Define a structure for our module configuration.
48 * These variables do not need to be in a structure, but it's
49 * a lot cleaner to do so, and a pointer to the structure can
50 * be used as the instance handle.
52 typedef struct rlm_checkval_t {
53 char *item_name; /* The attribute inside Access-Request ie Calling-Station-Id */
54 char *check_name; /* The attribute to check it with ie Allowed-Calling-Station-Id */
55 char *data_type; /* string,integer,ipaddr,date,abinary,octets */
59 int notfound_reject; /* If we don't find the item_name in the request send back a reject */
63 * A mapping of configuration file names to internal variables.
65 * Note that the string is dynamically allocated, so it MUST
66 * be freed. When the configuration file parse re-reads the string,
67 * it free's the old one, and strdup's the new one, placing the pointer
68 * to the strdup'd string into 'config.string'. This gets around
71 static const CONF_PARSER module_config[] = {
72 { "item-name", PW_TYPE_STRING_PTR, offsetof(rlm_checkval_t,item_name), NULL, NULL},
73 { "check-name", PW_TYPE_STRING_PTR, offsetof(rlm_checkval_t,check_name), NULL, NULL},
74 { "data-type", PW_TYPE_STRING_PTR, offsetof(rlm_checkval_t,data_type),NULL, "integer"},
75 { "notfound-reject", PW_TYPE_BOOLEAN, offsetof(rlm_checkval_t,notfound_reject),NULL, "no"},
76 { NULL, -1, 0, NULL, NULL } /* end the list */
80 static int checkval_detach(void *instance)
82 rlm_checkval_t *data = (rlm_checkval_t *) instance;
85 free((char *)data->item_name);
87 free((char *)data->check_name);
89 free((char *)data->data_type);
96 * Do any per-module initialization that is separate to each
97 * configured instance of the module. e.g. set up connections
98 * to external databases, read configuration files, set up
99 * dictionary entries, etc.
101 * If configuration information is given in the config section
102 * that must be referenced in later calls, store a handle to it
103 * in *instance otherwise put a null pointer there.
105 static int checkval_instantiate(CONF_SECTION *conf, void **instance)
107 rlm_checkval_t *data;
111 static const LRAD_NAME_NUMBER names[] = {
112 { "string", PW_TYPE_STRING },
113 { "integer", PW_TYPE_INTEGER },
114 { "ipaddr", PW_TYPE_IPADDR },
115 { "date", PW_TYPE_DATE },
116 { "abinary", PW_TYPE_OCTETS },
117 { "octets", PW_TYPE_OCTETS },
118 { "binary", PW_TYPE_OCTETS },
123 * Set up a storage area for instance data
125 data = rad_malloc(sizeof(*data));
129 memset(data, 0, sizeof(*data));
132 * If the configuration parameters can't be parsed, then
135 if (cf_section_parse(conf, data, module_config) < 0) {
136 checkval_detach(data);
141 * Check if data_type exists
143 if (!data->data_type || !strlen(data->data_type)){
144 radlog(L_ERR, "rlm_checkval: Data type not defined");
145 checkval_detach(data);
148 if (!data->item_name || !strlen(data->item_name)){
149 radlog(L_ERR, "rlm_checkval: Item name not defined");
150 checkval_detach(data);
153 if (!data->check_name || !strlen(data->check_name)){
154 radlog(L_ERR, "rlm_checkval: Check item name not defined");
155 checkval_detach(data);
160 * Discover the attribute number of the item name
162 dattr = dict_attrbyname(data->item_name);
164 radlog(L_ERR, "rlm_checkval: No such attribute %s",
166 checkval_detach(data);
169 data->item_attr = dattr->attr;
172 * Add the check attribute name to the dictionary
173 * if it does not already exists. dict_addattr() handles that
176 memset(&flags, 0, sizeof(flags));
177 dict_addattr(data->check_name, 0, PW_TYPE_STRING, -1,flags);
178 dattr = dict_attrbyname(data->check_name);
180 radlog(L_ERR, "rlm_checkval: No such attribute %s",
182 checkval_detach(data);
185 data->chk_attr = dattr->attr;
186 DEBUG2("rlm_checkval: Registered name %s for attribute %d",
187 dattr->name,dattr->attr);
190 * Convert the string type to an integer type,
191 * so we don't have to do string comparisons on each
194 data->dat_type = lrad_str2int(names, data->data_type, -1);
195 if (data->dat_type < 0) {
196 radlog(L_ERR, "rlm_checkval: Data type %s in not known",data->data_type);
197 checkval_detach(data);
206 static int do_checkval(void *instance, REQUEST *request)
208 rlm_checkval_t *data = (rlm_checkval_t *) instance;
209 int ret=RLM_MODULE_NOOP;
210 VALUE_PAIR *chk_vp, *item_vp;
214 /* quiet the compiler */
220 * Look for the check item
223 if (!(item_vp = pairfind(request->packet->vps, data->item_attr))){
224 DEBUG2("rlm_checkval: Could not find item named %s in request", data->item_name);
225 if (data->notfound_reject)
226 ret = RLM_MODULE_REJECT;
228 ret = RLM_MODULE_NOTFOUND;
231 DEBUG2("rlm_checkval: Item Name: %s, Value: %s",data->item_name, item_vp->vp_strvalue);
232 tmp = request->config_items;
234 if (!(chk_vp = pairfind(tmp, data->chk_attr))){
236 DEBUG2("rlm_checkval: Could not find attribute named %s in check pairs",data->check_name);
237 ret = RLM_MODULE_NOTFOUND;
243 DEBUG2("rlm_checkval: Value Name: %s, Value: %s",data->check_name, chk_vp->vp_strvalue);
246 * Check if item != check
249 if (data->dat_type == PW_TYPE_STRING ||
250 data->dat_type == PW_TYPE_OCTETS) {
251 if (item_vp->length != chk_vp->length)
252 ret = RLM_MODULE_REJECT;
254 if (!memcmp(item_vp->vp_strvalue,
256 (size_t) chk_vp->length))
259 ret = RLM_MODULE_REJECT;
262 else{ /* Integer or Date */
264 if (item_vp->lvalue == chk_vp->lvalue)
267 ret = RLM_MODULE_REJECT;
270 if (ret == RLM_MODULE_REJECT &&
271 chk_vp->operator == T_OP_REG_EQ) {
274 char err_msg[MAX_STRING_LEN];
276 DEBUG("rlm_checkval: Doing regex");
277 err = regcomp(®, (char *)chk_vp->vp_strvalue, REG_EXTENDED|REG_NOSUB);
279 regerror(err, ®,err_msg, MAX_STRING_LEN);
280 DEBUG("rlm_checkval: regcomp() returned error: %s", err_msg);
281 return RLM_MODULE_FAIL;
283 if (regexec(®, (char *)item_vp->vp_strvalue,0, NULL, 0) == 0)
286 ret = RLM_MODULE_REJECT;
291 } while (ret == RLM_MODULE_REJECT &&
294 if (ret == RLM_MODULE_REJECT) {
295 if (!item_vp && data->notfound_reject){
296 char module_fmsg[MAX_STRING_LEN];
297 VALUE_PAIR *module_fmsg_vp;
299 snprintf(module_fmsg,sizeof(module_fmsg),
300 "rlm_checkval: Could not find item named %s in request", data->item_name);
301 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
302 pairadd(&request->packet->vps, module_fmsg_vp);
305 char module_fmsg[MAX_STRING_LEN];
306 VALUE_PAIR *module_fmsg_vp;
308 snprintf(module_fmsg,sizeof(module_fmsg),
309 "rlm_checkval: This %s is not allowed for the user", data->item_name);
310 module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ);
311 pairadd(&request->packet->vps, module_fmsg_vp);
321 static int checkval_authorize(void *instance, REQUEST *request)
323 return do_checkval(instance,request);
326 static int checkval_accounting(void *instance, REQUEST *request)
328 return do_checkval(instance,request);
332 * The module name should be the only globally exported symbol.
333 * That is, everything else should be 'static'.
335 * If the module needs to temporarily modify it's instantiation
336 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
337 * The server will then take care of ensuring that the module
338 * is single-threaded.
340 module_t rlm_checkval = {
344 checkval_instantiate, /* instantiation */
345 checkval_detach, /* detach */
347 NULL, /* authentication */
348 checkval_authorize, /* authorization */
349 NULL, /* preaccounting */
350 checkval_accounting, /* accounting */
351 NULL, /* checksimul */
352 NULL, /* pre-proxy */
353 NULL, /* post-proxy */