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