2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 if the
4 * License as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * @file rlm_checkval.c
19 * @brief Enables simple value checking.
21 * @copyright 2003,2006 The FreeRADIUS server project
22 * @copyright 2003 Kostas Kalevras <kkalev@noc.ntua.gr>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
34 #define REG_EXTENDED (0)
41 * Define a structure for our module configuration.
43 * These variables do not need to be in a structure, but it's
44 * a lot cleaner to do so, and a pointer to the structure can
45 * be used as the instance handle.
47 typedef struct rlm_checkval_t {
48 char *item_name; //!< The attribute inside
49 //!< Access-Request i.e.
50 //!< Calling-Station-Id.
51 char *check_name; //!< The attribute to check it with ie
52 //!< Allowed-Calling-Station-Id.
53 char *data_type; //!< String, integer, ipaddr, date,
55 PW_TYPE type; //!< Resolved data type.
57 const DICT_ATTR *item;
58 const DICT_ATTR *check;
60 int notfound_reject; //!< If we don't find the
61 //!< item_name in the request
62 //!< send back a reject.
66 * A mapping of configuration file names to internal variables.
68 * Note that the string is dynamically allocated, so it MUST
69 * be freed. When the configuration file parse re-reads the string,
70 * it free's the old one, and strdup's the new one, placing the pointer
71 * to the strdup'd string into 'config.string'. This gets around
74 static const CONF_PARSER module_config[] = {
75 { "item-name", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
76 offsetof(rlm_checkval_t,item_name), NULL, NULL},
77 { "check-name", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
78 offsetof(rlm_checkval_t,check_name), NULL, NULL},
79 { "data-type", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
80 offsetof(rlm_checkval_t,data_type),NULL, "integer"},
81 { "notfound-reject", PW_TYPE_BOOLEAN,
82 offsetof(rlm_checkval_t,notfound_reject),NULL, "no"},
83 { NULL, -1, 0, NULL, NULL } /* end the list */
87 * Do any per-module initialization that is separate to each
88 * configured instance of the module. e.g. set up connections
89 * to external databases, read configuration files, set up
90 * dictionary entries, etc.
92 * If configuration information is given in the config section
93 * that must be referenced in later calls, store a handle to it
94 * in *instance otherwise put a null pointer there.
96 static int mod_instantiate(CONF_SECTION *conf, void *instance)
98 rlm_checkval_t *inst = instance;
102 rad_assert(inst->data_type && *inst->data_type);
103 rad_assert(inst->item_name && *inst->item_name);
104 rad_assert(inst->check_name && *inst->check_name);
107 * Convert the string type to an integer type,
108 * so we don't have to do string comparisons on each
111 inst->type = fr_str2int(dict_attr_types, inst->data_type, 0);
113 cf_log_err_cs(conf, "Invalid data-type '%s'",
119 * Discover the attribute number of the item name
121 inst->item = dict_attrbyname(inst->item_name);
122 rad_assert(inst->item != NULL);
125 * Add the check attribute name to the dictionary
126 * if it does not already exists. dict_addattr() handles that
128 memset(&flags, 0, sizeof(flags));
130 dict_addattr(inst->check_name, -1, 0, PW_TYPE_STRING, flags);
131 da = dict_attrbyname(inst->check_name);
133 ERROR("rlm_checkval: No such attribute %s",
138 DEBUG2("rlm_checkval: Registered name %s for attribute %d",
144 static rlm_rcode_t do_checkval(void *instance, REQUEST *request)
146 rlm_checkval_t *inst = instance;
147 rlm_rcode_t rcode = RLM_MODULE_NOOP;
148 VALUE_PAIR *check, *item;
153 * Look for the check item
155 if (!(item = pairfind(request->packet->vps, inst->item->attr, inst->item->vendor, TAG_ANY))){
156 DEBUG2("rlm_checkval: Could not find item named %s in request", inst->item_name);
157 if (inst->notfound_reject)
158 rcode = RLM_MODULE_REJECT;
160 rcode = RLM_MODULE_NOTFOUND;
163 DEBUG2("rlm_checkval: Item Name: %s, Value: %s",inst->item_name, item->vp_strvalue);
164 tmp = request->config_items;
166 if (!(check = pairfind(tmp, inst->check->attr, inst->check->vendor, TAG_ANY))){
168 DEBUG2("rlm_checkval: Could not find attribute named %s in check pairs",inst->check_name);
169 rcode = RLM_MODULE_NOTFOUND;
175 DEBUG2("rlm_checkval: Value Name: %s, Value: %s",inst->check_name, check->vp_strvalue);
178 * Check if item != check
180 * FIXME: !!! Call normal API functions!
183 if (inst->type == PW_TYPE_STRING ||
184 inst->type == PW_TYPE_OCTETS) {
185 if (item->length != check->length)
186 rcode = RLM_MODULE_REJECT;
188 if (!memcmp(item->vp_strvalue,
190 (size_t) check->length))
191 rcode = RLM_MODULE_OK;
193 rcode = RLM_MODULE_REJECT;
195 } else if (inst->type == PW_TYPE_DATE) {
196 if (item->vp_date == check->vp_date)
197 rcode = RLM_MODULE_OK;
199 rcode = RLM_MODULE_REJECT;
200 } else if (inst->type == PW_TYPE_INTEGER) {
201 if (item->vp_integer == check->vp_integer)
202 rcode = RLM_MODULE_OK;
204 rcode = RLM_MODULE_REJECT;
207 if (rcode == RLM_MODULE_REJECT &&
208 check->op == T_OP_REG_EQ) {
211 char err_msg[MAX_STRING_LEN];
213 DEBUG("rlm_checkval: Doing regex");
214 err = regcomp(®, (char *)check->vp_strvalue, REG_EXTENDED|REG_NOSUB);
216 regerror(err, ®,err_msg, MAX_STRING_LEN);
217 DEBUG("rlm_checkval: regcomp() returned error: %s", err_msg);
218 return RLM_MODULE_FAIL;
220 if (regexec(®, (char *)item->vp_strvalue,0, NULL, 0) == 0)
221 rcode = RLM_MODULE_OK;
223 rcode = RLM_MODULE_REJECT;
228 } while (rcode == RLM_MODULE_REJECT &&
231 if (rcode == RLM_MODULE_REJECT) {
232 if (!item && inst->notfound_reject){
233 RDEBUGE("Could not find item named %s in request", inst->item_name);
235 RDEBUGE("This %s is not allowed for the user", inst->item_name);
245 static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
247 return do_checkval(instance,request);
250 static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
252 return do_checkval(instance,request);
256 * The module name should be the only globally exported symbol.
257 * That is, everything else should be 'static'.
259 * If the module needs to temporarily modify it's instantiation
260 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
261 * The server will then take care of ensuring that the module
262 * is single-threaded.
264 module_t rlm_checkval = {
268 sizeof(rlm_checkval_t),
270 mod_instantiate, /* instantiation */
273 NULL, /* authentication */
274 mod_authorize, /* authorization */
275 NULL, /* preaccounting */
276 mod_accounting, /* accounting */
277 NULL, /* checksimul */
278 NULL, /* pre-proxy */
279 NULL, /* post-proxy */