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.
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.
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
20 * @brief Translates requests between the server an a python interpreter.
22 * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
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.
30 #define LOG_PREFIX "rlm_python - "
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/modules.h>
35 #include <freeradius-devel/rad_assert.h>
39 #ifdef HAVE_DL_ITERATE_PHDR
43 #define LIBPYTHON_LINKER_NAME \
44 "libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so"
46 static uint32_t python_instances = 0;
47 static void *python_dlhandle;
49 static PyThreadState *main_interpreter; //!< Main interpreter (cext safe)
50 static PyObject *main_module; //!< Pthon configuration dictionary.
52 /** Specifies the module.function to load for processing a section
55 typedef struct python_func_def {
56 PyObject *module; //!< Python reference to module.
57 PyObject *function; //!< Python reference to function in module.
59 char const *module_name; //!< String name of module.
60 char const *function_name; //!< String name of function in module.
63 /** An instance of the rlm_python module
66 typedef struct rlm_python_t {
67 char const *name; //!< Name of the module instance
68 PyThreadState *sub_interpreter; //!< The main interpreter/thread used for this instance.
69 char const *python_path; //!< Path to search for python files in.
70 PyObject *module; //!< Local, interpreter specific module, containing
71 //!< FreeRADIUS functions.
72 bool cext_compat; //!< Whether or not to create sub-interpreters per module
91 PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
92 //!< made available to the python script.
95 /** Tracks a python module inst/thread state pair
97 * Multiple instances of python create multiple interpreters and each
98 * thread must have a PyThreadState per interpreter, to track execution.
100 typedef struct python_thread_state {
101 PyThreadState *state; //!< Module instance/thread specific state.
102 rlm_python_t *inst; //!< Module instance that created this thread state.
103 } python_thread_state_t;
106 * A mapping of configuration file names to internal variables.
108 static CONF_PARSER module_config[] = {
110 #define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), "${.module}" }, \
111 { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
130 { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
131 { "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
133 CONF_PARSER_TERMINATOR
139 } radiusd_constants[] = {
141 #define A(x) { #x, x },
158 A(RLM_MODULE_HANDLED)
159 A(RLM_MODULE_INVALID)
160 A(RLM_MODULE_USERLOCK)
161 A(RLM_MODULE_NOTFOUND)
163 A(RLM_MODULE_UPDATED)
164 A(RLM_MODULE_NUMCODES)
172 * This allows us to initialise PyThreadState on a per thread basis
174 fr_thread_local_setup(rbtree_t *, local_thread_state) /* macro */
177 * radiusd Python functions
180 /** Allow radlog to be called from python
183 static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
188 if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
192 radlog(status, "%s", msg);
198 static PyMethodDef module_methods[] = {
199 { "radlog", &mod_radlog, METH_VARARGS,
200 "radiusd.radlog(level, msg)\n\n" \
201 "Print a message using radiusd logging system. level should be one of the\n" \
202 "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
204 { NULL, NULL, 0, NULL },
207 /** Print out the current error
209 * Must be called with a valid thread state set
211 static void python_error_log(void)
213 PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
215 PyErr_Fetch(&pType, &pValue, &pTraceback);
216 if (!pType || !pValue)
218 if (((pStr1 = PyObject_Str(pType)) == NULL) ||
219 ((pStr2 = PyObject_Str(pValue)) == NULL))
222 ERROR("%s (%s)", PyString_AsString(pStr1), PyString_AsString(pStr2));
229 Py_XDECREF(pTraceback);
232 static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
233 char const *funcname, char const *list_name)
239 REQUEST *current = request;
241 memset(&dst, 0, sizeof(dst));
244 * If the Python function gave us None for the tuple,
247 if (pValue == Py_None) return;
249 if (!PyTuple_CheckExact(pValue)) {
250 ERROR("%s - non-tuple passed to %s", funcname, list_name);
253 /* Get the tuple tuplesize. */
254 tuplesize = PyTuple_GET_SIZE(pValue);
255 for (i = 0; i < tuplesize; i++) {
256 PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
263 FR_TOKEN op = T_OP_EQ;
265 if (!PyTuple_CheckExact(pTupleElement)) {
266 ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
269 /* Check if it's a pair */
271 pairsize = PyTuple_GET_SIZE(pTupleElement);
272 if ((pairsize < 2) || (pairsize > 3)) {
273 ERROR("%s - Tuple element %d of %s is a tuple of size %d. Must be 2 or 3",
274 funcname, i, list_name, pairsize);
278 pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
279 pStr2 = PyTuple_GET_ITEM(pTupleElement, pairsize-1);
281 if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
282 ERROR("%s - Tuple element %d of %s must be as (str, str)",
283 funcname, i, list_name);
286 s1 = PyString_AsString(pStr1);
287 s2 = PyString_AsString(pStr2);
290 pOp = PyTuple_GET_ITEM(pTupleElement, 1);
291 if (PyString_CheckExact(pOp)) {
292 if (!(op = fr_str2int(fr_tokens, PyString_AsString(pOp), 0))) {
293 ERROR("%s - Invalid operator %s:%s %s %s, falling back to '='",
294 funcname, list_name, s1, PyString_AsString(pOp), s2);
297 } else if (PyInt_Check(pOp)) {
298 op = PyInt_AsLong(pOp);
299 if (!fr_int2str(fr_tokens, op, NULL)) {
300 ERROR("%s - Invalid operator %s:%s %i %s, falling back to '='",
301 funcname, list_name, s1, op, s2);
305 ERROR("%s - Invalid operator type for %s:%s ? %s, using default '='",
306 funcname, list_name, s1, s2);
310 if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
311 ERROR("%s - Failed to find attribute %s:%s", funcname, list_name, s1);
315 if (radius_request(¤t, dst.tmpl_request) < 0) {
316 ERROR("%s - Attribute name %s:%s refers to outer request but not in a tunnel, skipping...",
317 funcname, list_name, s1);
321 if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
322 ERROR("%s - Failed to create attribute %s:%s", funcname, list_name, s1);
327 if (fr_pair_value_from_str(vp, s2, -1) < 0) {
328 DEBUG("%s - Failed: '%s:%s' %s '%s'", funcname, list_name, s1,
329 fr_int2str(fr_tokens, op, "="), s2);
331 DEBUG("%s - '%s:%s' %s '%s'", funcname, list_name, s1,
332 fr_int2str(fr_tokens, op, "="), s2);
335 radius_pairmove(current, vps, vp, false);
341 * This is the core Python function that the others wrap around.
342 * Pass the value-pair print strings in a tuple.
344 * FIXME: We're not checking the errors. If we have errors, what
347 static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
349 PyObject *pStr = NULL;
352 /* Look at the fr_pair_fprint_name? */
354 if (vp->da->flags.has_tag) {
355 pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
357 pStr = PyString_FromString(vp->da->name);
360 if (!pStr) return -1;
362 PyTuple_SET_ITEM(pPair, 0, pStr);
364 vp_prints_value(buf, sizeof(buf), vp, '\0'); /* Python doesn't need any escaping */
366 pStr = PyString_FromString(buf);
367 if (pStr == NULL) return -1;
369 PyTuple_SET_ITEM(pPair, 1, pStr);
374 static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname)
378 PyObject *pRet = NULL;
379 PyObject *pArgs = NULL;
383 /* Default return value is "OK, continue" */
387 * We will pass a tuple containing (name, value) tuples
388 * We can safely use the Python function to build up a
389 * tuple, since the tuple is not used elsewhere.
391 * Determine the size of our tuple by walking through the packet.
392 * If request is NULL, pass None.
395 if (request != NULL) {
396 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
398 vp = fr_cursor_next(&cursor)) tuplelen++;
406 if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
407 ret = RLM_MODULE_FAIL;
411 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
413 vp = fr_cursor_next(&cursor), i++) {
416 /* The inside tuple has two only: */
417 if ((pPair = PyTuple_New(2)) == NULL) {
418 ret = RLM_MODULE_FAIL;
422 if (mod_populate_vptuple(pPair, vp) == 0) {
423 /* Put the tuple inside the container */
424 PyTuple_SET_ITEM(pArgs, i, pPair);
427 PyTuple_SET_ITEM(pArgs, i, Py_None);
433 /* Call Python function. */
434 pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
436 ret = RLM_MODULE_FAIL;
441 // check return code at module instantiation time
442 if (PyInt_CheckExact(pRet)) ret = PyInt_AsLong(pRet);
447 * The function returns either:
448 * 1. (returnvalue, replyTuple, configTuple), where
449 * - returnvalue is one of the constants RLM_*
450 * - replyTuple and configTuple are tuples of string
453 * 2. the function return value alone
455 * 3. None - default return value is set
457 * xxx This code is messy!
459 if (PyTuple_CheckExact(pRet)) {
462 if (PyTuple_GET_SIZE(pRet) != 3) {
463 ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
464 ret = RLM_MODULE_FAIL;
468 pTupleInt = PyTuple_GET_ITEM(pRet, 0);
469 if (!PyInt_CheckExact(pTupleInt)) {
470 ERROR("%s - First tuple element not an integer", funcname);
471 ret = RLM_MODULE_FAIL;
474 /* Now have the return value */
475 ret = PyInt_AsLong(pTupleInt);
476 /* Reply item tuple */
477 mod_vptuple(request->reply, request, &request->reply->vps,
478 PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
479 /* Config item tuple */
480 mod_vptuple(request, request, &request->config,
481 PyTuple_GET_ITEM(pRet, 2), funcname, "config");
483 } else if (PyInt_CheckExact(pRet)) {
484 /* Just an integer */
485 ret = PyInt_AsLong(pRet);
487 } else if (pRet == Py_None) {
488 /* returned 'None', return value defaults to "OK, continue." */
491 /* Not tuple or None */
492 ERROR("%s - Function did not return a tuple or None", funcname);
493 ret = RLM_MODULE_FAIL;
505 static void python_interpreter_free(PyThreadState *interp)
507 PyEval_AcquireLock();
508 PyThreadState_Swap(interp);
509 Py_EndInterpreter(interp);
510 PyEval_ReleaseLock();
513 /** Destroy a thread state
515 * @param thread to destroy.
518 static int _python_thread_free(python_thread_state_t *thread)
520 PyEval_RestoreThread(thread->state); /* Swap in our local thread state */
521 PyThreadState_Clear(thread->state);
524 PyThreadState_Delete(thread->state); /* Don't need to hold lock for this */
529 /** Callback for rbtree delete walker
532 static void _python_thread_entry_free(void *arg)
537 /** Cleanup any thread local storage on pthread_exit()
539 * @param arg The thread currently exiting.
541 static void _python_thread_tree_free(void *arg)
543 rad_assert(arg == local_thread_state);
545 rbtree_t *tree = talloc_get_type_abort(arg, rbtree_t);
546 rbtree_free(tree); /* Needs to be this not talloc_free to execute delete walker */
548 local_thread_state = NULL; /* Prevent double free in unittest env */
551 /** Compare instance pointers
554 static int _python_inst_cmp(const void *a, const void *b)
556 python_thread_state_t const *a_p = a, *b_p = b;
558 if (a_p->inst < b_p->inst) return -1;
559 if (a_p->inst > b_p->inst) return +1;
563 /** Thread safe call to a python function
565 * Will swap in thread state specific to module/thread.
567 static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname)
570 rbtree_t *thread_tree;
571 python_thread_state_t *this_thread;
572 python_thread_state_t find;
575 * It's a NOOP if the function wasn't defined
577 if (!pFunc) return RLM_MODULE_NOOP;
580 * Check to see if we've got a thread state tree
581 * If not, create one.
583 thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
585 thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
587 RERROR("Failed allocating thread state tree");
588 return RLM_MODULE_FAIL;
591 ret = fr_thread_local_set(local_thread_state, thread_tree);
593 talloc_free(thread_tree);
594 return RLM_MODULE_FAIL;
600 * Find the thread state associated with this instance
601 * and this thread, or create a new thread state.
603 this_thread = rbtree_finddata(thread_tree, &find);
605 PyThreadState *state;
607 state = PyThreadState_New(inst->sub_interpreter->interp);
609 RDEBUG3("Initialised new thread state %p", state);
611 REDEBUG("Failed initialising local PyThreadState on first run");
612 return RLM_MODULE_FAIL;
615 this_thread = talloc(NULL, python_thread_state_t);
616 this_thread->inst = inst;
617 this_thread->state = state;
618 talloc_set_destructor(this_thread, _python_thread_free);
620 if (!rbtree_insert(thread_tree, this_thread)) {
621 RERROR("Failed inserting thread state into TLS tree");
622 talloc_free(this_thread);
624 return RLM_MODULE_FAIL;
627 RDEBUG3("Using thread state %p", this_thread->state);
629 PyEval_RestoreThread(this_thread->state); /* Swap in our local thread state */
630 ret = do_python_single(request, pFunc, funcname);
636 #define MOD_FUNC(x) \
637 static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
638 return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x);\
641 MOD_FUNC(authenticate)
653 static void python_obj_destroy(PyObject **ob)
661 static void python_function_destroy(python_func_def_t *def)
663 python_obj_destroy(&def->function);
664 python_obj_destroy(&def->module);
667 /** Import a user module and load a function from it
670 static int python_function_load(python_func_def_t *def)
672 char const *funcname = "python_function_load";
674 if (def->module_name == NULL || def->function_name == NULL) return 0;
676 def->module = PyImport_ImportModule(def->module_name);
678 ERROR("%s - Module '%s' not found", funcname, def->module_name);
682 ERROR("%s - Failed to import python function '%s.%s'",
683 funcname, def->module_name, def->function_name);
684 Py_XDECREF(def->function);
685 def->function = NULL;
686 Py_XDECREF(def->module);
692 def->function = PyObject_GetAttrString(def->module, def->function_name);
693 if (!def->function) {
694 ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
698 if (!PyCallable_Check(def->function)) {
699 ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
707 * Parse a configuration section, and populate a dict.
708 * This function is recursively called (allows to have nested dicts.)
710 static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
712 int indent_section = (lvl + 1) * 4;
713 int indent_item = (lvl + 2) * 4;
714 CONF_ITEM *ci = NULL;
716 if (!cs || !dict) return;
718 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
720 while ((ci = cf_item_find_next(cs, ci))) {
723 * Create a new dict, store it in current dict,
724 * Then recursively call python_parse_config with this section and the new dict.
726 if (cf_item_is_section(ci)) {
727 CONF_SECTION *sub_cs = cf_item_to_section(ci);
728 char const *key = cf_section_name1(sub_cs); /* dict key */
729 PyObject *sub_dict, *pKey;
733 pKey = PyString_FromString(key);
736 if (PyDict_Contains(dict, pKey)) {
737 WARN("rlm_python: Ignoring duplicate config section '%s'", key);
741 if (!(sub_dict = PyDict_New())) {
742 WARN("rlm_python: Unable to create subdict for config section '%s'", key);
745 (void)PyDict_SetItem(dict, pKey, sub_dict);
747 python_parse_config(sub_cs, lvl + 1, sub_dict);
748 } else if (cf_item_is_pair(ci)) {
749 CONF_PAIR *cp = cf_item_to_pair(ci);
750 char const *key = cf_pair_attr(cp); /* dict key */
751 char const *value = cf_pair_value(cp); /* dict value */
752 PyObject *pKey, *pValue;
754 if (!key || !value) continue;
756 pKey = PyString_FromString(key);
757 pValue = PyString_FromString(value);
758 if (!pKey || !pValue) continue;
762 * Store item attr / value in current dict.
764 if (PyDict_Contains(dict, pKey)) {
765 WARN("rlm_python: Ignoring duplicate config item '%s'", key);
769 (void)PyDict_SetItem(dict, pKey, pValue);
771 DEBUG("%*s%s = %s", indent_item, " ", key, value);
775 DEBUG("%*s}", indent_section, " ");
778 #ifdef HAVE_DL_ITERATE_PHDR
779 static int dlopen_libpython_cb(struct dl_phdr_info *info,
780 UNUSED size_t size, void *data)
782 const char *pattern = "/" LIBPYTHON_LINKER_NAME;
783 char **ppath = (char **)data;
785 if (strstr(info->dlpi_name, pattern) != NULL) {
786 if (*ppath != NULL) {
791 *ppath = talloc_strdup(NULL, info->dlpi_name);
792 if (*ppath == NULL) {
800 /* Dlopen the already linked libpython */
801 static void *dlopen_libpython(int flags)
807 /* Find the linked libpython path */
808 rc = dl_iterate_phdr(dlopen_libpython_cb, &path);
810 WARN("Failed searching for libpython "
811 "among linked libraries: %s", strerror(rc));
813 } else if (path == NULL) {
814 WARN("Libpython is not found among linked libraries");
818 /* Dlopen the found library */
819 handle = dlopen(path, flags);
820 if (handle == NULL) {
821 WARN("Failed loading %s: %s", path, dlerror());
826 #else /* ! HAVE_DL_ITERATE_PHDR */
827 /* Dlopen libpython by its linker name (bare soname) */
828 static void *dlopen_libpython(int flags)
830 const char *name = LIBPYTHON_LINKER_NAME;
832 handle = dlopen(name, flags);
833 if (handle == NULL) {
834 WARN("Failed loading %s: %s", name, dlerror());
838 #endif /* ! HAVE_DL_ITERATE_PHDR */
840 /** Initialises a separate python interpreter for this module instance
843 static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
848 * Explicitly load libpython, so symbols will be available to lib-dynload modules
850 if (python_instances == 0) {
851 INFO("Python version: %s", Py_GetVersion());
853 python_dlhandle = dlopen_libpython(RTLD_NOW | RTLD_GLOBAL);
854 if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table");
856 #if PY_VERSION_HEX > 0x03050000
860 wide_name = Py_DecodeLocale(main_config.name, strlen(main_config.name));
861 Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
868 name = talloc_strdup(NULL, main_config.name);
869 Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
874 Py_InitializeEx(0); /* Don't override signal handlers - noop on subs calls */
875 PyEval_InitThreads(); /* This also grabs a lock (which we then need to release) */
876 main_interpreter = PyThreadState_Get(); /* Store reference to the main interpreter */
878 rad_assert(PyEval_ThreadsInitialized());
881 * Increment the reference counter
886 * This sets up a separate environment for each python module instance
887 * These will be destroyed on Py_Finalize().
889 if (!inst->cext_compat) {
890 inst->sub_interpreter = Py_NewInterpreter();
892 inst->sub_interpreter = main_interpreter;
895 PyThreadState_Swap(inst->sub_interpreter);
898 * Due to limitations in Python, sub-interpreters don't work well
899 * with Python C extensions if they use GIL lock functions.
901 if (!inst->cext_compat || !main_module) {
905 * Set the python search path
907 if (inst->python_path) {
908 #if PY_VERSION_HEX > 0x03050000
912 path = Py_DecodeLocale(inst->python_path, strlen(inst->python_path));
920 path = talloc_strdup(NULL, inst->python_path);
928 * Initialise a new module, with our default methods
930 inst->module = Py_InitModule3("radiusd", module_methods, "FreeRADIUS python module");
939 * Py_InitModule3 returns a borrowed ref, the actual
940 * module is owned by sys.modules, so we also need
941 * to own the module to prevent it being freed early.
943 Py_IncRef(inst->module);
945 if (inst->cext_compat) main_module = inst->module;
947 for (i = 0; radiusd_constants[i].name; i++) {
948 if ((PyModule_AddIntConstant(inst->module, radiusd_constants[i].name,
949 radiusd_constants[i].value)) < 0)
954 * Convert a FreeRADIUS config structure into a python
957 inst->pythonconf_dict = PyDict_New();
958 if (!inst->pythonconf_dict) {
959 ERROR("Unable to create python dict for config");
965 * Add module configuration as a dict
967 if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0) goto error;
969 cs = cf_section_sub_find(conf, "config");
970 if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
972 inst->module = main_module;
973 Py_IncRef(inst->module);
974 inst->pythonconf_dict = PyObject_GetAttrString(inst->module, "config");
975 Py_IncRef(inst->pythonconf_dict);
984 * Do any per-module initialization that is separate to each
985 * configured instance of the module. e.g. set up connections
986 * to external databases, read configuration files, set up
987 * dictionary entries, etc.
989 * If configuration information is given in the config section
990 * that must be referenced in later calls, store a handle to it
991 * in *instance otherwise put a null pointer there.
994 static int mod_instantiate(CONF_SECTION *conf, void *instance)
996 rlm_python_t *inst = instance;
999 inst->name = cf_section_name2(conf);
1000 if (!inst->name) inst->name = cf_section_name1(conf);
1003 * Load the python code required for this module instance
1005 if (python_interpreter_init(inst, conf) < 0) return -1;
1008 * Switch to our module specific main thread
1010 PyEval_RestoreThread(inst->sub_interpreter);
1013 * Process the various sections
1015 #define PYTHON_FUNC_LOAD(_x) if (python_function_load(&inst->_x) < 0) goto error
1016 PYTHON_FUNC_LOAD(instantiate);
1017 PYTHON_FUNC_LOAD(authenticate);
1018 PYTHON_FUNC_LOAD(authorize);
1019 PYTHON_FUNC_LOAD(preacct);
1020 PYTHON_FUNC_LOAD(accounting);
1021 PYTHON_FUNC_LOAD(checksimul);
1022 PYTHON_FUNC_LOAD(pre_proxy);
1023 PYTHON_FUNC_LOAD(post_proxy);
1024 PYTHON_FUNC_LOAD(post_auth);
1026 PYTHON_FUNC_LOAD(recv_coa);
1027 PYTHON_FUNC_LOAD(send_coa);
1029 PYTHON_FUNC_LOAD(detach);
1032 * Call the instantiate function.
1034 code = do_python_single(NULL, inst->instantiate.function, "instantiate");
1037 python_error_log(); /* Needs valid thread with GIL */
1038 PyEval_SaveThread();
1041 PyEval_SaveThread();
1046 static int mod_detach(void *instance)
1048 rlm_python_t *inst = instance;
1052 * Call module destructor
1054 PyEval_RestoreThread(inst->sub_interpreter);
1056 ret = do_python_single(NULL, inst->detach.function, "detach");
1058 #define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
1059 PYTHON_FUNC_DESTROY(instantiate);
1060 PYTHON_FUNC_DESTROY(authorize);
1061 PYTHON_FUNC_DESTROY(authenticate);
1062 PYTHON_FUNC_DESTROY(preacct);
1063 PYTHON_FUNC_DESTROY(accounting);
1064 PYTHON_FUNC_DESTROY(checksimul);
1065 PYTHON_FUNC_DESTROY(detach);
1067 Py_DecRef(inst->pythonconf_dict);
1068 Py_DecRef(inst->module);
1070 PyEval_SaveThread();
1073 * Force cleaning up of threads if this is *NOT* a worker
1074 * thread, which happens if this is being called from
1075 * unittest framework, and probably with the server running
1078 rbtree_free(local_thread_state);
1079 local_thread_state = NULL;
1082 * Only destroy if it's a subinterpreter
1084 if (!inst->cext_compat) python_interpreter_free(inst->sub_interpreter);
1086 if ((--python_instances) == 0) {
1087 PyThreadState_Swap(main_interpreter); /* Swap to the main thread */
1089 dlclose(python_dlhandle);
1096 * The module name should be the only globally exported symbol.
1097 * That is, everything else should be 'static'.
1099 * If the module needs to temporarily modify it's instantiation
1100 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
1101 * The server will then take care of ensuring that the module
1102 * is single-threaded.
1104 extern module_t rlm_python;
1105 module_t rlm_python = {
1106 .magic = RLM_MODULE_INIT,
1108 .type = RLM_TYPE_THREAD_SAFE,
1109 .inst_size = sizeof(rlm_python_t),
1110 .config = module_config,
1111 .instantiate = mod_instantiate,
1112 .detach = mod_detach,
1114 [MOD_AUTHENTICATE] = mod_authenticate,
1115 [MOD_AUTHORIZE] = mod_authorize,
1116 [MOD_PREACCT] = mod_preacct,
1117 [MOD_ACCOUNTING] = mod_accounting,
1118 [MOD_SESSION] = mod_checksimul,
1119 [MOD_PRE_PROXY] = mod_pre_proxy,
1120 [MOD_POST_PROXY] = mod_post_proxy,
1121 [MOD_POST_AUTH] = mod_post_auth,
1123 [MOD_RECV_COA] = mod_recv_coa,
1124 [MOD_SEND_COA] = mod_send_coa