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 - "
32 #include <freeradius-devel/radiusd.h>
33 #include <freeradius-devel/modules.h>
34 #include <freeradius-devel/rad_assert.h>
39 static uint32_t python_instances = 0;
40 static void *python_dlhandle;
42 static PyThreadState *main_interpreter; //!< Main interpreter (cext safe)
43 static PyObject *main_module; //!< Pthon configuration dictionary.
45 /** Specifies the module.function to load for processing a section
48 typedef struct python_func_def {
49 PyObject *module; //!< Python reference to module.
50 PyObject *function; //!< Python reference to function in module.
52 char const *module_name; //!< String name of module.
53 char const *function_name; //!< String name of function in module.
56 /** An instance of the rlm_python module
59 typedef struct rlm_python_t {
60 char const *name; //!< Name of the module instance
61 PyThreadState *sub_interpreter; //!< The main interpreter/thread used for this instance.
62 char const *python_path; //!< Path to search for python files in.
63 PyObject *module; //!< Local, interpreter specific module, containing
64 //!< FreeRADIUS functions.
65 bool cext_compat; //!< Whether or not to create sub-interpreters per module
84 PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
85 //!< made available to the python script.
88 /** Tracks a python module inst/thread state pair
90 * Multiple instances of python create multiple interpreters and each
91 * thread must have a PyThreadState per interpreter, to track execution.
93 typedef struct python_thread_state {
94 PyThreadState *state; //!< Module instance/thread specific state.
95 rlm_python_t *inst; //!< Module instance that created this thread state.
96 } python_thread_state_t;
99 * A mapping of configuration file names to internal variables.
101 static CONF_PARSER module_config[] = {
103 #define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), "${.module}" }, \
104 { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
123 { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
124 { "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
126 CONF_PARSER_TERMINATOR
132 } radiusd_constants[] = {
134 #define A(x) { #x, x },
151 A(RLM_MODULE_HANDLED)
152 A(RLM_MODULE_INVALID)
153 A(RLM_MODULE_USERLOCK)
154 A(RLM_MODULE_NOTFOUND)
156 A(RLM_MODULE_UPDATED)
157 A(RLM_MODULE_NUMCODES)
165 * This allows us to initialise PyThreadState on a per thread basis
167 fr_thread_local_setup(rbtree_t *, local_thread_state) /* macro */
170 * radiusd Python functions
173 /** Allow radlog to be called from python
176 static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
181 if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
185 radlog(status, "%s", msg);
191 static PyMethodDef module_methods[] = {
192 { "radlog", &mod_radlog, METH_VARARGS,
193 "radiusd.radlog(level, msg)\n\n" \
194 "Print a message using radiusd logging system. level should be one of the\n" \
195 "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
197 { NULL, NULL, 0, NULL },
200 /** Print out the current error
202 * Must be called with a valid thread state set
204 static void python_error_log(void)
206 PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
208 PyErr_Fetch(&pType, &pValue, &pTraceback);
209 if (!pType || !pValue)
211 if (((pStr1 = PyObject_Str(pType)) == NULL) ||
212 ((pStr2 = PyObject_Str(pValue)) == NULL))
215 ERROR("%s (%s)", PyString_AsString(pStr1), PyString_AsString(pStr2));
222 Py_XDECREF(pTraceback);
225 static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
226 char const *funcname, char const *list_name)
232 REQUEST *current = request;
234 memset(&dst, 0, sizeof(dst));
237 * If the Python function gave us None for the tuple,
240 if (pValue == Py_None) return;
242 if (!PyTuple_CheckExact(pValue)) {
243 ERROR("%s - non-tuple passed to %s", funcname, list_name);
246 /* Get the tuple tuplesize. */
247 tuplesize = PyTuple_GET_SIZE(pValue);
248 for (i = 0; i < tuplesize; i++) {
249 PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
256 FR_TOKEN op = T_OP_EQ;
258 if (!PyTuple_CheckExact(pTupleElement)) {
259 ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
262 /* Check if it's a pair */
264 pairsize = PyTuple_GET_SIZE(pTupleElement);
265 if ((pairsize < 2) || (pairsize > 3)) {
266 ERROR("%s - Tuple element %d of %s is a tuple of size %d. Must be 2 or 3",
267 funcname, i, list_name, pairsize);
271 pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
272 pStr2 = PyTuple_GET_ITEM(pTupleElement, pairsize-1);
274 if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
275 ERROR("%s - Tuple element %d of %s must be as (str, str)",
276 funcname, i, list_name);
279 s1 = PyString_AsString(pStr1);
280 s2 = PyString_AsString(pStr2);
283 pOp = PyTuple_GET_ITEM(pTupleElement, 1);
284 if (PyString_CheckExact(pOp)) {
285 if (!(op = fr_str2int(fr_tokens, PyString_AsString(pOp), 0))) {
286 ERROR("%s - Invalid operator %s:%s %s %s, falling back to '='",
287 funcname, list_name, s1, PyString_AsString(pOp), s2);
290 } else if (PyInt_Check(pOp)) {
291 op = PyInt_AsLong(pOp);
292 if (!fr_int2str(fr_tokens, op, NULL)) {
293 ERROR("%s - Invalid operator %s:%s %i %s, falling back to '='",
294 funcname, list_name, s1, op, s2);
298 ERROR("%s - Invalid operator type for %s:%s ? %s, using default '='",
299 funcname, list_name, s1, s2);
303 if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
304 ERROR("%s - Failed to find attribute %s:%s", funcname, list_name, s1);
308 if (radius_request(¤t, dst.tmpl_request) < 0) {
309 ERROR("%s - Attribute name %s:%s refers to outer request but not in a tunnel, skipping...",
310 funcname, list_name, s1);
314 if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
315 ERROR("%s - Failed to create attribute %s:%s", funcname, list_name, s1);
320 if (fr_pair_value_from_str(vp, s2, -1) < 0) {
321 DEBUG("%s - Failed: '%s:%s' %s '%s'", funcname, list_name, s1,
322 fr_int2str(fr_tokens, op, "="), s2);
324 DEBUG("%s - '%s:%s' %s '%s'", funcname, list_name, s1,
325 fr_int2str(fr_tokens, op, "="), s2);
328 radius_pairmove(current, vps, vp, false);
334 * This is the core Python function that the others wrap around.
335 * Pass the value-pair print strings in a tuple.
337 * FIXME: We're not checking the errors. If we have errors, what
340 static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
342 PyObject *pStr = NULL;
345 /* Look at the fr_pair_fprint_name? */
347 if (vp->da->flags.has_tag) {
348 pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
350 pStr = PyString_FromString(vp->da->name);
353 if (!pStr) return -1;
355 PyTuple_SET_ITEM(pPair, 0, pStr);
357 vp_prints_value(buf, sizeof(buf), vp, '\0'); /* Python doesn't need any escaping */
359 pStr = PyString_FromString(buf);
360 if (pStr == NULL) return -1;
362 PyTuple_SET_ITEM(pPair, 1, pStr);
367 static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname)
371 PyObject *pRet = NULL;
372 PyObject *pArgs = NULL;
376 /* Default return value is "OK, continue" */
380 * We will pass a tuple containing (name, value) tuples
381 * We can safely use the Python function to build up a
382 * tuple, since the tuple is not used elsewhere.
384 * Determine the size of our tuple by walking through the packet.
385 * If request is NULL, pass None.
388 if (request != NULL) {
389 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
391 vp = fr_cursor_next(&cursor)) tuplelen++;
399 if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
400 ret = RLM_MODULE_FAIL;
404 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
406 vp = fr_cursor_next(&cursor), i++) {
409 /* The inside tuple has two only: */
410 if ((pPair = PyTuple_New(2)) == NULL) {
411 ret = RLM_MODULE_FAIL;
415 if (mod_populate_vptuple(pPair, vp) == 0) {
416 /* Put the tuple inside the container */
417 PyTuple_SET_ITEM(pArgs, i, pPair);
420 PyTuple_SET_ITEM(pArgs, i, Py_None);
426 /* Call Python function. */
427 pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
429 ret = RLM_MODULE_FAIL;
434 // check return code at module instantiation time
435 if (PyInt_CheckExact(pRet)) ret = PyInt_AsLong(pRet);
440 * The function returns either:
441 * 1. (returnvalue, replyTuple, configTuple), where
442 * - returnvalue is one of the constants RLM_*
443 * - replyTuple and configTuple are tuples of string
446 * 2. the function return value alone
448 * 3. None - default return value is set
450 * xxx This code is messy!
452 if (PyTuple_CheckExact(pRet)) {
455 if (PyTuple_GET_SIZE(pRet) != 3) {
456 ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
457 ret = RLM_MODULE_FAIL;
461 pTupleInt = PyTuple_GET_ITEM(pRet, 0);
462 if (!PyInt_CheckExact(pTupleInt)) {
463 ERROR("%s - First tuple element not an integer", funcname);
464 ret = RLM_MODULE_FAIL;
467 /* Now have the return value */
468 ret = PyInt_AsLong(pTupleInt);
469 /* Reply item tuple */
470 mod_vptuple(request->reply, request, &request->reply->vps,
471 PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
472 /* Config item tuple */
473 mod_vptuple(request, request, &request->config,
474 PyTuple_GET_ITEM(pRet, 2), funcname, "config");
476 } else if (PyInt_CheckExact(pRet)) {
477 /* Just an integer */
478 ret = PyInt_AsLong(pRet);
480 } else if (pRet == Py_None) {
481 /* returned 'None', return value defaults to "OK, continue." */
484 /* Not tuple or None */
485 ERROR("%s - Function did not return a tuple or None", funcname);
486 ret = RLM_MODULE_FAIL;
498 static void python_interpreter_free(PyThreadState *interp)
500 PyEval_AcquireLock();
501 PyThreadState_Swap(interp);
502 Py_EndInterpreter(interp);
503 PyEval_ReleaseLock();
506 /** Destroy a thread state
508 * @param thread to destroy.
511 static int _python_thread_free(python_thread_state_t *thread)
513 PyEval_RestoreThread(thread->state); /* Swap in our local thread state */
514 PyThreadState_Clear(thread->state);
517 PyThreadState_Delete(thread->state); /* Don't need to hold lock for this */
522 /** Callback for rbtree delete walker
525 static void _python_thread_entry_free(void *arg)
530 /** Cleanup any thread local storage on pthread_exit()
532 * @param arg The thread currently exiting.
534 static void _python_thread_tree_free(void *arg)
536 rad_assert(arg == local_thread_state);
538 rbtree_t *tree = talloc_get_type_abort(arg, rbtree_t);
539 rbtree_free(tree); /* Needs to be this not talloc_free to execute delete walker */
541 local_thread_state = NULL; /* Prevent double free in unittest env */
544 /** Compare instance pointers
547 static int _python_inst_cmp(const void *a, const void *b)
549 python_thread_state_t const *a_p = a, *b_p = b;
551 if (a_p->inst < b_p->inst) return -1;
552 if (a_p->inst > b_p->inst) return +1;
556 /** Thread safe call to a python function
558 * Will swap in thread state specific to module/thread.
560 static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname)
563 rbtree_t *thread_tree;
564 python_thread_state_t *this_thread;
565 python_thread_state_t find;
568 * It's a NOOP if the function wasn't defined
570 if (!pFunc) return RLM_MODULE_NOOP;
573 * Check to see if we've got a thread state tree
574 * If not, create one.
576 thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
578 thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
580 RERROR("Failed allocating thread state tree");
581 return RLM_MODULE_FAIL;
584 ret = fr_thread_local_set(local_thread_state, thread_tree);
586 talloc_free(thread_tree);
587 return RLM_MODULE_FAIL;
593 * Find the thread state associated with this instance
594 * and this thread, or create a new thread state.
596 this_thread = rbtree_finddata(thread_tree, &find);
598 PyThreadState *state;
600 state = PyThreadState_New(inst->sub_interpreter->interp);
602 RDEBUG3("Initialised new thread state %p", state);
604 REDEBUG("Failed initialising local PyThreadState on first run");
605 return RLM_MODULE_FAIL;
608 this_thread = talloc(NULL, python_thread_state_t);
609 this_thread->inst = inst;
610 this_thread->state = state;
611 talloc_set_destructor(this_thread, _python_thread_free);
613 if (!rbtree_insert(thread_tree, this_thread)) {
614 RERROR("Failed inserting thread state into TLS tree");
615 talloc_free(this_thread);
617 return RLM_MODULE_FAIL;
620 RDEBUG3("Using thread state %p", this_thread->state);
622 PyEval_RestoreThread(this_thread->state); /* Swap in our local thread state */
623 ret = do_python_single(request, pFunc, funcname);
629 #define MOD_FUNC(x) \
630 static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
631 return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x);\
634 MOD_FUNC(authenticate)
646 static void python_obj_destroy(PyObject **ob)
654 static void python_function_destroy(python_func_def_t *def)
656 python_obj_destroy(&def->function);
657 python_obj_destroy(&def->module);
660 /** Import a user module and load a function from it
663 static int python_function_load(python_func_def_t *def)
665 char const *funcname = "python_function_load";
667 if (def->module_name == NULL || def->function_name == NULL) return 0;
669 def->module = PyImport_ImportModule(def->module_name);
671 ERROR("%s - Module '%s' not found", funcname, def->module_name);
675 ERROR("%s - Failed to import python function '%s.%s'",
676 funcname, def->module_name, def->function_name);
677 Py_XDECREF(def->function);
678 def->function = NULL;
679 Py_XDECREF(def->module);
685 def->function = PyObject_GetAttrString(def->module, def->function_name);
686 if (!def->function) {
687 ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
691 if (!PyCallable_Check(def->function)) {
692 ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
700 * Parse a configuration section, and populate a dict.
701 * This function is recursively called (allows to have nested dicts.)
703 static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
705 int indent_section = (lvl + 1) * 4;
706 int indent_item = (lvl + 2) * 4;
707 CONF_ITEM *ci = NULL;
709 if (!cs || !dict) return;
711 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
713 while ((ci = cf_item_find_next(cs, ci))) {
716 * Create a new dict, store it in current dict,
717 * Then recursively call python_parse_config with this section and the new dict.
719 if (cf_item_is_section(ci)) {
720 CONF_SECTION *sub_cs = cf_item_to_section(ci);
721 char const *key = cf_section_name1(sub_cs); /* dict key */
722 PyObject *sub_dict, *pKey;
726 pKey = PyString_FromString(key);
729 if (PyDict_Contains(dict, pKey)) {
730 WARN("rlm_python: Ignoring duplicate config section '%s'", key);
734 if (!(sub_dict = PyDict_New())) {
735 WARN("rlm_python: Unable to create subdict for config section '%s'", key);
738 (void)PyDict_SetItem(dict, pKey, sub_dict);
740 python_parse_config(sub_cs, lvl + 1, sub_dict);
741 } else if (cf_item_is_pair(ci)) {
742 CONF_PAIR *cp = cf_item_to_pair(ci);
743 char const *key = cf_pair_attr(cp); /* dict key */
744 char const *value = cf_pair_value(cp); /* dict value */
745 PyObject *pKey, *pValue;
747 if (!key || !value) continue;
749 pKey = PyString_FromString(key);
750 pValue = PyString_FromString(value);
751 if (!pKey || !pValue) continue;
755 * Store item attr / value in current dict.
757 if (PyDict_Contains(dict, pKey)) {
758 WARN("rlm_python: Ignoring duplicate config item '%s'", key);
762 (void)PyDict_SetItem(dict, pKey, pValue);
764 DEBUG("%*s%s = %s", indent_item, " ", key, value);
768 DEBUG("%*s}", indent_section, " ");
771 /** Initialises a separate python interpreter for this module instance
774 static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
779 * Explicitly load libpython, so symbols will be available to lib-dynload modules
781 if (python_instances == 0) {
782 INFO("Python version: %s", Py_GetVersion());
784 python_dlhandle = dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
785 RTLD_NOW | RTLD_GLOBAL);
786 if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
788 #if PY_VERSION_HEX > 0x03050000
792 wide_name = Py_DecodeLocale(main_config.name, strlen(main_config.name));
793 Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
800 name = talloc_strdup(NULL, main_config.name);
801 Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
806 Py_InitializeEx(0); /* Don't override signal handlers - noop on subs calls */
807 PyEval_InitThreads(); /* This also grabs a lock (which we then need to release) */
808 main_interpreter = PyThreadState_Get(); /* Store reference to the main interpreter */
810 rad_assert(PyEval_ThreadsInitialized());
813 * Increment the reference counter
818 * This sets up a separate environment for each python module instance
819 * These will be destroyed on Py_Finalize().
821 if (!inst->cext_compat) {
822 inst->sub_interpreter = Py_NewInterpreter();
824 inst->sub_interpreter = main_interpreter;
827 PyThreadState_Swap(inst->sub_interpreter);
830 * Due to limitations in Python, sub-interpreters don't work well
831 * with Python C extensions if they use GIL lock functions.
833 if (!inst->cext_compat || !main_module) {
837 * Set the python search path
839 if (inst->python_path) {
840 #if PY_VERSION_HEX > 0x03050000
844 path = Py_DecodeLocale(inst->python_path, strlen(inst->python_path));
852 path = talloc_strdup(NULL, inst->python_path);
860 * Initialise a new module, with our default methods
862 inst->module = Py_InitModule3("radiusd", module_methods, "FreeRADIUS python module");
871 * Py_InitModule3 returns a borrowed ref, the actual
872 * module is owned by sys.modules, so we also need
873 * to own the module to prevent it being freed early.
875 Py_IncRef(inst->module);
877 if (inst->cext_compat) main_module = inst->module;
879 for (i = 0; radiusd_constants[i].name; i++) {
880 if ((PyModule_AddIntConstant(inst->module, radiusd_constants[i].name,
881 radiusd_constants[i].value)) < 0)
886 * Convert a FreeRADIUS config structure into a python
889 inst->pythonconf_dict = PyDict_New();
890 if (!inst->pythonconf_dict) {
891 ERROR("Unable to create python dict for config");
897 * Add module configuration as a dict
899 if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0) goto error;
901 cs = cf_section_sub_find(conf, "config");
902 if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
904 inst->module = main_module;
905 Py_IncRef(inst->module);
906 inst->pythonconf_dict = PyObject_GetAttrString(inst->module, "config");
907 Py_IncRef(inst->pythonconf_dict);
916 * Do any per-module initialization that is separate to each
917 * configured instance of the module. e.g. set up connections
918 * to external databases, read configuration files, set up
919 * dictionary entries, etc.
921 * If configuration information is given in the config section
922 * that must be referenced in later calls, store a handle to it
923 * in *instance otherwise put a null pointer there.
926 static int mod_instantiate(CONF_SECTION *conf, void *instance)
928 rlm_python_t *inst = instance;
931 inst->name = cf_section_name2(conf);
932 if (!inst->name) inst->name = cf_section_name1(conf);
935 * Load the python code required for this module instance
937 if (python_interpreter_init(inst, conf) < 0) return -1;
940 * Switch to our module specific main thread
942 PyEval_RestoreThread(inst->sub_interpreter);
945 * Process the various sections
947 #define PYTHON_FUNC_LOAD(_x) if (python_function_load(&inst->_x) < 0) goto error
948 PYTHON_FUNC_LOAD(instantiate);
949 PYTHON_FUNC_LOAD(authenticate);
950 PYTHON_FUNC_LOAD(authorize);
951 PYTHON_FUNC_LOAD(preacct);
952 PYTHON_FUNC_LOAD(accounting);
953 PYTHON_FUNC_LOAD(checksimul);
954 PYTHON_FUNC_LOAD(pre_proxy);
955 PYTHON_FUNC_LOAD(post_proxy);
956 PYTHON_FUNC_LOAD(post_auth);
958 PYTHON_FUNC_LOAD(recv_coa);
959 PYTHON_FUNC_LOAD(send_coa);
961 PYTHON_FUNC_LOAD(detach);
964 * Call the instantiate function.
966 code = do_python_single(NULL, inst->instantiate.function, "instantiate");
969 python_error_log(); /* Needs valid thread with GIL */
978 static int mod_detach(void *instance)
980 rlm_python_t *inst = instance;
984 * Call module destructor
986 PyEval_RestoreThread(inst->sub_interpreter);
988 ret = do_python_single(NULL, inst->detach.function, "detach");
990 #define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
991 PYTHON_FUNC_DESTROY(instantiate);
992 PYTHON_FUNC_DESTROY(authorize);
993 PYTHON_FUNC_DESTROY(authenticate);
994 PYTHON_FUNC_DESTROY(preacct);
995 PYTHON_FUNC_DESTROY(accounting);
996 PYTHON_FUNC_DESTROY(checksimul);
997 PYTHON_FUNC_DESTROY(detach);
999 Py_DecRef(inst->pythonconf_dict);
1000 Py_DecRef(inst->module);
1002 PyEval_SaveThread();
1005 * Force cleaning up of threads if this is *NOT* a worker
1006 * thread, which happens if this is being called from
1007 * unittest framework, and probably with the server running
1010 rbtree_free(local_thread_state);
1011 local_thread_state = NULL;
1014 * Only destroy if it's a subinterpreter
1016 if (!inst->cext_compat) python_interpreter_free(inst->sub_interpreter);
1018 if ((--python_instances) == 0) {
1019 PyThreadState_Swap(main_interpreter); /* Swap to the main thread */
1021 dlclose(python_dlhandle);
1028 * The module name should be the only globally exported symbol.
1029 * That is, everything else should be 'static'.
1031 * If the module needs to temporarily modify it's instantiation
1032 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
1033 * The server will then take care of ensuring that the module
1034 * is single-threaded.
1036 extern module_t rlm_python;
1037 module_t rlm_python = {
1038 .magic = RLM_MODULE_INIT,
1040 .type = RLM_TYPE_THREAD_SAFE,
1041 .inst_size = sizeof(rlm_python_t),
1042 .config = module_config,
1043 .instantiate = mod_instantiate,
1044 .detach = mod_detach,
1046 [MOD_AUTHENTICATE] = mod_authenticate,
1047 [MOD_AUTHORIZE] = mod_authorize,
1048 [MOD_PREACCT] = mod_preacct,
1049 [MOD_ACCOUNTING] = mod_accounting,
1050 [MOD_SESSION] = mod_checksimul,
1051 [MOD_PRE_PROXY] = mod_pre_proxy,
1052 [MOD_POST_PROXY] = mod_post_proxy,
1053 [MOD_POST_AUTH] = mod_post_auth,
1055 [MOD_RECV_COA] = mod_recv_coa,
1056 [MOD_SEND_COA] = mod_send_coa