The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_mruby.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 9545797fed89ff723f40c42ca6fc197322c61c73 $
19 * @file rlm_mruby.c
20 * @brief Translates requests between the server an an mruby interpreter.
21 *
22 * @copyright 2016 Herwin Weststrate (freeradius@herwinw.nl)
23 * @copyright 2016 The FreeRADIUS server project
24 */
25RCSID("$Id: 9545797fed89ff723f40c42ca6fc197322c61c73 $")
26
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>
31
32#include "rlm_mruby.h"
33
34typedef struct {
35 char const *function_name; //!< Name of the function being called
36 char *name1; //!< Section name1 where this is called
37 char *name2; //!< Section name2 where this is called
38 fr_rb_node_t node; //!< Node in tree of function calls.
40
44
45/*
46 * Define a structure for our module configuration.
47 *
48 * These variables do not need to be in a structure, but it's
49 * a lot cleaner to do so, and a pointer to the structure can
50 * be used as the instance handle.
51 */
52typedef struct {
53 char const *filename;
54 char const *module_name;
55
56 fr_rb_tree_t funcs; //!< Tree of function calls found by call_env parser.
57 bool funcs_init; //!< Has the tree been initialised.
58
59 mrb_state *mrb;
60
61 struct RClass *mruby_module;
62 struct RClass *mruby_request;
63 mrb_value mrubyconf_hash;
65
66/*
67 * A mapping of configuration file names to internal variables.
68 */
69static const conf_parser_t module_config[] = {
71 { FR_CONF_OFFSET("module", rlm_mruby_t, module_name), .dflt = "Radiusd" },
73};
74
75/** How to compare two Ruby function calls
76 *
77 */
78static int8_t mruby_func_def_cmp(void const *one, void const *two)
79{
80 mruby_func_def_t const *a = one, *b = two;
81 int ret;
82
83 ret = strcmp(a->name1, b->name1);
84 if (ret != 0) return CMP(ret, 0);
85 if (!a->name2 && !b->name2) return 0;
86 if (!a->name2 || !b->name2) return a->name2 ? 1 : -1;
87 ret = strcmp(a->name2, b->name2);
88 return CMP(ret, 0);
89}
90
91static mrb_value mruby_log(mrb_state *mrb, UNUSED mrb_value self)
92{
93 mrb_int level;
94 char *msg = NULL;
95
96 mrb_get_args(mrb, "iz", &level, &msg);
97 fr_log(&default_log, level, __FILE__, __LINE__, "rlm_ruby: %s", msg);
98
99 return mrb_nil_value();
100}
101
102static void mruby_parse_config(mrb_state *mrb, CONF_SECTION *cs, int lvl, mrb_value hash)
103{
104 int indent_section = (lvl + 1) * 4;
105 int indent_item = (lvl + 2) * 4;
106 CONF_ITEM *ci = NULL;
107
108 if (!cs) return;
109
110 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
111
112 while ((ci = cf_item_next(cs, ci))) {
113 if (cf_item_is_section(ci)) {
114 CONF_SECTION *sub_cs = cf_item_to_section(ci);
115 char const *key = cf_section_name1(sub_cs);
116 mrb_value sub_hash, mrubyKey;
117
118 if (!key) continue;
119
120 mrubyKey = mrb_str_new_cstr(mrb, key);
121
122 if (!mrb_nil_p(mrb_hash_get(mrb, hash, mrubyKey))) {
123 WARN("rlm_mruby: Ignoring duplicate config section '%s'", key);
124 continue;
125 }
126
127 sub_hash = mrb_hash_new(mrb);
128 mrb_hash_set(mrb, hash, mrubyKey, sub_hash);
129
130 mruby_parse_config(mrb, sub_cs, lvl + 1, sub_hash);
131 } else if (cf_item_is_pair(ci)) {
132 CONF_PAIR *cp = cf_item_to_pair(ci);
133 const char *key = cf_pair_attr(cp);
134 const char *value = cf_pair_value(cp);
135 mrb_value mrubyKey, mrubyValue;
136
137 if (!key || !value) continue;
138
139 mrubyKey = mrb_str_new_cstr(mrb, key);
140 mrubyValue = mrb_str_new_cstr(mrb, value);
141
142 if (!mrb_nil_p(mrb_hash_get(mrb, hash, mrubyKey))) {
143 WARN("rlm_mruby: Ignoring duplicate config item '%s'", key);
144 continue;
145 }
146
147 mrb_hash_set(mrb, hash, mrubyKey, mrubyValue);
148
149 DEBUG("%*s%s = %s", indent_item, " ", key, value);
150 }
151 }
152
153 DEBUG("%*s}", indent_section, " ");
154}
155
156/*
157 * Do any per-module initialization that is separate to each
158 * configured instance of the module. e.g. set up connections
159 * to external databases, read configuration files, set up
160 * dictionary entries, etc.
161 */
162static int mod_instantiate(module_inst_ctx_t const *mctx)
163{
164 rlm_mruby_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_mruby_t);
166 mruby_func_def_t *func = NULL;
167 mrb_state *mrb;
168 CONF_SECTION *cs;
169 FILE *f;
170 mrb_value status;
171 char *pair_name;
172 CONF_PAIR *cp;
173 mrb_value func_sym;
174
175 mrb = inst->mrb = mrb_open();
176 if (!mrb) {
177 ERROR("mruby initialization failed");
178 return -1;
179 }
180
181 /* Define the freeradius module */
182 DEBUG("Creating module %s", inst->module_name);
183 inst->mruby_module = mrb_define_module(mrb, inst->module_name);
184 if (!inst->mruby_module) {
185 ERROR("Creating module %s failed", inst->module_name);
186 return -1;
187 }
188
189 /* Define the log method */
190 mrb_define_class_method(mrb, inst->mruby_module, "log", mruby_log, MRB_ARGS_REQ(2));
191
192#define A(x) mrb_define_const(mrb, inst->mruby_module, #x, mrb_fixnum_value(x));
193 /* Define the logging constants */
194 A(L_DBG);
195 A(L_WARN);
196 A(L_INFO);
197 A(L_ERR);
198 A(L_WARN);
199 A(L_DBG_WARN);
200 A(L_DBG_ERR);
203
204 /* Define the return value constants */
215#undef A
216
217 /* Convert a FreeRADIUS config structure into a mruby hash */
218 inst->mrubyconf_hash = mrb_hash_new(mrb);
219 cs = cf_section_find(mctx->mi->conf, "config", NULL);
220 if (cs) mruby_parse_config(mrb, cs, 0, inst->mrubyconf_hash);
221
222 /* Define the Request class */
223 inst->mruby_request = mruby_request_class(mrb, inst->mruby_module);
224
225 DEBUG("Loading file %s...", inst->filename);
226 f = fopen(inst->filename, "r");
227 if (!f) {
228 ERROR("Opening file failed");
229 return -1;
230 }
231
232 status = mrb_load_file(mrb, f);
233 fclose(f);
234 if (mrb_undef_p(status)) {
235 ERROR("Parsing file failed");
236 return -1;
237 }
238
239 if (!inst->funcs_init) fr_rb_inline_init(&inst->funcs, mruby_func_def_t, node, mruby_func_def_cmp, NULL);
240 func = fr_rb_iter_init_inorder(&iter, &inst->funcs);
241 while (func) {
242 /*
243 * Check for func_<name1>_<name2> or func_<name1> config pairs.
244 */
245 if (func->name2) {
246 pair_name = talloc_asprintf(func, "func_%s_%s", func->name1, func->name2);
247 cp = cf_pair_find(mctx->mi->conf, pair_name);
248 talloc_free(pair_name);
249 if (cp) goto found_func;
250 }
251 pair_name = talloc_asprintf(func, "func_%s", func->name1);
252 cp = cf_pair_find(mctx->mi->conf, pair_name);
253 talloc_free(pair_name);
254 found_func:
255 if (cp){
256 func->function_name = cf_pair_value(cp);
257 func_sym = mrb_check_intern_cstr(mrb, func->function_name);
258 if (mrb_nil_p(func_sym)) {
259 cf_log_err(cp, "mruby function %s does not exist", func->function_name);
260 return -1;
261 }
262 /*
263 * If no pair was found, then use <name1>_<name2> or <name1> as the function to call.
264 */
265 } else if (func->name2) {
266 func->function_name = talloc_asprintf(func, "%s_%s", func->name1, func->name2);
267 func_sym = mrb_check_intern_cstr(mrb, func->function_name);
268 if (mrb_nil_p(func_sym)) {
270 goto name1_only;
271 }
272 } else {
273 name1_only:
274 func->function_name = func->name1;
275 func_sym = mrb_check_intern_cstr(mrb, func->function_name);
276 if (mrb_nil_p(func_sym)) {
277 cf_log_err(cp, "mruby function %s does not exist", func->function_name);
278 return -1;
279 }
280 }
281
282 func = fr_rb_iter_next_inorder(&iter);
283 }
284
285 status = mrb_funcall(mrb, mrb_obj_value(inst->mruby_module), "instantiate", 0);
286 if (mrb_undef_p(status)) {
287 ERROR("Running instantiate failed");
288 return -1;
289 }
290
291 return 0;
292}
293
294static int mruby_vps_to_array(request_t *request, mrb_value *out, mrb_state *mrb, fr_pair_list_t *vps)
295{
296 mrb_value res;
297 fr_pair_t *vp;
298
299 res = mrb_ary_new(mrb);
300 for (vp = fr_pair_list_head(vps); vp; vp = fr_pair_list_next(vps, vp)) {
301 mrb_value tmp, key, val, to_cast;
302
303 tmp = mrb_ary_new_capa(mrb, 2);
304 key = mrb_str_new(mrb, vp->da->name, strlen(vp->da->name));
305
306 /*
307 * The only way to create floats, doubles, bools etc,
308 * is to feed mruby the string representation and have
309 * it convert to its internal types.
310 */
311 switch (vp->vp_type) {
312 case FR_TYPE_STRING:
313 case FR_TYPE_OCTETS:
314 to_cast = mrb_str_new(mrb, vp->vp_ptr, vp->vp_length);
315 break;
316
317 case FR_TYPE_BOOL:
318#ifndef NDEBUG
319 to_cast = mrb_nil_value(); /* Not needed but clang flags it */
320#endif
321 break;
322
323 default:
324 {
325 char *in;
326 size_t len;
327
328 len = fr_value_box_aprint(request, &in, &vp->data, NULL);
329 to_cast = mrb_str_new(mrb, in, len);
331 }
332 break;
333 }
334
335 switch (vp->vp_type) {
336 case FR_TYPE_STRING:
337 case FR_TYPE_OCTETS:
342 case FR_TYPE_IFID:
343 case FR_TYPE_ETHERNET:
346 val = to_cast; /* No conversions required */
347 break;
348
349 case FR_TYPE_BOOL:
350 val = vp->vp_bool ? mrb_obj_value(mrb->true_class) : mrb_obj_value(mrb->false_class);
351 break;
352
353 case FR_TYPE_UINT8:
354 case FR_TYPE_UINT16:
355 case FR_TYPE_UINT32:
356 case FR_TYPE_UINT64:
357 case FR_TYPE_INT8:
358 case FR_TYPE_INT16:
359 case FR_TYPE_INT32:
360 case FR_TYPE_INT64:
361 case FR_TYPE_DATE:
363 case FR_TYPE_SIZE:
364 val = mrb_convert_type(mrb, to_cast, MRB_TT_FIXNUM, "Fixnum", "to_int");
365 break;
366
367 case FR_TYPE_FLOAT32:
368 case FR_TYPE_FLOAT64:
369 val = mrb_convert_type(mrb, to_cast, MRB_TT_FLOAT, "Float", "to_f");
370 break;
371
372 case FR_TYPE_NON_LEAF:
373 fr_assert(0);
374 return -1;
375 }
376
377 mrb_ary_push(mrb, tmp, key);
378 mrb_ary_push(mrb, tmp, val);
379 mrb_ary_push(mrb, res, tmp);
380
381 *out = res;
382 }
383
384 return 0;
385}
386
387static 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)
388{
389 int i;
390 fr_pair_list_t tmp_list;
391
392 fr_pair_list_init(&tmp_list);
393
394 for (i = 0; i < RARRAY_LEN(value); i++) {
395 mrb_value tuple = mrb_ary_entry(value, i);
396 mrb_value key, val;
397 char const *ckey, *cval;
398 fr_pair_t *vp;
399 tmpl_t *dst;
400 fr_token_t op = T_OP_EQ;
401
402 /* This tuple should be an array of length 2 */
403 if (mrb_type(tuple) != MRB_TT_ARRAY) {
404 REDEBUG("add_vp_tuple, %s: non-array passed at index %i", function_name, i);
405 continue;
406 }
407
408 if (RARRAY_LEN(tuple) != 2 && RARRAY_LEN(tuple) != 3) {
409 REDEBUG("add_vp_tuple, %s: array with incorrect length passed at index "
410 "%i, expected 2 or 3, got %"PRId64, function_name, i, RARRAY_LEN(tuple));
411 continue;
412 }
413
414 key = mrb_ary_entry(tuple, 0);
415 val = mrb_ary_entry(tuple, -1);
416 if (mrb_type(key) != MRB_TT_STRING) {
417 REDEBUG("add_vp_tuple, %s: tuple element %i must have a string as first element", function_name, i);
418 continue;
419 }
420
421 ckey = mrb_str_to_cstr(mrb, key);
422 cval = mrb_str_to_cstr(mrb, mrb_obj_as_string(mrb, val));
423 if (ckey == NULL || cval == NULL) {
424 REDEBUG("%s: string conv failed", function_name);
425 continue;
426 }
427
428
429 if (RARRAY_LEN(tuple) == 3) {
430 if (mrb_type(mrb_ary_entry(tuple, 1)) != MRB_TT_STRING) {
431 REDEBUG("Invalid type for operator, expected string, falling back to =");
432 } else {
433 char const *cop = mrb_str_to_cstr(mrb, mrb_ary_entry(tuple, 1));
434 if (!(op = fr_table_value_by_str(fr_tokens_table, cop, 0))) {
435 REDEBUG("Invalid operator: %s, falling back to =", cop);
436 op = T_OP_EQ;
437 }
438 }
439 }
440 DEBUG("%s: %s %s %s", function_name, ckey, fr_table_str_by_value(fr_tokens_table, op, "="), cval);
441
442 if (tmpl_afrom_attr_str(request, NULL, &dst, ckey,
443 &(tmpl_rules_t){
444 .attr = {
445 .dict_def = request->proto_dict,
446 .list_def = request_attr_reply,
447 }
448 }) <= 0) {
449 ERROR("Failed to find attribute %s", ckey);
450 continue;
451 }
452
453 if (tmpl_request_ptr(&request, tmpl_request(dst)) < 0) {
454 ERROR("Attribute name %s refers to outer request but not in a tunnel, skipping...", ckey);
455 talloc_free(dst);
456 continue;
457 }
458
460 talloc_free(dst);
461
462 if (fr_pair_value_from_str(vp, cval, strlen(cval), NULL, false) < 0) {
463 REDEBUG("%s: %s = %s failed", function_name, ckey, cval);
464 } else {
465 DEBUG("%s: %s = %s OK", function_name, ckey, cval);
466 }
467
468 fr_pair_append(&tmp_list, vp);
469 }
470 radius_pairmove(request, vps, &tmp_list);
471}
472
473static inline int mruby_set_vps(request_t *request, mrb_state *mrb, mrb_value mruby_request,
474 char const *list_name, fr_pair_list_t *vps)
475{
476 mrb_value res;
477
478 memset(&res, 0, sizeof(res)); /* clang scan */
479
480 if (mruby_vps_to_array(request, &res, mrb, vps) < 0) return -1;
481
482 mrb_iv_set(mrb, mruby_request, mrb_intern_cstr(mrb, list_name), res);
483
484 return 0;
485}
486
487static unlang_action_t CC_HINT(nonnull) mod_mruby(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
488{
489 rlm_mruby_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_mruby_t);
490 mruby_call_env_t *func = talloc_get_type_abort(mctx->env_data, mruby_call_env_t);
491 mrb_state *mrb = inst->mrb;
492 mrb_value mruby_request, mruby_result;
493
494 mruby_request = mrb_obj_new(mrb, inst->mruby_request, 0, NULL);
495 mrb_iv_set(mrb, mruby_request, mrb_intern_cstr(mrb, "@frconfig"), inst->mrubyconf_hash);
496 mruby_set_vps(request, mrb, mruby_request, "@request", &request->request_pairs);
497 mruby_set_vps(request, mrb, mruby_request, "@reply", &request->reply_pairs);
498 mruby_set_vps(request, mrb, mruby_request, "@control", &request->control_pairs);
499 mruby_set_vps(request, mrb, mruby_request, "@session_state", &request->session_state_pairs);
500
502DIAG_OFF(class-varargs)
503 mruby_result = mrb_funcall(mrb, mrb_obj_value(inst->mruby_module), func->func->function_name, 1, mruby_request);
504DIAG_ON(class-varargs)
506
507 /* Two options for the return value:
508 * - a fixnum: convert to rlm_rcode_t, and return that
509 * - an array: this should have exactly three items in it. The first one
510 * should be a fixnum, this will once again be converted to
511 * rlm_rcode_t and eventually returned. The other two items
512 * should be arrays. The items of the first array should be
513 * merged into reply, the second array into control.
514 */
515 switch (mrb_type(mruby_result)) {
516 /* If it is a Fixnum: return that value */
517 case MRB_TT_FIXNUM:
518 RETURN_MODULE_RCODE((rlm_rcode_t)mrb_int(mrb, mruby_result));
519
520 case MRB_TT_ARRAY:
521 /* Must have exactly three items */
522 if (RARRAY_LEN(mruby_result) != 3) {
523 ERROR("Expected array to have exactly three values, got %" PRId64 " instead", RARRAY_LEN(mruby_result));
525 }
526
527 /* First item must be a Fixnum, this will be the return type */
528 if (mrb_type(mrb_ary_entry(mruby_result, 0)) != MRB_TT_FIXNUM) {
529 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))));
531 }
532
533 /* Second and third items must be Arrays, these will be the updates for reply and control */
534 if (mrb_type(mrb_ary_entry(mruby_result, 1)) != MRB_TT_ARRAY) {
535 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))));
537 } else if (mrb_type(mrb_ary_entry(mruby_result, 2)) != MRB_TT_ARRAY) {
538 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))));
540 }
541
542 add_vp_tuple(request->reply_ctx, request, &request->reply_pairs, mrb, mrb_ary_entry(mruby_result, 1), func->func->function_name);
543 add_vp_tuple(request->control_ctx, request, &request->control_pairs, mrb, mrb_ary_entry(mruby_result, 2), func->func->function_name);
544 RETURN_MODULE_RCODE((rlm_rcode_t)mrb_int(mrb, mrb_ary_entry(mruby_result, 0)));
545
546 default:
547 /* Invalid return type */
548 ERROR("Expected return to be a Fixnum or an Array, got %s instead", RSTRING_PTR(mrb_obj_as_string(mrb, mruby_result)));
550 }
551}
552
553/*
554 * Only free memory we allocated. The strings allocated via
555 * cf_section_parse() do not need to be freed.
556 */
557static int mod_detach(module_detach_ctx_t const *mctx)
558{
559 rlm_mruby_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_mruby_t);
560
561 mrb_close(inst->mrb);
562
563 return 0;
564}
565
566/*
567 * Restrict automatic Ruby function names to lowercase characters, numbers and underscore
568 * meaning that a module call in `recv Access-Request` will look for `recv_access_request`
569 */
570static void mruby_func_name_safe(char *name) {
571 char *p;
572 size_t i;
573
574 p = name;
575 for (i = 0; i < talloc_array_length(name); i++) {
576 *p = tolower(*p);
577 if (!strchr("abcdefghijklmnopqrstuvwxyz1234567890", *p)) *p = '_';
578 p++;
579 }
580}
581
582static int mruby_func_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, UNUSED tmpl_rules_t const *t_rules,
583 UNUSED CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
584{
585 rlm_mruby_t *inst = talloc_get_type_abort(cec->mi->data, rlm_mruby_t);
586 call_env_parsed_t *parsed;
587 mruby_func_def_t *func;
588 void *found;
589
590 if (!inst->funcs_init) {
592 inst->funcs_init = true;
593 }
594
595 MEM(parsed = call_env_parsed_add(ctx, out,
597 .name = "func",
599 .pair = {
600 .parsed = {
601 .offset = rule->pair.offset,
603 }
604 }
605 }));
606
607 MEM(func = talloc_zero(inst, mruby_func_def_t));
608 func->name1 = talloc_strdup(func, cec->asked->name1);
610 if (cec->asked->name2) {
611 func->name2 = talloc_strdup(func, cec->asked->name2);
613 }
614 if (fr_rb_find_or_insert(&found, &inst->funcs, func) < 0) {
615 talloc_free(func);
616 return -1;
617 }
618
619 /*
620 * If the function call is already in the tree, use that entry.
621 */
622 if (found) {
623 talloc_free(func);
624 call_env_parsed_set_data(parsed, found);
625 } else {
626 call_env_parsed_set_data(parsed, func);
627 }
628 return 0;
629}
630
638
639/*
640 * The module name should be the only globally exported symbol.
641 * That is, everything else should be 'static'.
642 *
643 * If the module needs to temporarily modify it's instantiation
644 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
645 * The server will then take care of ensuring that the module
646 * is single-threaded.
647 */
650 .common = {
651 .magic = MODULE_MAGIC_INIT,
652 .name = "mruby",
653 .flags = MODULE_TYPE_THREAD_UNSAFE, /* Not sure */
654 .inst_size = sizeof(rlm_mruby_t),
657 .detach = mod_detach,
658 },
659 .method_group = {
660 .bindings = (module_method_binding_t[]){
661 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_mruby, .method_env = &mruby_method_env },
663 }
664 }
665};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:485
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:458
#define DIAG_ON(_x)
Definition build.h:460
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
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.
Definition call_env.c:646
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
Definition call_env.c:703
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
#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...
Definition call_env.h:240
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
section_name_t const * asked
The actual name1/name2 that resolved to a module_method_binding_t.
Definition call_env.h:232
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition call_env.h:85
@ CALL_ENV_FLAG_PARSE_MISSING
If this subsection is missing, still parse it.
Definition call_env.h:88
@ CALL_ENV_PARSE_TYPE_VOID
Output of the parsing phase is undefined (a custom structure).
Definition call_env.h:62
module_instance_t const * mi
Module instance that the callenv is registered to.
Definition call_env.h:229
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
Definition call_env.h:412
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:658
#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
Definition cf_parse.h:284
#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
Definition cf_parse.h:272
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:434
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition cf_parse.h:440
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:595
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:631
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1027
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:683
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition cf_util.c:1438
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:617
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1593
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1577
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_item_next(_parent, _curr)
Definition cf_util.h:92
#define CF_IDENT_ANY
Definition cf_util.h:78
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
static fr_slen_t in
Definition dict.h:840
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
talloc_free(reap)
fr_log_t default_log
Definition log.c:292
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.
Definition log.c:581
@ L_DBG_WARN_REQ
Less severe warning only displayed when debugging is enabled.
Definition log.h:63
@ L_WARN
Warning.
Definition log.h:57
@ L_ERR
Error message.
Definition log.h:56
@ L_DBG_ERR
Error only displayed when debugging is enabled.
Definition log.h:62
@ L_DBG_ERR_REQ
Less severe error only displayed when debugging is enabled.
Definition log.h:64
@ L_DBG_WARN
Warning only displayed when debugging is enabled.
Definition log.h:61
@ L_INFO
Informational message.
Definition log.h:55
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
@ 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.
void * env_data
Per call environment data.
Definition module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
struct RClass * mruby_request_class(mrb_state *mrb, struct RClass *parent)
Definition mruby.c:53
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.
Definition pair.c:2599
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1351
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.
Definition pair.c:287
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
void radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from)
Definition pairmove.c:44
static const conf_parser_t config[]
Definition base.c:183
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define WARN(fmt,...)
Definition radclient.h:47
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
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.
Definition rb.c:598
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Definition rb.h:180
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
The main red black tree structure.
Definition rb.h:73
#define RETURN_MODULE_RCODE(_rcode)
Definition rcode.h:66
#define RETURN_MODULE_FAIL
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:51
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
fr_dict_attr_t const * request_attr_reply
Definition request.c:44
static int mod_detach(module_detach_ctx_t const *mctx)
Definition rlm_mruby.c:557
mrb_value mrubyconf_hash
Definition rlm_mruby.c:63
mruby_func_def_t * func
Definition rlm_mruby.c:42
char const * filename
Definition rlm_mruby.c:53
mrb_state * mrb
Definition rlm_mruby.c:59
char * name1
Section name1 where this is called.
Definition rlm_mruby.c:36
static int mruby_vps_to_array(request_t *request, mrb_value *out, mrb_state *mrb, fr_pair_list_t *vps)
Definition rlm_mruby.c:294
#define A(x)
static unlang_action_t mod_mruby(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_mruby.c:487
char const * module_name
Definition rlm_mruby.c:54
struct RClass * mruby_request
Definition rlm_mruby.c:62
static void mruby_func_name_safe(char *name)
Definition rlm_mruby.c:570
static int8_t mruby_func_def_cmp(void const *one, void const *two)
How to compare two Ruby function calls.
Definition rlm_mruby.c:78
struct RClass * mruby_module
Definition rlm_mruby.c:61
fr_rb_tree_t funcs
Tree of function calls found by call_env parser.
Definition rlm_mruby.c:56
char const * function_name
Name of the function being called.
Definition rlm_mruby.c:35
bool funcs_init
Has the tree been initialised.
Definition rlm_mruby.c:57
char * name2
Section name2 where this is called.
Definition rlm_mruby.c:37
static const call_env_method_t mruby_method_env
Definition rlm_mruby.c:631
static mrb_value mruby_log(mrb_state *mrb, UNUSED mrb_value self)
Definition rlm_mruby.c:91
fr_rb_node_t node
Node in tree of function calls.
Definition rlm_mruby.c:38
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)
Definition rlm_mruby.c:387
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)
Definition rlm_mruby.c:582
static void mruby_parse_config(mrb_state *mrb, CONF_SECTION *cs, int lvl, mrb_value hash)
Definition rlm_mruby.c:102
module_rlm_t rlm_mruby
Definition rlm_mruby.c:649
static const conf_parser_t module_config[]
Definition rlm_mruby.c:69
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_mruby.c:162
static int mruby_set_vps(request_t *request, mrb_state *mrb, mrb_value mruby_request, char const *list_name, fr_pair_list_t *vps)
Definition rlm_mruby.c:473
Translates requests between the server an an mruby interpreter.
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1313
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
Definition section.h:46
char const * name1
First section name. Usually a verb like 'recv', 'send', etc...
Definition section.h:45
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition module.h:48
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:228
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:330
void * data
Module's instance data.
Definition module.h:272
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
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.
Definition tmpl_eval.c:163
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:229
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:34
enum fr_token fr_token_t
@ T_OP_EQ
Definition token.h:83
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.
Definition pair_inline.c:69
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
#define FR_TYPE_NON_LEAF
Definition types.h:314
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
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1020