The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_python.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: 764dbff74487a6f02aafdeddd95805617881da3b $
19 * @file rlm_python.c
20 * @brief Translates requests between the server an a python interpreter.
21 *
22 * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
23 *
24 * @copyright 2000,2006,2015-2016 The FreeRADIUS server project
25 * @copyright 2002 Miguel A.L. Paraz (mparaz@mparaz.com)
26 * @copyright 2002 Imperium Technology, Inc.
27 */
28RCSID("$Id: 764dbff74487a6f02aafdeddd95805617881da3b $")
29
30#define LOG_PREFIX mctx->mi->name
31
32#include <freeradius-devel/server/base.h>
33#include <freeradius-devel/server/module_rlm.h>
34#include <freeradius-devel/server/pairmove.h>
35#include <freeradius-devel/util/debug.h>
36#include <freeradius-devel/util/lsan.h>
37
38#include <Python.h>
39#include <frameobject.h> /* Python header not pulled in by default. */
40#include <libgen.h>
41#include <dlfcn.h>
42
43/** Specifies the module.function to load for processing a section
44 *
45 */
46typedef struct {
47 PyObject *module; //!< Python reference to module.
48 PyObject *function; //!< Python reference to function in module.
49
50 char const *module_name; //!< String name of module.
51 char const *function_name; //!< String name of function in module.
53
54/** An instance of the rlm_python module
55 *
56 */
57typedef struct {
58 char const *name; //!< Name of the module instance
59 PyThreadState *interpreter; //!< The interpreter used for this instance of rlm_python.
60 PyObject *module; //!< Local, interpreter specific module.
61
70
71 PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
72 //!< made available to the python script.
74
75/** Global config for python library
76 *
77 */
78typedef struct {
79 char const *path; //!< Path to search for python files in.
80 bool path_include_default; //!< Include the default python path in `path`
82
83/** Tracks a python module inst/thread state pair
84 *
85 * Multiple instances of python create multiple interpreters and each
86 * thread must have a PyThreadState per interpreter, to track execution.
87 */
88typedef struct {
89 PyThreadState *state; //!< Module instance/thread specific state.
91
92static void *python_dlhandle;
93static PyThreadState *global_interpreter; //!< Our first interpreter.
94
95static module_ctx_t const *current_mctx; //!< Used for communication with inittab functions.
96static CONF_SECTION *current_conf; //!< Used for communication with inittab functions.
97
99 .path = NULL,
100 .path_include_default = true
101};
102
104 { FR_CONF_OFFSET("path", libpython_global_config_t, path) },
105 { FR_CONF_OFFSET("path_include_default", libpython_global_config_t, path_include_default) },
107};
108
109static int libpython_init(void);
110static void libpython_free(void);
111
113 .name = "python",
114 .config = python_global_config,
115 .init = libpython_init,
116 .free = libpython_free,
118};
119
120extern global_lib_autoinst_t const * const rlm_python_lib[];
125
126/*
127 * As of Python 3.8 the GIL will be per-interpreter
128 * If there are still issues with CEXTs,
129 * multiple interpreters and the GIL at that point
130 * users can build rlm_python against Python 3.8
131 * and the horrible hack of using a single interpreter
132 * for all instances of rlm_python will no longer be
133 * required.
134 *
135 * As Python 3.x module initialisation is significantly
136 * different than Python 2.x initialisation,
137 * it'd be a pain to retain the cext_compat for
138 * Python 3 and as Python 3 users have the option of
139 * using as version of Python which fixes the underlying
140 * issue, we only support using a global interpreter
141 * for Python 2.7 and below.
142 */
143
144/*
145 * A mapping of configuration file names to internal variables.
146 */
148
149#define A(x) { FR_CONF_OFFSET("mod_" #x, rlm_python_t, x.module_name), .dflt = "${.module}" }, \
150 { FR_CONF_OFFSET("func_" #x, rlm_python_t, x.function_name) },
151
153 A(authorize)
154 A(authenticate)
155 A(preacct)
156 A(accounting)
157 A(post_auth)
158 A(detach)
159
160#undef A
161
163};
164
165static struct {
166 char const *name;
167 int value;
169
170#define A(x) { #x, x },
171
172 A(L_DBG)
173 A(L_WARN)
174 A(L_INFO)
175 A(L_ERR)
176 A(L_WARN)
178 A(L_DBG_ERR)
191
192#undef A
193
194 { NULL, 0 },
196
197/*
198 * radiusd Python functions
199 */
200
201/** Allow fr_log to be called from python
202 *
203 */
204static PyObject *mod_log(UNUSED PyObject *module, PyObject *args)
205{
206 int status;
207 char *msg;
208
209 if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
210 Py_RETURN_NONE;
211 }
212
213 fr_log(&default_log, status, __FILE__, __LINE__, "%s", msg);
214
215 Py_RETURN_NONE;
216}
217
218static PyMethodDef module_methods[] = {
219 { "log", &mod_log, METH_VARARGS,
220 "freeradius.log(level, msg)\n\n" \
221 "Print a message using the freeradius daemon's logging system. level should be one of the\n" \
222 "following constants L_DBG, L_WARN, L_INFO, L_ERR, L_DBG_WARN, L_DBG_ERR, L_DBG_WARN_REQ, L_DBG_ERR_REQ\n"
223 },
224 { NULL, NULL, 0, NULL },
225};
226
227/** Print out the current error
228 *
229 * Must be called with a valid thread state set
230 */
231static void python_error_log(module_ctx_t const *mctx, request_t *request)
232{
233 PyObject *p_type = NULL, *p_value = NULL, *p_traceback = NULL, *p_str_1 = NULL, *p_str_2 = NULL;
234
235 PyErr_Fetch(&p_type, &p_value, &p_traceback);
236 PyErr_NormalizeException(&p_type, &p_value, &p_traceback);
237 if (!p_type || !p_value) goto failed;
238
239 if (((p_str_1 = PyObject_Str(p_type)) == NULL) || ((p_str_2 = PyObject_Str(p_value)) == NULL)) goto failed;
240
241 ROPTIONAL(RERROR, ERROR, "%s (%s)", PyUnicode_AsUTF8(p_str_1), PyUnicode_AsUTF8(p_str_2));
242
243 if (p_traceback != Py_None) {
244 PyTracebackObject *ptb = (PyTracebackObject*)p_traceback;
245 size_t fnum = 0;
246
247 while (ptb != NULL) {
248 PyFrameObject *cur_frame = ptb->tb_frame;
249#if PY_VERSION_HEX >= 0x030A0000
250 PyCodeObject *code = PyFrame_GetCode(cur_frame);
251
252 ROPTIONAL(RERROR, ERROR, "[%ld] %s:%d at %s()",
253 fnum,
254 PyUnicode_AsUTF8(code->co_filename),
255 PyFrame_GetLineNumber(cur_frame),
256 PyUnicode_AsUTF8(code->co_name)
257 );
258 Py_XDECREF(code);
259#else
260 ROPTIONAL(RERROR, ERROR, "[%ld] %s:%d at %s()",
261 fnum,
262 PyUnicode_AsUTF8(cur_frame->f_code->co_filename),
263 PyFrame_GetLineNumber(cur_frame),
264 PyUnicode_AsUTF8(cur_frame->f_code->co_name)
265 );
266#endif
267
268 ptb = ptb->tb_next;
269 fnum++;
270 }
271 }
272
273failed:
274 Py_XDECREF(p_str_1);
275 Py_XDECREF(p_str_2);
276 Py_XDECREF(p_type);
277 Py_XDECREF(p_value);
278 Py_XDECREF(p_traceback);
279}
280
281static void mod_vptuple(TALLOC_CTX *ctx, module_ctx_t const *mctx, request_t *request,
282 fr_pair_list_t *vps, PyObject *p_value, char const *funcname, char const *list_name)
283{
284 int i;
285 Py_ssize_t tuple_len;
286 tmpl_t *dst;
287 fr_pair_t *vp;
288 request_t *current = request;
289 fr_pair_list_t tmp_list;
290
291 fr_pair_list_init(&tmp_list);
292 /*
293 * If the Python function gave us None for the tuple,
294 * then just return.
295 */
296 if (p_value == Py_None) return;
297
298 if (!PyTuple_CheckExact(p_value)) {
299 ERROR("%s - non-tuple passed to %s", funcname, list_name);
300 return;
301 }
302 /* Get the tuple tuple_len. */
303 tuple_len = PyTuple_GET_SIZE(p_value);
304 for (i = 0; i < tuple_len; i++) {
305 PyObject *p_tuple_element = PyTuple_GET_ITEM(p_value, i);
306 PyObject *p_str_1;
307 PyObject *p_str_2;
308 Py_ssize_t pair_len;
309 char const *s1;
310 char const *s2;
311
312 if (!PyTuple_CheckExact(p_tuple_element)) {
313 ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
314 continue;
315 }
316 /* Check if it's a pair */
317
318 pair_len = PyTuple_GET_SIZE(p_tuple_element);
319 if ((pair_len < 2) || (pair_len > 3)) {
320 ERROR("%s - Tuple element %d of %s is a tuple of size %zu. Must be 2 or 3",
321 funcname, i, list_name, pair_len);
322 continue;
323 }
324
325 p_str_1 = PyTuple_GET_ITEM(p_tuple_element, 0);
326 p_str_2 = PyTuple_GET_ITEM(p_tuple_element, pair_len - 1);
327
328 if ((!PyUnicode_CheckExact(p_str_1)) || (!PyUnicode_CheckExact(p_str_2))) {
329 ERROR("%s - Tuple element %d of %s must be as (str, str)",
330 funcname, i, list_name);
331 continue;
332 }
333 s1 = PyUnicode_AsUTF8(p_str_1);
334 s2 = PyUnicode_AsUTF8(p_str_2);
335
336 if (tmpl_afrom_attr_str(ctx, NULL, &dst, s1,
337 &(tmpl_rules_t){
338 .attr = {
339 .dict_def = request->dict,
340 .list_def = request_attr_reply,
342 }
343 }) <= 0) {
344 PERROR("%s - Failed to find attribute %s.%s", funcname, list_name, s1);
345 continue;
346 }
347
348 if (tmpl_request_ptr(&current, tmpl_request(dst)) < 0) {
349 ERROR("%s - Attribute name %s.%s refers to outer request but not in a tunnel, skipping...",
350 funcname, list_name, s1);
351 talloc_free(dst);
352 continue;
353 }
354
356 talloc_free(dst);
357
358 if (fr_pair_value_from_str(vp, s2, strlen(s2), NULL, false) < 0) {
359 DEBUG("%s - Failed: '%s.%s' = '%s'", funcname, list_name, s1, s2);
360 } else {
361 DEBUG("%s - '%s.%s' = '%s'", funcname, list_name, s1, s2);
362 }
363
364 fr_pair_append(&tmp_list, vp);
365 }
366 radius_pairmove(request, vps, &tmp_list);
367}
368
369
370/*
371 * This is the core Python function that the others wrap around.
372 * Pass the value-pair print strings in a tuple.
373 */
374static int mod_populate_vptuple(module_ctx_t const *mctx, request_t *request, PyObject *pp, fr_pair_t *vp)
375{
376 PyObject *attribute = NULL;
377 PyObject *value = NULL;
378
379 attribute = PyUnicode_FromString(vp->da->name);
380 if (!attribute) return -1;
381
382 switch (vp->vp_type) {
383 case FR_TYPE_STRING:
384 value = PyUnicode_FromStringAndSize(vp->vp_strvalue, vp->vp_length);
385 break;
386
387 case FR_TYPE_OCTETS:
388 value = PyBytes_FromStringAndSize((char const *)vp->vp_octets, vp->vp_length);
389 break;
390
391 case FR_TYPE_BOOL:
392 value = PyBool_FromLong(vp->vp_bool);
393 break;
394
395 case FR_TYPE_UINT8:
396 value = PyLong_FromUnsignedLong(vp->vp_uint8);
397 break;
398
399 case FR_TYPE_UINT16:
400 value = PyLong_FromUnsignedLong(vp->vp_uint16);
401 break;
402
403 case FR_TYPE_UINT32:
404 value = PyLong_FromUnsignedLong(vp->vp_uint32);
405 break;
406
407 case FR_TYPE_UINT64:
408 value = PyLong_FromUnsignedLongLong(vp->vp_uint64);
409 break;
410
411 case FR_TYPE_INT8:
412 value = PyLong_FromLong(vp->vp_int8);
413 break;
414
415 case FR_TYPE_INT16:
416 value = PyLong_FromLong(vp->vp_int16);
417 break;
418
419 case FR_TYPE_INT32:
420 value = PyLong_FromLong(vp->vp_int32);
421 break;
422
423 case FR_TYPE_INT64:
424 value = PyLong_FromLongLong(vp->vp_int64);
425 break;
426
427 case FR_TYPE_FLOAT32:
428 value = PyFloat_FromDouble((double) vp->vp_float32);
429 break;
430
431 case FR_TYPE_FLOAT64:
432 value = PyFloat_FromDouble(vp->vp_float64);
433 break;
434
435 case FR_TYPE_SIZE:
436 value = PyLong_FromSize_t(vp->vp_size);
437 break;
438
440 case FR_TYPE_DATE:
441 case FR_TYPE_IFID:
448 case FR_TYPE_ETHERNET:
449 {
450 ssize_t slen;
451 char buffer[256];
452
453 slen = fr_value_box_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), &vp->data, NULL);
454 if (slen < 0) {
455 error:
456 ROPTIONAL(REDEBUG, ERROR, "Failed marshalling %pP to Python value", vp);
457 python_error_log(mctx, request);
458 Py_XDECREF(attribute);
459 return -1;
460 }
461 value = PyUnicode_FromStringAndSize(buffer, (size_t)slen);
462 }
463 break;
464
465 case FR_TYPE_NON_LEAF:
466 {
467 fr_pair_t *child_vp;
468 int child_len, i = 0;
469
470 child_len = fr_pair_list_num_elements(&vp->vp_group);
471 if (child_len == 0) {
472 Py_INCREF(Py_None);
473 value = Py_None;
474 break;
475 }
476
477 if ((value = PyTuple_New(child_len)) == NULL) goto error;
478
479 for (child_vp = fr_pair_list_head(&vp->vp_group);
480 child_vp;
481 child_vp = fr_pair_list_next(&vp->vp_group, child_vp), i++) {
482 PyObject *child_pp;
483
484 if ((child_pp = PyTuple_New(2)) == NULL) {
485 Py_DECREF(value);
486 goto error;
487 }
488
489 if (mod_populate_vptuple(mctx, request, child_pp, child_vp) == 0) {
490 PyTuple_SET_ITEM(value, i, child_pp);
491 } else {
492 Py_INCREF(Py_None);
493 PyTuple_SET_ITEM(value, i, Py_None);
494 Py_DECREF(child_pp);
495 }
496 }
497 }
498 break;
499 }
500
501 if (value == NULL) goto error;
502
503 PyTuple_SET_ITEM(pp, 0, attribute);
504 PyTuple_SET_ITEM(pp, 1, value);
505
506 return 0;
507}
508
510 request_t *request, PyObject *p_func, char const *funcname)
511{
512 fr_pair_t *vp;
513 PyObject *p_ret = NULL;
514 PyObject *p_arg = NULL;
515 int tuple_len;
517
518 /*
519 * We will pass a tuple containing (name, value) tuples
520 * We can safely use the Python function to build up a
521 * tuple, since the tuple is not used elsewhere.
522 *
523 * Determine the size of our tuple by walking through the packet.
524 * If request is NULL, pass None.
525 */
526 tuple_len = 0;
527 if (request != NULL) {
528 tuple_len = fr_pair_list_num_elements(&request->request_pairs);
529 }
530
531 if (tuple_len == 0) {
532 Py_INCREF(Py_None);
533 p_arg = Py_None;
534 } else {
535 int i = 0;
536 if ((p_arg = PyTuple_New(tuple_len)) == NULL) {
537 rcode = RLM_MODULE_FAIL;
538 goto finish;
539 }
540
541 for (vp = fr_pair_list_head(&request->request_pairs);
542 vp;
543 vp = fr_pair_list_next(&request->request_pairs, vp), i++) {
544 PyObject *pp;
545
546 /* The inside tuple has two only: */
547 if ((pp = PyTuple_New(2)) == NULL) {
548 rcode = RLM_MODULE_FAIL;
549 goto finish;
550 }
551
552 if (mod_populate_vptuple(mctx, request, pp, vp) == 0) {
553 /* Put the tuple inside the container */
554 PyTuple_SET_ITEM(p_arg, i, pp);
555 } else {
556 Py_INCREF(Py_None);
557 PyTuple_SET_ITEM(p_arg, i, Py_None);
558 Py_DECREF(pp);
559 }
560 }
561 }
562
563 /* Call Python function. */
564 p_ret = PyObject_CallFunctionObjArgs(p_func, p_arg, NULL);
565 if (!p_ret) {
566 python_error_log(mctx, request); /* Needs valid thread with GIL */
567 rcode = RLM_MODULE_FAIL;
568 goto finish;
569 }
570
571 if (!request) {
572 // check return code at module instantiation time
573 if (PyNumber_Check(p_ret)) rcode = PyLong_AsLong(p_ret);
574 goto finish;
575 }
576
577 /*
578 * The function returns either:
579 * 1. (returnvalue, replyTuple, configTuple), where
580 * - returnvalue is one of the constants RLM_*
581 * - replyTuple and configTuple are tuples of string
582 * tuples of size 2
583 *
584 * 2. the function return value alone
585 *
586 * 3. None - default return value is set
587 *
588 * xxx This code is messy!
589 */
590 if (PyTuple_CheckExact(p_ret)) {
591 PyObject *p_tuple_int;
592
593 if (PyTuple_GET_SIZE(p_ret) != 3) {
594 ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
595 rcode = RLM_MODULE_FAIL;
596 goto finish;
597 }
598
599 p_tuple_int = PyTuple_GET_ITEM(p_ret, 0);
600 if (!PyNumber_Check(p_tuple_int)) {
601 ERROR("%s - First tuple element not an integer", funcname);
602 rcode = RLM_MODULE_FAIL;
603 goto finish;
604 }
605 /* Now have the return value */
606 rcode = PyLong_AsLong(p_tuple_int);
607 /* Reply item tuple */
608 mod_vptuple(request->reply_ctx, mctx, request, &request->reply_pairs,
609 PyTuple_GET_ITEM(p_ret, 1), funcname, "reply");
610 /* Config item tuple */
611 mod_vptuple(request->control_ctx, mctx, request, &request->control_pairs,
612 PyTuple_GET_ITEM(p_ret, 2), funcname, "config");
613
614 } else if (PyNumber_Check(p_ret)) {
615 /* Just an integer */
616 rcode = PyLong_AsLong(p_ret);
617
618 } else if (p_ret == Py_None) {
619 /* returned 'None', return value defaults to "OK, continue." */
620 rcode = RLM_MODULE_OK;
621 } else {
622 /* Not tuple or None */
623 ERROR("%s - Function did not return a tuple or None", funcname);
624 rcode = RLM_MODULE_FAIL;
625 goto finish;
626 }
627
628finish:
629 if (rcode == RLM_MODULE_FAIL) python_error_log(mctx, request);
630 Py_XDECREF(p_arg);
631 Py_XDECREF(p_ret);
632
633 RETURN_MODULE_RCODE(rcode);
634}
635
636/** Thread safe call to a python function
637 *
638 * Will swap in thread state specific to module/thread.
639 */
640static unlang_action_t do_python(rlm_rcode_t *p_result, module_ctx_t const *mctx,
641 request_t *request, PyObject *p_func, char const *funcname)
642{
643 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
644 rlm_rcode_t rcode;
645
646 /*
647 * It's a NOOP if the function wasn't defined
648 */
649 if (!p_func) RETURN_MODULE_NOOP;
650
651 RDEBUG3("Using thread state %p/%p", mctx->mi->data, t->state);
652
653 PyEval_RestoreThread(t->state); /* Swap in our local thread state */
654 do_python_single(&rcode, mctx, request, p_func, funcname);
655 (void)fr_cond_assert(PyEval_SaveThread() == t->state);
656
657 RETURN_MODULE_RCODE(rcode);
658}
659
660#define MOD_FUNC(x) \
661static unlang_action_t CC_HINT(nonnull) mod_##x(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
662{ \
663 rlm_python_t const *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_python_t); \
664 return do_python(p_result, mctx, request, inst->x.function, #x);\
665}
666
667MOD_FUNC(authenticate)
668MOD_FUNC(authorize)
669MOD_FUNC(preacct)
670MOD_FUNC(accounting)
671MOD_FUNC(post_auth)
672
673static void python_obj_destroy(PyObject **ob)
674{
675 if (*ob != NULL) {
676 Py_DECREF(*ob);
677 *ob = NULL;
678 }
679}
680
682{
684 python_obj_destroy(&def->module);
685}
686
687/** Import a user module and load a function from it
688 *
689 */
691{
692 char const *funcname = "python_function_load";
693
694 if (def->module_name == NULL || def->function_name == NULL) return 0;
695
696 LSAN_DISABLE(def->module = PyImport_ImportModule(def->module_name));
697 if (!def->module) {
698 ERROR("%s - Module '%s' load failed", funcname, def->module_name);
699 error:
701 Py_XDECREF(def->function);
702 def->function = NULL;
703 Py_XDECREF(def->module);
704 def->module = NULL;
705
706 return -1;
707 }
708
709 def->function = PyObject_GetAttrString(def->module, def->function_name);
710 if (!def->function) {
711 ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
712 goto error;
713 }
714
715 if (!PyCallable_Check(def->function)) {
716 ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
717 goto error;
718 }
719
720 DEBUG2("Loaded function '%s.%s'", def->module_name, def->function_name);
721 return 0;
722}
723
724/*
725 * Parse a configuration section, and populate a dict.
726 * This function is recursively called (allows to have nested dicts.)
727 */
728static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
729{
730 int indent_section = (lvl * 4);
731 int indent_item = (lvl + 1) * 4;
732 int ret = 0;
733 CONF_ITEM *ci = NULL;
734
735 if (!cs || !dict) return -1;
736
737 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
738
739 while ((ci = cf_item_next(cs, ci))) {
740 /*
741 * This is a section.
742 * Create a new dict, store it in current dict,
743 * Then recursively call python_parse_config with this section and the new dict.
744 */
745 if (cf_item_is_section(ci)) {
746 CONF_SECTION *sub_cs = cf_item_to_section(ci);
747 char const *key = cf_section_name1(sub_cs); /* dict key */
748 PyObject *sub_dict, *p_key;
749
750 p_key = PyUnicode_FromString(key);
751 if (!p_key) {
752 ERROR("Failed converting config key \"%s\" to python string", key);
753 return -1;
754 }
755
756 if (PyDict_Contains(dict, p_key)) {
757 WARN("Ignoring duplicate config section '%s'", key);
758 continue;
759 }
760
761 MEM(sub_dict = PyDict_New());
762 (void)PyDict_SetItem(dict, p_key, sub_dict);
763
764 ret = python_parse_config(mctx, sub_cs, lvl + 1, sub_dict);
765 if (ret < 0) break;
766 } else if (cf_item_is_pair(ci)) {
767 CONF_PAIR *cp = cf_item_to_pair(ci);
768 char const *key = cf_pair_attr(cp); /* dict key */
769 char const *value = cf_pair_value(cp); /* dict value */
770 PyObject *p_key, *p_value;
771
772 if (!value) {
773 WARN("Skipping \"%s\" as it has no value", key);
774 continue;
775 }
776
777 p_key = PyUnicode_FromString(key);
778 p_value = PyUnicode_FromString(value);
779 if (!p_key) {
780 ERROR("Failed converting config key \"%s\" to python string", key);
781 return -1;
782 }
783 if (!p_value) {
784 ERROR("Failed converting config value \"%s\" to python string", value);
785 return -1;
786 }
787
788 /*
789 * This is an item.
790 * Store item attr / value in current dict.
791 */
792 if (PyDict_Contains(dict, p_key)) {
793 WARN("Ignoring duplicate config item '%s'", key);
794 continue;
795 }
796
797 (void)PyDict_SetItem(dict, p_key, p_value);
798
799 DEBUG("%*s%s = \"%s\"", indent_item, " ", key, value);
800 }
801 }
802
803 DEBUG("%*s}", indent_section, " ");
804
805 return ret;
806}
807
808/** Make the current instance's config available within the module we're initialising
809 *
810 */
811static int python_module_import_config(module_inst_ctx_t const *mctx, CONF_SECTION *conf, PyObject *module)
812{
813 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
814 CONF_SECTION *cs;
815
816 /*
817 * Convert a FreeRADIUS config structure into a python
818 * dictionary.
819 */
820 inst->pythonconf_dict = PyDict_New();
821 if (!inst->pythonconf_dict) {
822 ERROR("Unable to create python dict for config");
823 error:
824 Py_XDECREF(inst->pythonconf_dict);
825 inst->pythonconf_dict = NULL;
827 return -1;
828 }
829
830 cs = cf_section_find(conf, "config", NULL);
831 if (cs) {
832 DEBUG("Inserting \"config\" section into python environment as radiusd.config");
833 if (python_parse_config(mctx, cs, 0, inst->pythonconf_dict) < 0) goto error;
834 }
835
836 /*
837 * Add module configuration as a dict
838 */
839 if (PyModule_AddObject(module, "config", inst->pythonconf_dict) < 0) goto error;
840
841 return 0;
842}
843
844/** Import integer constants into the module we're initialising
845 *
846 */
847static int python_module_import_constants(module_inst_ctx_t const *mctx, PyObject *module)
848{
849 size_t i;
850
851 for (i = 0; freeradius_constants[i].name; i++) {
852 if ((PyModule_AddIntConstant(module, freeradius_constants[i].name, freeradius_constants[i].value)) < 0) {
853 ERROR("Failed adding constant to module");
855 return -1;
856 }
857 }
858
859 return 0;
860}
861
862/*
863 * Python 3 interpreter initialisation and destruction
864 */
865static PyObject *python_module_init(void)
866{
867 PyObject *module;
868
869 static struct PyModuleDef py_module_def = {
870 PyModuleDef_HEAD_INIT,
871 .m_name = "freeradius",
872 .m_doc = "freeRADIUS python module",
873 .m_size = -1,
874 .m_methods = module_methods
875 };
876
878
879 module = PyModule_Create(&py_module_def);
880 if (!module) {
882 Py_RETURN_NONE;
883 }
884
885 return module;
886}
887
889{
890 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
891 CONF_SECTION *conf = mctx->mi->conf;
892 PyObject *module;
893
894 /*
895 * python_module_init takes no args, so we need
896 * to set these globals so that when it's
897 * called during interpreter initialisation
898 * it can get at the current instance config.
899 */
902
903 PyEval_RestoreThread(global_interpreter);
904 LSAN_DISABLE(inst->interpreter = Py_NewInterpreter());
905 if (!inst->interpreter) {
906 ERROR("Failed creating new interpreter");
907 return -1;
908 }
909 DEBUG3("Created new interpreter %p", inst->interpreter);
910 PyEval_SaveThread(); /* Unlock GIL */
911
912 PyEval_RestoreThread(inst->interpreter);
913
914 /*
915 * Import the radiusd module into this python
916 * environment. Each interpreter gets its
917 * own copy which it can mutate as much as
918 * it wants.
919 */
920 module = PyImport_ImportModule("freeradius");
921 if (!module) {
922 ERROR("Failed importing \"freeradius\" module into interpreter %p", inst->interpreter);
923 return -1;
924 }
925 if ((python_module_import_config(mctx, conf, module) < 0) ||
926 (python_module_import_constants(mctx, module) < 0)) {
927 Py_DECREF(module);
928 return -1;
929 }
930 inst->module = module;
931 PyEval_SaveThread();
932
933 return 0;
934}
935
936static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
937{
938 /*
939 * We incremented the reference count earlier
940 * during module initialisation.
941 */
942 Py_XDECREF(inst->module);
943
944 PyEval_RestoreThread(interp); /* Switches thread state and locks GIL */
945 Py_EndInterpreter(interp); /* Destroys interpreter (GIL still locked) - sets thread state to NULL */
946 PyThreadState_Swap(global_interpreter); /* Get a none-null thread state */
947 PyEval_SaveThread(); /* Unlock GIL */
948}
949
950/*
951 * Do any per-module initialization that is separate to each
952 * configured instance of the module. e.g. set up connections
953 * to external databases, read configuration files, set up
954 * dictionary entries, etc.
955 *
956 * If configuration information is given in the config section
957 * that must be referenced in later calls, store a handle to it
958 * in *instance otherwise put a null pointer there.
959 *
960 */
961static int mod_instantiate(module_inst_ctx_t const *mctx)
962{
963 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
964
965 if (python_interpreter_init(mctx) < 0) return -1;
966
967 /*
968 * Switch to our module specific interpreter
969 */
970 PyEval_RestoreThread(inst->interpreter);
971
972 /*
973 * Process the various sections
974 */
975#define PYTHON_FUNC_LOAD(_x) if (python_function_load(mctx, &inst->_x) < 0) goto error
977 PYTHON_FUNC_LOAD(authenticate);
978 PYTHON_FUNC_LOAD(authorize);
979 PYTHON_FUNC_LOAD(preacct);
980 PYTHON_FUNC_LOAD(accounting);
981 PYTHON_FUNC_LOAD(post_auth);
982 PYTHON_FUNC_LOAD(detach);
983
984 /*
985 * Call the instantiate function.
986 */
987 if (inst->instantiate.function) {
988 rlm_rcode_t rcode;
989
990 do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->instantiate.function, "instantiate");
991 switch (rcode) {
992 case RLM_MODULE_FAIL:
994 error:
995 fr_cond_assert(PyEval_SaveThread() == inst->interpreter);
996 python_interpreter_free(inst, inst->interpreter);
997 return -1;
998
999 default:
1000 break;
1001 }
1002 }
1003
1004 /*
1005 * Switch back to the global interpreter
1006 */
1007 if (!fr_cond_assert(PyEval_SaveThread() == inst->interpreter)) goto error;
1008
1009 return 0;
1010}
1011
1012static int mod_detach(module_detach_ctx_t const *mctx)
1013{
1014 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
1015
1016 /*
1017 * If we don't have a interpreter
1018 * we didn't get far enough into
1019 * instantiation to generate things
1020 * we need to clean up...
1021 */
1022 if (!inst->interpreter) return 0;
1023
1024 /*
1025 * Call module destructor
1026 */
1027 PyEval_RestoreThread(inst->interpreter);
1028
1029 /*
1030 * We don't care if this fails.
1031 */
1032 if (inst->detach.function) {
1033 rlm_rcode_t rcode;
1034
1035 (void)do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->detach.function, "detach");
1036 }
1037
1038#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
1040 PYTHON_FUNC_DESTROY(authorize);
1041 PYTHON_FUNC_DESTROY(authenticate);
1042 PYTHON_FUNC_DESTROY(preacct);
1043 PYTHON_FUNC_DESTROY(accounting);
1044 PYTHON_FUNC_DESTROY(post_auth);
1045 PYTHON_FUNC_DESTROY(detach);
1046
1047 Py_XDECREF(inst->pythonconf_dict);
1048 PyEval_SaveThread();
1049
1050 /*
1051 * Free the module specific interpreter
1052 */
1053 python_interpreter_free(inst, inst->interpreter);
1054
1055 return 0;
1056}
1057
1059{
1060 PyThreadState *state;
1061 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
1062 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1063
1064 state = PyThreadState_New(inst->interpreter->interp);
1065 if (!state) {
1066 ERROR("Failed initialising local PyThreadState");
1067 return -1;
1068 }
1069
1070 DEBUG3("Initialised new thread state %p", state);
1071 t->state = state;
1072
1073 return 0;
1074}
1075
1077{
1078 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1079
1080 PyEval_RestoreThread(t->state); /* Swap in our local thread state */
1081 PyThreadState_Clear(t->state);
1082 PyEval_SaveThread();
1083
1084 PyThreadState_Delete(t->state); /* Don't need to hold lock for this */
1085
1086 return 0;
1087}
1088
1089static int libpython_init(void)
1090{
1091#define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_python - " _fmt, ## __VA_ARGS__)
1092#define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1093 &(fr_log_perror_format_t){ \
1094 .first_prefix = "rlm_python - ", \
1095 .subsq_prefix = "rlm_python - ", \
1096 }, \
1097 _fmt, ## __VA_ARGS__)
1098 PyConfig config;
1099 PyStatus status;
1100 wchar_t *wide_name;
1101 char *path;
1102
1103 fr_assert(!Py_IsInitialized());
1104
1105 LOAD_INFO("Python version: %s", Py_GetVersion());
1106 dependency_version_number_add(NULL, "python", Py_GetVersion());
1107
1108 /*
1109 * Load python using RTLD_GLOBAL and dlopen.
1110 * This fixes issues where python C extensions
1111 * can't find the symbols they need.
1112 */
1113 python_dlhandle = dl_open_by_sym("Py_IsInitialized", RTLD_NOW | RTLD_GLOBAL);
1114 if (!python_dlhandle) LOAD_WARN("Failed loading libpython symbols into global symbol table");
1115
1116 PyConfig_InitPythonConfig(&config);
1117
1118 /*
1119 * Set program name (i.e. the software calling the interpreter)
1120 * The value of argv[0] as a wide char string
1121 */
1122 wide_name = Py_DecodeLocale(main_config->name, NULL);
1123 status = PyConfig_SetString(&config, &config.program_name, wide_name);
1124 PyMem_RawFree(wide_name);
1125
1126 if (PyStatus_Exception(status)) {
1127 fail:
1128 LOAD_WARN("%s", status.err_msg);
1129 PyConfig_Clear(&config);
1130 return -1;
1131 }
1132
1133 /*
1134 * Python 3 introduces the concept of a
1135 * "inittab", i.e. a list of modules which
1136 * are automatically created when the first
1137 * interpreter is spawned.
1138 */
1139 PyImport_AppendInittab("freeradius", python_module_init);
1140
1142 wchar_t *wide_path = Py_DecodeLocale(libpython_global_config.path, NULL);
1143
1145 /*
1146 * The path from config is to be used in addition to the default.
1147 * Set it in the pythonpath_env.
1148 */
1149 status = PyConfig_SetString(&config, &config.pythonpath_env, wide_path);
1150 } else {
1151 /*
1152 * Only the path from config is to be used.
1153 * Setting module_search_paths_set to 1 disables any automatic paths.
1154 */
1155 config.module_search_paths_set = 1;
1156 status = PyWideStringList_Append(&config.module_search_paths, wide_path);
1157 }
1158 PyMem_RawFree(wide_path);
1159 if (PyStatus_Exception(status)) goto fail;
1160 }
1161
1162 config.install_signal_handlers = 0; /* Don't override signal handlers - noop on subs calls */
1163
1164 LSAN_DISABLE(status = Py_InitializeFromConfig(&config));
1165 if (PyStatus_Exception(status)) goto fail;
1166
1167 PyConfig_Clear(&config);
1168
1169 /*
1170 * Report the path
1171 */
1172 path = Py_EncodeLocale(Py_GetPath(), NULL);
1173 LOAD_INFO("Python path set to \"%s\"", path);
1174 PyMem_Free(path);
1175
1176 global_interpreter = PyEval_SaveThread(); /* Store reference to the main interpreter and release the GIL */
1177
1178 return 0;
1179}
1180
1181static void libpython_free(void)
1182{
1183 PyThreadState_Swap(global_interpreter); /* Swap to the main thread */
1184
1185 /*
1186 * PyImport_Cleanup - Leaks memory in python 3.6
1187 * should check once we require 3.8 that this is
1188 * still needed.
1189 */
1190 LSAN_DISABLE(Py_Finalize()); /* Ignore leaks on exit, we don't reload modules so we don't care */
1191 if (python_dlhandle) dlclose(python_dlhandle); /* dlclose will SEGV on null handle */
1192}
1193
1194/*
1195 * The module name should be the only globally exported symbol.
1196 * That is, everything else should be 'static'.
1197 *
1198 * If the module needs to temporarily modify it's instantiation
1199 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1200 * The server will then take care of ensuring that the module
1201 * is single-threaded.
1202 */
1205 .common = {
1206 .magic = MODULE_MAGIC_INIT,
1207 .name = "python",
1208
1209 .inst_size = sizeof(rlm_python_t),
1210 .thread_inst_size = sizeof(rlm_python_thread_t),
1211
1212 .config = module_config,
1213
1214 .instantiate = mod_instantiate,
1215 .detach = mod_detach,
1216
1217 .thread_instantiate = mod_thread_instantiate,
1218 .thread_detach = mod_thread_detach
1219 },
1220 .method_group = {
1221 .bindings = (module_method_binding_t[]){
1222 /*
1223 * Hack to support old configurations
1224 */
1225 { .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
1226 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
1227 { .section = SECTION_NAME("authorize", CF_IDENT_ANY), .method = mod_authorize },
1228
1229 { .section = SECTION_NAME("recv", "accounting-request"), .method = mod_preacct },
1230 { .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
1231
1232 { .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_post_auth },
1234 }
1235 }
1236};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
static int const char char buffer[256]
Definition acutest.h:576
log_entry msg
Definition acutest.h:794
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:483
#define UNUSED
Definition build.h:315
#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
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:632
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1171
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:1028
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:684
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:618
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:664
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1594
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1578
#define cf_item_next(_ci, _curr)
Definition cf_util.h:92
#define CF_IDENT_ANY
Definition cf_util.h:78
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
Add a library/server version pair to the main configuration.
Definition dependency.c:153
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
Test enumeration values.
Definition dict_test.h:92
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
Definition dl.c:186
#define RTLD_NOW
Definition dl.c:44
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
char const * name
Name of library and section within global config.
Definition global_lib.h:39
#define GLOBAL_LIB_TERMINATOR
Definition global_lib.h:51
Structure to define how to initialise libraries with global configuration.
Definition global_lib.h:38
#define PERROR(_fmt,...)
Definition log.h:228
#define DEBUG3(_fmt,...)
Definition log.h:266
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:528
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RERROR(fmt,...)
Definition log.h:298
talloc_free(reap)
fr_log_t default_log
Definition log.c:291
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:583
@ 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
#define LSAN_DISABLE(_x)
Definition lsan.h:41
main_config_t const * main_config
Main server configuration.
Definition main_config.c:69
char const * name
Name of the daemon, usually 'radiusd'.
Definition main_config.h:52
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
@ 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.
long int ssize_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
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_FROM_INST(_mctx)
Wrapper to create a module_ctx_t as a compound literal from a module_inst_ctx_t.
Definition module_ctx.h:138
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
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
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:1345
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:283
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
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.
Definition pair.c:2589
void radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from)
Definition pairmove.c:45
static const conf_parser_t config[]
Definition base.c:183
#define fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define DEBUG2(fmt,...)
Definition radclient.h:43
#define WARN(fmt,...)
Definition radclient.h:47
static rs_t * conf
Definition radsniff.c:53
#define RETURN_MODULE_NOOP
Definition rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition rcode.h:64
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:50
@ 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:46
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_chap.c:228
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_chap.c:176
static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_detail.c:359
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_detail.c:375
static int libpython_init(void)
PyObject * pythonconf_dict
Configuration parameters defined in the module made available to the python script.
Definition rlm_python.c:71
static int mod_detach(module_detach_ctx_t const *mctx)
PyObject *python_func_def_t authenticate
Definition rlm_python.c:65
static void python_function_destroy(python_func_def_t *def)
Definition rlm_python.c:681
static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
Definition rlm_python.c:728
static int python_module_import_config(module_inst_ctx_t const *mctx, CONF_SECTION *conf, PyObject *module)
Make the current instance's config available within the module we're initialising.
Definition rlm_python.c:811
PyObject *python_func_def_t accounting
Definition rlm_python.c:67
#define A(x)
PyObject *python_func_def_t preacct
Definition rlm_python.c:66
static struct @167 freeradius_constants[]
static global_lib_autoinst_t rlm_python_autoinst
Definition rlm_python.c:112
static void libpython_free(void)
PyThreadState * interpreter
The interpreter used for this instance of rlm_python.
Definition rlm_python.c:59
module_rlm_t rlm_python
PyObject *python_func_def_t detach
Definition rlm_python.c:69
static void python_obj_destroy(PyObject **ob)
Definition rlm_python.c:673
static void mod_vptuple(TALLOC_CTX *ctx, module_ctx_t const *mctx, request_t *request, fr_pair_list_t *vps, PyObject *p_value, char const *funcname, char const *list_name)
Definition rlm_python.c:281
PyObject *python_func_def_t instantiate
< Local, interpreter specific module.
Definition rlm_python.c:63
char const * module_name
String name of module.
Definition rlm_python.c:50
PyThreadState * state
Module instance/thread specific state.
Definition rlm_python.c:89
char const * name
Name of the module instance.
Definition rlm_python.c:58
#define MOD_FUNC(x)
Definition rlm_python.c:660
static PyThreadState * global_interpreter
Our first interpreter.
Definition rlm_python.c:93
bool path_include_default
Include the default python path in path
Definition rlm_python.c:80
static int mod_populate_vptuple(module_ctx_t const *mctx, request_t *request, PyObject *pp, fr_pair_t *vp)
Definition rlm_python.c:374
#define LOAD_WARN(_fmt,...)
static unlang_action_t do_python(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PyObject *p_func, char const *funcname)
Thread safe call to a python function.
Definition rlm_python.c:640
static PyObject * python_module_init(void)
Definition rlm_python.c:865
PyObject *PyObject * function
< Python reference to module.
Definition rlm_python.c:48
static conf_parser_t const python_global_config[]
Definition rlm_python.c:103
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
Definition rlm_python.c:936
static int python_function_load(module_inst_ctx_t const *mctx, python_func_def_t *def)
Import a user module and load a function from it.
Definition rlm_python.c:690
PyObject *python_func_def_t post_auth
Definition rlm_python.c:68
static libpython_global_config_t libpython_global_config
Definition rlm_python.c:98
char const * function_name
String name of function in module.
Definition rlm_python.c:51
static module_ctx_t const * current_mctx
Used for communication with inittab functions.
Definition rlm_python.c:95
static CONF_SECTION * current_conf
Used for communication with inittab functions.
Definition rlm_python.c:96
static unlang_action_t do_python_single(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PyObject *p_func, char const *funcname)
Definition rlm_python.c:509
#define LOAD_INFO(_fmt,...)
#define PYTHON_FUNC_LOAD(_x)
static void * python_dlhandle
Definition rlm_python.c:92
PyObject *python_func_def_t authorize
Definition rlm_python.c:64
static void python_error_log(module_ctx_t const *mctx, request_t *request)
Print out the current error.
Definition rlm_python.c:231
static int python_interpreter_init(module_inst_ctx_t const *mctx)
Definition rlm_python.c:888
char const * path
Path to search for python files in.
Definition rlm_python.c:79
#define PYTHON_FUNC_DESTROY(_x)
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_python.c:961
static int python_module_import_constants(module_inst_ctx_t const *mctx, PyObject *module)
Import integer constants into the module we're initialising.
Definition rlm_python.c:847
global_lib_autoinst_t const *const rlm_python_lib[]
Definition rlm_python.c:121
static conf_parser_t module_config[]
Definition rlm_python.c:147
static PyMethodDef module_methods[]
Definition rlm_python.c:218
static PyObject * mod_log(UNUSED PyObject *module, PyObject *args)
Allow fr_log to be called from python.
Definition rlm_python.c:204
Global config for python library.
Definition rlm_python.c:78
Specifies the module.function to load for processing a section.
Definition rlm_python.c:46
An instance of the rlm_python module.
Definition rlm_python.c:57
Tracks a python module inst/thread state pair.
Definition rlm_python.c:88
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
static unlang_action_t mod_preacct(rlm_rcode_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Definition rlm_test.c:246
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:329
size_t inst_size
Size of the module's instance data.
Definition module.h:203
void * data
Module's instance data.
Definition module.h:271
#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:169
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:818
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:347
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
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:70
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:43
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
#define FR_TYPE_NON_LEAF
Definition types.h:298
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:5398