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: eaf5e4e3bb77bf3efec67b321a95af107af28d7e $
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: eaf5e4e3bb77bf3efec67b321a95af107af28d7e $")
28
29#include <freeradius-devel/server/modpriv.h>
30#include <freeradius-devel/server/request_data.h>
31#include <freeradius-devel/server/rcode.h>
32#include <freeradius-devel/unlang/call_env.h>
33
34#include "module_priv.h"
35
36#include "tmpl.h"
37
40
41/** Push a module or submodule onto the stack for evaluation
42 *
43 * @param[out] p_result Where to write the result of calling the module.
44 * @param[in] request The current request.
45 * @param[in] mi Instance of the module to call.
46 * @param[in] method to call.
47 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
48 * Set to UNLANG_SUB_FRAME if the interprer should continue.
49 * @return
50 * - 0 on success.
51 * - -1 on failure.
52 */
54 module_instance_t *mi, module_method_t method, bool top_frame)
55{
56 unlang_stack_t *stack = request->stack;
60
61 /*
62 * We need to have a unlang_module_t to push on the
63 * stack. The only sane way to do it is to attach it to
64 * the frame state.
65 */
66 MEM(mc = talloc(stack, unlang_module_t)); /* Still gets allocated from the stack pool */
67 *mc = (unlang_module_t){
68 .self = {
70 .name = mi->name,
71 .debug_name = mi->name,
72 .actions = {
73 .actions = {
75 [RLM_MODULE_FAIL] = MOD_ACTION_RETURN, /* Exit out of nested levels */
76 [RLM_MODULE_OK] = 0,
81 [RLM_MODULE_NOOP] = 0,
83 },
84 .retry = RETRY_INIT,
85 },
86 },
87 .mmc = {
88 .mi = mi,
89 .mmb = {
90 .method = method
91 }
92 }
93 };
94
95 /*
96 * Push a new module frame onto the stack
97 */
99 RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, top_frame) < 0) {
100 return -1;
101 }
102
103 frame = &stack->frame[stack->depth];
104 state = frame->state;
106 .p_result = p_result,
107 .thread = module_thread(mi)
108 };
109
110 /*
111 * Bind the temporary unlang_module_t to the frame state.
112 *
113 * There aren't _that_ many children in the stack context.
114 * so we should be ok.
115 *
116 * Hopefully in future versions of talloc the O(n) problem
117 * will be fixed for stealing.
118 */
119 talloc_steal(state, mc);
120
121 return 0;
122}
123
124/** Change the resume function of a module.
125 *
126 * @param[in] request The current request.
127 * @param[in] resume function to call when the XLAT expansion is complete.
128 * @return
129 * - <0 on error
130 * - 0 on success
131 */
133{
134 unlang_stack_t *stack = request->stack;
135 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
137
138 /*
139 * Can't resume if it isn't yielded.
140 */
141 if (!is_yielded(frame)) return -1;
142
143 /*
144 * It must be yielded in a module.
145 */
146 if (frame->instruction->type != UNLANG_TYPE_MODULE) return -1;
147
148 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
149 state->resume = resume;
150
151 return 0;
152}
153
154/** Push a pre-compiled xlat and resumption state onto the stack for evaluation
155 *
156 * In order to use the async unlang processor the calling module needs to establish
157 * a resumption point, as the call to an xlat function may require yielding control
158 * back to the interpreter.
159 *
160 * To simplify the calling conventions, this function is provided to first push a
161 * resumption stack frame for the module, and then push an xlat stack frame.
162 *
163 * After pushing those frames the function updates the stack pointer to jump over
164 * the resumption frame and execute the xlat interpreter.
165 *
166 * When the xlat interpreter finishes, and pops the xlat frame, the unlang interpreter
167 * will then call the module resumption frame, allowing the module to continue execution.
168 *
169 * @param[in] ctx To allocate talloc value boxes and values in.
170 * @param[out] p_success Whether xlat evaluation was successful.
171 * @param[out] out Where to write the result of the expansion.
172 * @param[in] request The current request.
173 * @param[in] exp XLAT expansion to evaluate.
174 * @param[in] resume function to call when the XLAT expansion is complete.
175 * @param[in] signal function to call if a signal is received.
176 * @param[in] sigmask Signals to block.
177 * @param[in] rctx to pass to the resume() and signal() callbacks.
178 * @return
179 * - UNLANG_ACTION_PUSHED_CHILD
180 */
181unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out,
182 request_t *request, xlat_exp_head_t const *exp,
183 module_method_t resume,
184 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
185{
186 /*
187 * Push the resumption point BEFORE pushing the xlat onto
188 * the parents stack.
189 */
190 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
191
192 /*
193 * Push the xlat function
194 */
195 if (unlang_xlat_push(ctx, p_success, out, request, exp, false) < 0) return UNLANG_ACTION_STOP_PROCESSING;
196
198}
199
200/** Push a pre-compiled tmpl and resumption state onto the stack for evaluation
201 *
202 * In order to use the async unlang processor the calling module needs to establish
203 * a resumption point, as the call to an xlat function may require yielding control
204 * back to the interpreter.
205 *
206 * To simplify the calling conventions, this function is provided to first push a
207 * resumption stack frame for the module, and then push a tmpl stack frame.
208 *
209 * After pushing those frames the function updates the stack pointer to jump over
210 * the resumption frame and execute the tmpl expansion.
211 *
212 * When the tmpl interpreter finishes, and pops the tmpl frame, the unlang interpreter
213 * will then call the module resumption frame, allowing the module to continue execution.
214 *
215 * @param[in] ctx To allocate talloc value boxes and values in.
216 * @param[out] out Where to write the result of the expansion.
217 * @param[in] request The current request.
218 * @param[in] vpt the tmpl to expand
219 * @param[in] args Arguments which control how to evaluate the various
220 * types of xlats.
221 * @param[in] resume function to call when the XLAT expansion is complete.
222 * @param[in] signal function to call if a signal is received.
223 * @param[in] sigmask Signals to block.
224 * @param[in] rctx to pass to the resume() and signal() callbacks.
225 * @return
226 * - UNLANG_ACTION_PUSHED_CHILD
227 */
228unlang_action_t unlang_module_yield_to_tmpl(TALLOC_CTX *ctx, fr_value_box_list_t *out,
229 request_t *request, tmpl_t const *vpt,
231 module_method_t resume,
232 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
233{
234 /*
235 * Push the resumption point BEFORE pushing the xlat onto
236 * the parents stack.
237 */
238 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
239
240 /*
241 * Push the xlat function
242 */
243 if (unlang_tmpl_push(ctx, out, request, vpt, args) < 0) return UNLANG_ACTION_FAIL;
244
246}
247
249 request_t *request, CONF_SECTION *subcs,
250 rlm_rcode_t default_rcode,
251 module_method_t resume,
252 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
253{
254 if (!subcs) {
255 unlang_stack_t *stack = request->stack;
256 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
259
262
263 /*
264 * Be transparent to the resume function.
265 * frame->result will be overwritten
266 * anyway when we return.
267 */
268 stack->result = frame->result = default_rcode;
269 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
270
271 return resume(p_result,
273 state->env_data, rctx),
274 request);
275 }
276
277 /*
278 * Push the resumption point BEFORE adding the subsection
279 * to the parents stack.
280 */
281 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
282
283 if (unlang_interpret_push_section(request, subcs,
284 default_rcode, UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_STOP_PROCESSING;
285
287}
288
289/** Run the retry handler. Called from an async signal handler.
290 *
291 */
293{
294 unlang_stack_t *stack = request->stack;
295 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
296 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
297
298 if (!state->retry_cb) return;
299
300 /*
301 * Assert that we have the right things. Note that this function should only be called when the
302 * retry is being used as an expiry time, i.e. mrc==1. If the module has its own retry handlers,
303 * then this function must not be called.
304 */
305 fr_assert(state->retry.config != NULL);
306 fr_assert(state->retry.config->mrc == 1);
307 fr_assert(state->rctx == mctx->rctx);
308 fr_assert(state->request == request);
309
310 /*
311 * Update the time as to when the retry is being called. This is the main purpose of the
312 * function.
313 */
314 state->retry.updated = fr_time();
315
316 state->retry_cb(mctx, request, &state->retry);
317
318}
319
320/** Cancel the retry timer on resume
321 *
322 */
324{
325 unlang_stack_t *stack = request->stack;
326 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
327 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
328
329 /*
330 * Cancel the timers, and clean up any associated retry configuration.
331 */
332 talloc_const_free(state->ev);
333 state->ev = NULL;
334 state->retry_cb = NULL;
335 state->retry.config = NULL;
336
337 return state->retry_resume(p_result, mctx, request);
338}
339
340/** Yield a request back to the interpreter, with retries
341 *
342 * This passes control of the request back to the unlang interpreter, setting
343 * callbacks to execute when the request is 'signalled' asynchronously, or when
344 * the retry timer hits.
345 *
346 * @note The module function which calls #unlang_module_yield_to_retry should return control
347 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield_to_retry.
348 * A common pattern is to use ``return unlang_module_yield_to_retry(...)``.
349 *
350 * @param[in] request The current request.
351 * @param[in] resume Called on unlang_interpret_mark_runnable().
352 * @param[in] retry Called on when a retry timer hits
353 * @param[in] signal Called on unlang_action().
354 * @param[in] sigmask Set of signals to block.
355 * @param[in] rctx to pass to the callbacks.
356 * @param[in] retry_cfg to set up the retries
357 * @return
358 * - UNLANG_ACTION_YIELD on success
359 * - UNLANG_ACTION_FAIL on failure
360 */
362 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx,
363 fr_retry_config_t const *retry_cfg)
364{
365 unlang_stack_t *stack = request->stack;
366 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
368 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
369
370 fr_assert(stack->depth > 0);
373
374 fr_assert(!state->retry_cb);
375
376 state->retry_cb = retry;
377 state->retry_resume = resume; // so that we can cancel the retry timer
378 state->rctx = rctx;
379
380 state->request = request;
381 state->mi = m->mmc.mi;
382
383 /*
384 * Allow unlang statements to override the module configuration. i.e. if we already have a
385 * timer from unlang, then just use that.
386 */
387 if (!state->retry.config) {
388 fr_retry_init(&state->retry, fr_time(), retry_cfg);
389
390 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev,
391 state->retry.next,
392 false, unlang_module_event_retry_handler, request) < 0) {
393 RPEDEBUG("Failed inserting event");
394 return UNLANG_ACTION_FAIL;
395 }
396 }
397
398 return unlang_module_yield(request, unlang_module_retry_resume, signal, sigmask, rctx);
399}
400
401
402/** Yield a request back to the interpreter from within a module
403 *
404 * This passes control of the request back to the unlang interpreter, setting
405 * callbacks to execute when the request is 'signalled' asynchronously, or whatever
406 * timer or I/O event the module was waiting for occurs.
407 *
408 * @note The module function which calls #unlang_module_yield should return control
409 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield.
410 * A common pattern is to use ``return unlang_module_yield(...)``.
411 *
412 * @param[in] request The current request.
413 * @param[in] resume Called on unlang_interpret_mark_runnable().
414 * @param[in] signal Called on unlang_action().
415 * @param[in] sigmask Set of signals to block.
416 * @param[in] rctx to pass to the callbacks.
417 * @return
418 * - UNLANG_ACTION_YIELD.
419 */
421 module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
422{
423 unlang_stack_t *stack = request->stack;
424 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
425 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
426
427 REQUEST_VERIFY(request); /* Check the yielded request is sane */
428
429 state->rctx = rctx;
430 state->resume = resume;
431
432#ifndef NDEBUG
433 /*
434 * We can't do asynchronous signals if the module is not thread safe.
435 *
436 * Right now, none of the modules marked THREAD_UNSAFE call yield, or set signal callbacks.
437 * Which means that this code doesn't affect anything.
438 *
439 * At some point if we do have modules which take signals and which are not thread safe, then
440 * those modules have to ensure that their signal handlers do any locking necessary.
441 */
442 if (signal) {
444
446 fr_assert(m);
447
449 }
450#endif
451
452 state->signal = signal;
453 state->sigmask = sigmask;
454
455 /*
456 * We set the repeatable flag here,
457 * so that the resume function is always
458 * called going back up the stack.
459 */
461
462 return UNLANG_ACTION_YIELD;
463}
464
465/*
466 * Lock the mutex for the module
467 */
468static inline CC_HINT(always_inline) void safe_lock(module_instance_t *mi)
469{
470 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex);
471}
472
473/*
474 * Unlock the mutex for the module
475 */
476static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *mi)
477{
478 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex);
479}
480
481/** Send a signal (usually stop) to a request
482 *
483 * This is typically called via an "async" action, i.e. an action
484 * outside of the normal processing of the request.
485 *
486 * If there is no #unlang_module_signal_t callback defined, the action is ignored.
487 *
488 * @param[in] request The current request.
489 * @param[in] frame current stack frame.
490 * @param[in] action to signal.
491 */
493{
494 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
496 char const *caller;
497
498 if (!state->signal) return;
499
500 /*
501 * Async calls can't push anything onto the unlang stack, so we just use a local "caller" here.
502 */
503 caller = request->module;
504 request->module = m->mmc.mi->name;
505
506 /*
507 * Call the signal routines. Note that signals are
508 * explicitely asynchronous, even if the module has
509 * declared itself to be MODULE_TYPE_THREAD_UNSAFE.
510 */
511 if (!(action & state->sigmask)) state->signal(MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, state->rctx), request, action);
512
513 if (action == FR_SIGNAL_CANCEL) {
514 /*
515 * One fewer caller for this module. Since this module
516 * has been cancelled, decrement the active callers and
517 * ignore any future signals.
518 */
519 state->thread->active_callers--;
520 state->signal = NULL;
521 }
522
523 request->module = caller;
524
525}
526
527/** Cleanup after a module completes
528 *
529 */
531{
532 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
533 rlm_rcode_t rcode = state->rcode_set ? state->rcode : *p_result;
534
535#ifndef NDEBUG
536 fr_assert(state->unlang_indent == request->log.indent.unlang);
537#endif
538
541
542 RDEBUG("%s (%s)", frame->instruction->name ? frame->instruction->name : "",
543 fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
544
545 if (state->p_result) *state->p_result = rcode; /* Inform our caller if we have one */
546 *p_result = rcode;
547 request->module = state->previous_module;
548
550}
551
552/** Cleanup after a yielded module completes
553 *
554 */
556{
557 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
558
559 state->thread->active_callers--;
560
561 return unlang_module_done(p_result, request, frame);
562}
563
564/** Wrapper to call a module's resumption function
565 *
566 * This is called _after_ the module first yields, and again after any
567 * other yields.
568 */
570{
571 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
573 module_method_t resume;
575
576 /*
577 * Update the rcode from any child calls that
578 * may have been performed. The module still
579 * has a chance to override this rcode if it
580 * wants, but process modules in particular
581 * expect to see the result of child
582 * evaluations available to them in p_result.
583 */
584 state->rcode = *p_result < RLM_MODULE_NUMCODES ? *p_result : RLM_MODULE_NOOP;
585
586 fr_assert(state->resume != NULL);
587
588 resume = state->resume;
589
590 /*
591 * The module *MUST* explicitly set the resume
592 * function when yielding or pushing children
593 * if it wants to be called again later.
594 */
595 state->resume = NULL;
596
597 /*
598 * Lock is noop unless instance->mutex is set.
599 */
600 safe_lock(m->mmc.mi);
601 ua = resume(&state->rcode, MODULE_CTX(m->mmc.mi, state->thread->data,
602 state->env_data, state->rctx), request);
603 safe_unlock(m->mmc.mi);
604
605 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
606
607 switch (ua) {
609 RWARN("Module %s or worker signalled to stop processing request", m->mmc.mi->name);
610 if (state->p_result) *state->p_result = state->rcode;
611 state->thread->active_callers--;
612 *p_result = state->rcode;
613 request->module = state->previous_module;
615
617 /*
618 * The module yielded but didn't set a
619 * resume function, this means it's done
620 * and when the I/O operation completes
621 * it shouldn't be called again.
622 */
623 if (!state->resume) {
625 } else {
626 repeatable_set(frame);
627 }
628 return UNLANG_ACTION_YIELD;
629
630 /*
631 * The module is done (for now).
632 * But, running it pushed one or more asynchronous
633 * calls onto the stack for evaluation.
634 * These need to be run before the module resumes
635 * or the next unlang instruction is processed.
636 */
638 /*
639 * The module pushed a child and didn't
640 * set a resume function, this means
641 * it's done, and we won't call it again
642 * but we still need to do some cleanup
643 * after the child returns.
644 */
645 if (!state->resume) {
647 state->rcode_set = false; /* Preserve the child rcode */
648 } else {
649 repeatable_set(frame);
650 }
652
654 /*
655 * Module set a resume function but
656 * didn't yield or push additional
657 * children.
658 *
659 * Evaluate the function now and
660 * use the result as the final result.
661 */
662 if (state->resume) return unlang_module_resume(p_result, request, frame);
663 request->module = state->previous_module;
664 break;
665
667 request->module = state->previous_module;
668 break;
669
671 *p_result = RLM_MODULE_FAIL;
672 request->module = state->previous_module;
673 break;
674
675 case UNLANG_ACTION_EXECUTE_NEXT: /* Not valid */
676 fr_assert(0);
677 *p_result = RLM_MODULE_FAIL;
678 break;
679 }
680
681 unlang_module_resume_done(p_result, request, frame);
682 request->module = state->previous_module;
683
684 return ua;
685}
686
687/** Call the callback registered for a retry event
688 *
689 * @param[in] tl the event timer was inserted into.
690 * @param[in] now The current time, as held by the event_list.
691 * @param[in] ctx the stack frame
692 *
693 */
695{
696 request_t *request = talloc_get_type_abort(ctx, request_t);
697 unlang_stack_t *stack = request->stack;
698 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
699 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
700
701 switch (fr_retry_next(&state->retry, now)) {
703 if (state->retry_cb) {
704 /*
705 * Call the module retry handler, with the state of the retry. On MRD / MRC, the
706 * module is made runnable again, and the "resume" function is called.
707 */
708 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
709 } else {
710 /*
711 * For signals, the module will get either a RETRY
712 * signal, or a TIMEOUT signal (also for max count).
713 *
714 * The signal handler should generally change the resume
715 * function, and mark the request as runnable. We
716 * probably don't want the module to do tons of work in
717 * the signal handler, as it's called from the event
718 * loop. And doing so could affect the other event
719 * timers.
720 *
721 * Note also that we call frame->signal(), and not
722 * unlang_interpret_signal(). That is because we want to
723 * signal only the module. We know that the other frames
724 * on the stack can't handle this particular signal. So
725 * there's no point in calling them. Or, if sections
726 * have their own retry handlers, then we don't want to
727 * signal those _other_ retry handlers with _our_ signal.
728 */
729 frame->signal(request, frame, FR_SIGNAL_RETRY);
730 }
731
732 /*
733 * Reset the timer.
734 */
735 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev, state->retry.next,
736 false, unlang_module_event_retry_handler, request) < 0) {
737 RPEDEBUG("Failed inserting event");
738 unlang_interpret_mark_runnable(request); /* and let the caller figure out what's up */
739 }
740 return;
741
742 case FR_RETRY_MRD:
743 RDEBUG("Reached max_rtx_duration (%pVs > %pVs) - sending timeout",
745 break;
746
747 case FR_RETRY_MRC:
748 RDEBUG("Reached max_rtx_count %u- sending timeout",
749 state->retry.config->mrc);
750 break;
751 }
752
753 /*
754 * Run the retry handler on MRD / MRC, too.
755 */
756 if (state->retry_cb) {
757 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
758 } else {
759 frame->signal(request, frame, FR_SIGNAL_TIMEOUT);
760 }
761
762 /*
763 * On final timeout, always mark the request as runnable.
764 */
766}
767
769{
771 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
773 fr_time_t now = fr_time_wrap(0);
774
775 *p_result = state->rcode = RLM_MODULE_NOOP;
776 state->rcode_set = true;
777 state->previous_module = request->module;
778
779#ifndef NDEBUG
780 state->unlang_indent = request->log.indent.unlang;
781#endif
782 /*
783 * Process a stand-alone child, and fall through
784 * to dealing with it's parent.
785 */
787 fr_assert(m);
788
789 RDEBUG4("[%i] %s - %s (%s)", stack_depth_current(request), __FUNCTION__,
790 m->mmc.mi->module->exported->name, m->mmc.mi->name);
791
792 state->p_result = NULL;
793
794 /*
795 * Return administratively configured return code
796 */
797 if (m->mmc.mi->force) {
798 state->rcode = m->mmc.mi->code;
800 goto done;
801 }
802
803 if (m->mmc.mmb.method_env) {
804 if (!state->env_data) {
805 ua = call_env_expand(state, request, &state->env_result, &state->env_data, m->call_env);
806 switch (ua) {
808 goto fail;
809
813
814 default:
815 break;
816 }
817 }
818
819 /*
820 * Fail the module call on callenv failure
821 */
823 }
824
825 /*
826 * Grab the thread/module specific data if any exists.
827 */
828 state->thread = module_thread(m->mmc.mi);
829 fr_assert(state->thread != NULL);
830
831 /*
832 * Don't allow returning _through_ modules
833 */
835
836 /*
837 * For logging unresponsive children.
838 */
839 state->thread->total_calls++;
840
841 /*
842 * If we're doing retries, remember when we started
843 * running the module.
844 */
846
847 request->module = m->mmc.mi->name;
848 safe_lock(m->mmc.mi); /* Noop unless instance->mutex set */
849 ua = m->mmc.mmb.method(&state->rcode,
850 MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, NULL),
851 request);
852 safe_unlock(m->mmc.mi);
853
854 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
855
856 switch (ua) {
857 /*
858 * It is now marked as "stop" when it wasn't before, we
859 * must have been blocked.
860 */
862 RWARN("Module %s became unblocked", m->mmc.mi->name);
863 if (state->p_result) *state->p_result = state->rcode;
864 *p_result = state->rcode;
865 request->module = state->previous_module;
867
869 state->thread->active_callers++;
870
871 /*
872 * The module yielded but didn't set a
873 * resume function, this means it's done
874 * and when the I/O operation completes
875 * it shouldn't be called again.
876 */
877 if (!state->resume) {
879 } else {
881 }
882
883 /*
884 * If we have retry timers, then start the retries.
885 */
888
889 fr_retry_init(&state->retry, now, &frame->instruction->actions.retry);
890
891 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl,
892 &state->ev, state->retry.next,
893 false, unlang_module_event_retry_handler, request) < 0) {
894 RPEDEBUG("Failed inserting event");
895 goto fail;
896 }
897 }
898
899 return UNLANG_ACTION_YIELD;
900
901 /*
902 * The module is done (for now).
903 * But, running it pushed one or more asynchronous
904 * calls onto the stack for evaluation.
905 * These need to be run before the module resumes
906 * or the next unlang instruction is processed.
907 */
909 /*
910 * The module pushed a child and didn't
911 * set a resume function, this means
912 * it's done, and we won't call it again
913 * but we still need to do some cleanup
914 * after the child returns.
915 */
916 if (!state->resume) {
918 state->rcode_set = false; /* Preserve the child rcode */
919 } else {
920 repeatable_set(frame);
921 }
923
925 /*
926 * Module set a resume function but
927 * didn't yield or push additional
928 * children.
929 *
930 * Evaluate the function now and
931 * use the result as the final result.
932 */
933 if (state->resume) {
934 frame->process = unlang_module_resume; /* unlang_module_resume will assume this is set */
935 return unlang_module_resume(p_result, request, frame);
936 }
937 break;
938
940 break;
941
943 fail:
944 *p_result = RLM_MODULE_FAIL;
945 break;
946
948 fr_assert(0);
949 *p_result = RLM_MODULE_FAIL;
950 break;
951 }
952
953done:
954 request->module = state->previous_module;
955 unlang_module_done(p_result, request, frame);
956 return ua;
957}
958
960{
962 &(unlang_op_t){
963 .name = "module",
964 .interpret = unlang_module,
965 .rcode_set = true,
966 .signal = unlang_module_signal,
967 .frame_state_size = sizeof(unlang_frame_state_module_t),
968 .frame_state_type = "unlang_frame_state_module_t",
969 });
970}
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:296
@ 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:82
#define MEM(x)
Definition debug.h:36
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1374
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:161
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:1007
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1779
#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:80
#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:276
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:62
char const * name
Instance name e.g. user_database.
Definition module.h:335
@ 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:227
uint64_t active_callers
total number of times we've been called
Definition module.h:359
bool force
Force the module to return a specific code.
Definition module.h:297
module_method_t method
Module method to call.
Definition module.h:176
void * data
Thread specific instance data.
Definition module.h:352
rlm_rcode_t code
Code module will return when 'force' has has been set to true.
Definition module.h:300
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:481
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:276
pthread_mutex_t mutex
Used prevent multiple threads entering a thread unsafe module simultaneously.
Definition module.h:283
Module instance data.
Definition module.h:265
static fr_slen_t vpt
Definition tmpl.h:1274
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:248
int unlang_module_set_resume(request_t *request, module_method_t resume)
Change the resume function of a module.
Definition module.c:132
static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition module.c:768
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:181
static void safe_lock(module_instance_t *mi)
Definition module.c:468
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:694
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:53
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:420
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:361
void unlang_module_init(void)
Definition module.c:959
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:569
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:555
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:530
void unlang_module_retry_now(module_ctx_t const *mctx, request_t *request)
Run the retry handler.
Definition module.c:292
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:228
static void safe_unlock(module_instance_t *mi)
Definition module.c:476
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:492
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:323
#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:53
#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:262
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:287
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