Merge pull request #857 from spbnick/move_trigger_include
[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, 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         char const *debug_name;
52         enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
53 #ifdef WITH_UNLANG
54                MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
55                MOD_FOREACH, MOD_BREAK, MOD_RETURN,
56 #endif
57                MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
58         rlm_components_t method;
59         int actions[RLM_MODULE_NUMCODES];
60 };
61
62 #define MOD_LOG_OPEN_BRACE RDEBUG2("%s {", c->debug_name)
63
64 #define MOD_LOG_CLOSE_BRACE RDEBUG2("} # %s = %s", c->debug_name, 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         modcallable             *tail;          /* of the children list */
76         CONF_SECTION            *cs;
77         value_pair_map_t        *map;           /* update */
78         value_pair_tmpl_t       *vpt;           /* switch */
79         fr_cond_t               *cond;          /* if/elsif */
80         bool                    done_pass2;
81 } modgroup;
82
83 typedef struct {
84         modcallable mc;
85         module_instance_t *modinst;
86 } modsingle;
87
88 typedef struct {
89         modcallable mc;
90         char const *ref_name;
91         CONF_SECTION *ref_cs;
92 } modref;
93
94 typedef struct {
95         modcallable mc;
96         int exec;
97         char *xlat_name;
98 } modxlat;
99
100 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
101  * so we often want to go back and forth between them. */
102 static modsingle *mod_callabletosingle(modcallable *p)
103 {
104         rad_assert(p->type==MOD_SINGLE);
105         return (modsingle *)p;
106 }
107 static modgroup *mod_callabletogroup(modcallable *p)
108 {
109         rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
110
111         return (modgroup *)p;
112 }
113 static modcallable *mod_singletocallable(modsingle *p)
114 {
115         return (modcallable *)p;
116 }
117 static modcallable *mod_grouptocallable(modgroup *p)
118 {
119         return (modcallable *)p;
120 }
121
122 static modref *mod_callabletoref(modcallable *p)
123 {
124         rad_assert(p->type==MOD_REFERENCE);
125         return (modref *)p;
126 }
127 static modcallable *mod_reftocallable(modref *p)
128 {
129         return (modcallable *)p;
130 }
131
132 static modxlat *mod_callabletoxlat(modcallable *p)
133 {
134         rad_assert(p->type==MOD_XLAT);
135         return (modxlat *)p;
136 }
137 static modcallable *mod_xlattocallable(modxlat *p)
138 {
139         return (modcallable *)p;
140 }
141
142 /* modgroups are grown by adding a modcallable to the end */
143 static void add_child(modgroup *g, modcallable *c)
144 {
145         if (!c) return;
146
147         (void) talloc_steal(g, c);
148
149         if (!g->children) {
150                 g->children = g->tail = c;
151         } else {
152                 rad_assert(g->tail->next == NULL);
153                 g->tail->next = c;
154                 g->tail = c;
155         }
156
157         c->parent = mod_grouptocallable(g);
158 }
159
160 /* Here's where we recognize all of our keywords: first the rcodes, then the
161  * actions */
162 const FR_NAME_NUMBER mod_rcode_table[] = {
163         { "reject",     RLM_MODULE_REJECT       },
164         { "fail",       RLM_MODULE_FAIL  },
165         { "ok",         RLM_MODULE_OK      },
166         { "handled",    RLM_MODULE_HANDLED      },
167         { "invalid",    RLM_MODULE_INVALID      },
168         { "userlock",   RLM_MODULE_USERLOCK     },
169         { "notfound",   RLM_MODULE_NOTFOUND     },
170         { "noop",       RLM_MODULE_NOOP  },
171         { "updated",    RLM_MODULE_UPDATED      },
172         { NULL, 0 }
173 };
174
175
176 static char const *group_name[];
177
178 /*
179  *      Compile action && rcode for later use.
180  */
181 static int compile_action(modcallable *c, CONF_PAIR *cp)
182 {
183         int action;
184         char const *attr, *value;
185
186         attr = cf_pair_attr(cp);
187         value = cf_pair_value(cp);
188         if (!value) return 0;
189
190         if (c->type != MOD_SINGLE) {
191                 ERROR("%s[%d] Invalid return code assigment inside of a %s section",
192                       cf_pair_filename(cp), cf_pair_lineno(cp), group_name[c->type]);
193                 return 0;
194         }
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 CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
285 {
286         int blocked;
287         int indent = request->log.indent;
288
289         /*
290          *      If the request should stop, refuse to do anything.
291          */
292         blocked = (request->master_state == REQUEST_STOP_PROCESSING);
293         if (blocked) return RLM_MODULE_NOOP;
294
295         RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
296                 comp2str[component], sp->modinst->name,
297                 sp->modinst->entry->name, request->number);
298         request->log.indent = 0;
299
300         if (sp->modinst->force) {
301                 request->rcode = sp->modinst->code;
302                 goto fail;
303         }
304
305         /*
306          *      For logging unresponsive children.
307          */
308         request->module = sp->modinst->name;
309
310         safe_lock(sp->modinst);
311         request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
312         safe_unlock(sp->modinst);
313
314         request->module = "";
315
316         /*
317          *      Wasn't blocked, and now is.  Complain!
318          */
319         blocked = (request->master_state == REQUEST_STOP_PROCESSING);
320         if (blocked) {
321                 RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
322         }
323
324  fail:
325         request->log.indent = indent;
326         RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
327                comp2str[component], sp->modinst->name,
328                sp->modinst->entry->name, request->number);
329
330         return request->rcode;
331 }
332
333 static int default_component_results[RLM_COMPONENT_COUNT] = {
334         RLM_MODULE_REJECT,      /* AUTH */
335         RLM_MODULE_NOTFOUND,    /* AUTZ */
336         RLM_MODULE_NOOP,        /* PREACCT */
337         RLM_MODULE_NOOP,        /* ACCT */
338         RLM_MODULE_FAIL,        /* SESS */
339         RLM_MODULE_NOOP,        /* PRE_PROXY */
340         RLM_MODULE_NOOP,        /* POST_PROXY */
341         RLM_MODULE_NOOP         /* POST_AUTH */
342 #ifdef WITH_COA
343         ,
344         RLM_MODULE_NOOP,        /* RECV_COA_TYPE */
345         RLM_MODULE_NOOP         /* SEND_COA_TYPE */
346 #endif
347 };
348
349
350 static char const *group_name[] = {
351         "",
352         "single",
353         "group",
354         "load-balance group",
355         "redundant-load-balance group",
356 #ifdef WITH_UNLANG
357         "if",
358         "else",
359         "elsif",
360         "update",
361         "switch",
362         "case",
363         "foreach",
364         "break",
365         "return",
366 #endif
367         "policy",
368         "reference",
369         "xlat"
370 };
371
372 static char const modcall_spaces[] = "                                                                ";
373
374 #define MODCALL_STACK_MAX (32)
375
376 /*
377  *      Don't call the modules recursively.  Instead, do them
378  *      iteratively, and manage the call stack ourselves.
379  */
380 typedef struct modcall_stack_entry_t {
381         rlm_rcode_t result;
382         int priority;
383         int unwind;             /* unwind to this one if it exists */
384         modcallable *c;
385 } modcall_stack_entry_t;
386
387
388 static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
389                             modcall_stack_entry_t *entry);
390
391 /*
392  *      Call a child of a block.
393  */
394 static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
395                           modcall_stack_entry_t *entry, modcallable *c,
396                           rlm_rcode_t *result)
397 {
398         modcall_stack_entry_t *next;
399
400         if (depth >= MODCALL_STACK_MAX) {
401                 ERROR("Internal sanity check failed: module stack is too deep");
402                 fr_exit(1);
403         }
404
405         /*
406          *      Initialize the childs stack frame.
407          */
408         next = entry + 1;
409         next->c = c;
410         next->result = entry->result;
411         next->priority = 0;
412         next->unwind = 0;
413
414         if (!modcall_recurse(request, component,
415                              depth, next)) {
416                 *result = RLM_MODULE_FAIL;
417                  return;
418         }
419
420         /*
421          *      Unwind back up the stack
422          */
423         if (next->unwind != 0) {
424                 entry->unwind = next->unwind;
425         }
426
427         *result = next->result;
428
429         return;
430 }
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         RINDENT();
447
448 redo:
449         priority = -1;
450         c = entry->c;
451
452         /*
453          *      Nothing more to do.  Return the code and priority
454          *      which was set by the caller.
455          */
456         if (!c) goto finish;
457
458         /*
459          *      We've been asked to stop.  Do so.
460          */
461         if ((request->master_state == REQUEST_STOP_PROCESSING) ||
462             (request->parent &&
463              (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
464                 entry->result = RLM_MODULE_FAIL;
465                 entry->priority = 9999;
466                 goto finish;
467         }
468
469 #ifdef WITH_UNLANG
470         /*
471          *      Handle "if" conditions.
472          */
473         if (c->type == MOD_IF) {
474                 int condition;
475                 modgroup *g;
476
477         mod_if:
478                 g = mod_callabletogroup(c);
479                 rad_assert(g->cond != NULL);
480
481                 RDEBUG2("%s %s{", 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",
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("... skipping %s for request %d: Preceding \"if\" was taken",
522                                 group_name[c->type], request->number);
523                         was_if = true;
524                         if_taken = true;
525                         goto next_sibling;
526                 }
527
528                 /*
529                  *      Check the "if" condition.
530                  */
531                 goto mod_if;
532         } /* MOD_ELSIF */
533
534         /*
535          *      "else" for a preceding "if".
536          */
537         if (c->type == MOD_ELSE) {
538                 if (!was_if) { /* error */
539                 elsif_error:
540                         RDEBUG2("... skipping %s for request %d: No preceding \"if\"",
541                                 group_name[c->type], request->number);
542                         goto next_sibling;
543                 }
544
545                 if (if_taken) {
546                         RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
547                                 group_name[c->type], request->number);
548                         was_if = false;
549                         if_taken = false;
550                         goto next_sibling;
551                 }
552
553                 /*
554                  *      We need to process it.  Go do that.
555                  */
556                 was_if = false;
557                 if_taken = false;
558                 goto do_children;
559         } /* MOD_ELSE */
560
561         /*
562          *      We're no longer processing if/else/elsif.  Reset the
563          *      trackers for those conditions.
564          */
565         was_if = false;
566         if_taken = false;
567 #endif  /* WITH_UNLANG */
568
569         if (c->type == MOD_SINGLE) {
570                 modsingle *sp;
571
572                 /*
573                  *      Process a stand-alone child, and fall through
574                  *      to dealing with it's parent.
575                  */
576                 sp = mod_callabletosingle(c);
577
578                 result = call_modsingle(c->method, sp, request);
579                 RDEBUG2("[%s] = %s", c->name ? c->name : "",
580                         fr_int2str(mod_rcode_table, result, "<invalid>"));
581                 goto calculate_result;
582         } /* MOD_SINGLE */
583
584 #ifdef WITH_UNLANG
585         /*
586          *      Update attribute(s)
587          */
588         if (c->type == MOD_UPDATE) {
589                 int rcode;
590                 modgroup *g = mod_callabletogroup(c);
591                 value_pair_map_t *map;
592
593                 MOD_LOG_OPEN_BRACE;
594                 RINDENT();
595                 for (map = g->map; map != NULL; map = map->next) {
596                         rcode = map_to_request(request, map, map_to_vp, NULL);
597                         if (rcode < 0) {
598                                 result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
599                                 REXDENT();
600                                 MOD_LOG_CLOSE_BRACE;
601                                 goto calculate_result;
602                         }
603                 }
604                 REXDENT();
605                 result = RLM_MODULE_NOOP;
606                 MOD_LOG_CLOSE_BRACE;
607                 goto calculate_result;
608         } /* MOD_IF */
609
610         /*
611          *      Loop over a set of attributes.
612          */
613         if (c->type == MOD_FOREACH) {
614                 int i, foreach_depth = -1;
615                 VALUE_PAIR *vps, *vp;
616                 modcall_stack_entry_t *next = NULL;
617                 vp_cursor_t copy;
618                 modgroup *g = mod_callabletogroup(c);
619
620                 if (depth >= MODCALL_STACK_MAX) {
621                         ERROR("Internal sanity check failed: module stack is too deep");
622                         fr_exit(1);
623                 }
624
625                 /*
626                  *      Figure out how deep we are in nesting by looking at request_data
627                  *      stored previously.
628                  */
629                 for (i = 0; i < 8; i++) {
630                         if (!request_data_reference(request,
631                                                     radius_get_vp, i)) {
632                                 foreach_depth = i;
633                                 break;
634                         }
635                 }
636
637                 if (foreach_depth < 0) {
638                         REDEBUG("foreach Nesting too deep!");
639                         result = RLM_MODULE_FAIL;
640                         goto calculate_result;
641                 }
642
643                 /*
644                  *      Copy the VPs from the original request, this ensures deterministic
645                  *      behaviour if someone decides to add or remove VPs in the set were
646                  *      iterating over.
647                  */
648                 if (tmpl_copy_vps(request, &vps, request, g->vpt) < 0) {        /* nothing to loop over */
649                         MOD_LOG_OPEN_BRACE;
650                         result = RLM_MODULE_NOOP;
651                         MOD_LOG_CLOSE_BRACE;
652                         goto calculate_result;
653                 }
654
655                 rad_assert(vps != NULL);
656                 fr_cursor_init(&copy, &vps);
657
658                 RDEBUG2("foreach %s ", c->name);
659
660                 /*
661                  *      This is the actual body of the foreach loop
662                  */
663                 for (vp = fr_cursor_first(&copy);
664                      vp != NULL;
665                      vp = fr_cursor_next(&copy)) {
666 #ifndef NDEBUG
667                         if (fr_debug_flag >= 2) {
668                                 char buffer[1024];
669
670                                 vp_prints_value(buffer, sizeof(buffer), vp, '"');
671                                 RDEBUG2("# Foreach-Variable-%d = %s", foreach_depth, buffer);
672                         }
673 #endif
674
675                         /*
676                          *      Add the vp to the request, so that
677                          *      xlat.c, xlat_foreach() can find it.
678                          */
679                         request_data_add(request, radius_get_vp, foreach_depth, &vp, false);
680
681                         /*
682                          *      Initialize the childs stack frame.
683                          */
684                         next = entry + 1;
685                         next->c = g->children;
686                         next->result = entry->result;
687                         next->priority = 0;
688                         next->unwind = 0;
689
690                         if (!modcall_recurse(request, component, depth + 1, next)) {
691                                 break;
692                         }
693
694                         /*
695                          *      We've unwound to the enclosing
696                          *      "foreach".  Stop the unwinding.
697                          */
698                         if (next->unwind == MOD_FOREACH) {
699                                 break;
700                         }
701
702                         /*
703                          *      Unwind all the way.
704                          */
705                         if (next->unwind == MOD_RETURN) {
706                                 entry->unwind = MOD_RETURN;
707                                 break;
708                         }
709                 } /* loop over VPs */
710
711                 /*
712                  *      Free the copied vps and the request data
713                  *      If we don't remove the request data, something could call
714                  *      the xlat outside of a foreach loop and trigger a segv.
715                  */
716                 pairfree(&vps);
717                 request_data_get(request, radius_get_vp, foreach_depth);
718
719                 rad_assert(next != NULL);
720                 result = next->result;
721                 priority = next->priority;
722                 MOD_LOG_CLOSE_BRACE;
723                 goto calculate_result;
724         } /* MOD_FOREACH */
725
726         /*
727          *      Break out of a "foreach" loop, or return from a nested
728          *      group.
729          */
730         if ((c->type == MOD_BREAK) || (c->type == MOD_RETURN)) {
731                 int i;
732                 VALUE_PAIR **copy_p;
733
734                 RDEBUG2("%s", group_name[c->type]);
735
736                 for (i = 8; i >= 0; i--) {
737                         copy_p = request_data_get(request, radius_get_vp, i);
738                         if (copy_p) {
739                                 if (c->type == MOD_BREAK) {
740                                         RDEBUG2("# break Foreach-Variable-%d", i);
741                                         break;
742                                 }
743                         }
744                 }
745
746                 /*
747                  *      Leave result / priority on the stack, and stop processing the section.
748                  */
749                 entry->unwind = c->type;
750                 goto finish;
751         } /* MOD_BREAK */
752
753 #endif    /* WITH_UNLANG */
754
755         /*
756          *      Child is a group that has children of it's own.
757          */
758         if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
759 #ifdef WITH_UNLANG
760             || (c->type == MOD_CASE)
761 #endif
762                 ) {
763                 modgroup *g;
764
765 #ifdef WITH_UNLANG
766         do_children:
767 #endif
768                 g = mod_callabletogroup(c);
769
770                 /*
771                  *      This should really have been caught in the
772                  *      compiler, and the node never generated.  But
773                  *      doing that requires changing it's API so that
774                  *      it returns a flag instead of the compiled
775                  *      MOD_GROUP.
776                  */
777                 if (!g->children) {
778                         RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
779                         goto next_sibling;
780                 }
781
782                 MOD_LOG_OPEN_BRACE;
783                 modcall_child(request, component,
784                               depth + 1, entry, g->children,
785                               &result);
786                 MOD_LOG_CLOSE_BRACE;
787                 goto calculate_result;
788         } /* MOD_GROUP */
789
790 #ifdef WITH_UNLANG
791         if (c->type == MOD_SWITCH) {
792                 modcallable *this, *found, *null_case;
793                 modgroup *g, *h;
794                 fr_cond_t cond;
795                 value_data_t data;
796                 value_pair_map_t map;
797                 value_pair_tmpl_t vpt;
798
799                 MOD_LOG_OPEN_BRACE;
800
801                 g = mod_callabletogroup(c);
802
803                 memset(&cond, 0, sizeof(cond));
804                 memset(&map, 0, sizeof(map));
805
806                 cond.type = COND_TYPE_MAP;
807                 cond.data.map = &map;
808
809                 map.op = T_OP_CMP_EQ;
810                 map.ci = cf_sectiontoitem(g->cs);
811
812                 rad_assert(g->vpt != NULL);
813
814                 null_case = found = NULL;
815                 data.ptr = NULL;
816
817                 /*
818                  *      The attribute doesn't exist.  We can skip
819                  *      directly to the default 'case' statement.
820                  */
821                 if ((g->vpt->type == TMPL_TYPE_ATTR) && (tmpl_find_vp(NULL, request, g->vpt) < 0)) {
822                 find_null_case:
823                         for (this = g->children; this; this = this->next) {
824                                 rad_assert(this->type == MOD_CASE);
825
826                                 h = mod_callabletogroup(this);
827                                 if (h->vpt) continue;
828
829                                 found = this;
830                                 break;
831                         }
832
833                         goto do_null_case;
834                 }
835
836                 /*
837                  *      Expand the template if necessary, so that it
838                  *      is evaluated once instead of for each 'case'
839                  *      statement.
840                  */
841                 if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
842                     (g->vpt->type == TMPL_TYPE_XLAT) ||
843                     (g->vpt->type == TMPL_TYPE_EXEC)) {
844                         if (radius_expand_tmpl(&data, request, g->vpt) < 0) goto find_null_case;
845                         tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
846                 }
847
848                 /*
849                  *      Find either the exact matching name, or the
850                  *      "case {...}" statement.
851                  */
852                 for (this = g->children; this; this = this->next) {
853                         rad_assert(this->type == MOD_CASE);
854
855                         h = mod_callabletogroup(this);
856
857                         /*
858                          *      Remember the default case
859                          */
860                         if (!h->vpt) {
861                                 if (!null_case) null_case = this;
862                                 continue;
863                         }
864
865                         /*
866                          *      If we're switching over an attribute
867                          *      AND we haven't pre-parsed the data for
868                          *      the case statement, then cast the data
869                          *      to the type of the attribute.
870                          */
871                         if ((g->vpt->type == TMPL_TYPE_ATTR) &&
872                             (h->vpt->type != TMPL_TYPE_DATA)) {
873                                 map.rhs = g->vpt;
874                                 map.lhs = h->vpt;
875                                 cond.cast = g->vpt->tmpl_da;
876
877                                 /*
878                                  *      Remove unnecessary casting.
879                                  */
880                                 if ((h->vpt->type == TMPL_TYPE_ATTR) &&
881                                     (g->vpt->tmpl_da->type == h->vpt->tmpl_da->type)) {
882                                         cond.cast = NULL;
883                                 }
884
885                                 /*
886                                  *      Use the pre-expanded string.
887                                  */
888                         } else if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
889                                    (g->vpt->type == TMPL_TYPE_XLAT) ||
890                                    (g->vpt->type == TMPL_TYPE_EXEC)) {
891                                 map.rhs = h->vpt;
892                                 map.lhs = &vpt;
893                                 cond.cast = NULL;
894
895                                 /*
896                                  *      Else evaluate the 'switch' statement.
897                                  */
898                         } else {
899                                 map.rhs = h->vpt;
900                                 map.lhs = g->vpt;
901                                 cond.cast = NULL;
902                         }
903
904                         if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
905                                                 &cond) == 1) {
906                                 found = this;
907                                 break;
908                         }
909                 }
910
911                 if (!found) found = null_case;
912
913         do_null_case:
914                 talloc_free(data.ptr);
915                 modcall_child(request, component, depth + 1, entry, found, &result);
916                 MOD_LOG_CLOSE_BRACE;
917                 goto calculate_result;
918         } /* MOD_SWITCH */
919 #endif
920
921         if ((c->type == MOD_LOAD_BALANCE) ||
922             (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
923                 uint32_t count = 0;
924                 modcallable *this, *found;
925                 modgroup *g;
926
927                 MOD_LOG_OPEN_BRACE;
928
929                 g = mod_callabletogroup(c);
930                 found = g->children;
931                 rad_assert(g->children != NULL);
932
933                 /*
934                  *      Choose a child at random.
935                  */
936                 for (this = g->children; this; this = this->next) {
937                         count++;
938
939                         if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
940                                 found = this;
941                         }
942                 }
943
944                 MOD_LOG_OPEN_BRACE;
945
946                 if (c->type == MOD_LOAD_BALANCE) {
947                         modcall_child(request, component,
948                                       depth + 1, entry, found,
949                                       &result);
950
951                 } else {
952                         this = found;
953
954                         do {
955                                 modcall_child(request, component,
956                                               depth + 1, entry, this,
957                                               &result);
958                                 if (this->actions[result] == MOD_ACTION_RETURN) {
959                                         priority = -1;
960                                         break;
961                                 }
962
963                                 this = this->next;
964                                 if (!this) this = g->children;
965                         } while (this != found);
966                 }
967                 MOD_LOG_CLOSE_BRACE;
968                 goto calculate_result;
969         } /* MOD_LOAD_BALANCE */
970
971         /*
972          *      Reference another virtual server.
973          *
974          *      This should really be deleted, and replaced with a
975          *      more abstracted / functional version.
976          */
977         if (c->type == MOD_REFERENCE) {
978                 modref *mr = mod_callabletoref(c);
979                 char const *server = request->server;
980
981                 if (server == mr->ref_name) {
982                         RWDEBUG("Suppressing recursive call to server %s", server);
983                         goto next_sibling;
984                 }
985
986                 request->server = mr->ref_name;
987                 RDEBUG("server %s { # nested call", mr->ref_name);
988                 result = indexed_modcall(component, 0, request);
989                 RDEBUG("} # server %s with nested call", mr->ref_name);
990                 request->server = server;
991                 goto calculate_result;
992         } /* MOD_REFERENCE */
993
994         /*
995          *      xlat a string without doing anything else
996          *
997          *      This should really be deleted, and replaced with a
998          *      more abstracted / functional version.
999          */
1000         if (c->type == MOD_XLAT) {
1001                 modxlat *mx = mod_callabletoxlat(c);
1002                 char buffer[128];
1003
1004                 if (!mx->exec) {
1005                         radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
1006                 } else {
1007                         RDEBUG("`%s`", mx->xlat_name);
1008                         radius_exec_program(NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
1009                                             false, true, EXEC_TIMEOUT);
1010                 }
1011
1012                 goto next_sibling;
1013         } /* MOD_XLAT */
1014
1015         /*
1016          *      Add new module types here.
1017          */
1018
1019 calculate_result:
1020 #if 0
1021         RDEBUG("(%s, %d) ? (%s, %d)",
1022                fr_int2str(mod_rcode_table, result, "<invalid>"),
1023                priority,
1024                fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
1025                entry->priority);
1026 #endif
1027
1028
1029         rad_assert(result != RLM_MODULE_UNKNOWN);
1030
1031         /*
1032          *      The child's action says return.  Do so.
1033          */
1034         if ((c->actions[result] == MOD_ACTION_RETURN) &&
1035             (priority <= 0)) {
1036                 entry->result = result;
1037                 goto finish;
1038         }
1039
1040         /*
1041          *      If "reject", break out of the loop and return
1042          *      reject.
1043          */
1044         if (c->actions[result] == MOD_ACTION_REJECT) {
1045                 entry->result = RLM_MODULE_REJECT;
1046                 goto finish;
1047         }
1048
1049         /*
1050          *      The array holds a default priority for this return
1051          *      code.  Grab it in preference to any unset priority.
1052          */
1053         if (priority < 0) {
1054                 priority = c->actions[result];
1055         }
1056
1057         /*
1058          *      We're higher than any previous priority, remember this
1059          *      return code and priority.
1060          */
1061         if (priority > entry->priority) {
1062                 entry->result = result;
1063                 entry->priority = priority;
1064         }
1065
1066 #ifdef WITH_UNLANG
1067         /*
1068          *      If we're processing a "case" statement, we return once
1069          *      it's done, rather than going to the next "case" statement.
1070          */
1071         if (c->type == MOD_CASE) goto finish;
1072 #endif
1073
1074         /*
1075          *      If we've been told to stop processing
1076          *      it, do so.
1077          */
1078         if (entry->unwind == MOD_BREAK) {
1079                 RDEBUG2("# unwind to enclosing foreach");
1080                 entry->unwind = 0;
1081                 goto finish;
1082         }
1083
1084         if (entry->unwind == MOD_RETURN) {
1085                 goto finish;
1086         }
1087
1088 next_sibling:
1089         entry->c = entry->c->next;
1090
1091         if (entry->c) goto redo;
1092
1093 finish:
1094         /*
1095          *      And we're done!
1096          */
1097         REXDENT();
1098         return true;
1099 }
1100
1101
1102 /** Call a module, iteratively, with a local stack, rather than recursively
1103  *
1104  * What did Paul Graham say about Lisp...?
1105  */
1106 int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
1107 {
1108         modcall_stack_entry_t stack[MODCALL_STACK_MAX];
1109
1110 #ifndef NDEBUG
1111         memset(stack, 0, sizeof(stack));
1112 #endif
1113         /*
1114          *      Set up the initial stack frame.
1115          */
1116         stack[0].c = c;
1117         stack[0].result = default_component_results[component];
1118         stack[0].priority = 0;
1119         stack[0].unwind = 0;
1120
1121         /*
1122          *      Call the main handler.
1123          */
1124         if (!modcall_recurse(request, component, 0, &stack[0])) {
1125                 return RLM_MODULE_FAIL;
1126         }
1127
1128         /*
1129          *      Return the result.
1130          */
1131         return stack[0].result;
1132 }
1133
1134
1135 #if 0
1136 static char const *action2str(int action)
1137 {
1138         static char buf[32];
1139         if(action==MOD_ACTION_RETURN)
1140                 return "return";
1141         if(action==MOD_ACTION_REJECT)
1142                 return "reject";
1143         snprintf(buf, sizeof buf, "%d", action);
1144         return buf;
1145 }
1146
1147 /* If you suspect a bug in the parser, you'll want to use these dump
1148  * functions. dump_tree should reproduce a whole tree exactly as it was found
1149  * in radiusd.conf, but in long form (all actions explicitly defined) */
1150 static void dump_mc(modcallable *c, int indent)
1151 {
1152         int i;
1153
1154         if(c->type==MOD_SINGLE) {
1155                 modsingle *single = mod_callabletosingle(c);
1156                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1157                         single->modinst->name);
1158         } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
1159                 modgroup *g = mod_callabletogroup(c);
1160                 modcallable *p;
1161                 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
1162                       group_name[c->type]);
1163                 for(p = g->children;p;p = p->next)
1164                         dump_mc(p, indent+1);
1165         } /* else ignore it for now */
1166
1167         for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
1168                 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
1169                       fr_int2str(mod_rcode_table, i, "<invalid>"),
1170                       action2str(c->actions[i]));
1171         }
1172
1173         DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
1174 }
1175
1176 static void dump_tree(rlm_components_t comp, modcallable *c)
1177 {
1178         DEBUG("[%s]", comp2str[comp]);
1179         dump_mc(c, 0);
1180 }
1181 #else
1182 #define dump_tree(a, b)
1183 #endif
1184
1185 /* These are the default actions. For each component, the group{} block
1186  * behaves like the code from the old module_*() function. redundant{} and
1187  * append{} are based on my guesses of what they will be used for. --Pac. */
1188 static const int
1189 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
1190 {
1191         /* authenticate */
1192         {
1193                 /* group */
1194                 {
1195                         MOD_ACTION_RETURN,      /* reject   */
1196                         1,                      /* fail     */
1197                         MOD_ACTION_RETURN,      /* ok       */
1198                         MOD_ACTION_RETURN,      /* handled  */
1199                         1,                      /* invalid  */
1200                         MOD_ACTION_RETURN,      /* userlock */
1201                         MOD_ACTION_RETURN,      /* notfound */
1202                         1,                      /* noop     */
1203                         1                       /* updated  */
1204                 },
1205                 /* redundant */
1206                 {
1207                         MOD_ACTION_RETURN,      /* reject   */
1208                         1,                      /* fail     */
1209                         MOD_ACTION_RETURN,      /* ok       */
1210                         MOD_ACTION_RETURN,      /* handled  */
1211                         MOD_ACTION_RETURN,      /* invalid  */
1212                         MOD_ACTION_RETURN,      /* userlock */
1213                         MOD_ACTION_RETURN,      /* notfound */
1214                         MOD_ACTION_RETURN,      /* noop     */
1215                         MOD_ACTION_RETURN       /* updated  */
1216                 },
1217                 /* append */
1218                 {
1219                         MOD_ACTION_RETURN,      /* reject   */
1220                         1,                      /* fail     */
1221                         MOD_ACTION_RETURN,      /* ok       */
1222                         MOD_ACTION_RETURN,      /* handled  */
1223                         MOD_ACTION_RETURN,      /* invalid  */
1224                         MOD_ACTION_RETURN,      /* userlock */
1225                         2,                      /* notfound */
1226                         MOD_ACTION_RETURN,      /* noop     */
1227                         MOD_ACTION_RETURN       /* updated  */
1228                 }
1229         },
1230         /* authorize */
1231         {
1232                 /* group */
1233                 {
1234                         MOD_ACTION_RETURN,      /* reject   */
1235                         MOD_ACTION_RETURN,      /* fail     */
1236                         3,                      /* ok       */
1237                         MOD_ACTION_RETURN,      /* handled  */
1238                         MOD_ACTION_RETURN,      /* invalid  */
1239                         MOD_ACTION_RETURN,      /* userlock */
1240                         1,                      /* notfound */
1241                         2,                      /* noop     */
1242                         4                       /* updated  */
1243                 },
1244                 /* redundant */
1245                 {
1246                         MOD_ACTION_RETURN,      /* reject   */
1247                         1,                      /* fail     */
1248                         MOD_ACTION_RETURN,      /* ok       */
1249                         MOD_ACTION_RETURN,      /* handled  */
1250                         MOD_ACTION_RETURN,      /* invalid  */
1251                         MOD_ACTION_RETURN,      /* userlock */
1252                         MOD_ACTION_RETURN,      /* notfound */
1253                         MOD_ACTION_RETURN,      /* noop     */
1254                         MOD_ACTION_RETURN       /* updated  */
1255                 },
1256                 /* append */
1257                 {
1258                         MOD_ACTION_RETURN,      /* reject   */
1259                         1,                      /* fail     */
1260                         MOD_ACTION_RETURN,      /* ok       */
1261                         MOD_ACTION_RETURN,      /* handled  */
1262                         MOD_ACTION_RETURN,      /* invalid  */
1263                         MOD_ACTION_RETURN,      /* userlock */
1264                         2,                      /* notfound */
1265                         MOD_ACTION_RETURN,      /* noop     */
1266                         MOD_ACTION_RETURN       /* updated  */
1267                 }
1268         },
1269         /* preacct */
1270         {
1271                 /* group */
1272                 {
1273                         MOD_ACTION_RETURN,      /* reject   */
1274                         MOD_ACTION_RETURN,      /* fail     */
1275                         2,                      /* ok       */
1276                         MOD_ACTION_RETURN,      /* handled  */
1277                         MOD_ACTION_RETURN,      /* invalid  */
1278                         MOD_ACTION_RETURN,      /* userlock */
1279                         MOD_ACTION_RETURN,      /* notfound */
1280                         1,                      /* noop     */
1281                         3                       /* updated  */
1282                 },
1283                 /* redundant */
1284                 {
1285                         MOD_ACTION_RETURN,      /* reject   */
1286                         1,                      /* fail     */
1287                         MOD_ACTION_RETURN,      /* ok       */
1288                         MOD_ACTION_RETURN,      /* handled  */
1289                         MOD_ACTION_RETURN,      /* invalid  */
1290                         MOD_ACTION_RETURN,      /* userlock */
1291                         MOD_ACTION_RETURN,      /* notfound */
1292                         MOD_ACTION_RETURN,      /* noop     */
1293                         MOD_ACTION_RETURN       /* updated  */
1294                 },
1295                 /* append */
1296                 {
1297                         MOD_ACTION_RETURN,      /* reject   */
1298                         1,                      /* fail     */
1299                         MOD_ACTION_RETURN,      /* ok       */
1300                         MOD_ACTION_RETURN,      /* handled  */
1301                         MOD_ACTION_RETURN,      /* invalid  */
1302                         MOD_ACTION_RETURN,      /* userlock */
1303                         2,                      /* notfound */
1304                         MOD_ACTION_RETURN,      /* noop     */
1305                         MOD_ACTION_RETURN       /* updated  */
1306                 }
1307         },
1308         /* accounting */
1309         {
1310                 /* group */
1311                 {
1312                         MOD_ACTION_RETURN,      /* reject   */
1313                         MOD_ACTION_RETURN,      /* fail     */
1314                         2,                      /* ok       */
1315                         MOD_ACTION_RETURN,      /* handled  */
1316                         MOD_ACTION_RETURN,      /* invalid  */
1317                         MOD_ACTION_RETURN,      /* userlock */
1318                         MOD_ACTION_RETURN,      /* notfound */
1319                         1,                      /* noop     */
1320                         3                       /* updated  */
1321                 },
1322                 /* redundant */
1323                 {
1324                         1,                      /* reject   */
1325                         1,                      /* fail     */
1326                         MOD_ACTION_RETURN,      /* ok       */
1327                         MOD_ACTION_RETURN,      /* handled  */
1328                         1,                      /* invalid  */
1329                         1,                      /* userlock */
1330                         1,                      /* notfound */
1331                         2,                      /* noop     */
1332                         4                       /* updated  */
1333                 },
1334                 /* append */
1335                 {
1336                         MOD_ACTION_RETURN,      /* reject   */
1337                         1,                      /* fail     */
1338                         MOD_ACTION_RETURN,      /* ok       */
1339                         MOD_ACTION_RETURN,      /* handled  */
1340                         MOD_ACTION_RETURN,      /* invalid  */
1341                         MOD_ACTION_RETURN,      /* userlock */
1342                         2,                      /* notfound */
1343                         MOD_ACTION_RETURN,      /* noop     */
1344                         MOD_ACTION_RETURN       /* updated  */
1345                 }
1346         },
1347         /* checksimul */
1348         {
1349                 /* group */
1350                 {
1351                         MOD_ACTION_RETURN,      /* reject   */
1352                         1,                      /* fail     */
1353                         MOD_ACTION_RETURN,      /* ok       */
1354                         MOD_ACTION_RETURN,      /* handled  */
1355                         MOD_ACTION_RETURN,      /* invalid  */
1356                         MOD_ACTION_RETURN,      /* userlock */
1357                         MOD_ACTION_RETURN,      /* notfound */
1358                         MOD_ACTION_RETURN,      /* noop     */
1359                         MOD_ACTION_RETURN       /* updated  */
1360                 },
1361                 /* redundant */
1362                 {
1363                         MOD_ACTION_RETURN,      /* reject   */
1364                         1,                      /* fail     */
1365                         MOD_ACTION_RETURN,      /* ok       */
1366                         MOD_ACTION_RETURN,      /* handled  */
1367                         MOD_ACTION_RETURN,      /* invalid  */
1368                         MOD_ACTION_RETURN,      /* userlock */
1369                         MOD_ACTION_RETURN,      /* notfound */
1370                         MOD_ACTION_RETURN,      /* noop     */
1371                         MOD_ACTION_RETURN       /* updated  */
1372                 },
1373                 /* append */
1374                 {
1375                         MOD_ACTION_RETURN,      /* reject   */
1376                         1,                      /* fail     */
1377                         MOD_ACTION_RETURN,      /* ok       */
1378                         MOD_ACTION_RETURN,      /* handled  */
1379                         MOD_ACTION_RETURN,      /* invalid  */
1380                         MOD_ACTION_RETURN,      /* userlock */
1381                         MOD_ACTION_RETURN,      /* notfound */
1382                         MOD_ACTION_RETURN,      /* noop     */
1383                         MOD_ACTION_RETURN       /* updated  */
1384                 }
1385         },
1386         /* pre-proxy */
1387         {
1388                 /* group */
1389                 {
1390                         MOD_ACTION_RETURN,      /* reject   */
1391                         MOD_ACTION_RETURN,      /* fail     */
1392                         3,                      /* ok       */
1393                         MOD_ACTION_RETURN,      /* handled  */
1394                         MOD_ACTION_RETURN,      /* invalid  */
1395                         MOD_ACTION_RETURN,      /* userlock */
1396                         1,                      /* notfound */
1397                         2,                      /* noop     */
1398                         4                       /* updated  */
1399                 },
1400                 /* redundant */
1401                 {
1402                         MOD_ACTION_RETURN,      /* reject   */
1403                         1,                      /* fail     */
1404                         MOD_ACTION_RETURN,      /* ok       */
1405                         MOD_ACTION_RETURN,      /* handled  */
1406                         MOD_ACTION_RETURN,      /* invalid  */
1407                         MOD_ACTION_RETURN,      /* userlock */
1408                         MOD_ACTION_RETURN,      /* notfound */
1409                         MOD_ACTION_RETURN,      /* noop     */
1410                         MOD_ACTION_RETURN       /* updated  */
1411                 },
1412                 /* append */
1413                 {
1414                         MOD_ACTION_RETURN,      /* reject   */
1415                         1,                      /* fail     */
1416                         MOD_ACTION_RETURN,      /* ok       */
1417                         MOD_ACTION_RETURN,      /* handled  */
1418                         MOD_ACTION_RETURN,      /* invalid  */
1419                         MOD_ACTION_RETURN,      /* userlock */
1420                         2,                      /* notfound */
1421                         MOD_ACTION_RETURN,      /* noop     */
1422                         MOD_ACTION_RETURN       /* updated  */
1423                 }
1424         },
1425         /* post-proxy */
1426         {
1427                 /* group */
1428                 {
1429                         MOD_ACTION_RETURN,      /* reject   */
1430                         MOD_ACTION_RETURN,      /* fail     */
1431                         3,                      /* ok       */
1432                         MOD_ACTION_RETURN,      /* handled  */
1433                         MOD_ACTION_RETURN,      /* invalid  */
1434                         MOD_ACTION_RETURN,      /* userlock */
1435                         1,                      /* notfound */
1436                         2,                      /* noop     */
1437                         4                       /* updated  */
1438                 },
1439                 /* redundant */
1440                 {
1441                         MOD_ACTION_RETURN,      /* reject   */
1442                         1,                      /* fail     */
1443                         MOD_ACTION_RETURN,      /* ok       */
1444                         MOD_ACTION_RETURN,      /* handled  */
1445                         MOD_ACTION_RETURN,      /* invalid  */
1446                         MOD_ACTION_RETURN,      /* userlock */
1447                         MOD_ACTION_RETURN,      /* notfound */
1448                         MOD_ACTION_RETURN,      /* noop     */
1449                         MOD_ACTION_RETURN       /* updated  */
1450                 },
1451                 /* append */
1452                 {
1453                         MOD_ACTION_RETURN,      /* reject   */
1454                         1,                      /* fail     */
1455                         MOD_ACTION_RETURN,      /* ok       */
1456                         MOD_ACTION_RETURN,      /* handled  */
1457                         MOD_ACTION_RETURN,      /* invalid  */
1458                         MOD_ACTION_RETURN,      /* userlock */
1459                         2,                      /* notfound */
1460                         MOD_ACTION_RETURN,      /* noop     */
1461                         MOD_ACTION_RETURN       /* updated  */
1462                 }
1463         },
1464         /* post-auth */
1465         {
1466                 /* group */
1467                 {
1468                         MOD_ACTION_RETURN,      /* reject   */
1469                         MOD_ACTION_RETURN,      /* fail     */
1470                         3,                      /* ok       */
1471                         MOD_ACTION_RETURN,      /* handled  */
1472                         MOD_ACTION_RETURN,      /* invalid  */
1473                         MOD_ACTION_RETURN,      /* userlock */
1474                         1,                      /* notfound */
1475                         2,                      /* noop     */
1476                         4                       /* updated  */
1477                 },
1478                 /* redundant */
1479                 {
1480                         MOD_ACTION_RETURN,      /* reject   */
1481                         1,                      /* fail     */
1482                         MOD_ACTION_RETURN,      /* ok       */
1483                         MOD_ACTION_RETURN,      /* handled  */
1484                         MOD_ACTION_RETURN,      /* invalid  */
1485                         MOD_ACTION_RETURN,      /* userlock */
1486                         MOD_ACTION_RETURN,      /* notfound */
1487                         MOD_ACTION_RETURN,      /* noop     */
1488                         MOD_ACTION_RETURN       /* updated  */
1489                 },
1490                 /* append */
1491                 {
1492                         MOD_ACTION_RETURN,      /* reject   */
1493                         1,                      /* fail     */
1494                         MOD_ACTION_RETURN,      /* ok       */
1495                         MOD_ACTION_RETURN,      /* handled  */
1496                         MOD_ACTION_RETURN,      /* invalid  */
1497                         MOD_ACTION_RETURN,      /* userlock */
1498                         2,                      /* notfound */
1499                         MOD_ACTION_RETURN,      /* noop     */
1500                         MOD_ACTION_RETURN       /* updated  */
1501                 }
1502         }
1503 #ifdef WITH_COA
1504         ,
1505         /* recv-coa */
1506         {
1507                 /* group */
1508                 {
1509                         MOD_ACTION_RETURN,      /* reject   */
1510                         MOD_ACTION_RETURN,      /* fail     */
1511                         3,                      /* ok       */
1512                         MOD_ACTION_RETURN,      /* handled  */
1513                         MOD_ACTION_RETURN,      /* invalid  */
1514                         MOD_ACTION_RETURN,      /* userlock */
1515                         1,                      /* notfound */
1516                         2,                      /* noop     */
1517                         4                       /* updated  */
1518                 },
1519                 /* redundant */
1520                 {
1521                         MOD_ACTION_RETURN,      /* reject   */
1522                         1,                      /* fail     */
1523                         MOD_ACTION_RETURN,      /* ok       */
1524                         MOD_ACTION_RETURN,      /* handled  */
1525                         MOD_ACTION_RETURN,      /* invalid  */
1526                         MOD_ACTION_RETURN,      /* userlock */
1527                         MOD_ACTION_RETURN,      /* notfound */
1528                         MOD_ACTION_RETURN,      /* noop     */
1529                         MOD_ACTION_RETURN       /* updated  */
1530                 },
1531                 /* append */
1532                 {
1533                         MOD_ACTION_RETURN,      /* reject   */
1534                         1,                      /* fail     */
1535                         MOD_ACTION_RETURN,      /* ok       */
1536                         MOD_ACTION_RETURN,      /* handled  */
1537                         MOD_ACTION_RETURN,      /* invalid  */
1538                         MOD_ACTION_RETURN,      /* userlock */
1539                         2,                      /* notfound */
1540                         MOD_ACTION_RETURN,      /* noop     */
1541                         MOD_ACTION_RETURN       /* updated  */
1542                 }
1543         },
1544         /* send-coa */
1545         {
1546                 /* group */
1547                 {
1548                         MOD_ACTION_RETURN,      /* reject   */
1549                         MOD_ACTION_RETURN,      /* fail     */
1550                         3,                      /* ok       */
1551                         MOD_ACTION_RETURN,      /* handled  */
1552                         MOD_ACTION_RETURN,      /* invalid  */
1553                         MOD_ACTION_RETURN,      /* userlock */
1554                         1,                      /* notfound */
1555                         2,                      /* noop     */
1556                         4                       /* updated  */
1557                 },
1558                 /* redundant */
1559                 {
1560                         MOD_ACTION_RETURN,      /* reject   */
1561                         1,                      /* fail     */
1562                         MOD_ACTION_RETURN,      /* ok       */
1563                         MOD_ACTION_RETURN,      /* handled  */
1564                         MOD_ACTION_RETURN,      /* invalid  */
1565                         MOD_ACTION_RETURN,      /* userlock */
1566                         MOD_ACTION_RETURN,      /* notfound */
1567                         MOD_ACTION_RETURN,      /* noop     */
1568                         MOD_ACTION_RETURN       /* updated  */
1569                 },
1570                 /* append */
1571                 {
1572                         MOD_ACTION_RETURN,      /* reject   */
1573                         1,                      /* fail     */
1574                         MOD_ACTION_RETURN,      /* ok       */
1575                         MOD_ACTION_RETURN,      /* handled  */
1576                         MOD_ACTION_RETURN,      /* invalid  */
1577                         MOD_ACTION_RETURN,      /* userlock */
1578                         2,                      /* notfound */
1579                         MOD_ACTION_RETURN,      /* noop     */
1580                         MOD_ACTION_RETURN       /* updated  */
1581                 }
1582         }
1583 #endif
1584 };
1585
1586 /** Validate and fixup a map that's part of an update section.
1587  *
1588  * @param map to validate.
1589  * @param ctx data to pass to fixup function (currently unused).
1590  * @return 0 if valid else -1.
1591  */
1592 int modcall_fixup_update(value_pair_map_t *map, UNUSED void *ctx)
1593 {
1594         CONF_PAIR *cp = cf_itemtopair(map->ci);
1595
1596         /*
1597          *      Anal-retentive checks.
1598          */
1599         if (DEBUG_ENABLED2) {
1600                 if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
1601                         WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
1602                              cf_pair_filename(cp), cf_pair_lineno(cp),
1603                              map->lhs->name, fr_int2str(fr_tokens, map->op, "<INVALID>"));
1604                 }
1605
1606                 if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
1607                         WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
1608                              cf_pair_filename(cp), cf_pair_lineno(cp),
1609                              fr_int2str(fr_tokens, map->op, "<INVALID>"), map->rhs->name);
1610                 }
1611         }
1612
1613         /*
1614          *      Values used by unary operators should be literal ANY
1615          *
1616          *      We then free the template and alloc a NULL one instead.
1617          */
1618         if (map->op == T_OP_CMP_FALSE) {
1619                 if ((map->rhs->type != TMPL_TYPE_LITERAL) || (strcmp(map->rhs->name, "ANY") != 0)) {
1620                         WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
1621                              cf_pair_filename(cp), cf_pair_lineno(cp));
1622                 }
1623
1624                 tmpl_free(&map->rhs);
1625
1626                 map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, NULL, 0);
1627         }
1628
1629         /*
1630          *      Lots of sanity checks for insane people...
1631          */
1632
1633         /*
1634          *      What exactly where you expecting to happen here?
1635          */
1636         if ((map->lhs->type == TMPL_TYPE_ATTR) &&
1637             (map->rhs->type == TMPL_TYPE_LIST)) {
1638                 cf_log_err(map->ci, "Can't copy list into an attribute");
1639                 return -1;
1640         }
1641
1642         /*
1643          *      Depending on the attribute type, some operators are disallowed.
1644          */
1645         if (map->lhs->type == TMPL_TYPE_ATTR) {
1646                 switch (map->op) {
1647                 default:
1648                         cf_log_err(map->ci, "Invalid operator for attribute");
1649                         return -1;
1650
1651                 case T_OP_EQ:
1652                 case T_OP_CMP_EQ:
1653                 case T_OP_ADD:
1654                 case T_OP_SUB:
1655                 case T_OP_LE:
1656                 case T_OP_GE:
1657                 case T_OP_CMP_FALSE:
1658                 case T_OP_SET:
1659                         break;
1660                 }
1661         }
1662
1663         if (map->lhs->type == TMPL_TYPE_LIST) {
1664                 /*
1665                  *      Can't copy an xlat expansion or literal into a list,
1666                  *      we don't know what type of attribute we'd need
1667                  *      to create.
1668                  *
1669                  *      The only exception is where were using a unary
1670                  *      operator like !*.
1671                  */
1672                 if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
1673                 case TMPL_TYPE_XLAT:
1674                 case TMPL_TYPE_LITERAL:
1675                         cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
1676                         return -1;
1677
1678                 default:
1679                         break;
1680                 }
1681
1682                 /*
1683                  *      Only += and :=, and !* operators are supported
1684                  *      for lists.
1685                  */
1686                 switch (map->op) {
1687                 case T_OP_CMP_FALSE:
1688                         break;
1689
1690                 case T_OP_ADD:
1691                         if ((map->rhs->type != TMPL_TYPE_LIST) &&
1692                             (map->rhs->type != TMPL_TYPE_EXEC)) {
1693                                 cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
1694                                 return -1;
1695                         }
1696                         break;
1697
1698                 case T_OP_SET:
1699                         if (map->rhs->type == TMPL_TYPE_EXEC) {
1700                                 WARN("%s[%d] Please change ':=' to '=' for list assignment",
1701                                      cf_pair_filename(cp), cf_pair_lineno(cp));
1702                         }
1703
1704                         if (map->rhs->type != TMPL_TYPE_LIST) {
1705                                 cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
1706                                 return -1;
1707                         }
1708                         break;
1709
1710                 case T_OP_EQ:
1711                         if (map->rhs->type != TMPL_TYPE_EXEC) {
1712                                 cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
1713                                 return -1;
1714                         }
1715                         break;
1716
1717                 default:
1718                         cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
1719                                    fr_int2str(fr_tokens, map->op, "<INVALID>"));
1720                         return -1;
1721                 }
1722         }
1723
1724         /*
1725          *      If the map has a unary operator there's no further
1726          *      processing we need to, as RHS is unused.
1727          */
1728         if (map->op == T_OP_CMP_FALSE) return 0;
1729
1730         /*
1731          *      If LHS is an attribute, and RHS is a literal, we can
1732          *      preparse the information into a TMPL_TYPE_DATA.
1733          *
1734          *      Unless it's a unary operator in which case we
1735          *      ignore map->rhs.
1736          */
1737         if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->rhs->type == TMPL_TYPE_LITERAL)) {
1738                 /*
1739                  *      It's a literal string, just copy it.
1740                  *      Don't escape anything.
1741                  */
1742                 if (!cf_new_escape &&
1743                     (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
1744                     (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
1745                         tmpl_cast_in_place_str(map->rhs);
1746                 } else {
1747                         if (!tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da)) {
1748                                 cf_log_err(map->ci, "%s", fr_strerror());
1749                                 return -1;
1750                         }
1751
1752                         /*
1753                          *      Fixup LHS da if it doesn't match the type
1754                          *      of the RHS.
1755                          */
1756                         if (map->lhs->tmpl_da->type != map->rhs->tmpl_data_type) {
1757                                 DICT_ATTR const *da;
1758
1759                                 da = dict_attrbytype(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor,
1760                                                      map->rhs->tmpl_data_type);
1761                                 if (!da) {
1762                                         fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
1763                                                            fr_int2str(dict_attr_types, map->rhs->tmpl_data_type,
1764                                                            "<INVALID>"), map->lhs->tmpl_da->name);
1765                                         return -1;
1766                                 }
1767                                 map->lhs->tmpl_da = da;
1768                         }
1769                 }
1770         } /* else we can't precompile the data */
1771
1772         return 0;
1773 }
1774
1775
1776 #ifdef WITH_UNLANG
1777 static modcallable *do_compile_modupdate(modcallable *parent, UNUSED rlm_components_t component,
1778                                          CONF_SECTION *cs, char const *name2)
1779 {
1780         int rcode;
1781         modgroup *g;
1782         modcallable *csingle;
1783
1784         value_pair_map_t *head;
1785
1786         /*
1787          *      This looks at cs->name2 to determine which list to update
1788          */
1789         rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
1790         if (rcode < 0) return NULL; /* message already printed */
1791         if (!head) {
1792                 cf_log_err_cs(cs, "'update' sections cannot be empty");
1793                 return NULL;
1794         }
1795
1796         g = talloc_zero(parent, modgroup);
1797         csingle = mod_grouptocallable(g);
1798
1799         csingle->parent = parent;
1800         csingle->next = NULL;
1801
1802         if (name2) {
1803                 csingle->name = name2;
1804         } else {
1805                 csingle->name = "";
1806         }
1807         csingle->type = MOD_UPDATE;
1808         csingle->method = component;
1809
1810         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
1811                sizeof(csingle->actions));
1812
1813         g->grouptype = GROUPTYPE_SIMPLE;
1814         g->children = NULL;
1815         g->cs = cs;
1816         g->map = talloc_steal(g, head);
1817
1818         return csingle;
1819 }
1820
1821
1822 static modcallable *do_compile_modswitch (modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1823 {
1824         CONF_ITEM *ci;
1825         FR_TOKEN type;
1826         char const *name2;
1827         bool had_seen_default = false;
1828         modcallable *csingle;
1829         modgroup *g;
1830         ssize_t slen;
1831         value_pair_tmpl_t *vpt;
1832
1833         name2 = cf_section_name2(cs);
1834         if (!name2) {
1835                 cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
1836                 return NULL;
1837         }
1838
1839         if (!cf_item_find_next(cs, NULL)) {
1840                 cf_log_err_cs(cs, "'switch' statements cannot be empty");
1841                 return NULL;
1842         }
1843
1844         /*
1845          *      Create the template.  If we fail, AND it's a bare word
1846          *      with &Foo-Bar, it MAY be an attribute defined by a
1847          *      module.  Allow it for now.  The pass2 checks below
1848          *      will fix it up.
1849          */
1850         type = cf_section_name2_type(cs);
1851         slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1852         if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1853                 char *spaces, *text;
1854
1855                 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1856
1857                 cf_log_err_cs(cs, "Syntax error");
1858                 cf_log_err_cs(cs, "%s", name2);
1859                 cf_log_err_cs(cs, "%s^ %s", spaces, text);
1860
1861                 talloc_free(spaces);
1862                 talloc_free(text);
1863
1864                 return NULL;
1865         }
1866
1867         /*
1868          *      Otherwise a NULL vpt may refer to an attribute defined
1869          *      by a module.  That is checked in pass 2.
1870          */
1871
1872         /*
1873          *      Walk through the children of the switch section,
1874          *      ensuring that they're all 'case' statements
1875          */
1876         for (ci = cf_item_find_next(cs, NULL);
1877              ci != NULL;
1878              ci = cf_item_find_next(cs, ci)) {
1879                 CONF_SECTION *subcs;
1880                 char const *name1;
1881
1882                 if (!cf_item_is_section(ci)) {
1883                         if (!cf_item_is_pair(ci)) continue;
1884
1885                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1886                         talloc_free(vpt);
1887                         return NULL;
1888                 }
1889
1890                 subcs = cf_itemtosection(ci);   /* can't return NULL */
1891                 name1 = cf_section_name1(subcs);
1892
1893                 if (strcmp(name1, "case") != 0) {
1894                         cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
1895                         talloc_free(vpt);
1896                         return NULL;
1897                 }
1898
1899                 name2 = cf_section_name2(subcs);
1900                 if (!name2) {
1901                         if (!had_seen_default) {
1902                                 had_seen_default = true;
1903                                 continue;
1904                         }
1905
1906                         cf_log_err(ci, "Cannot have two 'default' case statements");
1907                         talloc_free(vpt);
1908                         return NULL;
1909                 }
1910         }
1911
1912         csingle = do_compile_modgroup(parent, component, cs,
1913                                       GROUPTYPE_SIMPLE,
1914                                       GROUPTYPE_SIMPLE,
1915                                       MOD_SWITCH);
1916         if (!csingle) {
1917                 talloc_free(vpt);
1918                 return NULL;
1919         }
1920
1921         g = mod_callabletogroup(csingle);
1922         g->vpt = talloc_steal(g, vpt);
1923
1924         return csingle;
1925 }
1926
1927 static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
1928 {
1929         int i;
1930         char const *name2;
1931         modcallable *csingle;
1932         modgroup *g;
1933         value_pair_tmpl_t *vpt;
1934
1935         if (!parent || (parent->type != MOD_SWITCH)) {
1936                 cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
1937                 return NULL;
1938         }
1939
1940         /*
1941          *      case THING means "match THING"
1942          *      case       means "match anything"
1943          */
1944         name2 = cf_section_name2(cs);
1945         if (name2) {
1946                 ssize_t slen;
1947                 FR_TOKEN type;
1948
1949                 type = cf_section_name2_type(cs);
1950
1951                 slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
1952                 if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
1953                         char *spaces, *text;
1954
1955                         fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
1956
1957                         cf_log_err_cs(cs, "Syntax error");
1958                         cf_log_err_cs(cs, "%s", name2);
1959                         cf_log_err_cs(cs, "%s^ %s", spaces, text);
1960
1961                         talloc_free(spaces);
1962                         talloc_free(text);
1963
1964                         return NULL;
1965                 }
1966
1967                 /*
1968                  *      Otherwise a NULL vpt may refer to an attribute defined
1969                  *      by a module.  That is checked in pass 2.
1970                  */
1971
1972         } else {
1973                 vpt = NULL;
1974         }
1975
1976         csingle = do_compile_modgroup(parent, component, cs,
1977                                       GROUPTYPE_SIMPLE,
1978                                       GROUPTYPE_SIMPLE,
1979                                       MOD_CASE);
1980         if (!csingle) {
1981                 talloc_free(vpt);
1982                 return NULL;
1983         }
1984
1985         /*
1986          *      The interpretor expects this to be NULL for the
1987          *      default case.  do_compile_modgroup sets it to name2,
1988          *      unless name2 is NULL, in which case it sets it to name1.
1989          */
1990         csingle->name = name2;
1991
1992         g = mod_callabletogroup(csingle);
1993         g->vpt = talloc_steal(g, vpt);
1994
1995         /*
1996          *      Set all of it's codes to return, so that
1997          *      when we pick a 'case' statement, we don't
1998          *      fall through to processing the next one.
1999          */
2000         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2001                 csingle->actions[i] = MOD_ACTION_RETURN;
2002         }
2003
2004         return csingle;
2005 }
2006
2007 static modcallable *do_compile_modforeach(modcallable *parent,
2008                                           UNUSED rlm_components_t component, CONF_SECTION *cs)
2009 {
2010         FR_TOKEN type;
2011         char const *name2;
2012         modcallable *csingle;
2013         modgroup *g;
2014         ssize_t slen;
2015         value_pair_tmpl_t *vpt;
2016
2017         name2 = cf_section_name2(cs);
2018         if (!name2) {
2019                 cf_log_err_cs(cs,
2020                            "You must specify an attribute to loop over in 'foreach'");
2021                 return NULL;
2022         }
2023
2024         if (!cf_item_find_next(cs, NULL)) {
2025                 cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
2026                 return NULL;
2027         }
2028
2029         /*
2030          *      Create the template.  If we fail, AND it's a bare word
2031          *      with &Foo-Bar, it MAY be an attribute defined by a
2032          *      module.  Allow it for now.  The pass2 checks below
2033          *      will fix it up.
2034          */
2035         type = cf_section_name2_type(cs);
2036         slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
2037         if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
2038                 char *spaces, *text;
2039
2040                 fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
2041
2042                 cf_log_err_cs(cs, "Syntax error");
2043                 cf_log_err_cs(cs, "%s", name2);
2044                 cf_log_err_cs(cs, "%s^ %s", spaces, text);
2045
2046                 talloc_free(spaces);
2047                 talloc_free(text);
2048
2049                 return NULL;
2050         }
2051
2052         if (vpt && (vpt->type != TMPL_TYPE_ATTR)) {
2053                 cf_log_err_cs(cs, "MUST use attribute reference in 'foreach'");
2054                 return NULL;
2055         }
2056
2057         /*
2058          *      Fix up the template to iterate over all instances of
2059          *      the attribute. In a perfect consistent world, users would do
2060          *      foreach &attr[*], but that's taking the consistency thing a bit far.
2061          */
2062         if (vpt && (vpt->type == TMPL_TYPE_ATTR)) {
2063                 vpt->tmpl_num = NUM_ALL;
2064         }
2065
2066         csingle = do_compile_modgroup(parent, component, cs,
2067                                       GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2068                                       MOD_FOREACH);
2069
2070         if (!csingle) {
2071                 talloc_free(vpt);
2072                 return NULL;
2073         }
2074
2075         g = mod_callabletogroup(csingle);
2076         g->vpt = vpt;
2077
2078         return csingle;
2079 }
2080
2081 static modcallable *do_compile_modbreak(modcallable *parent,
2082                                         rlm_components_t component, CONF_ITEM const *ci)
2083 {
2084         CONF_SECTION const *cs = NULL;
2085
2086         for (cs = cf_item_parent(ci);
2087              cs != NULL;
2088              cs = cf_item_parent(cf_sectiontoitem(cs))) {
2089                 if (strcmp(cf_section_name1(cs), "foreach") == 0) {
2090                         break;
2091                 }
2092         }
2093
2094         if (!cs) {
2095                 cf_log_err(ci, "'break' can only be used in a 'foreach' section");
2096                 return NULL;
2097         }
2098
2099         return do_compile_modgroup(parent, component, NULL,
2100                                    GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2101                                    MOD_BREAK);
2102 }
2103 #endif
2104
2105 static modcallable *do_compile_modserver(modcallable *parent,
2106                                          rlm_components_t component, CONF_ITEM *ci,
2107                                          char const *name,
2108                                          CONF_SECTION *cs,
2109                                          char const *server)
2110 {
2111         modcallable *csingle;
2112         CONF_SECTION *subcs;
2113         modref *mr;
2114
2115         subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
2116         if (!subcs) {
2117                 cf_log_err(ci, "Server %s has no %s section",
2118                            server, comp2str[component]);
2119                 return NULL;
2120         }
2121
2122         mr = talloc_zero(parent, modref);
2123
2124         csingle = mod_reftocallable(mr);
2125         csingle->parent = parent;
2126         csingle->next = NULL;
2127         csingle->name = name;
2128         csingle->type = MOD_REFERENCE;
2129         csingle->method = component;
2130
2131         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2132                sizeof(csingle->actions));
2133
2134         mr->ref_name = strdup(server);
2135         mr->ref_cs = cs;
2136
2137         return csingle;
2138 }
2139
2140 static modcallable *do_compile_modxlat(modcallable *parent,
2141                                        rlm_components_t component, char const *fmt)
2142 {
2143         modcallable *csingle;
2144         modxlat *mx;
2145
2146         mx = talloc_zero(parent, modxlat);
2147
2148         csingle = mod_xlattocallable(mx);
2149         csingle->parent = parent;
2150         csingle->next = NULL;
2151         csingle->name = "expand";
2152         csingle->type = MOD_XLAT;
2153         csingle->method = component;
2154
2155         memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
2156                sizeof(csingle->actions));
2157
2158         mx->xlat_name = strdup(fmt);
2159         if (fmt[0] != '%') {
2160                 char *p;
2161                 mx->exec = true;
2162
2163                 strcpy(mx->xlat_name, fmt + 1);
2164                 p = strrchr(mx->xlat_name, '`');
2165                 if (p) *p = '\0';
2166         }
2167
2168         return csingle;
2169 }
2170
2171 /*
2172  *      redundant, etc. can refer to modules or groups, but not much else.
2173  */
2174 static int all_children_are_modules(CONF_SECTION *cs, char const *name)
2175 {
2176         CONF_ITEM *ci;
2177
2178         for (ci=cf_item_find_next(cs, NULL);
2179              ci != NULL;
2180              ci=cf_item_find_next(cs, ci)) {
2181                 /*
2182                  *      If we're a redundant, etc. group, then the
2183                  *      intention is to call modules, rather than
2184                  *      processing logic.  These checks aren't
2185                  *      *strictly* necessary, but they keep the users
2186                  *      from doing crazy things.
2187                  */
2188                 if (cf_item_is_section(ci)) {
2189                         CONF_SECTION *subcs = cf_itemtosection(ci);
2190                         char const *name1 = cf_section_name1(subcs);
2191
2192                         if ((strcmp(name1, "if") == 0) ||
2193                             (strcmp(name1, "else") == 0) ||
2194                             (strcmp(name1, "elsif") == 0) ||
2195                             (strcmp(name1, "update") == 0) ||
2196                             (strcmp(name1, "switch") == 0) ||
2197                             (strcmp(name1, "case") == 0)) {
2198                                 cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
2199                                        name, name1);
2200                                 return 0;
2201                         }
2202                         continue;
2203                 }
2204
2205                 if (cf_item_is_pair(ci)) {
2206                         CONF_PAIR *cp = cf_itemtopair(ci);
2207                         if (cf_pair_value(cp) != NULL) {
2208                                 cf_log_err(ci,
2209                                            "Entry with no value is invalid");
2210                                 return 0;
2211                         }
2212                 }
2213         }
2214
2215         return 1;
2216 }
2217
2218
2219 /*
2220  *      Compile one entry of a module call.
2221  */
2222 static modcallable *do_compile_modsingle(modcallable *parent,
2223                                          rlm_components_t component, CONF_ITEM *ci,
2224                                          int grouptype,
2225                                          char const **modname)
2226 {
2227         char const *modrefname;
2228         modsingle *single;
2229         modcallable *csingle;
2230         module_instance_t *this;
2231         CONF_SECTION *cs, *subcs, *modules;
2232         char const *realname;
2233
2234         if (cf_item_is_section(ci)) {
2235                 char const *name2;
2236
2237                 cs = cf_itemtosection(ci);
2238                 modrefname = cf_section_name1(cs);
2239                 name2 = cf_section_name2(cs);
2240                 if (!name2) name2 = "";
2241
2242                 /*
2243                  *      group{}, redundant{}, or append{} may appear
2244                  *      where a single module instance was expected.
2245                  *      In that case, we hand it off to
2246                  *      compile_modgroup
2247                  */
2248                 if (strcmp(modrefname, "group") == 0) {
2249                         *modname = name2;
2250                         return do_compile_modgroup(parent, component, cs,
2251                                                    GROUPTYPE_SIMPLE,
2252                                                    grouptype, MOD_GROUP);
2253
2254                 } else if (strcmp(modrefname, "redundant") == 0) {
2255                         *modname = name2;
2256
2257                         if (!all_children_are_modules(cs, modrefname)) {
2258                                 return NULL;
2259                         }
2260
2261                         return do_compile_modgroup(parent, component, cs,
2262                                                    GROUPTYPE_REDUNDANT,
2263                                                    grouptype, MOD_GROUP);
2264
2265                 } else if (strcmp(modrefname, "append") == 0) {
2266                         *modname = name2;
2267                         return do_compile_modgroup(parent, component, cs,
2268                                                    GROUPTYPE_APPEND,
2269                                                    grouptype, MOD_GROUP);
2270
2271                 } else if (strcmp(modrefname, "load-balance") == 0) {
2272                         *modname = name2;
2273
2274                         if (!all_children_are_modules(cs, modrefname)) {
2275                                 return NULL;
2276                         }
2277
2278                         return do_compile_modgroup(parent, component, cs,
2279                                                    GROUPTYPE_SIMPLE,
2280                                                    grouptype, MOD_LOAD_BALANCE);
2281
2282                 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
2283                         *modname = name2;
2284
2285                         if (!all_children_are_modules(cs, modrefname)) {
2286                                 return NULL;
2287                         }
2288
2289                         return do_compile_modgroup(parent, component, cs,
2290                                                    GROUPTYPE_REDUNDANT,
2291                                                    grouptype, MOD_REDUNDANT_LOAD_BALANCE);
2292
2293 #ifdef WITH_UNLANG
2294                 } else  if (strcmp(modrefname, "if") == 0) {
2295                         if (!cf_section_name2(cs)) {
2296                                 cf_log_err(ci, "'if' without condition");
2297                                 return NULL;
2298                         }
2299
2300                         *modname = name2;
2301                         csingle= do_compile_modgroup(parent, component, cs,
2302                                                      GROUPTYPE_SIMPLE,
2303                                                      grouptype, MOD_IF);
2304                         if (!csingle) return NULL;
2305                         *modname = name2;
2306
2307                         return csingle;
2308
2309                 } else  if (strcmp(modrefname, "elsif") == 0) {
2310                         if (parent &&
2311                             ((parent->type == MOD_LOAD_BALANCE) ||
2312                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2313                                 cf_log_err(ci, "'elsif' cannot be used in this section");
2314                                 return NULL;
2315                         }
2316
2317                         if (!cf_section_name2(cs)) {
2318                                 cf_log_err(ci, "'elsif' without condition");
2319                                 return NULL;
2320                         }
2321
2322                         *modname = name2;
2323                         return do_compile_modgroup(parent, component, cs,
2324                                                    GROUPTYPE_SIMPLE,
2325                                                    grouptype, MOD_ELSIF);
2326
2327                 } else  if (strcmp(modrefname, "else") == 0) {
2328                         if (parent &&
2329                             ((parent->type == MOD_LOAD_BALANCE) ||
2330                              (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
2331                                 cf_log_err(ci, "'else' cannot be used in this section section");
2332                                 return NULL;
2333                         }
2334
2335                         if (cf_section_name2(cs)) {
2336                                 cf_log_err(ci, "Cannot have conditions on 'else'");
2337                                 return NULL;
2338                         }
2339
2340                         *modname = name2;
2341                         return  do_compile_modgroup(parent, component, cs,
2342                                                     GROUPTYPE_SIMPLE,
2343                                                     grouptype, MOD_ELSE);
2344
2345                 } else  if (strcmp(modrefname, "update") == 0) {
2346                         *modname = name2;
2347
2348                         return do_compile_modupdate(parent, component, cs,
2349                                                     name2);
2350
2351                 } else  if (strcmp(modrefname, "switch") == 0) {
2352                         *modname = name2;
2353
2354                         return do_compile_modswitch (parent, component, cs);
2355
2356                 } else  if (strcmp(modrefname, "case") == 0) {
2357                         *modname = name2;
2358
2359                         return do_compile_modcase(parent, component, cs);
2360
2361                 } else  if (strcmp(modrefname, "foreach") == 0) {
2362                         *modname = name2;
2363
2364                         return do_compile_modforeach(parent, component, cs);
2365
2366 #endif
2367                 } /* else it's something like sql { fail = 1 ...} */
2368
2369         } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
2370                 return NULL;
2371
2372                 /*
2373                  *      Else it's a module reference, with updated return
2374                  *      codes.
2375                  */
2376         } else {
2377                 CONF_SECTION *loop;
2378                 CONF_PAIR *cp = cf_itemtopair(ci);
2379                 modrefname = cf_pair_attr(cp);
2380
2381                 /*
2382                  *      Actions (ok = 1), etc. are orthogonal to just
2383                  *      about everything else.
2384                  */
2385                 if (cf_pair_value(cp) != NULL) {
2386                         cf_log_err(ci, "Entry is not a reference to a module");
2387                         return NULL;
2388                 }
2389
2390                 if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
2391                     (modrefname[0] == '`')) {
2392                         return do_compile_modxlat(parent, component,
2393                                                   modrefname);
2394                 }
2395
2396                 /*
2397                  *      See if the module is a virtual one.  If so,
2398                  *      return that, rather than doing anything here.
2399                  */
2400                 subcs = NULL;
2401                 cs = cf_section_find("instantiate");
2402                 if (cs) subcs = cf_section_sub_find_name2(cs, NULL,
2403                                                           modrefname);
2404                 if (!subcs &&
2405                     (cs = cf_section_find("policy")) != NULL) {
2406                         char buffer[256];
2407
2408                         snprintf(buffer, sizeof(buffer), "%s.%s",
2409                                  modrefname, comp2str[component]);
2410
2411                         /*
2412                          *      Prefer name.section, then name.
2413                          */
2414                         subcs = cf_section_sub_find_name2(cs, NULL,
2415                                                           buffer);
2416                         if (!subcs) {
2417                                 subcs = cf_section_sub_find_name2(cs, NULL,
2418                                                                   modrefname);
2419                         }
2420                 }
2421
2422                 /*
2423                  *      Allow policies to over-ride module names.
2424                  *      i.e. the "sql" policy can do some extra things,
2425                  *      and then call the "sql" module.
2426                  */
2427                 for (loop = cf_item_parent(ci);
2428                      loop && subcs;
2429                      loop = cf_item_parent(cf_sectiontoitem(loop))) {
2430                         if (loop == subcs) {
2431                                 subcs = NULL;
2432                         }
2433                 }
2434
2435                 if (subcs) {
2436                         /*
2437                          *      redundant foo {} is a single.
2438                          */
2439                         if (cf_section_name2(subcs)) {
2440                                 return do_compile_modsingle(parent,
2441                                                             component,
2442                                                             cf_sectiontoitem(subcs),
2443                                                             grouptype,
2444                                                             modname);
2445                         } else {
2446                                 /*
2447                                  *      foo {} is a group.
2448                                  */
2449                                 return do_compile_modgroup(parent,
2450                                                            component,
2451                                                            subcs,
2452                                                            GROUPTYPE_SIMPLE,
2453                                                            grouptype, MOD_GROUP);
2454                         }
2455                 }
2456         }
2457
2458 #ifdef WITH_UNLANG
2459         if (strcmp(modrefname, "break") == 0) {
2460                 return do_compile_modbreak(parent, component, ci);
2461         }
2462
2463         if (strcmp(modrefname, "return") == 0) {
2464                 return do_compile_modgroup(parent, component, NULL,
2465                                            GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
2466                                            MOD_RETURN);
2467         }
2468 #endif
2469
2470         /*
2471          *      Not a virtual module.  It must be a real module.
2472          */
2473         modules = cf_section_find("modules");
2474         this = NULL;
2475         realname = modrefname;
2476
2477         if (modules) {
2478                 /*
2479                  *      Try to load the optional module.
2480                  */
2481                 if (realname[0] == '-') realname++;
2482
2483                 /*
2484                  *      As of v3, only known modules are in the
2485                  *      "modules" section.
2486                  */
2487                 if (cf_section_sub_find_name2(modules, NULL, realname)) {
2488                         this = find_module_instance(modules, realname, true);
2489                         if (!this && (realname != modrefname)) {
2490                                 return NULL;
2491                         }
2492
2493                 } else {
2494                         /*
2495                          *      We were asked to MAYBE load it and it
2496                          *      doesn't exist.  Return a soft error.
2497                          */
2498                         if (realname != modrefname) {
2499                                 *modname = modrefname;
2500                                 return NULL;
2501                         }
2502                 }
2503         }
2504
2505         if (!this) do {
2506                 int i;
2507                 char *p;
2508
2509                 /*
2510                  *      Maybe it's module.method
2511                  */
2512                 p = strrchr(modrefname, '.');
2513                 if (p) for (i = RLM_COMPONENT_AUTH;
2514                             i < RLM_COMPONENT_COUNT;
2515                             i++) {
2516                         if (strcmp(p + 1, comp2str[i]) == 0) {
2517                                 char buffer[256];
2518
2519                                 strlcpy(buffer, modrefname, sizeof(buffer));
2520                                 buffer[p - modrefname] = '\0';
2521                                 component = i;
2522
2523                                 this = find_module_instance(modules, buffer, true);
2524                                 if (this && !this->entry->module->methods[i]) {
2525                                         *modname = NULL;
2526                                         cf_log_err(ci, "Module %s has no such method %s", buffer, comp2str[i]);
2527                                         return NULL;
2528                                 }
2529                                 break;
2530                         }
2531                 }
2532                 if (this) break;
2533
2534                 /*
2535                  *      Call a server.  This should really be deleted...
2536                  */
2537                 if (strncmp(modrefname, "server[", 7) == 0) {
2538                         char buffer[256];
2539
2540                         strlcpy(buffer, modrefname + 7, sizeof(buffer));
2541                         p = strrchr(buffer, ']');
2542                         if (!p || p[1] != '\0' || (p == buffer)) {
2543                                 cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
2544                                 return NULL;
2545                         }
2546                         *p = '\0';
2547
2548                         cs = cf_section_sub_find_name2(NULL, "server", buffer);
2549                         if (!cs) {
2550                                 cf_log_err(ci, "No such server \"%s\".", buffer);
2551                                 return NULL;
2552                         }
2553
2554                         return do_compile_modserver(parent, component, ci,
2555                                                     modrefname, cs, buffer);
2556                 }
2557
2558                 *modname = NULL;
2559                 cf_log_err(ci, "Failed to find \"%s\" in the \"modules\" section.", modrefname);
2560                 cf_log_err(ci, "Please verify that the configuration exists in the file %s/mods-enabled/%s.", get_radius_dir(), modrefname);
2561                 return NULL;
2562         } while (0);
2563
2564         /*
2565          *      We know it's all OK, allocate the structures, and fill
2566          *      them in.
2567          */
2568         single = talloc_zero(parent, modsingle);
2569         csingle = mod_singletocallable(single);
2570         csingle->parent = parent;
2571         csingle->next = NULL;
2572         if (!parent || (component != RLM_COMPONENT_AUTH)) {
2573                 memcpy(csingle->actions, defaultactions[component][grouptype],
2574                        sizeof csingle->actions);
2575         } else { /* inside Auth-Type has different rules */
2576                 memcpy(csingle->actions, defaultactions[RLM_COMPONENT_AUTZ][grouptype],
2577                        sizeof csingle->actions);
2578         }
2579         rad_assert(modrefname != NULL);
2580         csingle->name = realname;
2581         csingle->type = MOD_SINGLE;
2582         csingle->method = component;
2583
2584         /*
2585          *      Singles can override the actions, virtual modules cannot.
2586          *
2587          *      FIXME: We may want to re-visit how to do this...
2588          *      maybe a csingle as a ref?
2589          */
2590         if (cf_item_is_section(ci)) {
2591                 CONF_ITEM *csi;
2592
2593                 cs = cf_itemtosection(ci);
2594                 for (csi=cf_item_find_next(cs, NULL);
2595                      csi != NULL;
2596                      csi=cf_item_find_next(cs, csi)) {
2597
2598                         if (cf_item_is_section(csi)) {
2599                                 cf_log_err(csi, "Subsection of module instance call not allowed");
2600                                 talloc_free(csingle);
2601                                 return NULL;
2602                         }
2603
2604                         if (!cf_item_is_pair(csi)) continue;
2605
2606                         if (!compile_action(csingle, cf_itemtopair(csi))) {
2607                                 talloc_free(csingle);
2608                                 return NULL;
2609                         }
2610                 }
2611         }
2612
2613         /*
2614          *      Bail out if the module in question does not supply the
2615          *      wanted component
2616          */
2617         if (!this->entry->module->methods[component]) {
2618                 cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
2619                        comp2str[component]);
2620                 talloc_free(csingle);
2621                 return NULL;
2622         }
2623
2624         single->modinst = this;
2625         *modname = this->entry->module->name;
2626         return csingle;
2627 }
2628
2629 modcallable *compile_modsingle(TALLOC_CTX *ctx,
2630                                modcallable **parent,
2631                                rlm_components_t component, CONF_ITEM *ci,
2632                                char const **modname)
2633 {
2634         modcallable *ret;
2635
2636         if (!*parent) {
2637                 modcallable *c;
2638                 modgroup *g;
2639                 CONF_SECTION *parentcs;
2640
2641                 g = talloc_zero(ctx, modgroup);
2642                 memset(g, 0, sizeof(*g));
2643                 g->grouptype = GROUPTYPE_SIMPLE;
2644                 c = mod_grouptocallable(g);
2645                 c->next = NULL;
2646                 memcpy(c->actions,
2647                        defaultactions[component][GROUPTYPE_SIMPLE],
2648                        sizeof(c->actions));
2649
2650                 parentcs = cf_item_parent(ci);
2651                 c->name = cf_section_name2(parentcs);
2652                 if (!c->name) {
2653                         c->name = cf_section_name1(parentcs);
2654                 }
2655
2656                 c->type = MOD_GROUP;
2657                 c->method = component;
2658                 g->children = NULL;
2659
2660                 *parent = mod_grouptocallable(g);
2661         }
2662
2663         ret = do_compile_modsingle(*parent, component, ci,
2664                                    GROUPTYPE_SIMPLE,
2665                                    modname);
2666         dump_tree(component, ret);
2667         return ret;
2668 }
2669
2670
2671 /*
2672  *      Internal compile group code.
2673  */
2674 static modcallable *do_compile_modgroup(modcallable *parent,
2675                                         rlm_components_t component, CONF_SECTION *cs,
2676                                         int grouptype, int parentgrouptype, int mod_type)
2677 {
2678         int i;
2679         modgroup *g;
2680         modcallable *c;
2681         CONF_ITEM *ci;
2682
2683         g = talloc_zero(parent, modgroup);
2684         g->grouptype = grouptype;
2685         g->children = NULL;
2686         g->cs = cs;
2687
2688         c = mod_grouptocallable(g);
2689         c->parent = parent;
2690         c->type = mod_type;
2691         c->next = NULL;
2692         memset(c->actions, 0, sizeof(c->actions));
2693
2694         if (!cs) {              /* only for "break" and "return" */
2695                 c->name = "";
2696                 goto set_codes;
2697         }
2698
2699         /*
2700          *      Remember the name for printing, etc.
2701          *
2702          *      FIXME: We may also want to put the names into a
2703          *      rbtree, so that groups can reference each other...
2704          */
2705         c->name = cf_section_name2(cs);
2706         if (!c->name) {
2707                 c->name = cf_section_name1(cs);
2708                 if ((strcmp(c->name, "group") == 0) ||
2709                     (strcmp(c->name, "redundant") == 0)) {
2710                         c->name = "";
2711                 } else if (c->type == MOD_GROUP) {
2712                         c->type = MOD_POLICY;
2713                 }
2714         }
2715
2716 #ifdef WITH_UNLANG
2717         /*
2718          *      Do load-time optimizations
2719          */
2720         if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
2721                 modgroup *f, *p;
2722
2723                 rad_assert(parent != NULL);
2724
2725                 if (c->type == MOD_IF) {
2726                         g->cond = cf_data_find(g->cs, "if");
2727                         rad_assert(g->cond != NULL);
2728
2729                 check_if:
2730                         if (g->cond->type == COND_TYPE_FALSE) {
2731                                 INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
2732                                      group_name[g->mc.type],
2733                                      cf_section_filename(g->cs), cf_section_lineno(g->cs));
2734                                 goto set_codes;
2735                         }
2736
2737                 } else if (c->type == MOD_ELSIF) {
2738
2739                         g->cond = cf_data_find(g->cs, "if");
2740                         rad_assert(g->cond != NULL);
2741
2742                         rad_assert(parent != NULL);
2743                         p = mod_callabletogroup(parent);
2744
2745                         rad_assert(p->tail != NULL);
2746
2747                         f = mod_callabletogroup(p->tail);
2748                         rad_assert((f->mc.type == MOD_IF) ||
2749                                    (f->mc.type == MOD_ELSIF));
2750
2751                         /*
2752                          *      If we took the previous condition, we
2753                          *      don't need to take this one.
2754                          *
2755                          *      We reset our condition to 'true', so
2756                          *      that subsequent sections can check
2757                          *      that they don't need to be executed.
2758                          */
2759                         if (f->cond->type == COND_TYPE_TRUE) {
2760                         skip_true:
2761                                 INFO(" # Skipping contents of '%s' as previous '%s' is always  'true' -- %s:%d",
2762                                      group_name[g->mc.type],
2763                                      group_name[f->mc.type],
2764                                      cf_section_filename(g->cs), cf_section_lineno(g->cs));
2765                                 g->cond = f->cond;
2766                                 goto set_codes;
2767                         }
2768                         goto check_if;
2769
2770                 } else {
2771                         rad_assert(c->type == MOD_ELSE);
2772
2773                         rad_assert(parent != NULL);
2774                         p = mod_callabletogroup(parent);
2775
2776                         rad_assert(p->tail != NULL);
2777
2778                         f = mod_callabletogroup(p->tail);
2779                         rad_assert((f->mc.type == MOD_IF) ||
2780                                    (f->mc.type == MOD_ELSIF));
2781
2782                         /*
2783                          *      If we took the previous condition, we
2784                          *      don't need to take this one.
2785                          */
2786                         if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
2787                 }
2788
2789                 /*
2790                  *      Else we need to compile this section
2791                  */
2792         }
2793 #endif
2794
2795         /*
2796          *      Loop over the children of this group.
2797          */
2798         for (ci=cf_item_find_next(cs, NULL);
2799              ci != NULL;
2800              ci=cf_item_find_next(cs, ci)) {
2801
2802                 /*
2803                  *      Sections are references to other groups, or
2804                  *      to modules with updated return codes.
2805                  */
2806                 if (cf_item_is_section(ci)) {
2807                         char const *junk = NULL;
2808                         modcallable *single;
2809                         CONF_SECTION *subcs = cf_itemtosection(ci);
2810
2811                         single = do_compile_modsingle(c, component, ci,
2812                                                       grouptype, &junk);
2813                         if (!single) {
2814                                 cf_log_err(ci, "Failed to parse \"%s\" subsection.",
2815                                        cf_section_name1(subcs));
2816                                 talloc_free(c);
2817                                 return NULL;
2818                         }
2819                         add_child(g, single);
2820
2821                 } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
2822                         continue;
2823
2824                 } else {
2825                         char const *attr, *value;
2826                         CONF_PAIR *cp = cf_itemtopair(ci);
2827
2828                         attr = cf_pair_attr(cp);
2829                         value = cf_pair_value(cp);
2830
2831                         /*
2832                          *      A CONF_PAIR is either a module
2833                          *      instance with no actions
2834                          *      specified ...
2835                          */
2836                         if (!value) {
2837                                 modcallable *single;
2838                                 char const *junk = NULL;
2839
2840                                 single = do_compile_modsingle(c,
2841                                                               component,
2842                                                               ci,
2843                                                               grouptype,
2844                                                               &junk);
2845                                 if (!single) {
2846                                         if (cf_item_is_pair(ci) &&
2847                                             cf_pair_attr(cf_itemtopair(ci))[0] == '-') {
2848                                                 continue;
2849                                         }
2850
2851                                         cf_log_err(ci,
2852                                                    "Failed to parse \"%s\" entry.",
2853                                                    attr);
2854                                         talloc_free(c);
2855                                         return NULL;
2856                                 }
2857                                 add_child(g, single);
2858
2859                                 /*
2860                                  *      Or a module instance with action.
2861                                  */
2862                         } else if (!compile_action(c, cp)) {
2863                                 talloc_free(c);
2864                                 return NULL;
2865                         } /* else it worked */
2866                 }
2867         }
2868
2869 set_codes:
2870         /*
2871          *      Set the default actions, if they haven't already been
2872          *      set.
2873          */
2874         for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
2875                 if (!c->actions[i]) {
2876                         if (!parent || (component != RLM_COMPONENT_AUTH)) {
2877                                 c->actions[i] = defaultactions[component][parentgrouptype][i];
2878                         } else { /* inside Auth-Type has different rules */
2879                                 c->actions[i] = defaultactions[RLM_COMPONENT_AUTZ][parentgrouptype][i];
2880                         }
2881                 }
2882         }
2883
2884         switch (c->type) {
2885         default:
2886                 break;
2887
2888         case MOD_GROUP:
2889                 if (grouptype != GROUPTYPE_REDUNDANT) break;
2890                 /* FALL-THROUGH */
2891
2892         case MOD_LOAD_BALANCE:
2893         case MOD_REDUNDANT_LOAD_BALANCE:
2894                 if (!g->children) {
2895                         cf_log_err_cs(g->cs, "%s sections cannot be empty",
2896                                       cf_section_name1(g->cs));
2897                         talloc_free(c);
2898                         return NULL;
2899                 }
2900         }
2901
2902         /*
2903          *      FIXME: If there are no children, return NULL?
2904          */
2905         return mod_grouptocallable(g);
2906 }
2907
2908 modcallable *compile_modgroup(modcallable *parent,
2909                               rlm_components_t component, CONF_SECTION *cs)
2910 {
2911         modcallable *ret = do_compile_modgroup(parent, component, cs,
2912                                                GROUPTYPE_SIMPLE,
2913                                                GROUPTYPE_SIMPLE, MOD_GROUP);
2914
2915         if (debug_flag > 3) {
2916                 modcall_debug(ret, 2);
2917         }
2918
2919         return ret;
2920 }
2921
2922 void add_to_modcallable(modcallable *parent, modcallable *this)
2923 {
2924         modgroup *g;
2925
2926         rad_assert(this != NULL);
2927         rad_assert(parent != NULL);
2928
2929         g = mod_callabletogroup(parent);
2930
2931         add_child(g, this);
2932 }
2933
2934
2935 #ifdef WITH_UNLANG
2936 static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert,
2937                                DICT_ATTR const *da)
2938 {
2939         ssize_t slen;
2940         char *fmt;
2941         char const *error;
2942         xlat_exp_t *head;
2943         value_pair_tmpl_t *vpt;
2944
2945         vpt = *pvpt;
2946
2947         rad_assert(vpt->type == TMPL_TYPE_XLAT);
2948
2949         fmt = talloc_typed_strdup(vpt, vpt->name);
2950         slen = xlat_tokenize(vpt, fmt, &head, &error);
2951
2952         if (slen < 0) {
2953                 char *spaces, *text;
2954
2955                 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
2956
2957                 cf_log_err(ci, "Failed parsing expanded string:");
2958                 cf_log_err(ci, "%s", text);
2959                 cf_log_err(ci, "%s^ %s", spaces, error);
2960
2961                 talloc_free(spaces);
2962                 talloc_free(text);
2963                 return false;
2964         }
2965
2966         /*
2967          *      Convert %{Attribute-Name} to &Attribute-Name
2968          */
2969         if (convert) {
2970                 value_pair_tmpl_t *attr;
2971
2972                 attr = xlat_to_tmpl_attr(talloc_parent(vpt), head);
2973                 if (attr) {
2974                         /*
2975                          *      If it's a virtual attribute, leave it
2976                          *      alone.
2977                          */
2978                         if (attr->tmpl_da->flags.virtual) {
2979                                 talloc_free(attr);
2980                                 return true;
2981                         }
2982
2983                         /*
2984                          *      If the attribute is of incompatible
2985                          *      type, leave it alone.
2986                          */
2987                         if (da && (da->type != attr->tmpl_da->type)) {
2988                                 talloc_free(attr);
2989                                 return true;
2990                         }
2991
2992                         if (cf_item_is_pair(ci)) {
2993                                 CONF_PAIR *cp = cf_itemtopair(ci);
2994
2995                                 WARN("%s[%d] Please change %%{%s} to &%s",
2996                                        cf_pair_filename(cp), cf_pair_lineno(cp),
2997                                        attr->name, attr->name);
2998                         } else {
2999                                 CONF_SECTION *cs = cf_itemtosection(ci);
3000
3001                                 WARN("%s[%d] Please change %%{%s} to &%s",
3002                                        cf_section_filename(cs), cf_section_lineno(cs),
3003                                        attr->name, attr->name);
3004                         }
3005                         TALLOC_FREE(*pvpt);
3006                         *pvpt = attr;
3007                         return true;
3008                 }
3009         }
3010
3011         /*
3012          *      Re-write it to be a pre-parsed XLAT structure.
3013          */
3014         vpt->type = TMPL_TYPE_XLAT_STRUCT;
3015         vpt->tmpl_xlat = head;
3016
3017         return true;
3018 }
3019
3020
3021 #ifdef HAVE_REGEX
3022 static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3023 {
3024         ssize_t slen;
3025         regex_t *preg;
3026
3027         rad_assert(vpt->type == TMPL_TYPE_REGEX);
3028
3029         /*
3030          *      It's a dynamic expansion.  We can't expand the string,
3031          *      but we can pre-parse it as an xlat struct.  In that
3032          *      case, we convert it to a pre-compiled XLAT.
3033          *
3034          *      This is a little more complicated than it needs to be
3035          *      because radius_evaluate_map() keys off of the src
3036          *      template type, instead of the operators.  And, the
3037          *      pass2_xlat_compile() function expects to get passed an
3038          *      XLAT instead of a REGEX.
3039          */
3040         if (strchr(vpt->name, '%')) {
3041                 vpt->type = TMPL_TYPE_XLAT;
3042                 return pass2_xlat_compile(ci, &vpt, false, NULL);
3043         }
3044
3045         slen = regex_compile(vpt, &preg, vpt->name, vpt->len,
3046                              vpt->tmpl_iflag, vpt->tmpl_mflag, false);
3047         if (slen <= 0) {
3048                 char *spaces, *text;
3049
3050                 fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
3051
3052                 cf_log_err(ci, "Invalid regular expression:");
3053                 cf_log_err(ci, "%s", text);
3054                 cf_log_err(ci, "%s^ %s", spaces, fr_strerror());
3055
3056                 talloc_free(spaces);
3057                 talloc_free(text);
3058
3059                 return false;
3060         }
3061
3062         vpt->type = TMPL_TYPE_REGEX_STRUCT;
3063         vpt->tmpl_preg = preg;
3064
3065         return true;
3066 }
3067 #endif
3068
3069 static bool pass2_fixup_undefined(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
3070 {
3071         DICT_ATTR const *da;
3072
3073         rad_assert(vpt->type == TMPL_TYPE_ATTR_UNDEFINED);
3074
3075         da = dict_attrbyname(vpt->tmpl_unknown_name);
3076         if (!da) {
3077                 cf_log_err(ci, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
3078                 return false;
3079         }
3080
3081         vpt->tmpl_da = da;
3082         vpt->type = TMPL_TYPE_ATTR;
3083         return true;
3084 }
3085
3086 static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
3087 {
3088         value_pair_map_t *map;
3089
3090         if (c->type == COND_TYPE_EXISTS) {
3091                 if (c->data.vpt->type == TMPL_TYPE_XLAT) {
3092                         return pass2_xlat_compile(c->ci, &c->data.vpt, true, NULL);
3093                 }
3094
3095                 rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
3096
3097                 /*
3098                  *      The existence check might have been &Foo-Bar,
3099                  *      where Foo-Bar is defined by a module.
3100                  */
3101                 if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3102                         if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
3103                         c->pass2_fixup = PASS2_FIXUP_NONE;
3104                 }
3105                 return true;
3106         }
3107
3108         /*
3109          *      Maps have a paircompare fixup applied to them.
3110          *      Others get ignored.
3111          */
3112         if (c->pass2_fixup == PASS2_FIXUP_NONE) {
3113                 if (c->type == COND_TYPE_MAP) {
3114                         map = c->data.map;
3115                         goto check_paircmp;
3116                 }
3117
3118                 return true;
3119         }
3120
3121         map = c->data.map;      /* shorter */
3122
3123         /*
3124          *      Auth-Type := foo
3125          *
3126          *      Where "foo" is dynamically defined.
3127          */
3128         if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
3129                 if (!dict_valbyname(map->lhs->tmpl_da->attr,
3130                                     map->lhs->tmpl_da->vendor,
3131                                     map->rhs->name)) {
3132                         cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
3133                                    map->lhs->tmpl_da->name,
3134                                    map->rhs->name);
3135                         return false;
3136                 }
3137
3138                 /*
3139                  *      These guys can't have a paircompare fixup applied.
3140                  */
3141                 c->pass2_fixup = PASS2_FIXUP_NONE;
3142                 return true;
3143         }
3144
3145         if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
3146                 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3147                         if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
3148                 }
3149
3150                 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3151                         if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
3152                 }
3153
3154                 c->pass2_fixup = PASS2_FIXUP_NONE;
3155         }
3156
3157 check_paircmp:
3158         /*
3159          *      Just in case someone adds a new fixup later.
3160          */
3161         rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
3162                    (c->pass2_fixup == PASS2_PAIRCOMPARE));
3163
3164         /*
3165          *      Precompile xlat's
3166          */
3167         if (map->lhs->type == TMPL_TYPE_XLAT) {
3168                 /*
3169                  *      Don't compile the LHS to an attribute
3170                  *      reference for now.  When we do that, we've got
3171                  *      to check the RHS for type-specific data, and
3172                  *      parse it to a TMPL_TYPE_DATA.
3173                  */
3174                 if (!pass2_xlat_compile(map->ci, &map->lhs, false, NULL)) {
3175                         return false;
3176                 }
3177         }
3178
3179         if (map->rhs->type == TMPL_TYPE_XLAT) {
3180                 /*
3181                  *      Convert the RHS to an attribute reference only
3182                  *      if the LHS is an attribute reference, AND is
3183                  *      of the same type as the RHS.
3184                  *
3185                  *      We can fix this when the code in evaluate.c
3186                  *      can handle strings on the LHS, and attributes
3187                  *      on the RHS.  For now, the code in parser.c
3188                  *      forbids this.
3189                  */
3190                 if (map->lhs->type == TMPL_TYPE_ATTR) {
3191                         DICT_ATTR const *da = c->cast;
3192
3193                         if (!c->cast) da = map->lhs->tmpl_da;
3194
3195                         if (!pass2_xlat_compile(map->ci, &map->rhs, true, da)) {
3196                                 return false;
3197                         }
3198
3199                 } else {
3200                         if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3201                                 return false;
3202                         }
3203                 }
3204         }
3205
3206         /*
3207          *      Convert bare refs to %{Foreach-Variable-N}
3208          */
3209         if ((map->lhs->type == TMPL_TYPE_LITERAL) &&
3210             (strncmp(map->lhs->name, "Foreach-Variable-", 17) == 0)) {
3211                 char *fmt;
3212                 ssize_t slen;
3213                 value_pair_tmpl_t *vpt;
3214
3215                 fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
3216                 slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
3217                                       T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
3218                 if (slen < 0) {
3219                         char *spaces, *text;
3220
3221                         fr_canonicalize_error(map->ci, &spaces, &text, slen, fr_strerror());
3222
3223                         cf_log_err(map->ci, "Failed converting %s to xlat", map->lhs->name);
3224                         cf_log_err(map->ci, "%s", fmt);
3225                         cf_log_err(map->ci, "%s^ %s", spaces, text);
3226
3227                         talloc_free(spaces);
3228                         talloc_free(text);
3229                         talloc_free(fmt);
3230
3231                         return false;
3232                 }
3233                 talloc_free(map->lhs);
3234                 map->lhs = vpt;
3235         }
3236
3237 #ifdef HAVE_REGEX
3238         if (map->rhs->type == TMPL_TYPE_REGEX) {
3239                 if (!pass2_regex_compile(map->ci, map->rhs)) {
3240                         return false;
3241                 }
3242         }
3243         rad_assert(map->lhs->type != TMPL_TYPE_REGEX);
3244 #endif
3245
3246         /*
3247          *      Only attributes can have a paircompare registered, and
3248          *      they can only be with the current REQUEST, and only
3249          *      with the request pairs.
3250          */
3251         if ((map->lhs->type != TMPL_TYPE_ATTR) ||
3252             (map->lhs->tmpl_request != REQUEST_CURRENT) ||
3253             (map->lhs->tmpl_list != PAIR_LIST_REQUEST)) {
3254                 return true;
3255         }
3256
3257         if (!radius_find_compare(map->lhs->tmpl_da)) return true;
3258
3259         if (map->rhs->type == TMPL_TYPE_ATTR) {
3260                 cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
3261                            map->lhs->name);
3262                 return false;
3263         }
3264
3265         if (map->rhs->type == TMPL_TYPE_REGEX) {
3266                 cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
3267                            map->lhs->name);
3268                 return false;
3269         }
3270
3271         if (c->cast) {
3272                 cf_log_err(map->ci, "Cannot cast virtual attribute %s",
3273                            map->lhs->name);
3274                 return false;
3275         }
3276
3277         if (map->op != T_OP_CMP_EQ) {
3278                 cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
3279                            map->lhs->name);
3280                 return false;
3281         }
3282
3283         /*
3284          *      Mark it as requiring a paircompare() call, instead of
3285          *      paircmp().
3286          */
3287         c->pass2_fixup = PASS2_PAIRCOMPARE;
3288
3289         return true;
3290 }
3291
3292
3293 /*
3294  *      Compile the RHS of update sections to xlat_exp_t
3295  */
3296 static bool modcall_pass2_update(modgroup *g)
3297 {
3298         value_pair_map_t *map;
3299
3300         for (map = g->map; map != NULL; map = map->next) {
3301                 if (map->rhs->type == TMPL_TYPE_XLAT) {
3302                         rad_assert(map->rhs->tmpl_xlat == NULL);
3303
3304                         /*
3305                          *      FIXME: compile to attribute && handle
3306                          *      the conversion in map_to_vp().
3307                          */
3308                         if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
3309                                 return false;
3310                         }
3311                 }
3312
3313                 rad_assert(map->rhs->type != TMPL_TYPE_REGEX);
3314
3315                 if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3316                         cf_log_err(map->ci, "Attribute '%s' is unknown", map->lhs->name);
3317                         return false;
3318                 }
3319
3320                 if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
3321                         cf_log_err(map->ci, "Attribute '%s' is unknown", map->rhs->name);
3322                         return false;
3323                 }
3324         }
3325
3326         return true;
3327 }
3328 #endif
3329
3330 /*
3331  *      Do a second-stage pass on compiling the modules.
3332  */
3333 bool modcall_pass2(modcallable *mc)
3334 {
3335         ssize_t slen;
3336         char const *name2;
3337         modcallable *c;
3338         modgroup *g;
3339
3340         for (c = mc; c != NULL; c = c->next) {
3341                 switch (c->type) {
3342                 default:
3343                         rad_assert(0 == 1);
3344                         break;
3345
3346 #ifdef WITH_UNLANG
3347                 case MOD_UPDATE:
3348                         g = mod_callabletogroup(c);
3349                         if (g->done_pass2) return true;
3350
3351                         name2 = cf_section_name2(g->cs);
3352                         if (!name2) {
3353                                 c->debug_name = group_name[c->type];
3354                         } else {
3355                                 c->debug_name = talloc_asprintf(c, "update %s", name2);
3356                         }
3357
3358                         if (!modcall_pass2_update(g)) {
3359                                 return false;
3360                         }
3361                         g->done_pass2 = true;
3362                         break;
3363
3364                 case MOD_XLAT:   /* @todo: pre-parse xlat's */
3365                 case MOD_REFERENCE:
3366                 case MOD_BREAK:
3367                 case MOD_RETURN:
3368 #endif
3369
3370                 case MOD_SINGLE:
3371                         c->debug_name = c->name;
3372                         break;  /* do nothing */
3373
3374 #ifdef WITH_UNLANG
3375                 case MOD_IF:
3376                 case MOD_ELSIF:
3377                         g = mod_callabletogroup(c);
3378                         if (g->done_pass2) return true;
3379
3380                         name2 = cf_section_name2(g->cs);
3381                         c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3382
3383                         /*
3384                          *      Don't walk over these.
3385                          */
3386                         if ((g->cond->type == COND_TYPE_TRUE) ||
3387                             (g->cond->type == COND_TYPE_FALSE)) {
3388                                 break;
3389                         }
3390
3391                         /*
3392                          *      The compilation code takes care of
3393                          *      simplifying 'true' and 'false'
3394                          *      conditions.  For others, we have to do
3395                          *      a second pass to parse && compile xlats.
3396                          */
3397                         if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
3398                                 return false;
3399                         }
3400
3401                         if (!modcall_pass2(g->children)) return false;
3402                         g->done_pass2 = true;
3403                         break;
3404 #endif
3405
3406 #ifdef WITH_UNLANG
3407                 case MOD_SWITCH:
3408                         g = mod_callabletogroup(c);
3409                         if (g->done_pass2) return true;
3410
3411                         name2 = cf_section_name2(g->cs);
3412                         c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3413
3414                         /*
3415                          *      We had &Foo-Bar, where Foo-Bar is
3416                          *      defined by a module.
3417                          */
3418                         if (!g->vpt) {
3419                                 rad_assert(c->name != NULL);
3420                                 rad_assert(c->name[0] == '&');
3421                                 rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3422
3423                                 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3424                                                       cf_section_name2_type(g->cs),
3425                                                       REQUEST_CURRENT, PAIR_LIST_REQUEST);
3426                                 if (slen < 0) {
3427                                         char *spaces, *text;
3428
3429                                 parse_error:
3430                                         fr_canonicalize_error(g->cs, &spaces, &text, slen, fr_strerror());
3431
3432                                         cf_log_err_cs(g->cs, "Syntax error");
3433                                         cf_log_err_cs(g->cs, "%s", c->name);
3434                                         cf_log_err_cs(g->cs, "%s^ %s", spaces, text);
3435
3436                                         talloc_free(spaces);
3437                                         talloc_free(text);
3438
3439                                         return false;
3440                                 }
3441
3442                                 goto do_children;
3443                         }
3444
3445                         /*
3446                          *      Statically compile xlats
3447                          */
3448                         if (g->vpt->type == TMPL_TYPE_XLAT) {
3449                                 if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3450                                                         &g->vpt, true, NULL)) {
3451                                         return false;
3452                                 }
3453
3454                                 goto do_children;
3455                         }
3456
3457                         /*
3458                          *      We may have: switch Foo-Bar {
3459                          *
3460                          *      where Foo-Bar is an attribute defined
3461                          *      by a module.  Since there's no leading
3462                          *      &, it's parsed as a literal.  But if
3463                          *      we can parse it as an attribute,
3464                          *      switch to using that.
3465                          */
3466                         if (g->vpt->type == TMPL_TYPE_LITERAL) {
3467                                 value_pair_tmpl_t *vpt;
3468
3469                                 slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3470                                                       REQUEST_CURRENT, PAIR_LIST_REQUEST);
3471                                 if (slen < 0) goto parse_error;
3472                                 if (vpt->type == TMPL_TYPE_ATTR) {
3473                                         talloc_free(g->vpt);
3474                                         g->vpt = vpt;
3475                                 }
3476
3477                                 goto do_children;
3478                         }
3479
3480                         /*
3481                          *      Warn about old-style configuration.
3482                          *
3483                          *      DEPRECATED: switch User-Name { ...
3484                          *      ALLOWED   : switch &User-Name { ...
3485                          */
3486                         if ((g->vpt->type == TMPL_TYPE_ATTR) &&
3487                             (c->name[0] != '&')) {
3488                                 WARN("%s[%d]: Please change %s to &%s",
3489                                        cf_section_filename(g->cs),
3490                                        cf_section_lineno(g->cs),
3491                                        c->name, c->name);
3492                         }
3493
3494                 do_children:
3495                         if (!modcall_pass2(g->children)) return false;
3496                         g->done_pass2 = true;
3497                         break;
3498
3499                 case MOD_CASE:
3500                         g = mod_callabletogroup(c);
3501                         if (g->done_pass2) return true;
3502
3503                         name2 = cf_section_name2(g->cs);
3504                         if (!name2) {
3505                                 c->debug_name = group_name[c->type];
3506                         } else {
3507                                 c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3508                         }
3509
3510                         rad_assert(c->parent != NULL);
3511                         rad_assert(c->parent->type == MOD_SWITCH);
3512
3513                         /*
3514                          *      The statement may refer to an
3515                          *      attribute which doesn't exist until
3516                          *      all of the modules have been loaded.
3517                          *      Check for that now.
3518                          */
3519                         if (!g->vpt && c->name &&
3520                             (c->name[0] == '&') &&
3521                             (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
3522                                 slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
3523                                                       cf_section_name2_type(g->cs),
3524                                                       REQUEST_CURRENT, PAIR_LIST_REQUEST);
3525                                 if (slen < 0) goto parse_error;
3526                         }
3527
3528                         /*
3529                          *      We have "case {...}".  There's no
3530                          *      argument, so we don't need to check
3531                          *      it.
3532                          */
3533                         if (!g->vpt) goto do_children;
3534
3535                         /*
3536                          *      Do type-specific checks on the case statement
3537                          */
3538                         if (g->vpt->type == TMPL_TYPE_LITERAL) {
3539                                 modgroup *f;
3540
3541                                 f = mod_callabletogroup(mc->parent);
3542                                 rad_assert(f->vpt != NULL);
3543
3544                                 /*
3545                                  *      We're switching over an
3546                                  *      attribute.  Check that the
3547                                  *      values match.
3548                                  */
3549                                 if (f->vpt->type == TMPL_TYPE_ATTR) {
3550                                         rad_assert(f->vpt->tmpl_da != NULL);
3551
3552                                         if (!tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da)) {
3553                                                 cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
3554                                                               fr_strerror());
3555                                                 return false;
3556                                         }
3557                                 }
3558
3559                                 goto do_children;
3560                         }
3561
3562                         /*
3563                          *      Compile and sanity check xlat
3564                          *      expansions.
3565                          */
3566                         if (g->vpt->type == TMPL_TYPE_XLAT) {
3567                                 modgroup *f;
3568
3569                                 f = mod_callabletogroup(mc->parent);
3570                                 rad_assert(f->vpt != NULL);
3571
3572                                 /*
3573                                  *      Don't expand xlat's into an
3574                                  *      attribute of a different type.
3575                                  */
3576                                 if (f->vpt->type == TMPL_TYPE_ATTR) {
3577                                         if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3578                                                                 &g->vpt, true, f->vpt->tmpl_da)) {
3579                                                 return false;
3580                                         }
3581                                 } else {
3582                                         if (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
3583                                                                 &g->vpt, true, NULL)) {
3584                                                 return false;
3585                                         }
3586                                 }
3587                         }
3588
3589                         if (!modcall_pass2(g->children)) return false;
3590                         g->done_pass2 = true;
3591                         break;
3592
3593                 case MOD_FOREACH:
3594                         g = mod_callabletogroup(c);
3595                         if (g->done_pass2) return true;
3596
3597                         name2 = cf_section_name2(g->cs);
3598                         c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], name2);
3599
3600                         /*
3601                          *      Already parsed, handle the children.
3602                          */
3603                         if (g->vpt) goto check_children;
3604
3605                         /*
3606                          *      We had &Foo-Bar, where Foo-Bar is
3607                          *      defined by a module.
3608                          */
3609                         rad_assert(c->name != NULL);
3610                         rad_assert(c->name[0] == '&');
3611                         rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
3612
3613                         /*
3614                          *      The statement may refer to an
3615                          *      attribute which doesn't exist until
3616                          *      all of the modules have been loaded.
3617                          *      Check for that now.
3618                          */
3619                         slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
3620                                               REQUEST_CURRENT, PAIR_LIST_REQUEST);
3621                         if (slen < 0) goto parse_error;
3622
3623                 check_children:
3624                         rad_assert(g->vpt->type == TMPL_TYPE_ATTR);
3625                         if (g->vpt->tmpl_num != NUM_ALL) {
3626                                 cf_log_err_cs(g->cs, "MUST NOT use instance selectors in 'foreach'");
3627                                 return false;
3628                         }
3629                         if (!modcall_pass2(g->children)) return false;
3630                         g->done_pass2 = true;
3631                         break;
3632
3633                 case MOD_ELSE:
3634                         c->debug_name = group_name[c->type];
3635                         goto do_recurse;
3636
3637                 case MOD_POLICY:
3638                         g = mod_callabletogroup(c);
3639                         c->debug_name = talloc_asprintf(c, "%s %s", group_name[c->type], cf_section_name1(g->cs));
3640                         goto do_recurse;
3641 #endif
3642
3643                 case MOD_GROUP:
3644                 case MOD_LOAD_BALANCE:
3645                 case MOD_REDUNDANT_LOAD_BALANCE:
3646                         c->debug_name = group_name[c->type];
3647
3648 #ifdef WITH_UNLANG
3649                 do_recurse:
3650 #endif
3651                         g = mod_callabletogroup(c);
3652                         if (!g->cs) {
3653                                 c->debug_name = mc->name; /* for authorize, etc. */
3654
3655                         } else if (c->type == MOD_GROUP) { /* for Auth-Type, etc. */
3656                                 char const *name1 = cf_section_name1(g->cs);
3657
3658                                 if (strcmp(name1, group_name[c->type]) != 0) {
3659                                         c->debug_name = talloc_asprintf(c, "%s %s", name1, cf_section_name2(g->cs));
3660                                 }
3661                         }
3662
3663                         if (g->done_pass2) return true;
3664                         if (!modcall_pass2(g->children)) return false;
3665                         g->done_pass2 = true;
3666                         break;
3667                 }
3668         }
3669
3670         return true;
3671 }
3672
3673 void modcall_debug(modcallable *mc, int depth)
3674 {
3675         modcallable *this;
3676         modgroup *g;
3677         value_pair_map_t *map;
3678         char buffer[1024];
3679
3680         for (this = mc; this != NULL; this = this->next) {
3681                 switch (this->type) {
3682                 default:
3683                         break;
3684
3685                 case MOD_SINGLE: {
3686                         modsingle *single = mod_callabletosingle(this);
3687
3688                         DEBUG("%.*s%s", depth, modcall_spaces,
3689                                 single->modinst->name);
3690                         }
3691                         break;
3692
3693 #ifdef WITH_UNLANG
3694                 case MOD_UPDATE:
3695                         g = mod_callabletogroup(this);
3696                         DEBUG("%.*s%s {", depth, modcall_spaces,
3697                                 group_name[this->type]);
3698
3699                         for (map = g->map; map != NULL; map = map->next) {
3700                                 map_prints(buffer, sizeof(buffer), map);
3701                                 DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
3702                         }
3703
3704                         DEBUG("%.*s}", depth, modcall_spaces);
3705                         break;
3706
3707                 case MOD_ELSE:
3708                         g = mod_callabletogroup(this);
3709                         DEBUG("%.*s%s {", depth, modcall_spaces,
3710                                 group_name[this->type]);
3711                         modcall_debug(g->children, depth + 1);
3712                         DEBUG("%.*s}", depth, modcall_spaces);
3713                         break;
3714
3715                 case MOD_IF:
3716                 case MOD_ELSIF:
3717                         g = mod_callabletogroup(this);
3718                         fr_cond_sprint(buffer, sizeof(buffer), g->cond);
3719                         DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
3720                                 group_name[this->type], buffer);
3721                         modcall_debug(g->children, depth + 1);
3722                         DEBUG("%.*s}", depth, modcall_spaces);
3723                         break;
3724
3725                 case MOD_SWITCH:
3726                 case MOD_CASE:
3727                         g = mod_callabletogroup(this);
3728                         tmpl_prints(buffer, sizeof(buffer), g->vpt, NULL);
3729                         DEBUG("%.*s%s %s {", depth, modcall_spaces,
3730                                 group_name[this->type], buffer);
3731                         modcall_debug(g->children, depth + 1);
3732                         DEBUG("%.*s}", depth, modcall_spaces);
3733                         break;
3734
3735                 case MOD_POLICY:
3736                 case MOD_FOREACH:
3737                         g = mod_callabletogroup(this);
3738                         DEBUG("%.*s%s %s {", depth, modcall_spaces,
3739                                 group_name[this->type], this->name);
3740                         modcall_debug(g->children, depth + 1);
3741                         DEBUG("%.*s}", depth, modcall_spaces);
3742                         break;
3743
3744                 case MOD_BREAK:
3745                         DEBUG("%.*sbreak", depth, modcall_spaces);
3746                         break;
3747
3748 #endif
3749                 case MOD_GROUP:
3750                         g = mod_callabletogroup(this);
3751                         DEBUG("%.*s%s {", depth, modcall_spaces,
3752                               group_name[this->type]);
3753                         modcall_debug(g->children, depth + 1);
3754                         DEBUG("%.*s}", depth, modcall_spaces);
3755                         break;
3756
3757
3758                 case MOD_LOAD_BALANCE:
3759                 case MOD_REDUNDANT_LOAD_BALANCE:
3760                         g = mod_callabletogroup(this);
3761                         DEBUG("%.*s%s {", depth, modcall_spaces,
3762                                 group_name[this->type]);
3763                         modcall_debug(g->children, depth + 1);
3764                         DEBUG("%.*s}", depth, modcall_spaces);
3765                         break;
3766                 }
3767         }
3768 }