25 RCSID(
"$Id: 64b2292bf1634f7f9edc4fdacd1f3cd649184b36 $")
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>
47 #include <semaphore.h>
49 #if defined(__APPLE__) || defined(__FreeBSD__)
50 extern char **environ;
54 # error perl must be compiled with USE_ITHREADS
69 char const *func_authorize;
70 char const *func_authenticate;
71 char const *func_accounting;
72 char const *func_preacct;
73 char const *func_detach;
74 char const *func_post_auth;
75 char const *perl_flags;
76 PerlInterpreter *perl;
91 #define RLM_PERL_CONF(_x) { FR_CONF_OFFSET("func_" STRINGIFY(_x), rlm_perl_t, func_##_x), \
92 .data = NULL, .dflt = STRINGIFY(_x), .quote = T_INVALID }
116 # define dl_librefs "DynaLoader::dl_librefs"
117 # define dl_modules "DynaLoader::dl_modules"
133 if (!librefs)
return NULL;
135 if (!(AvFILL(librefs) >= 0)) {
139 MEM(handles = talloc_array(NULL,
void *, AvFILL(librefs) + 2));
140 for (i = 0; i <= AvFILL(librefs); i++) {
142 SV *handle_sv = *av_fetch(librefs, i,
false);
147 handle = (
void *)SvIV(handle_sv);
149 if (handle) handles[i] = handle;
155 handles[i] = (
void *)0;
168 for (i = 0; handles[i]; i++) {
169 DEBUG(
"Close %p", handles[i]);
181 static XS(XS_radiusd_log)
185 croak(
"Usage: radiusd::log(level, message)");
190 level = (int) SvIV(ST(0));
191 msg = (
char *) SvPV(ST(1), PL_na);
209 static XS(XS_radiusd_xlat)
217 if (items != 1) croak(
"Usage: radiusd::xlat(string)");
221 in_str = (
char *) SvPV(ST(0), PL_na);
223 slen =
xlat_aeval(request, &expanded, request, in_str, NULL, NULL);
225 REDEBUG(
"Error parsing xlat '%s'", in_str);
229 XST_mPV(0, expanded);
236 char const *
file = __FILE__;
241 newXS(
"radiusd::log",XS_radiusd_log,
"rlm_perl");
242 newXS(
"radiusd::xlat",XS_radiusd_xlat,
"rlm_perl");
260 while ((vb = fr_value_box_list_next(
head, vb))) {
263 sv = newSVpvn(vb->vb_strvalue, vb->vb_length);
267 sv = newSVpvn((
char const *)vb->vb_octets, vb->vb_length);
275 sv = newRV_inc((SV *)sub_av);
284 if (slen < 0)
return -1;
285 sv = newSVpvn(
buffer, (
size_t)slen);
290 if (vb->tainted) SvTAINT(sv);
325 DEBUG3(
"Reference returned");
329 DEBUG3(
"Integer returned");
331 vb->vb_int32 = SvIV(sv);
338 vb->vb_float64 = SvNV(sv);
343 DEBUG3(
"String returned");
344 tmp = SvPVutf8(sv, len);
348 RPEDEBUG(
"Failed to allocate %ld for output", len);
360 for (i = 0; i <= sv_len; i++) {
361 av_sv = av_fetch(av, i, 0);
375 for (i = hv_iterinit(hv); i > 0; i--) {
376 hv_sv = hv_iternextsv(hv, &tmp, &sv_len);
383 RPEDEBUG(
"Failed to allocate %d for output", sv_len);
386 fr_value_box_list_insert_tail(list, vb);
404 RPEDEBUG(
"Perl returned unsupported data type %d",
type);
410 vb->tainted = SvTAINTED(sv);
411 fr_value_box_list_insert_tail(list, vb);
439 fr_value_box_list_t list, sub_list;
442 fr_value_box_list_init(&list);
443 fr_value_box_list_init(&sub_list);
447 PERL_SET_CONTEXT(t->
perl);
458 if (fr_value_box_list_empty(&arg->vb_group))
continue;
460 if (fr_value_box_list_num_elements(&arg->vb_group) == 1) {
461 child = fr_value_box_list_head(&arg->vb_group);
465 if (child->vb_length == 0)
continue;
466 DEBUG3(
"Passing single value %pV", child);
467 sv = newSVpvn(child->vb_strvalue, child->vb_length);
468 if (child->tainted) SvTAINT(sv);
469 XPUSHs(sv_2mortal(sv));
478 DEBUG3(
"Passing list as array %pM", &arg->vb_group);
479 sv = newRV_inc((SV *)av);
480 XPUSHs(sv_2mortal(sv));
485 count = call_pv(func->vb_strvalue, G_ARRAY | G_EVAL);
489 REDEBUG(
"Exit %s", SvPV(ERRSV,n_a));
499 for (i = 0; i <
count; i++) {
502 fr_value_box_list_move_head(&list, &sub_list);
527 int indent_section = (lvl + 1) * 4;
528 int indent_item = (lvl + 2) * 4;
530 if (!cs || !rad_hv)
return;
548 if (hv_exists(rad_hv, key, strlen(key))) {
549 WARN(
"Ignoring duplicate config section '%s'", key);
554 ref = newRV_inc((SV*) sub_hv);
556 (void)hv_store(rad_hv, key, strlen(key), ref, 0);
564 if (!key || !
value)
continue;
570 if (hv_exists(rad_hv, key, strlen(key))) {
571 WARN(
"Ignoring duplicate config item '%s'", key);
575 (void)hv_store(rad_hv, key, strlen(key), newSVpvn(
value, strlen(
value)), 0);
577 DEBUG(
"%*s%s = %s", indent_item,
" ", key,
value);
581 DEBUG(
"%*s}", indent_section,
" ");
595 int *i,
const char *hash_name,
const char *list_name)
600 switch (
vp->vp_type) {
602 RDEBUG2(
"$%s{'%s'}[%i] = &%s.%s -> '%s'", hash_name,
vp->
da->name, *i,
603 list_name,
vp->
da->name,
vp->vp_strvalue);
604 sv = newSVpvn(
vp->vp_strvalue,
vp->vp_length);
608 RDEBUG2(
"$%s{'%s'}[%i] = &%s.%s -> 0x%pH", hash_name,
vp->
da->name, *i,
609 list_name,
vp->
da->name, &
vp->data);
610 sv = newSVpvn((
char const *)
vp->vp_octets,
vp->vp_length);
619 if (slen < 0)
return;
621 RDEBUG2(
"$%s{'%s'}[%i] = &%s.%s -> '%pV'", hash_name,
vp->
da->name, *i,
623 sv = newSVpvn(
buffer, (
size_t)slen);
641 const char *hash_name,
const char *list_name)
671 (void)hv_store(rad_hv,
name, strlen(
name), newRV_noinc((SV *)av), 0);
679 switch (
vp->vp_type) {
681 RDEBUG2(
"$%s{'%s'} = &%s.%s -> '%pV'", hash_name,
vp->
da->name, list_name,
683 (void)hv_store(rad_hv,
name, strlen(
name), newSVpvn(
vp->vp_strvalue,
vp->vp_length), 0);
687 RDEBUG2(
"$%s{'%s'} = &%s.%s -> %pV", hash_name,
vp->
da->name, list_name,
689 (void)hv_store(rad_hv,
name, strlen(
name),
690 newSVpvn((
char const *)
vp->vp_octets,
vp->vp_length), 0);
699 RDEBUG2(
"$%s{'%s'} = &%s.%s -> '%pV'", hash_name,
vp->
da->name,
701 (void)hv_store(rad_hv,
name, strlen(
name),
702 newSVpvn(
buffer, (
size_t)(slen)), 0);
717 const char *hash_name,
const char *list_name)
724 if (!SvOK(sv))
return -1;
730 REDEBUG(
"Ignoring unknown attribute '%s'", key);
738 RPEDEBUG(
"Failed to create pair %s.%s = %s", list_name, key, val);
742 switch (
vp->vp_type) {
757 RDEBUG2(
"&%s.%s = $%s{'%s'} -> '%s'", list_name, key, hash_name, key, val);
765 const char *hash_name,
const char *list_name)
770 I32 key_len, len, i, j;
773 for (i = hv_iterinit(my_hv); i > 0; i--) {
774 res_sv = hv_iternextsv(my_hv,&key,&key_len);
775 if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
776 av = (AV*)SvRV(res_sv);
778 for (j = 0; j <= len; j++) {
779 av_sv = av_fetch(av, j, 0);
780 if (
pairadd_sv(ctx, request, vps, key, *av_sv, hash_name, list_name) < 0)
continue;
784 if (
pairadd_sv(ctx, request, vps, key, res_sv, hash_name, list_name) < 0)
continue;
800 PerlInterpreter *interp,
char const *function_name)
821 PERL_SET_CONTEXT(interp);
830 rad_reply_hv = get_hv(
"RAD_REPLY", 1);
831 rad_config_hv = get_hv(
"RAD_CONFIG", 1);
832 rad_request_hv = get_hv(
"RAD_REQUEST", 1);
833 rad_state_hv = get_hv(
"RAD_STATE", 1);
835 perl_store_vps(request->request_ctx, request, &request->request_pairs, rad_request_hv,
"RAD_REQUEST",
"request");
836 perl_store_vps(request->reply_ctx, request, &request->reply_pairs, rad_reply_hv,
"RAD_REPLY",
"reply");
837 perl_store_vps(request->control_ctx, request, &request->control_pairs, rad_config_hv,
"RAD_CONFIG",
"control");
838 perl_store_vps(request->session_state_ctx, request, &request->session_state_pairs, rad_state_hv,
"RAD_STATE",
"session-state");
854 count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);
861 REDEBUG(
"perl_embed:: module = %s , func = %s exit status= %s\n",
862 inst->module, function_name, SvPV(ERRSV,n_a));
865 }
else if (
count == 1) {
867 if (ret >= 100 || ret < 0) {
878 if ((
get_hv_content(request->request_ctx, request, rad_request_hv, &vps,
"RAD_REQUEST",
"request")) > 0) {
883 if ((
get_hv_content(request->reply_ctx, request, rad_reply_hv, &vps,
"RAD_REPLY",
"reply")) > 0) {
888 if ((
get_hv_content(request->control_ctx, request, rad_config_hv, &vps,
"RAD_CONFIG",
"control")) > 0) {
893 if ((
get_hv_content(request->session_state_ctx, request, rad_state_hv, &vps,
"RAD_STATE",
"session-state")) > 0) {
902 #define RLM_PERL_FUNC(_x) \
903 static unlang_action_t CC_HINT(nonnull) mod_##_x(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
905 rlm_perl_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_perl_t); \
906 return do_perl(p_result, mctx, request, \
907 ((rlm_perl_thread_t *)talloc_get_type_abort(mctx->thread, rlm_perl_thread_t))->perl, \
925 PERL_SET_CONTEXT(perl);
931 PL_perl_destruct_level = 2;
933 PL_origenviron = environ;
939 while (PL_scopestack_ix > 1) LEAVE;
951 PerlInterpreter *interp;
954 PERL_SET_CONTEXT(
inst->perl);
956 interp = perl_clone(
inst->perl, clone_flags);
960 # if PERL_REVISION >= 5 && PERL_VERSION <8
963 ptr_table_free(PL_ptr_table);
966 PERL_SET_CONTEXT(aTHX);
1003 char const **embed_c;
1005 int ret = 0, argc = 0;
1013 MEM(embed_c = talloc_zero_array(
inst,
char const *, 4));
1014 memcpy(&embed, &embed_c,
sizeof(embed));
1016 if (
inst->perl_flags) {
1017 embed_c[1] =
inst->perl_flags;
1018 embed_c[2] =
inst->module;
1022 embed_c[1] =
inst->module;
1030 if ((
inst->perl = perl_alloc()) == NULL) {
1031 ERROR(
"No memory for allocating new perl interpreter!");
1034 perl_construct(
inst->perl);
1036 PL_perl_destruct_level = 2;
1040 PERL_SET_CONTEXT(
inst->perl);
1042 #if PERL_REVISION >= 5 && PERL_VERSION >=8
1043 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
1046 ret = perl_parse(
inst->perl,
xs_init, argc, embed, NULL);
1049 PL_endav = (AV *)NULL;
1052 ERROR(
"Perl_parse failed: %s not found or has syntax errors",
inst->module);
1059 inst->rad_perlconf_hv = get_hv(
"RAD_PERLCONF", 1);
1063 inst->perl_parsed =
true;
1064 perl_run(
inst->perl);
1078 int ret = 0,
count = 0;
1081 if (
inst->perl_parsed) {
1083 PERL_SET_CONTEXT(
inst->perl);
1084 if (
inst->rad_perlconf_hv != NULL) hv_undef(
inst->rad_perlconf_hv);
1086 if (
inst->func_detach) {
1087 dSP;
ENTER; SAVETMPS;
1090 count = call_pv(
inst->func_detach, G_SCALAR | G_EVAL );
1095 if (ret >= 100 || ret < 0) {
1113 char const **embed_c;
1118 #define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_perl - " _fmt, ## __VA_ARGS__)
1119 #define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1120 &(fr_log_perror_format_t){ \
1121 .first_prefix = "rlm_perl - ", \
1122 .subsq_prefix = "rlm_perl - ", \
1124 _fmt, ## __VA_ARGS__)
1126 LOAD_INFO(
"Perl version: %s", PERL_API_VERSION_STRING);
1140 MEM(embed_c = talloc_zero_array(NULL,
char const *, 1));
1141 memcpy(&embed, &embed_c,
sizeof(embed));
1145 PERL_SYS_INIT3(&argc, &embed, &envp);
1193 { .name1 =
"recv", .name2 =
"accounting-request", .method =
mod_preacct },
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 CONF_PARSER_TERMINATOR
#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
@ 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.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
#define cf_item_next(_ci, _prev)
static int split(char **input, char **output, bool syntax_string)
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.
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
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_search_by_qualified_oid(fr_dict_attr_err_t *err, fr_dict_t const *dict_def, char const *attr, bool internal, bool foreign))
Locate a qualified fr_dict_attr_t by its name and a dictionary qualifier.
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
void *_CONST data
Module instance's parsed configuration.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
CONF_SECTION *_CONST conf
Module's instance configuration.
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_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 * thread
Thread specific instance data.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
void * thread
Thread instance data.
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
Specifies a module method identifier.
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.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
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.
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
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[]
#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 unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Write accounting data to Couchbase documents.
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
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.
static int mod_detach(module_detach_ctx_t const *mctx)
static int mod_load(void)
PerlInterpreter * perl
Thread specific perl interpreter.
#define RLM_PERL_FUNC(_x)
static xlat_arg_parser_t const perl_xlat_args[]
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)
#define RLM_PERL_CONF(_x)
static int mod_bootstrap(module_inst_ctx_t const *mctx)
static void rlm_perl_interp_free(PerlInterpreter *perl)
static unlang_action_t do_perl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PerlInterpreter *interp, char const *function_name)
static void mod_unload(void)
static void xs_init(pTHX)
#define LOAD_WARN(_fmt,...)
static void rlm_perl_close_handles(void **handles)
static void perl_store_vps(UNUSED TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, HV *rad_hv, const char *hash_name, const char *list_name)
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static void ** rlm_perl_get_handles(pTHX)
DIAG_OFF(compound-token-split-by-macro) typedef struct
static int pairadd_sv(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, char *key, SV *sv, const char *hash_name, const char *list_name)
static void perl_vp_to_svpvn_element(request_t *request, AV *av, fr_pair_t const *vp, int *i, const char *hash_name, const char *list_name)
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 _Thread_local request_t * rlm_perl_request
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static int get_hv_content(TALLOC_CTX *ctx, request_t *request, HV *my_hv, fr_pair_list_t *vps, const char *hash_name, const char *list_name)
static void rlm_perl_clear_handles(pTHX)
static int instantiate(module_inst_ctx_t const *mctx)
static unlang_action_t mod_preacct(rlm_rcode_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
#define FR_SBUFF_OUT(_start, _len_or_end)
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
#define MODULE_NAME_TERMINATOR
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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
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.
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_box_strvalue_len(_val, _len)
#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.
xlat_t * xlat_func_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function for a module.