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