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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2002 The FreeRADIUS server project
21 * Copyright 2002 Alan DeKok <aland@ox.org>
34 static const char rcsid[] = "$Id$";
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)
81 * Loop over the input.
86 for (p = *string; *p != '\0'; /* nothing */) {
94 * Discover which token it is.
97 for (i = 0; map[i].token != TOKEN_LAST; i++) {
98 if (*p == map[i].op) {
99 if (this != TOKEN_NONE) {
100 DEBUG2("rlm_expr: Invalid operator at \"%s\"", p);
111 * Found the algebraic operator. Get the next number.
118 * End of a group. Stop.
121 if (this != TOKEN_NONE) {
122 DEBUG2("rlm_expr: Trailing operator before end sub-expression at \"%s\"", p);
130 * Start of a group. Call ourselves recursively.
135 found = get_number(request, &p, &x);
141 * No algrebraic operator found, the next thing
144 * If it isn't, then we die.
146 if ((*p < '0') || (*p > '9')) {
147 DEBUG2("rlm_expr: Not a number at \"%s\"", p);
152 * This is doing it the hard way, but it also allows
153 * us to increment 'p'.
156 while ((*p >= '0') && (*p <= '9')) {
181 case TOKEN_REMAINDER:
199 * We've used this token.
205 * And return the answer to the caller.
213 * Do xlat of strings!
215 static int expr_xlat(void *instance, REQUEST *request, char *fmt, char *out, int outlen,
216 RADIUS_ESCAPE_STRING func)
219 rlm_expr_t *inst = instance;
223 inst = inst; /* -Wunused */
226 * Do an xlat on the provided string (nice recursive operation).
228 if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
229 radlog(L_ERR, "rlm_expr: xlat failed.");
234 rcode = get_number(request, &p, &result);
240 * We MUST have eaten the entire input string.
243 DEBUG2("rlm_expr: Failed at %s", p);
247 snprintf(out, outlen, "%d", result);
252 * Do any per-module initialization that is separate to each
253 * configured instance of the module. e.g. set up connections
254 * to external databases, read configuration files, set up
255 * dictionary entries, etc.
257 * If configuration information is given in the config section
258 * that must be referenced in later calls, store a handle to it
259 * in *instance otherwise put a null pointer there.
261 static int expr_instantiate(CONF_SECTION *conf, void **instance)
267 * Set up a storage area for instance data
270 inst = rad_malloc(sizeof(rlm_expr_t));
273 memset(inst, 0, sizeof(rlm_expr_t));
275 xlat_name = cf_section_name2(conf);
276 if (xlat_name == NULL)
277 xlat_name = cf_section_name1(conf);
279 inst->xlat_name = strdup(xlat_name);
280 xlat_register(xlat_name, expr_xlat, inst);
283 * Initialize various paircompare functions
285 pair_builtincompare_init();
292 * Detach a instance free all ..
294 static int expr_detach(void *instance)
296 rlm_expr_t *inst = instance;
298 xlat_unregister(inst->xlat_name, expr_xlat);
299 free(inst->xlat_name);
306 * The module name should be the only globally exported symbol.
307 * That is, everything else should be 'static'.
309 * If the module needs to temporarily modify it's instantiation
310 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
311 * The server will then take care of ensuring that the module
312 * is single-threaded.
314 module_t rlm_expr = {
316 RLM_TYPE_THREAD_SAFE, /* type */
317 NULL, /* initialization */
318 expr_instantiate, /* instantiation */
320 NULL, /* authentication */
321 NULL, /* authorization */
322 NULL, /* pre-accounting */
323 NULL /* accounting */
325 expr_detach, /* detach */