25RCSID(
"$Id: 8d78fcca17dd0175a09908ad69825f6f9d7a72ed $")
27#define LOG_PREFIX "perl"
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/module_rlm.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/unlang/xlat_func.h>
33#include <freeradius-devel/unlang/xlat.h>
34#include <freeradius-devel/radius/radius.h>
49#if defined(__APPLE__) || defined(__FreeBSD__)
54# error perl must be compiled with USE_ITHREADS
134 ret = strcmp(a->
name1, b->name1);
135 if (ret != 0)
return CMP(ret, 0);
136 if (!a->
name2 && !b->name2)
return 0;
137 if (!a->
name2 || !b->name2)
return a->
name2 ? 1 : -1;
138 ret = strcmp(a->
name2, b->name2);
149# define dl_librefs "DynaLoader::dl_librefs"
150# define dl_modules "DynaLoader::dl_modules"
166 if (!librefs)
return NULL;
168 if (!(AvFILL(librefs) >= 0)) {
172 MEM(handles = talloc_array(NULL,
void *, AvFILL(librefs) + 2));
173 for (i = 0; i <= AvFILL(librefs); i++) {
175 SV *handle_sv = *av_fetch(librefs, i,
false);
180 handle = (
void *)SvIV(handle_sv);
182 if (handle) handles[i] = handle;
188 handles[i] = (
void *)0;
201 for (i = 0; handles[i]; i++) {
202 DEBUG(
"Close %p", handles[i]);
214static XS(XS_radiusd_log)
218 croak(
"Usage: radiusd::log(level, message)");
223 level = (int) SvIV(ST(0));
224 msg = (
char *) SvPV(ST(1), PL_na);
242static XS(XS_radiusd_xlat)
250 if (items != 1) croak(
"Usage: radiusd::xlat(string)");
254 in_str = (
char *) SvPV(ST(0), PL_na);
256 slen =
xlat_aeval(request, &expanded, request, in_str, NULL, NULL);
258 REDEBUG(
"Error parsing xlat '%s'", in_str);
262 XST_mPV(0, expanded);
269 char const *
file = __FILE__;
274 newXS(
"radiusd::log",XS_radiusd_log,
"rlm_perl");
275 newXS(
"radiusd::xlat",XS_radiusd_xlat,
"rlm_perl");
293 while ((vb = fr_value_box_list_next(
head, vb))) {
296 sv = newSVpvn(vb->vb_strvalue, vb->vb_length);
300 sv = newSVpvn((
char const *)vb->vb_octets, vb->vb_length);
308 sv = newRV_inc((SV *)sub_av);
317 if (slen < 0)
return -1;
318 sv = newSVpvn(
buffer, (
size_t)slen);
323 if (vb->tainted) SvTAINT(sv);
364 vb->vb_int32 = SvIV(sv);
371 vb->vb_float64 = SvNV(sv);
377 tmp = SvPVutf8(sv, len);
381 RPEDEBUG(
"Failed to allocate %ld for output", len);
393 for (i = 0; i <= sv_len; i++) {
394 av_sv = av_fetch(av, i, 0);
408 for (i = hv_iterinit(hv); i > 0; i--) {
409 hv_sv = hv_iternextsv(hv, &tmp, &sv_len);
416 RPEDEBUG(
"Failed to allocate %d for output", sv_len);
419 fr_value_box_list_insert_tail(list, vb);
437 RPEDEBUG(
"Perl returned unsupported data type %d",
type);
443 vb->tainted = SvTAINTED(sv);
444 fr_value_box_list_insert_tail(list, vb);
472 fr_value_box_list_t list, sub_list;
475 fr_value_box_list_init(&list);
476 fr_value_box_list_init(&sub_list);
480 PERL_SET_CONTEXT(t->
perl);
497 if (fr_value_box_list_empty(&arg->vb_group))
continue;
499 if (fr_value_box_list_num_elements(&arg->vb_group) == 1) {
500 child = fr_value_box_list_head(&arg->vb_group);
502 switch (child->type) {
504 if (child->vb_length == 0)
continue;
506 RDEBUG3(
"Passing single value %pV", child);
507 sv = newSVpvn(child->vb_strvalue, child->vb_length);
511 RDEBUG3(
"Ignoring nested group");
524 RDEBUG3(
"Passing single value %pV", child);
526 fr_sbuff_set_to_start(sbuff);
530 if (child->tainted) SvTAINT(sv);
531 XPUSHs(sv_2mortal(sv));
540 RDEBUG3(
"Passing list as array %pM", &arg->vb_group);
541 sv = newRV_inc((SV *)av);
542 XPUSHs(sv_2mortal(sv));
547 count = call_pv(func->vb_strvalue, G_ARRAY | G_EVAL);
551 REDEBUG(
"Exit %s", SvPV(ERRSV,n_a));
561 for (i = 0; i <
count; i++) {
564 fr_value_box_list_move_head(&list, &sub_list);
589 int indent_section = (lvl + 1) * 4;
590 int indent_item = (lvl + 2) * 4;
592 if (!cs || !rad_hv)
return;
610 if (hv_exists(rad_hv, key, strlen(key))) {
611 WARN(
"Ignoring duplicate config section '%s'", key);
616 ref = newRV_inc((SV*) sub_hv);
618 (void)hv_store(rad_hv, key, strlen(key), ref, 0);
626 if (!key || !
value)
continue;
632 if (hv_exists(rad_hv, key, strlen(key))) {
633 WARN(
"Ignoring duplicate config item '%s'", key);
637 (void)hv_store(rad_hv, key, strlen(key), newSVpvn(
value, strlen(
value)), 0);
639 DEBUG(
"%*s%s = %s", indent_item,
" ", key,
value);
643 DEBUG(
"%*s}", indent_section,
" ");
647 const char *hash_name,
bool dbg_print);
650 int *i,
const char *hash_name,
bool dbg_print)
655 if (dbg_print)
RDEBUG2(
"$%s{'%s'}[%i] = %pP", hash_name,
vp->
da->name, *i,
vp);
656 switch (
vp->vp_type) {
658 sv = newSVpvn(
vp->vp_strvalue,
vp->vp_length);
662 sv = newSVpvn((
char const *)
vp->vp_octets,
vp->vp_length);
670 sv = newRV_noinc((SV *)hv);
680 if (slen < 0)
return;
682 sv = newSVpvn(
buffer, (
size_t)slen);
700 const char *hash_name,
bool dbg_print)
730 (void)hv_store(rad_hv,
name, strlen(
name), newRV_noinc((SV *)av), 0);
738 if (dbg_print)
RDEBUG2(
"$%s{'%s'} = %pP'", hash_name,
vp->
da->name,
vp);
739 switch (
vp->vp_type) {
741 (void)hv_store(rad_hv,
name, strlen(
name), newSVpvn(
vp->vp_strvalue,
vp->vp_length), 0);
745 (void)hv_store(rad_hv,
name, strlen(
name),
746 newSVpvn((
char const *)
vp->vp_octets,
vp->vp_length), 0);
754 (void)hv_store(rad_hv,
name, strlen(
name), newRV_noinc((SV *)hv), 0);
764 (void)hv_store(rad_hv,
name, strlen(
name),
765 newSVpvn(
buffer, (
size_t)(slen)), 0);
790 if (!SvOK(sv))
return -1;
796 REDEBUG(
"Ignoring unknown attribute '%s'", key);
805 RPEDEBUG(
"Failed to create pair %s.%s = %s", list_name, key, val);
809 switch (
vp->vp_type) {
821 if (!SvROK(sv) || (SvTYPE(SvRV(sv)) != SVt_PVHV)) {
822 RPEDEBUG(
"%s should be retuned as a hash",
vp->
da->name);
826 if (
get_hv_content(
vp, request, hv, &
vp->vp_group, list_name, da,
false) < 0)
goto fail;
838 if (dbg_print)
RDEBUG2(
"%s.%pP", list_name,
vp);
851 I32 key_len, len, i, j;
854 for (i = hv_iterinit(my_hv); i > 0; i--) {
855 res_sv = hv_iternextsv(my_hv,&key,&key_len);
856 if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
857 av = (AV*)SvRV(res_sv);
859 for (j = 0; j <= len; j++) {
860 av_sv = av_fetch(av, j, 0);
861 if (
pairadd_sv(ctx, request, vps, key, *av_sv, list_name,
parent, dbg_print) < 0)
continue;
865 if (
pairadd_sv(ctx, request, vps, key, res_sv, list_name,
parent, dbg_print) < 0)
continue;
901 PERL_SET_CONTEXT(interp);
910 rad_reply_hv = get_hv(
"RAD_REPLY", 1);
911 rad_config_hv = get_hv(
"RAD_CONFIG", 1);
912 rad_request_hv = get_hv(
"RAD_REQUEST", 1);
913 rad_state_hv = get_hv(
"RAD_STATE", 1);
915 perl_store_vps(request, &request->request_pairs, rad_request_hv,
"RAD_REQUEST",
true);
916 perl_store_vps(request, &request->reply_pairs, rad_reply_hv,
"RAD_REPLY",
true);
917 perl_store_vps(request, &request->control_pairs, rad_config_hv,
"RAD_CONFIG",
true);
918 perl_store_vps(request, &request->session_state_pairs, rad_state_hv,
"RAD_STATE",
true);
941 REDEBUG(
"perl_embed:: module = %s , func = %s exit status= %s\n",
945 }
else if (
count == 1) {
947 if (ret >= 100 || ret < 0) {
958 if (
inst->replace.request &&
959 (
get_hv_content(request->request_ctx, request, rad_request_hv, &vps,
"request",
965 if (
inst->replace.reply &&
966 (
get_hv_content(request->reply_ctx, request, rad_reply_hv, &vps,
"reply",
972 if (
inst->replace.control &&
973 (
get_hv_content(request->control_ctx, request, rad_config_hv, &vps,
"control",
979 if (
inst->replace.session &&
980 (
get_hv_content(request->session_state_ctx, request, rad_state_hv, &vps,
"session-state",
998 PERL_SET_CONTEXT(perl);
1004 PL_perl_destruct_level = 2;
1006 PL_origenviron = environ;
1012 while (PL_scopestack_ix > 1) LEAVE;
1014 perl_destruct(perl);
1024 PerlInterpreter *interp;
1027 PERL_SET_CONTEXT(
inst->perl);
1029 interp = perl_clone(
inst->perl, clone_flags);
1033# if PERL_REVISION >= 5 && PERL_VERSION <8
1034 call_pv(
"CLONE", 0);
1036 ptr_table_free(PL_ptr_table);
1037 PL_ptr_table = NULL;
1039 PERL_SET_CONTEXT(aTHX);
1068 eval_str = talloc_asprintf(NULL,
"(main->can('%s') ? 1 : 0)", func);
1069 val = eval_pv(eval_str, TRUE);
1071 return SvIV(val) ? true :
false;
1099 char const **embed_c;
1101 int ret = 0, argc = 0;
1109 MEM(embed_c = talloc_zero_array(
inst,
char const *, 4));
1110 memcpy(&embed, &embed_c,
sizeof(embed));
1112 if (
inst->perl_flags) {
1113 embed_c[1] =
inst->perl_flags;
1114 embed_c[2] =
inst->module;
1118 embed_c[1] =
inst->module;
1126 if ((
inst->perl = perl_alloc()) == NULL) {
1127 ERROR(
"No memory for allocating new perl interpreter!");
1130 perl_construct(
inst->perl);
1132 PL_perl_destruct_level = 2;
1136 PERL_SET_CONTEXT(
inst->perl);
1138#if PERL_REVISION >= 5 && PERL_VERSION >=8
1139 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1142 ret = perl_parse(
inst->perl,
xs_init, argc, embed, NULL);
1145 PL_endav = (AV *)NULL;
1148 ERROR(
"Perl_parse failed: %s not found or has syntax errors",
inst->module);
1155 inst->rad_perlconf_hv = get_hv(
"RAD_PERLCONF", 1);
1159 inst->perl_parsed =
true;
1160 perl_run(
inst->perl);
1174 pair_name = talloc_asprintf(func,
"func_%s_%s", func->
name1, func->
name2);
1177 if (cp)
goto found_func;
1179 pair_name = talloc_asprintf(func,
"func_%s", func->
name1);
1192 }
else if (func->
name2) {
1222 int ret = 0,
count = 0;
1225 if (
inst->perl_parsed) {
1227 PERL_SET_CONTEXT(
inst->perl);
1228 if (
inst->rad_perlconf_hv != NULL) hv_undef(
inst->rad_perlconf_hv);
1230 if (
inst->func_detach) {
1231 dSP;
ENTER; SAVETMPS;
1234 count = call_pv(
inst->func_detach, G_SCALAR | G_EVAL );
1239 if (ret >= 100 || ret < 0) {
1267 char const **embed_c;
1272#define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_perl - " _fmt, ## __VA_ARGS__)
1273#define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1274 &(fr_log_perror_format_t){ \
1275 .first_prefix = "rlm_perl - ", \
1276 .subsq_prefix = "rlm_perl - ", \
1278 _fmt, ## __VA_ARGS__)
1280 LOAD_INFO(
"Perl version: %s", PERL_API_VERSION_STRING);
1294 MEM(embed_c = talloc_zero_array(NULL,
char const *, 1));
1295 memcpy(&embed, &embed_c,
sizeof(embed));
1299 PERL_SYS_INIT3(&argc, &embed, &envp);
1321 for (i = 0; i < talloc_array_length(
name); i++) {
1323 if (!strchr(
"abcdefghijklmnopqrstuvwxyz1234567890", *p)) *p =
'_';
1336 if (!
inst->funcs_init) {
1338 inst->funcs_init =
true;
1347 .offset = rule->pair.offset,
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
static int const char char buffer[256]
#define DIAG_UNKNOWN_PRAGMAS
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
call_env_parsed_t * call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs.
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
section_name_t const * asked
The actual name1/name2 that resolved to a module_method_binding_t.
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
@ CALL_ENV_FLAG_PARSE_MISSING
If this subsection is missing, still parse it.
@ CALL_ENV_PARSE_TYPE_VOID
Output of the parsing phase is undefined (a custom structure).
module_instance_t const * mi
Module instance that the callenv is registered to.
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
#define CONF_PARSER_TERMINATOR
void * data
Pointer to a static variable to write the parsed value to.
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
Configuration AVP similar to a fr_pair_t.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_item_next(_parent, _curr)
static int split(char **input, char **output, bool syntax_string)
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
Add a library/server version pair to the main configuration.
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.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
static xlat_action_t perl_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Call perl code using an xlat.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RPEDEBUG(fmt,...)
#define RINDENT()
Indent R* messages by one level.
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
void * thread
Thread instance data.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
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)
module_t common
Common fields presented by all modules.
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.
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
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.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
static const conf_parser_t config[]
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
int fr_rb_find_or_insert(void **found, fr_rb_tree_t *tree, void const *data)
Attempt to find current data in the tree, if it does not exist insert it.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
#define RETURN_MODULE_RCODE(_rcode)
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_FAIL
Module failed, don't reply.
static int perl_sv_to_vblist(TALLOC_CTX *ctx, fr_value_box_list_t *list, request_t *request, SV *sv)
Parse a Perl SV and create value boxes, appending to a list.
fr_rb_node_t node
Node in tree of function calls.
static int mod_detach(module_detach_ctx_t const *mctx)
static int mod_load(void)
PerlInterpreter * perl
Thread specific perl interpreter.
static bool perl_func_exists(char const *func)
Check if a given Perl subroutine exists.
HV * rad_perlconf_hv
holds "config" items (perl RAD_PERLCONF hash).
rlm_perl_replace_t replace
static void perl_func_name_safe(char *name)
static xlat_arg_parser_t const perl_xlat_args[]
char const * func_detach
Function to run when mod_detach is run.
char const * function_name
Name of the function being called.
static void ** rlm_perl_get_handles(pTHX)
static const conf_parser_t replace_config[]
static XS(XS_radiusd_log)
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv)
static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
static int mod_bootstrap(module_inst_ctx_t const *mctx)
char * name1
Section name1 where this is called.
static void rlm_perl_interp_free(PerlInterpreter *perl)
char const *fr_rb_tree_t funcs
Tree of function calls found by call_env parser.
static void mod_unload(void)
static void xs_init(pTHX)
static int8_t perl_func_def_cmp(void const *one, void const *two)
How to compare two Perl function calls.
#define LOAD_WARN(_fmt,...)
static void rlm_perl_close_handles(void **handles)
static void perl_store_vps(request_t *request, fr_pair_list_t *vps, HV *rad_hv, const char *hash_name, bool dbg_print)
bool session
Should the session list be replaced after module call.
static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv, const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t *vp, int *i, const char *hash_name, bool dbg_print)
char * name2
Section name2 where this is called.
static unlang_action_t mod_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static int perl_vblist_to_av(AV *av, fr_value_box_list_t *head)
Convert a list of value boxes to a Perl array for passing to subroutines.
static void * perl_dlhandle
To allow us to load perl's symbols into the global symbol table.
#define LOAD_INFO(_fmt,...)
static const conf_parser_t module_config[]
static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps, const char *list_name, fr_dict_attr_t const *parent, bool dbg_print)
static _Thread_local request_t * rlm_perl_request
static const call_env_method_t perl_method_env
bool reply
Should the reply list be replaced after module call.
bool funcs_init
Has the tree been initialised.
bool control
Should the control list be replaced after module call.
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static void rlm_perl_clear_handles(pTHX)
bool request
Should the request list be replaced after module call.
static int perl_func_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, UNUSED tmpl_rules_t const *t_rules, UNUSED CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
static int instantiate(module_inst_ctx_t const *mctx)
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
char const * name1
First section name. Usually a verb like 'recv', 'send', etc...
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
Optional arguments passed to vp_tmpl functions.
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define talloc_get_type_abort_const
static int talloc_const_free(void const *ptr)
Free const'd memory.
bool required
Argument must be present, and non-empty.
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition for a single argument consumend by an xlat function.
#define ATTRIBUTE_EQ(_x, _y)
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
void fr_pair_list_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
#define PAIR_LIST_VERIFY(_x)
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
#define FR_TYPE_STRUCTURAL
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
#define fr_value_box_list_foreach(_list_head, _iter)
static size_t char ** out
module_ctx_t const * mctx
Synthesised module calling ctx.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.