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