The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
26 RCSID("$Id: 4477a947db040f398f29b21d866e4493e7dfbbbd $")
27 
28 #include "unlang_priv.h"
29 #include "function.h"
30 
31 /*
32  * Some functions differ mainly in their parsing
33  */
34 typedef 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 = {
54  [RLM_MODULE_REJECT] = 0,
55  [RLM_MODULE_FAIL] = 0,
56  [RLM_MODULE_OK] = 0,
57  [RLM_MODULE_HANDLED] = 0,
58  [RLM_MODULE_INVALID] = 0,
59  [RLM_MODULE_DISALLOW] = 0,
60  [RLM_MODULE_NOTFOUND] = 0,
61  [RLM_MODULE_NOOP] = 0,
62  [RLM_MODULE_UPDATED] = 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  */
74 static 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 {
86  unlang_action_t ua;
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 {
111  unlang_action_t ua;
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:
144  if (state->repeat) frame_repeat(frame, unlang_function_call_repeat);
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  */
194 int _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  */
232 int _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  */
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;
286  unlang_stack_frame_t *frame;
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:444
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_function_signal_set(request_t *request, unlang_function_signal_t signal, fr_signal_t sigmask, char const *name)
Set a new signal function for an existing function frame.
Definition: function.c:194
int _unlang_function_repeat_set(request_t *request, unlang_function_t repeat, char const *name)
Set a new repeat function for an existing function frame.
Definition: function.c:232
unlang_action_t _unlang_function_push(request_t *request, unlang_function_t func, char const *func_name, unlang_function_t repeat, char const *repeat_name, unlang_function_signal_t signal, fr_signal_t sigmask, char const *signal_name, bool top_frame, void *uctx)
Push a generic function onto the unlang stack.
Definition: function.c:279
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:65
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
Definition: signal.h:48
static void repeatable_clear(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:359
void * state
Stack frame specialisations.
Definition: unlang_priv.h:304
#define UNLANG_NEXT_STOP
Definition: unlang_priv.h:102
int priority
Result priority.
Definition: unlang_priv.h:309
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition: unlang_priv.h:57
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.
Definition: unlang_priv.h:526
unlang_t const * instruction
The unlang node we're evaluating.
Definition: unlang_priv.h:289
static void repeatable_set(unlang_stack_frame_t *frame)
Definition: unlang_priv.h:353
unlang_process_t process
function to call for interpreting this stack frame
Definition: unlang_priv.h:292
unlang_type_t type
The specialisation of this node.
Definition: unlang_priv.h:127
An unlang operation.
Definition: unlang_priv.h:214
A node in a graph of unlang_op_t (s) that we execute.
Definition: unlang_priv.h:122
Our interpreter stack, as distinct from the C stack.
Definition: unlang_priv.h:288
An unlang stack associated with a request.
Definition: unlang_priv.h:322
#define RETRY_INIT
Definition: retry.h:39