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