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/autoconf.h>
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/modules.h>
37 * Define a structure for our module configuration.
39 typedef struct rlm_expr_t {
43 typedef enum expr_token_t {
56 typedef struct expr_map_t {
61 static expr_map_t map[] =
64 {'-', TOKEN_SUBTRACT },
66 {'*', TOKEN_MULTIPLY },
67 {'%', TOKEN_REMAINDER },
73 static int get_number(REQUEST *request, const char **string, int *answer)
82 * Loop over the input.
87 for (p = *string; *p != '\0'; /* nothing */) {
95 * Discover which token it is.
98 for (i = 0; map[i].token != TOKEN_LAST; i++) {
99 if (*p == map[i].op) {
100 if (this != TOKEN_NONE) {
101 DEBUG2("rlm_expr: Invalid operator at \"%s\"", p);
112 * Found the algebraic operator. Get the next number.
119 * End of a group. Stop.
122 if (this != TOKEN_NONE) {
123 DEBUG2("rlm_expr: Trailing operator before end sub-expression at \"%s\"", p);
131 * Start of a group. Call ourselves recursively.
136 found = get_number(request, &p, &x);
142 * No algrebraic operator found, the next thing
145 * If it isn't, then we die.
147 if ((*p < '0') || (*p > '9')) {
148 DEBUG2("rlm_expr: Not a number at \"%s\"", p);
153 * This is doing it the hard way, but it also allows
154 * us to increment 'p'.
157 while ((*p >= '0') && (*p <= '9')) {
182 case TOKEN_REMAINDER:
200 * We've used this token.
206 * And return the answer to the caller.
214 * Do xlat of strings!
216 static int expr_xlat(void *instance, REQUEST *request, char *fmt, char *out, int outlen,
217 RADIUS_ESCAPE_STRING func)
220 rlm_expr_t *inst = instance;
224 inst = inst; /* -Wunused */
227 * Do an xlat on the provided string (nice recursive operation).
229 if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
230 radlog(L_ERR, "rlm_expr: xlat failed.");
235 rcode = get_number(request, &p, &result);
241 * We MUST have eaten the entire input string.
244 DEBUG2("rlm_expr: Failed at %s", p);
248 snprintf(out, outlen, "%d", result);
253 * Do any per-module initialization that is separate to each
254 * configured instance of the module. e.g. set up connections
255 * to external databases, read configuration files, set up
256 * dictionary entries, etc.
258 * If configuration information is given in the config section
259 * that must be referenced in later calls, store a handle to it
260 * in *instance otherwise put a null pointer there.
262 static int expr_instantiate(CONF_SECTION *conf, void **instance)
268 * Set up a storage area for instance data
271 inst = rad_malloc(sizeof(rlm_expr_t));
274 memset(inst, 0, sizeof(rlm_expr_t));
276 xlat_name = cf_section_name2(conf);
277 if (xlat_name == NULL)
278 xlat_name = cf_section_name1(conf);
280 inst->xlat_name = strdup(xlat_name);
281 xlat_register(xlat_name, expr_xlat, inst);
284 * Initialize various paircompare functions
286 pair_builtincompare_init();
293 * Detach a instance free all ..
295 static int expr_detach(void *instance)
297 rlm_expr_t *inst = instance;
299 xlat_unregister(inst->xlat_name, expr_xlat);
300 pair_builtincompare_detach();
301 free(inst->xlat_name);
308 * The module name should be the only globally exported symbol.
309 * That is, everything else should be 'static'.
311 * If the module needs to temporarily modify it's instantiation
312 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
313 * The server will then take care of ensuring that the module
314 * is single-threaded.
316 module_t rlm_expr = {
319 RLM_TYPE_THREAD_SAFE, /* type */
320 expr_instantiate, /* instantiation */
321 expr_detach, /* detach */
323 NULL, /* authentication */
324 NULL, /* authorization */
325 NULL, /* pre-accounting */
326 NULL /* accounting */