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