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