The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
function.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: 17489614eae6e4de2adae23523f96da7ba3f4125 $
19 *
20 * @file unlang/function.c
21 * @brief Unlang "function" keyword evaluation.
22
23 * @copyright 2018,2021 The FreeRADIUS server project
24 * @copyright 2018,2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSID("$Id: 17489614eae6e4de2adae23523f96da7ba3f4125 $")
27
28#include "action.h"
29#include "unlang_priv.h"
30#include "function.h"
31
32#define FUNC(_state) *((void **)&state->func)
33#define REPEAT(_state) *((void **)&state->repeat)
34
35/*
36 * Some functions differ mainly in their parsing
37 */
38typedef struct {
39 union {
40 unlang_function_no_result_t nres; //!< To call when going down the stack.
41 unlang_function_with_result_t wres; //!< To call when going down the stack.
42 } func;
43 char const *func_name; //!< Debug name for the function.
44
45 union {
46 unlang_function_no_result_t nres; //!< To call when going back up the stack.
47 unlang_function_with_result_t wres; //!< To call when going back up the stack.
48 } repeat;
49 unlang_function_type_t type; //!< Record whether we need to call the
50 char const *repeat_name; //!< Debug name for the repeat function.
51
52 unlang_function_signal_t signal; //!< Signal function to call.
53 fr_signal_t sigmask; //!< Signals to block.
54 char const *signal_name; //!< Debug name for the signal function.
55 void *uctx; //!< Uctx to pass to function.
57
58/** Static instruction for allowing modules/xlats to call functions within themselves, or submodules
59 *
60 */
63 .name = "function",
64 .debug_name = "function",
65 .actions = DEFAULT_MOD_ACTIONS,
66};
67
68/** Generic signal handler
69 *
70 * @param[in] request being signalled.
71 * @param[in] frame being signalled.
72 * @param[in] action Type of signal.
73 */
74static void unlang_function_signal(request_t *request,
75 unlang_stack_frame_t *frame, fr_signal_t action)
76{
77 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
78
79 if (!state->signal || (action & state->sigmask)) return;
80
81 state->signal(request, action, state->uctx);
82}
83
84
85/*
86 * Don't let the callback mess with the current
87 * module permanently.
88 */
89#define STORE_CALLER \
90 char const *caller; \
91 caller = request->module; \
92 request->module = NULL
93
94#define RESTORE_CALLER \
95 request->module = caller;
96
97/** Call a generic function that produces a result
98 *
99 * @param[out] p_result The frame result.
100 * @param[in] request The current request.
101 * @param[in] frame The current frame.
102 */
104{
106 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
108
110
111 if (!REPEAT(state)) {
112 RDEBUG4("Repeat function is NULL, likely due to previous yield, skipping call");
114 goto done;
115 }
116
117again:
118 RDEBUG4("Calling repeat function %p (%s)", REPEAT(state), state->repeat_name);
119
120 /*
121 * Only called once...
122 */
123 REPEAT(state) = NULL;
124 state->repeat_name = NULL;
125 ua = func(p_result, request, state->uctx);
126 if (REPEAT(state)) { /* set again by func */
127 switch (ua) {
129 goto again;
130
131 default:
133 }
134 }
135
136done:
138
139 return ua;
140}
141
142/** Call a generic function that produces a result
143 *
144 * @param[out] p_result The frame result.
145 * @param[in] request The current request.
146 * @param[in] frame The current frame.
147 */
149{
151 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
152
154
155 RDEBUG4("Calling function %p (%s)", FUNC(state), state->func_name);
156 ua = state->func.wres(p_result, request, state->uctx);
157 FUNC(state) = NULL;
158 state->func_name = NULL;
159 if (REPEAT(state)) {
160 switch (ua) {
162 ua = call_with_result_repeat(p_result, request, frame);
163 break;
164
165 default:
167 }
168 }
170
171 return ua;
172}
173
174/** Call a generic function that produces a result
175 *
176 * @param[out] p_result The frame result.
177 * @param[in] request The current request.
178 * @param[in] frame The current frame.
179 */
181{
183 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
185
187
188 if (!REPEAT(state)) {
189 RDEBUG4("Repeat function is NULL, likely due to previous yield, skipping call");
191 goto done;
192 }
193
194again:
195 RDEBUG4("Calling repeat function %p (%s)", REPEAT(state), state->repeat_name);
196
197 /*
198 * Only called once...
199 */
200 REPEAT(state) = NULL;
201 state->repeat_name = NULL;
202 ua = func(request, state->uctx);
203 if (REPEAT(state)) { /* set again by func */
204 switch (ua) {
206 goto again;
207
209 no_action_fail:
210 fr_assert_msg(0, "Function %s (%p) is not allowed to indicate failure via UNLANG_ACTION_FAIL",
211 state->repeat_name, REPEAT(state));
213 break;
214
215 default:
217 }
218 }
219
220 if (ua == UNLANG_ACTION_FAIL) goto no_action_fail;
221
222done:
224
225 return ua;
226}
227
228/** Call a generic function that produces a result
229 *
230 * @param[out] p_result The frame result.
231 * @param[in] request The current request.
232 * @param[in] frame The current frame.
233 */
235{
237 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
238
240
241 RDEBUG4("Calling function %p (%s)", FUNC(state), state->func_name);
242 ua = state->func.nres(request, state->uctx);
243 FUNC(state) = NULL;
244 state->func_name = NULL;
245 if (REPEAT(state)) {
246 switch (ua) {
248 ua = call_no_result_repeat(p_result, request, frame);
249 break;
250
252 no_action_fail:
253 fr_assert_msg(0, "Function is not allowed to indicate failure via UNLANG_ACTION_FAIL");
255 break;
256
257 default:
259 }
260 }
261 if (ua == UNLANG_ACTION_FAIL) goto no_action_fail;
262
264
265 return ua;
266}
267
268/** Clear pending repeat function calls, and remove the signal handler.
269 *
270 * The function frame being modified must be at the top of the stack.
271 *
272 * @param[in] request The current request.
273 * @return
274 * - 0 on success.
275 * - -1 on failure.
276 */
278{
279 unlang_stack_t *stack = request->stack;
280 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
282
283 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
284 RERROR("Can't clear function on non-function frame");
285 return -1;
286 }
287
288 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
289 REPEAT(state) = NULL;
290 state->signal = NULL;
291
292 repeatable_clear(frame);
293
294 return 0;
295}
296
297/** Set a new signal function for an existing function frame
298 *
299 * @private
300 *
301 * The function frame being modified must be at the top of the stack.
302 *
303 * @param[in] request The current request.
304 * @param[in] signal The signal function to set.
305 * @param[in] sigmask Signals to block.
306 * @param[in] signal_name Name of the signal function call (for debugging).
307 * @return
308 * - 0 on success.
309 * - -1 on failure.
310 */
311int _unlang_function_signal_set(request_t *request, unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name)
312{
313 unlang_stack_t *stack = request->stack;
314 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
316
317 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
318 RERROR("Can't set repeat function on non-function frame");
319 return -1;
320 }
321
322 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
323
324 /*
325 * If we're inside unlang_function_call,
326 * it'll pickup state->repeat and do the right thing
327 * once the current function returns.
328 */
329 state->signal = signal;
330 state->sigmask = sigmask;
331 state->signal_name = signal_name;
332
333 return 0;
334}
335
336/** Set a new repeat function for an existing function frame
337 *
338 * @private
339 *
340 * The function frame being modified must be at the top of the stack.
341 *
342 * @param[in] request The current request.
343 * @param[in] repeat the repeat function to set.
344 * @param[in] repeat_name Name of the repeat function call (for debugging).
345 * @param[in] type Type of repeat function (with or without result).
346 * @return
347 * - 0 on success.
348 * - -1 on failure.
349 */
350int _unlang_function_repeat_set(request_t *request, void *repeat, char const *repeat_name, unlang_function_type_t type)
351{
352 unlang_stack_t *stack = request->stack;
353 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
355
356 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
357 RERROR("Can't set repeat function on non-function frame");
358 return -1;
359 }
360
361 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
362
363 if (unlikely(state->type != type)) {
364 fr_assert_msg(0, "Function type mismatch \"%s\"", repeat_name);
365 return -1;
366 }
367
368 /*
369 * If we're inside unlang_function_call,
370 * it'll pickup state->repeat and do the right thing
371 * once the current function returns.
372 */
373 REPEAT(state) = repeat;
374 state->repeat_name = repeat_name;
375 repeatable_set(frame);
376
377 return 0;
378}
379
380static inline CC_HINT(always_inline)
382 request_t *request,
383 void *func,
384 char const *func_name,
385 void *repeat,
386 char const *repeat_name,
387 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
389 bool top_frame,
390 void *uctx)
391{
392 unlang_stack_t *stack = request->stack;
395
396 if (!func && !repeat) {
397 fr_assert_msg(0, "function push must push at least one function!");
398 return UNLANG_ACTION_FAIL;
399 }
400
401 /*
402 * Push module's function
403 */
404 if (unlang_interpret_push(p_result, request, &function_instruction,
405 FRAME_CONF(RLM_MODULE_NOOP, top_frame), UNLANG_NEXT_STOP) < 0) {
406 return UNLANG_ACTION_FAIL;
407 }
408
409 frame = &stack->frame[stack->depth];
410
411 /*
412 * Initialize state
413 */
414 state = frame->state;
415 state->signal = signal;
416 state->sigmask = sigmask;
417 state->signal_name = signal_name;
418 state->type = type;
419 state->uctx = uctx;
420
421 FUNC(state) = func;
422 state->func_name = func_name;
423 REPEAT(state) = repeat;
424 state->repeat_name = repeat_name;
425
426 if (repeat) repeatable_set(frame); /* execute on the way back up */
427
429}
430
431/** Push a generic function onto the unlang stack with a result
432 *
433 * @private
434 *
435 * These can be pushed by any other type of unlang op to allow a submodule or function
436 * deeper in the C call stack to establish a new resumption point.
437 *
438 * @param[in] p_result Where to write the result of the function evaluation.
439 *
440 * @param[in] request The current request.
441 * @param[in] func to call going up the stack.
442 * @param[in] func_name Name of the function call (for debugging).
443 * @param[in] repeat function to call going back down the stack (may be NULL).
444 * This may be the same as func.
445 * @param[in] repeat_name Name of the repeat function call (for debugging).
446 * @param[in] signal function to call if the request is signalled.
447 * @param[in] sigmask Signals to block.
448 * @param[in] signal_name Name of the signal function call (for debugging).
449 * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
450 * @param[in] uctx to pass to func(s).
451 * @return
452 * - UNLANG_ACTION_PUSHED_CHILD on success.
453 * - UNLANG_ACTION_FAIL on failure.
454 */
455unlang_action_t _unlang_function_push_with_result(unlang_result_t *p_result,
456 request_t *request,
457 unlang_function_with_result_t func, char const *func_name,
458 unlang_function_with_result_t repeat, char const *repeat_name,
459 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
460 bool top_frame, void *uctx)
461{
464
465 ua = unlang_function_push_common(p_result,
466 request,
467 func, func_name,
468 repeat, repeat_name,
469 signal, sigmask, signal_name,
470 UNLANG_FUNCTION_TYPE_WITH_RESULT, top_frame, uctx);
471
473
474 frame = frame_current(request);
475 if (!func && repeat) {
477 } else {
478 frame->process = call_with_result;
479 }
480
481 return ua;
482}
483
484/** Push a generic function onto the unlang stack
485 *
486 * @private
487 *
488 * These can be pushed by any other type of unlang op to allow a submodule or function
489 * deeper in the C call stack to establish a new resumption point.
490 *
491 * @param[in] request The current request.
492 * @param[in] func to call going up the stack.
493 * @param[in] func_name Name of the function call (for debugging).
494 * @param[in] repeat function to call going back down the stack (may be NULL).
495 * This may be the same as func.
496 * @param[in] repeat_name Name of the repeat function call (for debugging).
497 * @param[in] signal function to call if the request is signalled.
498 * @param[in] sigmask Signals to block.
499 * @param[in] signal_name Name of the signal function call (for debugging).
500 * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
501 * @param[in] uctx to pass to func(s).
502 * @return
503 * - UNLANG_ACTION_PUSHED_CHILD on success.
504 * - UNLANG_ACTION_FAIL on failure.
505 */
506unlang_action_t _unlang_function_push_no_result(request_t *request,
507 unlang_function_no_result_t func, char const *func_name,
508 unlang_function_no_result_t repeat, char const *repeat_name,
509 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
510 bool top_frame, void *uctx)
511{
514
516 request,
517 func, func_name,
518 repeat, repeat_name,
519 signal, sigmask, signal_name,
520 UNLANG_FUNCTION_TYPE_NO_RESULT, top_frame, uctx);
521
523
524 frame = frame_current(request);
525 if (!func && repeat) {
527 }
528
529 /* frame->process = call_no_result - This is the default, we don't need to set it again */
530
531 return ua;
532}
533
534/** Custom frame state dumper
535 *
536 */
538{
539 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
540
541 RDEBUG2("frame state");
542 if (FUNC(state)) RDEBUG2("function %p (%s)", FUNC(state), state->func_name);
543 if (REPEAT(state)) RDEBUG2("repeat %p (%s)", REPEAT(state), state->repeat_name);
544 if (state->signal) RDEBUG2("signal %p (%s)", state->signal, state->signal_name);
545}
546
548{
550 .name = "function",
551 .type = UNLANG_TYPE_FUNCTION,
553
554 .interpret = call_no_result,
555 .signal = unlang_function_signal,
556 .dump = unlang_function_dump,
557
558 .unlang_size = sizeof(unlang_group_t),
559 .unlang_name = "unlang_group_t",
560
561 .frame_state_size = sizeof(unlang_frame_state_func_t),
562 .frame_state_type = "unlang_frame_state_func_t",
563 });
564}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ 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
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
static void unlang_function_dump(request_t *request, unlang_stack_frame_t *frame)
Custom frame state dumper.
Definition function.c:537
char const * repeat_name
Debug name for the repeat function.
Definition function.c:50
unlang_function_type_t type
Record whether we need to call the.
Definition function.c:49
static unlang_action_t call_with_result(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Call a generic function that produces a result.
Definition function.c:148
#define RESTORE_CALLER
Definition function.c:94
int unlang_function_clear(request_t *request)
Clear pending repeat function calls, and remove the signal handler.
Definition function.c:277
static unlang_action_t call_with_result_repeat(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Call a generic function that produces a result.
Definition function.c:103
static unlang_t function_instruction
Static instruction for allowing modules/xlats to call functions within themselves,...
Definition function.c:61
#define REPEAT(_state)
Definition function.c:33
unlang_function_signal_t signal
Signal function to call.
Definition function.c:52
void * uctx
Uctx to pass to function.
Definition function.c:55
union unlang_frame_state_func_t::@101 func
char const * func_name
Debug name for the function.
Definition function.c:43
fr_signal_t sigmask
Signals to block.
Definition function.c:53
static unlang_action_t call_no_result_repeat(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Call a generic function that produces a result.
Definition function.c:180
static unlang_action_t unlang_function_push_common(unlang_result_t *p_result, request_t *request, void *func, char const *func_name, void *repeat, char const *repeat_name, unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name, unlang_function_type_t type, bool top_frame, void *uctx)
Definition function.c:381
#define STORE_CALLER
Definition function.c:89
void unlang_function_init(void)
Definition function.c:547
static void unlang_function_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Generic signal handler.
Definition function.c:74
static unlang_action_t call_no_result(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Call a generic function that produces a result.
Definition function.c:234
char const * signal_name
Debug name for the signal function.
Definition function.c:54
#define FUNC(_state)
Definition function.c:32
Declarations for generic unlang functions.
unlang_function_type_t
Definition function.h:41
@ UNLANG_FUNCTION_TYPE_NO_RESULT
Function without a result.
Definition function.h:43
@ UNLANG_FUNCTION_TYPE_WITH_RESULT
Function with a result.
Definition function.h:42
void(* unlang_function_signal_t)(request_t *request, fr_signal_t action, void *uctx)
Function to call if the request was signalled.
Definition function.h:78
unlang_action_t(* unlang_function_no_result_t)(request_t *request, void *uctx)
A generic function pushed by a module or xlat to functions deeper in the C call stack to create resum...
Definition function.h:68
unlang_action_t(* unlang_function_with_result_t)(unlang_result_t *p_result, request_t *request, void *uctx)
A generic function pushed by a module or xlat to functions deeper in the C call stack to create resum...
Definition function.h:55
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:280
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:152
#define RERROR(fmt,...)
Definition log.h:298
#define RDEBUG4(fmt,...)
Definition log.h:344
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
static char * stack[MAX_STACK]
Definition radmin.c:159
#define DEFAULT_MOD_ACTIONS
Definition mod_action.h:68
static bool done
Definition radclient.c:81
#define RDEBUG2(fmt,...)
Definition radclient.h:54
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:50
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
fr_aka_sim_id_type_t type
Private interpreter structures and functions.
static void repeatable_clear(unlang_stack_frame_t *frame)
void * state
Stack frame specialisations.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:98
static unlang_stack_frame_t * frame_current(request_t *request)
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:50
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.
@ UNLANG_OP_FLAG_RETURN_POINT
Return point.
@ UNLANG_OP_FLAG_INTERNAL
it's not a real keyword
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.
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.