📄 rlm_python.c
字号:
} if ((PyTuple_SetItem(pArgs, 0, pValuePairContainer)) != 0) { radlog(L_ERR, "%s: could not set tuple item", function_name); return -1; } if ((pValue = PyObject_CallObject(pFunc, pArgs)) == NULL) { radlog(L_ERR, "%s: function call failed", function_name); python_error(); return -1; } /* The function returns either: * 1. tuple containing the integer return value, * then the integer reply code (or None to not set), * then the string tuples to build the reply with. * (returnvalue, (p1, s1), (p2, s2)) * * 2. the function return value alone * * 3. None - default return value is set * * xxx This code is messy! */ if (PyTuple_Check(pValue)) { PyObject *pTupleInt; if (PyTuple_Size(pValue) != 3) { radlog(L_ERR, "%s: tuple must be " \ "(return, replyTuple, configTuple)", function_name); } else { pTupleInt = PyTuple_GetItem(pValue, 0); if ((pTupleInt == NULL) || !PyInt_Check(pTupleInt)) { radlog(L_ERR, "%s: first tuple element not an integer", function_name); } else { /* Now have the return value */ return_value = PyInt_AsLong(pTupleInt); /* Reply item tuple */ add_vp_tuple(&request->reply->vps, PyTuple_GetItem(pValue, 1), function_name); /* Config item tuple */ add_vp_tuple(&request->config_items, PyTuple_GetItem(pValue, 2), function_name); } } } else if (PyInt_Check(pValue)) { /* Just an integer */ return_value = PyInt_AsLong(pValue); } else if (pValue == Py_None) { /* returned 'None', return value defaults to "OK, continue." */ return_value = RLM_MODULE_OK; } else { /* Not tuple or None */ radlog(L_ERR, "%s function did not return a tuple or None\n", function_name); } /* Decrease reference counts for the argument and return tuple */ Py_DECREF(pArgs); Py_DECREF(pValue); } /* Decrease reference count for the tuples passed, the * container tuple, and the return value. */ pValueHolderPtr = pValueHolder; i = n_tuple; while (i--) { /* Can't write as pValueHolderPtr since Py_DECREF is a macro */ Py_DECREF(*pValueHolderPtr); pValueHolderPtr++; } free(pValueHolder); Py_DECREF(pValuePairContainer); /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */ /* Free pairs if we are rejecting. * xxx Shouldn't the core do that? */ if ((return_value == RLM_MODULE_REJECT) && (request != NULL)) { pairfree(&(request->reply->vps)); } /* Return the specified by the Python module */ return return_value;}static struct varlookup { const char* name; int value;} constants[] = { { "L_DBG", L_DBG }, { "L_AUTH", L_AUTH }, { "L_INFO", L_INFO }, { "L_ERR", L_ERR }, { "L_PROXY", L_PROXY }, { "L_CONS", L_CONS }, { "RLM_MODULE_REJECT", RLM_MODULE_REJECT }, { "RLM_MODULE_FAIL", RLM_MODULE_FAIL }, { "RLM_MODULE_OK", RLM_MODULE_OK }, { "RLM_MODULE_HANDLED", RLM_MODULE_HANDLED }, { "RLM_MODULE_INVALID", RLM_MODULE_INVALID }, { "RLM_MODULE_USERLOCK",RLM_MODULE_USERLOCK }, { "RLM_MODULE_NOTFOUND",RLM_MODULE_NOTFOUND }, { "RLM_MODULE_NOOP", RLM_MODULE_NOOP }, { "RLM_MODULE_UPDATED", RLM_MODULE_UPDATED }, { "RLM_MODULE_NUMCODES",RLM_MODULE_NUMCODES }, { NULL, 0 },};/* * Import a user module and load a function from it */static int load_python_function(const char* module, const char* func, PyObject** pyModule, PyObject** pyFunc) { if ((module==NULL) || (func==NULL)) { *pyFunc=NULL; *pyModule=NULL; } else { PyObject *pName; pName = PyString_FromString(module); Py_INCREF(pName); *pyModule = PyImport_Import(pName); Py_DECREF(pName); if (*pyModule != NULL) { PyObject *pDict; pDict = PyModule_GetDict(*pyModule); /* pDict: borrowed reference */ *pyFunc = PyDict_GetItemString(pDict, func); /* pFunc: Borrowed reference */ } else { python_error(); radlog(L_ERR, "Failed to import python module \"%s\"\n", module); return -1; } } return 0;}/* * 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){ rlm_python_t *data; PyObject *module; int idx; /* * Set up a storage area for instance data */ data = rad_malloc(sizeof(*data)); if (!data) { return -1; } memset(data, 0, sizeof(*data)); /* * If the configuration parameters can't be parsed, then * fail. */ if (cf_section_parse(conf, data, module_config) < 0) { free(data); return -1; } /* * Setup our 'radiusd' module. */ /* Code */ if ((module = data->pModule_builtin = Py_InitModule3("radiusd", radiusd_methods, "FreeRADIUS Module.")) == NULL) { radlog(L_ERR, "Python Py_InitModule3 failed"); free(data); return -1; } /* * Load constants into module */ for (idx=0; constants[idx].name; idx++) if ((PyModule_AddIntConstant(module, constants[idx].name, constants[idx].value)) == -1) { radlog(L_ERR, "Python AddIntConstant failed"); } /* * Import user modules. */ if (load_python_function(data->mod_instantiate, data->func_instantiate, &data->pModule_instantiate, &data->pFunc_instantiate)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_authenticate, data->func_authenticate, &data->pModule_authenticate, &data->pFunc_authenticate)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_authorize, data->func_authorize, &data->pModule_authorize, &data->pFunc_authorize)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_preacct, data->func_preacct, &data->pModule_preacct, &data->pFunc_preacct)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_accounting, data->func_accounting, &data->pModule_accounting, &data->pFunc_accounting)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_checksimul, data->func_checksimul, &data->pModule_checksimul, &data->pFunc_checksimul)==-1) { /* TODO: check if we need to cleanup data */ return -1; } if (load_python_function(data->mod_detach, data->func_detach, &data->pModule_detach, &data->pFunc_detach)==-1) { /* TODO: check if we need to cleanup data */ return -1; } *instance=data; /* Call the instantiate function. No request. Use the return value. */ return python_function(NULL, data->pFunc_instantiate, "instantiate");}/* Wrapper functions */static int python_authorize(void *instance, REQUEST *request){ return python_function(request, ((struct rlm_python_t *)instance)->pFunc_authorize, "authorize");}static int python_authenticate(void *instance, REQUEST *request){ return python_function( request, ((struct rlm_python_t *)instance)->pFunc_authenticate, "authenticate");}static int python_preacct(void *instance, REQUEST *request){ return python_function( request, ((struct rlm_python_t *)instance)->pFunc_preacct, "preacct");}static int python_accounting(void *instance, REQUEST *request){ return python_function( request, ((struct rlm_python_t *)instance)->pFunc_accounting, "accounting");}static int python_checksimul(void *instance, REQUEST *request){ return python_function( request, ((struct rlm_python_t *)instance)->pFunc_checksimul, "checksimul");}static int python_detach(void *instance){ int return_value; /* Default return value is failure */ return_value = -1; if (((rlm_python_t *)instance)->pFunc_detach && PyCallable_Check(((rlm_python_t *)instance)->pFunc_detach)) { PyObject *pArgs, *pValue; /* call the function with an empty tuple */ pArgs = PyTuple_New(0); pValue = PyObject_CallObject(((rlm_python_t *)instance)->pFunc_detach, pArgs); if (pValue == NULL) { python_error(); return -1; } else { if (!PyInt_Check(pValue)) { radlog(L_ERR, "detach: return value not an integer"); } else { return_value = PyInt_AsLong(pValue); } } /* Decrease reference counts for the argument and return tuple */ Py_DECREF(pArgs); Py_DECREF(pValue); } free(instance);#if 0 /* xxx test delete module object so it will be reloaded later. * xxx useless since we can't SIGHUP reliably, anyway. */ PyObject_Del(((struct rlm_python_t *)instance)->pModule_accounting);#endif radlog(L_DBG, "python_detach done"); /* Return the specified by the Python module */ return return_value;}/* * 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 = { "python", RLM_TYPE_THREAD_SAFE, /* type */ python_init, /* initialization */ python_instantiate, /* instantiation */ { python_authenticate, /* authentication */ python_authorize, /* authorization */ python_preacct, /* preaccounting */ python_accounting, /* accounting */ python_checksimul, /* checksimul */ NULL, /* pre-proxy */ NULL, /* post-proxy */ NULL /* post-auth */ }, python_detach, /* detach */ NULL, /* destroy */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -