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