📄 rlm_python.c
字号:
{ 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 == NULL) 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 = request->packet->vps; vp; vp = vp->next) 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 = request->packet->vps; vp != NULL; vp = vp->next, i++) { PyObject *pPair; /* The inside tuple has two only: */ if ((pPair = PyTuple_New(2)) == NULL) goto failed; if (python_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 == NULL) goto failed; if (request == NULL) 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) { radlog(L_ERR, "rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname); goto failed; } pTupleInt = PyTuple_GET_ITEM(pRet, 0); if (!PyInt_CheckExact(pTupleInt)) { radlog(L_ERR, "rlm_python:%s: first tuple element not an integer", funcname); goto failed; } /* Now have the return value */ ret = PyInt_AsLong(pTupleInt); /* Reply item tuple */ python_vptuple(&request->reply->vps, PyTuple_GET_ITEM(pRet, 1), funcname); /* Config item tuple */ python_vptuple(&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 */ radlog(L_ERR, "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: python_error(); Py_XDECREF(pArgs); Py_XDECREF(pRet); PyGILState_Release(gstate); return -1;}/* * Import a user module and load a function from it */static int python_load_function(struct py_function_def *def){ const char *funcname = "python_load_function"; PyGILState_STATE gstate; gstate = PyGILState_Ensure(); if (def->module_name != NULL && def->function_name != NULL) { if ((def->module = PyImport_ImportModule(def->module_name)) == NULL) { radlog(L_ERR, "rlm_python:%s: module '%s' is not found", funcname, def->module_name); goto failed; } if ((def->function = PyObject_GetAttrString(def->module, def->function_name)) == NULL) { radlog(L_ERR, "rlm_python:%s: function '%s.%s' is not found", funcname, def->module_name, def->function_name); goto failed; } if (!PyCallable_Check(def->function)) { radlog(L_ERR, "rlm_python:%s: function '%s.%s' is not callable", funcname, def->module_name, def->function_name); goto failed; } } PyGILState_Release(gstate); return 0; failed: python_error(); radlog(L_ERR, "rlm_python:%s: failed to import python function '%s.%s'", funcname, def->module_name, def->function_name); Py_XDECREF(def->function); def->function = NULL; Py_XDECREF(def->module); def->module = NULL; PyGILState_Release(gstate); return -1;}static void python_objclear(PyObject **ob){ if (*ob != NULL) { Pyx_BLOCK_THREADS Py_DECREF(*ob); Pyx_UNBLOCK_THREADS *ob = NULL; }}static void free_and_null(char **p){ if (*p != NULL) { free(*p); *p = NULL; }}static void python_funcdef_clear(struct py_function_def *def){ python_objclear(&def->function); python_objclear(&def->module); free_and_null(&def->function_name); free_and_null(&def->module_name);}static void python_instance_clear(struct rlm_python_t *data){#define A(x) python_funcdef_clear(&data->x) A(instantiate); A(authorize); A(authenticate); A(preacct); A(accounting); A(checksimul); A(detach);#undef A}/* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections * to external databases, read configuration files, set up * dictionary entries, etc. * * If configuration information is given in the config section * that must be referenced in later calls, store a handle to it * in *instance otherwise put a null pointer there. * */static int python_instantiate(CONF_SECTION *conf, void **instance){ struct rlm_python_t *data = NULL; /* * Set up a storage area for instance data */ if ((data = malloc(sizeof(*data))) == NULL) return -1; memset(data, 0, sizeof(*data)); if (python_init() != 0) { free(data); return -1; } /* * If the configuration parameters can't be parsed, then * fail. */ if (cf_section_parse(conf, data, module_config) < 0) { free(data); return -1; }#define A(x) if (python_load_function(&data->x) < 0) goto failed A(instantiate); A(authenticate); A(authorize); A(preacct); A(accounting); A(checksimul); A(detach);#undef A *instance = data; /* * Call the instantiate function. No request. Use the * return value. */ return python_function(NULL, data->instantiate.function, "instantiate"); failed: python_error(); python_instance_clear(data); free(data); return -1;}static int python_detach(void *instance){ struct rlm_python_t *data = (struct rlm_python_t *) instance; int ret; ret = python_function(NULL, data->detach.function, "detach"); python_instance_clear(data); free(data); return ret;}#define A(x) static int python_##x(void *instance, REQUEST *request) { \ return python_function(request, ((struct rlm_python_t *)instance)->x.function, #x); \}A(authenticate)A(authorize)A(preacct)A(accounting)A(checksimul)#undef A/* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. * * If the module needs to temporarily modify it's instantiation * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. * The server will then take care of ensuring that the module * is single-threaded. */module_t rlm_python = { RLM_MODULE_INIT, "python", RLM_TYPE_THREAD_SAFE, /* type */ python_instantiate, /* instantiation */ python_detach, { python_authenticate, /* authentication */ python_authorize, /* authorization */ python_preacct, /* preaccounting */ python_accounting, /* accounting */ python_checksimul, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ NULL /* post-auth */ }};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -