28 RCSID(
"$Id: c19b23742580801c33c2e10348f7d9fae0b2161d $")
30 #include <freeradius-devel/server/base.h>
31 #include <freeradius-devel/server/module_rlm.h>
32 #include <freeradius-devel/tls/base.h>
33 #include <freeradius-devel/tls/cert.h>
34 #include <freeradius-devel/tls/log.h>
35 #include <freeradius-devel/tls/utils.h>
36 #include <freeradius-devel/tls/strerror.h>
37 #include <freeradius-devel/util/debug.h>
38 #include <freeradius-devel/unlang/xlat_func.h>
39 #include <freeradius-devel/unlang/xlat.h>
41 #include <freeradius-devel/tls/openssl_user_macros.h>
42 #include <openssl/crypto.h>
43 #include <openssl/pem.h>
44 #include <openssl/evp.h>
45 #include <openssl/rsa.h>
46 #include <openssl/x509.h>
91 {
L(
"DH"), EVP_PKEY_DH },
92 {
L(
"DSA"), EVP_PKEY_DSA },
93 {
L(
"EC"), EVP_PKEY_EC },
94 {
L(
"RSA"), EVP_PKEY_RSA }
102 {
L(
"none"), RSA_NO_PADDING },
103 {
L(
"oaep"), RSA_PKCS1_OAEP_PADDING },
104 {
L(
"pkcs"), RSA_PKCS1_PADDING },
105 {
L(
"x931"), RSA_X931_PADDING }
257 char const *type_str;
260 md = EVP_get_digestbyname(type_str);
262 cf_log_err(ci,
"Invalid digest type \"%s\"", type_str);
266 *((EVP_MD
const **)
out) = md;
286 char const *type_str;
291 cf_log_err(ci,
"Invalid padding type \"%s\"", type_str);
314 char const *type_str;
324 cf_log_err(ci,
"Invalid cipher type \"%s\"", type_str);
375 char const *filename;
382 fp = fopen(filename,
"r");
393 fr_tls_strerror_printf(NULL);
394 cf_log_perr(ci,
"Error loading private certificate file \"%s\"", filename);
399 pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey));
400 if (pkey_type != EVP_PKEY_RSA) {
401 cf_log_err(ci,
"Expected certificate to contain %s private key, got %s private key",
409 talloc_set_type(pkey, EVP_PKEY);
410 (void)talloc_steal(ctx, pkey);
434 char const *filename;
443 fp = fopen(filename,
"r");
452 cert = PEM_read_X509(fp, NULL, NULL, NULL);
456 fr_tls_strerror_printf(NULL);
457 cf_log_perr(ci,
"Error loading certificate file \"%s\"", filename);
467 talloc_set_type(cert, X509);
468 (void)talloc_steal(ctx, cert);
474 pkey = X509_get_pubkey(cert);
476 fr_tls_strerror_printf(NULL);
477 cf_log_perr(ci,
"Failed extracting public key from certificate");
482 pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey));
483 if (pkey_type != EVP_PKEY_RSA) {
484 cf_log_err(ci,
"Expected certificate to contain %s public key, got %s public key",
497 cf_log_debug(ci,
"Certificate validity starts at %pV and ends at %pV",
525 talloc_set_type(pkey, EVP_PKEY);
526 (void)talloc_steal(cert, pkey);
530 *(EVP_PKEY **)
out = pkey;
558 char const *plaintext;
559 size_t plaintext_len;
562 size_t ciphertext_len;
567 plaintext = in_head->vb_strvalue;
568 plaintext_len = in_head->vb_length;
573 RHEXDUMP3((
uint8_t const *)plaintext, plaintext_len,
"Plaintext (%zu bytes)", plaintext_len);
575 (
unsigned char const *)plaintext, plaintext_len) <= 0) {
576 fr_tls_log(request,
"Failed getting length of encrypted plaintext");
583 (
unsigned char const *)plaintext, plaintext_len) <= 0) {
584 fr_tls_log(request,
"Failed encrypting plaintext");
588 RHEXDUMP3(ciphertext, ciphertext_len,
"Ciphertext (%zu bytes)", ciphertext_len);
626 unsigned int digest_len = 0;
631 msg = in_head->vb_strvalue;
632 msg_len = in_head->vb_length;
638 fr_tls_log(request,
"Failed initialising message digest");
643 fr_tls_log(request,
"Failed ingesting message");
648 fr_tls_log(request,
"Failed finalising message digest");
657 fr_tls_log(request,
"Failed getting length of digest");
664 fr_tls_log(request,
"Failed signing message digest");
698 size_t ciphertext_len;
701 size_t plaintext_len;
706 ciphertext = in_head->vb_octets;
707 ciphertext_len = in_head->vb_length;
712 RHEXDUMP3(ciphertext, ciphertext_len,
"Ciphertext (%zu bytes)", ciphertext_len);
713 if (EVP_PKEY_decrypt(t->
evp_decrypt_ctx, NULL, &plaintext_len, ciphertext, ciphertext_len) <= 0) {
714 fr_tls_log(request,
"Failed getting length of cleartext");
720 if (EVP_PKEY_decrypt(t->
evp_decrypt_ctx, (
unsigned char *)plaintext, &plaintext_len,
721 ciphertext, ciphertext_len) <= 0) {
722 fr_tls_log(request,
"Failed decrypting ciphertext");
726 RHEXDUMP3((
uint8_t const *)plaintext, plaintext_len,
"Plaintext (%zu bytes)", plaintext_len);
766 unsigned int digest_len = 0;
778 REDEBUG(
"Signature argument wrong type, expected %s, got %s. "
779 "Use %%base64.decode(<text>) or %%hex_decode(<text>) if signature is armoured",
784 sig = in_head->vb_octets;
785 sig_len = in_head->vb_length;
790 args = fr_value_box_list_head(
in);
795 REDEBUG(
"Failed concatenating arguments to form plaintext");
799 msg_len =
args->vb_length;
802 REDEBUG(
"Zero length message data");
810 fr_tls_log(request,
"Failed initialising message digest");
815 fr_tls_log(request,
"Failed ingesting message");
820 fr_tls_log(request,
"Failed finalising message digest");
842 fr_tls_log(request,
"Failed validating signature");
851 { .required =
false, .concat =
false, .single =
true, .type =
FR_TYPE_STRING },
876 if (!fr_value_box_list_next(
in, fr_value_box_list_head(
in))) {
877 REDEBUG(
"Missing digest argument");
884 md_name = ((
fr_value_box_t *)fr_value_box_list_next(
in, fr_value_box_list_head(
in)))->vb_strvalue;
885 md = EVP_get_digestbyname(md_name);
887 REDEBUG(
"Specified digest \"%s\" is not a valid digest type", md_name);
891 md_len = EVP_MD_size(md);
895 if (X509_digest(
inst->rsa->x509_certificate_file, md, digest, (
unsigned int *)&md_len) != 1) {
896 fr_tls_log(request,
"Failed calculating certificate fingerprint");
919 ASN1_INTEGER
const *serial;
922 serial = X509_get0_serialNumber(
inst->rsa->x509_certificate_file);
924 fr_tls_log(request,
"Failed retrieving certificate serial");
941 char const *attribute = fr_value_box_list_head(
in)->vb_strvalue;
946 REDEBUG(
"Unknown certificate attribute \"%s\"", attribute);
957 vb->vb_date =
inst->rsa->not_before;
964 vb->vb_date =
inst->rsa->not_after;
978 EVP_PKEY_CTX_free(evp_pkey_ctx);
990 EVP_MD_CTX_destroy(evp_md_ctx);
997 if (
unlikely(EVP_PKEY_CTX_set_rsa_padding(evp_pkey_ctx, rsa_inst->
padding)) <= 0) {
998 fr_tls_strerror_printf(NULL);
999 PERROR(
"%s: Failed setting RSA padding type", __FUNCTION__);
1004 case RSA_NO_PADDING:
1005 case RSA_X931_PADDING:
1006 case RSA_PKCS1_PADDING:
1012 case RSA_PKCS1_OAEP_PADDING:
1014 fr_tls_strerror_printf(NULL);
1015 PERROR(
"%s: Failed setting OAEP digest", __FUNCTION__);
1020 fr_tls_strerror_printf(NULL);
1021 PERROR(
"%s: Failed setting MGF1 digest", __FUNCTION__);
1027 size_t label_len = talloc_array_length(rsa_inst->
oaep->
label) - 1;
1037 if (
unlikely(EVP_PKEY_CTX_set0_rsa_oaep_label(evp_pkey_ctx, label, label_len) <= 0)) {
1038 fr_tls_strerror_printf(NULL);
1039 PERROR(
"%s: Failed setting OAEP padding label", __FUNCTION__);
1040 OPENSSL_free(label);
1072 if (
inst->rsa->certificate_file) {
1078 fr_tls_strerror_printf(NULL);
1079 PERROR(
"%s: Failed allocating encrypt EVP_PKEY_CTX", __FUNCTION__);
1090 fr_tls_strerror_printf(NULL);
1091 PERROR(
"%s: Failed initialising encrypt EVP_PKEY_CTX", __FUNCTION__);
1095 ERROR(
"%s: Failed setting padding for encrypt EVP_PKEY_CTX", __FUNCTION__);
1104 fr_tls_strerror_printf(NULL);
1105 PERROR(
"%s: Failed allocating verify EVP_PKEY_CTX", __FUNCTION__);
1116 fr_tls_strerror_printf(NULL);
1117 PERROR(
"%s: Failed initialising verify EVP_PKEY_CTX", __FUNCTION__);
1124 if (
inst->rsa->padding != RSA_PKCS1_OAEP_PADDING) {
1126 ERROR(
"%s: Failed setting padding for verify EVP_PKEY_CTX", __FUNCTION__);
1132 fr_tls_strerror_printf(NULL);
1133 PERROR(
"%s: Failed setting signature digest type", __FUNCTION__);
1138 if (
inst->rsa->private_key_file) {
1144 fr_tls_strerror_printf(NULL);
1145 PERROR(
"%s: Failed allocating decrypt EVP_PKEY_CTX", __FUNCTION__);
1156 fr_tls_strerror_printf(NULL);
1157 PERROR(
"%s: Failed initialising decrypt EVP_PKEY_CTX", __FUNCTION__);
1161 ERROR(
"%s: Failed setting padding for decrypt EVP_PKEY_CTX", __FUNCTION__);
1170 fr_tls_strerror_printf(NULL);
1171 PERROR(
"%s: Failed allocating sign EVP_PKEY_CTX", __FUNCTION__);
1182 fr_tls_strerror_printf(NULL);
1183 PERROR(
"%s: Failed initialising sign EVP_PKEY_CTX", __FUNCTION__);
1190 if (
inst->rsa->padding != RSA_PKCS1_OAEP_PADDING) {
1192 ERROR(
"%s: Failed setting padding for sign EVP_PKEY_CTX", __FUNCTION__);
1198 fr_tls_strerror_printf(NULL);
1199 PERROR(
"%s: Failed setting signature digest type", __FUNCTION__);
1208 fr_tls_strerror_printf(NULL);
1209 PERROR(
"%s: Failed allocating EVP_MD_CTX", __FUNCTION__);
1252 cf_log_err(
conf,
"type = rsa, but no 'rsa { ... }' configuration section provided");
1256 if (!
inst->rsa->private_key_file && !
inst->rsa->certificate_file) {
1258 "'private_key_file' nor 'certificate_file' configured");
1262 if (
inst->rsa->private_key_file) {
1278 if (
inst->rsa->certificate_file) {
1288 if (
inst->rsa->private_key_file &&
inst->rsa->x509_certificate_file) {
1289 if (X509_check_private_key(
inst->rsa->x509_certificate_file,
1290 inst->rsa->private_key_file) == 0) {
1291 fr_tls_strerror_printf(NULL);
1292 cf_log_perr(
conf,
"Private key does not match the certificate public key");
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define L(_str)
Helper for initialising arrays of string literals.
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
#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
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
#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
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
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.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
#define cf_log_pwarn(_cf, _fmt,...)
#define cf_log_debug(_cf, _fmt,...)
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
static xlat_action_t cipher_rsa_decrypt_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Decrypt input data.
static xlat_action_t cipher_rsa_encrypt_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Encrypt input data.
static xlat_action_t cipher_rsa_sign_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Sign input data.
static xlat_action_t cipher_serial_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Return the serial of the public certificate.
static xlat_action_t cipher_rsa_verify_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Verify input data.
static xlat_action_t cipher_fingerprint_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Return the fingerprint of the public certificate.
#define RHEXDUMP3(_data, _len, _fmt,...)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
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 const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
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.
EVP_PKEY_CTX * evp_verify_ctx
Pre-allocated evp_pkey_ctx.
static size_t cipher_rsa_padding_len
static int cipher_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Checks if the specified cipher type is valid.
static const conf_parser_t rsa_oaep_config[]
Configuration for the RSA-PCKS1-OAEP padding scheme.
static int cipher_rsa_private_key_file_load(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
cipher_rsa_oaep_t * oaep
OAEP can use a configurable message digest type.
X509 * x509_certificate_file
Needed for extracting certificate attributes.
cipher_cert_verify_mode_t verify_mode
How hard we try to verify the certificate.
static xlat_arg_parser_t const cipher_rsa_verify_xlat_arg[]
static fr_table_num_sorted_t const cipher_rsa_padding[]
The type of padding used.
static fr_table_num_sorted_t const cert_attributes[]
Public key types.
cipher_cert_verify_mode_t
Certificate validation modes.
@ CIPHER_CERT_VERIFY_HARD
Fail if the certificate isn't valid.
@ CIPHER_CERT_VERIFY_SOFT
Warn if the certificate isn't valid.
@ CIPHER_CERT_VERIFY_NONE
Don't check to see if the we're between notBefore or notAfter.
@ CIPHER_CERT_VERIFY_INVALID
static const conf_parser_t rsa_config[]
Configuration for the RSA cipher type.
static int cipher_rsa_padding_params_set(EVP_PKEY_CTX *evp_pkey_ctx, cipher_rsa_t const *rsa_inst)
cipher_type_t type
Type of encryption to use.
static size_t cipher_cert_verify_mode_table_len
@ CIPHER_CERT_ATTR_NOT_AFTER
Time the certificate expires.
@ CIPHER_CERT_ATTR_SERIAL
Certificate's serial number.
@ CIPHER_CERT_ATTR_UNKNOWN
Unrecognised attribute.
@ CIPHER_CERT_ATTR_FINGERPRINT
Dynamically calculated fingerprint.
@ CIPHER_CERT_ATTR_NOT_BEFORE
Time the certificate becomes valid.
char const * label
Additional input to the hashing function.
EVP_MD_CTX * evp_md_ctx
Pre-allocated evp_md_ctx for sign and verify.
int padding
Type of padding to apply to the plaintext or ciphertext before feeding it to RSA crypto functions.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
static int digest_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Calls EVP_get_digestbyname() to convert the digest type.
uint8_t * digest_buff
Pre-allocated digest buffer.
EVP_MD * mgf1_digest
Masking function digest.
static xlat_arg_parser_t const cipher_rsa_decrypt_xlat_arg[]
static fr_table_num_sorted_t const cipher_cert_verify_mode_table[]
@ RLM_CIPHER_TYPE_SYMMETRIC
Any symmetric cipher available via OpenSSL's EVP interface.
@ RLM_CIPHER_TYPE_INVALID
static xlat_arg_parser_t const cipher_rsa_sign_xlat_arg[]
static int _evp_pkey_free(EVP_PKEY *pkey)
Talloc destructor for freeing an EVP_PKEY (representing a certificate)
fr_unix_time_t not_before
Certificate isn't valid before this time.
static xlat_arg_parser_t const cipher_rsa_encrypt_xlat_arg[]
fr_unix_time_t not_after
Certificate isn't valid after this time.
char const * private_key_password
Password to decrypt the private key.
static int cipher_rsa_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Pre-initialises the EVP_PKEY_CTX necessary for performing RSA encryption/decryption/sign/verify.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
EVP_PKEY * certificate_file
Public (certificate) file.
EVP_PKEY * private_key_file
Private key file.
static size_t cipher_type_len
static int cipher_rsa_padding_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Checks if the specified padding type is valid.
static int _x509_cert_free(X509 *cert)
Talloc destructor for freeing an X509 struct (representing a public certificate)
static int _evp_md_ctx_free(EVP_MD_CTX *evp_md_ctx)
Talloc destructor for freeing an EVP_MD_CTX.
static xlat_arg_parser_t const cipher_certificate_xlat_args[]
static fr_table_num_sorted_t const cipher_type[]
EVP_PKEY_CTX * evp_decrypt_ctx
Pre-allocated evp_pkey_ctx.
EVP_PKEY_CTX * evp_encrypt_ctx
Pre-allocated evp_pkey_ctx.
static const conf_parser_t module_config[]
static int cipher_rsa_certificate_file_load(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
static xlat_action_t cipher_certificate_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static size_t cert_attributes_len
EVP_PKEY_CTX * evp_sign_ctx
Pre-allocated evp_pkey_ctx.
static int _evp_pkey_ctx_free(EVP_PKEY_CTX *evp_pkey_ctx)
Talloc destructor for freeing an EVP_PKEY_CTX.
static size_t pkey_types_len
EVP_MD * sig_digest
Signature digest type.
char const * random_file
If set, we read 10K of data (or the complete file) and use it to seed OpenSSL's PRNG.
static fr_table_num_sorted_t const pkey_types[]
Public key types.
EVP_MD * oaep_digest
Padding digest type.
Configuration for the OAEP padding method.
Configuration for RSA encryption/decryption/signing.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
void * boot
Data allocated during the boostrap phase.
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
eap_type_t type
The preferred EAP-Type of this instance of the EAP-SIM/AKA/AKA' state machine.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
#define talloc_get_type_abort_const
bool required
Argument must be present, and non-empty.
@ XLAT_ARG_VARIADIC_EMPTY_SQUASH
Empty argument groups are removed.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition for a single argument consumend by an xlat function.
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
int fr_utils_get_private_key_password(char *buf, int size, UNUSED int rwflag, void *u)
Return the static private key password we have configured.
int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Pre-allocate an octets buffer for filling by the caller.
int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
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.
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
#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.
static size_t char ** out
#define fr_box_date(_val)
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.