static int do_python(REQUEST *request, PyObject *pFunc, char const *funcname) { vp_cursor_t cursor; VALUE_PAIR *vp; PyObject *pRet = NULL; PyObject *pArgs = NULL; int tuplelen; int ret; PyGILState_STATE gstate; /* Return with "OK, continue" if the function is not defined. */ if (!pFunc) return RLM_MODULE_OK; /* Default return value is "OK, continue" */ ret = RLM_MODULE_OK; /* * We will pass a tuple containing (name, value) tuples * We can safely use the Python function to build up a * tuple, since the tuple is not used elsewhere. * * Determine the size of our tuple by walking through the packet. * If request is NULL, pass None. */ tuplelen = 0; if (request != NULL) { for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) { tuplelen++; } } gstate = PyGILState_Ensure(); if (tuplelen == 0) { Py_INCREF(Py_None); pArgs = Py_None; } else { int i = 0; if ((pArgs = PyTuple_New(tuplelen)) == NULL) goto failed; for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor), i++) { PyObject *pPair; /* The inside tuple has two only: */ if ((pPair = PyTuple_New(2)) == NULL) goto failed; if (mod_populate_vptuple(pPair, vp) == 0) { /* Put the tuple inside the container */ PyTuple_SET_ITEM(pArgs, i, pPair); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(pArgs, i, Py_None); Py_DECREF(pPair); } } } /* Call Python function. */ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL); if (!pRet) goto failed; if (!request) goto okay; /* * The function returns either: * 1. (returnvalue, replyTuple, configTuple), where * - returnvalue is one of the constants RLM_* * - replyTuple and configTuple are tuples of string * tuples of size 2 * * 2. the function return value alone * * 3. None - default return value is set * * xxx This code is messy! */ if (PyTuple_CheckExact(pRet)) { PyObject *pTupleInt; if (PyTuple_GET_SIZE(pRet) != 3) { ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname); goto failed; } pTupleInt = PyTuple_GET_ITEM(pRet, 0); if (!PyInt_CheckExact(pTupleInt)) { ERROR("rlm_python:%s: first tuple element not an integer", funcname); goto failed; } /* Now have the return value */ ret = PyInt_AsLong(pTupleInt); /* Reply item tuple */ mod_vptuple(request->reply, &request->reply->vps, PyTuple_GET_ITEM(pRet, 1), funcname); /* Config item tuple */ mod_vptuple(request, &request->config_items, PyTuple_GET_ITEM(pRet, 2), funcname); } else if (PyInt_CheckExact(pRet)) { /* Just an integer */ ret = PyInt_AsLong(pRet); } else if (pRet == Py_None) { /* returned 'None', return value defaults to "OK, continue." */ ret = RLM_MODULE_OK; } else { /* Not tuple or None */ ERROR("rlm_python:%s: function did not return a tuple or None", funcname); goto failed; } okay: Py_DECREF(pArgs); Py_DECREF(pRet); PyGILState_Release(gstate); return ret; failed: mod_error(); Py_XDECREF(pArgs); Py_XDECREF(pRet); PyGILState_Release(gstate); return -1; }
static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker) { vp_cursor_t cursor; VALUE_PAIR *vp; PyObject *pRet = NULL; PyObject *pArgs = NULL; int tuplelen; int ret; PyGILState_STATE gstate; PyThreadState *prev_thread_state = NULL; /* -Wuninitialized */ memset(&gstate, 0, sizeof(gstate)); /* -Wuninitialized */ /* Return with "OK, continue" if the function is not defined. */ if (!pFunc) return RLM_MODULE_NOOP; #ifdef HAVE_PTHREAD_H gstate = PyGILState_Ensure(); if (worker) { PyThreadState *my_thread_state; my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup); if (!my_thread_state) { my_thread_state = PyThreadState_New(inst->main_thread_state->interp); if (!my_thread_state) { REDEBUG("Failed initialising local PyThreadState on first run"); PyGILState_Release(gstate); return RLM_MODULE_FAIL; } ret = fr_thread_local_set(local_thread_state, my_thread_state); if (ret != 0) { REDEBUG("Failed storing PyThreadState in TLS: %s", fr_syserror(ret)); PyThreadState_Clear(my_thread_state); PyThreadState_Delete(my_thread_state); PyGILState_Release(gstate); return RLM_MODULE_FAIL; } } prev_thread_state = PyThreadState_Swap(my_thread_state); /* Swap in our local thread state */ } #endif /* Default return value is "OK, continue" */ ret = RLM_MODULE_OK; /* * We will pass a tuple containing (name, value) tuples * We can safely use the Python function to build up a * tuple, since the tuple is not used elsewhere. * * Determine the size of our tuple by walking through the packet. * If request is NULL, pass None. */ tuplelen = 0; if (request != NULL) { for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) { tuplelen++; } } if (tuplelen == 0) { Py_INCREF(Py_None); pArgs = Py_None; } else { int i = 0; if ((pArgs = PyTuple_New(tuplelen)) == NULL) { ret = RLM_MODULE_FAIL; goto finish; } for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor), i++) { PyObject *pPair; /* The inside tuple has two only: */ if ((pPair = PyTuple_New(2)) == NULL) { ret = RLM_MODULE_FAIL; goto finish; } if (mod_populate_vptuple(pPair, vp) == 0) { /* Put the tuple inside the container */ PyTuple_SET_ITEM(pArgs, i, pPair); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(pArgs, i, Py_None); Py_DECREF(pPair); } } } /* Call Python function. */ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL); if (!pRet) { ret = RLM_MODULE_FAIL; goto finish; } if (!request) goto finish; /* * The function returns either: * 1. (returnvalue, replyTuple, configTuple), where * - returnvalue is one of the constants RLM_* * - replyTuple and configTuple are tuples of string * tuples of size 2 * * 2. the function return value alone * * 3. None - default return value is set * * xxx This code is messy! */ if (PyTuple_CheckExact(pRet)) { PyObject *pTupleInt; if (PyTuple_GET_SIZE(pRet) != 3) { ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname); ret = RLM_MODULE_FAIL; goto finish; } pTupleInt = PyTuple_GET_ITEM(pRet, 0); if (!PyInt_CheckExact(pTupleInt)) { ERROR("rlm_python:%s: first tuple element not an integer", funcname); ret = RLM_MODULE_FAIL; goto finish; } /* Now have the return value */ ret = PyInt_AsLong(pTupleInt); /* Reply item tuple */ mod_vptuple(request->reply, &request->reply->vps, PyTuple_GET_ITEM(pRet, 1), funcname); /* Config item tuple */ mod_vptuple(request, &request->config_items, PyTuple_GET_ITEM(pRet, 2), funcname); } else if (PyInt_CheckExact(pRet)) { /* Just an integer */ ret = PyInt_AsLong(pRet); } else if (pRet == Py_None) { /* returned 'None', return value defaults to "OK, continue." */ ret = RLM_MODULE_OK; } else { /* Not tuple or None */ ERROR("rlm_python:%s: function did not return a tuple or None", funcname); ret = RLM_MODULE_FAIL; goto finish; } finish: if (pArgs) { Py_DECREF(pArgs); } if (pRet) { Py_DECREF(pRet); } #ifdef HAVE_PTHREAD_H if (worker) { PyThreadState_Swap(prev_thread_state); } PyGILState_Release(gstate); #endif return ret; }