The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 4a6575b4873e04926b487722a2972aa565270d83 $
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: 4a6575b4873e04926b487722a2972aa565270d83 $")
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
40 switch (pair_update_reply(&packet_type_vp, gext->attr_packet_type)) {
41 case 0:
42 packet_type_vp->vp_uint32 = request->reply->code;
43 break;
44
45 case 1:
46 break; /* Don't change */
47
48 default:
50 }
51
53}
54
57{
59
60 /*
61 * Push the contents of the call { } section onto the stack.
62 * This gets executed after the server returns.
63 */
65}
66
67
70{
72 unlang_call_t *gext;
73 fr_dict_enum_value_t const *type_enum;
74 fr_pair_t *packet_type_vp = NULL;
75
76 /*
77 * Do not check for children here.
78 *
79 * Call shouldn't require children to execute as there
80 * can still be side effects from executing the virtual
81 * server.
82 */
84 gext = unlang_group_to_call(g);
85
86 /*
87 * Work out the current request type.
88 */
89 type_enum = fr_dict_enum_by_value(gext->attr_packet_type, fr_box_uint32(request->packet->code));
90 if (!type_enum) {
91 packet_type_vp = fr_pair_find_by_da(&request->request_pairs, NULL, gext->attr_packet_type);
92 if (!packet_type_vp) {
93 bad_packet_type:
94 REDEBUG("No such value '%u' of attribute 'Packet-Type' for server %s",
95 request->packet->code, cf_section_name2(gext->server_cs));
96 error:
98 }
99 type_enum = fr_dict_enum_by_value(packet_type_vp->da, &packet_type_vp->data);
100 if (!type_enum) goto bad_packet_type;
101
102 /*
103 * Sync up packet->code
104 */
105 request->packet->code = packet_type_vp->vp_uint32;
106 }
107
108 /*
109 * Sync up packet codes and attributes
110 *
111 * Fixme - packet->code needs to die...
112 */
113 if (!packet_type_vp) switch (pair_update_request(&packet_type_vp, gext->attr_packet_type)) {
114 case 0:
115 packet_type_vp->vp_uint32 = request->packet->code;
116 break;
117
118 case 1:
119 request->packet->code = packet_type_vp->vp_uint32;
120 break;
121
122 default:
123 goto error;
124 }
125
126 /*
127 * Need to add reply.Packet-Type if it
128 * wasn't set by the virtual server...
129 *
130 * AGAIN packet->code NEEDS TO DIE.
131 * DIE DIE DIE DIE DIE DIE DIE DIE DIE
132 * DIE DIE DIE DIE DIE DIE DIE DIE DIE
133 * DIE DIE DIE.
134 */
135 if (unlang_list_empty(&g->children)) {
137 } else {
139 }
140
141 if (virtual_server_push(NULL, request, virtual_server_from_cs(gext->server_cs), UNLANG_SUB_FRAME) < 0) goto error;
142
144}
145
146/** Push a call frame onto the stack
147 *
148 * This should be used instead of virtual_server_push in the majority of the code
149 */
150unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
151{
152 unlang_stack_t *stack = request->stack;
153 unlang_call_t *c;
154 char const *name;
155 fr_dict_t const *dict;
157
158 /*
159 * Temporary hack until packet->code is removed
160 */
161 dict = virtual_server_dict_by_cs(server_cs);
162 if (!dict) {
163 REDEBUG("Virtual server \"%s\" not compiled", cf_section_name2(server_cs));
164 return UNLANG_ACTION_FAIL;
165 }
166
168 if (!attr_packet_type) {
169 REDEBUG("No Packet-Type attribute available");
170 return UNLANG_ACTION_FAIL;
171 }
172
173 /*
174 * We need to have a unlang_module_t to push on the
175 * stack. The only sane way to do it is to attach it to
176 * the frame state.
177 */
178 name = cf_section_name2(server_cs);
179 MEM(c = talloc(stack, unlang_call_t)); /* Free at the same time as the state */
180 *c = (unlang_call_t){
181 .group = {
182 .self = {
184 .name = name,
185 .debug_name = name,
186 .ci = CF_TO_ITEM(server_cs),
188 },
189
190 .cs = server_cs,
191 },
192 .server_cs = server_cs,
193 .attr_packet_type = attr_packet_type
194 };
195
197
198 /*
199 * Push a new call frame onto the stack
200 */
201 if (unlang_interpret_push(p_result, request, unlang_call_to_generic(c),
203 talloc_free(c);
204 return UNLANG_ACTION_FAIL;
205 }
206
208}
209
210/** Return the last virtual server that was called
211 *
212 * @param[in] request To return virtual server for.
213 * @return
214 * - A virtual server CONF_SECTION on success.
215 * - NULL on failure.
216 */
218{
219 unlang_stack_t *stack = request->stack;
220 unsigned int depth;
221
222 /*
223 * Work back from the deepest frame
224 * looking for modules.
225 */
226 for (depth = stack_depth_current(request); depth > 0; depth--) {
227 unlang_stack_frame_t *frame = &stack->frame[depth];
228
229 /*
230 * Look at the module frames,
231 * trying to find one that represents
232 * a process state machine.
233 */
234 if (frame->instruction->type != UNLANG_TYPE_CALL) continue;
235
237 }
238 return NULL;
239}
240
242{
244 virtual_server_t const *vs;
245 unlang_t *c;
246
248 unlang_call_t *gext;
249
251 char const *server;
252 CONF_SECTION *server_cs;
253 fr_dict_t const *dict;
255
256 server = cf_section_name2(cs);
257 if (!server) {
258 cf_log_err(cs, "You MUST specify a server name for 'call <server> { ... }'");
259 print_url:
260 cf_log_err(ci, DOC_KEYWORD_REF(call));
261 return NULL;
262 }
263
265 if (type != T_BARE_WORD) {
266 cf_log_err(cs, "The arguments to 'call' cannot be a quoted string or a dynamic value");
267 goto print_url;
268 }
269
270 vs = virtual_server_find(server);
271 if (!vs) {
272 cf_log_err(cs, "Unknown virtual server '%s'", server);
273 return NULL;
274 }
275
276 server_cs = virtual_server_cs(vs);
277
278 /*
279 * The dictionaries are not compatible, forbid it.
280 */
282 if (!dict) {
283 cf_log_err(cs, "Cannot call virtual server '%s', failed retrieving its namespace",
284 server);
285 return NULL;
286 }
287 if ((dict != fr_dict_internal()) && fr_dict_internal() &&
288 unlang_ctx->rules->attr.dict_def && !fr_dict_compatible(unlang_ctx->rules->attr.dict_def, dict)) {
289 cf_log_err(cs, "Cannot call server %s with namespace '%s' from namespaces '%s' - they have incompatible protocols",
290 server, fr_dict_root(dict)->name, fr_dict_root(unlang_ctx->rules->attr.dict_def)->name);
291 return NULL;
292 }
293
295 if (!attr_packet_type) {
296 cf_log_err(cs, "Cannot call server %s with namespace '%s' - it has no Packet-Type attribute",
297 server, fr_dict_root(dict)->name);
298 return NULL;
299 }
300
302 if (!c) return NULL;
303
304 /*
305 * Set the virtual server name, which tells unlang_call()
306 * which virtual server to call.
307 */
309 gext = unlang_group_to_call(g);
310 gext->server_cs = server_cs;
312
313 return c;
314}
315
317{
319 .name = "call",
321 .type = UNLANG_TYPE_CALL,
322
323 .compile = unlang_compile_call,
324 .interpret = unlang_call_frame_init,
325
326 .unlang_size = sizeof(unlang_call_t),
327 .unlang_name = "unlang_call_t",
328 });
329}
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:55
static unlang_t * unlang_compile_call(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition call.c:241
void unlang_call_init(void)
Definition call.c:316
unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a call frame onto the stack.
Definition call.c:150
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:217
static unlang_action_t unlang_call_frame_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition call.c:68
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:64
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:48
Entry point into a proto_ module.
Definition call_priv.h:36
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:1352
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:1397
#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:1519
#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:616
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:720
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:157
#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 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
enum fr_token fr_token_t
@ T_BARE_WORD
Definition token.h:118
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:99
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:98
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.
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_t const * virtual_server_dict_by_cs(CONF_SECTION const *server_cs)
Return the namespace for the virtual server specified by a config section.
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.