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