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