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