The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_lua.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, version 2 if the
4 * License as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16/**
17 * $Id: 5a0ba9d9ee23a129b831b492fec70268067a5224 $
18 * @file rlm_lua.c
19 * @brief Translates requests between the server an a Lua interpreter.
20 *
21 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 *
23 * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2016 The FreeRADIUS Server Project.
25 */
26RCSID("$Id: 5a0ba9d9ee23a129b831b492fec70268067a5224 $")
27
28#define LOG_PREFIX mctx->mi->name
29
30#include <freeradius-devel/server/base.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/server/module_rlm.h>
33
34#include "lua.h"
35/*
36 * A mapping of configuration file names to internal variables.
37 *
38 * Note that the string is dynamically allocated, so it MUST
39 * be freed. When the configuration file parse re-reads the string,
40 * it free's the old one, and strdup's the new one, placing the pointer
41 * to the strdup'd string into 'config.string'. This gets around
42 * buffer over-flows.
43 */
44static const conf_parser_t module_config[] = {
46 { FR_CONF_OFFSET("func_instantiate", rlm_lua_t, func_instantiate), NULL},
47 { FR_CONF_OFFSET("func_detach", rlm_lua_t, func_detach), NULL},
48 { FR_CONF_OFFSET("func_xlat", rlm_lua_t, func_xlat), NULL},
49
51};
52
53typedef struct {
54 char const *function_name; //!< Name of the function being called
55 char *name1; //!< Section name1 where this is called
56 char *name2; //!< Section name2 where this is called
57 fr_rb_node_t node; //!< Node in tree of function calls.
59
60typedef struct {
63
64/** How to compare two Lua function calls
65 *
66 */
67static int8_t lua_func_def_cmp(void const *one, void const *two)
68{
69 lua_func_def_t const *a = one, *b = two;
70 int ret;
71
72 ret = strcmp(a->name1, b->name1);
73 if (ret != 0) return CMP(ret, 0);
74 if (!a->name2 && !b->name2) return 0;
75 if (!a->name2 || !b->name2) return a->name2 ? 1 : -1;
76 ret = strcmp(a->name2, b->name2);
77 return CMP(ret, 0);
78}
79
80static unlang_action_t mod_lua(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
81{
82 lua_call_env_t *func = talloc_get_type_abort(mctx->env_data, lua_call_env_t);
83 return fr_lua_run(p_result, mctx, request, func->func->function_name);
84}
85
86/** Free any thread specific interpreters
87 *
88 */
90{
91 rlm_lua_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_lua_thread_t);
92
93 /*
94 * May be NULL if fr_lua_init failed
95 */
96 if (t->interpreter) lua_close(t->interpreter);
97
98 return 0;
99}
100
101/** Create thread-specific connections and buffers
102 *
103 * @param[in] mctx specific data (where we write the interpreter).
104 * @return
105 * - 0 on success.
106 * - -1 on failure.
107 */
109{
110 rlm_lua_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_lua_thread_t);
111
112 if (fr_lua_init(&t->interpreter, (module_inst_ctx_t const *)mctx) < 0) return -1;
113
114 return 0;
115}
116
117/** Close the global interpreter
118 *
119 */
120static int mod_detach(module_detach_ctx_t const *mctx)
121{
122 rlm_lua_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_lua_t);
123 rlm_rcode_t ret = 0;
124
125 /*
126 * May be NULL if fr_lua_init failed
127 */
128 if (inst->interpreter) {
129 if (inst->func_detach) {
130 fr_lua_run(&ret,
131 MODULE_CTX(mctx->mi,
133 .interpreter = inst->interpreter
134 },
135 NULL, NULL),
136 NULL, inst->func_detach);
137 }
138 lua_close(inst->interpreter);
139 }
140
141 return ret;
142}
143
144static int mod_instantiate(module_inst_ctx_t const *mctx)
145{
146 rlm_lua_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_lua_t);
147 lua_func_def_t *func = NULL;
149 CONF_PAIR *cp;
150 char *pair_name;
151 rlm_rcode_t rcode;
152
153 /*
154 * Get an instance global interpreter to use with various things...
155 */
156 if (fr_lua_init(&inst->interpreter, mctx) < 0) return -1;
157 inst->jit = fr_lua_isjit(inst->interpreter);
158 if (!inst->jit) WARN("Using standard Lua interpreter, performance will be suboptimal");
159
160 DEBUG("Using %s interpreter", fr_lua_version(inst->interpreter));
161
162 /*
163 * The call_env parser has found all the places the module is called
164 * Check for config options which set the subroutine name, falling back to
165 * automatic subroutine names based on section name.
166 */
167 if (!inst->funcs_init) fr_rb_inline_init(&inst->funcs, lua_func_def_t, node, lua_func_def_cmp, NULL);
168 func = fr_rb_iter_init_inorder(&iter, &inst->funcs);
169 while (func) {
170 /*
171 * Check for func_<name1>_<name2> or func_<name1> config pairs.
172 */
173 if (func->name2) {
174 pair_name = talloc_asprintf(func, "func_%s_%s", func->name1, func->name2);
175 cp = cf_pair_find(mctx->mi->conf, pair_name);
176 talloc_free(pair_name);
177 if (cp) goto found_func;
178 }
179 pair_name = talloc_asprintf(func, "func_%s", func->name1);
180 cp = cf_pair_find(mctx->mi->conf, pair_name);
181 talloc_free(pair_name);
182 found_func:
183 if (cp){
184 func->function_name = cf_pair_value(cp);
185 if (fr_lua_check_func(mctx, inst->interpreter, func->function_name) < 0) {
186 cf_log_err(cp, "Lua function %s does not exist", func->function_name);
187 return -1;
188 }
189 /*
190 * If no pair was found, then use <name1>_<name2> or <name1> as the function to call.
191 */
192 } else if (func->name2) {
193 func->function_name = talloc_asprintf(func, "%s_%s", func->name1, func->name2);
194 if (fr_lua_check_func(mctx, inst->interpreter, func->function_name) < 0) {
196 goto name1_only;
197 }
198 } else {
199 name1_only:
200 func->function_name = func->name1;
201 if (fr_lua_check_func(mctx, inst->interpreter, func->function_name) < 0) {
202 cf_log_err(cp, "Lua function %s does not exist", func->function_name);
203 return -1;
204 }
205 }
206
207 func = fr_rb_iter_next_inorder(&iter);
208 }
209
210 if (inst->func_instantiate) {
211 fr_lua_run(&rcode,
212 MODULE_CTX(mctx->mi,
214 .interpreter = inst->interpreter
215 },
216 NULL, NULL),
217 NULL, inst->func_instantiate);
218 }
219
220 return 0;
221}
222
223/*
224 * Restrict automatic Lua function names to lowercase characters, numbers and underscore
225 * meaning that a module call in `recv Access-Request` will look for `recv_access_request`
226 */
227static void lua_func_name_safe(char *name) {
228 char *p;
229 size_t i;
230
231 p = name;
232 for (i = 0; i < talloc_array_length(name); i++) {
233 *p = tolower(*p);
234 if (!strchr("abcdefghijklmnopqrstuvwxyz1234567890", *p)) *p = '_';
235 p++;
236 }
237}
238
239static int lua_func_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, UNUSED tmpl_rules_t const *t_rules,
240 UNUSED CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
241{
242 rlm_lua_t *inst = talloc_get_type_abort(cec->mi->data, rlm_lua_t);
243 call_env_parsed_t *parsed;
244 lua_func_def_t *func;
245 void *found;
246
247 if (!inst->funcs_init) {
249 inst->funcs_init = true;
250 }
251
252 MEM(parsed = call_env_parsed_add(ctx, out,
254 .name = "func",
256 .pair = {
257 .parsed = {
258 .offset = rule->pair.offset,
260 }
261 }
262 }));
263
264 MEM(func = talloc_zero(inst, lua_func_def_t));
265 func->name1 = talloc_strdup(func, cec->asked->name1);
267 if (cec->asked->name2) {
268 func->name2 = talloc_strdup(func, cec->asked->name2);
270 }
271 if (fr_rb_find_or_insert(&found, &inst->funcs, func) < 0) {
272 talloc_free(func);
273 return -1;
274 }
275
276 /*
277 * If the function call is already in the tree, use that entry.
278 */
279 if (found) {
280 talloc_free(func);
281 call_env_parsed_set_data(parsed, found);
282 } else {
283 call_env_parsed_set_data(parsed, func);
284 }
285 return 0;
286}
287
295
296/*
297 * The module name should be the only globally exported symbol.
298 * That is, everything else should be 'static'.
299 *
300 * If the module needs to temporarily modify it's instantiation
301 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
302 * The server will then take care of ensuring that the module
303 * is single-threaded.
304 */
305extern module_rlm_t rlm_lua;
307 .common = {
308 .magic = MODULE_MAGIC_INIT,
309 .name = "lua",
310 .inst_size = sizeof(rlm_lua_t),
311
312 .thread_inst_size = sizeof(rlm_lua_thread_t),
313
314 .config = module_config,
315 .instantiate = mod_instantiate,
316 .thread_instantiate = mod_thread_instantiate,
317
318 .detach = mod_detach,
319 .thread_detach = mod_thread_detach
320 },
321 .method_group = {
322 .bindings = (module_method_binding_t[]){
323 { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_lua, .method_env = &lua_method_env },
325 }
326 }
327};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define RCSID(id)
Definition build.h:485
#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
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:644
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:701
#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
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
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1593
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define CF_IDENT_ANY
Definition cf_util.h:78
#define MEM(x)
Definition debug.h:36
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
talloc_free(reap)
unlang_action_t fr_lua_run(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, char const *funcname)
Definition lua.c:753
char const * fr_lua_version(lua_State *L)
Definition lua.c:605
bool fr_lua_isjit(lua_State *L)
Check whether the Lua interpreter were actually linked to is LuaJIT.
Definition lua.c:591
int fr_lua_check_func(module_inst_ctx_t const *mctx, lua_State *L, char const *name)
Check if a given function was loaded into an index in the global table.
Definition lua.c:634
int fr_lua_init(lua_State **out, module_inst_ctx_t const *mctx)
Initialise a new Lua/LuaJIT interpreter.
Definition lua.c:892
Library function signatures for lua module.
lua_State * interpreter
Thread specific interpreter.
Definition lua.h:61
void * env_data
Per call environment data.
Definition module_ctx.h:44
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
void * thread
Thread instance data.
Definition module_ctx.h:67
#define MODULE_CTX(_mi, _thread, _env_data, _rctx)
Wrapper to create a module_ctx_t as a compound literal.
Definition module_ctx.h:128
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
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
#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
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
module_rlm_t rlm_lua
Definition rlm_lua.c:306
static int mod_detach(module_detach_ctx_t const *mctx)
Close the global interpreter.
Definition rlm_lua.c:120
static const call_env_method_t lua_method_env
Definition rlm_lua.c:288
fr_rb_node_t node
Node in tree of function calls.
Definition rlm_lua.c:57
char const * function_name
Name of the function being called.
Definition rlm_lua.c:54
lua_func_def_t * func
Definition rlm_lua.c:61
static unlang_action_t mod_lua(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_lua.c:80
char * name2
Section name2 where this is called.
Definition rlm_lua.c:56
static void lua_func_name_safe(char *name)
Definition rlm_lua.c:227
char * name1
Section name1 where this is called.
Definition rlm_lua.c:55
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Create thread-specific connections and buffers.
Definition rlm_lua.c:108
static int8_t lua_func_def_cmp(void const *one, void const *two)
How to compare two Lua function calls.
Definition rlm_lua.c:67
static const conf_parser_t module_config[]
Definition rlm_lua.c:44
static int lua_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_lua.c:239
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Free any thread specific interpreters.
Definition rlm_lua.c:89
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_lua.c:144
static char const * name
#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
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:330
size_t inst_size
Size of the module's instance data.
Definition module.h:204
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
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
eap_aka_sim_process_conf_t * inst
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
static size_t char ** out
Definition value.h:1012