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 2002,2006 The FreeRADIUS server project
21 * Copyright 2002 Alan DeKok <aland@ox.org>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
31 * Define a structure for our module configuration.
33 typedef struct rlm_expr_t {
37 typedef enum expr_token_t {
50 typedef struct expr_map_t {
55 static expr_map_t map[] =
58 {'-', TOKEN_SUBTRACT },
60 {'*', TOKEN_MULTIPLY },
61 {'%', TOKEN_REMAINDER },
67 static int get_number(REQUEST *request, const char **string, int *answer)
76 * Loop over the input.
81 for (p = *string; *p != '\0'; /* nothing */) {
89 * Discover which token it is.
92 for (i = 0; map[i].token != TOKEN_LAST; i++) {
93 if (*p == map[i].op) {
94 if (this != TOKEN_NONE) {
95 DEBUG2("rlm_expr: Invalid operator at \"%s\"", p);
106 * Found the algebraic operator. Get the next number.
113 * End of a group. Stop.
116 if (this != TOKEN_NONE) {
117 DEBUG2("rlm_expr: Trailing operator before end sub-expression at \"%s\"", p);
125 * Start of a group. Call ourselves recursively.
130 found = get_number(request, &p, &x);
136 * No algrebraic operator found, the next thing
139 * If it isn't, then we die.
141 if ((*p < '0') || (*p > '9')) {
142 DEBUG2("rlm_expr: Not a number at \"%s\"", p);
147 * This is doing it the hard way, but it also allows
148 * us to increment 'p'.
151 while ((*p >= '0') && (*p <= '9')) {
176 case TOKEN_REMAINDER:
194 * We've used this token.
200 * And return the answer to the caller.
208 * Do xlat of strings!
210 static int expr_xlat(void *instance, REQUEST *request, char *fmt, char *out, int outlen,
211 RADIUS_ESCAPE_STRING func)
214 rlm_expr_t *inst = instance;
218 inst = inst; /* -Wunused */
221 * Do an xlat on the provided string (nice recursive operation).
223 if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
224 radlog(L_ERR, "rlm_expr: xlat failed.");
229 rcode = get_number(request, &p, &result);
235 * We MUST have eaten the entire input string.
238 DEBUG2("rlm_expr: Failed at %s", p);
242 snprintf(out, outlen, "%d", result);
247 * Do any per-module initialization that is separate to each
248 * configured instance of the module. e.g. set up connections
249 * to external databases, read configuration files, set up
250 * dictionary entries, etc.
252 * If configuration information is given in the config section
253 * that must be referenced in later calls, store a handle to it
254 * in *instance otherwise put a null pointer there.
256 static int expr_instantiate(CONF_SECTION *conf, void **instance)
262 * Set up a storage area for instance data
265 inst = rad_malloc(sizeof(rlm_expr_t));
268 memset(inst, 0, sizeof(rlm_expr_t));
270 xlat_name = cf_section_name2(conf);
271 if (xlat_name == NULL)
272 xlat_name = cf_section_name1(conf);
274 inst->xlat_name = strdup(xlat_name);
275 xlat_register(xlat_name, expr_xlat, inst);
278 * Initialize various paircompare functions
280 pair_builtincompare_init();
287 * Detach a instance free all ..
289 static int expr_detach(void *instance)
291 rlm_expr_t *inst = instance;
293 xlat_unregister(inst->xlat_name, expr_xlat);
294 pair_builtincompare_detach();
295 free(inst->xlat_name);
302 * The module name should be the only globally exported symbol.
303 * That is, everything else should be 'static'.
305 * If the module needs to temporarily modify it's instantiation
306 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
307 * The server will then take care of ensuring that the module
308 * is single-threaded.
310 module_t rlm_expr = {
313 RLM_TYPE_THREAD_SAFE, /* type */
314 expr_instantiate, /* instantiation */
315 expr_detach, /* detach */
317 NULL, /* authentication */
318 NULL, /* authorization */
319 NULL, /* pre-accounting */
320 NULL /* accounting */