25RCSID(
"$Id: 54e131110274126e951f0ee0f11d7f7ded62a5a9 $")
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/module_rlm.h>
29#include <freeradius-devel/util/debug.h>
61 ret = strcmp(a->
name1, b->name1);
62 if (ret != 0)
return CMP(ret, 0);
63 if (!a->
name2 && !b->name2)
return 0;
64 if (!a->
name2 || !b->name2)
return a->
name2 ? 1 : -1;
65 ret = strcmp(a->
name2, b->name2);
74 mrb_get_args(mrb,
"iz", &level, &
msg);
77 return mrb_nil_value();
82 int indent_section = (lvl + 1) * 4;
83 int indent_item = (lvl + 2) * 4;
94 mrb_value sub_hash, mrubyKey;
98 mrubyKey = mrb_str_new_cstr(mrb, key);
100 if (!mrb_nil_p(mrb_hash_get(mrb,
hash, mrubyKey))) {
101 WARN(
"rlm_mruby: Ignoring duplicate config section '%s'", key);
105 sub_hash = mrb_hash_new(mrb);
106 mrb_hash_set(mrb,
hash, mrubyKey, sub_hash);
113 mrb_value mrubyKey, mrubyValue;
115 if (!key || !
value)
continue;
117 mrubyKey = mrb_str_new_cstr(mrb, key);
118 mrubyValue = mrb_str_new_cstr(mrb,
value);
120 if (!mrb_nil_p(mrb_hash_get(mrb,
hash, mrubyKey))) {
121 WARN(
"rlm_mruby: Ignoring duplicate config item '%s'", key);
125 mrb_hash_set(mrb,
hash, mrubyKey, mrubyValue);
127 DEBUG(
"%*s%s = %s", indent_item,
" ", key,
value);
131 DEBUG(
"%*s}", indent_section,
" ");
153 mrb =
inst->mrb = mrb_open();
155 ERROR(
"mruby initialization failed");
160 DEBUG(
"Creating module %s",
inst->module_name);
161 inst->mruby_module = mrb_define_module(mrb,
inst->module_name);
162 if (!
inst->mruby_module) {
163 ERROR(
"Creating module %s failed",
inst->module_name);
168 mrb_define_class_method(mrb,
inst->mruby_module,
"log",
mruby_log, MRB_ARGS_REQ(2));
170#define A(x) mrb_define_const(mrb, inst->mruby_module, #x, mrb_fixnum_value(x));
196 inst->mrubyconf_hash = mrb_hash_new(mrb);
206 inst->mruby_ptr = mrb_define_class_under(mrb,
inst->mruby_module,
"Ptr", mrb->object_class);
207 MRB_SET_INSTANCE_TT(
inst->mruby_ptr, MRB_TT_DATA);
209 DEBUG(
"Loading file %s...",
inst->filename);
210 f = fopen(
inst->filename,
"r");
212 ERROR(
"Opening file failed");
216 status = mrb_load_file(mrb, f);
218 if (mrb_undef_p(status)) {
219 ERROR(
"Parsing file failed");
230 pair_name = talloc_asprintf(func,
"func_%s_%s", func->
name1, func->
name2);
233 if (cp)
goto found_func;
235 pair_name = talloc_asprintf(func,
"func_%s", func->
name1);
242 if (mrb_nil_p(func_sym)) {
249 }
else if (func->
name2) {
252 if (mrb_nil_p(func_sym)) {
260 if (mrb_nil_p(func_sym)) {
269 if (mrb_nil_p(mrb_check_intern_cstr(mrb,
"instantiate")))
return 0;
271 status = mrb_funcall(mrb, mrb_obj_value(
inst->mruby_module),
"instantiate", 0);
272 if (mrb_undef_p(status)) {
273 ERROR(
"Running instantiate failed");
284 mrb_state *mrb =
inst->mrb;
285 mrb_value mruby_packet, mruby_result, mruby_request, mruby_reply, mruby_control, mruby_session_state;
288 mruby_packet = mrb_obj_new(mrb,
inst->mruby_request, 0, NULL);
289 mrb_iv_set(mrb, mruby_packet, mrb_intern_cstr(mrb,
"@frconfig"),
inst->mrubyconf_hash);
294 args[3] = mrb_int_value(mrb, 0);
296 mruby_request = mrb_obj_new(mrb,
inst->mruby_pair_list, 5,
args);
297 mrb_iv_set(mrb, mruby_packet, mrb_intern_cstr(mrb,
"@request"), mruby_request);
300 mruby_reply = mrb_obj_new(mrb,
inst->mruby_pair_list, 5,
args);
301 mrb_iv_set(mrb, mruby_packet, mrb_intern_cstr(mrb,
"@reply"), mruby_reply);
304 mruby_control = mrb_obj_new(mrb,
inst->mruby_pair_list, 5,
args);
305 mrb_iv_set(mrb, mruby_packet, mrb_intern_cstr(mrb,
"@control"), mruby_control);
308 mruby_session_state = mrb_obj_new(mrb,
inst->mruby_pair_list, 5,
args);
309 mrb_iv_set(mrb, mruby_packet, mrb_intern_cstr(mrb,
"@session_state"), mruby_session_state);
314 mruby_result = mrb_funcall(mrb, mrb_obj_value(
inst->mruby_module), func->
func->
function_name, 1, mruby_packet);
324 RERROR(
"Expected return to be a Fixnum, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mruby_result)));
336 mrb_close(
inst->mrb);
350 for (i = 0; i < talloc_array_length(
name); i++) {
352 if (!strchr(
"abcdefghijklmnopqrstuvwxyz1234567890", *p)) *p =
'_';
365 if (!
inst->funcs_init) {
367 inst->funcs_init =
true;
376 .offset = rule->pair.offset,
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#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
#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.
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)
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
#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.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Module instance to detach.
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.
module_t common
Common fields presented by all modules.
struct RClass * mruby_request_class(mrb_state *mrb, struct RClass *parent)
mrb_value mruby_request_object(mrb_state *mrb, struct RClass *klass, request_t *request)
mrb_value mruby_value_pair_object(mrb_state *mrb, struct RClass *klass, fr_pair_t *vp)
mrb_value mruby_dict_attr_object(mrb_state *mrb, struct RClass *klass, fr_dict_attr_t const *da)
struct RClass * mruby_pair_list_class(mrb_state *mrb, struct RClass *parent)
struct RClass * mruby_pair_class(mrb_state *mrb, struct RClass *parent)
mrb_value mruby_inst_object(mrb_state *mrb, struct RClass *klass, rlm_mruby_t const *inst)
fr_pair_t * fr_pair_list_parent(fr_pair_list_t const *list)
Return a pointer to the parent pair which contains this list.
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.
#define RETURN_UNLANG_RCODE(_rcode)
#define RETURN_UNLANG_FAIL
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.
static int mod_detach(module_detach_ctx_t const *mctx)
char * name1
Section name1 where this is called.
static void mruby_func_name_safe(char *name)
static int8_t mruby_func_def_cmp(void const *one, void const *two)
How to compare two Ruby function calls.
static unlang_action_t mod_mruby(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
char const * function_name
Name of the function being called.
char * name2
Section name2 where this is called.
static const call_env_method_t mruby_method_env
static mrb_value mruby_log(mrb_state *mrb, UNUSED mrb_value self)
fr_rb_node_t node
Node in tree of function calls.
static int mruby_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 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)
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)
#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...
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
module_flags_t flags
Flags that control how a module starts up and how a module is called.
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.
Optional arguments passed to vp_tmpl functions.
eap_aka_sim_process_conf_t * inst
static int talloc_const_free(void const *ptr)
Free const'd memory.
static size_t char ** out