4ec7b95f5c1b5090b3a86f3908ee4ad1a7e2ddfb
[freeradius.git] / src / main / modcall.c
1 /*
2  * modcall.c
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modpriv.h>
28 #include <freeradius-devel/modcall.h>
29 #include <freeradius-devel/rad_assert.h>
30
31
32 /* mutually-recursive static functions need a prototype up front */
33 static modcallable *do_compile_modgroup(modcallable *,
34                                         int, CONF_SECTION *,
35                                         int, int);
36
37 /* Actions may be a positive integer (the highest one returned in the group
38  * will be returned), or the keyword "return", represented here by
39  * MOD_ACTION_RETURN, to cause an immediate return.
40  * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
41  * to cause an immediate reject. */
42 #define MOD_ACTION_RETURN  (-1)
43 #define MOD_ACTION_REJECT  (-2)
44
45 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
46  * explanation of what they are all about, see ../../doc/README.failover */
47 struct modcallable {
48         modcallable *parent;
49         struct modcallable *next;
50         const char *name;
51         enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE, MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE, MOD_POLICY } type;
52         int method;
53         int actions[RLM_MODULE_NUMCODES];
54 };
55
56 #define GROUPTYPE_SIMPLE        0
57 #define GROUPTYPE_REDUNDANT     1
58 #define GROUPTYPE_APPEND        2
59 #define GROUPTYPE_COUNT         3
60
61 typedef struct {
62         modcallable mc;         /* self */
63         int grouptype;  /* after mc */
64         modcallable *children;
65         CONF_SECTION *cs;
66         VALUE_PAIR *vps;
67 } modgroup;
68
69 typedef struct {
70         modcallable mc;
71         module_instance_t *modinst;
72 } modsingle;
73
74 static const FR_NAME_NUMBER grouptype_table[] = {
75         { "", GROUPTYPE_SIMPLE },
76         { "redundant ", GROUPTYPE_REDUNDANT },
77         { "append ", GROUPTYPE_APPEND },
78         { NULL, -1 }
79 };
80
81 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
82  * so we often want to go back and forth between them. */
83 static modsingle *mod_callabletosingle(modcallable *p)
84 {
85         rad_assert(p->type==MOD_SINGLE);
86         return (modsingle *)p;
87 }
88 static modgroup *mod_callabletogroup(modcallable *p)
89 {
90         rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
91
92         return (modgroup *)p;
93 }
94 static modcallable *mod_singletocallable(modsingle *p)
95 {
96         return (modcallable *)p;
97 }
98 static modcallable *mod_grouptocallable(modgroup *p)
99 {
100         return (modcallable *)p;
101 }
102
103 /* modgroups are grown by adding a modcallable to the end */
104 static void add_child(modgroup *g, modcallable *c)
105 {
106         modcallable **head = &g->children;
107         modcallable *node = *head;
108         modcallable **last = head;
109
110         if (!c) return;
111
112         while (node) {
113                 last = &node->next;
114                 node = node->next;
115         }
116
117         rad_assert(c->next == NULL);
118         *last = c;
119         c->parent = mod_grouptocallable(g);
120 }
121
122 /* Here's where we recognize all of our keywords: first the rcodes, then the
123  * actions */
124 static const FR_NAME_NUMBER rcode_table[] = {
125         { "reject",     RLM_MODULE_REJECT       },
126         { "fail",       RLM_MODULE_FAIL         },
127         { "ok",         RLM_MODULE_OK           },
128         { "handled",    RLM_MODULE_HANDLED      },
129         { "invalid",    RLM_MODULE_INVALID      },
130         { "userlock",   RLM_MODULE_USERLOCK     },
131         { "notfound",   RLM_MODULE_NOTFOUND     },
132         { "noop",       RLM_MODULE_NOOP         },
133         { "updated",    RLM_MODULE_UPDATED      },
134         { NULL, 0 }
135 };
136
137
138 /*
139  *      Compile action && rcode for later use.
140  */
141 static int compile_action(modcallable *c, CONF_PAIR *cp)
142 {
143         int action;
144         const char *attr, *value;
145
146         attr = cf_pair_attr(cp);
147         value = cf_pair_value(cp);
148         if (!value) return 0;
149
150         if (!strcasecmp(value, "return"))
151                 action = MOD_ACTION_RETURN;
152
153         else if (!strcasecmp(value, "break"))
154                 action = MOD_ACTION_RETURN;
155
156         else if (!strcasecmp(value, "reject"))
157                 action = MOD_ACTION_REJECT;
158
159         else if (strspn(value, "0123456789")==strlen(value)) {
160                 action = atoi(value);
161
162                 /*
163                  *      Don't allow priority zero, for future use.
164                  */
165                 if (action == 0) return 0;
166         } else {
167                 cf_log_err(cf_pairtoitem(cp), "Unknown action '%s'.\n",
168                            value);
169                 return 0;
170         }
171
172         if (strcasecmp(attr, "default") != 0) {
173                 int rcode;
174
175                 rcode = fr_str2int(rcode_table, attr, -1);
176                 if (rcode < 0) {
177                         cf_log_err(cf_pairtoitem(cp),
178                                    "Unknown module rcode '%s'.\n",
179                                    attr);
180                         return 0;
181                 }
182                 c->actions[rcode] = action;
183
184         } else {                /* set all unset values to the default */
185                 int i;
186
187                 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
188                         if (!c->actions[i]) c->actions[i] = action;
189                 }
190         }
191
192         return 1;
193 }
194
195 /* Some short names for debugging output */
196 static const char * const comp2str[] = {
197         "authenticate",
198         "authorize",
199         "preacct",
200         "accounting",
201         "session",
202         "pre-proxy",
203         "post-proxy",
204         "post-auth"
205 };
206
207 #ifdef HAVE_PTHREAD_H
208 /*
209  *      Lock the mutex for the module
210  */
211 static void safe_lock(module_instance_t *instance)
212 {
213         if (instance->mutex)
214                 pthread_mutex_lock(instance->mutex);
215 }
216
217 /*
218  *      Unlock the mutex for the module
219  */
220 static void safe_unlock(module_instance_t *instance)
221 {
222         if (instance->mutex)
223                 pthread_mutex_unlock(instance->mutex);
224 }
225 #else
226 /*
227  *      No threads: these functions become NULL's.
228  */
229 #define safe_lock(foo)
230 #define safe_unlock(foo)
231 #endif
232
233 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
234                           int default_result)
235 {
236         int myresult = default_result;
237
238         DEBUG3("  modsingle[%s]: calling %s (%s) for request %d",
239                comp2str[component], sp->modinst->name,
240                sp->modinst->entry->name, request->number);
241         safe_lock(sp->modinst);
242
243         /*
244          *      For logging unresponsive children.
245          */
246         request->module = sp->modinst->name;
247
248         myresult = sp->modinst->entry->module->methods[component](
249                         sp->modinst->insthandle, request);
250
251         request->module = "<server-core>";
252         safe_unlock(sp->modinst);
253         DEBUG3("  modsingle[%s]: returned from %s (%s) for request %d",
254                comp2str[component], sp->modinst->name,
255                sp->modinst->entry->name, request->number);
256
257         return myresult;
258 }
259
260
261 static int default_component_results[RLM_COMPONENT_COUNT] = {
262         RLM_MODULE_REJECT,      /* AUTH */
263         RLM_MODULE_NOTFOUND,    /* AUTZ */
264         RLM_MODULE_NOOP,        /* PREACCT */
265         RLM_MODULE_NOOP,        /* ACCT */
266         RLM_MODULE_FAIL,        /* SESS */
267         RLM_MODULE_NOOP,        /* PRE_PROXY */
268         RLM_MODULE_NOOP,        /* POST_PROXY */
269         RLM_MODULE_NOOP         /* POST_AUTH */
270 };
271
272
273 static const char *group_name[] = {
274         "",
275         "single",
276         "group",
277         "load-balance group",
278         "redundant-load-balance group",
279         "if",
280         "else",
281         "elsif",
282         "update",
283         "switch",
284         "case",
285         "policy"
286 };
287
288 static const char *modcall_spaces = "++++++++++++++++++++++++++++++++";
289
290 #define MODCALL_STACK_MAX (32)
291
292 /*
293  *      Don't call the modules recursively.  Instead, do them
294  *      iteratively, and manage the call stack ourselves.
295  */
296 typedef struct modcall_stack {
297         int pointer;
298
299         int priority[MODCALL_STACK_MAX];
300         int result[MODCALL_STACK_MAX];
301         modcallable *children[MODCALL_STACK_MAX];
302         modcallable *start[MODCALL_STACK_MAX];
303 } modcall_stack;
304
305
306 /*
307  *      Call a module, iteratively, with a local stack, rather than
308  *      recursively.  What did Paul Graham say about Lisp...?
309  */
310 int modcall(int component, modcallable *c, REQUEST *request)
311 {
312         int myresult;
313         modcall_stack stack;
314         modcallable *parent, *child;
315         modsingle *sp;
316         int if_taken, was_if;
317
318         if ((component < 0) || (component >= RLM_COMPONENT_COUNT)) {
319                 return RLM_MODULE_FAIL;
320         }
321
322         stack.pointer = 0;
323         stack.priority[0] = 0;
324         stack.children[0] = c;
325         myresult = stack.result[0] = default_component_results[component];
326         was_if = if_taken = FALSE;
327
328         while (1) {
329                 /*
330                  *      A module has taken too long to process the request,
331                  *      and we've been told to stop processing it.
332                  */
333                 if ((request->master_state == REQUEST_STOP_PROCESSING) ||
334                     (request->parent &&
335                      (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
336                         myresult = RLM_MODULE_FAIL;
337                         break;
338                 }
339
340                 child = stack.children[stack.pointer];
341                 if (!child) {
342                         myresult = stack.result[stack.pointer];
343                         break;
344                 }
345                 parent = child->parent;
346
347                 if ((child->type == MOD_ELSE) || (child->type == MOD_ELSIF)) {
348                         myresult = stack.result[stack.pointer];
349
350                         if (!was_if) { /* error */
351                                 DEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
352                                        stack.pointer + 1, modcall_spaces,
353                                        group_name[child->type],
354                                        request->number);
355                                 goto unroll;
356                         }
357                         if (if_taken) {
358                                 DEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
359                                        stack.pointer + 1, modcall_spaces,
360                                        group_name[child->type],
361                                        request->number);
362                                 goto unroll;
363                         }
364                 }
365
366                 /*
367                  *      "if" or "elsif".  Evaluate the condition.
368                  */
369                 if ((child->type == MOD_IF) || (child->type == MOD_ELSIF)) {
370                         int condition = TRUE;
371                         const char *p = child->name;
372
373                         DEBUG2("%.*s? %s %s",
374                                stack.pointer + 1, modcall_spaces,
375                                (child->type == MOD_IF) ? "if" : "elsif",
376                                child->name);
377
378                         if (radius_evaluate_condition(request, myresult,
379                                                       0, &p, TRUE, &condition)) {
380                                 DEBUG2("%.*s? %s %s -> %s",
381                                        stack.pointer + 1, modcall_spaces,
382                                        (child->type == MOD_IF) ? "if" : "elsif",
383                                        child->name, (condition != FALSE) ? "TRUE" : "FALSE");
384                         } else {
385                                 /*
386                                  *      This should never happen, the
387                                  *      condition is checked when the
388                                  *      module section is loaded.
389                                  */
390                                 condition = FALSE;
391                         }
392
393                         if (!condition) {
394                                 stack.result[stack.pointer] = myresult;
395                                 stack.children[stack.pointer] = NULL;
396                                 was_if = TRUE;
397                                 if_taken = FALSE;
398                                 goto next_section;
399                         } /* else process it as a simple group */
400                 }
401
402                 if (child->type == MOD_UPDATE) {
403                         int rcode;
404                         modgroup *g = mod_callabletogroup(child);
405
406                         rcode = radius_update_attrlist(request, g->cs,
407                                                        g->vps, child->name);
408                         if (rcode != RLM_MODULE_UPDATED) {
409                                 myresult = rcode;
410                         }
411                         goto handle_result;
412                 }
413
414                 /*
415                  *      Child is a group that has children of it's own.
416                  */
417                 if (child->type != MOD_SINGLE) {
418                         int count = 1;
419                         modcallable *p, *q, *null_case;
420                         modgroup *g = mod_callabletogroup(child);
421
422                         stack.pointer++;
423
424                         /*
425                          *      Catastrophic error.  This SHOULD have
426                          *      been caught when we were reading in the
427                          *      conf files.
428                          *
429                          *      FIXME: Do so.
430                          */
431                         if (stack.pointer >= MODCALL_STACK_MAX) {
432                                 radlog(L_ERR, "Internal sanity check failed: module stack is too deep");
433                                 exit(1);
434                         }
435
436                         stack.priority[stack.pointer] = 0;
437                         stack.result[stack.pointer] = default_component_results[component];
438                         switch (child->type) {
439                                 char buffer[1024];
440
441                         case MOD_IF:
442                         case MOD_ELSE:
443                         case MOD_ELSIF:
444                         case MOD_CASE:
445                         case MOD_GROUP:
446                         case MOD_POLICY: /* same as MOD_GROUP */
447                                 stack.children[stack.pointer] = g->children;
448                                 break;
449
450                                 /*
451                                  *      See the "camel book" for why
452                                  *      this works.
453                                  *
454                                  *      If (rand(0..n) < 1), pick the
455                                  *      current realm.  We add a scale
456                                  *      factor of 65536, to avoid
457                                  *      floating point.
458                                  */
459                         case MOD_LOAD_BALANCE:
460                         case MOD_REDUNDANT_LOAD_BALANCE:
461                                 q = NULL;
462                                 for(p = g->children; p; p = p->next) {
463                                         if (!q) {
464                                                 q = p;
465                                                 count = 1;
466                                                 continue;
467                                         }
468
469                                         count++;
470
471                                         if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
472                                                 q = p;
473                                         }
474                                 }
475                                 stack.children[stack.pointer] = q;
476                                 break;
477
478                         case MOD_SWITCH:
479                                 radius_xlat(buffer, sizeof(buffer),
480                                             child->name, request, NULL);
481
482                                 null_case = q = NULL;
483                                 for(p = g->children; p; p = p->next) {
484                                         if (!p->name) {
485                                                 if (!null_case) null_case = p;
486                                                 continue;
487                                         }
488                                         if (strcmp(buffer, p->name) == 0) {
489                                                 q = p;
490                                                 break;
491                                         }
492                                 }
493
494                                 if (!q) q = null_case;
495
496                                 stack.children[stack.pointer] = q;
497                                 break;
498
499                         default:
500                                 DEBUG2("Internal sanity check failed in modcall %d", child->type);
501                                 exit(1); /* internal sanity check failure */
502                                 break;
503                         }
504
505
506                         stack.start[stack.pointer] = stack.children[stack.pointer];
507
508                         DEBUG2("%.*s- entering %s %s",
509                                stack.pointer, modcall_spaces,
510                                group_name[child->type],
511                                child->name ? child->name : "");
512
513                         /*
514                          *      Catch the special case of a NULL group.
515                          */
516                         if (!stack.children[stack.pointer]) {
517                                 /*
518                                  *      Print message for NULL group
519                                  */
520                                 DEBUG2("%.*s- %s %s returns %s",
521                                        stack.pointer + 1, modcall_spaces,
522                                        group_name[child->type],
523                                        child->name ? child->name : "",
524                                        fr_int2str(rcode_table,
525                                                     stack.result[stack.pointer],
526                                                     "??"));
527                                 goto do_return;
528                         }
529
530                         /*
531                          *      The child may be a group, so we want to
532                          *      recurse into it's children, rather than
533                          *      falling through to the code below.
534                          */
535                         continue;
536                 }
537
538                 /*
539                  *      Process a stand-alone child, and fall through
540                  *      to dealing with it's parent.
541                  */
542                 sp = mod_callabletosingle(child);
543
544                 myresult = call_modsingle(child->method, sp, request,
545                                           default_component_results[component]);
546         handle_result:
547                 DEBUG2("%.*s[%s] returns %s",
548                        stack.pointer + 1, modcall_spaces,
549                        child->name ? child->name : "",
550                        fr_int2str(rcode_table, myresult, "??"));
551
552
553                 /*
554                  *      FIXME: Allow modules to push a modcallable
555                  *      onto this stack.  This should simplify
556                  *      configuration a LOT!
557                  *
558                  *      Once we do that, we can't do load-time
559                  *      checking of the maximum stack depth, and we've
560                  *      got to cache the stack pointer before storing
561                  *      myresult.
562                  *
563                  *      Also, if the stack changed, we need to set
564                  *      children[ptr] to NULL, and process the next
565                  *      entry on the stack, rather than falling
566                  *      through to finalize the processing of this
567                  *      entry.
568                  *
569                  *      Don't put "myresult" on the stack here,
570                  *      we have to do so with priority.
571                  */
572
573                 /*
574                  *      We roll back up the stack at this point.
575                  */
576         unroll:
577                 /*
578                  *      The child's action says return.  Do so.
579                  */
580                 if (child->actions[myresult] == MOD_ACTION_RETURN) {
581                         stack.result[stack.pointer] = myresult;
582                         stack.children[stack.pointer] = NULL;
583                         goto do_return;
584                 }
585
586                 /*
587                  *      If "reject", break out of the loop and return
588                  *      reject.
589                  */
590                 if (child->actions[myresult] == MOD_ACTION_REJECT) {
591                         stack.children[stack.pointer] = NULL;
592                         stack.result[stack.pointer] = RLM_MODULE_REJECT;
593                         goto do_return;
594                 }
595
596                 /*
597                  *      Otherwise, the action is a number, the
598                  *      preference level of this return code. If no
599                  *      higher preference has been seen yet, remember
600                  *      this one.
601                  */
602                 if (child->actions[myresult] >= stack.priority[stack.pointer]) {
603                         stack.result[stack.pointer] = myresult;
604                         stack.priority[stack.pointer] = child->actions[myresult];
605                 }
606
607
608         next_section:
609                 /*
610                  *      No parent, we must be done.
611                  */
612                 if (!parent) {
613                         rad_assert(stack.pointer == 0);
614                         myresult = stack.result[0];
615                         break;
616                 }
617
618                 rad_assert(child != NULL);
619
620                 /*
621                  *      Go to the "next" child, whatever that is.
622                  */
623                 switch (parent->type) {
624                         case MOD_IF:
625                         case MOD_ELSE:
626                         case MOD_ELSIF:
627                         case MOD_CASE:
628                         case MOD_GROUP:
629                         case MOD_POLICY: /* same as MOD_GROUP */
630                                 stack.children[stack.pointer] = child->next;
631                                 break;
632
633                         case MOD_SWITCH:
634                         case MOD_LOAD_BALANCE:
635                                 stack.children[stack.pointer] = NULL;
636                                 break;
637
638                         case MOD_REDUNDANT_LOAD_BALANCE:
639                                 if (child->next) {
640                                         stack.children[stack.pointer] = child->next;
641                                 } else {
642                                         modgroup *g = mod_callabletogroup(parent);
643
644                                         stack.children[stack.pointer] = g->children;
645                                 }
646                                 if (stack.children[stack.pointer] == stack.start[stack.pointer]) {
647                                         stack.children[stack.pointer] = NULL;
648                                 }
649                                 break;
650                         default:
651                                 DEBUG2("Internal sanity check failed in modcall  next %d", child->type);
652                                 exit(1);
653                 }
654
655                 /*
656                  *      No child, we're done this group, and we return
657                  *      "myresult" to the caller by pushing it back up
658                  *      the stack.
659                  */
660                 if (!stack.children[stack.pointer]) {
661                 do_return:
662                         rad_assert(stack.pointer > 0);
663                         myresult = stack.result[stack.pointer];
664                         stack.pointer--;
665
666                         if (stack.pointer == 0) break;
667
668                         DEBUG2("%.*s- %s %s returns %s",
669                                stack.pointer + 1, modcall_spaces,
670                                group_name[parent->type],
671                                parent->name ? parent->name : "",
672                                fr_int2str(rcode_table, myresult, "??"));
673
674                         if ((parent->type == MOD_IF) ||
675                             (parent->type == MOD_ELSIF)) {
676                                 if_taken = was_if = TRUE;
677                         } else {
678                                 if_taken = was_if = FALSE;
679                         }
680
681                         /*
682                          *      Unroll the stack.
683                          */
684                         child = stack.children[stack.pointer];
685                         parent = child->parent;
686                         goto unroll;
687                 }
688
689         } /* loop until done */
690
691         return myresult;
692 }
693
694
695 #if 0
696 static const char *action2str(int action)
697 {
698         static char buf[32];
699         if(action==MOD_ACTION_RETURN)
700                 return "return";
701         if(action==MOD_ACTION_REJECT)
702                 return "reject";
703         snprintf(buf, sizeof buf, "%d", action);
704         return buf;
705 }
706
707 /* If you suspect a bug in the parser, you'll want to use these dump
708  * functions. dump_tree should reproduce a whole tree exactly as it was found
709  * in radiusd.conf, but in long form (all actions explicitly defined) */
710 static void dump_mc(modcallable *c, int indent)
711 {
712         int i;
713
714         if(c->type==MOD_SINGLE) {
715                 modsingle *single = mod_callabletosingle(c);
716                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
717                         single->modinst->name);
718         } else {
719                 modgroup *g = mod_callabletogroup(c);
720                 modcallable *p;
721                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
722                       group_name[c->type]);
723                 for(p = g->children;p;p = p->next)
724                         dump_mc(p, indent+1);
725         }
726
727         for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
728                 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
729                       fr_int2str(rcode_table, i, "??"),
730                       action2str(c->actions[i]));
731         }
732
733         DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
734 }
735
736 static void dump_tree(int comp, modcallable *c)
737 {
738         DEBUG("[%s]", comp2str[comp]);
739         dump_mc(c, 0);
740 }
741 #else
742 #define dump_tree(a, b)
743 #endif
744
745 /* These are the default actions. For each component, the group{} block
746  * behaves like the code from the old module_*() function. redundant{} and
747  * append{} are based on my guesses of what they will be used for. --Pac. */
748 static const int
749 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
750 {
751         /* authenticate */
752         {
753                 /* group */
754                 {
755                         MOD_ACTION_RETURN,      /* reject   */
756                         1,                      /* fail     */
757                         MOD_ACTION_RETURN,      /* ok       */
758                         MOD_ACTION_RETURN,      /* handled  */
759                         1,                      /* invalid  */
760                         MOD_ACTION_RETURN,      /* userlock */
761                         MOD_ACTION_RETURN,      /* notfound */
762                         1,                      /* noop     */
763                         1                       /* updated  */
764                 },
765                 /* redundant */
766                 {
767                         MOD_ACTION_RETURN,      /* reject   */
768                         1,                      /* fail     */
769                         MOD_ACTION_RETURN,      /* ok       */
770                         MOD_ACTION_RETURN,      /* handled  */
771                         MOD_ACTION_RETURN,      /* invalid  */
772                         MOD_ACTION_RETURN,      /* userlock */
773                         MOD_ACTION_RETURN,      /* notfound */
774                         MOD_ACTION_RETURN,      /* noop     */
775                         MOD_ACTION_RETURN       /* updated  */
776                 },
777                 /* append */
778                 {
779                         MOD_ACTION_RETURN,      /* reject   */
780                         1,                      /* fail     */
781                         MOD_ACTION_RETURN,      /* ok       */
782                         MOD_ACTION_RETURN,      /* handled  */
783                         MOD_ACTION_RETURN,      /* invalid  */
784                         MOD_ACTION_RETURN,      /* userlock */
785                         2,                      /* notfound */
786                         MOD_ACTION_RETURN,      /* noop     */
787                         MOD_ACTION_RETURN       /* updated  */
788                 }
789         },
790         /* authorize */
791         {
792                 /* group */
793                 {
794                         MOD_ACTION_RETURN,      /* reject   */
795                         MOD_ACTION_RETURN,      /* fail     */
796                         3,                      /* ok       */
797                         MOD_ACTION_RETURN,      /* handled  */
798                         MOD_ACTION_RETURN,      /* invalid  */
799                         MOD_ACTION_RETURN,      /* userlock */
800                         1,                      /* notfound */
801                         2,                      /* noop     */
802                         4                       /* updated  */
803                 },
804                 /* redundant */
805                 {
806                         MOD_ACTION_RETURN,      /* reject   */
807                         1,                      /* fail     */
808                         MOD_ACTION_RETURN,      /* ok       */
809                         MOD_ACTION_RETURN,      /* handled  */
810                         MOD_ACTION_RETURN,      /* invalid  */
811                         MOD_ACTION_RETURN,      /* userlock */
812                         MOD_ACTION_RETURN,      /* notfound */
813                         MOD_ACTION_RETURN,      /* noop     */
814                         MOD_ACTION_RETURN       /* updated  */
815                 },
816                 /* append */
817                 {
818                         MOD_ACTION_RETURN,      /* reject   */
819                         1,                      /* fail     */
820                         MOD_ACTION_RETURN,      /* ok       */
821                         MOD_ACTION_RETURN,      /* handled  */
822                         MOD_ACTION_RETURN,      /* invalid  */
823                         MOD_ACTION_RETURN,      /* userlock */
824                         2,                      /* notfound */
825                         MOD_ACTION_RETURN,      /* noop     */
826                         MOD_ACTION_RETURN       /* updated  */
827                 }
828         },
829         /* preacct */
830         {
831                 /* group */
832                 {
833                         MOD_ACTION_RETURN,      /* reject   */
834                         MOD_ACTION_RETURN,      /* fail     */
835                         2,                      /* ok       */
836                         MOD_ACTION_RETURN,      /* handled  */
837                         MOD_ACTION_RETURN,      /* invalid  */
838                         MOD_ACTION_RETURN,      /* userlock */
839                         MOD_ACTION_RETURN,      /* notfound */
840                         1,                      /* noop     */
841                         3                       /* updated  */
842                 },
843                 /* redundant */
844                 {
845                         MOD_ACTION_RETURN,      /* reject   */
846                         1,                      /* fail     */
847                         MOD_ACTION_RETURN,      /* ok       */
848                         MOD_ACTION_RETURN,      /* handled  */
849                         MOD_ACTION_RETURN,      /* invalid  */
850                         MOD_ACTION_RETURN,      /* userlock */
851                         MOD_ACTION_RETURN,      /* notfound */
852                         MOD_ACTION_RETURN,      /* noop     */
853                         MOD_ACTION_RETURN       /* updated  */
854                 },
855                 /* append */
856                 {
857                         MOD_ACTION_RETURN,      /* reject   */
858                         1,                      /* fail     */
859                         MOD_ACTION_RETURN,      /* ok       */
860                         MOD_ACTION_RETURN,      /* handled  */
861                         MOD_ACTION_RETURN,      /* invalid  */
862                         MOD_ACTION_RETURN,      /* userlock */
863                         2,                      /* notfound */
864                         MOD_ACTION_RETURN,      /* noop     */
865                         MOD_ACTION_RETURN       /* updated  */
866                 }
867         },
868         /* accounting */
869         {
870                 /* group */
871                 {
872                         MOD_ACTION_RETURN,      /* reject   */
873                         MOD_ACTION_RETURN,      /* fail     */
874                         2,                      /* ok       */
875                         MOD_ACTION_RETURN,      /* handled  */
876                         MOD_ACTION_RETURN,      /* invalid  */
877                         MOD_ACTION_RETURN,      /* userlock */
878                         MOD_ACTION_RETURN,      /* notfound */
879                         1,                      /* noop     */
880                         3                       /* updated  */
881                 },
882                 /* redundant */
883                 {
884                         1,                      /* reject   */
885                         1,                      /* fail     */
886                         MOD_ACTION_RETURN,      /* ok       */
887                         MOD_ACTION_RETURN,      /* handled  */
888                         1,                      /* invalid  */
889                         1,                      /* userlock */
890                         1,                      /* notfound */
891                         2,                      /* noop     */
892                         4                       /* updated  */
893                 },
894                 /* append */
895                 {
896                         MOD_ACTION_RETURN,      /* reject   */
897                         1,                      /* fail     */
898                         MOD_ACTION_RETURN,      /* ok       */
899                         MOD_ACTION_RETURN,      /* handled  */
900                         MOD_ACTION_RETURN,      /* invalid  */
901                         MOD_ACTION_RETURN,      /* userlock */
902                         2,                      /* notfound */
903                         MOD_ACTION_RETURN,      /* noop     */
904                         MOD_ACTION_RETURN       /* updated  */
905                 }
906         },
907         /* checksimul */
908         {
909                 /* group */
910                 {
911                         MOD_ACTION_RETURN,      /* reject   */
912                         1,                      /* fail     */
913                         MOD_ACTION_RETURN,      /* ok       */
914                         MOD_ACTION_RETURN,      /* handled  */
915                         MOD_ACTION_RETURN,      /* invalid  */
916                         MOD_ACTION_RETURN,      /* userlock */
917                         MOD_ACTION_RETURN,      /* notfound */
918                         MOD_ACTION_RETURN,      /* noop     */
919                         MOD_ACTION_RETURN       /* updated  */
920                 },
921                 /* redundant */
922                 {
923                         MOD_ACTION_RETURN,      /* reject   */
924                         1,                      /* fail     */
925                         MOD_ACTION_RETURN,      /* ok       */
926                         MOD_ACTION_RETURN,      /* handled  */
927                         MOD_ACTION_RETURN,      /* invalid  */
928                         MOD_ACTION_RETURN,      /* userlock */
929                         MOD_ACTION_RETURN,      /* notfound */
930                         MOD_ACTION_RETURN,      /* noop     */
931                         MOD_ACTION_RETURN       /* updated  */
932                 },
933                 /* append */
934                 {
935                         MOD_ACTION_RETURN,      /* reject   */
936                         1,                      /* fail     */
937                         MOD_ACTION_RETURN,      /* ok       */
938                         MOD_ACTION_RETURN,      /* handled  */
939                         MOD_ACTION_RETURN,      /* invalid  */
940                         MOD_ACTION_RETURN,      /* userlock */
941                         MOD_ACTION_RETURN,      /* notfound */
942                         MOD_ACTION_RETURN,      /* noop     */
943                         MOD_ACTION_RETURN       /* updated  */
944                 }
945         },
946         /* pre-proxy */
947         {
948                 /* group */
949                 {
950                         MOD_ACTION_RETURN,      /* reject   */
951                         MOD_ACTION_RETURN,      /* fail     */
952                         3,                      /* ok       */
953                         MOD_ACTION_RETURN,      /* handled  */
954                         MOD_ACTION_RETURN,      /* invalid  */
955                         MOD_ACTION_RETURN,      /* userlock */
956                         1,                      /* notfound */
957                         2,                      /* noop     */
958                         4                       /* updated  */
959                 },
960                 /* redundant */
961                 {
962                         MOD_ACTION_RETURN,      /* reject   */
963                         1,                      /* fail     */
964                         MOD_ACTION_RETURN,      /* ok       */
965                         MOD_ACTION_RETURN,      /* handled  */
966                         MOD_ACTION_RETURN,      /* invalid  */
967                         MOD_ACTION_RETURN,      /* userlock */
968                         MOD_ACTION_RETURN,      /* notfound */
969                         MOD_ACTION_RETURN,      /* noop     */
970                         MOD_ACTION_RETURN       /* updated  */
971                 },
972                 /* append */
973                 {
974                         MOD_ACTION_RETURN,      /* reject   */
975                         1,                      /* fail     */
976                         MOD_ACTION_RETURN,      /* ok       */
977                         MOD_ACTION_RETURN,      /* handled  */
978                         MOD_ACTION_RETURN,      /* invalid  */
979                         MOD_ACTION_RETURN,      /* userlock */
980                         2,                      /* notfound */
981                         MOD_ACTION_RETURN,      /* noop     */
982                         MOD_ACTION_RETURN       /* updated  */
983                 }
984         },
985         /* post-proxy */
986         {
987                 /* group */
988                 {
989                         MOD_ACTION_RETURN,      /* reject   */
990                         MOD_ACTION_RETURN,      /* fail     */
991                         3,                      /* ok       */
992                         MOD_ACTION_RETURN,      /* handled  */
993                         MOD_ACTION_RETURN,      /* invalid  */
994                         MOD_ACTION_RETURN,      /* userlock */
995                         1,                      /* notfound */
996                         2,                      /* noop     */
997                         4                       /* updated  */
998                 },
999                 /* redundant */
1000                 {
1001                         MOD_ACTION_RETURN,      /* reject   */
1002                         1,                      /* fail     */
1003                         MOD_ACTION_RETURN,      /* ok       */
1004                         MOD_ACTION_RETURN,      /* handled  */
1005                         MOD_ACTION_RETURN,      /* invalid  */
1006                         MOD_ACTION_RETURN,      /* userlock */
1007                         MOD_ACTION_RETURN,      /* notfound */
1008                         MOD_ACTION_RETURN,      /* noop     */
1009                         MOD_ACTION_RETURN       /* updated  */
1010                 },
1011                 /* append */
1012                 {
1013                         MOD_ACTION_RETURN,      /* reject   */
1014                         1,                      /* fail     */
1015                         MOD_ACTION_RETURN,      /* ok       */
1016                         MOD_ACTION_RETURN,      /* handled  */
1017                         MOD_ACTION_RETURN,      /* invalid  */
1018                         MOD_ACTION_RETURN,      /* userlock */
1019                         2,                      /* notfound */
1020                         MOD_ACTION_RETURN,      /* noop     */
1021                         MOD_ACTION_RETURN       /* updated  */
1022                 }
1023         },
1024         /* post-auth */
1025         {
1026                 /* group */
1027                 {
1028                         MOD_ACTION_RETURN,      /* reject   */
1029                         MOD_ACTION_RETURN,      /* fail     */
1030                         3,                      /* ok       */
1031                         MOD_ACTION_RETURN,      /* handled  */
1032                         MOD_ACTION_RETURN,      /* invalid  */
1033                         MOD_ACTION_RETURN,      /* userlock */
1034                         1,                      /* notfound */
1035                         2,                      /* noop     */
1036                         4                       /* updated  */
1037                 },
1038                 /* redundant */
1039                 {
1040                         MOD_ACTION_RETURN,      /* reject   */
1041                         1,                      /* fail     */
1042                         MOD_ACTION_RETURN,      /* ok       */
1043                         MOD_ACTION_RETURN,      /* handled  */
1044                         MOD_ACTION_RETURN,      /* invalid  */
1045                         MOD_ACTION_RETURN,      /* userlock */
1046                         MOD_ACTION_RETURN,      /* notfound */
1047                         MOD_ACTION_RETURN,      /* noop     */
1048                         MOD_ACTION_RETURN       /* updated  */
1049                 },
1050                 /* append */
1051                 {
1052                         MOD_ACTION_RETURN,      /* reject   */
1053                         1,                      /* fail     */
1054                         MOD_ACTION_RETURN,      /* ok       */
1055                         MOD_ACTION_RETURN,      /* handled  */
1056                         MOD_ACTION_RETURN,      /* invalid  */
1057                         MOD_ACTION_RETURN,      /* userlock */
1058                         2,                      /* notfound */
1059                         MOD_ACTION_RETURN,      /* noop     */
1060                         MOD_ACTION_RETURN       /* updated  */
1061                 }
1062         }
1063 };
1064
1065
1066 static modcallable *do_compile_modupdate(modcallable *parent,
1067                                          int component, CONF_SECTION *cs,
1068                                          const char *name2)
1069 {
1070         int i, ok = FALSE;
1071         modgroup *g;
1072         modcallable *csingle;
1073         CONF_ITEM *ci;
1074         VALUE_PAIR *head, **tail;
1075
1076         static const char *attrlist_names[] = {
1077                 "request", "reply", "proxy-request", "proxy-reply",
1078                 "config", "control",
1079                 "outer.request", "outer.reply",
1080                 "outer.config", "outer.control",
1081                 NULL
1082         };
1083
1084         component = component;  /* -Wunused */
1085
1086         if (!cf_section_name2(cs)) {
1087                 cf_log_err(cf_sectiontoitem(cs),
1088                            "Require list name for 'update'.\n");
1089                 return NULL;
1090         }
1091
1092         for (i = 0; attrlist_names[i] != NULL; i++) {
1093                 if (strcmp(name2, attrlist_names[i]) == 0) {
1094                         ok = TRUE;
1095                         break;
1096                 }
1097         }
1098
1099         if (!ok) {
1100                 cf_log_err(cf_sectiontoitem(cs),
1101                            "Unknown attribute list \"%s\"",
1102                            name2);
1103                 return NULL;
1104         }
1105
1106         head = NULL;
1107         tail = &head;
1108
1109         /*
1110          *      Walk through the children of the update section,
1111          *      ensuring that they're all known attributes.
1112          */
1113         for (ci=cf_item_find_next(cs, NULL);
1114              ci != NULL;
1115              ci=cf_item_find_next(cs, ci)) {
1116                 CONF_PAIR *cp;
1117                 VALUE_PAIR *vp;
1118
1119                 if (cf_item_is_section(ci)) {
1120                         cf_log_err(ci, "\"update\" sections cannot have subsections");
1121                         return NULL;
1122                 }
1123
1124                 if (!cf_item_is_pair(ci)) continue;
1125
1126                 cp = cf_itemtopair(ci); /* can't return NULL */
1127                 vp = cf_pairtovp(cp);
1128                 if (!vp) {
1129                         pairfree(&head);
1130                         cf_log_err(ci, "ERROR: %s", librad_errstr);
1131                         return NULL;
1132                 }
1133
1134                 if ((vp->operator != T_OP_EQ) &&
1135                     (vp->operator != T_OP_CMP_EQ) &&
1136                     (vp->operator != T_OP_ADD) &&
1137                     (vp->operator != T_OP_SUB) &&
1138                     (vp->operator != T_OP_LE) &&
1139                     (vp->operator != T_OP_GE) &&
1140                     (vp->operator != T_OP_SET)) {
1141                         pairfree(&head);
1142                         pairfree(&vp);
1143                         cf_log_err(ci, "Invalid operator for attribute");
1144                         return NULL;
1145                 }
1146
1147                 /*
1148                  *      A few more sanity checks.  The enforcement of
1149                  *      <= or >= can only happen for integer
1150                  *      attributes.
1151                  */
1152                 if ((vp->operator == T_OP_LE) ||
1153                     (vp->operator == T_OP_GE)) {
1154                         if ((vp->type != PW_TYPE_BYTE) &&
1155                             (vp->type != PW_TYPE_SHORT) &&
1156                             (vp->type != PW_TYPE_INTEGER)) {
1157                                 pairfree(&head);
1158                                 pairfree(&vp);
1159                                 cf_log_err(ci, "Enforcment of <= or >= is possible only for integer attributes");
1160                                 return NULL;
1161                         }
1162                 }
1163
1164                 *tail = vp;
1165                 tail = &(vp->next);
1166         }
1167
1168         if (!head) {
1169                 cf_log_err(cf_sectiontoitem(cs),
1170                            "ERROR: update %s section cannot be empty",
1171                            name2);
1172                 return NULL;
1173         }
1174
1175         g = rad_malloc(sizeof(*g)); /* never fails */
1176         memset(g, 0, sizeof(*g));
1177         csingle = mod_grouptocallable(g);
1178         
1179         csingle->parent = parent;
1180         csingle->next = NULL;
1181         csingle->name = name2;
1182         csingle->type = MOD_UPDATE;
1183         csingle->method = component;
1184         
1185         g->grouptype = GROUPTYPE_SIMPLE;
1186         g->children = NULL;
1187         g->cs = cs;
1188         g->vps = head;
1189
1190         return csingle;
1191 }
1192
1193
1194 static modcallable *do_compile_modswitch(modcallable *parent,
1195         int component, CONF_SECTION *cs)
1196 {
1197         modcallable *csingle;
1198         CONF_ITEM *ci;
1199         int had_seen_default = FALSE;
1200
1201         component = component;  /* -Wunused */
1202
1203         if (!cf_section_name2(cs)) {
1204                 cf_log_err(cf_sectiontoitem(cs),
1205                            "You must specify a variable to switch over for 'switch'.");
1206                 return NULL;
1207         }
1208
1209         if (!cf_item_find_next(cs, NULL)) {
1210                 cf_log_err(cf_sectiontoitem(cs), "'switch' statments cannot be empty.");
1211                 return NULL;
1212         }
1213
1214         /*
1215          *      Walk through the children of the switch section,
1216          *      ensuring that they're all 'case' statements
1217          */
1218         for (ci=cf_item_find_next(cs, NULL);
1219              ci != NULL;
1220              ci=cf_item_find_next(cs, ci)) {
1221                 CONF_SECTION *subcs;
1222                 const char *name1, *name2;
1223
1224                 if (!cf_item_is_section(ci)) {
1225                         if (!cf_item_is_pair(ci)) continue;
1226
1227                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1228                         return NULL;
1229                 }
1230
1231                 subcs = cf_itemtosection(ci);   /* can't return NULL */
1232                 name1 = cf_section_name1(subcs);
1233
1234                 if (strcmp(name1, "case") != 0) {
1235                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1236                         return NULL;
1237                 }
1238
1239                 name2 = cf_section_name2(subcs);
1240                 if (!name2 && !had_seen_default) {
1241                         had_seen_default = TRUE;
1242                         continue;
1243                 }
1244
1245                 if (!name2 || (name2[0] == '\0')) {
1246                         cf_log_err(ci, "\"case\" sections must have a name");
1247                         return NULL;
1248                 }
1249         }
1250
1251         csingle= do_compile_modgroup(parent, component, cs,
1252                                      GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1253         if (!csingle) return NULL;
1254         csingle->type = MOD_SWITCH;
1255         return csingle;
1256 }
1257
1258 /*
1259  *      redundant, etc. can refer to modules or groups, but not much else.
1260  */
1261 static int all_children_are_modules(CONF_SECTION *cs, const char *name)
1262 {
1263         CONF_ITEM *ci;
1264
1265         for (ci=cf_item_find_next(cs, NULL);
1266              ci != NULL;
1267              ci=cf_item_find_next(cs, ci)) {
1268                 /*
1269                  *      If we're a redundant, etc. group, then the
1270                  *      intention is to call modules, rather than
1271                  *      processing logic.  These checks aren't
1272                  *      *strictly* necessary, but they keep the users
1273                  *      from doing crazy things.
1274                  */
1275                 if (cf_item_is_section(ci)) {
1276                         CONF_SECTION *subcs = cf_itemtosection(ci);
1277                         const char *name1 = cf_section_name1(subcs);
1278
1279                         if ((strcmp(name1, "if") == 0) ||
1280                             (strcmp(name1, "else") == 0) ||
1281                             (strcmp(name1, "elsif") == 0) ||
1282                             (strcmp(name1, "update") == 0) ||
1283                             (strcmp(name1, "switch") == 0) ||
1284                             (strcmp(name1, "case") == 0)) {
1285                                 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1286                                        name, name1);
1287                                 return 0;
1288                         }
1289                         continue;
1290                 }
1291
1292                 if (cf_item_is_pair(ci)) {
1293                         CONF_PAIR *cp = cf_itemtopair(ci);
1294                         if (cf_pair_value(cp) != NULL) {
1295                                 cf_log_err(ci, "Invalid entry in %s section");
1296                                 return 0;
1297                         }
1298                 }
1299         }
1300
1301         return 1;
1302 }
1303
1304
1305 /*
1306  *      Compile one entry of a module call.
1307  */
1308 static modcallable *do_compile_modsingle(modcallable *parent,
1309                                          int component, CONF_ITEM *ci,
1310                                          int grouptype,
1311                                          const char **modname)
1312 {
1313         int result;
1314         const char *modrefname;
1315         modsingle *single;
1316         modcallable *csingle;
1317         module_instance_t *this;
1318         CONF_SECTION *cs, *subcs, *modules;
1319
1320         if (cf_item_is_section(ci)) {
1321                 const char *name2;
1322
1323                 cs = cf_itemtosection(ci);
1324                 modrefname = cf_section_name1(cs);
1325                 name2 = cf_section_name2(cs);
1326                 if (!name2) name2 = "_UnNamedGroup";
1327
1328                 /*
1329                  *      group{}, redundant{}, or append{} may appear
1330                  *      where a single module instance was expected.
1331                  *      In that case, we hand it off to
1332                  *      compile_modgroup
1333                  */
1334                 if (strcmp(modrefname, "group") == 0) {
1335                         *modname = name2;
1336                         return do_compile_modgroup(parent, component, cs,
1337                                                    GROUPTYPE_SIMPLE,
1338                                                    grouptype);
1339
1340                 } else if (strcmp(modrefname, "redundant") == 0) {
1341                         *modname = name2;
1342
1343                         if (!all_children_are_modules(cs, modrefname)) {
1344                                 return NULL;
1345                         }
1346
1347                         return do_compile_modgroup(parent, component, cs,
1348                                                    GROUPTYPE_REDUNDANT,
1349                                                    grouptype);
1350
1351                 } else if (strcmp(modrefname, "append") == 0) {
1352                         *modname = name2;
1353                         return do_compile_modgroup(parent, component, cs,
1354                                                    GROUPTYPE_APPEND,
1355                                                    grouptype);
1356
1357                 } else if (strcmp(modrefname, "load-balance") == 0) {
1358                         *modname = name2;
1359
1360                         if (!all_children_are_modules(cs, modrefname)) {
1361                                 return NULL;
1362                         }
1363
1364                         csingle= do_compile_modgroup(parent, component, cs,
1365                                                      GROUPTYPE_SIMPLE,
1366                                                      grouptype);
1367                         if (!csingle) return NULL;
1368                         csingle->type = MOD_LOAD_BALANCE;
1369                         return csingle;
1370
1371                 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1372                         *modname = name2;
1373
1374                         if (!all_children_are_modules(cs, modrefname)) {
1375                                 return NULL;
1376                         }
1377
1378                         csingle= do_compile_modgroup(parent, component, cs,
1379                                                      GROUPTYPE_REDUNDANT,
1380                                                      grouptype);
1381                         if (!csingle) return NULL;
1382                         csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1383                         return csingle;
1384
1385                 } else  if (strcmp(modrefname, "if") == 0) {
1386                         if (!cf_section_name2(cs)) {
1387                                 cf_log_err(ci, "'if' without condition.");
1388                                 return NULL;
1389                         }
1390
1391                         *modname = name2;
1392                         csingle= do_compile_modgroup(parent, component, cs,
1393                                                      GROUPTYPE_SIMPLE,
1394                                                      grouptype);
1395                         if (!csingle) return NULL;
1396                         csingle->type = MOD_IF;
1397
1398                         if (!radius_evaluate_condition(NULL, 0, 0, modname,
1399                                                        FALSE, &result)) {
1400                                 modcallable_free(&csingle);
1401                                 return NULL;
1402                         }
1403                         *modname = name2;
1404
1405                         return csingle;
1406
1407                 } else  if (strcmp(modrefname, "elsif") == 0) {
1408                         if (parent &&
1409                             ((parent->type == MOD_LOAD_BALANCE) ||
1410                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1411                                 cf_log_err(ci, "'elsif' cannot be used in this section section.");
1412                                 return NULL;
1413                         }
1414
1415                         if (!cf_section_name2(cs)) {
1416                                 cf_log_err(ci, "'elsif' without condition.");
1417                                 return NULL;
1418                         }
1419
1420                         *modname = name2;
1421                         csingle= do_compile_modgroup(parent, component, cs,
1422                                                      GROUPTYPE_SIMPLE,
1423                                                      grouptype);
1424                         if (!csingle) return NULL;
1425                         csingle->type = MOD_ELSIF;
1426
1427                         if (!radius_evaluate_condition(NULL, 0, 0, modname,
1428                                                        FALSE, &result)) {
1429                                 modcallable_free(&csingle);
1430                                 return NULL;
1431                         }
1432                         *modname = name2;
1433
1434                         return csingle;
1435
1436                 } else  if (strcmp(modrefname, "else") == 0) {
1437                         if (parent &&
1438                             ((parent->type == MOD_LOAD_BALANCE) ||
1439                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1440                                 cf_log_err(ci, "'else' cannot be used in this section section.");
1441                                 return NULL;
1442                         }
1443
1444                         if (cf_section_name2(cs)) {
1445                                 cf_log_err(ci, "Cannot have conditions on 'else'.");
1446                                 return NULL;
1447                         }
1448
1449                         *modname = name2;
1450                         csingle= do_compile_modgroup(parent, component, cs,
1451                                                      GROUPTYPE_SIMPLE,
1452                                                      grouptype);
1453                         if (!csingle) return NULL;
1454                         csingle->type = MOD_ELSE;
1455                         return csingle;
1456
1457                 } else  if (strcmp(modrefname, "update") == 0) {
1458                         *modname = name2;
1459
1460                         csingle = do_compile_modupdate(parent, component, cs,
1461                                                        name2);
1462                         if (!csingle) return NULL;
1463
1464                         return csingle;
1465
1466                 } else  if (strcmp(modrefname, "switch") == 0) {
1467                         *modname = name2;
1468
1469                         csingle = do_compile_modswitch(parent, component, cs);
1470                         if (!csingle) return NULL;
1471
1472                         return csingle;
1473
1474                 } else  if (strcmp(modrefname, "case") == 0) {
1475                         int i;
1476
1477                         *modname = name2;
1478
1479                         /*
1480                          *      FIXME: How to tell that the parent can only
1481                          *      be a "switch" statement?
1482                          */
1483                         if (!parent) {
1484                                 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1485                                 return NULL;
1486                         }
1487
1488                         csingle= do_compile_modgroup(parent, component, cs,
1489                                                      GROUPTYPE_SIMPLE,
1490                                                      grouptype);
1491                         if (!csingle) return NULL;
1492                         csingle->type = MOD_CASE;
1493                         csingle->name = cf_section_name2(cs); /* may be NULL */
1494
1495                         /*
1496                          *      Set all of it's codes to return, so that
1497                          *      when we pick a 'case' statement, we don't
1498                          *      fall through to processing the next one.
1499                          */
1500                         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1501                                 csingle->actions[i] = MOD_ACTION_RETURN;
1502                         }
1503
1504                         return csingle;
1505
1506                 } /* else it's something like sql { fail = 1 ...} */
1507
1508         } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
1509                 return NULL;
1510
1511                 /*
1512                  *      Else it's a module reference, with updated return
1513                  *      codes.
1514                  */
1515         } else {
1516                 CONF_PAIR *cp = cf_itemtopair(ci);
1517                 modrefname = cf_pair_attr(cp);
1518
1519                 /*
1520                  *      Actions (ok = 1), etc. are orthoganal to just
1521                  *      about everything else.
1522                  */
1523                 if (cf_pair_value(cp) != NULL) {
1524                         cf_log_err(ci, "Entry is not a reference to a module");
1525                         return NULL;
1526                 }
1527
1528                 /*
1529                  *      See if the module is a virtual one.  If so,
1530                  *      return that, rather than doing anything here.
1531                  */
1532                 subcs = NULL;
1533                 cs = cf_section_find("instantiate");
1534                 if (!subcs) {
1535                         cs = cf_section_find("policy");
1536                         if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
1537                                                                   modrefname);
1538                 }
1539                 if (subcs) {
1540                         DEBUG2(" Module: Loading virtual module %s",
1541                                modrefname);
1542
1543                         /*
1544                          *      redundant foo {} is a single.
1545                          */
1546                         if (cf_section_name2(subcs)) {
1547                                 return do_compile_modsingle(parent,
1548                                                             component,
1549                                                             cf_sectiontoitem(subcs),
1550                                                             grouptype,
1551                                                             modname);
1552                         } else {
1553                                 /*
1554                                  *      foo {} is a group.
1555                                  */
1556                                 return do_compile_modgroup(parent,
1557                                                            component,
1558                                                            subcs,
1559                                                            GROUPTYPE_SIMPLE,
1560                                                            grouptype);
1561                         }
1562                 }
1563         }
1564
1565         /*
1566          *      Not a virtual module.  It must be a real module.
1567          */
1568         modules = cf_section_find("modules");
1569         this = NULL;
1570
1571         if (modules && cf_section_sub_find_name2(modules, NULL, modrefname)) {
1572                 this = find_module_instance(modules, modrefname);
1573         }
1574
1575         if (!this) {
1576                 int i;
1577                 char *p;
1578
1579                 /*
1580                  *      Maybe it's module.method
1581                  */
1582                 p = strchr(modrefname, '.');
1583                 if (p) for (i = RLM_COMPONENT_AUTH;
1584                             i < RLM_COMPONENT_COUNT;
1585                             i++) {
1586                         if (strcmp(p + 1, comp2str[i]) == 0) {
1587                                 char buffer[256];
1588
1589                                 strlcpy(buffer, modrefname, sizeof(buffer));
1590                                 buffer[p - modrefname] = '\0';
1591                                 component = i;
1592                                 
1593                                 this = find_module_instance(cf_section_find("modules"), buffer);
1594                                 if (this &&
1595                                     !this->entry->module->methods[i]) {
1596                                         *modname = NULL;
1597                                         cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
1598                                         return NULL;
1599                                 }
1600                                 break;
1601                         }
1602                 }
1603
1604                 if (!this) {
1605                         *modname = NULL;
1606                         cf_log_err(ci, "Failed to find module \"%s\".", modrefname);
1607                         return NULL;
1608                 }
1609         }
1610
1611         /*
1612          *      We know it's all OK, allocate the structures, and fill
1613          *      them in.
1614          */
1615         single = rad_malloc(sizeof(*single));
1616         memset(single, 0, sizeof(*single));
1617         csingle = mod_singletocallable(single);
1618         csingle->parent = parent;
1619         csingle->next = NULL;
1620         memcpy(csingle->actions, defaultactions[component][grouptype],
1621                sizeof csingle->actions);
1622         rad_assert(modrefname != NULL);
1623         csingle->name = modrefname;
1624         csingle->type = MOD_SINGLE;
1625         csingle->method = component;
1626
1627         /*
1628          *      Singles can override the actions, virtual modules cannot.
1629          *
1630          *      FIXME: We may want to re-visit how to do this...
1631          *      maybe a csingle as a ref?
1632          */
1633         if (cf_item_is_section(ci)) {
1634                 cs = cf_itemtosection(ci);
1635
1636                 for (ci=cf_item_find_next(cs, NULL);
1637                      ci != NULL;
1638                      ci=cf_item_find_next(cs, ci)) {
1639
1640                         if (cf_item_is_section(ci)) {
1641                                 cf_log_err(ci, "Subsection of module instance call not allowed");
1642                                 modcallable_free(&csingle);
1643                                 return NULL;
1644                         }
1645
1646                         if (!cf_item_is_pair(ci)) continue;
1647
1648                         if (!compile_action(csingle, cf_itemtopair(ci))) {
1649                                 modcallable_free(&csingle);
1650                                 return NULL;
1651                         }
1652                 }
1653         }
1654
1655         /*
1656          *      Bail out if the module in question does not supply the
1657          *      wanted component
1658          */
1659         if (!this->entry->module->methods[component]) {
1660                 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
1661                        comp2str[component]);
1662                 modcallable_free(&csingle);
1663                 return NULL;
1664         }
1665
1666         single->modinst = this;
1667         *modname = this->entry->module->name;
1668         return csingle;
1669 }
1670
1671 modcallable *compile_modsingle(modcallable *parent,
1672                                int component, CONF_ITEM *ci,
1673                                const char **modname)
1674 {
1675         modcallable *ret = do_compile_modsingle(parent, component, ci,
1676                                                 GROUPTYPE_SIMPLE,
1677                                                 modname);
1678         dump_tree(component, ret);
1679         return ret;
1680 }
1681
1682
1683 /*
1684  *      Internal compile group code.
1685  */
1686 static modcallable *do_compile_modgroup(modcallable *parent,
1687                                         int component, CONF_SECTION *cs,
1688                                         int grouptype, int parentgrouptype)
1689 {
1690         int i;
1691         modgroup *g;
1692         modcallable *c;
1693         CONF_ITEM *ci;
1694
1695         g = rad_malloc(sizeof(*g));
1696         memset(g, 0, sizeof(*g));
1697         g->grouptype = grouptype;
1698
1699         c = mod_grouptocallable(g);
1700         c->parent = parent;
1701         c->type = MOD_GROUP;
1702         c->next = NULL;
1703         memset(c->actions, 0, sizeof(c->actions));
1704
1705         /*
1706          *      Remember the name for printing, etc.
1707          *
1708          *      FIXME: We may also want to put the names into a
1709          *      rbtree, so that groups can reference each other...
1710          */
1711         c->name = cf_section_name2(cs);
1712         if (!c->name) {
1713                 c->name = cf_section_name1(cs);
1714                 if (strcmp(c->name, "group") == 0) {
1715                         c->name = "";
1716                 } else {
1717                         c->type = MOD_POLICY;
1718                 }
1719         }
1720         g->children = NULL;
1721
1722         /*
1723          *      Loop over the children of this group.
1724          */
1725         for (ci=cf_item_find_next(cs, NULL);
1726              ci != NULL;
1727              ci=cf_item_find_next(cs, ci)) {
1728
1729                 /*
1730                  *      Sections are references to other groups, or
1731                  *      to modules with updated return codes.
1732                  */
1733                 if (cf_item_is_section(ci)) {
1734                         const char *junk = NULL;
1735                         modcallable *single;
1736                         CONF_SECTION *subcs = cf_itemtosection(ci);
1737
1738                         single = do_compile_modsingle(c, component, ci,
1739                                                       grouptype, &junk);
1740                         if (!single) {
1741                                 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
1742                                        cf_section_name1(subcs));
1743                                 modcallable_free(&c);
1744                                 return NULL;
1745                         }
1746                         add_child(g, single);
1747
1748                 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
1749                         continue;
1750
1751                 } else {
1752                         const char *attr, *value;
1753                         CONF_PAIR *cp = cf_itemtopair(ci);
1754
1755                         attr = cf_pair_attr(cp);
1756                         value = cf_pair_value(cp);
1757
1758                         /*
1759                          *      A CONF_PAIR is either a module
1760                          *      instance with no actions
1761                          *      specified ...
1762                          */
1763                         if (!value) {
1764                                 modcallable *single;
1765                                 const char *junk = NULL;
1766
1767                                 single = do_compile_modsingle(c,
1768                                                               component,
1769                                                               ci,
1770                                                               grouptype,
1771                                                               &junk);
1772                                 if (!single) {
1773                                         cf_log_err(ci,
1774                                                    "Failed to parse \"%s\" entry.",
1775                                                    attr);
1776                                         modcallable_free(&c);
1777                                         return NULL;
1778                                 }
1779                                 add_child(g, single);
1780
1781                                 /*
1782                                  *      Or a module instance with action.
1783                                  */
1784                         } else if (!compile_action(c, cp)) {
1785                                 modcallable_free(&c);
1786                                 return NULL;
1787                         } /* else it worked */
1788                 }
1789         }
1790
1791         /*
1792          *      Set the default actions, if they haven't already been
1793          *      set.
1794          */
1795         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1796                 if (!c->actions[i]) {
1797                         c->actions[i] = defaultactions[component][parentgrouptype][i];
1798                 }
1799         }
1800
1801         /*
1802          *      FIXME: If there are no children, return NULL?
1803          */
1804         return mod_grouptocallable(g);
1805 }
1806
1807 modcallable *compile_modgroup(modcallable *parent,
1808                               int component, CONF_SECTION *cs)
1809 {
1810         modcallable *ret = do_compile_modgroup(parent, component, cs,
1811                                                GROUPTYPE_SIMPLE,
1812                                                GROUPTYPE_SIMPLE);
1813         dump_tree(component, ret);
1814         return ret;
1815 }
1816
1817 void add_to_modcallable(modcallable **parent, modcallable *this,
1818                         int component, const char *name)
1819 {
1820         modgroup *g;
1821
1822         rad_assert(this != NULL);
1823
1824         if (*parent == NULL) {
1825                 modcallable *c;
1826
1827                 g = rad_malloc(sizeof *g);
1828                 memset(g, 0, sizeof(*g));
1829                 g->grouptype = GROUPTYPE_SIMPLE;
1830                 c = mod_grouptocallable(g);
1831                 c->next = NULL;
1832                 memcpy(c->actions,
1833                        defaultactions[component][GROUPTYPE_SIMPLE],
1834                        sizeof(c->actions));
1835                 rad_assert(name != NULL);
1836                 c->name = name;
1837                 c->type = MOD_GROUP;
1838                 c->method = component;
1839                 g->children = NULL;
1840
1841                 *parent = mod_grouptocallable(g);
1842         } else {
1843                 g = mod_callabletogroup(*parent);
1844         }
1845
1846         add_child(g, this);
1847 }
1848
1849 void modcallable_free(modcallable **pc)
1850 {
1851         modcallable *c, *loop, *next;
1852         c = *pc;
1853         if (c->type != MOD_SINGLE) {
1854                 modgroup *g = mod_callabletogroup(c);
1855
1856                 for(loop = g->children;
1857                     loop ;
1858                     loop = next) {
1859                         next = loop->next;
1860                         modcallable_free(&loop);
1861                 }
1862                 pairfree(&g->vps);
1863         }
1864         free(c);
1865         *pc = NULL;
1866 }