If the module was optional (-sql) it's real name is "sql"
[freeradius.git] / src / main / modcall.c
1 /*
2  * @name 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 RCSID("$Id$")
24
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/modpriv.h>
27 #include <freeradius-devel/modcall.h>
28 #include <freeradius-devel/parser.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                                         rlm_components_t, CONF_SECTION *,
35                                         int, int);
36
37 /* Actions may be a positive integer (the highest one returned in the group
38  * will be returned), or the keyword "return", represented here by
39  * MOD_ACTION_RETURN, to cause an immediate return.
40  * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
41  * to cause an immediate reject. */
42 #define MOD_ACTION_RETURN  (-1)
43 #define MOD_ACTION_REJECT  (-2)
44
45 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
46  * explanation of what they are all about, see doc/configurable_failover.rst */
47 struct modcallable {
48         modcallable *parent;
49         struct modcallable *next;
50         char const *name;
51         enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
52 #ifdef WITH_UNLANG
53                MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
54                MOD_FOREACH, MOD_BREAK,
55 #endif
56                MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
57         rlm_components_t method;
58         int actions[RLM_MODULE_NUMCODES];
59 };
60
61 #define MOD_LOG_OPEN_BRACE(_name) RDEBUG2("%.*s%s %s {", depth + 1, modcall_spaces, _name ? _name : "", c->name)
62 #define MOD_LOG_CLOSE_BRACE() RDEBUG2("%.*s} # %s %s = %s", depth + 1, modcall_spaces, \
63                                       cf_section_name1(g->cs) ? cf_section_name1(g->cs) : "", c->name ? c->name : "", \
64                                       fr_int2str(mod_rcode_table, result, "<invalid>"))
65
66 typedef struct {
67         modcallable             mc;             /* self */
68         enum {
69                 GROUPTYPE_SIMPLE = 0,
70                 GROUPTYPE_REDUNDANT,
71                 GROUPTYPE_APPEND,
72                 GROUPTYPE_COUNT
73         } grouptype;                            /* after mc */
74         modcallable             *children;
75         CONF_SECTION            *cs;
76         value_pair_map_t        *map;           /* update */
77         fr_cond_t               *cond;          /* if/elsif */
78 } modgroup;
79
80 typedef struct {
81         modcallable mc;
82         module_instance_t *modinst;
83 } modsingle;
84
85 typedef struct {
86         modcallable mc;
87         char const *ref_name;
88         CONF_SECTION *ref_cs;
89 } modref;
90
91 typedef struct {
92         modcallable mc;
93         int exec;
94         char *xlat_name;
95 } modxlat;
96
97 /*
98 static const FR_NAME_NUMBER grouptype_table[] = {
99         { "", GROUPTYPE_SIMPLE },
100         { "redundant ", GROUPTYPE_REDUNDANT },
101         { "append ", GROUPTYPE_APPEND },
102         { NULL, -1 }
103 };
104 */
105
106 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
107  * so we often want to go back and forth between them. */
108 static modsingle *mod_callabletosingle(modcallable *p)
109 {
110         rad_assert(p->type==MOD_SINGLE);
111         return (modsingle *)p;
112 }
113 static modgroup *mod_callabletogroup(modcallable *p)
114 {
115         rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
116
117         return (modgroup *)p;
118 }
119 static modcallable *mod_singletocallable(modsingle *p)
120 {
121         return (modcallable *)p;
122 }
123 static modcallable *mod_grouptocallable(modgroup *p)
124 {
125         return (modcallable *)p;
126 }
127
128 static modref *mod_callabletoref(modcallable *p)
129 {
130         rad_assert(p->type==MOD_REFERENCE);
131         return (modref *)p;
132 }
133 static modcallable *mod_reftocallable(modref *p)
134 {
135         return (modcallable *)p;
136 }
137
138 static modxlat *mod_callabletoxlat(modcallable *p)
139 {
140         rad_assert(p->type==MOD_XLAT);
141         return (modxlat *)p;
142 }
143 static modcallable *mod_xlattocallable(modxlat *p)
144 {
145         return (modcallable *)p;
146 }
147
148 /* modgroups are grown by adding a modcallable to the end */
149 /* FIXME: This is O(N^2) */
150 static void add_child(modgroup *g, modcallable *c)
151 {
152         modcallable **head = &g->children;
153         modcallable *node = *head;
154         modcallable **last = head;
155
156         if (!c) return;
157
158         while (node) {
159                 last = &node->next;
160                 node = node->next;
161         }
162
163         rad_assert(c->next == NULL);
164         *last = c;
165         c->parent = mod_grouptocallable(g);
166 }
167
168 /* Here's where we recognize all of our keywords: first the rcodes, then the
169  * actions */
170 const FR_NAME_NUMBER mod_rcode_table[] = {
171         { "reject",     RLM_MODULE_REJECT       },
172         { "fail",       RLM_MODULE_FAIL  },
173         { "ok",         RLM_MODULE_OK      },
174         { "handled",    RLM_MODULE_HANDLED      },
175         { "invalid",    RLM_MODULE_INVALID      },
176         { "userlock",   RLM_MODULE_USERLOCK     },
177         { "notfound",   RLM_MODULE_NOTFOUND     },
178         { "noop",       RLM_MODULE_NOOP  },
179         { "updated",    RLM_MODULE_UPDATED      },
180         { NULL, 0 }
181 };
182
183
184 /*
185  *      Compile action && rcode for later use.
186  */
187 static int compile_action(modcallable *c, CONF_PAIR *cp)
188 {
189         int action;
190         char const *attr, *value;
191
192         attr = cf_pair_attr(cp);
193         value = cf_pair_value(cp);
194         if (!value) return 0;
195
196         if (!strcasecmp(value, "return"))
197                 action = MOD_ACTION_RETURN;
198
199         else if (!strcasecmp(value, "break"))
200                 action = MOD_ACTION_RETURN;
201
202         else if (!strcasecmp(value, "reject"))
203                 action = MOD_ACTION_REJECT;
204
205         else if (strspn(value, "0123456789")==strlen(value)) {
206                 action = atoi(value);
207
208                 /*
209                  *      Don't allow priority zero, for future use.
210                  */
211                 if (action == 0) return 0;
212         } else {
213                 cf_log_err_cp(cp, "Unknown action '%s'.\n",
214                            value);
215                 return 0;
216         }
217
218         if (strcasecmp(attr, "default") != 0) {
219                 int rcode;
220
221                 rcode = fr_str2int(mod_rcode_table, attr, -1);
222                 if (rcode < 0) {
223                         cf_log_err_cp(cp,
224                                    "Unknown module rcode '%s'.\n",
225                                    attr);
226                         return 0;
227                 }
228                 c->actions[rcode] = action;
229
230         } else {                /* set all unset values to the default */
231                 int i;
232
233                 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
234                         if (!c->actions[i]) c->actions[i] = action;
235                 }
236         }
237
238         return 1;
239 }
240
241 /* Some short names for debugging output */
242 static char const * const comp2str[] = {
243         "authenticate",
244         "authorize",
245         "preacct",
246         "accounting",
247         "session",
248         "pre-proxy",
249         "post-proxy",
250         "post-auth"
251 #ifdef WITH_COA
252         ,
253         "recv-coa",
254         "send-coa"
255 #endif
256 };
257
258 #ifdef HAVE_PTHREAD_H
259 /*
260  *      Lock the mutex for the module
261  */
262 static void safe_lock(module_instance_t *instance)
263 {
264         if (instance->mutex)
265                 pthread_mutex_lock(instance->mutex);
266 }
267
268 /*
269  *      Unlock the mutex for the module
270  */
271 static void safe_unlock(module_instance_t *instance)
272 {
273         if (instance->mutex)
274                 pthread_mutex_unlock(instance->mutex);
275 }
276 #else
277 /*
278  *      No threads: these functions become NULL's.
279  */
280 #define safe_lock(foo)
281 #define safe_unlock(foo)
282 #endif
283
284 static rlm_rcode_t call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
285 {
286         rlm_rcode_t myresult;
287         int blocked;
288
289         rad_assert(request != NULL);
290
291         /*
292          *      If the request should stop, refuse to do anything.
293          */
294         blocked = (request->master_state == REQUEST_STOP_PROCESSING);
295         if (blocked) return RLM_MODULE_NOOP;
296
297         RDEBUG3("  modsingle[%s]: calling %s (%s) for request %d",
298                comp2str[component], sp->modinst->name,
299                sp->modinst->entry->name, request->number);
300
301         if (sp->modinst->force) {
302                 myresult = sp->modinst->code;
303                 goto fail;
304         }
305
306         safe_lock(sp->modinst);
307
308         /*
309          *      For logging unresponsive children.
310          */
311         request->module = sp->modinst->name;
312
313         myresult = sp->modinst->entry->module->methods[component](
314                         sp->modinst->insthandle, request);
315
316         request->module = "";
317         safe_unlock(sp->modinst);
318
319         /*
320          *      Wasn't blocked, and now is.  Complain!
321          */
322         blocked = (request->master_state == REQUEST_STOP_PROCESSING);
323         if (blocked) {
324                 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
325         }
326
327  fail:
328         RDEBUG3("  modsingle[%s]: returned from %s (%s) for request %d",
329                comp2str[component], sp->modinst->name,
330                sp->modinst->entry->name, request->number);
331
332         return myresult;
333 }
334
335 static int default_component_results[RLM_COMPONENT_COUNT] = {
336         RLM_MODULE_REJECT,      /* AUTH */
337         RLM_MODULE_NOTFOUND,    /* AUTZ */
338         RLM_MODULE_NOOP,        /* PREACCT */
339         RLM_MODULE_NOOP,        /* ACCT */
340         RLM_MODULE_FAIL,        /* SESS */
341         RLM_MODULE_NOOP,        /* PRE_PROXY */
342         RLM_MODULE_NOOP,        /* POST_PROXY */
343         RLM_MODULE_NOOP         /* POST_AUTH */
344 #ifdef WITH_COA
345         ,
346         RLM_MODULE_NOOP,        /* RECV_COA_TYPE */
347         RLM_MODULE_NOOP         /* SEND_COA_TYPE */
348 #endif
349 };
350
351
352 static char const *group_name[] = {
353         "",
354         "single",
355         "group",
356         "load-balance group",
357         "redundant-load-balance group",
358 #ifdef WITH_UNLANG
359         "if",
360         "else",
361         "elsif",
362         "update",
363         "switch",
364         "case",
365         "foreach",
366         "break",
367 #endif
368         "policy",
369         "reference",
370         "xlat"
371 };
372
373 static char const *modcall_spaces = "                                                                ";
374
375 #define MODCALL_STACK_MAX (32)
376
377 /*
378  *      Don't call the modules recursively.  Instead, do them
379  *      iteratively, and manage the call stack ourselves.
380  */
381 typedef struct modcall_stack_entry_t {
382         rlm_rcode_t result;
383         int priority;
384         int unwind;             /* unwind to this one if it exists */
385         modcallable *c;
386 } modcall_stack_entry_t;
387
388
389 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
390                             modcall_stack_entry_t *entry);
391
392 /*
393  *      Call a child of a block.
394  */
395 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
396                           modcall_stack_entry_t *entry, modcallable *c,
397                           rlm_rcode_t *result)
398 {
399         modcall_stack_entry_t *next;
400
401         if (depth >= MODCALL_STACK_MAX) {
402                 ERROR("Internal sanity check failed: module stack is too deep");
403                 fr_exit(1);
404         }
405
406         /*
407          *      Initialize the childs stack frame.
408          */
409         next = entry + 1;
410         next->c = c;
411         next->result = entry->result;
412         next->priority = 0;
413         next->unwind = 0;
414
415         if (!modcall_recurse(request, component,
416                              depth, next)) {
417                 *result = RLM_MODULE_FAIL;
418                  return;
419         }
420
421         /*
422          *      Unwind back up the stack
423          */
424         if (next->unwind != 0) {
425                 entry->unwind = next->unwind;
426         }
427
428         *result = next->result;
429
430         return;
431 }
432
433 /*
434  *      Interpret the various types of blocks.
435  */
436 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
437                             modcall_stack_entry_t *entry)
438 {
439         bool if_taken, was_if;
440         modcallable *c;
441         int priority;
442         rlm_rcode_t result;
443
444         was_if = if_taken = false;
445         result = RLM_MODULE_UNKNOWN;
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 #ifdef WITH_UNLANG
469         /*
470          *      Handle "if" conditions.
471          */
472         if (c->type == MOD_IF) {
473                 int condition;
474                 modgroup *g;
475
476         mod_if:
477                 g = mod_callabletogroup(c);
478                 rad_assert(g->cond != NULL);
479
480                 RDEBUG2("%.*s %s %s", depth + 1, modcall_spaces,
481                         group_name[c->type], c->name);
482
483                 condition = radius_evaluate_cond(request, result, 0, g->cond);
484                 if (condition < 0) {
485                         condition = false;
486                         REDEBUG("Failed retrieving values required to evaluate condition");
487                 } else {
488                         RDEBUG2("%.*s %s %s -> %s", depth + 1, modcall_spaces,
489                                 group_name[c->type],
490                                 c->name, condition ? "TRUE" : "FALSE");
491                 }
492
493                 /*
494                  *      Didn't pass.  Remember that.
495                  */
496                 if (!condition) {
497                         was_if = true;
498                         if_taken = false;
499                         goto next_sibling;
500                 }
501
502                 /*
503                  *      We took the "if".  Go recurse into its' children.
504                  */
505                 was_if = true;
506                 if_taken = true;
507                 goto do_children;
508         } /* MOD_IF */
509
510         /*
511          *      "else" if the previous "if" was taken.
512          *      "if" if the previous if wasn't taken.
513          */
514         if (c->type == MOD_ELSIF) {
515                 if (!was_if) goto elsif_error;
516
517                 /*
518                  *      Like MOD_ELSE, but allow for a later "else"
519                  */
520                 if (if_taken) {
521                         RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
522                                 depth + 1, modcall_spaces,
523                                 group_name[c->type], request->number);
524                         was_if = true;
525                         if_taken = true;
526                         goto next_sibling;
527                 }
528
529                 /*
530                  *      Check the "if" condition.
531                  */
532                 goto mod_if;
533         } /* MOD_ELSIF */
534
535         /*
536          *      "else" for a preceding "if".
537          */
538         if (c->type == MOD_ELSE) {
539                 if (!was_if) { /* error */
540                 elsif_error:
541                         RDEBUG2("%.*s ... skipping %s for request %d: No preceding \"if\"",
542                                 depth + 1, modcall_spaces,
543                                 group_name[c->type], request->number);
544                         goto next_sibling;
545                 }
546
547                 if (if_taken) {
548                         RDEBUG2("%.*s ... skipping %s for request %d: Preceding \"if\" was taken",
549                                 depth + 1, modcall_spaces,
550                                 group_name[c->type], request->number);
551                         was_if = false;
552                         if_taken = false;
553                         goto next_sibling;
554                 }
555
556                 /*
557                  *      We need to process it.  Go do that.
558                  */
559                 was_if = false;
560                 if_taken = false;
561                 goto do_children;
562         } /* MOD_ELSE */
563
564         /*
565          *      We're no longer processing if/else/elsif.  Reset the
566          *      trackers for those conditions.
567          */
568         was_if = false;
569         if_taken = false;
570 #endif  /* WITH_UNLANG */
571
572         if (c->type == MOD_SINGLE) {
573                 modsingle *sp;
574
575                 /*
576                  *      Process a stand-alone child, and fall through
577                  *      to dealing with it's parent.
578                  */
579                 sp = mod_callabletosingle(c);
580
581                 result = call_modsingle(c->method, sp, request);
582                 RDEBUG2("%.*s[%s] = %s", depth + 1, modcall_spaces, c->name ? c->name : "",
583                         fr_int2str(mod_rcode_table, result, "<invalid>"));
584                 goto calculate_result;
585         } /* MOD_SINGLE */
586
587 #ifdef WITH_UNLANG
588         /*
589          *      Update attribute(s)
590          */
591         if (c->type == MOD_UPDATE) {
592                 int rcode;
593                 modgroup *g = mod_callabletogroup(c);
594                 value_pair_map_t *map;
595
596
597                 MOD_LOG_OPEN_BRACE("update");
598                 for (map = g->map; map != NULL; map = map->next) {
599                         rcode = radius_map2request(request, map, "update", radius_map2vp, NULL);
600                         if (rcode < 0) {
601                                 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
602                                 MOD_LOG_CLOSE_BRACE();
603                                 goto calculate_result;
604                         }
605                 }
606
607                 result = RLM_MODULE_NOOP;
608                 MOD_LOG_CLOSE_BRACE();
609                 goto calculate_result;
610         } /* MOD_IF */
611
612         /*
613          *      Loop over a set of attributes.
614          */
615         if (c->type == MOD_FOREACH) {
616                 int i, foreach_depth = -1;
617                 VALUE_PAIR *vp;
618                 modcall_stack_entry_t *next = NULL;
619                 vp_cursor_t cursor;
620                 modgroup *g = mod_callabletogroup(c);
621
622                 if (depth >= MODCALL_STACK_MAX) {
623                         ERROR("Internal sanity check failed: module stack is too deep");
624                         fr_exit(1);
625                 }
626
627                 /*
628                  *      Figure out how deep we are in nesting by looking at request_data
629                  *      stored previously.
630                  */
631                 for (i = 0; i < 8; i++) {
632                         if (!request_data_reference(request,
633                                                     radius_get_vp, i)) {
634                                 foreach_depth = i;
635                                 break;
636                         }
637                 }
638
639                 if (foreach_depth < 0) {
640                         REDEBUG("foreach Nesting too deep!");
641                         result = RLM_MODULE_FAIL;
642                         goto calculate_result;
643                 }
644
645                 if (radius_get_vp(&vp, request, c->name) < 0) {
646                         RDEBUG("Unknown attribute \"%s\"", c->name);
647                         result = RLM_MODULE_FAIL;
648                         goto calculate_result;
649                 }
650
651                 if (!vp) {      /* nothing to loop over */
652                         MOD_LOG_OPEN_BRACE("foreach");
653                         result = RLM_MODULE_NOOP;
654                         MOD_LOG_CLOSE_BRACE();
655                         goto calculate_result;
656                 }
657
658                 RDEBUG2("%.*sforeach %s ", depth + 1, modcall_spaces,
659                         c->name);
660
661                 fr_cursor_init(&cursor, &vp);
662                 /* Prime the cursor. */
663                 cursor.found = cursor.current;
664                 while (vp) {
665                         VALUE_PAIR *copy = NULL, **copy_p;
666
667 #ifndef NDEBUG
668                         if (fr_debug_flag >= 2) {
669                                 char buffer[1024];
670
671                                 vp_prints_value(buffer, sizeof(buffer), vp, '"');
672                                 RDEBUG2("%.*s #  Foreach-Variable-%d = %s", depth + 1,
673                                         modcall_spaces, foreach_depth, buffer);
674                         }
675 #endif
676
677                         /*
678                          *      Copy only the one VP we care about.
679                          */
680                         copy = paircopyvp(request, vp);
681                         copy_p = &copy;
682
683                         /*
684                          *      @fixme: The old code freed copy on
685                          *      request_data_add or request_data_get.
686                          *      There's no way to easily do that now.
687                          *      The foreach code should be audited for
688                          *      possible memory leaks, though it's not
689                          *      a huge priority as any leaked memory
690                          *      will be freed on request free.
691                          */
692                         request_data_add(request, radius_get_vp, foreach_depth, copy_p, false);
693
694                         /*
695                          *      Initialize the childs stack frame.
696                          */
697                         next = entry + 1;
698                         next->c = g->children;
699                         next->result = entry->result;
700                         next->priority = 0;
701                         next->unwind = 0;
702
703                         if (!modcall_recurse(request, component, depth + 1, next)) {
704                                 request_data_get(request, radius_get_vp, foreach_depth);
705                                 pairfree(&copy);
706                                 break;
707                         }
708
709                         vp = fr_cursor_next_by_num(&cursor, vp->da->attr, vp->da->vendor, TAG_ANY);
710
711                         /*
712                          *      Delete the cached attribute, if it exists.
713                          */
714                         if (copy) {
715                                 request_data_get(request, radius_get_vp, foreach_depth);
716                                 pairfree(&copy);
717                         } else {
718                                 break;
719                         }
720
721                         /*
722                          *      If we've been told to stop processing
723                          *      it, do so.
724                          */
725                         if (entry->unwind == MOD_FOREACH) {
726                                 entry->unwind = 0;
727                                 break;
728                         }
729                 } /* loop over VPs */
730
731                 result = next->result;
732                 priority = next->priority;
733                 MOD_LOG_CLOSE_BRACE();
734                 goto calculate_result;
735         } /* MOD_FOREACH */
736
737         /*
738          *      Break out of a "foreach" loop.
739          */
740         if (c->type == MOD_BREAK) {
741                 int i;
742                 VALUE_PAIR **copy_p;
743
744                 for (i = 8; i >= 0; i--) {
745                         copy_p = request_data_get(request, radius_get_vp, i);
746                         if (copy_p) {
747                                 RDEBUG2("%.*s # break Foreach-Variable-%d", depth + 1,
748                                         modcall_spaces, i);
749                                 pairfree(copy_p);
750                                 break;
751                         }
752                 }
753
754                 /*
755                  *      Leave result / priority on the stack, and stop processing the section.
756                  */
757                 entry->unwind = MOD_FOREACH;
758                 return true;
759         } /* MOD_BREAK */
760 #endif    /* WITH_PROXY */
761
762         /*
763          *      Child is a group that has children of it's own.
764          */
765         if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
766 #ifdef WITH_UNLANG
767             || (c->type == MOD_CASE)
768 #endif
769                 ) {
770                 modgroup *g;
771
772 #ifdef WITH_UNLANG
773         do_children:
774 #endif
775                 g = mod_callabletogroup(c);
776
777                 /*
778                  *      This should really have been caught in the
779                  *      compiler, and the node never generated.  But
780                  *      doing that requires changing it's API so that
781                  *      it returns a flag instead of the compiled
782                  *      MOD_GROUP.
783                  */
784                 if (!g->children) {
785                         RDEBUG2("%.*s%s %s { ... } # empty sub-section is ignored",
786                                 depth + 1, modcall_spaces, cf_section_name1(g->cs), c->name);
787                         goto next_sibling;
788                 }
789
790                 MOD_LOG_OPEN_BRACE(cf_section_name1(g->cs));
791                 modcall_child(request, component,
792                               depth + 1, entry, g->children,
793                               &result);
794                 MOD_LOG_CLOSE_BRACE();
795                 goto calculate_result;
796         } /* MOD_GROUP */
797
798 #ifdef WITH_UNLANG
799         if (c->type == MOD_SWITCH) {
800                 modcallable *this, *found, *null_case;
801                 modgroup *g;
802                 char buffer[1024];
803
804                 MOD_LOG_OPEN_BRACE("switch");
805
806                 /*
807                  *      If there's no %, it refers to an attribute.
808                  *      Otherwise, expand it.
809                  */
810                 if (!strchr(c->name, '%')) {
811                         VALUE_PAIR *vp = NULL;
812
813                         radius_get_vp(&vp, request, c->name);
814                         if (vp) {
815                                 vp_prints_value(buffer,
816                                                 sizeof(buffer),
817                                                 vp, 0);
818                         } else {
819                                 *buffer = '\0';
820                         }
821                 } else {
822                         radius_xlat(buffer, sizeof(buffer),
823                                     request, c->name, NULL, NULL);
824                 }
825
826                 /*
827                  *      Find either the exact matching name, or the
828                  *      "case {...}" statement.
829                  */
830                 g = mod_callabletogroup(c);
831                 null_case = found = NULL;
832                 for (this = g->children; this; this = this->next) {
833                         if (!this->name) {
834                                 if (!null_case) null_case = this;
835                                 continue;
836                         }
837                         if (strcmp(buffer, this->name) == 0) {
838                                 found = this;
839                                 break;
840                         }
841                 }
842
843                 if (!found) found = null_case;
844
845                 MOD_LOG_OPEN_BRACE(group_name[c->type]);
846                 modcall_child(request, component,
847                               depth + 1, entry, found,
848                               &result);
849                 MOD_LOG_CLOSE_BRACE();
850                 goto calculate_result;
851         } /* MOD_SWITCH */
852 #endif
853
854         if ((c->type == MOD_LOAD_BALANCE) ||
855             (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
856                 int count = 0;
857                 modcallable *this, *found;
858                 modgroup *g;
859
860                 MOD_LOG_OPEN_BRACE("load-balance");
861
862                 g = mod_callabletogroup(c);
863                 found = NULL;
864                 for (this = g->children; this; this = this->next) {
865                         if (!found) {
866                                 found = this;
867                                 count = 1;
868                                 continue;
869                         }
870                         count++;
871
872                         if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
873                                 found = this;
874                         }
875                 }
876
877                 MOD_LOG_OPEN_BRACE(group_name[c->type]);
878
879                 if (c->type == MOD_LOAD_BALANCE) {
880                         modcall_child(request, component,
881                                       depth + 1, entry, found,
882                                       &result);
883
884                 } else {
885                         int i;
886
887                         /*
888                          *      Loop over all children in this
889                          *      section.  If we get FAIL, then
890                          *      continue.  Otherwise, stop.
891                          */
892                         for (i = 1; i < count; i++) {
893                                 modcall_child(request, component,
894                                               depth + 1, entry, found,
895                                               &result);
896                                 if (c->actions[result] == MOD_ACTION_RETURN) {
897                                         priority = -1;
898                                         break;
899                                 }
900                         }
901                 }
902                 MOD_LOG_CLOSE_BRACE();
903                 goto calculate_result;
904         } /* MOD_LOAD_BALANCE */
905
906         /*
907          *      Reference another virtual server.
908          *
909          *      This should really be deleted, and replaced with a
910          *      more abstracted / functional version.
911          */
912         if (c->type == MOD_REFERENCE) {
913                 modref *mr = mod_callabletoref(c);
914                 char const *server = request->server;
915
916                 if (server == mr->ref_name) {
917                         RWDEBUG("Suppressing recursive call to server %s", server);
918                         goto next_sibling;
919                 }
920
921                 request->server = mr->ref_name;
922                 RDEBUG("server %s { # nested call", mr->ref_name);
923                 result = indexed_modcall(component, 0, request);
924                 RDEBUG("} # server %s with nested call", mr->ref_name);
925                 request->server = server;
926                 goto calculate_result;
927         } /* MOD_REFERENCE */
928
929         /*
930          *      xlat a string without doing anything else
931          *
932          *      This should really be deleted, and replaced with a
933          *      more abstracted / functional version.
934          */
935         if (c->type == MOD_XLAT) {
936                 modxlat *mx = mod_callabletoxlat(c);
937                 char buffer[128];
938
939                 if (!mx->exec) {
940                         radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
941                 } else {
942                         RDEBUG("`%s`", mx->xlat_name);
943                         radius_exec_program(request, mx->xlat_name, false, true, NULL, 0,
944                                             EXEC_TIMEOUT, request->packet->vps, NULL);
945                 }
946
947                 goto next_sibling;
948         } /* MOD_XLAT */
949
950         /*
951          *      Add new module types here.
952          */
953
954 calculate_result:
955 #if 0
956         RDEBUG("(%s, %d) ? (%s, %d)",
957                fr_int2str(mod_rcode_table, result, "<invalid>"),
958                priority,
959                fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
960                entry->priority);
961 #endif
962
963
964         rad_assert(result != RLM_MODULE_UNKNOWN);
965
966         /*
967          *      The child's action says return.  Do so.
968          */
969         if ((c->actions[result] == MOD_ACTION_RETURN) &&
970             (priority <= 0)) {
971                 entry->result = result;
972                 return true;
973         }
974
975         /*
976          *      If "reject", break out of the loop and return
977          *      reject.
978          */
979         if (c->actions[result] == MOD_ACTION_REJECT) {
980                 entry->result = RLM_MODULE_REJECT;
981                 return true;
982         }
983
984         /*
985          *      The array holds a default priority for this return
986          *      code.  Grab it in preference to any unset priority.
987          */
988         if (priority < 0) {
989                 priority = c->actions[result];
990         }
991
992         /*
993          *      We're higher than any previous priority, remember this
994          *      return code and priority.
995          */
996         if (priority > entry->priority) {
997                 entry->result = result;
998                 entry->priority = priority;
999         }
1000
1001 #ifdef WITH_UNLANG
1002         /*
1003          *      If we're processing a "case" statement, we return once
1004          *      it's done, rather than going to the next "case" statement.
1005          */
1006         if (c->type == MOD_CASE) return true;
1007 #endif
1008
1009         /*
1010          *      If we've been told to stop processing
1011          *      it, do so.
1012          */
1013         if (entry->unwind != 0) {
1014                 RDEBUG2("%.*s # unwind to enclosing %s", depth + 1, modcall_spaces,
1015                         group_name[entry->unwind]);
1016                 entry->unwind = 0;
1017                 return true;
1018         }
1019
1020 next_sibling:
1021         entry->c = entry->c->next;
1022
1023         if (entry->c) goto redo;
1024
1025         /*
1026          *      And we're done!
1027          */
1028         return true;
1029 }
1030
1031
1032 /**
1033  * @brief Call a module, iteratively, with a local stack, rather than
1034  *      recursively.  What did Paul Graham say about Lisp...?
1035  */
1036 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1037 {
1038         modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1039
1040         /*
1041          *      Set up the initial stack frame.
1042          */
1043         stack[0].c = c;
1044         stack[0].result = default_component_results[component];
1045         stack[0].priority = 0;
1046         stack[0].unwind = 0;
1047
1048         /*
1049          *      Call the main handler.
1050          */
1051         if (!modcall_recurse(request, component, 0, &stack[0])) {
1052                 return RLM_MODULE_FAIL;
1053         }
1054
1055         /*
1056          *      Return the result.
1057          */
1058         return stack[0].result;
1059 }
1060
1061
1062 #if 0
1063 static char const *action2str(int action)
1064 {
1065         static char buf[32];
1066         if(action==MOD_ACTION_RETURN)
1067                 return "return";
1068         if(action==MOD_ACTION_REJECT)
1069                 return "reject";
1070         snprintf(buf, sizeof buf, "%d", action);
1071         return buf;
1072 }
1073
1074 /* If you suspect a bug in the parser, you'll want to use these dump
1075  * functions. dump_tree should reproduce a whole tree exactly as it was found
1076  * in radiusd.conf, but in long form (all actions explicitly defined) */
1077 static void dump_mc(modcallable *c, int indent)
1078 {
1079         int i;
1080
1081         if(c->type==MOD_SINGLE) {
1082                 modsingle *single = mod_callabletosingle(c);
1083                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1084                         single->modinst->name);
1085         } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1086                 modgroup *g = mod_callabletogroup(c);
1087                 modcallable *p;
1088                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1089                       group_name[c->type]);
1090                 for(p = g->children;p;p = p->next)
1091                         dump_mc(p, indent+1);
1092         } /* else ignore it for now */
1093
1094         for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1095                 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1096                       fr_int2str(mod_rcode_table, i, "<invalid>"),
1097                       action2str(c->actions[i]));
1098         }
1099
1100         DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1101 }
1102
1103 static void dump_tree(rlm_components_t comp, modcallable *c)
1104 {
1105         DEBUG("[%s]", comp2str[comp]);
1106         dump_mc(c, 0);
1107 }
1108 #else
1109 #define dump_tree(a, b)
1110 #endif
1111
1112 /* These are the default actions. For each component, the group{} block
1113  * behaves like the code from the old module_*() function. redundant{} and
1114  * append{} are based on my guesses of what they will be used for. --Pac. */
1115 static const int
1116 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1117 {
1118         /* authenticate */
1119         {
1120                 /* group */
1121                 {
1122                         MOD_ACTION_RETURN,      /* reject   */
1123                         1,                      /* fail     */
1124                         MOD_ACTION_RETURN,      /* ok       */
1125                         MOD_ACTION_RETURN,      /* handled  */
1126                         1,                      /* invalid  */
1127                         MOD_ACTION_RETURN,      /* userlock */
1128                         MOD_ACTION_RETURN,      /* notfound */
1129                         1,                      /* noop     */
1130                         1                       /* updated  */
1131                 },
1132                 /* redundant */
1133                 {
1134                         MOD_ACTION_RETURN,      /* reject   */
1135                         1,                      /* fail     */
1136                         MOD_ACTION_RETURN,      /* ok       */
1137                         MOD_ACTION_RETURN,      /* handled  */
1138                         MOD_ACTION_RETURN,      /* invalid  */
1139                         MOD_ACTION_RETURN,      /* userlock */
1140                         MOD_ACTION_RETURN,      /* notfound */
1141                         MOD_ACTION_RETURN,      /* noop     */
1142                         MOD_ACTION_RETURN       /* updated  */
1143                 },
1144                 /* append */
1145                 {
1146                         MOD_ACTION_RETURN,      /* reject   */
1147                         1,                      /* fail     */
1148                         MOD_ACTION_RETURN,      /* ok       */
1149                         MOD_ACTION_RETURN,      /* handled  */
1150                         MOD_ACTION_RETURN,      /* invalid  */
1151                         MOD_ACTION_RETURN,      /* userlock */
1152                         2,                      /* notfound */
1153                         MOD_ACTION_RETURN,      /* noop     */
1154                         MOD_ACTION_RETURN       /* updated  */
1155                 }
1156         },
1157         /* authorize */
1158         {
1159                 /* group */
1160                 {
1161                         MOD_ACTION_RETURN,      /* reject   */
1162                         MOD_ACTION_RETURN,      /* fail     */
1163                         3,                      /* ok       */
1164                         MOD_ACTION_RETURN,      /* handled  */
1165                         MOD_ACTION_RETURN,      /* invalid  */
1166                         MOD_ACTION_RETURN,      /* userlock */
1167                         1,                      /* notfound */
1168                         2,                      /* noop     */
1169                         4                       /* updated  */
1170                 },
1171                 /* redundant */
1172                 {
1173                         MOD_ACTION_RETURN,      /* reject   */
1174                         1,                      /* fail     */
1175                         MOD_ACTION_RETURN,      /* ok       */
1176                         MOD_ACTION_RETURN,      /* handled  */
1177                         MOD_ACTION_RETURN,      /* invalid  */
1178                         MOD_ACTION_RETURN,      /* userlock */
1179                         MOD_ACTION_RETURN,      /* notfound */
1180                         MOD_ACTION_RETURN,      /* noop     */
1181                         MOD_ACTION_RETURN       /* updated  */
1182                 },
1183                 /* append */
1184                 {
1185                         MOD_ACTION_RETURN,      /* reject   */
1186                         1,                      /* fail     */
1187                         MOD_ACTION_RETURN,      /* ok       */
1188                         MOD_ACTION_RETURN,      /* handled  */
1189                         MOD_ACTION_RETURN,      /* invalid  */
1190                         MOD_ACTION_RETURN,      /* userlock */
1191                         2,                      /* notfound */
1192                         MOD_ACTION_RETURN,      /* noop     */
1193                         MOD_ACTION_RETURN       /* updated  */
1194                 }
1195         },
1196         /* preacct */
1197         {
1198                 /* group */
1199                 {
1200                         MOD_ACTION_RETURN,      /* reject   */
1201                         MOD_ACTION_RETURN,      /* fail     */
1202                         2,                      /* ok       */
1203                         MOD_ACTION_RETURN,      /* handled  */
1204                         MOD_ACTION_RETURN,      /* invalid  */
1205                         MOD_ACTION_RETURN,      /* userlock */
1206                         MOD_ACTION_RETURN,      /* notfound */
1207                         1,                      /* noop     */
1208                         3                       /* updated  */
1209                 },
1210                 /* redundant */
1211                 {
1212                         MOD_ACTION_RETURN,      /* reject   */
1213                         1,                      /* fail     */
1214                         MOD_ACTION_RETURN,      /* ok       */
1215                         MOD_ACTION_RETURN,      /* handled  */
1216                         MOD_ACTION_RETURN,      /* invalid  */
1217                         MOD_ACTION_RETURN,      /* userlock */
1218                         MOD_ACTION_RETURN,      /* notfound */
1219                         MOD_ACTION_RETURN,      /* noop     */
1220                         MOD_ACTION_RETURN       /* updated  */
1221                 },
1222                 /* append */
1223                 {
1224                         MOD_ACTION_RETURN,      /* reject   */
1225                         1,                      /* fail     */
1226                         MOD_ACTION_RETURN,      /* ok       */
1227                         MOD_ACTION_RETURN,      /* handled  */
1228                         MOD_ACTION_RETURN,      /* invalid  */
1229                         MOD_ACTION_RETURN,      /* userlock */
1230                         2,                      /* notfound */
1231                         MOD_ACTION_RETURN,      /* noop     */
1232                         MOD_ACTION_RETURN       /* updated  */
1233                 }
1234         },
1235         /* accounting */
1236         {
1237                 /* group */
1238                 {
1239                         MOD_ACTION_RETURN,      /* reject   */
1240                         MOD_ACTION_RETURN,      /* fail     */
1241                         2,                      /* ok       */
1242                         MOD_ACTION_RETURN,      /* handled  */
1243                         MOD_ACTION_RETURN,      /* invalid  */
1244                         MOD_ACTION_RETURN,      /* userlock */
1245                         MOD_ACTION_RETURN,      /* notfound */
1246                         1,                      /* noop     */
1247                         3                       /* updated  */
1248                 },
1249                 /* redundant */
1250                 {
1251                         1,                      /* reject   */
1252                         1,                      /* fail     */
1253                         MOD_ACTION_RETURN,      /* ok       */
1254                         MOD_ACTION_RETURN,      /* handled  */
1255                         1,                      /* invalid  */
1256                         1,                      /* userlock */
1257                         1,                      /* notfound */
1258                         2,                      /* noop     */
1259                         4                       /* updated  */
1260                 },
1261                 /* append */
1262                 {
1263                         MOD_ACTION_RETURN,      /* reject   */
1264                         1,                      /* fail     */
1265                         MOD_ACTION_RETURN,      /* ok       */
1266                         MOD_ACTION_RETURN,      /* handled  */
1267                         MOD_ACTION_RETURN,      /* invalid  */
1268                         MOD_ACTION_RETURN,      /* userlock */
1269                         2,                      /* notfound */
1270                         MOD_ACTION_RETURN,      /* noop     */
1271                         MOD_ACTION_RETURN       /* updated  */
1272                 }
1273         },
1274         /* checksimul */
1275         {
1276                 /* group */
1277                 {
1278                         MOD_ACTION_RETURN,      /* reject   */
1279                         1,                      /* fail     */
1280                         MOD_ACTION_RETURN,      /* ok       */
1281                         MOD_ACTION_RETURN,      /* handled  */
1282                         MOD_ACTION_RETURN,      /* invalid  */
1283                         MOD_ACTION_RETURN,      /* userlock */
1284                         MOD_ACTION_RETURN,      /* notfound */
1285                         MOD_ACTION_RETURN,      /* noop     */
1286                         MOD_ACTION_RETURN       /* updated  */
1287                 },
1288                 /* redundant */
1289                 {
1290                         MOD_ACTION_RETURN,      /* reject   */
1291                         1,                      /* fail     */
1292                         MOD_ACTION_RETURN,      /* ok       */
1293                         MOD_ACTION_RETURN,      /* handled  */
1294                         MOD_ACTION_RETURN,      /* invalid  */
1295                         MOD_ACTION_RETURN,      /* userlock */
1296                         MOD_ACTION_RETURN,      /* notfound */
1297                         MOD_ACTION_RETURN,      /* noop     */
1298                         MOD_ACTION_RETURN       /* updated  */
1299                 },
1300                 /* append */
1301                 {
1302                         MOD_ACTION_RETURN,      /* reject   */
1303                         1,                      /* fail     */
1304                         MOD_ACTION_RETURN,      /* ok       */
1305                         MOD_ACTION_RETURN,      /* handled  */
1306                         MOD_ACTION_RETURN,      /* invalid  */
1307                         MOD_ACTION_RETURN,      /* userlock */
1308                         MOD_ACTION_RETURN,      /* notfound */
1309                         MOD_ACTION_RETURN,      /* noop     */
1310                         MOD_ACTION_RETURN       /* updated  */
1311                 }
1312         },
1313         /* pre-proxy */
1314         {
1315                 /* group */
1316                 {
1317                         MOD_ACTION_RETURN,      /* reject   */
1318                         MOD_ACTION_RETURN,      /* fail     */
1319                         3,                      /* ok       */
1320                         MOD_ACTION_RETURN,      /* handled  */
1321                         MOD_ACTION_RETURN,      /* invalid  */
1322                         MOD_ACTION_RETURN,      /* userlock */
1323                         1,                      /* notfound */
1324                         2,                      /* noop     */
1325                         4                       /* updated  */
1326                 },
1327                 /* redundant */
1328                 {
1329                         MOD_ACTION_RETURN,      /* reject   */
1330                         1,                      /* fail     */
1331                         MOD_ACTION_RETURN,      /* ok       */
1332                         MOD_ACTION_RETURN,      /* handled  */
1333                         MOD_ACTION_RETURN,      /* invalid  */
1334                         MOD_ACTION_RETURN,      /* userlock */
1335                         MOD_ACTION_RETURN,      /* notfound */
1336                         MOD_ACTION_RETURN,      /* noop     */
1337                         MOD_ACTION_RETURN       /* updated  */
1338                 },
1339                 /* append */
1340                 {
1341                         MOD_ACTION_RETURN,      /* reject   */
1342                         1,                      /* fail     */
1343                         MOD_ACTION_RETURN,      /* ok       */
1344                         MOD_ACTION_RETURN,      /* handled  */
1345                         MOD_ACTION_RETURN,      /* invalid  */
1346                         MOD_ACTION_RETURN,      /* userlock */
1347                         2,                      /* notfound */
1348                         MOD_ACTION_RETURN,      /* noop     */
1349                         MOD_ACTION_RETURN       /* updated  */
1350                 }
1351         },
1352         /* post-proxy */
1353         {
1354                 /* group */
1355                 {
1356                         MOD_ACTION_RETURN,      /* reject   */
1357                         MOD_ACTION_RETURN,      /* fail     */
1358                         3,                      /* ok       */
1359                         MOD_ACTION_RETURN,      /* handled  */
1360                         MOD_ACTION_RETURN,      /* invalid  */
1361                         MOD_ACTION_RETURN,      /* userlock */
1362                         1,                      /* notfound */
1363                         2,                      /* noop     */
1364                         4                       /* updated  */
1365                 },
1366                 /* redundant */
1367                 {
1368                         MOD_ACTION_RETURN,      /* reject   */
1369                         1,                      /* fail     */
1370                         MOD_ACTION_RETURN,      /* ok       */
1371                         MOD_ACTION_RETURN,      /* handled  */
1372                         MOD_ACTION_RETURN,      /* invalid  */
1373                         MOD_ACTION_RETURN,      /* userlock */
1374                         MOD_ACTION_RETURN,      /* notfound */
1375                         MOD_ACTION_RETURN,      /* noop     */
1376                         MOD_ACTION_RETURN       /* updated  */
1377                 },
1378                 /* append */
1379                 {
1380                         MOD_ACTION_RETURN,      /* reject   */
1381                         1,                      /* fail     */
1382                         MOD_ACTION_RETURN,      /* ok       */
1383                         MOD_ACTION_RETURN,      /* handled  */
1384                         MOD_ACTION_RETURN,      /* invalid  */
1385                         MOD_ACTION_RETURN,      /* userlock */
1386                         2,                      /* notfound */
1387                         MOD_ACTION_RETURN,      /* noop     */
1388                         MOD_ACTION_RETURN       /* updated  */
1389                 }
1390         },
1391         /* post-auth */
1392         {
1393                 /* group */
1394                 {
1395                         MOD_ACTION_RETURN,      /* reject   */
1396                         MOD_ACTION_RETURN,      /* fail     */
1397                         3,                      /* ok       */
1398                         MOD_ACTION_RETURN,      /* handled  */
1399                         MOD_ACTION_RETURN,      /* invalid  */
1400                         MOD_ACTION_RETURN,      /* userlock */
1401                         1,                      /* notfound */
1402                         2,                      /* noop     */
1403                         4                       /* updated  */
1404                 },
1405                 /* redundant */
1406                 {
1407                         MOD_ACTION_RETURN,      /* reject   */
1408                         1,                      /* fail     */
1409                         MOD_ACTION_RETURN,      /* ok       */
1410                         MOD_ACTION_RETURN,      /* handled  */
1411                         MOD_ACTION_RETURN,      /* invalid  */
1412                         MOD_ACTION_RETURN,      /* userlock */
1413                         MOD_ACTION_RETURN,      /* notfound */
1414                         MOD_ACTION_RETURN,      /* noop     */
1415                         MOD_ACTION_RETURN       /* updated  */
1416                 },
1417                 /* append */
1418                 {
1419                         MOD_ACTION_RETURN,      /* reject   */
1420                         1,                      /* fail     */
1421                         MOD_ACTION_RETURN,      /* ok       */
1422                         MOD_ACTION_RETURN,      /* handled  */
1423                         MOD_ACTION_RETURN,      /* invalid  */
1424                         MOD_ACTION_RETURN,      /* userlock */
1425                         2,                      /* notfound */
1426                         MOD_ACTION_RETURN,      /* noop     */
1427                         MOD_ACTION_RETURN       /* updated  */
1428                 }
1429         }
1430 #ifdef WITH_COA
1431         ,
1432         /* recv-coa */
1433         {
1434                 /* group */
1435                 {
1436                         MOD_ACTION_RETURN,      /* reject   */
1437                         MOD_ACTION_RETURN,      /* fail     */
1438                         3,                      /* ok       */
1439                         MOD_ACTION_RETURN,      /* handled  */
1440                         MOD_ACTION_RETURN,      /* invalid  */
1441                         MOD_ACTION_RETURN,      /* userlock */
1442                         1,                      /* notfound */
1443                         2,                      /* noop     */
1444                         4                       /* updated  */
1445                 },
1446                 /* redundant */
1447                 {
1448                         MOD_ACTION_RETURN,      /* reject   */
1449                         1,                      /* fail     */
1450                         MOD_ACTION_RETURN,      /* ok       */
1451                         MOD_ACTION_RETURN,      /* handled  */
1452                         MOD_ACTION_RETURN,      /* invalid  */
1453                         MOD_ACTION_RETURN,      /* userlock */
1454                         MOD_ACTION_RETURN,      /* notfound */
1455                         MOD_ACTION_RETURN,      /* noop     */
1456                         MOD_ACTION_RETURN       /* updated  */
1457                 },
1458                 /* append */
1459                 {
1460                         MOD_ACTION_RETURN,      /* reject   */
1461                         1,                      /* fail     */
1462                         MOD_ACTION_RETURN,      /* ok       */
1463                         MOD_ACTION_RETURN,      /* handled  */
1464                         MOD_ACTION_RETURN,      /* invalid  */
1465                         MOD_ACTION_RETURN,      /* userlock */
1466                         2,                      /* notfound */
1467                         MOD_ACTION_RETURN,      /* noop     */
1468                         MOD_ACTION_RETURN       /* updated  */
1469                 }
1470         },
1471         /* send-coa */
1472         {
1473                 /* group */
1474                 {
1475                         MOD_ACTION_RETURN,      /* reject   */
1476                         MOD_ACTION_RETURN,      /* fail     */
1477                         3,                      /* ok       */
1478                         MOD_ACTION_RETURN,      /* handled  */
1479                         MOD_ACTION_RETURN,      /* invalid  */
1480                         MOD_ACTION_RETURN,      /* userlock */
1481                         1,                      /* notfound */
1482                         2,                      /* noop     */
1483                         4                       /* updated  */
1484                 },
1485                 /* redundant */
1486                 {
1487                         MOD_ACTION_RETURN,      /* reject   */
1488                         1,                      /* fail     */
1489                         MOD_ACTION_RETURN,      /* ok       */
1490                         MOD_ACTION_RETURN,      /* handled  */
1491                         MOD_ACTION_RETURN,      /* invalid  */
1492                         MOD_ACTION_RETURN,      /* userlock */
1493                         MOD_ACTION_RETURN,      /* notfound */
1494                         MOD_ACTION_RETURN,      /* noop     */
1495                         MOD_ACTION_RETURN       /* updated  */
1496                 },
1497                 /* append */
1498                 {
1499                         MOD_ACTION_RETURN,      /* reject   */
1500                         1,                      /* fail     */
1501                         MOD_ACTION_RETURN,      /* ok       */
1502                         MOD_ACTION_RETURN,      /* handled  */
1503                         MOD_ACTION_RETURN,      /* invalid  */
1504                         MOD_ACTION_RETURN,      /* userlock */
1505                         2,                      /* notfound */
1506                         MOD_ACTION_RETURN,      /* noop     */
1507                         MOD_ACTION_RETURN       /* updated  */
1508                 }
1509         }
1510 #endif
1511 };
1512
1513
1514 #ifdef WITH_UNLANG
1515 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1516                                          CONF_SECTION *cs, char const *name2)
1517 {
1518         int rcode;
1519         modgroup *g;
1520         modcallable *csingle;
1521         value_pair_map_t *map, *head = NULL;
1522
1523         /*
1524          *      This looks at cs->name2 to determine which list to update
1525          */
1526         rcode = radius_attrmap(cs, &head, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, 128);
1527         if (rcode < 0) return NULL; /* message already printed */
1528
1529         if (!head) {
1530                 cf_log_err_cs(cs, "'update' sections cannot be empty");
1531                 return NULL;
1532         }
1533
1534         for (map = head; map != NULL; map = map->next) {
1535                 if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LITERAL)) {
1536                         /*
1537                          *      If LHS is an attribute, and RHS is a literal, we can
1538                          *      check that the format is correct.
1539                          */
1540                         VALUE_PAIR *vp;
1541                         bool ret;
1542
1543                         MEM(vp = pairalloc(cs, map->dst->da));
1544                         vp->op = map->op;
1545
1546                         ret = pairparsevalue(vp, map->src->name);
1547                         talloc_free(vp);
1548                         if (!ret) {
1549                                 talloc_free(head);
1550                                 cf_log_err(map->ci, "%s", fr_strerror());
1551                                 return NULL;
1552                         }
1553                 }
1554         }
1555
1556         g = rad_malloc(sizeof(*g)); /* never fails */
1557         memset(g, 0, sizeof(*g));
1558
1559         csingle = mod_grouptocallable(g);
1560
1561         csingle->parent = parent;
1562         csingle->next = NULL;
1563
1564         if (name2) {
1565                 csingle->name = name2;
1566         } else {
1567                 csingle->name = "";
1568         }
1569         csingle->type = MOD_UPDATE;
1570         csingle->method = component;
1571
1572         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1573                sizeof(csingle->actions));
1574
1575         g->grouptype = GROUPTYPE_SIMPLE;
1576         g->children = NULL;
1577         g->cs = cs;
1578         g->map = head;
1579
1580         return csingle;
1581 }
1582
1583
1584 static modcallable *do_compile_modswitch(modcallable *parent, UNUSED rlm_components_t component, CONF_SECTION *cs)
1585 {
1586         modcallable *csingle;
1587         CONF_ITEM *ci;
1588         bool had_seen_default = false;
1589
1590         if (!cf_section_name2(cs)) {
1591                 cf_log_err_cs(cs,
1592                            "You must specify a variable to switch over for 'switch'.");
1593                 return NULL;
1594         }
1595
1596         if (!cf_item_find_next(cs, NULL)) {
1597                 cf_log_err_cs(cs, "'switch' statements cannot be empty.");
1598                 return NULL;
1599         }
1600
1601         /*
1602          *      Walk through the children of the switch section,
1603          *      ensuring that they're all 'case' statements
1604          */
1605         for (ci=cf_item_find_next(cs, NULL);
1606              ci != NULL;
1607              ci=cf_item_find_next(cs, ci)) {
1608                 CONF_SECTION *subcs;
1609                 char const *name1, *name2;
1610
1611                 if (!cf_item_is_section(ci)) {
1612                         if (!cf_item_is_pair(ci)) continue;
1613
1614                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1615                         return NULL;
1616                 }
1617
1618                 subcs = cf_itemtosection(ci);   /* can't return NULL */
1619                 name1 = cf_section_name1(subcs);
1620
1621                 if (strcmp(name1, "case") != 0) {
1622                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1623                         return NULL;
1624                 }
1625
1626                 name2 = cf_section_name2(subcs);
1627                 if (!name2 && !had_seen_default) {
1628                         had_seen_default = true;
1629                         continue;
1630                 }
1631
1632                 if (!name2 || (name2[0] == '\0')) {
1633                         cf_log_err(ci, "\"case\" sections must have a name");
1634                         return NULL;
1635                 }
1636         }
1637
1638         csingle = do_compile_modgroup(parent, component, cs, GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1639         if (!csingle) return NULL;
1640         csingle->type = MOD_SWITCH;
1641         return csingle;
1642 }
1643
1644 static modcallable *do_compile_modforeach(modcallable *parent,
1645                                           UNUSED rlm_components_t component, CONF_SECTION *cs,
1646                                           char const *name2)
1647 {
1648         modcallable *csingle;
1649
1650         if (!cf_section_name2(cs)) {
1651                 cf_log_err_cs(cs,
1652                            "You must specify an attribute to loop over in 'foreach'.");
1653                 return NULL;
1654         }
1655
1656         if (!cf_item_find_next(cs, NULL)) {
1657                 cf_log_err_cs(cs, "'foreach' blocks cannot be empty.");
1658                 return NULL;
1659         }
1660
1661         csingle= do_compile_modgroup(parent, component, cs,
1662                                      GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1663         if (!csingle) return NULL;
1664         csingle->name = name2;
1665         csingle->type = MOD_FOREACH;
1666         return csingle;
1667 }
1668
1669 static modcallable *do_compile_modbreak(modcallable *parent,
1670                                         rlm_components_t component, CONF_ITEM const *ci)
1671 {
1672         modcallable *csingle;
1673         CONF_SECTION const *cs = NULL;
1674
1675         for (cs = cf_item_parent(ci);
1676              cs != NULL;
1677              cs = cf_item_parent(cf_sectiontoitem(cs))) {
1678                 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
1679                         break;
1680                 }
1681         }
1682
1683         if (!cs) {
1684                 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
1685                 return NULL;
1686         }
1687
1688         csingle = do_compile_modgroup(parent, component, NULL,
1689                                       GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
1690         if (!csingle) return NULL;
1691         csingle->name = "";
1692         csingle->type = MOD_BREAK;
1693         return csingle;
1694 }
1695 #endif
1696
1697 static modcallable *do_compile_modserver(modcallable *parent,
1698                                          rlm_components_t component, CONF_ITEM *ci,
1699                                          char const *name,
1700                                          CONF_SECTION *cs,
1701                                          char const *server)
1702 {
1703         modcallable *csingle;
1704         CONF_SECTION *subcs;
1705         modref *mr;
1706
1707         subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
1708         if (!subcs) {
1709                 cf_log_err(ci, "Server %s has no %s section",
1710                            server, comp2str[component]);
1711                 return NULL;
1712         }
1713
1714         mr = rad_malloc(sizeof(*mr));
1715         memset(mr, 0, sizeof(*mr));
1716
1717         csingle = mod_reftocallable(mr);
1718         csingle->parent = parent;
1719         csingle->next = NULL;
1720         csingle->name = name;
1721         csingle->type = MOD_REFERENCE;
1722         csingle->method = component;
1723
1724         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1725                sizeof(csingle->actions));
1726
1727         mr->ref_name = strdup(server);
1728         mr->ref_cs = cs;
1729
1730         return csingle;
1731 }
1732
1733 static modcallable *do_compile_modxlat(modcallable *parent,
1734                                        rlm_components_t component, char const *fmt)
1735 {
1736         modcallable *csingle;
1737         modxlat *mx;
1738
1739         mx = rad_malloc(sizeof(*mx));
1740         memset(mx, 0, sizeof(*mx));
1741
1742         csingle = mod_xlattocallable(mx);
1743         csingle->parent = parent;
1744         csingle->next = NULL;
1745         csingle->name = "expand";
1746         csingle->type = MOD_XLAT;
1747         csingle->method = component;
1748
1749         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1750                sizeof(csingle->actions));
1751
1752         mx->xlat_name = strdup(fmt);
1753         if (fmt[0] != '%') {
1754                 char *p;
1755                 mx->exec = true;
1756
1757                 strcpy(mx->xlat_name, fmt + 1);
1758                 p = strrchr(mx->xlat_name, '`');
1759                 if (p) *p = '\0';
1760         }
1761
1762         return csingle;
1763 }
1764
1765 /*
1766  *      redundant, etc. can refer to modules or groups, but not much else.
1767  */
1768 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
1769 {
1770         CONF_ITEM *ci;
1771
1772         for (ci=cf_item_find_next(cs, NULL);
1773              ci != NULL;
1774              ci=cf_item_find_next(cs, ci)) {
1775                 /*
1776                  *      If we're a redundant, etc. group, then the
1777                  *      intention is to call modules, rather than
1778                  *      processing logic.  These checks aren't
1779                  *      *strictly* necessary, but they keep the users
1780                  *      from doing crazy things.
1781                  */
1782                 if (cf_item_is_section(ci)) {
1783                         CONF_SECTION *subcs = cf_itemtosection(ci);
1784                         char const *name1 = cf_section_name1(subcs);
1785
1786                         if ((strcmp(name1, "if") == 0) ||
1787                             (strcmp(name1, "else") == 0) ||
1788                             (strcmp(name1, "elsif") == 0) ||
1789                             (strcmp(name1, "update") == 0) ||
1790                             (strcmp(name1, "switch") == 0) ||
1791                             (strcmp(name1, "case") == 0)) {
1792                                 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
1793                                        name, name1);
1794                                 return 0;
1795                         }
1796                         continue;
1797                 }
1798
1799                 if (cf_item_is_pair(ci)) {
1800                         CONF_PAIR *cp = cf_itemtopair(ci);
1801                         if (cf_pair_value(cp) != NULL) {
1802                                 cf_log_err(ci,
1803                                            "Entry with no value is invalid");
1804                                 return 0;
1805                         }
1806                 }
1807         }
1808
1809         return 1;
1810 }
1811
1812
1813 /*
1814  *      Compile one entry of a module call.
1815  */
1816 static modcallable *do_compile_modsingle(modcallable *parent,
1817                                          rlm_components_t component, CONF_ITEM *ci,
1818                                          int grouptype,
1819                                          char const **modname)
1820 {
1821         char const *modrefname;
1822         modsingle *single;
1823         modcallable *csingle;
1824         module_instance_t *this;
1825         CONF_SECTION *cs, *subcs, *modules;
1826         char const *realname;
1827
1828         if (cf_item_is_section(ci)) {
1829                 char const *name2;
1830
1831                 cs = cf_itemtosection(ci);
1832                 modrefname = cf_section_name1(cs);
1833                 name2 = cf_section_name2(cs);
1834                 if (!name2) name2 = "";
1835
1836                 /*
1837                  *      group{}, redundant{}, or append{} may appear
1838                  *      where a single module instance was expected.
1839                  *      In that case, we hand it off to
1840                  *      compile_modgroup
1841                  */
1842                 if (strcmp(modrefname, "group") == 0) {
1843                         *modname = name2;
1844                         return do_compile_modgroup(parent, component, cs,
1845                                                    GROUPTYPE_SIMPLE,
1846                                                    grouptype);
1847
1848                 } else if (strcmp(modrefname, "redundant") == 0) {
1849                         *modname = name2;
1850
1851                         if (!all_children_are_modules(cs, modrefname)) {
1852                                 return NULL;
1853                         }
1854
1855                         return do_compile_modgroup(parent, component, cs,
1856                                                    GROUPTYPE_REDUNDANT,
1857                                                    grouptype);
1858
1859                 } else if (strcmp(modrefname, "append") == 0) {
1860                         *modname = name2;
1861                         return do_compile_modgroup(parent, component, cs,
1862                                                    GROUPTYPE_APPEND,
1863                                                    grouptype);
1864
1865                 } else if (strcmp(modrefname, "load-balance") == 0) {
1866                         *modname = name2;
1867
1868                         if (!all_children_are_modules(cs, modrefname)) {
1869                                 return NULL;
1870                         }
1871
1872                         csingle= do_compile_modgroup(parent, component, cs,
1873                                                      GROUPTYPE_SIMPLE,
1874                                                      grouptype);
1875                         if (!csingle) return NULL;
1876                         csingle->type = MOD_LOAD_BALANCE;
1877                         return csingle;
1878
1879                 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1880                         *modname = name2;
1881
1882                         if (!all_children_are_modules(cs, modrefname)) {
1883                                 return NULL;
1884                         }
1885
1886                         csingle= do_compile_modgroup(parent, component, cs,
1887                                                      GROUPTYPE_REDUNDANT,
1888                                                      grouptype);
1889                         if (!csingle) return NULL;
1890                         csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1891                         return csingle;
1892
1893 #ifdef WITH_UNLANG
1894                 } else  if (strcmp(modrefname, "if") == 0) {
1895                         modgroup *g;
1896
1897                         if (!cf_section_name2(cs)) {
1898                                 cf_log_err(ci, "'if' without condition.");
1899                                 return NULL;
1900                         }
1901
1902                         *modname = name2;
1903                         csingle= do_compile_modgroup(parent, component, cs,
1904                                                      GROUPTYPE_SIMPLE,
1905                                                      grouptype);
1906                         if (!csingle) return NULL;
1907                         csingle->type = MOD_IF;
1908                         *modname = name2;
1909
1910                         g = mod_callabletogroup(csingle);
1911                         g->cond = cf_data_find(g->cs, "if");
1912                         rad_assert(g->cond != NULL);
1913
1914                         return csingle;
1915
1916                 } else  if (strcmp(modrefname, "elsif") == 0) {
1917                         modgroup *g;
1918
1919                         if (parent &&
1920                             ((parent->type == MOD_LOAD_BALANCE) ||
1921                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1922                                 cf_log_err(ci, "'elsif' cannot be used in this section.");
1923                                 return NULL;
1924                         }
1925
1926                         if (!cf_section_name2(cs)) {
1927                                 cf_log_err(ci, "'elsif' without condition.");
1928                                 return NULL;
1929                         }
1930
1931                         *modname = name2;
1932                         csingle= do_compile_modgroup(parent, component, cs,
1933                                                      GROUPTYPE_SIMPLE,
1934                                                      grouptype);
1935                         if (!csingle) return NULL;
1936                         csingle->type = MOD_ELSIF;
1937                         *modname = name2;
1938
1939                         g = mod_callabletogroup(csingle);
1940                         g->cond = cf_data_find(g->cs, "if");
1941                         rad_assert(g->cond != NULL);
1942
1943                         return csingle;
1944
1945                 } else  if (strcmp(modrefname, "else") == 0) {
1946                         if (parent &&
1947                             ((parent->type == MOD_LOAD_BALANCE) ||
1948                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
1949                                 cf_log_err(ci, "'else' cannot be used in this section section.");
1950                                 return NULL;
1951                         }
1952
1953                         if (cf_section_name2(cs)) {
1954                                 cf_log_err(ci, "Cannot have conditions on 'else'.");
1955                                 return NULL;
1956                         }
1957
1958                         *modname = name2;
1959                         csingle= do_compile_modgroup(parent, component, cs,
1960                                                      GROUPTYPE_SIMPLE,
1961                                                      grouptype);
1962                         if (!csingle) return NULL;
1963                         csingle->type = MOD_ELSE;
1964                         return csingle;
1965
1966                 } else  if (strcmp(modrefname, "update") == 0) {
1967                         *modname = name2;
1968
1969                         csingle = do_compile_modupdate(parent, component, cs,
1970                                                        name2);
1971                         if (!csingle) return NULL;
1972
1973                         return csingle;
1974
1975                 } else  if (strcmp(modrefname, "switch") == 0) {
1976                         *modname = name2;
1977
1978                         csingle = do_compile_modswitch(parent, component, cs);
1979                         if (!csingle) return NULL;
1980
1981                         return csingle;
1982
1983                 } else  if (strcmp(modrefname, "case") == 0) {
1984                         int i;
1985
1986                         *modname = name2;
1987
1988                         if (!parent) {
1989                                 cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
1990                                 return NULL;
1991                         }
1992
1993                         csingle= do_compile_modgroup(parent, component, cs,
1994                                                      GROUPTYPE_SIMPLE,
1995                                                      grouptype);
1996                         if (!csingle) return NULL;
1997                         csingle->type = MOD_CASE;
1998                         csingle->name = cf_section_name2(cs); /* may be NULL */
1999
2000                         /*
2001                          *      Set all of it's codes to return, so that
2002                          *      when we pick a 'case' statement, we don't
2003                          *      fall through to processing the next one.
2004                          */
2005                         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2006                                 csingle->actions[i] = MOD_ACTION_RETURN;
2007                         }
2008
2009                         return csingle;
2010
2011                 } else  if (strcmp(modrefname, "foreach") == 0) {
2012                         *modname = name2;
2013
2014                         csingle = do_compile_modforeach(parent, component, cs,
2015                                                         name2);
2016                         if (!csingle) return NULL;
2017
2018                         return csingle;
2019 #endif
2020                 } /* else it's something like sql { fail = 1 ...} */
2021
2022         } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2023                 return NULL;
2024
2025                 /*
2026                  *      Else it's a module reference, with updated return
2027                  *      codes.
2028                  */
2029         } else {
2030                 CONF_SECTION *loop;
2031                 CONF_PAIR *cp = cf_itemtopair(ci);
2032                 modrefname = cf_pair_attr(cp);
2033
2034                 /*
2035                  *      Actions (ok = 1), etc. are orthoganal to just
2036                  *      about everything else.
2037                  */
2038                 if (cf_pair_value(cp) != NULL) {
2039                         cf_log_err(ci, "Entry is not a reference to a module");
2040                         return NULL;
2041                 }
2042
2043                 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2044                     (modrefname[0] == '`')) {
2045                         return do_compile_modxlat(parent, component,
2046                                                   modrefname);
2047                 }
2048
2049                 /*
2050                  *      See if the module is a virtual one.  If so,
2051                  *      return that, rather than doing anything here.
2052                  */
2053                 subcs = NULL;
2054                 cs = cf_section_find("instantiate");
2055                 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2056                                                           modrefname);
2057                 if (!subcs &&
2058                     (cs = cf_section_find("policy")) != NULL) {
2059                         char buffer[256];
2060
2061                         snprintf(buffer, sizeof(buffer), "%s.%s",
2062                                  modrefname, comp2str[component]);
2063
2064                         /*
2065                          *      Prefer name.section, then name.
2066                          */
2067                         subcs = cf_section_sub_find_name2(cs, NULL,
2068                                                           buffer);
2069                         if (!subcs) {
2070                                 subcs = cf_section_sub_find_name2(cs, NULL,
2071                                                                   modrefname);
2072                         }
2073                 }
2074
2075                 /*
2076                  *      Allow policies to over-ride module names.
2077                  *      i.e. the "sql" policy can do some extra things,
2078                  *      and then call the "sql" module.
2079                  */
2080                 for (loop = cf_item_parent(ci);
2081                      loop && subcs;
2082                      loop = cf_item_parent(cf_sectiontoitem(loop))) {
2083                         if (loop == subcs) {
2084                                 subcs = NULL;
2085                         }
2086                 }
2087
2088                 if (subcs) {
2089                         /*
2090                          *      redundant foo {} is a single.
2091                          */
2092                         if (cf_section_name2(subcs)) {
2093                                 return do_compile_modsingle(parent,
2094                                                             component,
2095                                                             cf_sectiontoitem(subcs),
2096                                                             grouptype,
2097                                                             modname);
2098                         } else {
2099                                 /*
2100                                  *      foo {} is a group.
2101                                  */
2102                                 return do_compile_modgroup(parent,
2103                                                            component,
2104                                                            subcs,
2105                                                            GROUPTYPE_SIMPLE,
2106                                                            grouptype);
2107                         }
2108                 }
2109         }
2110
2111 #ifdef WITH_UNLANG
2112         if (strcmp(modrefname, "break") == 0) {
2113                 return do_compile_modbreak(parent, component, ci);
2114         }
2115 #endif
2116
2117         /*
2118          *      Not a virtual module.  It must be a real module.
2119          */
2120         modules = cf_section_find("modules");
2121         this = NULL;
2122         realname = modrefname;
2123
2124         if (modules) {
2125                 /*
2126                  *      Try to load the optional module.
2127                  */
2128                 if (realname[0] == '-') realname++;
2129
2130                 /*
2131                  *      As of v3, only known modules are in the
2132                  *      "modules" section.
2133                  */
2134                 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2135                         this = find_module_instance(modules, realname, 1);
2136                         if (!this && (realname != modrefname)) {
2137                                 return NULL;
2138                         }
2139
2140                 } else {
2141                         /*
2142                          *      We were asked to MAYBE load it and it
2143                          *      doesn't exist.  Return a soft error.
2144                          */
2145                         if (realname != modrefname) {
2146                                 *modname = modrefname;
2147                                 return NULL;
2148                         }
2149                 }
2150         }
2151
2152         if (!this) do {
2153                 int i;
2154                 char *p;
2155
2156                 /*
2157                  *      Maybe it's module.method
2158                  */
2159                 p = strrchr(modrefname, '.');
2160                 if (p) for (i = RLM_COMPONENT_AUTH;
2161                             i < RLM_COMPONENT_COUNT;
2162                             i++) {
2163                         if (strcmp(p + 1, comp2str[i]) == 0) {
2164                                 char buffer[256];
2165
2166                                 strlcpy(buffer, modrefname, sizeof(buffer));
2167                                 buffer[p - modrefname] = '\0';
2168                                 component = i;
2169
2170                                 this = find_module_instance(modules, buffer, 1);
2171                                 if (this &&
2172                                     !this->entry->module->methods[i]) {
2173                                         *modname = NULL;
2174                                         cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2175                                         return NULL;
2176                                 }
2177                                 break;
2178                         }
2179                 }
2180                 if (this) break;
2181
2182                 /*
2183                  *      Call a server.  This should really be deleted...
2184                  */
2185                 if (strncmp(modrefname, "server[", 7) == 0) {
2186                         char buffer[256];
2187
2188                         strlcpy(buffer, modrefname + 7, sizeof(buffer));
2189                         p = strrchr(buffer, ']');
2190                         if (!p || p[1] != '\0' || (p == buffer)) {
2191                                 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2192                                 return NULL;
2193                         }
2194                         *p = '\0';
2195
2196                         cs = cf_section_sub_find_name2(NULL, "server", buffer);
2197                         if (!cs) {
2198                                 cf_log_err(ci, "No such server \"%s\".", buffer);
2199                                 return NULL;
2200                         }
2201
2202                         return do_compile_modserver(parent, component, ci,
2203                                                     modrefname, cs, buffer);
2204                 }
2205
2206                 *modname = NULL;
2207                 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2208                 return NULL;
2209         } while (0);
2210
2211         /*
2212          *      We know it's all OK, allocate the structures, and fill
2213          *      them in.
2214          */
2215         single = rad_malloc(sizeof(*single));
2216         memset(single, 0, sizeof(*single));
2217         csingle = mod_singletocallable(single);
2218         csingle->parent = parent;
2219         csingle->next = NULL;
2220         if (!parent || (component != RLM_COMPONENT_AUTH)) {
2221                 memcpy(csingle->actions, defaultactions[component][grouptype],
2222                        sizeof csingle->actions);
2223         } else { /* inside Auth-Type has different rules */
2224                 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2225                        sizeof csingle->actions);
2226         }
2227         rad_assert(modrefname != NULL);
2228         csingle->name = realname;
2229         csingle->type = MOD_SINGLE;
2230         csingle->method = component;
2231
2232         /*
2233          *      Singles can override the actions, virtual modules cannot.
2234          *
2235          *      FIXME: We may want to re-visit how to do this...
2236          *      maybe a csingle as a ref?
2237          */
2238         if (cf_item_is_section(ci)) {
2239                 CONF_ITEM *csi;
2240
2241                 cs = cf_itemtosection(ci);
2242                 for (csi=cf_item_find_next(cs, NULL);
2243                      csi != NULL;
2244                      csi=cf_item_find_next(cs, csi)) {
2245
2246                         if (cf_item_is_section(csi)) {
2247                                 cf_log_err(csi, "Subsection of module instance call not allowed");
2248                                 modcallable_free(&csingle);
2249                                 return NULL;
2250                         }
2251
2252                         if (!cf_item_is_pair(csi)) continue;
2253
2254                         if (!compile_action(csingle, cf_itemtopair(csi))) {
2255                                 modcallable_free(&csingle);
2256                                 return NULL;
2257                         }
2258                 }
2259         }
2260
2261         /*
2262          *      Bail out if the module in question does not supply the
2263          *      wanted component
2264          */
2265         if (!this->entry->module->methods[component]) {
2266                 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2267                        comp2str[component]);
2268                 modcallable_free(&csingle);
2269                 return NULL;
2270         }
2271
2272         single->modinst = this;
2273         *modname = this->entry->module->name;
2274         return csingle;
2275 }
2276
2277 modcallable *compile_modsingle(modcallable *parent,
2278                                rlm_components_t component, CONF_ITEM *ci,
2279                                char const **modname)
2280 {
2281         modcallable *ret = do_compile_modsingle(parent, component, ci,
2282                                                 GROUPTYPE_SIMPLE,
2283                                                 modname);
2284         dump_tree(component, ret);
2285         return ret;
2286 }
2287
2288
2289 /*
2290  *      Internal compile group code.
2291  */
2292 static modcallable *do_compile_modgroup(modcallable *parent,
2293                                         rlm_components_t component, CONF_SECTION *cs,
2294                                         int grouptype, int parentgrouptype)
2295 {
2296         int i;
2297         modgroup *g;
2298         modcallable *c;
2299         CONF_ITEM *ci;
2300
2301         g = rad_malloc(sizeof(*g));
2302         memset(g, 0, sizeof(*g));
2303         g->grouptype = grouptype;
2304         g->children = NULL;
2305         g->cs = cs;
2306
2307         c = mod_grouptocallable(g);
2308         c->parent = parent;
2309         c->type = MOD_GROUP;
2310         c->next = NULL;
2311         memset(c->actions, 0, sizeof(c->actions));
2312
2313         if (!cs) {              /* only for "break" */
2314                 c->name = "";
2315                 goto set_codes;
2316         }
2317
2318         /*
2319          *      Remember the name for printing, etc.
2320          *
2321          *      FIXME: We may also want to put the names into a
2322          *      rbtree, so that groups can reference each other...
2323          */
2324         c->name = cf_section_name2(cs);
2325         if (!c->name) {
2326                 c->name = cf_section_name1(cs);
2327                 if (strcmp(c->name, "group") == 0) {
2328                         c->name = "";
2329                 } else {
2330                         c->type = MOD_POLICY;
2331                 }
2332         }
2333
2334         /*
2335          *      Loop over the children of this group.
2336          */
2337         for (ci=cf_item_find_next(cs, NULL);
2338              ci != NULL;
2339              ci=cf_item_find_next(cs, ci)) {
2340
2341                 /*
2342                  *      Sections are references to other groups, or
2343                  *      to modules with updated return codes.
2344                  */
2345                 if (cf_item_is_section(ci)) {
2346                         char const *junk = NULL;
2347                         modcallable *single;
2348                         CONF_SECTION *subcs = cf_itemtosection(ci);
2349
2350                         single = do_compile_modsingle(c, component, ci,
2351                                                       grouptype, &junk);
2352                         if (!single) {
2353                                 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2354                                        cf_section_name1(subcs));
2355                                 modcallable_free(&c);
2356                                 return NULL;
2357                         }
2358                         add_child(g, single);
2359
2360                 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2361                         continue;
2362
2363                 } else {
2364                         char const *attr, *value;
2365                         CONF_PAIR *cp = cf_itemtopair(ci);
2366
2367                         attr = cf_pair_attr(cp);
2368                         value = cf_pair_value(cp);
2369
2370                         /*
2371                          *      A CONF_PAIR is either a module
2372                          *      instance with no actions
2373                          *      specified ...
2374                          */
2375                         if (!value) {
2376                                 modcallable *single;
2377                                 char const *junk = NULL;
2378
2379                                 single = do_compile_modsingle(c,
2380                                                               component,
2381                                                               ci,
2382                                                               grouptype,
2383                                                               &junk);
2384                                 if (!single) {
2385                                         if (cf_item_is_pair(ci) &&
2386                                             cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2387                                                 continue;
2388                                         }
2389
2390                                         cf_log_err(ci,
2391                                                    "Failed to parse \"%s\" entry.",
2392                                                    attr);
2393                                         modcallable_free(&c);
2394                                         return NULL;
2395                                 }
2396                                 add_child(g, single);
2397
2398                                 /*
2399                                  *      Or a module instance with action.
2400                                  */
2401                         } else if (!compile_action(c, cp)) {
2402                                 modcallable_free(&c);
2403                                 return NULL;
2404                         } /* else it worked */
2405                 }
2406         }
2407
2408 set_codes:
2409         /*
2410          *      Set the default actions, if they haven't already been
2411          *      set.
2412          */
2413         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2414                 if (!c->actions[i]) {
2415                         if (!parent || (component != RLM_COMPONENT_AUTH)) {
2416                                 c->actions[i] = defaultactions[component][parentgrouptype][i];
2417                         } else { /* inside Auth-Type has different rules */
2418                                 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2419                         }
2420                 }
2421         }
2422
2423         /*
2424          *      FIXME: If there are no children, return NULL?
2425          */
2426         return mod_grouptocallable(g);
2427 }
2428
2429 modcallable *compile_modgroup(modcallable *parent,
2430                               rlm_components_t component, CONF_SECTION *cs)
2431 {
2432         modcallable *ret = do_compile_modgroup(parent, component, cs,
2433                                                GROUPTYPE_SIMPLE,
2434                                                GROUPTYPE_SIMPLE);
2435         dump_tree(component, ret);
2436         return ret;
2437 }
2438
2439 void add_to_modcallable(modcallable **parent, modcallable *this,
2440                         rlm_components_t component, char const *name)
2441 {
2442         modgroup *g;
2443
2444         rad_assert(this != NULL);
2445
2446         if (*parent == NULL) {
2447                 modcallable *c;
2448
2449                 g = rad_malloc(sizeof *g);
2450                 memset(g, 0, sizeof(*g));
2451                 g->grouptype = GROUPTYPE_SIMPLE;
2452                 c = mod_grouptocallable(g);
2453                 c->next = NULL;
2454                 memcpy(c->actions,
2455                        defaultactions[component][GROUPTYPE_SIMPLE],
2456                        sizeof(c->actions));
2457                 rad_assert(name != NULL);
2458                 c->name = name;
2459                 c->type = MOD_GROUP;
2460                 c->method = component;
2461                 g->children = NULL;
2462
2463                 *parent = mod_grouptocallable(g);
2464         } else {
2465                 g = mod_callabletogroup(*parent);
2466         }
2467
2468         add_child(g, this);
2469 }
2470
2471 void modcallable_free(modcallable **pc)
2472 {
2473         modcallable *c, *loop, *next;
2474
2475         if (!pc || !*pc) return;
2476
2477         c = *pc;
2478
2479         if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
2480                 modgroup *g = mod_callabletogroup(c);
2481
2482                 if (g->children) for (loop = g->children;
2483                     loop ;
2484                     loop = next) {
2485                         next = loop->next;
2486                         modcallable_free(&loop);
2487                 }
2488                 talloc_free(g->map);
2489         }
2490         free(c);
2491         *pc = NULL;
2492 }
2493
2494
2495 #ifdef WITH_UNLANG
2496 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
2497 {
2498         value_pair_map_t *map;
2499
2500         /*
2501          *      Maps have a paircompare fixup applied to them.
2502          *      Others get ignored.
2503          */
2504         if (c->pass2_fixup == PASS2_FIXUP_NONE) {
2505                 if (c->type == COND_TYPE_MAP) {
2506                         map = c->data.map;
2507                         goto check_paircmp;
2508                 }
2509                 return true;
2510         }
2511
2512         map = c->data.map;      /* shorter */
2513
2514         /*
2515          *      Auth-Type := foo
2516          *
2517          *      Where "foo" is dynamically defined.
2518          */
2519         if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
2520                 if (!dict_valbyname(map->dst->da->attr,
2521                                     map->dst->da->vendor,
2522                                     map->src->name)) {
2523                         cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
2524                                    map->dst->da->name,
2525                                    map->src->name);
2526                         return false;
2527                 }
2528
2529                 /*
2530                  *      These guys can't have a paircompare fixup applied.
2531                  */
2532                 c->pass2_fixup = PASS2_FIXUP_NONE;
2533                 return true;
2534         }
2535
2536         if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
2537                 value_pair_map_t *old;
2538                 value_pair_tmpl_t vpt;
2539
2540                 old = c->data.map;
2541
2542                 /*
2543                  *      It's still not an attribute.  Ignore it.
2544                  */
2545                 if (radius_parse_attr(&vpt, map->dst->name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
2546                         cf_log_err(old->ci, "Failed parsing condition: %s", fr_strerror());
2547                         c->pass2_fixup = PASS2_FIXUP_NONE;
2548                         return true;
2549                 }
2550
2551                 /*
2552                  *      Re-parse the LHS as an attribute.
2553                  */
2554                 map = radius_str2map(c, old->dst->name, T_BARE_WORD, old->op,
2555                                      old->src->name, T_BARE_WORD,
2556                                      REQUEST_CURRENT, PAIR_LIST_REQUEST,
2557                                      REQUEST_CURRENT, PAIR_LIST_REQUEST);
2558                 if (!map) {
2559                         cf_log_err(old->ci, "Failed parsing condition");
2560                         return false;
2561                 }
2562                 map->ci = old->ci;
2563                 talloc_free(old);
2564                 c->data.map = map;
2565                 c->pass2_fixup = PASS2_FIXUP_NONE;
2566         }
2567
2568 check_paircmp:
2569         /*
2570          *      Just in case someone adds a new fixup later.
2571          */
2572         rad_assert(c->pass2_fixup == PASS2_FIXUP_NONE);
2573
2574         /*
2575          *      Only attributes can have a paircompare registered, and
2576          *      they can only be with the current REQUEST, and only
2577          *      with the request pairs.
2578          */
2579         if ((map->dst->type != VPT_TYPE_ATTR) ||
2580             (map->dst->request != REQUEST_CURRENT) ||
2581             (map->dst->list != PAIR_LIST_REQUEST)) {
2582                 return true;
2583         }
2584
2585         if (!radius_find_compare(map->dst->da)) return true;
2586
2587         if (map->src->type == VPT_TYPE_ATTR) {
2588                 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
2589                            map->dst->name);
2590                 return false;
2591         }
2592
2593         if (map->src->type == VPT_TYPE_REGEX) {
2594                 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
2595                            map->dst->name);
2596                 return false;
2597         }
2598
2599         if (c->cast) {
2600                 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
2601                            map->dst->name);
2602                 return false;
2603         }
2604
2605         if (map->op != T_OP_CMP_EQ) {
2606                 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
2607                            map->dst->name);
2608                 return false;
2609         }
2610
2611         /*
2612          *      Mark it as requiring a paircompare() call, instead of
2613          *      paircmp().
2614          */
2615         c->pass2_fixup = PASS2_PAIRCOMPARE;
2616
2617         return true;
2618 }
2619 #endif
2620
2621 /*
2622  *      Do a second-stage pass on compiling the modules.
2623  */
2624 bool modcall_pass2(modcallable *mc)
2625 {
2626         modcallable *this;
2627         modgroup *g;
2628
2629         for (this = mc; this != NULL; this = this->next) {
2630                 switch (this->type) {
2631                 default:
2632                         rad_assert(0 == 1);
2633                         break;
2634
2635                 case MOD_SINGLE:
2636 #ifdef WITH_UNLANG
2637                 case MOD_UPDATE: /* @todo: pre-parse xlat's */
2638                 case MOD_XLAT:   /* @todo: pre-parse xlat's */
2639                 case MOD_BREAK:
2640                 case MOD_REFERENCE:
2641 #endif
2642                         break;  /* do nothing */
2643
2644 #ifdef WITH_UNLANG
2645                 case MOD_IF:
2646                 case MOD_ELSIF:
2647                         g = mod_callabletogroup(this);
2648                         if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
2649                                 return false;
2650                         }
2651                         /* FALL-THROUGH */
2652 #endif
2653
2654                 case MOD_GROUP:
2655                 case MOD_LOAD_BALANCE:
2656                 case MOD_REDUNDANT_LOAD_BALANCE:
2657
2658 #ifdef WITH_UNLANG
2659                 case MOD_ELSE:
2660                 case MOD_SWITCH:
2661                 case MOD_CASE:
2662                 case MOD_FOREACH:
2663                 case MOD_POLICY:
2664 #endif
2665                         g = mod_callabletogroup(this);
2666                         if (!modcall_pass2(g->children)) return false;
2667                         break;
2668                 }
2669         }
2670
2671         return true;
2672 }