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: 7c8dc1174b0cb1ccc14088ac2ed07cffc5aac71b $
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: 7c8dc1174b0cb1ccc14088ac2ed07cffc5aac71b $")
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 break;
130
132 goto again;
133
134 default:
136 }
137 }
138
139done:
141
142 return ua;
143}
144
145/** Call a generic function that produces a result
146 *
147 * @param[out] p_result The frame result.
148 * @param[in] request The current request.
149 * @param[in] frame The current frame.
150 */
152{
154 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
155
157
158 RDEBUG4("Calling function %p (%s)", FUNC(state), state->func_name);
159 ua = state->func.wres(p_result, request, state->uctx);
160 FUNC(state) = NULL;
161 state->func_name = NULL;
162 if (REPEAT(state)) {
163 switch (ua) {
165 break;
166
168 ua = call_with_result_repeat(p_result, request, frame);
169 break;
170
171 default:
173 }
174 }
176
177 return ua;
178}
179
180/** Call a generic function that produces a result
181 *
182 * @param[out] p_result The frame result.
183 * @param[in] request The current request.
184 * @param[in] frame The current frame.
185 */
187{
189 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
191
193
194 if (!REPEAT(state)) {
195 RDEBUG4("Repeat function is NULL, likely due to previous yield, skipping call");
197 goto done;
198 }
199
200again:
201 RDEBUG4("Calling repeat function %p (%s)", REPEAT(state), state->repeat_name);
202
203 /*
204 * Only called once...
205 */
206 REPEAT(state) = NULL;
207 state->repeat_name = NULL;
208 ua = func(request, state->uctx);
209 if (REPEAT(state)) { /* set again by func */
210 switch (ua) {
212 break;
213
215 goto again;
216
218 no_action_fail:
219 fr_assert_msg(0, "Function %s (%p) is not allowed to indicate failure via UNLANG_ACTION_FAIL",
220 state->repeat_name, REPEAT(state));
222 break;
223
224 default:
226 }
227 }
228
229 if (ua == UNLANG_ACTION_FAIL) goto no_action_fail;
230
231done:
233
234 return ua;
235}
236
237/** Call a generic function that produces a result
238 *
239 * @param[out] p_result The frame result.
240 * @param[in] request The current request.
241 * @param[in] frame The current frame.
242 */
244{
246 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
247
249
250 RDEBUG4("Calling function %p (%s)", FUNC(state), state->func_name);
251 ua = state->func.nres(request, state->uctx);
252 FUNC(state) = NULL;
253 state->func_name = NULL;
254 if (REPEAT(state)) {
255 switch (ua) {
257 break;
258
260 ua = call_no_result_repeat(p_result, request, frame);
261 break;
262
264 no_action_fail:
265 fr_assert_msg(0, "Function is not allowed to indicate failure via UNLANG_ACTION_FAIL");
267 break;
268
269 default:
271 }
272 }
273 if (ua == UNLANG_ACTION_FAIL) goto no_action_fail;
274
276
277 return ua;
278}
279
280/** Clear pending repeat function calls, and remove the signal handler.
281 *
282 * The function frame being modified must be at the top of the stack.
283 *
284 * @param[in] request The current request.
285 * @return
286 * - 0 on success.
287 * - -1 on failure.
288 */
290{
291 unlang_stack_t *stack = request->stack;
292 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
294
295 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
296 RERROR("Can't clear function on non-function frame");
297 return -1;
298 }
299
300 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
301 REPEAT(state) = NULL;
302 state->signal = NULL;
303
304 repeatable_clear(frame);
305
306 return 0;
307}
308
309/** Set a new signal function for an existing function frame
310 *
311 * @private
312 *
313 * The function frame being modified must be at the top of the stack.
314 *
315 * @param[in] request The current request.
316 * @param[in] signal The signal function to set.
317 * @param[in] sigmask Signals to block.
318 * @param[in] signal_name Name of the signal function call (for debugging).
319 * @return
320 * - 0 on success.
321 * - -1 on failure.
322 */
323int _unlang_function_signal_set(request_t *request, unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name)
324{
325 unlang_stack_t *stack = request->stack;
326 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
328
329 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
330 RERROR("Can't set repeat function on non-function frame");
331 return -1;
332 }
333
334 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
335
336 /*
337 * If we're inside unlang_function_call,
338 * it'll pickup state->repeat and do the right thing
339 * once the current function returns.
340 */
341 state->signal = signal;
342 state->sigmask = sigmask;
343 state->signal_name = signal_name;
344
345 return 0;
346}
347
348/** Set a new repeat function for an existing function frame
349 *
350 * @private
351 *
352 * The function frame being modified must be at the top of the stack.
353 *
354 * @param[in] request The current request.
355 * @param[in] repeat the repeat function to set.
356 * @param[in] repeat_name Name of the repeat function call (for debugging).
357 * @param[in] type Type of repeat function (with or without result).
358 * @return
359 * - 0 on success.
360 * - -1 on failure.
361 */
362int _unlang_function_repeat_set(request_t *request, void *repeat, char const *repeat_name, unlang_function_type_t type)
363{
364 unlang_stack_t *stack = request->stack;
365 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
367
368 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
369 RERROR("Can't set repeat function on non-function frame");
370 return -1;
371 }
372
373 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
374
375 if (unlikely(state->type != type)) {
376 fr_assert_msg(0, "Function type mismatch \"%s\"", repeat_name);
377 return -1;
378 }
379
380 /*
381 * If we're inside unlang_function_call,
382 * it'll pickup state->repeat and do the right thing
383 * once the current function returns.
384 */
385 REPEAT(state) = repeat;
386 state->repeat_name = repeat_name;
387 repeatable_set(frame);
388
389 return 0;
390}
391
392static inline CC_HINT(always_inline)
394 request_t *request,
395 void *func,
396 char const *func_name,
397 void *repeat,
398 char const *repeat_name,
399 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
401 bool top_frame,
402 void *uctx)
403{
404 unlang_stack_t *stack = request->stack;
407
408 if (!func && !repeat) {
409 fr_assert_msg(0, "function push must push at least one function!");
410 return UNLANG_ACTION_FAIL;
411 }
412
413 /*
414 * Push module's function
415 */
416 if (unlang_interpret_push(p_result, request, &function_instruction,
417 FRAME_CONF(RLM_MODULE_NOOP, top_frame), UNLANG_NEXT_STOP) < 0) {
418 return UNLANG_ACTION_FAIL;
419 }
420
421 frame = &stack->frame[stack->depth];
422
423 /*
424 * Initialize state
425 */
426 state = frame->state;
427 state->signal = signal;
428 state->sigmask = sigmask;
429 state->signal_name = signal_name;
430 state->type = type;
431 state->uctx = uctx;
432
433 FUNC(state) = func;
434 state->func_name = func_name;
435 REPEAT(state) = repeat;
436 state->repeat_name = repeat_name;
437
438 if (repeat) repeatable_set(frame); /* execute on the way back up */
439
441}
442
443/** Push a generic function onto the unlang stack with a result
444 *
445 * @private
446 *
447 * These can be pushed by any other type of unlang op to allow a submodule or function
448 * deeper in the C call stack to establish a new resumption point.
449 *
450 * @param[in] p_result Where to write the result of the function evaluation.
451 *
452 * @param[in] request The current request.
453 * @param[in] func to call going up the stack.
454 * @param[in] func_name Name of the function call (for debugging).
455 * @param[in] repeat function to call going back down the stack (may be NULL).
456 * This may be the same as func.
457 * @param[in] repeat_name Name of the repeat function call (for debugging).
458 * @param[in] signal function to call if the request is signalled.
459 * @param[in] sigmask Signals to block.
460 * @param[in] signal_name Name of the signal function call (for debugging).
461 * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
462 * @param[in] uctx to pass to func(s).
463 * @return
464 * - UNLANG_ACTION_PUSHED_CHILD on success.
465 * - UNLANG_ACTION_FAIL on failure.
466 */
467unlang_action_t _unlang_function_push_with_result(unlang_result_t *p_result,
468 request_t *request,
469 unlang_function_with_result_t func, char const *func_name,
470 unlang_function_with_result_t repeat, char const *repeat_name,
471 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
472 bool top_frame, void *uctx)
473{
476
477 ua = unlang_function_push_common(p_result,
478 request,
479 func, func_name,
480 repeat, repeat_name,
481 signal, sigmask, signal_name,
482 UNLANG_FUNCTION_TYPE_WITH_RESULT, top_frame, uctx);
483
485
486 frame = frame_current(request);
487 if (!func && repeat) {
489 } else {
490 frame->process = call_with_result;
491 }
492
493 return ua;
494}
495
496/** Push a generic function onto the unlang stack
497 *
498 * @private
499 *
500 * These can be pushed by any other type of unlang op to allow a submodule or function
501 * deeper in the C call stack to establish a new resumption point.
502 *
503 * @param[in] request The current request.
504 * @param[in] func to call going up the stack.
505 * @param[in] func_name Name of the function call (for debugging).
506 * @param[in] repeat function to call going back down the stack (may be NULL).
507 * This may be the same as func.
508 * @param[in] repeat_name Name of the repeat function call (for debugging).
509 * @param[in] signal function to call if the request is signalled.
510 * @param[in] sigmask Signals to block.
511 * @param[in] signal_name Name of the signal function call (for debugging).
512 * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
513 * @param[in] uctx to pass to func(s).
514 * @return
515 * - UNLANG_ACTION_PUSHED_CHILD on success.
516 * - UNLANG_ACTION_FAIL on failure.
517 */
518unlang_action_t _unlang_function_push_no_result(request_t *request,
519 unlang_function_no_result_t func, char const *func_name,
520 unlang_function_no_result_t repeat, char const *repeat_name,
521 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
522 bool top_frame, void *uctx)
523{
526
528 request,
529 func, func_name,
530 repeat, repeat_name,
531 signal, sigmask, signal_name,
532 UNLANG_FUNCTION_TYPE_NO_RESULT, top_frame, uctx);
533
535
536 frame = frame_current(request);
537 if (!func && repeat) {
539 }
540
541 /* frame->process = call_no_result - This is the default, we don't need to set it again */
542
543 return ua;
544}
545
546/** Custom frame state dumper
547 *
548 */
550{
551 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
552
553 RDEBUG2("frame state");
554 if (FUNC(state)) RDEBUG2("function %p (%s)", FUNC(state), state->func_name);
555 if (REPEAT(state)) RDEBUG2("repeat %p (%s)", REPEAT(state), state->repeat_name);
556 if (state->signal) RDEBUG2("signal %p (%s)", state->signal, state->signal_name);
557}
558
560{
562 .name = "function",
563 .type = UNLANG_TYPE_FUNCTION,
565
566 .interpret = call_no_result,
567 .signal = unlang_function_signal,
568 .dump = unlang_function_dump,
569
570 .unlang_size = sizeof(unlang_group_t),
571 .unlang_name = "unlang_group_t",
572
573 .frame_state_size = sizeof(unlang_frame_state_func_t),
574 .frame_state_type = "unlang_frame_state_func_t",
575 });
576}
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_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ 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:549
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:151
#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:289
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:186
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:393
#define STORE_CALLER
Definition function.c:89
void unlang_function_init(void)
Definition function.c:559
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:243
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:99
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.