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: 4477a947db040f398f29b21d866e4493e7dfbbbd $
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: 4477a947db040f398f29b21d866e4493e7dfbbbd $")
27
28#include "unlang_priv.h"
29#include "function.h"
30
31/*
32 * Some functions differ mainly in their parsing
33 */
34typedef struct {
35 unlang_function_t func; //!< To call when going down the stack.
36 char const *func_name; //!< Debug name for the function.
37 unlang_function_t repeat; //!< To call when going back up the stack.
38 char const *repeat_name; //!< Debug name for the repeat function.
39 unlang_function_signal_t signal; //!< Signal function to call.
40 fr_signal_t sigmask; //!< Signals to block.
41 char const *signal_name; //!< Debug name for the signal function.
42 void *uctx; //!< Uctx to pass to function.
44
45/** Static instruction for allowing modules/xlats to call functions within themselves, or submodules
46 *
47 */
50 .name = "function",
51 .debug_name = "function",
52 .actions = {
53 .actions = {
55 [RLM_MODULE_FAIL] = 0,
56 [RLM_MODULE_OK] = 0,
61 [RLM_MODULE_NOOP] = 0,
63 },
64 .retry = RETRY_INIT,
65 },
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
85{
87 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
88 char const *caller;
89
90 /*
91 * Don't let the callback mess with the current
92 * module permanently.
93 */
94 caller = request->module;
95 request->module = NULL;
96 RDEBUG4("Calling repeat function %p (%s)", state->repeat, state->repeat_name);
97 ua = state->repeat(p_result, &frame->priority, request, state->uctx);
98 request->module = caller;
99
100 return ua;
101}
102
103/** Call a generic function
104 *
105 * @param[out] p_result The frame result.
106 * @param[in] request The current request.
107 * @param[in] frame The current frame.
108 */
110{
112 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
113 char const *caller;
114
115 /*
116 * Don't let the callback mess with the current
117 * module permanently.
118 */
119 caller = request->module;
120 request->module = NULL;
121
122 RDEBUG4("Calling function %p (%s)", state->func, state->func_name);
123 ua = state->func(p_result, &frame->priority, request, state->uctx);
124 switch (ua) {
126 break;
127
128 /*
129 * Similar functionality to the modcall code.
130 * If we have a repeat function set and the
131 * initial function is done, call the repeat
132 * function using the C stack.
133 */
135 if (state->repeat) unlang_function_call_repeat(p_result, request, frame);
136 break;
137
138 /*
139 * Function pushed more children or yielded
140 * setup our repeat function for when we
141 * eventually start heading back up the stack.
142 */
143 default:
145 }
146 request->module = caller;
147
148 return ua;
149}
150
151/** Clear pending repeat function calls, and remove the signal handler.
152 *
153 * The function frame being modified must be at the top of the stack.
154 *
155 * @param[in] request The current request.
156 * @return
157 * - 0 on success.
158 * - -1 on failure.
159 */
161{
162 unlang_stack_t *stack = request->stack;
163 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
165
166 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
167 RERROR("Can't clear function on non-function frame");
168 return -1;
169 }
170
171 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
172 state->repeat = NULL;
173 state->signal = NULL;
174
175 repeatable_clear(frame);
176
177 return 0;
178}
179
180/** Set a new signal function for an existing function frame
181 *
182 * @private
183 *
184 * The function frame being modified must be at the top of the stack.
185 *
186 * @param[in] request The current request.
187 * @param[in] signal The signal function to set.
188 * @param[in] sigmask Signals to block.
189 * @param[in] signal_name Name of the signal function call (for debugging).
190 * @return
191 * - 0 on success.
192 * - -1 on failure.
193 */
194int _unlang_function_signal_set(request_t *request, unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name)
195{
196 unlang_stack_t *stack = request->stack;
197 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
199
200 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
201 RERROR("Can't set repeat function on non-function frame");
202 return -1;
203 }
204
205 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
206
207 /*
208 * If we're inside unlang_function_call,
209 * it'll pickup state->repeat and do the right thing
210 * once the current function returns.
211 */
212 state->signal = signal;
213 state->sigmask = sigmask;
214 state->signal_name = signal_name;
215
216 return 0;
217}
218
219/** Set a new repeat function for an existing function frame
220 *
221 * @private
222 *
223 * The function frame being modified must be at the top of the stack.
224 *
225 * @param[in] request The current request.
226 * @param[in] repeat the repeat function to set.
227 * @param[in] repeat_name Name of the repeat function call (for debugging).
228 * @return
229 * - 0 on success.
230 * - -1 on failure.
231 */
232int _unlang_function_repeat_set(request_t *request, unlang_function_t repeat, char const *repeat_name)
233{
234 unlang_stack_t *stack = request->stack;
235 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
237
238 if (frame->instruction->type != UNLANG_TYPE_FUNCTION) {
239 RERROR("Can't set repeat function on non-function frame");
240 return -1;
241 }
242
243 state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
244
245 /*
246 * If we're inside unlang_function_call,
247 * it'll pickup state->repeat and do the right thing
248 * once the current function returns.
249 */
250 state->repeat = repeat;
251 state->repeat_name = repeat_name;
252 repeatable_set(frame);
253
254 return 0;
255}
256
257/** Push a generic function onto the unlang stack
258 *
259 * @private
260 *
261 * These can be pushed by any other type of unlang op to allow a submodule or function
262 * deeper in the C call stack to establish a new resumption point.
263 *
264 * @param[in] request The current request.
265 * @param[in] func to call going up the stack.
266 * @param[in] func_name Name of the function call (for debugging).
267 * @param[in] repeat function to call going back down the stack (may be NULL).
268 * This may be the same as func.
269 * @param[in] repeat_name Name of the repeat function call (for debugging).
270 * @param[in] signal function to call if the request is signalled.
271 * @param[in] sigmask Signals to block.
272 * @param[in] signal_name Name of the signal function call (for debugging).
273 * @param[in] top_frame Return out of the unlang interpreter when popping this frame.
274 * @param[in] uctx to pass to func(s).
275 * @return
276 * - UNLANG_ACTION_PUSHED_CHILD on success.
277 * - UNLANG_ACTION_FAIL on failure.
278 */
279unlang_action_t _unlang_function_push(request_t *request,
280 unlang_function_t func, char const *func_name,
281 unlang_function_t repeat, char const *repeat_name,
282 unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name,
283 bool top_frame, void *uctx)
284{
285 unlang_stack_t *stack = request->stack;
288
289 /*
290 * Push module's function
291 */
293 RLM_MODULE_NOOP, UNLANG_NEXT_STOP, top_frame) < 0) return UNLANG_ACTION_FAIL;
294
295 frame = &stack->frame[stack->depth];
296
297 /*
298 * Tell the interpreter to call unlang_function_call
299 * again when going back up the stack.
300 */
301 if (repeat) repeatable_set(frame);
302
303 /*
304 * Initialize state
305 */
306 state = frame->state;
307 state->func = func;
308 state->func_name = func_name;
309 state->repeat = repeat;
310 state->repeat_name = repeat_name;
311 state->signal = signal;
312 state->sigmask = sigmask;
313 state->signal_name = signal_name;
314 state->uctx = uctx;
315
316 /*
317 * Just skip to the repeat state directly
318 */
319 if (!func && repeat) frame->process = unlang_function_call_repeat;
320
322}
323
324/** Custom frame state dumper
325 *
326 */
328{
329 unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
330
331 RDEBUG2("frame state");
332 if (state->func) RDEBUG2("function %p (%s)", state->func, state->func_name);
333 if (state->repeat) RDEBUG2("repeat %p (%s)", state->repeat, state->repeat_name);
334 if (state->signal) RDEBUG2("signal %p (%s)", state->signal, state->signal_name);
335}
336
338{
340 &(unlang_op_t){
341 .name = "function",
342 .interpret = unlang_function_call,
343 .signal = unlang_function_signal,
344 .dump = unlang_function_dump,
345 .debug_braces = false,
346 .frame_state_size = sizeof(unlang_frame_state_func_t),
347 .frame_state_type = "unlang_frame_state_func_t",
348 });
349
350}
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: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
#define RCSID(id)
Definition build.h:483
static void unlang_function_dump(request_t *request, unlang_stack_frame_t *frame)
Custom frame state dumper.
Definition function.c:327
char const * repeat_name
Debug name for the repeat function.
Definition function.c:38
int unlang_function_clear(request_t *request)
Clear pending repeat function calls, and remove the signal handler.
Definition function.c:160
static unlang_t function_instruction
Static instruction for allowing modules/xlats to call functions within themselves,...
Definition function.c:48
unlang_function_t repeat
To call when going back up the stack.
Definition function.c:37
unlang_function_signal_t signal
Signal function to call.
Definition function.c:39
unlang_function_t func
To call when going down the stack.
Definition function.c:35
void * uctx
Uctx to pass to function.
Definition function.c:42
static unlang_action_t unlang_function_call_repeat(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition function.c:84
char const * func_name
Debug name for the function.
Definition function.c:36
fr_signal_t sigmask
Signals to block.
Definition function.c:40
void unlang_function_init(void)
Definition function.c:337
static void unlang_function_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Generic signal handler.
Definition function.c:74
char const * signal_name
Debug name for the signal function.
Definition function.c:41
static unlang_action_t unlang_function_call(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Call a generic function.
Definition function.c:109
Declarations for generic unlang functions.
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:59
unlang_action_t(* unlang_function_t)(rlm_rcode_t *p_result, int *priority, 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:49
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
#define RERROR(fmt,...)
Definition log.h:298
#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
#define RDEBUG2(fmt,...)
Definition radclient.h:54
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_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
static void repeatable_clear(unlang_stack_frame_t *frame)
void * state
Stack frame specialisations.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:92
int priority
Result priority.
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:47
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 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.
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.
#define RETRY_INIT
Definition retry.h:39