📄 rlm_python.c
字号:
/* * rlm_python.c * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006 The FreeRADIUS server project * Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com> * Copyright 2002 Imperium Technology, Inc. */#include <freeradius-devel/ident.h>RCSID("$Id: rlm_python.c,v 1.15 2007/12/28 21:08:39 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include <Python.h>/* * Define a structure for our module configuration. * * These variables do not need to be in a structure, but it's * a lot cleaner to do so, and a pointer to the structure can * be used as the instance handle. */typedef struct rlm_python_t {#define RLM_PYTHON_STRUCT(foo) char *mod_##foo; \ char *func_##foo; \ PyObject *pModule_##foo; \ PyObject *pFunc_##foo RLM_PYTHON_STRUCT(instantiate); RLM_PYTHON_STRUCT(authorize); RLM_PYTHON_STRUCT(authenticate); RLM_PYTHON_STRUCT(preacct); RLM_PYTHON_STRUCT(accounting); RLM_PYTHON_STRUCT(checksimul); RLM_PYTHON_STRUCT(preproxy); RLM_PYTHON_STRUCT(postproxy); RLM_PYTHON_STRUCT(postauth); RLM_PYTHON_STRUCT(detach); PyObject *pModule_builtin;} rlm_python_t;/* * A mapping of configuration file names to internal variables. * * Note that the string is dynamically allocated, so it MUST * be freed. When the configuration file parse re-reads the string, * it free's the old one, and strdup's the new one, placing the pointer * to the strdup'd string into 'config.string'. This gets around * buffer over-flows. */#define RLM_PYTHON_CONF(foo) { "mod_"#foo, PW_TYPE_STRING_PTR, \ offsetof(rlm_python_t, mod_##foo), NULL, NULL}, \ { "func_"#foo, PW_TYPE_STRING_PTR, \ offsetof(rlm_python_t, func_##foo), NULL, NULL}static const CONF_PARSER module_config[] = { RLM_PYTHON_CONF(instantiate), RLM_PYTHON_CONF(authorize), RLM_PYTHON_CONF(authenticate), RLM_PYTHON_CONF(preacct), RLM_PYTHON_CONF(accounting), RLM_PYTHON_CONF(checksimul), RLM_PYTHON_CONF(preproxy), RLM_PYTHON_CONF(postproxy), RLM_PYTHON_CONF(postauth), RLM_PYTHON_CONF(detach), { NULL, -1, 0, NULL, NULL } /* end the list */};/* * radiusd Python functions *//* radlog wrapper */static PyObject *radlog_py(UNUSED const PyObject *self, PyObject *args) { int status; char *msg; if (!PyArg_ParseTuple(args, "is", &status, &msg)) { return NULL; } radlog(status, msg); return Py_None;}static PyMethodDef radiusd_methods[] = { {"radlog", (PyCFunction)radlog_py, METH_VARARGS, "freeradius radlog()."}, {NULL, NULL, 0, NULL}};/* Extract string representation of Python error. */static void python_error(void) { PyObject *pType, *pValue, *pTraceback, *pStr1, *pStr2; PyErr_Fetch(&pType, &pValue, &pTraceback); pStr1 = PyObject_Str(pType); pStr2 = PyObject_Str(pValue); radlog(L_ERR, "%s: %s\n", PyString_AsString(pStr1), PyString_AsString(pStr2));}/* Tuple to value pair conversion */static void add_vp_tuple(VALUE_PAIR **vpp, PyObject *pValue, const char *function_name) { int i, outertuplesize; VALUE_PAIR *vp; /* If the Python function gave us None for the tuple, then just return. */ if (pValue == Py_None) { return; } if (!PyTuple_Check(pValue)) { radlog(L_ERR, "%s: non-tuple passed", function_name); } /* Get the tuple size. */ outertuplesize = PyTuple_Size(pValue); for (i = 0; i < outertuplesize; i++) { PyObject *pTupleElement = PyTuple_GetItem(pValue, i); if ((pTupleElement != NULL) && (PyTuple_Check(pTupleElement))) { /* Check if it's a pair */ int tuplesize; if ((tuplesize = PyTuple_Size(pTupleElement)) != 2) { radlog(L_ERR, "%s: tuple element %d is a tuple " " of size %d. must be 2\n", function_name, i, tuplesize); } else { PyObject *pString1, *pString2; pString1 = PyTuple_GetItem(pTupleElement, 0); pString2 = PyTuple_GetItem(pTupleElement, 1); /* xxx PyString_Check does not compile here */ if ((pString1 != NULL) && (pString2 != NULL) && PyObject_TypeCheck(pString1,&PyString_Type) && PyObject_TypeCheck(pString2,&PyString_Type)) { const char *s1, *s2; /* pairmake() will convert and find any * errors in the pair. */ s1 = PyString_AsString(pString1); s2 = PyString_AsString(pString2); if ((s1 != NULL) && (s2 != NULL)) { radlog(L_DBG, "%s: %s = %s ", function_name, s1, s2); /* xxx Might need to support other T_OP */ vp = pairmake(s1, s2, T_OP_EQ); if (vp != NULL) { pairadd(vpp, vp); radlog(L_DBG, "%s: s1, s2 OK\n", function_name); } else { radlog(L_DBG, "%s: s1, s2 FAILED\n", function_name); } } else { radlog(L_ERR, "%s: string conv failed\n", function_name); } } else { radlog(L_ERR, "%s: tuple element %d must be " "(string, string)", function_name, i); } } } else { radlog(L_ERR, "%s: tuple element %d is not a tuple\n", function_name, i); } }}/* This is the core Python function that the others wrap around. * Pass the value-pair print strings in a tuple. * xxx We're not checking the errors. If we have errors, what do we do? */static int python_function(REQUEST *request, PyObject *pFunc, const char *function_name){#define BUF_SIZE 1024 char buf[BUF_SIZE]; /* same size as vp_print buffer */ VALUE_PAIR *vp; PyObject *pValue, *pValuePairContainer, **pValueHolder, **pValueHolderPtr; int i, n_tuple, return_value; /* Return with "OK, continue" if the function is not defined. */ if (pFunc == NULL) { return RLM_MODULE_OK; } /* Default return value is "OK, continue" */ return_value = 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. */ n_tuple = 0; if (request != NULL) { for (vp = request->packet->vps; vp; vp = vp->next) { n_tuple++; } } /* Create the tuple and a holder for the pointers, so that we can * decref more efficiently later without the overhead of reading * the tuple. * * We use malloc() instead of the Python memory allocator since we * are not embedded. */ if (NULL == (pValueHolder = pValueHolderPtr = malloc(sizeof(PyObject *) * n_tuple))) { radlog(L_ERR, "%s: malloc of %d bytes failed\n", function_name, sizeof(PyObject *) * n_tuple); return -1; } if (n_tuple == 0) { pValuePairContainer = Py_None; } else { pValuePairContainer = PyTuple_New(n_tuple); i = 0; for (vp = request->packet->vps; vp; vp = vp->next) { PyObject *pValuePair, *pString1, *pString2; /* The inside tuple has two only: */ pValuePair = PyTuple_New(2); /* The name. logic from vp_prints, lib/print.c */ if (vp->flags.has_tag) { snprintf(buf, BUF_SIZE, "%s:%d", vp->name, vp->flags.tag); } else { strcpy(buf, vp->name); } pString1 = PyString_FromString(buf); PyTuple_SetItem(pValuePair, 0, pString1); /* The value. Use delimiter - don't know what that means */ vp_prints_value(buf, sizeof(buf), vp, 1); pString2 = PyString_FromString(buf); PyTuple_SetItem(pValuePair, 1, pString2); /* Put the tuple inside the container */ PyTuple_SetItem(pValuePairContainer, i++, pValuePair); /* Store the pointer in our malloc() storage */ *pValueHolderPtr++ = pValuePair; } } /* Call Python function. */ if (pFunc && PyCallable_Check(pFunc)) { PyObject *pArgs; /* call the function with a singleton tuple containing the * container tuple. */ if ((pArgs = PyTuple_New(1)) == NULL) { Py_DECREF(pValuePairContainer); free(pValueHolder); radlog(L_ERR, "%s: could not create tuple", function_name); return -1; } if ((PyTuple_SetItem(pArgs, 0, pValuePairContainer)) != 0) { Py_DECREF(pValuePairContainer); free(pValueHolder); Py_DECREF(pArgs); radlog(L_ERR, "%s: could not set tuple item", function_name); return -1; } if ((pValue = PyObject_CallObject(pFunc, pArgs)) == NULL) { Py_DECREF(pValuePairContainer); free(pValueHolder); Py_DECREF(pArgs); radlog(L_ERR, "%s: function call failed", function_name); python_error();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -