The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 83074ae6c809e56f0aceae968a41aed0129e9fd5 $
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  */
25 RCSID("$Id: 83074ae6c809e56f0aceae968a41aed0129e9fd5 $")
26 
27 #include <freeradius-devel/server/state.h>
28 #include <freeradius-devel/server/pair.h>
29 
30 #include "call_priv.h"
31 #include "module_priv.h"
32 
34  unlang_stack_frame_t *frame)
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 
50 }
51 
53  unlang_stack_frame_t *frame)
54 {
56 
57  /*
58  * Push the contents of the call { } section onto the stack.
59  * This gets executed after the server returns.
60  */
61  return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
62 }
63 
64 
66  unlang_stack_frame_t *frame)
67 {
68  unlang_group_t *g;
69  unlang_call_t *gext;
70  fr_dict_enum_value_t const *type_enum;
71  fr_pair_t *packet_type_vp = NULL;
72 
73  /*
74  * Do not check for children here.
75  *
76  * Call shouldn't require children to execute as there
77  * can still be side effects from executing the virtual
78  * server.
79  */
81  gext = unlang_group_to_call(g);
82 
83  /*
84  * Work out the current request type.
85  */
86  type_enum = fr_dict_enum_by_value(gext->attr_packet_type, fr_box_uint32(request->packet->code));
87  if (!type_enum) {
88  packet_type_vp = fr_pair_find_by_da(&request->request_pairs, NULL, gext->attr_packet_type);
89  if (!packet_type_vp) {
90  bad_packet_type:
91  REDEBUG("No such value '%d' of attribute 'Packet-Type' for server %s",
92  request->packet->code, cf_section_name2(gext->server_cs));
93  error:
94  *p_result = RLM_MODULE_FAIL;
96  }
97  type_enum = fr_dict_enum_by_value(packet_type_vp->da, &packet_type_vp->data);
98  if (!type_enum) goto bad_packet_type;
99 
100  /*
101  * Sync up packet->code
102  */
103  request->packet->code = packet_type_vp->vp_uint32;
104  }
105 
106  /*
107  * Sync up packet codes and attributes
108  *
109  * Fixme - packet->code needs to die...
110  */
111  if (!packet_type_vp) switch (pair_update_request(&packet_type_vp, gext->attr_packet_type)) {
112  case 0:
113  packet_type_vp->vp_uint32 = request->packet->code;
114  break;
115 
116  case 1:
117  request->packet->code = packet_type_vp->vp_uint32;
118  break;
119 
120  default:
121  goto error;
122  }
123 
124  /*
125  * Need to add reply.Packet-Type if it
126  * wasn't set by the virtual server...
127  *
128  * AGAIN packet->code NEEDS TO DIE.
129  * DIE DIE DIE DIE DIE DIE DIE DIE DIE
130  * DIE DIE DIE DIE DIE DIE DIE DIE DIE.
131  */
132  if (!g->children) {
134  } else {
136  }
137 
138  if (virtual_server_push(request, gext->server_cs, UNLANG_SUB_FRAME) < 0) goto error;
139 
141 }
142 
143 /** Push a call frame onto the stack
144  *
145  * This should be used instead of virtual_server_push in the majority of the code
146  */
147 unlang_action_t unlang_call_push(request_t *request, CONF_SECTION *server_cs, bool top_frame)
148 {
149  unlang_stack_t *stack = request->stack;
150  unlang_call_t *c;
151  char const *name;
152  fr_dict_t const *dict;
154 
155  /*
156  * Temporary hack until packet->code is removed
157  */
158  dict = virtual_server_dict_by_cs(server_cs);
159  if (!dict) {
160  REDEBUG("Virtual server \"%s\" not compiled", cf_section_name2(server_cs));
161  return UNLANG_ACTION_FAIL;
162  }
163 
164  attr_packet_type = fr_dict_attr_by_name(NULL, fr_dict_root(dict), "Packet-Type");
165  if (!attr_packet_type) {
166  REDEBUG("No Packet-Type attribute available");
167  return UNLANG_ACTION_FAIL;
168  }
169 
170  /*
171  * We need to have a unlang_module_t to push on the
172  * stack. The only sane way to do it is to attach it to
173  * the frame state.
174  */
175  name = cf_section_name2(server_cs);
176  MEM(c = talloc(stack, unlang_call_t)); /* Free at the same time as the state */
177  *c = (unlang_call_t){
178  .group = {
179  .self = {
181  .name = name,
182  .debug_name = name,
183  .ci = CF_TO_ITEM(server_cs),
184  .actions = {
185  .actions = {
186  [RLM_MODULE_REJECT] = 0,
187  [RLM_MODULE_FAIL] = MOD_ACTION_RETURN, /* Exit out of nested levels */
188  [RLM_MODULE_OK] = 0,
189  [RLM_MODULE_HANDLED] = 0,
190  [RLM_MODULE_INVALID] = 0,
191  [RLM_MODULE_DISALLOW] = 0,
192  [RLM_MODULE_NOTFOUND] = 0,
193  [RLM_MODULE_NOOP] = 0,
194  [RLM_MODULE_UPDATED] = 0
195  },
196  .retry = RETRY_INIT,
197  },
198  },
199 
200  .cs = server_cs,
201  },
202  .server_cs = server_cs,
203  .attr_packet_type = attr_packet_type
204  };
205 
206  /*
207  * Push a new call frame onto the stack
208  */
210  RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, top_frame) < 0) {
211  talloc_free(c);
212  return UNLANG_ACTION_FAIL;
213  }
214 
216 }
217 
218 /** Return the last virtual server that was called
219  *
220  * @param[in] request To return virtual server for.
221  * @return
222  * - A virtual server CONF_SECTION on success.
223  * - NULL on failure.
224  */
226 {
227  unlang_stack_t *stack = request->stack;
228  unsigned int depth;
229 
230  /*
231  * Work back from the deepest frame
232  * looking for modules.
233  */
234  for (depth = stack_depth_current(request); depth > 0; depth--) {
235  unlang_stack_frame_t *frame = &stack->frame[depth];
236 
237  /*
238  * Look at the module frames,
239  * trying to find one that represents
240  * a process state machine.
241  */
242  if (frame->instruction->type != UNLANG_TYPE_CALL) continue;
243 
245  }
246  return NULL;
247 }
248 
250 {
252  &(unlang_op_t){
253  .name = "call",
254  .interpret = unlang_call_frame_init,
255  .debug_braces = true,
256  });
257 }
258 
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
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
static unlang_action_t unlang_call_children(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: call.c:52
void unlang_call_init(void)
Definition: call.c:249
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition: call.c:225
unlang_action_t unlang_call_push(request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a call frame onto the stack.
Definition: call.c:147
static unlang_action_t unlang_call_frame_init(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: call.c:65
static unlang_action_t unlang_call_finalize(UNUSED rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition: call.c:33
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
CONF_SECTION * server_cs
Config section of the virtual server being executed.
Definition: call_priv.h:39
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
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
Entry point into a proto_ module.
Definition: call_priv.h:36
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1126
#define CF_TO_ITEM(_cf)
Auto cast from the input type to CONF_ITEM (which is the base type)
Definition: cf_util.h:65
static fr_dict_attr_t const * attr_packet_type
Definition: dhcpclient.c:89
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition: dict_util.c:2860
fr_dict_enum_value_t * 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:2946
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
Value of an enumerated attribute.
Definition: dict.h:209
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
unlang_action_t unlang_interpret_push_children(rlm_rcode_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:243
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition: base.c:65
talloc_free(reap)
static char * stack[MAX_STACK]
Definition: radmin.c:158
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
Declarations for the unlang module interface.
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:688
#define pair_update_request(_attr, _da)
Definition: radclient-ng.c:60
#define REDEBUG(fmt,...)
Definition: radclient.h:52
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_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition: rcode.h:51
@ 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
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
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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 UNLANG_NEXT_SIBLING
Definition: unlang_priv.h:103
#define UNLANG_NEXT_STOP
Definition: unlang_priv.h:102
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
Definition: unlang_priv.h:539
#define MOD_ACTION_RETURN
Definition: unlang_priv.h:44
static int stack_depth_current(request_t *request)
Definition: unlang_priv.h:401
@ UNLANG_TYPE_CALL
call another virtual server
Definition: unlang_priv.h:76
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
unlang_t self
Definition: unlang_priv.h:156
rlm_rcode_t result
The result from executing the instruction.
Definition: unlang_priv.h:308
unlang_type_t type
The specialisation of this node.
Definition: unlang_priv.h:127
unlang_t * children
Children beneath this group.
Definition: unlang_priv.h:157
Generic representation of a grouping.
Definition: unlang_priv.h:155
An unlang operation.
Definition: unlang_priv.h:214
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
#define fr_box_uint32(_val)
Definition: value.h:305
unlang_action_t virtual_server_push(request_t *request, CONF_SECTION *server_cs, bool top_frame)
Set the request processing function.
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.