The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_chap.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 (at
5 * 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: 3e4fe31b7566a7822eaaf638a8629bdaf7dcd2e8 $
19 * @file rlm_chap.c
20 * @brief Process chap authentication requests.
21 *
22 * @copyright 2001,2006 The FreeRADIUS server project
23 */
24RCSID("$Id: 3e4fe31b7566a7822eaaf638a8629bdaf7dcd2e8 $")
25
26#define LOG_PREFIX mctx->mi->name
27
28#include <freeradius-devel/server/base.h>
29#include <freeradius-devel/server/module_rlm.h>
30#include <freeradius-devel/util/chap.h>
31#include <freeradius-devel/unlang/xlat_func.h>
32
37
38static const conf_parser_t module_config[] = {
39 { FR_CONF_OFFSET_TYPE_FLAGS("min_challenge_len", FR_TYPE_SIZE, 0, rlm_chap_t, min_challenge_len), .dflt = "16" },
41};
42
46
48 FR_CALL_ENV_METHOD_OUT(chap_xlat_call_env_t),
50 { FR_CALL_ENV_OFFSET("chap_challenge", FR_TYPE_OCTETS,
53 chap_challenge), .pair.dflt = "Chap-Challenge", .pair.dflt_quote = T_BARE_WORD },
55 }
56};
57
63
65 FR_CALL_ENV_METHOD_OUT(chap_autz_call_env_t),
67 { FR_CALL_ENV_OFFSET("chap_password", FR_TYPE_OCTETS,
69 chap_autz_call_env_t, chap_password),
70 .pair.dflt = "Chap-Password", .pair.dflt_quote = T_BARE_WORD },
71 { FR_CALL_ENV_PARSE_OFFSET("chap_challenge", FR_TYPE_OCTETS,
73 chap_autz_call_env_t, chap_challenge, chap_challenge_tmpl),
74 .pair.dflt = "Chap-Challenge", .pair.dflt_quote = T_BARE_WORD },
76 }
77};
78
84
86 FR_CALL_ENV_METHOD_OUT(chap_auth_call_env_t),
90 chap_auth_call_env_t, username),
91 .pair.dflt = "User-Name", .pair.dflt_quote = T_BARE_WORD },
92 { FR_CALL_ENV_OFFSET("chap_password", FR_TYPE_OCTETS,
94 chap_auth_call_env_t, chap_password),
95 .pair.dflt = "Chap-Password", .pair.dflt_quote = T_BARE_WORD },
96 { FR_CALL_ENV_OFFSET("chap_challenge", FR_TYPE_OCTETS,
98 chap_auth_call_env_t, chap_challenge),
99 .pair.dflt = "Chap-Challenge", .pair.dflt_quote = T_BARE_WORD },
101 }
102};
103
105
108 { .out = &dict_freeradius, .proto = "freeradius" },
110};
111
114
117 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
118 { .out = &attr_cleartext_password, .name = "Password.Cleartext", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
119
121};
122
124 { .required = true, .single = true, .type = FR_TYPE_STRING },
126};
127
128/** Produce a CHAP-Password hash value
129 *
130 * Example:
131@verbatim
132%chap.password(<password>) == 0x<id><md5_hash>
133@endverbatim
134 *
135 * @ingroup xlat_functions
136 */
138 xlat_ctx_t const *xctx,
139 request_t *request, fr_value_box_list_t *in)
140{
142 uint8_t chap_password[1 + FR_CHAP_CHALLENGE_LENGTH];
143 fr_value_box_t *vb;
144 uint8_t const *challenge;
145 size_t challenge_len;
146 fr_value_box_t *in_head = fr_value_box_list_head(in);
147 chap_xlat_call_env_t *env_data = talloc_get_type_abort(xctx->env_data, chap_xlat_call_env_t);
148
149 /*
150 * Use Chap-Challenge pair if present,
151 * Request Authenticator otherwise.
152 */
153 if ((env_data->chap_challenge.type == FR_TYPE_OCTETS) &&
154 (env_data->chap_challenge.vb_length >= inst->min_challenge_len)) {
155 challenge = env_data->chap_challenge.vb_octets;
156 challenge_len = env_data->chap_challenge.vb_length;
157 } else {
158 if (env_data->chap_challenge.type == FR_TYPE_OCTETS)
159 RWDEBUG("request.CHAP-Challenge shorter than minimum length (%ld)", inst->min_challenge_len);
160 challenge = request->packet->vector;
161 challenge_len = RADIUS_AUTH_VECTOR_LENGTH;
162 }
163 fr_chap_encode(chap_password, (uint8_t)(fr_rand() & 0xff), challenge, challenge_len,
164 in_head->vb_strvalue, in_head->vb_length);
165
166 MEM(vb = fr_value_box_alloc_null(ctx));
167 fr_value_box_memdup(vb, vb, NULL, chap_password, sizeof(chap_password), false);
169
170 return XLAT_ACTION_DONE;
171}
172
173static unlang_action_t CC_HINT(nonnull) mod_authorize(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
174{
175 fr_pair_t *vp;
177 chap_autz_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, chap_autz_call_env_t);
178
179 if (fr_pair_find_by_da(&request->control_pairs, NULL, attr_auth_type) != NULL) {
180 RDEBUG3("Auth-Type is already set. Not setting 'Auth-Type := %s'", mctx->mi->name);
182 }
183
184 /*
185 * This case means the warnings below won't be printed
186 * unless there's a CHAP-Password in the request.
187 */
188 if (env_data->chap_password.type != FR_TYPE_OCTETS) {
190 }
191
192 /*
193 * Create the CHAP-Challenge if it wasn't already in the packet.
194 *
195 * This is so that the rest of the code does not need to
196 * understand CHAP.
197 */
198 if (env_data->chap_challenge.type != FR_TYPE_OCTETS) {
199 RDEBUG2("Creating %s from request authenticator", env_data->chap_challenge_tmpl->name);
200
201 MEM(vp = fr_pair_afrom_da(request->request_ctx, tmpl_attr_tail_da(env_data->chap_challenge_tmpl)));
202 fr_pair_value_memdup(vp, request->packet->vector, sizeof(request->packet->vector), true);
203 fr_pair_append(&request->request_pairs, vp);
204 }
205
206 if (!inst->auth_type) {
207 WARN("No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup CHAP authentication",
208 mctx->mi->name, mctx->mi->name);
210 }
211
212 if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) {
214 }
215
217}
218
219/*
220 * Find the named user in this modules database. Create the set
221 * of attribute-value pairs to check and reply with for this user
222 * from the database. The authentication code only needs to check
223 * the password, the rest is done here.
224 */
225static unlang_action_t CC_HINT(nonnull) mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
226{
228 fr_pair_t *known_good;
229 uint8_t pass_str[1 + FR_CHAP_CHALLENGE_LENGTH];
230 chap_auth_call_env_t *env_data = talloc_get_type_abort(mctx->env_data, chap_auth_call_env_t);
231
232 int ret;
233
234 fr_dict_attr_t const *allowed_passwords[] = { attr_cleartext_password };
235 bool ephemeral;
236
237 uint8_t const *challenge;
238 size_t challenge_len;
239
240 if (env_data->username.type != FR_TYPE_STRING) {
241 REDEBUG("User-Name attribute is required for authentication");
243 }
244
245 if (env_data->chap_password.type != FR_TYPE_OCTETS) {
246 REDEBUG("You set 'control.Auth-Type = CHAP' for a request that "
247 "does not contain a CHAP-Password attribute!");
249 }
250
251 if (env_data->chap_password.vb_length == 0) {
252 REDEBUG("request.CHAP-Password is empty");
254 }
255
256 if (env_data->chap_password.vb_length != FR_CHAP_CHALLENGE_LENGTH + 1) {
257 REDEBUG("request.CHAP-Password has invalid length");
259 }
260
261 /*
262 * Retrieve the normalised version of
263 * the known_good password, without
264 * mangling the current password attributes
265 * in the request.
266 */
267 known_good = password_find(&ephemeral, request, request,
268 allowed_passwords, NUM_ELEMENTS(allowed_passwords),
269 false);
270 if (!known_good) {
271 REDEBUG("No \"known good\" password found for user");
273 }
274
275 /*
276 * Output is id + password hash
277 */
278
279 /*
280 * Use Chap-Challenge pair if present,
281 * Request Authenticator otherwise.
282 */
283 if ((env_data->chap_challenge.type == FR_TYPE_OCTETS) &&
284 (env_data->chap_challenge.vb_length >= inst->min_challenge_len)) {
285 challenge = env_data->chap_challenge.vb_octets;
286 challenge_len = env_data->chap_challenge.vb_length;
287 } else {
288 if (env_data->chap_challenge.type == FR_TYPE_OCTETS)
289 RWDEBUG("request.CHAP-Challenge shorter than minimum length (%ld)", inst->min_challenge_len);
290 challenge = request->packet->vector;
291 challenge_len = RADIUS_AUTH_VECTOR_LENGTH;
292 }
293 fr_chap_encode(pass_str, env_data->chap_password.vb_octets[0], challenge, challenge_len,
294 known_good->vp_strvalue, known_good->vp_length);
295
296 /*
297 * The password_find function already emits
298 * a log message about the password attribute contents
299 * so we don't need to duplicate it here.
300 */
301 if (RDEBUG_ENABLED3) {
302 uint8_t const *p;
303 size_t length;
304
305 if (env_data->chap_challenge.type == FR_TYPE_OCTETS) {
306 RDEBUG2("Using challenge from request.CHAP-Challenge");
307 p = env_data->chap_challenge.vb_octets;
308 length = env_data->chap_challenge.vb_length;
309 } else {
310 RDEBUG2("Using challenge from authenticator field");
311 p = request->packet->vector;
312 length = sizeof(request->packet->vector);
313 }
314
315 RINDENT();
316 RDEBUG3("CHAP challenge : %pH", fr_box_octets(p, length));
317 RDEBUG3("Client sent : %pH", fr_box_octets(env_data->chap_password.vb_octets + 1,
319 RDEBUG3("We calculated : %pH", fr_box_octets(pass_str + 1, FR_CHAP_CHALLENGE_LENGTH));
320 REXDENT();
321 }
322
323 /*
324 * Skip the id field at the beginning of the
325 * password and chap response.
326 */
327 ret = fr_digest_cmp(pass_str + 1, env_data->chap_password.vb_octets + 1, FR_CHAP_CHALLENGE_LENGTH);
328 if (ephemeral) TALLOC_FREE(known_good);
329 if (ret != 0) {
330 REDEBUG("Password comparison failed: password is incorrect");
331
333 }
334
335 RDEBUG2("CHAP user \"%pV\" authenticated successfully", &env_data->username);
336
338}
339
340/*
341 * Create instance for our module. Allocate space for
342 * instance structure and read configuration parameters
343 */
344static int mod_instantiate(module_inst_ctx_t const *mctx)
345{
346 rlm_chap_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_chap_t);
347
348 inst->auth_type = fr_dict_enum_by_name(attr_auth_type, mctx->mi->name, -1);
349 if (!inst->auth_type) {
350 WARN("Failed to find 'authenticate %s {...}' section. CHAP authentication will likely not work",
351 mctx->mi->name);
352 }
353
354 return 0;
355}
356
357static int mod_bootstrap(module_inst_ctx_t const *mctx)
358{
359 xlat_t *xlat;
360
361 if (unlikely((xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "password", xlat_func_chap_password,
362 FR_TYPE_OCTETS)) == NULL)) return -1;
365
366 return 0;
367}
368
369/*
370 * The module name should be the only globally exported symbol.
371 * That is, everything else should be 'static'.
372 *
373 * If the module needs to temporarily modify it's instantiation
374 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
375 * The server will then take care of ensuring that the module
376 * is single-threaded.
377 */
380 .common = {
381 .magic = MODULE_MAGIC_INIT,
382 .name = "chap",
383 .inst_size = sizeof(rlm_chap_t),
384 .bootstrap = mod_bootstrap,
386 .instantiate = mod_instantiate
387 },
388 .method_group = {
389 .bindings = (module_method_binding_t[]){
390 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &chap_auth_method_env },
391 { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize, .method_env = &chap_autz_method_env },
393 }
394 }
395};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:506
#define unlikely(_x)
Definition build.h:402
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#define FR_CALL_ENV_PARSE_OFFSET(_name, _cast_type, _flags, _struct, _field, _parse_field)
Specify a call_env_parser_t which writes out runtime results and the result of the parsing phase to t...
Definition call_env.h:365
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
Definition call_env.h:86
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition call_env.h:75
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition call_env.h:80
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
Definition call_env.h:340
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define CF_IDENT_ANY
Definition cf_util.h:75
void fr_chap_encode(uint8_t out[static 1+FR_CHAP_CHALLENGE_LENGTH], uint8_t id, uint8_t const *challenge, size_t challenge_len, char const *password, size_t password_len)
Encode a CHAP password.
Definition chap.c:34
#define FR_CHAP_CHALLENGE_LENGTH
Definition chap.h:33
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
#define MEM(x)
Definition debug.h:46
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3701
static fr_slen_t in
Definition dict.h:882
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Value of an enumerated attribute.
Definition dict.h:253
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t xlat_func_chap_password(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Produce a CHAP-Password hash value.
Definition rlm_chap.c:137
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define RWDEBUG(fmt,...)
Definition log.h:373
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:347
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
int fr_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
Do a comparison of two authentication digests by comparing the FULL data.
Definition misc.c:504
void * env_data
Per call environment data.
Definition module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:232
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
Definition module_rlm.c:403
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
#define RADIUS_AUTH_VECTOR_LENGTH
Definition net.h:89
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2962
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
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1352
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:290
fr_pair_t * password_find(bool *ephemeral, TALLOC_CTX *ctx, request_t *request, fr_dict_attr_t const *allowed_attrs[], size_t allowed_attrs_len, bool normify)
Find a "known good" password in the control list of a request.
Definition password.c:994
static const conf_parser_t config[]
Definition base.c:163
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define WARN(fmt,...)
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
#define RETURN_UNLANG_INVALID
Definition rcode.h:66
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_OK
Definition rcode.h:64
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
fr_dict_attr_autoload_t rlm_chap_dict_attr[]
Definition rlm_chap.c:116
static const call_env_method_t chap_autz_method_env
Definition rlm_chap.c:64
fr_value_box_t chap_password
Definition rlm_chap.c:81
static fr_dict_t const * dict_freeradius
Definition rlm_chap.c:104
fr_value_box_t chap_challenge
Definition rlm_chap.c:82
fr_dict_enum_value_t const * auth_type
Definition rlm_chap.c:34
size_t min_challenge_len
Definition rlm_chap.c:35
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_chap.c:357
fr_value_box_t chap_password
Definition rlm_chap.c:59
fr_dict_autoload_t rlm_chap_dict[]
Definition rlm_chap.c:107
static const call_env_method_t chap_auth_method_env
Definition rlm_chap.c:85
static fr_dict_attr_t const * attr_auth_type
Definition rlm_chap.c:112
static xlat_arg_parser_t const xlat_func_chap_password_args[]
Definition rlm_chap.c:123
static unlang_action_t mod_authorize(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_chap.c:173
static fr_dict_attr_t const * attr_cleartext_password
Definition rlm_chap.c:113
module_rlm_t rlm_chap
Definition rlm_chap.c:379
fr_value_box_t chap_challenge
Definition rlm_chap.c:44
static unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_chap.c:225
static const call_env_method_t chap_xlat_method_env
Definition rlm_chap.c:47
tmpl_t * chap_challenge_tmpl
Definition rlm_chap.c:61
static const conf_parser_t module_config[]
Definition rlm_chap.c:38
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_chap.c:344
fr_value_box_t username
Definition rlm_chap.c:80
fr_value_box_t chap_challenge
Definition rlm_chap.c:60
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
char const * name
Instance name e.g. user_database.
Definition module.h:357
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
void * boot
Data allocated during the boostrap phase.
Definition module.h:296
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:110
@ T_BARE_WORD
Definition token.h:118
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumed by an xlat function.
Definition xlat.h:145
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition value.c:5064
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:655
static size_t char ** out
Definition value.h:1030
#define fr_box_octets(_val, _len)
Definition value.h:311
void * env_data
Expanded call env data.
Definition xlat_ctx.h:53
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
void xlat_func_call_env_set(xlat_t *x, call_env_method_t const *env_method)
Register call environment of an xlat.
Definition xlat_func.c:389