28 RCSID(
"$Id: d82fc558fc29356130567efd0cdfa7914c6367c2 $")
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/modules.h>
37 #define Pyx_BLOCK_THREADS {PyGILState_STATE __gstate = PyGILState_Ensure();
38 #define Pyx_UNBLOCK_THREADS PyGILState_Release(__gstate);}
40 #define Pyx_BLOCK_THREADS
41 #define Pyx_UNBLOCK_THREADS
84 #define A(x) { FR_CONF_OFFSET("mod_" #x, PW_TYPE_STRING, rlm_python_t, x.module_name) }, \
85 { FR_CONF_OFFSET("func_" #x, PW_TYPE_STRING, rlm_python_t, x.function_name) },
113 #define A(x) { #x, x },
147 static PyObject *radiusd_module = NULL;
154 static PyObject *mod_radlog(
UNUSED PyObject *module, PyObject *args)
159 if (!PyArg_ParseTuple(args,
"is", &status, &msg)) {
163 radlog(status,
"%s", msg);
170 {
"radlog", &mod_radlog, METH_VARARGS,
171 "radiusd.radlog(level, msg)\n\n" \
172 "Print a message using radiusd logging system. level should be one of the\n" \
173 "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
175 { NULL, NULL, 0, NULL },
181 PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
185 PyErr_Fetch(&pType, &pValue, &pTraceback);
186 if (!pType || !pValue)
188 if (((pStr1 = PyObject_Str(pType)) == NULL) ||
189 ((pStr2 = PyObject_Str(pValue)) == NULL))
192 ERROR(
"rlm_python:EXCEPT:%s: %s", PyString_AsString(pStr1), PyString_AsString(pStr2));
199 Py_XDECREF(pTraceback);
207 if (radiusd_module)
return 0;
215 WARN(
"Failed loading libpython symbols into global symbol table: %s", dlerror());
219 Py_SetProgramName(name);
220 #ifdef HAVE_PTHREAD_H
222 PyEval_InitThreads();
232 if ((radiusd_module = Py_InitModule3(
main_config.
name, module_methods,
"rlm_python module")) == NULL)
242 #ifdef HAVE_PTHREAD_H
243 PyThreadState_Swap(NULL);
244 PyEval_ReleaseLock();
246 DEBUG(
"mod_init done");
250 Py_XDECREF(radiusd_module);
252 #ifdef HAVE_PTHREAD_H
253 PyEval_ReleaseLock();
260 radiusd_module = NULL;
268 static int mod_destroy(
void)
271 Py_XDECREF(radiusd_module);
287 char const *funcname)
297 if (pValue == Py_None)
300 if (!PyTuple_CheckExact(pValue)) {
301 ERROR(
"rlm_python:%s: non-tuple passed", funcname);
305 tuplesize = PyTuple_GET_SIZE(pValue);
306 for (i = 0; i < tuplesize; i++) {
307 PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
316 if (!PyTuple_CheckExact(pTupleElement)) {
317 ERROR(
"rlm_python:%s: tuple element %d is not a tuple", funcname, i);
322 pairsize = PyTuple_GET_SIZE(pTupleElement);
323 if ((pairsize < 2) || (pairsize > 3)) {
324 ERROR(
"rlm_python:%s: tuple element %d is a tuple of size %d. Must be 2 or 3.", funcname, i, pairsize);
329 pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
330 pStr2 = PyTuple_GET_ITEM(pTupleElement, 1);
333 pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
334 pStr2 = PyTuple_GET_ITEM(pTupleElement, 2);
335 pOp = PyTuple_GET_ITEM(pTupleElement, 1);
336 op = PyInt_AsLong(pOp);
339 if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
340 ERROR(
"rlm_python:%s: tuple element %d must be as (str, str)", funcname, i);
343 s1 = PyString_AsString(pStr1);
344 s2 = PyString_AsString(pStr2);
347 DEBUG(
"rlm_python:%s: '%s' = '%s'", funcname, s1, s2);
349 DEBUG(
"rlm_python:%s: Failed: '%s' = '%s'", funcname, s1, s2);
364 PyObject *pStr = NULL;
370 pStr = PyString_FromFormat(
"%s:%d", vp->
da->
name, vp->
tag);
372 pStr = PyString_FromString(vp->
da->
name);
377 PyTuple_SET_ITEM(pPair, 0, pStr);
381 if ((pStr = PyString_FromString(buf)) == NULL)
383 PyTuple_SET_ITEM(pPair, 1, pStr);
391 #ifdef HAVE_PTHREAD_H
394 static void do_python_cleanup(
void *arg)
396 PyThreadState *my_thread_state = arg;
398 PyEval_AcquireLock();
399 PyThreadState_Swap(NULL);
400 PyThreadState_Clear(my_thread_state);
401 PyThreadState_Delete(my_thread_state);
402 PyEval_ReleaseLock();
410 PyObject *pRet = NULL;
411 PyObject *pArgs = NULL;
415 PyGILState_STATE gstate;
416 PyThreadState *prev_thread_state = NULL;
417 memset(&gstate, 0,
sizeof(gstate));
423 #ifdef HAVE_PTHREAD_H
424 gstate = PyGILState_Ensure();
426 PyThreadState *my_thread_state;
427 my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup);
428 if (!my_thread_state) {
430 RDEBUG3(
"Initialised new thread state %p", my_thread_state);
431 if (!my_thread_state) {
432 REDEBUG(
"Failed initialising local PyThreadState on first run");
433 PyGILState_Release(gstate);
437 ret = fr_thread_local_set(local_thread_state, my_thread_state);
440 PyThreadState_Clear(my_thread_state);
441 PyThreadState_Delete(my_thread_state);
442 PyGILState_Release(gstate);
446 RDEBUG3(
"Using thread state %p", my_thread_state);
447 prev_thread_state = PyThreadState_Swap(my_thread_state);
463 if (request != NULL) {
476 if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
487 if ((pPair = PyTuple_New(2)) == NULL) {
494 PyTuple_SET_ITEM(pArgs, i, pPair);
497 PyTuple_SET_ITEM(pArgs, i, Py_None);
504 pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
527 if (PyTuple_CheckExact(pRet)) {
530 if (PyTuple_GET_SIZE(pRet) != 3) {
531 ERROR(
"rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
536 pTupleInt = PyTuple_GET_ITEM(pRet, 0);
537 if (!PyInt_CheckExact(pTupleInt)) {
538 ERROR(
"rlm_python:%s: first tuple element not an integer", funcname);
543 ret = PyInt_AsLong(pTupleInt);
546 PyTuple_GET_ITEM(pRet, 1), funcname);
549 PyTuple_GET_ITEM(pRet, 2), funcname);
551 }
else if (PyInt_CheckExact(pRet)) {
553 ret = PyInt_AsLong(pRet);
555 }
else if (pRet == Py_None) {
560 ERROR(
"rlm_python:%s: function did not return a tuple or None", funcname);
569 #ifdef HAVE_PTHREAD_H
571 PyThreadState_Swap(prev_thread_state);
573 PyGILState_Release(gstate);
585 char const *funcname =
"mod_load_function";
586 PyGILState_STATE gstate;
588 gstate = PyGILState_Ensure();
592 ERROR(
"rlm_python:%s: module '%s' is not found", funcname, def->
module_name);
601 if (!PyCallable_Check(def->
function)) {
606 PyGILState_Release(gstate);
616 PyGILState_Release(gstate);
639 #define A(x) mod_funcdef_clear(&inst->x)
671 #define A(x) if (mod_load_function(&inst->x) < 0) goto failed
694 return do_python(inst, NULL, inst->instantiate.function,
"instantiate",
false);
719 #define A(x) static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
720 return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x, true);\
753 .config = module_config,
5 methods index for preproxy section.
struct py_function_def instantiate authorize authenticate preacct accounting checksimul pre_proxy post_proxy post_auth recv_coa send_coa detach
static void mod_instance_clear(rlm_python_t *inst)
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Only displayed when debugging is enabled.
Main server configuration.
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
Write accounting data to Couchbase documents.
The module is OK, continue.
static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
int radlog(log_type_t lvl, char const *fmt,...) CC_HINT(format(printf
static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker)
7 methods index for postauth section.
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
int8_t tag
Tag value used to group valuepairs.
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define CONF_PARSER_TERMINATOR
#define Pyx_BLOCK_THREADS
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
The module considers the request invalid.
char const * name
Name of the daemon, usually 'radiusd'.
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull)
Defines a CONF_PAIR to C data type mapping.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
fr_dict_attr_flags_t flags
Flags.
Reject the request (user is locked out).
static struct @22 radiusd_constants[]
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
fr_thread_local_setup(PyThreadState *, local_thread_state)
4 methods index for checksimul section.
struct rlm_python_t rlm_python_t
static void mod_error(void)
static void mod_vptuple(TALLOC_CTX *ctx, VALUE_PAIR **vps, PyObject *pValue, char const *funcname)
Immediately reject the request.
static CONF_PARSER module_config[]
static void mod_funcdef_clear(struct py_function_def *def)
3 methods index for accounting section.
Stores an attribute, a value and various bits of other data.
static void mod_objclear(PyObject **ob)
static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request)
Check if a given user is already logged in.
RADIUS_PACKET * reply
Outgoing response.
0 methods index for authenticate section.
static PyMethodDef module_methods[]
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
Module succeeded without doing anything.
char name[1]
Attribute name.
uint64_t magic
Used to validate module struct.
Module failed, don't reply.
#define Pyx_UNBLOCK_THREADS
#define FR_CONF_OFFSET(_n, _t, _s, _f)
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
RADIUS_PACKET * packet
Incoming request.
static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
PyThreadState * main_thread_state
unsigned int has_tag
Tagged attribute.
static int mod_detach(void *instance)
6 methods index for postproxy section.
2 methods index for preacct section.
8 methods index for recvcoa section.
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
9 methods index for sendcoa section.
How many valid return codes there are.
String of printable characters.
char const * function_name
1 methods index for authorize section.
The module handled the request, so stop.
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
static int mod_load_function(struct py_function_def *def)
static int mod_init(rlm_python_t *inst)