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