The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
call.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: 33257708ce45d13dbfe417ce8a9c6dd7f4660d41 $
19 *
20 * @file unlang/call.c
21 * @brief Unlang "call" keyword evaluation. Used for calling virtual servers.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: 33257708ce45d13dbfe417ce8a9c6dd7f4660d41 $")
26
27#include <freeradius-devel/server/rcode.h>
28#include <freeradius-devel/server/state.h>
29#include <freeradius-devel/server/pair.h>
30
31#include "call_priv.h"
32
35{
38 fr_pair_t *packet_type_vp = NULL;
39 unlang_frame_state_call_t *state = frame->state;
40
41 switch (pair_update_reply(&packet_type_vp, gext->attr_packet_type)) {
42 case 0:
43 packet_type_vp->vp_uint32 = request->reply->code;
44 break;
45
46 case 1:
47 break; /* Don't change */
48
49 default:
50 request->module = state->module;
52 }
53
54 request->module = state->module;
55
57}
58
61{
63
64 /*
65 * Push the contents of the call { } section onto the stack.
66 * This gets executed after the server returns.
67 */
69}
70
71
74{
76 unlang_call_t *gext;
77 fr_dict_enum_value_t const *type_enum;
78 fr_pair_t *packet_type_vp = NULL;
79 unlang_stack_t *stack = request->stack;
80
81 /*
82 * Do not check for children here.
83 *
84 * Call shouldn't require children to execute as there
85 * can still be side effects from executing the virtual
86 * server.
87 */
89 gext = unlang_group_to_call(g);
90
91 /*
92 * Work out the current request type.
93 */
94 type_enum = fr_dict_enum_by_value(gext->attr_packet_type, fr_box_uint32(request->packet->code));
95 if (!type_enum) {
96 packet_type_vp = fr_pair_find_by_da(&request->request_pairs, NULL, gext->attr_packet_type);
97 if (!packet_type_vp) {
98 bad_packet_type:
99 REDEBUG("No such value '%u' of attribute 'Packet-Type' for server %s",
100 request->packet->code, cf_section_name2(gext->server_cs));
101 error:
103 }
104 type_enum = fr_dict_enum_by_value(packet_type_vp->da, &packet_type_vp->data);
105 if (!type_enum) goto bad_packet_type;
106
107 /*
108 * Sync up packet->code
109 */
110 request->packet->code = packet_type_vp->vp_uint32;
111 }
112
113 /*
114 * Sync up packet codes and attributes
115 *
116 * Fixme - packet->code needs to die...
117 */
118 if (!packet_type_vp) switch (pair_update_request(&packet_type_vp, gext->attr_packet_type)) {
119 case 0:
120 packet_type_vp->vp_uint32 = request->packet->code;
121 break;
122
123 case 1:
124 request->packet->code = packet_type_vp->vp_uint32;
125 break;
126
127 default:
128 goto error;
129 }
130
131 /*
132 * Need to add reply.Packet-Type if it
133 * wasn't set by the virtual server...
134 *
135 * AGAIN packet->code NEEDS TO DIE.
136 * DIE DIE DIE DIE DIE DIE DIE DIE DIE
137 * DIE DIE DIE DIE DIE DIE DIE DIE DIE
138 * DIE DIE DIE.
139 */
140 if (unlang_list_empty(&g->children)) {
142 } else {
144 }
145 frame->prev.frame_call = stack->depth;
146
147 if (virtual_server_push(NULL, request, virtual_server_from_cs(gext->server_cs), UNLANG_SUB_FRAME) < 0) goto error;
148
150}
151
152/** Push a virtual server #CONF_SECTION as a call frame onto the stack
153 *
154 * This should be used instead of virtual_server_push in the majority of the code
155 */
156unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
157{
158 unlang_stack_t *stack = request->stack;
159 unlang_call_t *c;
160 char const *name;
161 fr_dict_t const *dict;
165
166 /*
167 * Temporary hack until packet->code is removed
168 */
169 dict = virtual_server_dict_by_cs(server_cs);
170 if (!dict) {
171 REDEBUG("Virtual server \"%s\" not compiled", cf_section_name2(server_cs));
172 return UNLANG_ACTION_FAIL;
173 }
174
176 if (!attr_packet_type) {
177 REDEBUG("No Packet-Type attribute available");
178 return UNLANG_ACTION_FAIL;
179 }
180
181 /*
182 * We need to have a unlang_module_t to push on the
183 * stack. The only sane way to do it is to attach it to
184 * the frame state.
185 */
186 name = talloc_asprintf(request, "server %s", cf_section_name2(server_cs));
187 MEM(c = talloc(stack, unlang_call_t)); /* Free at the same time as the state */
188 *c = (unlang_call_t){
189 .group = {
190 .self = {
192 .name = name,
193 .debug_name = name,
194 .ci = CF_TO_ITEM(server_cs),
196 .add_filename = true,
197 },
198
199 .cs = server_cs,
200 },
201 .server_cs = server_cs,
202 .attr_packet_type = attr_packet_type
203 };
204
206
207 /*
208 * Push a new call frame onto the stack
209 */
210 if (unlang_interpret_push(p_result, request, unlang_call_to_generic(c),
212 talloc_free(c);
213 return UNLANG_ACTION_FAIL;
214 }
215
216 frame = &stack->frame[stack->depth];
217 state = frame->state;
218 state->module = request->module;
219 request->module = NULL;
220
222}
223
224/** Return the last virtual server that was called
225 *
226 * @param[in] request To return virtual server for.
227 * @return
228 * - A virtual server CONF_SECTION on success.
229 * - NULL on failure.
230 */
232{
233 unlang_stack_t *stack = request->stack;
235
236#ifndef NDEBUG
237 unsigned int depth;
238
239 /*
240 * Work back from the deepest frame
241 * looking for modules.
242 */
243 for (depth = stack_depth_current(request); depth > 0; depth--) {
244 frame = &stack->frame[depth];
245
246 /*
247 * Look at the module frames,
248 * trying to find one that represents
249 * a process state machine.
250 */
251 if (frame->instruction->type != UNLANG_TYPE_CALL) continue;
252
253 fr_assert(stack->frame[stack->depth].prev.frame_call == depth);
254
256 }
257
258 return NULL;
259#else
260 frame = &stack->frame[stack->depth];
261 if (!frame->prev.frame_call) return NULL;
262
263 frame = &stack->frame[frame->prev.frame_call];
265#endif
266}
267
269{
271 virtual_server_t const *vs;
272 unlang_t *c;
273
275 unlang_call_t *gext;
276
278 char const *server;
279 CONF_SECTION *server_cs;
280 fr_dict_t const *dict;
282
283 server = cf_section_name2(cs);
284 if (!server) {
285 cf_log_err(cs, "You MUST specify a server name for 'call <server> { ... }'");
286 print_url:
287 cf_log_err(ci, DOC_KEYWORD_REF(call));
288 return NULL;
289 }
290
292 if (type != T_BARE_WORD) {
293 cf_log_err(cs, "The arguments to 'call' cannot be a quoted string or a dynamic value");
294 goto print_url;
295 }
296
297 vs = virtual_server_find(server);
298 if (!vs) {
299 cf_log_err(cs, "Unknown virtual server '%s'", server);
300 return NULL;
301 }
302
303 server_cs = virtual_server_cs(vs);
304
305 /*
306 * The dictionaries are not compatible, forbid it.
307 */
309 if (!dict) {
310 cf_log_err(cs, "Cannot call virtual server '%s', failed retrieving its namespace",
311 server);
312 return NULL;
313 }
314 if ((dict != fr_dict_internal()) && fr_dict_internal() &&
315 unlang_ctx->rules->attr.dict_def && !fr_dict_compatible(unlang_ctx->rules->attr.dict_def, dict)) {
316 cf_log_err(cs, "Cannot call server %s with namespace '%s' from namespaces '%s' - they have incompatible protocols",
317 server, fr_dict_root(dict)->name, fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
318 return NULL;
319 }
320
322 if (!attr_packet_type) {
323 cf_log_err(cs, "Cannot call server %s with namespace '%s' - it has no Packet-Type attribute",
324 server, fr_dict_root(dict)->name);
325 return NULL;
326 }
327
329 if (!c) return NULL;
330
331 /*
332 * Set the virtual server name, which tells unlang_call()
333 * which virtual server to call.
334 */
336 gext = unlang_group_to_call(g);
337 gext->server_cs = server_cs;
339
340 return c;
341}
342
344{
346 .name = "call",
348 .type = UNLANG_TYPE_CALL,
349
350 .compile = unlang_compile_call,
351 .interpret = unlang_call_frame_init,
352
353 .unlang_size = sizeof(unlang_call_t),
354 .unlang_name = "unlang_call_t",
355
356 .frame_state_size = sizeof(unlang_frame_state_call_t),
357 .frame_state_type = "unlang_frame_state_call_t",
358 });
359}
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:512
#define UNUSED
Definition build.h:336
static unlang_action_t unlang_call_children(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition call.c:59
static unlang_t * unlang_compile_call(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition call.c:268
void unlang_call_init(void)
Definition call.c:343
unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a virtual server CONF_SECTION as a call frame onto the stack.
Definition call.c:156
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:231
static unlang_action_t unlang_call_frame_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition call.c:72
static unlang_action_t unlang_call_resume(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition call.c:33
static unlang_t * unlang_call_to_generic(unlang_call_t *call)
Cast a call keyword extension to a unlang_t structure.
Definition call_priv.h:73
CONF_SECTION * server_cs
Config section of the virtual server being executed.
Definition call_priv.h:39
fr_dict_attr_t const * attr_packet_type
Attribute used to specify packet type and sections run in the server_cs.
Definition call_priv.h:41
unlang_group_t group
Generic field common to all group type unlang_t nodes.
Definition call_priv.h:37
static unlang_call_t * unlang_group_to_call(unlang_group_t *g)
Cast a group structure to the call keyword extension.
Definition call_priv.h:57
Entry point into a proto_ module.
Definition call_priv.h:36
A module stack entry.
Definition call_priv.h:49
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1359
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:692
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1404
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:345
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
Definition cf_util.h:65
fr_dict_t * dict
Definition common.c:31
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1518
#define MEM(x)
Definition debug.h:36
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:88
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2861
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2639
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition dict_util.c:3632
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4905
Value of an enumerated attribute.
Definition dict.h:253
talloc_free(hp)
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:621
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
Definition interpret.c:725
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:158
#define UNLANG_SUB_FRAME
Definition interpret.h:37
static TALLOC_CTX * unlang_ctx
Definition base.c:71
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:158
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
#define MOD_ACTIONS_FAIL_TIMEOUT_RETURN
Definition mod_action.h:74
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:707
#define fr_assert(_expr)
Definition rad_assert.h:37
#define pair_update_request(_attr, _da)
#define REDEBUG(fmt,...)
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:45
static char const * name
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
fr_aka_sim_id_type_t type
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define talloc_asprintf
Definition talloc.h:151
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:118
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:99
void * state
Stack frame specialisations.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:98
struct unlang_stack_frame_s::@106 prev
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
unlang_list_t children
static int stack_depth_current(request_t *request)
@ UNLANG_TYPE_CALL
call another virtual server
Definition unlang_priv.h:71
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 unlang_group_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
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.
static fr_slen_t parent
Definition pair.h:858
#define DOC_KEYWORD_REF(_x)
Definition version.h:89
#define fr_box_uint32(_val)
Definition value.h:335
virtual_server_t const * virtual_server_from_cs(CONF_SECTION const *server_cs)
Resolve a CONF_SECTION to a virtual server.
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
unlang_action_t virtual_server_push(unlang_result_t *p_result, request_t *request, virtual_server_t const *vs, bool top_frame)
Set the request processing function.
fr_dict_t const * virtual_server_dict_by_cs(CONF_SECTION const *cs)
Return the namespace for specified CONF_SECTION.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
fr_dict_attr_t const * virtual_server_packet_type_by_cs(CONF_SECTION const *server_cs)
Return the packet type attribute for a virtual server specified by a config section.