All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_python.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: d82fc558fc29356130567efd0cdfa7914c6367c2 $
19  * @file rlm_python.c
20  * @brief Translates requests between the server an a python interpreter.
21  *
22  * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
23  *
24  * @copyright 2000,2006 The FreeRADIUS server project
25  * @copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
26  * @copyright 2002 Imperium Technology, Inc.
27  */
28 RCSID("$Id: d82fc558fc29356130567efd0cdfa7914c6367c2 $")
29 
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/modules.h>
32 
33 #include <Python.h>
34 #include <dlfcn.h>
35 
36 #ifdef HAVE_PTHREAD_H
37 #define Pyx_BLOCK_THREADS {PyGILState_STATE __gstate = PyGILState_Ensure();
38 #define Pyx_UNBLOCK_THREADS PyGILState_Release(__gstate);}
39 #else
40 #define Pyx_BLOCK_THREADS
41 #define Pyx_UNBLOCK_THREADS
42 #endif
43 
44 /*
45  * TODO: The only needed thing here is function. Anything else is
46  * required for initialization only. I will remove it, putting a
47  * symbolic constant here instead.
48  */
50  PyObject *module;
51  PyObject *function;
52 
53  char const *module_name;
54  char const *function_name;
55 };
56 
57 typedef struct rlm_python_t {
58  void *libpython;
59  PyThreadState *main_thread_state;
60  char const *python_path;
61 
63  instantiate,
64  authorize,
65  authenticate,
66  preacct,
67  accounting,
68  checksimul,
69  pre_proxy,
70  post_proxy,
71  post_auth,
72 #ifdef WITH_COA
73  recv_coa,
74  send_coa,
75 #endif
76  detach;
77 } rlm_python_t;
78 
79 /*
80  * A mapping of configuration file names to internal variables.
81  */
83 
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) },
86 
87  A(instantiate)
88  A(authorize)
89  A(authenticate)
90  A(preacct)
91  A(accounting)
92  A(checksimul)
93  A(pre_proxy)
94  A(post_proxy)
95  A(post_auth)
96 #ifdef WITH_COA
97  A(recv_coa)
98  A(send_coa)
99 #endif
100  A(detach)
101 
102 #undef A
103 
104  { FR_CONF_OFFSET("python_path", PW_TYPE_STRING, rlm_python_t, python_path) },
106 };
107 
108 static struct {
109  char const *name;
110  int value;
111 } radiusd_constants[] = {
112 
113 #define A(x) { #x, x },
114 
115  A(L_DBG)
116  A(L_AUTH)
117  A(L_INFO)
118  A(L_ERR)
119  A(L_PROXY)
130 
131 #undef A
132 
133  { NULL, 0 },
134 };
135 
136 /*
137  * This allows us to initialise PyThreadState on a per thread basis
138  */
139 fr_thread_local_setup(PyThreadState *, local_thread_state) /* macro */
140 
141 
142 /*
143  * Let assume that radiusd module is only one since we have only
144  * one intepreter
145  */
146 
147 static PyObject *radiusd_module = NULL;
148 
149 /*
150  * radiusd Python functions
151  */
152 
153 /* radlog wrapper */
154 static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
155 {
156  int status;
157  char *msg;
158 
159  if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
160  return NULL;
161  }
162 
163  radlog(status, "%s", msg);
164  Py_INCREF(Py_None);
165 
166  return Py_None;
167 }
168 
169 static PyMethodDef module_methods[] = {
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"
174  },
175  { NULL, NULL, 0, NULL },
176 };
177 
178 
179 static void mod_error(void)
180 {
181  PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
182 
183  /* This will be called with the GIL lock held */
184 
185  PyErr_Fetch(&pType, &pValue, &pTraceback);
186  if (!pType || !pValue)
187  goto failed;
188  if (((pStr1 = PyObject_Str(pType)) == NULL) ||
189  ((pStr2 = PyObject_Str(pValue)) == NULL))
190  goto failed;
191 
192  ERROR("rlm_python:EXCEPT:%s: %s", PyString_AsString(pStr1), PyString_AsString(pStr2));
193 
194 failed:
195  Py_XDECREF(pStr1);
196  Py_XDECREF(pStr2);
197  Py_XDECREF(pType);
198  Py_XDECREF(pValue);
199  Py_XDECREF(pTraceback);
200 }
201 
203 {
204  int i;
205  char *name;
206 
207  if (radiusd_module) return 0;
208 
209  /*
210  * Explicitly load libpython, so symbols will be available to lib-dynload modules
211  */
212  inst->libpython = dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
213  RTLD_NOW | RTLD_GLOBAL);
214  if (!inst->libpython) {
215  WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
216  }
217 
218  memcpy(&name, &main_config.name, sizeof(name));
219  Py_SetProgramName(name);
220 #ifdef HAVE_PTHREAD_H
221  Py_InitializeEx(0); /* Don't override signal handlers */
222  PyEval_InitThreads(); /* This also grabs a lock */
223  inst->main_thread_state = PyThreadState_Get(); /* We need this for setting up thread local stuff */
224 #endif
225  if (inst->python_path) {
226  char *path;
227 
228  memcpy(&path, &inst->python_path, sizeof(path));
229  PySys_SetPath(path);
230  }
231 
232  if ((radiusd_module = Py_InitModule3(main_config.name, module_methods, "rlm_python module")) == NULL)
233  goto failed;
234 
235  for (i = 0; radiusd_constants[i].name; i++) {
236  if ((PyModule_AddIntConstant(radiusd_module, radiusd_constants[i].name,
237  radiusd_constants[i].value)) < 0) {
238  goto failed;
239  }
240  }
241 
242 #ifdef HAVE_PTHREAD_H
243  PyThreadState_Swap(NULL); /* We have to swap out the current thread else we get deadlocks */
244  PyEval_ReleaseLock(); /* Drop lock grabbed by InitThreads */
245 #endif
246  DEBUG("mod_init done");
247  return 0;
248 
249 failed:
250  Py_XDECREF(radiusd_module);
251 
252 #ifdef HAVE_PTHREAD_H
253  PyEval_ReleaseLock();
254 #endif
255 
257  mod_error();
259 
260  radiusd_module = NULL;
261 
262  Py_Finalize();
263  return -1;
264 }
265 
266 #if 0
267 
268 static int mod_destroy(void)
269 {
271  Py_XDECREF(radiusd_module);
272  Py_Finalize();
274 
275  return 0;
276 }
277 
278 /*
279  * This will need reconsidering in a future. Maybe we'll need to
280  * have our own reference counting for radiusd_module
281  */
282 #endif
283 
284 /* TODO: Convert this function to accept any iterable objects? */
285 
286 static void mod_vptuple(TALLOC_CTX *ctx, VALUE_PAIR **vps, PyObject *pValue,
287  char const *funcname)
288 {
289  int i;
290  int tuplesize;
291  VALUE_PAIR *vp;
292 
293  /*
294  * If the Python function gave us None for the tuple,
295  * then just return.
296  */
297  if (pValue == Py_None)
298  return;
299 
300  if (!PyTuple_CheckExact(pValue)) {
301  ERROR("rlm_python:%s: non-tuple passed", funcname);
302  return;
303  }
304  /* Get the tuple tuplesize. */
305  tuplesize = PyTuple_GET_SIZE(pValue);
306  for (i = 0; i < tuplesize; i++) {
307  PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
308  PyObject *pStr1;
309  PyObject *pStr2;
310  PyObject *pOp;
311  int pairsize;
312  char const *s1;
313  char const *s2;
314  long op;
315 
316  if (!PyTuple_CheckExact(pTupleElement)) {
317  ERROR("rlm_python:%s: tuple element %d is not a tuple", funcname, i);
318  continue;
319  }
320  /* Check if it's a pair */
321 
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);
325  continue;
326  }
327 
328  if (pairsize == 2) {
329  pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
330  pStr2 = PyTuple_GET_ITEM(pTupleElement, 1);
331  op = T_OP_EQ;
332  } else {
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);
337  }
338 
339  if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
340  ERROR("rlm_python:%s: tuple element %d must be as (str, str)", funcname, i);
341  continue;
342  }
343  s1 = PyString_AsString(pStr1);
344  s2 = PyString_AsString(pStr2);
345  vp = fr_pair_make(ctx, vps, s1, s2, op);
346  if (vp != NULL) {
347  DEBUG("rlm_python:%s: '%s' = '%s'", funcname, s1, s2);
348  } else {
349  DEBUG("rlm_python:%s: Failed: '%s' = '%s'", funcname, s1, s2);
350  }
351  }
352 }
353 
354 
355 /*
356  * This is the core Python function that the others wrap around.
357  * Pass the value-pair print strings in a tuple.
358  *
359  * FIXME: We're not checking the errors. If we have errors, what
360  * do we do?
361  */
362 static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
363 {
364  PyObject *pStr = NULL;
365  char buf[1024];
366 
367  /* Look at the fr_pair_fprint_name? */
368 
369  if (vp->da->flags.has_tag)
370  pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
371  else
372  pStr = PyString_FromString(vp->da->name);
373 
374  if (!pStr)
375  goto failed;
376 
377  PyTuple_SET_ITEM(pPair, 0, pStr);
378 
379  fr_pair_value_snprint(buf, sizeof(buf), vp, '"');
380 
381  if ((pStr = PyString_FromString(buf)) == NULL)
382  goto failed;
383  PyTuple_SET_ITEM(pPair, 1, pStr);
384 
385  return 0;
386 
387 failed:
388  return -1;
389 }
390 
391 #ifdef HAVE_PTHREAD_H
392 /** Cleanup any thread local storage on pthread_exit()
393  */
394 static void do_python_cleanup(void *arg)
395 {
396  PyThreadState *my_thread_state = arg;
397 
398  PyEval_AcquireLock();
399  PyThreadState_Swap(NULL); /* Not entirely sure this is needed */
400  PyThreadState_Clear(my_thread_state);
401  PyThreadState_Delete(my_thread_state);
402  PyEval_ReleaseLock();
403 }
404 #endif
405 
406 static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker)
407 {
408  vp_cursor_t cursor;
409  VALUE_PAIR *vp;
410  PyObject *pRet = NULL;
411  PyObject *pArgs = NULL;
412  int tuplelen;
413  int ret;
414 
415  PyGILState_STATE gstate;
416  PyThreadState *prev_thread_state = NULL; /* -Wuninitialized */
417  memset(&gstate, 0, sizeof(gstate)); /* -Wuninitialized */
418 
419  /* Return with "OK, continue" if the function is not defined. */
420  if (!pFunc)
421  return RLM_MODULE_NOOP;
422 
423 #ifdef HAVE_PTHREAD_H
424  gstate = PyGILState_Ensure();
425  if (worker) {
426  PyThreadState *my_thread_state;
427  my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup);
428  if (!my_thread_state) {
429  my_thread_state = PyThreadState_New(inst->main_thread_state->interp);
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);
434  return RLM_MODULE_FAIL;
435  }
436 
437  ret = fr_thread_local_set(local_thread_state, my_thread_state);
438  if (ret != 0) {
439  REDEBUG("Failed storing PyThreadState in TLS: %s", fr_syserror(ret));
440  PyThreadState_Clear(my_thread_state);
441  PyThreadState_Delete(my_thread_state);
442  PyGILState_Release(gstate);
443  return RLM_MODULE_FAIL;
444  }
445  }
446  RDEBUG3("Using thread state %p", my_thread_state);
447  prev_thread_state = PyThreadState_Swap(my_thread_state); /* Swap in our local thread state */
448  }
449 #endif
450 
451  /* Default return value is "OK, continue" */
452  ret = RLM_MODULE_OK;
453 
454  /*
455  * We will pass a tuple containing (name, value) tuples
456  * We can safely use the Python function to build up a
457  * tuple, since the tuple is not used elsewhere.
458  *
459  * Determine the size of our tuple by walking through the packet.
460  * If request is NULL, pass None.
461  */
462  tuplelen = 0;
463  if (request != NULL) {
464  for (vp = fr_cursor_init(&cursor, &request->packet->vps);
465  vp;
466  vp = fr_cursor_next(&cursor)) {
467  tuplelen++;
468  }
469  }
470 
471  if (tuplelen == 0) {
472  Py_INCREF(Py_None);
473  pArgs = Py_None;
474  } else {
475  int i = 0;
476  if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
477  ret = RLM_MODULE_FAIL;
478  goto finish;
479  }
480 
481  for (vp = fr_cursor_init(&cursor, &request->packet->vps);
482  vp;
483  vp = fr_cursor_next(&cursor), i++) {
484  PyObject *pPair;
485 
486  /* The inside tuple has two only: */
487  if ((pPair = PyTuple_New(2)) == NULL) {
488  ret = RLM_MODULE_FAIL;
489  goto finish;
490  }
491 
492  if (mod_populate_vptuple(pPair, vp) == 0) {
493  /* Put the tuple inside the container */
494  PyTuple_SET_ITEM(pArgs, i, pPair);
495  } else {
496  Py_INCREF(Py_None);
497  PyTuple_SET_ITEM(pArgs, i, Py_None);
498  Py_DECREF(pPair);
499  }
500  }
501  }
502 
503  /* Call Python function. */
504  pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
505 
506  if (!pRet) {
507  ret = RLM_MODULE_FAIL;
508  goto finish;
509  }
510 
511  if (!request)
512  goto finish;
513 
514  /*
515  * The function returns either:
516  * 1. (returnvalue, replyTuple, configTuple), where
517  * - returnvalue is one of the constants RLM_*
518  * - replyTuple and configTuple are tuples of string
519  * tuples of size 2
520  *
521  * 2. the function return value alone
522  *
523  * 3. None - default return value is set
524  *
525  * xxx This code is messy!
526  */
527  if (PyTuple_CheckExact(pRet)) {
528  PyObject *pTupleInt;
529 
530  if (PyTuple_GET_SIZE(pRet) != 3) {
531  ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
532  ret = RLM_MODULE_FAIL;
533  goto finish;
534  }
535 
536  pTupleInt = PyTuple_GET_ITEM(pRet, 0);
537  if (!PyInt_CheckExact(pTupleInt)) {
538  ERROR("rlm_python:%s: first tuple element not an integer", funcname);
539  ret = RLM_MODULE_FAIL;
540  goto finish;
541  }
542  /* Now have the return value */
543  ret = PyInt_AsLong(pTupleInt);
544  /* Reply item tuple */
545  mod_vptuple(request->reply, &request->reply->vps,
546  PyTuple_GET_ITEM(pRet, 1), funcname);
547  /* Config item tuple */
548  mod_vptuple(request, &request->config,
549  PyTuple_GET_ITEM(pRet, 2), funcname);
550 
551  } else if (PyInt_CheckExact(pRet)) {
552  /* Just an integer */
553  ret = PyInt_AsLong(pRet);
554 
555  } else if (pRet == Py_None) {
556  /* returned 'None', return value defaults to "OK, continue." */
557  ret = RLM_MODULE_OK;
558  } else {
559  /* Not tuple or None */
560  ERROR("rlm_python:%s: function did not return a tuple or None", funcname);
561  ret = RLM_MODULE_FAIL;
562  goto finish;
563  }
564 
565 finish:
566  Py_XDECREF(pArgs);
567  Py_XDECREF(pRet);
568 
569 #ifdef HAVE_PTHREAD_H
570  if (worker) {
571  PyThreadState_Swap(prev_thread_state);
572  }
573  PyGILState_Release(gstate);
574 #endif
575 
576  return ret;
577 }
578 
579 /*
580  * Import a user module and load a function from it
581  */
582 
583 static int mod_load_function(struct py_function_def *def)
584 {
585  char const *funcname = "mod_load_function";
586  PyGILState_STATE gstate;
587 
588  gstate = PyGILState_Ensure();
589 
590  if (def->module_name != NULL && def->function_name != NULL) {
591  if ((def->module = PyImport_ImportModule(def->module_name)) == NULL) {
592  ERROR("rlm_python:%s: module '%s' is not found", funcname, def->module_name);
593  goto failed;
594  }
595 
596  if ((def->function = PyObject_GetAttrString(def->module, def->function_name)) == NULL) {
597  ERROR("rlm_python:%s: function '%s.%s' is not found", funcname, def->module_name, def->function_name);
598  goto failed;
599  }
600 
601  if (!PyCallable_Check(def->function)) {
602  ERROR("rlm_python:%s: function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
603  goto failed;
604  }
605  }
606  PyGILState_Release(gstate);
607  return 0;
608 
609 failed:
610  mod_error();
611  ERROR("rlm_python:%s: failed to import python function '%s.%s'", funcname, def->module_name, def->function_name);
612  Py_XDECREF(def->function);
613  def->function = NULL;
614  Py_XDECREF(def->module);
615  def->module = NULL;
616  PyGILState_Release(gstate);
617  return -1;
618 }
619 
620 
621 static void mod_objclear(PyObject **ob)
622 {
623  if (*ob != NULL) {
625  Py_DECREF(*ob);
627  *ob = NULL;
628  }
629 }
630 
631 static void mod_funcdef_clear(struct py_function_def *def)
632 {
633  mod_objclear(&def->function);
634  mod_objclear(&def->module);
635 }
636 
638 {
639 #define A(x) mod_funcdef_clear(&inst->x)
640 
641  A(instantiate);
642  A(authorize);
643  A(authenticate);
644  A(preacct);
645  A(accounting);
646  A(checksimul);
647  A(detach);
648 
649 #undef A
650 }
651 
652 /*
653  * Do any per-module initialization that is separate to each
654  * configured instance of the module. e.g. set up connections
655  * to external databases, read configuration files, set up
656  * dictionary entries, etc.
657  *
658  * If configuration information is given in the config section
659  * that must be referenced in later calls, store a handle to it
660  * in *instance otherwise put a null pointer there.
661  *
662  */
663 static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
664 {
665  rlm_python_t *inst = instance;
666 
667  if (mod_init(inst) != 0) {
668  return -1;
669  }
670 
671 #define A(x) if (mod_load_function(&inst->x) < 0) goto failed
672 
673  A(instantiate);
674  A(authenticate);
675  A(authorize);
676  A(preacct);
677  A(accounting);
678  A(checksimul);
679  A(pre_proxy);
680  A(post_proxy);
681  A(post_auth);
682 #ifdef WITH_COA
683  A(recv_coa);
684  A(send_coa);
685 #endif
686  A(detach);
687 
688 #undef A
689 
690  /*
691  * Call the instantiate function. No request. Use the
692  * return value.
693  */
694  return do_python(inst, NULL, inst->instantiate.function, "instantiate", false);
695 failed:
697  mod_error();
699  mod_instance_clear(inst);
700  return -1;
701 }
702 
703 static int mod_detach(void *instance)
704 {
705  rlm_python_t *inst = instance;
706  int ret;
707 
708  /*
709  * Master should still have no thread state
710  */
711  ret = do_python(inst, NULL, inst->detach.function, "detach", false);
712 
713  mod_instance_clear(inst);
714  dlclose(inst->libpython);
715 
716  return ret;
717 }
718 
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);\
721  }
722 
723 A(authenticate)
724 A(authorize)
725 A(preacct)
726 A(accounting)
727 A(checksimul)
728 A(pre_proxy)
729 A(post_proxy)
730 A(post_auth)
731 #ifdef WITH_COA
732 A(recv_coa)
733 A(send_coa)
734 #endif
735 
736 #undef A
737 
738 /*
739  * The module name should be the only globally exported symbol.
740  * That is, everything else should be 'static'.
741  *
742  * If the module needs to temporarily modify it's instantiation
743  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
744  * The server will then take care of ensuring that the module
745  * is single-threaded.
746  */
747 extern module_t rlm_python;
748 module_t rlm_python = {
750  .name = "python",
751  .type = RLM_TYPE_THREAD_SAFE,
752  .inst_size = sizeof(rlm_python_t),
753  .config = module_config,
754  .instantiate = mod_instantiate,
755  .detach = mod_detach,
756  .methods = {
759  [MOD_PREACCT] = mod_preacct,
762  [MOD_PRE_PROXY] = mod_pre_proxy,
763  [MOD_POST_PROXY] = mod_post_proxy,
765 #ifdef WITH_COA
766  [MOD_RECV_COA] = mod_recv_coa,
767  [MOD_SEND_COA] = mod_send_coa
768 #endif
769  }
770 };
5 methods index for preproxy section.
Definition: modules.h:46
struct py_function_def instantiate authorize authenticate preacct accounting checksimul pre_proxy post_proxy post_auth recv_coa send_coa detach
Definition: rlm_python.c:62
static void mod_instance_clear(rlm_python_t *inst)
Definition: rlm_python.c:637
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
Only displayed when debugging is enabled.
Definition: log.h:41
PyObject * module
Definition: rlm_python.c:50
Main server configuration.
Definition: radiusd.h:108
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
Write accounting data to Couchbase documents.
The module is OK, continue.
Definition: radiusd.h:91
static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
Definition: rlm_python.c:663
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
Definition: modules.h:134
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)
Definition: rlm_python.c:406
#define A(x)
Definition: rlm_python.c:719
7 methods index for postauth section.
Definition: modules.h:48
static char const * name
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.
Definition: modules.h:75
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
int8_t tag
Tag value used to group valuepairs.
Definition: pair.h:121
Error message.
Definition: log.h:36
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.
Definition: pair.c:2107
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
char const * python_path
Definition: rlm_python.c:60
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
#define Pyx_BLOCK_THREADS
Definition: rlm_python.c:40
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
#define inst
Definition: token.h:46
The module considers the request invalid.
Definition: radiusd.h:93
char const * name
Name of the daemon, usually 'radiusd'.
Definition: radiusd.h:109
static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull)
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
Reject the request (user is locked out).
Definition: radiusd.h:94
static struct @22 radiusd_constants[]
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
fr_thread_local_setup(PyThreadState *, local_thread_state)
Definition: rlm_python.c:139
#define DEBUG(fmt,...)
Definition: log.h:175
#define STRINGIFY(x)
Definition: build.h:34
4 methods index for checksimul section.
Definition: modules.h:45
struct rlm_python_t rlm_python_t
static void mod_error(void)
Definition: rlm_python.c:179
static void mod_vptuple(TALLOC_CTX *ctx, VALUE_PAIR **vps, PyObject *pValue, char const *funcname)
Definition: rlm_python.c:286
Immediately reject the request.
Definition: radiusd.h:89
static CONF_PARSER module_config[]
Definition: rlm_python.c:82
static void mod_funcdef_clear(struct py_function_def *def)
Definition: rlm_python.c:631
3 methods index for accounting section.
Definition: modules.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
static void mod_objclear(PyObject **ob)
Definition: rlm_python.c:621
static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request)
Check if a given user is already logged in.
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
0 methods index for authenticate section.
Definition: modules.h:41
static PyMethodDef module_methods[]
Definition: rlm_python.c:169
Authentication message.
Definition: log.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
static rs_t * conf
Definition: radsniff.c:46
void * libpython
Definition: rlm_python.c:58
Module succeeded without doing anything.
Definition: radiusd.h:96
char name[1]
Attribute name.
Definition: dict.h:89
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
#define Pyx_UNBLOCK_THREADS
Definition: rlm_python.c:41
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
#define RTLD_NOW
Definition: modules.c:81
char const * module_name
Definition: rlm_python.c:53
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
Definition: rlm_python.c:362
#define WARN(fmt,...)
Definition: log.h:144
Proxy messages.
Definition: log.h:38
#define REDEBUG(fmt,...)
Definition: log.h:254
PyThreadState * main_thread_state
Definition: rlm_python.c:59
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
static int mod_detach(void *instance)
Definition: rlm_python.c:703
6 methods index for postproxy section.
Definition: modules.h:47
2 methods index for preacct section.
Definition: modules.h:43
8 methods index for recvcoa section.
Definition: modules.h:50
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
9 methods index for sendcoa section.
Definition: modules.h:51
How many valid return codes there are.
Definition: radiusd.h:98
String of printable characters.
Definition: radius.h:33
Informational message.
Definition: log.h:35
char const * function_name
Definition: rlm_python.c:54
1 methods index for authorize section.
Definition: modules.h:42
User not found.
Definition: radiusd.h:95
#define RCSID(id)
Definition: build.h:135
OK (pairs modified).
Definition: radiusd.h:97
The module handled the request, so stop.
Definition: radiusd.h:92
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.
Definition: pair.c:338
static int mod_load_function(struct py_function_def *def)
Definition: rlm_python.c:583
#define ERROR(fmt,...)
Definition: log.h:145
static int mod_init(rlm_python_t *inst)
Definition: rlm_python.c:202
PyObject * function
Definition: rlm_python.c:51
#define RDEBUG3(fmt,...)
Definition: log.h:245