The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
module.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 135a9a866178f15ac9b076100a7552d6a89f0f21 $
19 *
20 * @file unlang/module.c
21 * @brief Defines functions for calling modules asynchronously
22 *
23 * @copyright 2018 The FreeRADIUS server project
24 * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26
27RCSID("$Id: 135a9a866178f15ac9b076100a7552d6a89f0f21 $")
28
29#include <freeradius-devel/server/modpriv.h>
30#include <freeradius-devel/server/request_data.h>
31
32#include "module_priv.h"
33
34#include "tmpl.h"
35
38
39/** Push a module or submodule onto the stack for evaluation
40 *
41 * @param[out] p_result Where to write the result of calling the module.
42 * @param[in] request The current request.
43 * @param[in] mi Instance of the module to call.
44 * @param[in] method to call.
45 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
46 * Set to UNLANG_SUB_FRAME if the interprer should continue.
47 * @return
48 * - 0 on success.
49 * - -1 on failure.
50 */
52 module_instance_t *mi, module_method_t method, bool top_frame)
53{
54 unlang_stack_t *stack = request->stack;
58
59 /*
60 * We need to have a unlang_module_t to push on the
61 * stack. The only sane way to do it is to attach it to
62 * the frame state.
63 */
64 MEM(mc = talloc(stack, unlang_module_t)); /* Still gets allocated from the stack pool */
65 *mc = (unlang_module_t){
66 .self = {
68 .name = mi->name,
69 .debug_name = mi->name,
70 .actions = {
71 .actions = {
73 [RLM_MODULE_FAIL] = MOD_ACTION_RETURN, /* Exit out of nested levels */
74 [RLM_MODULE_OK] = 0,
79 [RLM_MODULE_NOOP] = 0,
81 },
82 .retry = RETRY_INIT,
83 },
84 },
85 .mmc = {
86 .mi = mi,
87 .mmb = {
88 .method = method
89 }
90 }
91 };
92
93 /*
94 * Push a new module frame onto the stack
95 */
97 RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, top_frame) < 0) {
98 return -1;
99 }
100
101 frame = &stack->frame[stack->depth];
102 state = frame->state;
104 .p_result = p_result,
105 .thread = module_thread(mi)
106 };
107
108 /*
109 * Bind the temporary unlang_module_t to the frame state.
110 *
111 * There aren't _that_ many children in the stack context.
112 * so we should be ok.
113 *
114 * Hopefully in future versions of talloc the O(n) problem
115 * will be fixed for stealing.
116 */
117 talloc_steal(state, mc);
118
119 return 0;
120}
121
122/** Change the resume function of a module.
123 *
124 * @param[in] request The current request.
125 * @param[in] resume function to call when the XLAT expansion is complete.
126 * @return
127 * - <0 on error
128 * - 0 on success
129 */
131{
132 unlang_stack_t *stack = request->stack;
133 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
135
136 /*
137 * Can't resume if it isn't yielded.
138 */
139 if (!is_yielded(frame)) return -1;
140
141 /*
142 * It must be yielded in a module.
143 */
144 if (frame->instruction->type != UNLANG_TYPE_MODULE) return -1;
145
146 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
147 state->resume = resume;
148
149 return 0;
150}
151
152/** Push a pre-compiled xlat and resumption state onto the stack for evaluation
153 *
154 * In order to use the async unlang processor the calling module needs to establish
155 * a resumption point, as the call to an xlat function may require yielding control
156 * back to the interpreter.
157 *
158 * To simplify the calling conventions, this function is provided to first push a
159 * resumption stack frame for the module, and then push an xlat stack frame.
160 *
161 * After pushing those frames the function updates the stack pointer to jump over
162 * the resumption frame and execute the xlat interpreter.
163 *
164 * When the xlat interpreter finishes, and pops the xlat frame, the unlang interpreter
165 * will then call the module resumption frame, allowing the module to continue execution.
166 *
167 * @param[in] ctx To allocate talloc value boxes and values in.
168 * @param[out] p_success Whether xlat evaluation was successful.
169 * @param[out] out Where to write the result of the expansion.
170 * @param[in] request The current request.
171 * @param[in] exp XLAT expansion to evaluate.
172 * @param[in] resume function to call when the XLAT expansion is complete.
173 * @param[in] signal function to call if a signal is received.
174 * @param[in] sigmask Signals to block.
175 * @param[in] rctx to pass to the resume() and signal() callbacks.
176 * @return
177 * - UNLANG_ACTION_PUSHED_CHILD
178 */
179unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
180 request_t *request, xlat_exp_head_t const *exp,
181 module_method_t resume,
182 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
183{
184 /*
185 * Push the resumption point BEFORE pushing the xlat onto
186 * the parents stack.
187 */
188 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
189
190 /*
191 * Push the xlat function
192 */
193 if (unlang_xlat_push(ctx, p_success, out, request, exp, false) < 0) return UNLANG_ACTION_STOP_PROCESSING;
194
196}
197
198/** Push a pre-compiled tmpl and resumption state onto the stack for evaluation
199 *
200 * In order to use the async unlang processor the calling module needs to establish
201 * a resumption point, as the call to an xlat function may require yielding control
202 * back to the interpreter.
203 *
204 * To simplify the calling conventions, this function is provided to first push a
205 * resumption stack frame for the module, and then push a tmpl stack frame.
206 *
207 * After pushing those frames the function updates the stack pointer to jump over
208 * the resumption frame and execute the tmpl expansion.
209 *
210 * When the tmpl interpreter finishes, and pops the tmpl frame, the unlang interpreter
211 * will then call the module resumption frame, allowing the module to continue execution.
212 *
213 * @param[in] ctx To allocate talloc value boxes and values in.
214 * @param[out] out Where to write the result of the expansion.
215 * @param[in] request The current request.
216 * @param[in] vpt the tmpl to expand
217 * @param[in] args Arguments which control how to evaluate the various
218 * types of xlats.
219 * @param[in] resume function to call when the XLAT expansion is complete.
220 * @param[in] signal function to call if a signal is received.
221 * @param[in] sigmask Signals to block.
222 * @param[in] rctx to pass to the resume() and signal() callbacks.
223 * @return
224 * - UNLANG_ACTION_PUSHED_CHILD
225 */
226unlang_action_t unlang_module_yield_to_tmpl(TALLOC_CTX *ctx, fr_value_box_list_t *out,
227 request_t *request, tmpl_t const *vpt,
229 module_method_t resume,
230 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
231{
232 /*
233 * Push the resumption point BEFORE pushing the xlat onto
234 * the parents stack.
235 */
236 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
237
238 /*
239 * Push the xlat function
240 */
241 if (unlang_tmpl_push(ctx, out, request, vpt, args) < 0) return UNLANG_ACTION_FAIL;
242
244}
245
247 request_t *request, CONF_SECTION *subcs,
248 rlm_rcode_t default_rcode,
249 module_method_t resume,
250 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
251{
252 if (!subcs) {
253 unlang_stack_t *stack = request->stack;
254 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
257
260
261 /*
262 * Be transparent to the resume function.
263 * frame->result will be overwritten
264 * anyway when we return.
265 */
266 stack->result = frame->result = default_rcode;
267 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
268
269 return resume(p_result,
271 state->env_data, rctx),
272 request);
273 }
274
275 /*
276 * Push the resumption point BEFORE adding the subsection
277 * to the parents stack.
278 */
279 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
280
281 if (unlang_interpret_push_section(request, subcs,
282 default_rcode, UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_STOP_PROCESSING;
283
285}
286
287/** Run the retry handler. Called from an async signal handler.
288 *
289 */
291{
292 unlang_stack_t *stack = request->stack;
293 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
294 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
295
296 if (!state->retry_cb) return;
297
298 /*
299 * Assert that we have the right things. Note that this function should only be called when the
300 * retry is being used as an expiry time, i.e. mrc==1. If the module has its own retry handlers,
301 * then this function must not be called.
302 */
303 fr_assert(state->retry.config != NULL);
304 fr_assert(state->retry.config->mrc == 1);
305 fr_assert(state->rctx == mctx->rctx);
306 fr_assert(state->request == request);
307
308 /*
309 * Update the time as to when the retry is being called. This is the main purpose of the
310 * function.
311 */
312 state->retry.updated = fr_time();
313
314 state->retry_cb(mctx, request, &state->retry);
315
316}
317
318/** Cancel the retry timer on resume
319 *
320 */
322{
323 unlang_stack_t *stack = request->stack;
324 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
325 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
326
327 /*
328 * Cancel the timers, and clean up any associated retry configuration.
329 */
330 talloc_const_free(state->ev);
331 state->ev = NULL;
332 state->retry_cb = NULL;
333 state->retry.config = NULL;
334
335 return state->retry_resume(p_result, mctx, request);
336}
337
338/** Yield a request back to the interpreter, with retries
339 *
340 * This passes control of the request back to the unlang interpreter, setting
341 * callbacks to execute when the request is 'signalled' asynchronously, or when
342 * the retry timer hits.
343 *
344 * @note The module function which calls #unlang_module_yield_to_retry should return control
345 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield_to_retry.
346 * A common pattern is to use ``return unlang_module_yield_to_retry(...)``.
347 *
348 * @param[in] request The current request.
349 * @param[in] resume Called on unlang_interpret_mark_runnable().
350 * @param[in] retry Called on when a retry timer hits
351 * @param[in] signal Called on unlang_action().
352 * @param[in] sigmask Set of signals to block.
353 * @param[in] rctx to pass to the callbacks.
354 * @param[in] retry_cfg to set up the retries
355 * @return
356 * - UNLANG_ACTION_YIELD on success
357 * - UNLANG_ACTION_FAIL on failure
358 */
360 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx,
361 fr_retry_config_t const *retry_cfg)
362{
363 unlang_stack_t *stack = request->stack;
364 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
366 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
367
368 fr_assert(stack->depth > 0);
371
372 fr_assert(!state->retry_cb);
373
374 state->retry_cb = retry;
375 state->retry_resume = resume; // so that we can cancel the retry timer
376 state->rctx = rctx;
377
378 state->request = request;
379 state->mi = m->mmc.mi;
380
381 /*
382 * Allow unlang statements to override the module configuration. i.e. if we already have a
383 * timer from unlang, then just use that.
384 */
385 if (!state->retry.config) {
386 fr_retry_init(&state->retry, fr_time(), retry_cfg);
387
388 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev,
389 state->retry.next,
390 false, unlang_module_event_retry_handler, request) < 0) {
391 RPEDEBUG("Failed inserting event");
392 return UNLANG_ACTION_FAIL;
393 }
394 }
395
396 return unlang_module_yield(request, unlang_module_retry_resume, signal, sigmask, rctx);
397}
398
399
400/** Yield a request back to the interpreter from within a module
401 *
402 * This passes control of the request back to the unlang interpreter, setting
403 * callbacks to execute when the request is 'signalled' asynchronously, or whatever
404 * timer or I/O event the module was waiting for occurs.
405 *
406 * @note The module function which calls #unlang_module_yield should return control
407 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield.
408 * A common pattern is to use ``return unlang_module_yield(...)``.
409 *
410 * @param[in] request The current request.
411 * @param[in] resume Called on unlang_interpret_mark_runnable().
412 * @param[in] signal Called on unlang_action().
413 * @param[in] sigmask Set of signals to block.
414 * @param[in] rctx to pass to the callbacks.
415 * @return
416 * - UNLANG_ACTION_YIELD.
417 */
419 module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
420{
421 unlang_stack_t *stack = request->stack;
422 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
423 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
424
425 REQUEST_VERIFY(request); /* Check the yielded request is sane */
426
427 state->rctx = rctx;
428 state->resume = resume;
429
430#ifndef NDEBUG
431 /*
432 * We can't do asynchronous signals if the module is not thread safe.
433 *
434 * Right now, none of the modules marked THREAD_UNSAFE call yield, or set signal callbacks.
435 * Which means that this code doesn't affect anything.
436 *
437 * At some point if we do have modules which take signals and which are not thread safe, then
438 * those modules have to ensure that their signal handlers do any locking necessary.
439 */
440 if (signal) {
442
444 fr_assert(m);
445
447 }
448#endif
449
450 state->signal = signal;
451 state->sigmask = sigmask;
452
453 /*
454 * We set the repeatable flag here,
455 * so that the resume function is always
456 * called going back up the stack.
457 */
459
460 return UNLANG_ACTION_YIELD;
461}
462
463/*
464 * Lock the mutex for the module
465 */
466static inline CC_HINT(always_inline) void safe_lock(module_instance_t *mi)
467{
468 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex);
469}
470
471/*
472 * Unlock the mutex for the module
473 */
474static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *mi)
475{
476 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex);
477}
478
479/** Send a signal (usually stop) to a request
480 *
481 * This is typically called via an "async" action, i.e. an action
482 * outside of the normal processing of the request.
483 *
484 * If there is no #unlang_module_signal_t callback defined, the action is ignored.
485 *
486 * @param[in] request The current request.
487 * @param[in] frame current stack frame.
488 * @param[in] action to signal.
489 */
491{
492 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
494 char const *caller;
495
496 if (!state->signal) return;
497
498 /*
499 * Async calls can't push anything onto the unlang stack, so we just use a local "caller" here.
500 */
501 caller = request->module;
502 request->module = m->mmc.mi->name;
503
504 /*
505 * Call the signal routines. Note that signals are
506 * explicitely asynchronous, even if the module has
507 * declared itself to be MODULE_TYPE_THREAD_UNSAFE.
508 */
509 if (!(action & state->sigmask)) state->signal(MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, state->rctx), request, action);
510
511 if (action == FR_SIGNAL_CANCEL) {
512 /*
513 * One fewer caller for this module. Since this module
514 * has been cancelled, decrement the active callers and
515 * ignore any future signals.
516 */
517 state->thread->active_callers--;
518 state->signal = NULL;
519 }
520
521 request->module = caller;
522
523}
524
525/** Cleanup after a module completes
526 *
527 */
529{
530 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
531 rlm_rcode_t rcode = state->rcode_set ? state->rcode : *p_result;
532
533#ifndef NDEBUG
534 fr_assert(state->unlang_indent == request->log.indent.unlang);
535#endif
536
539
540 RDEBUG("%s (%s)", frame->instruction->name ? frame->instruction->name : "",
541 fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
542
543 if (state->p_result) *state->p_result = rcode; /* Inform our caller if we have one */
544 *p_result = rcode;
545 request->module = state->previous_module;
546
548}
549
550/** Cleanup after a yielded module completes
551 *
552 */
554{
555 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
556
557 state->thread->active_callers--;
558
559 return unlang_module_done(p_result, request, frame);
560}
561
562/** Wrapper to call a module's resumption function
563 *
564 * This is called _after_ the module first yields, and again after any
565 * other yields.
566 */
568{
569 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
571 module_method_t resume;
573
574 /*
575 * Update the rcode from any child calls that
576 * may have been performed. The module still
577 * has a chance to override this rcode if it
578 * wants, but process modules in particular
579 * expect to see the result of child
580 * evaluations available to them in p_result.
581 */
582 state->rcode = *p_result < RLM_MODULE_NUMCODES ? *p_result : RLM_MODULE_NOOP;
583
584 fr_assert(state->resume != NULL);
585
586 resume = state->resume;
587
588 /*
589 * The module *MUST* explicitly set the resume
590 * function when yielding or pushing children
591 * if it wants to be called again later.
592 */
593 state->resume = NULL;
594
595 /*
596 * Lock is noop unless instance->mutex is set.
597 */
598 safe_lock(m->mmc.mi);
599 ua = resume(&state->rcode, MODULE_CTX(m->mmc.mi, state->thread->data,
600 state->env_data, state->rctx), request);
601 safe_unlock(m->mmc.mi);
602
603 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
604
605 switch (ua) {
607 RWARN("Module %s or worker signalled to stop processing request", m->mmc.mi->name);
608 if (state->p_result) *state->p_result = state->rcode;
609 state->thread->active_callers--;
610 *p_result = state->rcode;
611 request->module = state->previous_module;
613
615 /*
616 * The module yielded but didn't set a
617 * resume function, this means it's done
618 * and when the I/O operation completes
619 * it shouldn't be called again.
620 */
621 if (!state->resume) {
623 } else {
624 repeatable_set(frame);
625 }
626 return UNLANG_ACTION_YIELD;
627
628 /*
629 * The module is done (for now).
630 * But, running it pushed one or more asynchronous
631 * calls onto the stack for evaluation.
632 * These need to be run before the module resumes
633 * or the next unlang instruction is processed.
634 */
636 /*
637 * The module pushed a child and didn't
638 * set a resume function, this means
639 * it's done, and we won't call it again
640 * but we still need to do some cleanup
641 * after the child returns.
642 */
643 if (!state->resume) {
645 state->rcode_set = false; /* Preserve the child rcode */
646 } else {
647 repeatable_set(frame);
648 }
650
652 /*
653 * Module set a resume function but
654 * didn't yield or push additional
655 * children.
656 *
657 * Evaluate the function now and
658 * use the result as the final result.
659 */
660 if (state->resume) return unlang_module_resume(p_result, request, frame);
661 request->module = state->previous_module;
662 break;
663
665 request->module = state->previous_module;
666 break;
667
669 *p_result = RLM_MODULE_FAIL;
670 request->module = state->previous_module;
671 break;
672
673 case UNLANG_ACTION_EXECUTE_NEXT: /* Not valid */
674 fr_assert(0);
675 *p_result = RLM_MODULE_FAIL;
676 break;
677 }
678
679 unlang_module_resume_done(p_result, request, frame);
680 request->module = state->previous_module;
681
682 return ua;
683}
684
685/** Call the callback registered for a retry event
686 *
687 * @param[in] tl the event timer was inserted into.
688 * @param[in] now The current time, as held by the event_list.
689 * @param[in] ctx the stack frame
690 *
691 */
693{
694 request_t *request = talloc_get_type_abort(ctx, request_t);
695 unlang_stack_t *stack = request->stack;
696 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
697 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
698
699 switch (fr_retry_next(&state->retry, now)) {
701 if (state->retry_cb) {
702 /*
703 * Call the module retry handler, with the state of the retry. On MRD / MRC, the
704 * module is made runnable again, and the "resume" function is called.
705 */
706 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
707 } else {
708 /*
709 * For signals, the module will get either a RETRY
710 * signal, or a TIMEOUT signal (also for max count).
711 *
712 * The signal handler should generally change the resume
713 * function, and mark the request as runnable. We
714 * probably don't want the module to do tons of work in
715 * the signal handler, as it's called from the event
716 * loop. And doing so could affect the other event
717 * timers.
718 *
719 * Note also that we call frame->signal(), and not
720 * unlang_interpret_signal(). That is because we want to
721 * signal only the module. We know that the other frames
722 * on the stack can't handle this particular signal. So
723 * there's no point in calling them. Or, if sections
724 * have their own retry handlers, then we don't want to
725 * signal those _other_ retry handlers with _our_ signal.
726 */
727 frame->signal(request, frame, FR_SIGNAL_RETRY);
728 }
729
730 /*
731 * Reset the timer.
732 */
733 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev, state->retry.next,
734 false, unlang_module_event_retry_handler, request) < 0) {
735 RPEDEBUG("Failed inserting event");
736 unlang_interpret_mark_runnable(request); /* and let the caller figure out what's up */
737 }
738 return;
739
740 case FR_RETRY_MRD:
741 RDEBUG("Reached max_rtx_duration (%pVs > %pVs) - sending timeout",
743 break;
744
745 case FR_RETRY_MRC:
746 RDEBUG("Reached max_rtx_count %u- sending timeout",
747 state->retry.config->mrc);
748 break;
749 }
750
751 /*
752 * Run the retry handler on MRD / MRC, too.
753 */
754 if (state->retry_cb) {
755 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
756 } else {
757 frame->signal(request, frame, FR_SIGNAL_TIMEOUT);
758 }
759
760 /*
761 * On final timeout, always mark the request as runnable.
762 */
764}
765
767{
769 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
771 fr_time_t now = fr_time_wrap(0);
772
773 *p_result = state->rcode = RLM_MODULE_NOOP;
774 state->rcode_set = true;
775 state->previous_module = request->module;
776
777#ifndef NDEBUG
778 state->unlang_indent = request->log.indent.unlang;
779#endif
780 /*
781 * Process a stand-alone child, and fall through
782 * to dealing with it's parent.
783 */
785 fr_assert(m);
786
787 RDEBUG4("[%i] %s - %s (%s)", stack_depth_current(request), __FUNCTION__,
788 m->mmc.mi->module->exported->name, m->mmc.mi->name);
789
790 state->p_result = NULL;
791
792 /*
793 * Return administratively configured return code
794 */
795 if (m->mmc.mi->force) {
796 state->rcode = m->mmc.mi->code;
798 goto done;
799 }
800
801 if (m->mmc.mmb.method_env) {
802 if (!state->env_data) {
803 ua = call_env_expand(state, request, &state->env_result, &state->env_data, m->call_env);
804 switch (ua) {
806 goto fail;
807
811
812 default:
813 break;
814 }
815 }
816
817 /*
818 * Fail the module call on callenv failure
819 */
821 }
822
823 /*
824 * Grab the thread/module specific data if any exists.
825 */
826 state->thread = module_thread(m->mmc.mi);
827 fr_assert(state->thread != NULL);
828
829 /*
830 * Don't allow returning _through_ modules
831 */
833
834 /*
835 * For logging unresponsive children.
836 */
837 state->thread->total_calls++;
838
839 /*
840 * If we're doing retries, remember when we started
841 * running the module.
842 */
844
845 request->module = m->mmc.mi->name;
846 safe_lock(m->mmc.mi); /* Noop unless instance->mutex set */
847 ua = m->mmc.mmb.method(&state->rcode,
848 MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, NULL),
849 request);
850 safe_unlock(m->mmc.mi);
851
852 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
853
854 switch (ua) {
855 /*
856 * It is now marked as "stop" when it wasn't before, we
857 * must have been blocked.
858 */
860 RWARN("Module %s became unblocked", m->mmc.mi->name);
861 if (state->p_result) *state->p_result = state->rcode;
862 *p_result = state->rcode;
863 request->module = state->previous_module;
865
867 state->thread->active_callers++;
868
869 /*
870 * The module yielded but didn't set a
871 * resume function, this means it's done
872 * and when the I/O operation completes
873 * it shouldn't be called again.
874 */
875 if (!state->resume) {
877 } else {
879 }
880
881 /*
882 * If we have retry timers, then start the retries.
883 */
886
887 fr_retry_init(&state->retry, now, &frame->instruction->actions.retry);
888
889 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl,
890 &state->ev, state->retry.next,
891 false, unlang_module_event_retry_handler, request) < 0) {
892 RPEDEBUG("Failed inserting event");
893 goto fail;
894 }
895 }
896
897 return UNLANG_ACTION_YIELD;
898
899 /*
900 * The module is done (for now).
901 * But, running it pushed one or more asynchronous
902 * calls onto the stack for evaluation.
903 * These need to be run before the module resumes
904 * or the next unlang instruction is processed.
905 */
907 /*
908 * The module pushed a child and didn't
909 * set a resume function, this means
910 * it's done, and we won't call it again
911 * but we still need to do some cleanup
912 * after the child returns.
913 */
914 if (!state->resume) {
916 state->rcode_set = false; /* Preserve the child rcode */
917 } else {
918 repeatable_set(frame);
919 }
921
923 /*
924 * Module set a resume function but
925 * didn't yield or push additional
926 * children.
927 *
928 * Evaluate the function now and
929 * use the result as the final result.
930 */
931 if (state->resume) {
932 frame->process = unlang_module_resume; /* unlang_module_resume will assume this is set */
933 return unlang_module_resume(p_result, request, frame);
934 }
935 break;
936
938 break;
939
941 fail:
942 *p_result = RLM_MODULE_FAIL;
943 break;
944
946 fr_assert(0);
947 *p_result = RLM_MODULE_FAIL;
948 break;
949 }
950
951done:
952 request->module = state->previous_module;
953 unlang_module_done(p_result, request, frame);
954 return ua;
955}
956
958{
960 &(unlang_op_t){
961 .name = "module",
962 .interpret = unlang_module,
963 .rcode_set = true,
964 .signal = unlang_module_signal,
965 .frame_state_size = sizeof(unlang_frame_state_module_t),
966 .frame_state_type = "unlang_frame_state_module_t",
967 });
968}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_UNWIND
Break out of the current group.
Definition action.h:41
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
@ UNLANG_ACTION_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:43
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:42
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data, call_env_t const *call_env)
Initialise the expansion of a call environment.
Definition call_env.c:294
@ CALL_ENV_SUCCESS
Definition call_env.h:52
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:78
#define MEM(x)
Definition debug.h:36
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1418
int unlang_interpret_push(request_t *request, unlang_t const *instruction, rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
Push a new frame onto the stack.
Definition interpret.c:159
int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:1009
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1822
#define UNLANG_SUB_FRAME
Definition interpret.h:36
#define RWARN(fmt,...)
Definition log.h:297
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RDEBUG4(fmt,...)
Definition log.h:344
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:63
static char * stack[MAX_STACK]
Definition radmin.c:158
@ MOD_ACTION_RETURN
Definition mod_action.h:40
fr_retry_config_t retry
Definition mod_action.h:63
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
#define MODULE_CTX(_mi, _thread, _env_data, _rctx)
Wrapper to create a module_ctx_t as a compound literal.
Definition module_ctx.h:128
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Declarations for the unlang module interface.
fr_timer_t * ev
retry timer just for this module.
Definition module_priv.h:87
rlm_rcode_t rcode
the result, only for unlang_module_resume_final.
Definition module_priv.h:63
static unlang_t * unlang_module_to_generic(unlang_module_t *p)
static unlang_module_t * unlang_generic_to_module(unlang_t const *p)
Definition module_priv.h:94
module_instance_t const * mi
Module instance to pass to callbacks.
Definition module_priv.h:84
module_method_t resume
resumption handler
Definition module_priv.h:72
char const * previous_module
old request->module
Definition module_priv.h:46
fr_signal_t sigmask
Signals to block.
Definition module_priv.h:74
module_method_t retry_resume
which stops retries on resume
Definition module_priv.h:81
bool rcode_set
Overwrite the current rcode for the section with the module rcode.
Definition module_priv.h:64
call_env_result_t env_result
Result of the previous call environment expansion.
Definition module_priv.h:52
module_method_call_t mmc
Everything needed to call a module method.
Definition module_priv.h:38
fr_retry_t retry
retry timers, etc.
Definition module_priv.h:88
void * env_data
Expanded per call "call environment" tmpls.
Definition module_priv.h:53
rlm_rcode_t * p_result
Where to store the result.
Definition module_priv.h:62
module_thread_instance_t * thread
thread-local data for this module.
Definition module_priv.h:47
unlang_t self
Common fields in all unlang_t tree nodes.
Definition module_priv.h:36
unlang_module_signal_t signal
for signal handlers
Definition module_priv.h:73
int unlang_indent
Record what this was when we entered the module.
Definition module_priv.h:56
void * rctx
for resume / signal
Definition module_priv.h:71
call_env_t const * call_env
The per call parsed call environment.
Definition module_priv.h:37
unlang_module_retry_t retry_cb
callback to run on timeout
Definition module_priv.h:82
A module stack entry.
Definition module_priv.h:45
A call to a module method.
Definition module_priv.h:35
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
Definition module_rlm.h:63
module_method_binding_t mmb
Method we're calling.
Definition module_rlm.h:70
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:51
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:50
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
#define REQUEST_VERIFY(_x)
Definition request.h:305
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:88
char const * name
Instance name e.g. user_database.
Definition module.h:336
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition module.h:48
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:228
uint64_t active_callers
total number of times we've been called
Definition module.h:360
bool force
Force the module to return a specific code.
Definition module.h:298
module_method_t method
Module method to call.
Definition module.h:176
void * data
Thread specific instance data.
Definition module.h:353
rlm_rcode_t code
Code module will return when 'force' has has been set to true.
Definition module.h:301
call_env_method_t const * method_env
Method specific call_env.
Definition module.h:177
static module_thread_instance_t * module_thread(module_instance_t const *mi)
Retrieve module/thread specific instance for a module.
Definition module.h:482
unlang_action_t(* module_method_t)(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
Definition module.h:68
module_t * exported
Public module structure.
Definition module.h:277
pthread_mutex_t mutex
Used prevent multiple threads entering a thread unsafe module simultaneously.
Definition module.h:284
Module instance data.
Definition module.h:266
static fr_slen_t vpt
Definition tmpl.h:1269
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_RETRY
a retry timer has hit
Definition signal.h:46
@ FR_SIGNAL_TIMEOUT
a retry timeout or max count has hit
Definition signal.h:47
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
unlang_action_t unlang_module_yield_to_section(rlm_rcode_t *p_result, request_t *request, CONF_SECTION *subcs, rlm_rcode_t default_rcode, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Definition module.c:246
int unlang_module_set_resume(request_t *request, module_method_t resume)
Change the resume function of a module.
Definition module.c:130
static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition module.c:766
unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *exp, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Push a pre-compiled xlat and resumption state onto the stack for evaluation.
Definition module.c:179
static void safe_lock(module_instance_t *mi)
Definition module.c:466
static void unlang_module_event_retry_handler(UNUSED fr_timer_list_t *tl, fr_time_t now, void *ctx)
Call the callback registered for a retry event.
Definition module.c:692
int unlang_module_push(rlm_rcode_t *p_result, request_t *request, module_instance_t *mi, module_method_t method, bool top_frame)
Push a module or submodule onto the stack for evaluation.
Definition module.c:51
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:418
unlang_action_t unlang_module_yield_to_retry(request_t *request, module_method_t resume, unlang_module_retry_t retry, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx, fr_retry_config_t const *retry_cfg)
Yield a request back to the interpreter, with retries.
Definition module.c:359
void unlang_module_init(void)
Definition module.c:957
static unlang_action_t unlang_module_resume(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Wrapper to call a module's resumption function.
Definition module.c:567
static unlang_action_t unlang_module_resume_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Cleanup after a yielded module completes.
Definition module.c:553
static unlang_action_t unlang_module_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Cleanup after a module completes.
Definition module.c:528
void unlang_module_retry_now(module_ctx_t const *mctx, request_t *request)
Run the retry handler.
Definition module.c:290
unlang_action_t unlang_module_yield_to_tmpl(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt, unlang_tmpl_args_t *args, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Push a pre-compiled tmpl and resumption state onto the stack for evaluation.
Definition module.c:226
static void safe_unlock(module_instance_t *mi)
Definition module.c:474
static void unlang_module_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition module.c:490
static unlang_action_t unlang_module_retry_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Cancel the retry timer on resume.
Definition module.c:321
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
#define fr_timer_at(...)
Definition timer.h:80
int unlang_tmpl_push(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args)
Push a tmpl onto the stack for evaluation.
Definition tmpl.c:261
void(* unlang_module_retry_t)(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
A callback when a retry happens.
Definition module.h:52
void(* unlang_module_signal_t)(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
Definition module.h:80
Functions to allow tmpls to push resumption frames onto the stack and inform the interpreter about th...
Arguments for evaluating different types of tmpls.
Definition tmpl.h:47
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:282
unlang_signal_t signal
function to call when signalling this stack frame
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:92
static unlang_stack_frame_t * frame_current(request_t *request)
static void return_point_set(unlang_stack_frame_t *frame)
char const * name
Unknown...
static int stack_depth_current(request_t *request)
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:46
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
static bool is_yielded(unlang_stack_frame_t const *frame)
rlm_rcode_t result
The result from executing the instruction.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
An unlang operation.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
Definition retry.c:108
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
Definition retry.c:36
fr_time_t start
when we started the retransmission
Definition retry.h:53
fr_time_delta_t irt
Initial transmission time.
Definition retry.h:33
#define RETRY_INIT
Definition retry.h:39
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
fr_retry_config_t const * config
master configuration
Definition retry.h:52
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
fr_time_t updated
last update, really a cached "now".
Definition retry.h:56
fr_time_t next
when the next timer should be set
Definition retry.h:55
#define fr_box_time_delta(_val)
Definition value.h:354
static size_t char ** out
Definition value.h:1012