25 RCSID(
"$Id: 9b3290940629e0a41f8e355bb87886c5e7c65805 $")
27 #include <freeradius-devel/server/base.h>
28 #include <freeradius-devel/server/module_rlm.h>
29 #include <freeradius-devel/server/pairmove.h>
30 #include <freeradius-devel/util/debug.h>
66 mrb_get_args(mrb,
"iz", &level, &
msg);
69 return mrb_nil_value();
74 int indent_section = (lvl + 1) * 4;
75 int indent_item = (lvl + 2) * 4;
86 mrb_value sub_hash, mrubyKey;
90 mrubyKey = mrb_str_new_cstr(mrb, key);
92 if (!mrb_nil_p(mrb_hash_get(mrb,
hash, mrubyKey))) {
93 WARN(
"rlm_mruby: Ignoring duplicate config section '%s'", key);
97 sub_hash = mrb_hash_new(mrb);
98 mrb_hash_set(mrb,
hash, mrubyKey, sub_hash);
105 mrb_value mrubyKey, mrubyValue;
107 if (!key || !
value)
continue;
109 mrubyKey = mrb_str_new_cstr(mrb, key);
110 mrubyValue = mrb_str_new_cstr(mrb,
value);
112 if (!mrb_nil_p(mrb_hash_get(mrb,
hash, mrubyKey))) {
113 WARN(
"rlm_mruby: Ignoring duplicate config item '%s'", key);
117 mrb_hash_set(mrb,
hash, mrubyKey, mrubyValue);
119 DEBUG(
"%*s%s = %s", indent_item,
" ", key,
value);
123 DEBUG(
"%*s}", indent_section,
" ");
140 mrb =
inst->mrb = mrb_open();
142 ERROR(
"mruby initialization failed");
147 DEBUG(
"Creating module %s",
inst->module_name);
148 inst->mruby_module = mrb_define_module(mrb,
inst->module_name);
149 if (!
inst->mruby_module) {
150 ERROR(
"Creating module %s failed",
inst->module_name);
155 mrb_define_class_method(mrb,
inst->mruby_module,
"log",
mruby_log, MRB_ARGS_REQ(2));
157 #define A(x) mrb_define_const(mrb, inst->mruby_module, #x, mrb_fixnum_value(x));
183 inst->mrubyconf_hash = mrb_hash_new(mrb);
190 DEBUG(
"Loading file %s...",
inst->filename);
191 f = fopen(
inst->filename,
"r");
193 ERROR(
"Opening file failed");
197 status = mrb_load_file(mrb, f);
199 if (mrb_undef_p(status)) {
200 ERROR(
"Parsing file failed");
204 status = mrb_funcall(mrb, mrb_obj_value(
inst->mruby_module),
"instantiate", 0);
205 if (mrb_undef_p(status)) {
206 ERROR(
"Running instantiate failed");
218 res = mrb_ary_new(mrb);
220 mrb_value tmp, key, val, to_cast;
222 tmp = mrb_ary_new_capa(mrb, 2);
223 key = mrb_str_new(mrb,
vp->
da->name, strlen(
vp->
da->name));
230 switch (
vp->vp_type) {
233 to_cast = mrb_str_new(mrb,
vp->vp_ptr,
vp->vp_length);
238 to_cast = mrb_nil_value();
248 to_cast = mrb_str_new(mrb,
in, len);
254 switch (
vp->vp_type) {
269 val =
vp->vp_bool ? mrb_obj_value(mrb->true_class) : mrb_obj_value(mrb->false_class);
283 val = mrb_convert_type(mrb, to_cast, MRB_TT_FIXNUM,
"Fixnum",
"to_int");
288 val = mrb_convert_type(mrb, to_cast, MRB_TT_FLOAT,
"Float",
"to_f");
296 mrb_ary_push(mrb, tmp, key);
297 mrb_ary_push(mrb, tmp, val);
298 mrb_ary_push(mrb, res, tmp);
313 for (i = 0; i < RARRAY_LEN(
value); i++) {
314 mrb_value tuple = mrb_ary_entry(
value, i);
316 char const *ckey, *cval;
322 if (mrb_type(tuple) != MRB_TT_ARRAY) {
323 REDEBUG(
"add_vp_tuple, %s: non-array passed at index %i", function_name, i);
327 if (RARRAY_LEN(tuple) != 2 && RARRAY_LEN(tuple) != 3) {
328 REDEBUG(
"add_vp_tuple, %s: array with incorrect length passed at index "
329 "%i, expected 2 or 3, got %"PRId64, function_name, i, RARRAY_LEN(tuple));
333 key = mrb_ary_entry(tuple, 0);
334 val = mrb_ary_entry(tuple, -1);
335 if (mrb_type(key) != MRB_TT_STRING) {
336 REDEBUG(
"add_vp_tuple, %s: tuple element %i must have a string as first element", function_name, i);
340 ckey = mrb_str_to_cstr(mrb, key);
341 cval = mrb_str_to_cstr(mrb, mrb_obj_as_string(mrb, val));
342 if (ckey == NULL || cval == NULL) {
343 REDEBUG(
"%s: string conv failed", function_name);
348 if (RARRAY_LEN(tuple) == 3) {
349 if (mrb_type(mrb_ary_entry(tuple, 1)) != MRB_TT_STRING) {
350 REDEBUG(
"Invalid type for operator, expected string, falling back to =");
352 char const *cop = mrb_str_to_cstr(mrb, mrb_ary_entry(tuple, 1));
354 REDEBUG(
"Invalid operator: %s, falling back to =", cop);
364 .dict_def = request->dict,
368 ERROR(
"Failed to find attribute %s", ckey);
373 ERROR(
"Attribute name %s refers to outer request but not in a tunnel, skipping...", ckey);
382 REDEBUG(
"%s: %s = %s failed", function_name, ckey, cval);
384 DEBUG(
"%s: %s = %s OK", function_name, ckey, cval);
397 memset(&res, 0,
sizeof(res));
401 mrb_iv_set(mrb, mruby_request, mrb_intern_cstr(mrb, list_name), res);
407 char const *function_name)
409 mrb_state *mrb =
inst->mrb;
410 mrb_value mruby_request, mruby_result;
412 mruby_request = mrb_obj_new(mrb,
inst->mruby_request, 0, NULL);
413 mrb_iv_set(mrb, mruby_request, mrb_intern_cstr(mrb,
"@frconfig"),
inst->mrubyconf_hash);
414 mruby_set_vps(request, mrb, mruby_request,
"@request", &request->request_pairs);
415 mruby_set_vps(request, mrb, mruby_request,
"@reply", &request->reply_pairs);
416 mruby_set_vps(request, mrb, mruby_request,
"@control", &request->control_pairs);
417 mruby_set_vps(request, mrb, mruby_request,
"@session_state", &request->session_state_pairs);
421 mruby_result = mrb_funcall(mrb, mrb_obj_value(
inst->mruby_module), function_name, 1, mruby_request);
433 switch (mrb_type(mruby_result)) {
440 if (RARRAY_LEN(mruby_result) != 3) {
441 ERROR(
"Expected array to have exactly three values, got %" PRId64
" instead", RARRAY_LEN(mruby_result));
446 if (mrb_type(mrb_ary_entry(mruby_result, 0)) != MRB_TT_FIXNUM) {
447 ERROR(
"Expected first array element to be a Fixnum, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mrb_ary_entry(mruby_result, 0))));
452 if (mrb_type(mrb_ary_entry(mruby_result, 1)) != MRB_TT_ARRAY) {
453 ERROR(
"Expected second array element to be an Array, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mrb_ary_entry(mruby_result, 1))));
455 }
else if (mrb_type(mrb_ary_entry(mruby_result, 2)) != MRB_TT_ARRAY) {
456 ERROR(
"Expected third array element to be an Array, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mrb_ary_entry(mruby_result, 2))));
460 add_vp_tuple(request->reply_ctx, request, &request->reply_pairs, mrb, mrb_ary_entry(mruby_result, 1), function_name);
461 add_vp_tuple(request->control_ctx, request, &request->control_pairs, mrb, mrb_ary_entry(mruby_result, 2), function_name);
466 ERROR(
"Expected return to be a Fixnum or an Array, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mruby_result)));
472 #define RLM_MRUBY_FUNC(foo) static unlang_action_t CC_HINT(nonnull) mod_##foo(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
474 return do_mruby(p_result, \
476 (rlm_mruby_t const *)mctx->mi->data, \
495 mrb_close(
inst->mrb);
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#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, _curr)
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
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.
@ L_DBG_WARN_REQ
Less severe warning only displayed when debugging is enabled.
@ L_DBG_ERR
Error only displayed when debugging is enabled.
@ L_DBG_ERR_REQ
Less severe error only displayed when debugging is enabled.
@ L_DBG_WARN
Warning only displayed when debugging is enabled.
@ L_INFO
Informational message.
@ L_DBG
Only displayed when debugging is enabled.
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_FLOAT64
Double precision floating point.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
module_t common
Common fields presented by all modules.
struct RClass * mruby_request_class(mrb_state *mrb, struct RClass *parent)
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.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
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.
void radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from)
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_INVALID
The module considers the request invalid.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_NOTFOUND
User not found.
@ RLM_MODULE_UPDATED
OK (pairs modified).
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
fr_dict_attr_t const * request_attr_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 mod_detach(module_detach_ctx_t const *mctx)
static int mruby_vps_to_array(request_t *request, mrb_value *out, mrb_state *mrb, fr_pair_list_t *vps)
#define RLM_MRUBY_FUNC(foo)
static unlang_action_t do_mruby(rlm_rcode_t *p_result, request_t *request, rlm_mruby_t const *inst, char const *function_name)
struct RClass * mruby_request
struct RClass * mruby_module
static mrb_value mruby_log(mrb_state *mrb, UNUSED mrb_value self)
static void add_vp_tuple(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *vps, mrb_state *mrb, mrb_value value, char const *function_name)
static void mruby_parse_config(mrb_state *mrb, CONF_SECTION *cs, int lvl, mrb_value hash)
static const conf_parser_t module_config[]
static int mod_instantiate(module_inst_ctx_t const *mctx)
static int mruby_set_vps(request_t *request, mrb_state *mrb, mrb_value mruby_request, char const *list_name, fr_pair_list_t *vps)
Translates requests between the server an an mruby interpreter.
static unsigned int hash(char const *username, unsigned int tablesize)
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 SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
int tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
Optional arguments passed to vp_tmpl functions.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
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 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.
fr_table_num_ordered_t const fr_tokens_table[]
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
static size_t char ** out