The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 6a38b788ffe70febd69b9eb46e5e7f02bb801ecf $
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,2015-2016 The FreeRADIUS server project
25  * @copyright 2002 Miguel A.L. Paraz (mparaz@mparaz.com)
26  * @copyright 2002 Imperium Technology, Inc.
27  */
28 RCSID("$Id: 6a38b788ffe70febd69b9eb46e5e7f02bb801ecf $")
29 
30 #define LOG_PREFIX mctx->mi->name
31 
32 #include <freeradius-devel/server/base.h>
33 #include <freeradius-devel/server/module_rlm.h>
34 #include <freeradius-devel/server/pairmove.h>
35 #include <freeradius-devel/util/debug.h>
36 #include <freeradius-devel/util/lsan.h>
37 
38 #include <Python.h>
39 #include <frameobject.h> /* Python header not pulled in by default. */
40 #include <libgen.h>
41 #include <dlfcn.h>
42 
43 /** Specifies the module.function to load for processing a section
44  *
45  */
46 typedef struct {
47  PyObject *module; //!< Python reference to module.
48  PyObject *function; //!< Python reference to function in module.
49 
50  char const *module_name; //!< String name of module.
51  char const *function_name; //!< String name of function in module.
53 
54 /** An instance of the rlm_python module
55  *
56  */
57 typedef struct {
58  char const *name; //!< Name of the module instance
59  PyThreadState *interpreter; //!< The interpreter used for this instance of rlm_python.
60  PyObject *module; //!< Local, interpreter specific module.
61 
70 
71  PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
72  //!< made available to the python script.
73 } rlm_python_t;
74 
75 /** Global config for python library
76  *
77  */
78 typedef struct {
79  char const *path; //!< Path to search for python files in.
80  bool path_include_default; //!< Include the default python path in `path`
82 
83 /** Tracks a python module inst/thread state pair
84  *
85  * Multiple instances of python create multiple interpreters and each
86  * thread must have a PyThreadState per interpreter, to track execution.
87  */
88 typedef struct {
89  PyThreadState *state; //!< Module instance/thread specific state.
91 
92 static void *python_dlhandle;
93 static PyThreadState *global_interpreter; //!< Our first interpreter.
94 
95 static module_ctx_t const *current_mctx; //!< Used for communication with inittab functions.
96 static CONF_SECTION *current_conf; //!< Used for communication with inittab functions.
97 
99  .path = NULL,
100  .path_include_default = true
101 };
102 
104  { FR_CONF_OFFSET("path", libpython_global_config_t, path) },
105  { FR_CONF_OFFSET("path_include_default", libpython_global_config_t, path_include_default) },
107 };
108 
109 static int libpython_init(void);
110 static void libpython_free(void);
111 
113  .name = "python",
114  .config = python_global_config,
115  .init = libpython_init,
116  .free = libpython_free,
117  .inst = &libpython_global_config
118 };
119 
120 extern global_lib_autoinst_t const * const rlm_python_lib[];
124 };
125 
126 /*
127  * As of Python 3.8 the GIL will be per-interpreter
128  * If there are still issues with CEXTs,
129  * multiple interpreters and the GIL at that point
130  * users can build rlm_python against Python 3.8
131  * and the horrible hack of using a single interpreter
132  * for all instances of rlm_python will no longer be
133  * required.
134  *
135  * As Python 3.x module initialisation is significantly
136  * different than Python 2.x initialisation,
137  * it'd be a pain to retain the cext_compat for
138  * Python 3 and as Python 3 users have the option of
139  * using as version of Python which fixes the underlying
140  * issue, we only support using a global interpreter
141  * for Python 2.7 and below.
142  */
143 
144 /*
145  * A mapping of configuration file names to internal variables.
146  */
148 
149 #define A(x) { FR_CONF_OFFSET("mod_" #x, rlm_python_t, x.module_name), .dflt = "${.module}" }, \
150  { FR_CONF_OFFSET("func_" #x, rlm_python_t, x.function_name) },
151 
152  A(instantiate)
153  A(authorize)
154  A(authenticate)
155  A(preacct)
156  A(accounting)
157  A(post_auth)
158  A(detach)
159 
160 #undef A
161 
163 };
164 
165 static struct {
166  char const *name;
167  int value;
168 } freeradius_constants[] = {
169 
170 #define A(x) { #x, x },
171 
172  A(L_DBG)
173  A(L_WARN)
174  A(L_INFO)
175  A(L_ERR)
176  A(L_WARN)
177  A(L_DBG_WARN)
178  A(L_DBG_ERR)
191 
192 #undef A
193 
194  { NULL, 0 },
195 };
196 
197 /*
198  * radiusd Python functions
199  */
200 
201 /** Allow fr_log to be called from python
202  *
203  */
204 static PyObject *mod_log(UNUSED PyObject *module, PyObject *args)
205 {
206  int status;
207  char *msg;
208 
209  if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
210  Py_RETURN_NONE;
211  }
212 
213  fr_log(&default_log, status, __FILE__, __LINE__, "%s", msg);
214 
215  Py_RETURN_NONE;
216 }
217 
218 static PyMethodDef module_methods[] = {
219  { "log", &mod_log, METH_VARARGS,
220  "freeradius.log(level, msg)\n\n" \
221  "Print a message using the freeradius daemon's logging system. level should be one of the\n" \
222  "following constants L_DBG, L_WARN, L_INFO, L_ERR, L_DBG_WARN, L_DBG_ERR, L_DBG_WARN_REQ, L_DBG_ERR_REQ\n"
223  },
224  { NULL, NULL, 0, NULL },
225 };
226 
227 /** Print out the current error
228  *
229  * Must be called with a valid thread state set
230  */
231 static void python_error_log(module_ctx_t const *mctx, request_t *request)
232 {
233  PyObject *p_type = NULL, *p_value = NULL, *p_traceback = NULL, *p_str_1 = NULL, *p_str_2 = NULL;
234 
235  PyErr_Fetch(&p_type, &p_value, &p_traceback);
236  PyErr_NormalizeException(&p_type, &p_value, &p_traceback);
237  if (!p_type || !p_value) goto failed;
238 
239  if (((p_str_1 = PyObject_Str(p_type)) == NULL) || ((p_str_2 = PyObject_Str(p_value)) == NULL)) goto failed;
240 
241  ROPTIONAL(RERROR, ERROR, "%s (%s)", PyUnicode_AsUTF8(p_str_1), PyUnicode_AsUTF8(p_str_2));
242 
243  if (p_traceback != Py_None) {
244  PyTracebackObject *ptb = (PyTracebackObject*)p_traceback;
245  size_t fnum = 0;
246 
247  while (ptb != NULL) {
248  PyFrameObject *cur_frame = ptb->tb_frame;
249 #if PY_VERSION_HEX >= 0x030A0000
250  PyCodeObject *code = PyFrame_GetCode(cur_frame);
251 
252  ROPTIONAL(RERROR, ERROR, "[%ld] %s:%d at %s()",
253  fnum,
254  PyUnicode_AsUTF8(code->co_filename),
255  PyFrame_GetLineNumber(cur_frame),
256  PyUnicode_AsUTF8(code->co_name)
257  );
258  Py_XDECREF(code);
259 #else
260  ROPTIONAL(RERROR, ERROR, "[%ld] %s:%d at %s()",
261  fnum,
262  PyUnicode_AsUTF8(cur_frame->f_code->co_filename),
263  PyFrame_GetLineNumber(cur_frame),
264  PyUnicode_AsUTF8(cur_frame->f_code->co_name)
265  );
266 #endif
267 
268  ptb = ptb->tb_next;
269  fnum++;
270  }
271  }
272 
273 failed:
274  Py_XDECREF(p_str_1);
275  Py_XDECREF(p_str_2);
276  Py_XDECREF(p_type);
277  Py_XDECREF(p_value);
278  Py_XDECREF(p_traceback);
279 }
280 
281 static void mod_vptuple(TALLOC_CTX *ctx, module_ctx_t const *mctx, request_t *request,
282  fr_pair_list_t *vps, PyObject *p_value, char const *funcname, char const *list_name)
283 {
284  int i;
285  Py_ssize_t tuple_len;
286  tmpl_t *dst;
287  fr_pair_t *vp;
288  request_t *current = request;
289  fr_pair_list_t tmp_list;
290 
291  fr_pair_list_init(&tmp_list);
292  /*
293  * If the Python function gave us None for the tuple,
294  * then just return.
295  */
296  if (p_value == Py_None) return;
297 
298  if (!PyTuple_CheckExact(p_value)) {
299  ERROR("%s - non-tuple passed to %s", funcname, list_name);
300  return;
301  }
302  /* Get the tuple tuple_len. */
303  tuple_len = PyTuple_GET_SIZE(p_value);
304  for (i = 0; i < tuple_len; i++) {
305  PyObject *p_tuple_element = PyTuple_GET_ITEM(p_value, i);
306  PyObject *p_str_1;
307  PyObject *p_str_2;
308  Py_ssize_t pair_len;
309  char const *s1;
310  char const *s2;
311 
312  if (!PyTuple_CheckExact(p_tuple_element)) {
313  ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
314  continue;
315  }
316  /* Check if it's a pair */
317 
318  pair_len = PyTuple_GET_SIZE(p_tuple_element);
319  if ((pair_len < 2) || (pair_len > 3)) {
320  ERROR("%s - Tuple element %d of %s is a tuple of size %zu. Must be 2 or 3",
321  funcname, i, list_name, pair_len);
322  continue;
323  }
324 
325  p_str_1 = PyTuple_GET_ITEM(p_tuple_element, 0);
326  p_str_2 = PyTuple_GET_ITEM(p_tuple_element, pair_len - 1);
327 
328  if ((!PyUnicode_CheckExact(p_str_1)) || (!PyUnicode_CheckExact(p_str_2))) {
329  ERROR("%s - Tuple element %d of %s must be as (str, str)",
330  funcname, i, list_name);
331  continue;
332  }
333  s1 = PyUnicode_AsUTF8(p_str_1);
334  s2 = PyUnicode_AsUTF8(p_str_2);
335 
336  if (tmpl_afrom_attr_str(ctx, NULL, &dst, s1,
337  &(tmpl_rules_t){
338  .attr = {
339  .dict_def = request->dict,
340  .list_def = request_attr_reply
341  }
342  }) <= 0) {
343  PERROR("%s - Failed to find attribute %s.%s", funcname, list_name, s1);
344  continue;
345  }
346 
347  if (tmpl_request_ptr(&current, tmpl_request(dst)) < 0) {
348  ERROR("%s - Attribute name %s.%s refers to outer request but not in a tunnel, skipping...",
349  funcname, list_name, s1);
350  talloc_free(dst);
351  continue;
352  }
353 
355  talloc_free(dst);
356 
357  if (fr_pair_value_from_str(vp, s2, strlen(s2), NULL, false) < 0) {
358  DEBUG("%s - Failed: '%s.%s' = '%s'", funcname, list_name, s1, s2);
359  } else {
360  DEBUG("%s - '%s.%s' = '%s'", funcname, list_name, s1, s2);
361  }
362 
363  fr_pair_append(&tmp_list, vp);
364  }
365  radius_pairmove(request, vps, &tmp_list);
366 }
367 
368 
369 /*
370  * This is the core Python function that the others wrap around.
371  * Pass the value-pair print strings in a tuple.
372  */
373 static int mod_populate_vptuple(module_ctx_t const *mctx, request_t *request, PyObject *pp, fr_pair_t *vp)
374 {
375  PyObject *attribute = NULL;
376  PyObject *value = NULL;
377 
378  attribute = PyUnicode_FromString(vp->da->name);
379  if (!attribute) return -1;
380 
381  switch (vp->vp_type) {
382  case FR_TYPE_STRING:
383  value = PyUnicode_FromStringAndSize(vp->vp_strvalue, vp->vp_length);
384  break;
385 
386  case FR_TYPE_OCTETS:
387  value = PyBytes_FromStringAndSize((char const *)vp->vp_octets, vp->vp_length);
388  break;
389 
390  case FR_TYPE_BOOL:
391  value = PyBool_FromLong(vp->vp_bool);
392  break;
393 
394  case FR_TYPE_UINT8:
395  value = PyLong_FromUnsignedLong(vp->vp_uint8);
396  break;
397 
398  case FR_TYPE_UINT16:
399  value = PyLong_FromUnsignedLong(vp->vp_uint16);
400  break;
401 
402  case FR_TYPE_UINT32:
403  value = PyLong_FromUnsignedLong(vp->vp_uint32);
404  break;
405 
406  case FR_TYPE_UINT64:
407  value = PyLong_FromUnsignedLongLong(vp->vp_uint64);
408  break;
409 
410  case FR_TYPE_INT8:
411  value = PyLong_FromLong(vp->vp_int8);
412  break;
413 
414  case FR_TYPE_INT16:
415  value = PyLong_FromLong(vp->vp_int16);
416  break;
417 
418  case FR_TYPE_INT32:
419  value = PyLong_FromLong(vp->vp_int32);
420  break;
421 
422  case FR_TYPE_INT64:
423  value = PyLong_FromLongLong(vp->vp_int64);
424  break;
425 
426  case FR_TYPE_FLOAT32:
427  value = PyFloat_FromDouble((double) vp->vp_float32);
428  break;
429 
430  case FR_TYPE_FLOAT64:
431  value = PyFloat_FromDouble(vp->vp_float64);
432  break;
433 
434  case FR_TYPE_SIZE:
435  value = PyLong_FromSize_t(vp->vp_size);
436  break;
437 
438  case FR_TYPE_TIME_DELTA:
439  case FR_TYPE_DATE:
440  case FR_TYPE_IFID:
441  case FR_TYPE_IPV6_ADDR:
442  case FR_TYPE_IPV6_PREFIX:
443  case FR_TYPE_IPV4_ADDR:
444  case FR_TYPE_IPV4_PREFIX:
447  case FR_TYPE_ETHERNET:
448  {
449  ssize_t slen;
450  char buffer[256];
451 
452  slen = fr_value_box_print(&FR_SBUFF_OUT(buffer, sizeof(buffer)), &vp->data, NULL);
453  if (slen < 0) {
454  error:
455  ROPTIONAL(REDEBUG, ERROR, "Failed marshalling %pP to Python value", vp);
456  python_error_log(mctx, request);
457  Py_XDECREF(attribute);
458  return -1;
459  }
460  value = PyUnicode_FromStringAndSize(buffer, (size_t)slen);
461  }
462  break;
463 
464  case FR_TYPE_NON_LEAF:
465  return 0;
466  }
467 
468  if (value == NULL) goto error;
469 
470  PyTuple_SET_ITEM(pp, 0, attribute);
471  PyTuple_SET_ITEM(pp, 1, value);
472 
473  return 0;
474 }
475 
477  request_t *request, PyObject *p_func, char const *funcname)
478 {
479  fr_pair_t *vp;
480  PyObject *p_ret = NULL;
481  PyObject *p_arg = NULL;
482  int tuple_len;
483  rlm_rcode_t rcode = RLM_MODULE_OK;
484 
485  /*
486  * We will pass a tuple containing (name, value) tuples
487  * We can safely use the Python function to build up a
488  * tuple, since the tuple is not used elsewhere.
489  *
490  * Determine the size of our tuple by walking through the packet.
491  * If request is NULL, pass None.
492  */
493  tuple_len = 0;
494  if (request != NULL) {
495  tuple_len = fr_pair_list_num_elements(&request->request_pairs);
496  }
497 
498  if (tuple_len == 0) {
499  Py_INCREF(Py_None);
500  p_arg = Py_None;
501  } else {
502  int i = 0;
503  if ((p_arg = PyTuple_New(tuple_len)) == NULL) {
504  rcode = RLM_MODULE_FAIL;
505  goto finish;
506  }
507 
508  for (vp = fr_pair_list_head(&request->request_pairs);
509  vp;
510  vp = fr_pair_list_next(&request->request_pairs, vp), i++) {
511  PyObject *pp;
512 
513  /* The inside tuple has two only: */
514  if ((pp = PyTuple_New(2)) == NULL) {
515  rcode = RLM_MODULE_FAIL;
516  goto finish;
517  }
518 
519  if (mod_populate_vptuple(mctx, request, pp, vp) == 0) {
520  /* Put the tuple inside the container */
521  PyTuple_SET_ITEM(p_arg, i, pp);
522  } else {
523  Py_INCREF(Py_None);
524  PyTuple_SET_ITEM(p_arg, i, Py_None);
525  Py_DECREF(pp);
526  }
527  }
528  }
529 
530  /* Call Python function. */
531  p_ret = PyObject_CallFunctionObjArgs(p_func, p_arg, NULL);
532  if (!p_ret) {
533  python_error_log(mctx, request); /* Needs valid thread with GIL */
534  rcode = RLM_MODULE_FAIL;
535  goto finish;
536  }
537 
538  if (!request) {
539  // check return code at module instantiation time
540  if (PyNumber_Check(p_ret)) rcode = PyLong_AsLong(p_ret);
541  goto finish;
542  }
543 
544  /*
545  * The function returns either:
546  * 1. (returnvalue, replyTuple, configTuple), where
547  * - returnvalue is one of the constants RLM_*
548  * - replyTuple and configTuple are tuples of string
549  * tuples of size 2
550  *
551  * 2. the function return value alone
552  *
553  * 3. None - default return value is set
554  *
555  * xxx This code is messy!
556  */
557  if (PyTuple_CheckExact(p_ret)) {
558  PyObject *p_tuple_int;
559 
560  if (PyTuple_GET_SIZE(p_ret) != 3) {
561  ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
562  rcode = RLM_MODULE_FAIL;
563  goto finish;
564  }
565 
566  p_tuple_int = PyTuple_GET_ITEM(p_ret, 0);
567  if (!PyNumber_Check(p_tuple_int)) {
568  ERROR("%s - First tuple element not an integer", funcname);
569  rcode = RLM_MODULE_FAIL;
570  goto finish;
571  }
572  /* Now have the return value */
573  rcode = PyLong_AsLong(p_tuple_int);
574  /* Reply item tuple */
575  mod_vptuple(request->reply_ctx, mctx, request, &request->reply_pairs,
576  PyTuple_GET_ITEM(p_ret, 1), funcname, "reply");
577  /* Config item tuple */
578  mod_vptuple(request->control_ctx, mctx, request, &request->control_pairs,
579  PyTuple_GET_ITEM(p_ret, 2), funcname, "config");
580 
581  } else if (PyNumber_Check(p_ret)) {
582  /* Just an integer */
583  rcode = PyLong_AsLong(p_ret);
584 
585  } else if (p_ret == Py_None) {
586  /* returned 'None', return value defaults to "OK, continue." */
587  rcode = RLM_MODULE_OK;
588  } else {
589  /* Not tuple or None */
590  ERROR("%s - Function did not return a tuple or None", funcname);
591  rcode = RLM_MODULE_FAIL;
592  goto finish;
593  }
594 
595 finish:
596  if (rcode == RLM_MODULE_FAIL) python_error_log(mctx, request);
597  Py_XDECREF(p_arg);
598  Py_XDECREF(p_ret);
599 
600  RETURN_MODULE_RCODE(rcode);
601 }
602 
603 /** Thread safe call to a python function
604  *
605  * Will swap in thread state specific to module/thread.
606  */
607 static unlang_action_t do_python(rlm_rcode_t *p_result, module_ctx_t const *mctx,
608  request_t *request, PyObject *p_func, char const *funcname)
609 {
610  rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
611  rlm_rcode_t rcode;
612 
613  /*
614  * It's a NOOP if the function wasn't defined
615  */
616  if (!p_func) RETURN_MODULE_NOOP;
617 
618  RDEBUG3("Using thread state %p/%p", mctx->mi->data, t->state);
619 
620  PyEval_RestoreThread(t->state); /* Swap in our local thread state */
621  do_python_single(&rcode, mctx, request, p_func, funcname);
622  (void)fr_cond_assert(PyEval_SaveThread() == t->state);
623 
624  RETURN_MODULE_RCODE(rcode);
625 }
626 
627 #define MOD_FUNC(x) \
628 static unlang_action_t CC_HINT(nonnull) mod_##x(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
629 { \
630  rlm_python_t const *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_python_t); \
631  return do_python(p_result, mctx, request, inst->x.function, #x);\
632 }
633 
634 MOD_FUNC(authenticate)
635 MOD_FUNC(authorize)
636 MOD_FUNC(preacct)
637 MOD_FUNC(accounting)
638 MOD_FUNC(post_auth)
639 
640 static void python_obj_destroy(PyObject **ob)
641 {
642  if (*ob != NULL) {
643  Py_DECREF(*ob);
644  *ob = NULL;
645  }
646 }
647 
649 {
651  python_obj_destroy(&def->module);
652 }
653 
654 /** Import a user module and load a function from it
655  *
656  */
658 {
659  char const *funcname = "python_function_load";
660 
661  if (def->module_name == NULL || def->function_name == NULL) return 0;
662 
663  LSAN_DISABLE(def->module = PyImport_ImportModule(def->module_name));
664  if (!def->module) {
665  ERROR("%s - Module '%s' load failed", funcname, def->module_name);
666  error:
668  Py_XDECREF(def->function);
669  def->function = NULL;
670  Py_XDECREF(def->module);
671  def->module = NULL;
672 
673  return -1;
674  }
675 
676  def->function = PyObject_GetAttrString(def->module, def->function_name);
677  if (!def->function) {
678  ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
679  goto error;
680  }
681 
682  if (!PyCallable_Check(def->function)) {
683  ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
684  goto error;
685  }
686 
687  return 0;
688 }
689 
690 /*
691  * Parse a configuration section, and populate a dict.
692  * This function is recursively called (allows to have nested dicts.)
693  */
694 static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
695 {
696  int indent_section = (lvl * 4);
697  int indent_item = (lvl + 1) * 4;
698  int ret = 0;
699  CONF_ITEM *ci = NULL;
700 
701  if (!cs || !dict) return -1;
702 
703  DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
704 
705  while ((ci = cf_item_next(cs, ci))) {
706  /*
707  * This is a section.
708  * Create a new dict, store it in current dict,
709  * Then recursively call python_parse_config with this section and the new dict.
710  */
711  if (cf_item_is_section(ci)) {
712  CONF_SECTION *sub_cs = cf_item_to_section(ci);
713  char const *key = cf_section_name1(sub_cs); /* dict key */
714  PyObject *sub_dict, *p_key;
715 
716  p_key = PyUnicode_FromString(key);
717  if (!p_key) {
718  ERROR("Failed converting config key \"%s\" to python string", key);
719  return -1;
720  }
721 
722  if (PyDict_Contains(dict, p_key)) {
723  WARN("Ignoring duplicate config section '%s'", key);
724  continue;
725  }
726 
727  MEM(sub_dict = PyDict_New());
728  (void)PyDict_SetItem(dict, p_key, sub_dict);
729 
730  ret = python_parse_config(mctx, sub_cs, lvl + 1, sub_dict);
731  if (ret < 0) break;
732  } else if (cf_item_is_pair(ci)) {
733  CONF_PAIR *cp = cf_item_to_pair(ci);
734  char const *key = cf_pair_attr(cp); /* dict key */
735  char const *value = cf_pair_value(cp); /* dict value */
736  PyObject *p_key, *p_value;
737 
738  if (!value) {
739  WARN("Skipping \"%s\" as it has no value", key);
740  continue;
741  }
742 
743  p_key = PyUnicode_FromString(key);
744  p_value = PyUnicode_FromString(value);
745  if (!p_key) {
746  ERROR("Failed converting config key \"%s\" to python string", key);
747  return -1;
748  }
749  if (!p_value) {
750  ERROR("Failed converting config value \"%s\" to python string", value);
751  return -1;
752  }
753 
754  /*
755  * This is an item.
756  * Store item attr / value in current dict.
757  */
758  if (PyDict_Contains(dict, p_key)) {
759  WARN("Ignoring duplicate config item '%s'", key);
760  continue;
761  }
762 
763  (void)PyDict_SetItem(dict, p_key, p_value);
764 
765  DEBUG("%*s%s = \"%s\"", indent_item, " ", key, value);
766  }
767  }
768 
769  DEBUG("%*s}", indent_section, " ");
770 
771  return ret;
772 }
773 
774 /** Make the current instance's config available within the module we're initialising
775  *
776  */
777 static int python_module_import_config(module_inst_ctx_t const *mctx, CONF_SECTION *conf, PyObject *module)
778 {
779  rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
780  CONF_SECTION *cs;
781 
782  /*
783  * Convert a FreeRADIUS config structure into a python
784  * dictionary.
785  */
786  inst->pythonconf_dict = PyDict_New();
787  if (!inst->pythonconf_dict) {
788  ERROR("Unable to create python dict for config");
789  error:
790  Py_XDECREF(inst->pythonconf_dict);
791  inst->pythonconf_dict = NULL;
793  return -1;
794  }
795 
796  cs = cf_section_find(conf, "config", NULL);
797  if (cs) {
798  DEBUG("Inserting \"config\" section into python environment as radiusd.config");
799  if (python_parse_config(mctx, cs, 0, inst->pythonconf_dict) < 0) goto error;
800  }
801 
802  /*
803  * Add module configuration as a dict
804  */
805  if (PyModule_AddObject(module, "config", inst->pythonconf_dict) < 0) goto error;
806 
807  return 0;
808 }
809 
810 /** Import integer constants into the module we're initialising
811  *
812  */
813 static int python_module_import_constants(module_inst_ctx_t const *mctx, PyObject *module)
814 {
815  size_t i;
816 
817  for (i = 0; freeradius_constants[i].name; i++) {
818  if ((PyModule_AddIntConstant(module, freeradius_constants[i].name, freeradius_constants[i].value)) < 0) {
819  ERROR("Failed adding constant to module");
821  return -1;
822  }
823  }
824 
825  return 0;
826 }
827 
828 /*
829  * Python 3 interpreter initialisation and destruction
830  */
831 static PyObject *python_module_init(void)
832 {
833  PyObject *module;
834 
835  static struct PyModuleDef py_module_def = {
836  PyModuleDef_HEAD_INIT,
837  .m_name = "freeradius",
838  .m_doc = "freeRADIUS python module",
839  .m_size = -1,
840  .m_methods = module_methods
841  };
842 
844 
845  module = PyModule_Create(&py_module_def);
846  if (!module) {
848  Py_RETURN_NONE;
849  }
850 
851  return module;
852 }
853 
855 {
856  rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
857  CONF_SECTION *conf = mctx->mi->conf;
858  PyObject *module;
859 
860  /*
861  * python_module_init takes no args, so we need
862  * to set these globals so that when it's
863  * called during interpreter initialisation
864  * it can get at the current instance config.
865  */
867  current_conf = conf;
868 
869  PyEval_RestoreThread(global_interpreter);
870  LSAN_DISABLE(inst->interpreter = Py_NewInterpreter());
871  if (!inst->interpreter) {
872  ERROR("Failed creating new interpreter");
873  return -1;
874  }
875  DEBUG3("Created new interpreter %p", inst->interpreter);
876  PyEval_SaveThread(); /* Unlock GIL */
877 
878  PyEval_RestoreThread(inst->interpreter);
879 
880  /*
881  * Import the radiusd module into this python
882  * environment. Each interpreter gets its
883  * own copy which it can mutate as much as
884  * it wants.
885  */
886  module = PyImport_ImportModule("freeradius");
887  if (!module) {
888  ERROR("Failed importing \"freeradius\" module into interpreter %p", inst->interpreter);
889  return -1;
890  }
891  if ((python_module_import_config(mctx, conf, module) < 0) ||
892  (python_module_import_constants(mctx, module) < 0)) {
893  Py_DECREF(module);
894  return -1;
895  }
896  inst->module = module;
897  PyEval_SaveThread();
898 
899  return 0;
900 }
901 
902 static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
903 {
904  /*
905  * We incremented the reference count earlier
906  * during module initialisation.
907  */
908  Py_XDECREF(inst->module);
909 
910  PyEval_RestoreThread(interp); /* Switches thread state and locks GIL */
911  Py_EndInterpreter(interp); /* Destroys interpreter (GIL still locked) - sets thread state to NULL */
912  PyThreadState_Swap(global_interpreter); /* Get a none-null thread state */
913  PyEval_SaveThread(); /* Unlock GIL */
914 }
915 
916 /*
917  * Do any per-module initialization that is separate to each
918  * configured instance of the module. e.g. set up connections
919  * to external databases, read configuration files, set up
920  * dictionary entries, etc.
921  *
922  * If configuration information is given in the config section
923  * that must be referenced in later calls, store a handle to it
924  * in *instance otherwise put a null pointer there.
925  *
926  */
927 static int mod_instantiate(module_inst_ctx_t const *mctx)
928 {
929  rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
930 
931  if (python_interpreter_init(mctx) < 0) return -1;
932 
933  /*
934  * Switch to our module specific interpreter
935  */
936  PyEval_RestoreThread(inst->interpreter);
937 
938  /*
939  * Process the various sections
940  */
941 #define PYTHON_FUNC_LOAD(_x) if (python_function_load(mctx, &inst->_x) < 0) goto error
943  PYTHON_FUNC_LOAD(authenticate);
944  PYTHON_FUNC_LOAD(authorize);
945  PYTHON_FUNC_LOAD(preacct);
946  PYTHON_FUNC_LOAD(accounting);
947  PYTHON_FUNC_LOAD(post_auth);
948  PYTHON_FUNC_LOAD(detach);
949 
950  /*
951  * Call the instantiate function.
952  */
953  if (inst->instantiate.function) {
954  rlm_rcode_t rcode;
955 
956  do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->instantiate.function, "instantiate");
957  switch (rcode) {
958  case RLM_MODULE_FAIL:
959  case RLM_MODULE_REJECT:
960  error:
961  fr_cond_assert(PyEval_SaveThread() == inst->interpreter);
962  return -1;
963 
964  default:
965  break;
966  }
967  }
968 
969  /*
970  * Switch back to the global interpreter
971  */
972  if (!fr_cond_assert(PyEval_SaveThread() == inst->interpreter)) goto error;
973 
974  return 0;
975 }
976 
977 static int mod_detach(module_detach_ctx_t const *mctx)
978 {
979  rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
980 
981  /*
982  * If we don't have a interpreter
983  * we didn't get far enough into
984  * instantiation to generate things
985  * we need to clean up...
986  */
987  if (!inst->interpreter) return 0;
988 
989  /*
990  * Call module destructor
991  */
992  PyEval_RestoreThread(inst->interpreter);
993 
994  /*
995  * We don't care if this fails.
996  */
997  if (inst->detach.function) {
998  rlm_rcode_t rcode;
999 
1000  (void)do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->detach.function, "detach");
1001  }
1002 
1003 #define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
1005  PYTHON_FUNC_DESTROY(authorize);
1006  PYTHON_FUNC_DESTROY(authenticate);
1007  PYTHON_FUNC_DESTROY(preacct);
1008  PYTHON_FUNC_DESTROY(accounting);
1009  PYTHON_FUNC_DESTROY(post_auth);
1010  PYTHON_FUNC_DESTROY(detach);
1011 
1012  Py_XDECREF(inst->pythonconf_dict);
1013  PyEval_SaveThread();
1014 
1015  /*
1016  * Free the module specific interpreter
1017  */
1018  python_interpreter_free(inst, inst->interpreter);
1019 
1020  return 0;
1021 }
1022 
1024 {
1025  PyThreadState *state;
1026  rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
1027  rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1028 
1029  state = PyThreadState_New(inst->interpreter->interp);
1030  if (!state) {
1031  ERROR("Failed initialising local PyThreadState");
1032  return -1;
1033  }
1034 
1035  DEBUG3("Initialised new thread state %p", state);
1036  t->state = state;
1037 
1038  return 0;
1039 }
1040 
1042 {
1043  rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1044 
1045  PyEval_RestoreThread(t->state); /* Swap in our local thread state */
1046  PyThreadState_Clear(t->state);
1047  PyEval_SaveThread();
1048 
1049  PyThreadState_Delete(t->state); /* Don't need to hold lock for this */
1050 
1051  return 0;
1052 }
1053 
1054 static int libpython_init(void)
1055 {
1056 #define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_python - " _fmt, ## __VA_ARGS__)
1057 #define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1058  &(fr_log_perror_format_t){ \
1059  .first_prefix = "rlm_python - ", \
1060  .subsq_prefix = "rlm_python - ", \
1061  }, \
1062  _fmt, ## __VA_ARGS__)
1063  PyConfig config;
1064  PyStatus status;
1065  wchar_t *wide_name;
1066  char *path;
1067 
1068  fr_assert(!Py_IsInitialized());
1069 
1070  LOAD_INFO("Python version: %s", Py_GetVersion());
1071  dependency_version_number_add(NULL, "python", Py_GetVersion());
1072 
1073  /*
1074  * Load python using RTLD_GLOBAL and dlopen.
1075  * This fixes issues where python C extensions
1076  * can't find the symbols they need.
1077  */
1078  python_dlhandle = dl_open_by_sym("Py_IsInitialized", RTLD_NOW | RTLD_GLOBAL);
1079  if (!python_dlhandle) LOAD_WARN("Failed loading libpython symbols into global symbol table");
1080 
1081  PyConfig_InitPythonConfig(&config);
1082 
1083  /*
1084  * Set program name (i.e. the software calling the interpreter)
1085  * The value of argv[0] as a wide char string
1086  */
1087  wide_name = Py_DecodeLocale(main_config->name, NULL);
1088  status = PyConfig_SetString(&config, &config.program_name, wide_name);
1089  PyMem_RawFree(wide_name);
1090 
1091  if (PyStatus_Exception(status)) {
1092  fail:
1093  LOAD_WARN("%s", status.err_msg);
1094  PyConfig_Clear(&config);
1095  return -1;
1096  }
1097 
1098  /*
1099  * Python 3 introduces the concept of a
1100  * "inittab", i.e. a list of modules which
1101  * are automatically created when the first
1102  * interpreter is spawned.
1103  */
1104  PyImport_AppendInittab("freeradius", python_module_init);
1105 
1107  wchar_t *wide_path = Py_DecodeLocale(libpython_global_config.path, NULL);
1108 
1110  /*
1111  * The path from config is to be used in addition to the default.
1112  * Set it in the pythonpath_env.
1113  */
1114  status = PyConfig_SetString(&config, &config.pythonpath_env, wide_path);
1115  } else {
1116  /*
1117  * Only the path from config is to be used.
1118  * Setting module_search_paths_set to 1 disables any automatic paths.
1119  */
1120  config.module_search_paths_set = 1;
1121  status = PyWideStringList_Append(&config.module_search_paths, wide_path);
1122  }
1123  PyMem_RawFree(wide_path);
1124  if (PyStatus_Exception(status)) goto fail;
1125  }
1126 
1127  config.install_signal_handlers = 0; /* Don't override signal handlers - noop on subs calls */
1128 
1129  LSAN_DISABLE(status = Py_InitializeFromConfig(&config));
1130  if (PyStatus_Exception(status)) goto fail;
1131 
1132  PyConfig_Clear(&config);
1133 
1134  /*
1135  * Report the path
1136  */
1137  path = Py_EncodeLocale(Py_GetPath(), NULL);
1138  LOAD_INFO("Python path set to \"%s\"", path);
1139  PyMem_Free(path);
1140 
1141  global_interpreter = PyEval_SaveThread(); /* Store reference to the main interpreter and release the GIL */
1142 
1143  return 0;
1144 }
1145 
1146 static void libpython_free(void)
1147 {
1148  PyThreadState_Swap(global_interpreter); /* Swap to the main thread */
1149 
1150  /*
1151  * PyImport_Cleanup - Leaks memory in python 3.6
1152  * should check once we require 3.8 that this is
1153  * still needed.
1154  */
1155  LSAN_DISABLE(Py_Finalize()); /* Ignore leaks on exit, we don't reload modules so we don't care */
1156  if (python_dlhandle) dlclose(python_dlhandle); /* dlclose will SEGV on null handle */
1157 }
1158 
1159 /*
1160  * The module name should be the only globally exported symbol.
1161  * That is, everything else should be 'static'.
1162  *
1163  * If the module needs to temporarily modify it's instantiation
1164  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1165  * The server will then take care of ensuring that the module
1166  * is single-threaded.
1167  */
1168 extern module_rlm_t rlm_python;
1170  .common = {
1171  .magic = MODULE_MAGIC_INIT,
1172  .name = "python",
1173 
1174  .inst_size = sizeof(rlm_python_t),
1175  .thread_inst_size = sizeof(rlm_python_thread_t),
1176 
1177  .config = module_config,
1178 
1179  .instantiate = mod_instantiate,
1180  .detach = mod_detach,
1181 
1182  .thread_instantiate = mod_thread_instantiate,
1183  .thread_detach = mod_thread_detach
1184  },
1185  .method_group = {
1186  .bindings = (module_method_binding_t[]){
1187  /*
1188  * Hack to support old configurations
1189  */
1190  { .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
1191  { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
1192  { .section = SECTION_NAME("authorize", CF_IDENT_ANY), .method = mod_authorize },
1193 
1194  { .section = SECTION_NAME("recv", "accounting-request"), .method = mod_preacct },
1195  { .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
1196 
1197  { .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_post_auth },
1199  }
1200  }
1201 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
static int const char char buffer[256]
Definition: acutest.h:574
log_entry msg
Definition: acutest.h:794
va_list args
Definition: acutest.h:770
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition: cf_util.c:632
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:664
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1578
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:1028
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:684
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition: cf_util.c:618
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1171
#define cf_item_next(_ci, _curr)
Definition: cf_util.h:92
#define CF_IDENT_ANY
Definition: cf_util.h:78
fr_dcursor_iter_t void * current
Definition: dcursor.h:148
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:139
int dependency_version_number_add(CONF_SECTION *cs, char const *name, char const *version)
Add a library/server version pair to the main configuration.
Definition: dependency.c:153
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
Test enumeration values.
Definition: dict_test.h:92
void * dl_open_by_sym(char const *sym_name, int flags)
Utility function to dlopen the library containing a particular symbol.
Definition: dl.c:186
#define RTLD_NOW
Definition: dl.c:44
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
char const * name
Name of library and section within global config.
Definition: global_lib.h:39
#define GLOBAL_LIB_TERMINATOR
Definition: global_lib.h:51
Structure to define how to initialise libraries with global configuration.
Definition: global_lib.h:38
#define PERROR(_fmt,...)
Definition: log.h:228
#define DEBUG3(_fmt,...)
Definition: log.h:266
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition: log.h:528
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RERROR(fmt,...)
Definition: log.h:298
talloc_free(reap)
fr_log_t default_log
Definition: log.c:291
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition: log.c:583
@ L_DBG_WARN_REQ
Less severe warning only displayed when debugging is enabled.
Definition: log.h:63
@ L_WARN
Warning.
Definition: log.h:57
@ L_ERR
Error message.
Definition: log.h:56
@ L_DBG_ERR
Error only displayed when debugging is enabled.
Definition: log.h:62
@ L_DBG_ERR_REQ
Less severe error only displayed when debugging is enabled.
Definition: log.h:64
@ L_DBG_WARN
Warning only displayed when debugging is enabled.
Definition: log.h:61
@ L_INFO
Informational message.
Definition: log.h:55
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
#define LSAN_DISABLE(_x)
Definition: lsan.h:41
main_config_t const * main_config
Main server configuration.
Definition: main_config.c:69
char const * name
Name of the daemon, usually 'radiusd'.
Definition: main_config.h:52
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_FLOAT32
Single precision floating point.
Definition: merged_model.c:108
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_INT8
8 Bit signed integer.
Definition: merged_model.c:103
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
Definition: merged_model.c:93
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_INT64
64 Bit signed integer.
Definition: merged_model.c:106
@ FR_TYPE_INT16
16 Bit signed integer.
Definition: merged_model.c:104
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
Definition: merged_model.c:92
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
Definition: merged_model.c:115
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
Definition: merged_model.c:91
@ FR_TYPE_IFID
Interface ID.
Definition: merged_model.c:90
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_FLOAT64
Double precision floating point.
Definition: merged_model.c:109
long int ssize_t
Definition: merged_model.c:24
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
void * thread
Thread specific instance data.
Definition: module_ctx.h:43
module_instance_t * mi
Module instance to detach.
Definition: module_ctx.h:57
void * thread
Thread instance data.
Definition: module_ctx.h:67
#define MODULE_CTX_FROM_INST(_mctx)
Wrapper to create a module_ctx_t as a compound literal from a module_inst_ctx_t.
Definition: module_ctx.h:138
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition: module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition: module_ctx.h:63
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:283
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1345
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
Definition: pair.c:2589
void radius_pairmove(request_t *request, fr_pair_list_t *to, fr_pair_list_t *from)
Definition: pairmove.c:45
static const conf_parser_t config[]
Definition: base.c:183
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define WARN(fmt,...)
Definition: radclient.h:47
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition: rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition: rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition: rcode.h:41
@ RLM_MODULE_NOTFOUND
User not found.
Definition: rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition: rcode.h:49
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition: rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition: rcode.h:50
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition: rcode.h:44
fr_dict_attr_t const * request_attr_reply
Definition: request.c:46
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_chap.c:228
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_chap.c:176
static unlang_action_t mod_accounting(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Write accounting data to Couchbase documents.
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_detail.c:400
static int libpython_init(void)
Definition: rlm_python.c:1054
PyObject * pythonconf_dict
Configuration parameters defined in the module made available to the python script.
Definition: rlm_python.c:71
static int mod_detach(module_detach_ctx_t const *mctx)
Definition: rlm_python.c:977
static void python_function_destroy(python_func_def_t *def)
Definition: rlm_python.c:648
static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
Definition: rlm_python.c:694
static int python_module_import_config(module_inst_ctx_t const *mctx, CONF_SECTION *conf, PyObject *module)
Make the current instance's config available within the module we're initialising.
Definition: rlm_python.c:777
python_func_def_t detach
Definition: rlm_python.c:69
#define A(x)
python_func_def_t post_auth
Definition: rlm_python.c:68
static PyObject * mod_log(UNUSED PyObject *module, PyObject *args)
Allow fr_log to be called from python.
Definition: rlm_python.c:204
static struct @167 freeradius_constants[]
static global_lib_autoinst_t rlm_python_autoinst
Definition: rlm_python.c:112
static void libpython_free(void)
Definition: rlm_python.c:1146
PyThreadState * interpreter
The interpreter used for this instance of rlm_python.
Definition: rlm_python.c:59
module_rlm_t rlm_python
Definition: rlm_python.c:1169
PyObject * module
Local, interpreter specific module.
Definition: rlm_python.c:60
static PyObject * python_module_init(void)
Definition: rlm_python.c:831
python_func_def_t accounting
Definition: rlm_python.c:67
static void python_obj_destroy(PyObject **ob)
Definition: rlm_python.c:640
static void mod_vptuple(TALLOC_CTX *ctx, module_ctx_t const *mctx, request_t *request, fr_pair_list_t *vps, PyObject *p_value, char const *funcname, char const *list_name)
Definition: rlm_python.c:281
char const * module_name
String name of module.
Definition: rlm_python.c:50
PyThreadState * state
Module instance/thread specific state.
Definition: rlm_python.c:89
char const * name
Name of the module instance.
Definition: rlm_python.c:58
#define MOD_FUNC(x)
Definition: rlm_python.c:627
static PyThreadState * global_interpreter
Our first interpreter.
Definition: rlm_python.c:93
bool path_include_default
Include the default python path in path
Definition: rlm_python.c:80
static int mod_populate_vptuple(module_ctx_t const *mctx, request_t *request, PyObject *pp, fr_pair_t *vp)
Definition: rlm_python.c:373
PyObject * module
Python reference to module.
Definition: rlm_python.c:47
#define LOAD_WARN(_fmt,...)
static unlang_action_t do_python(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PyObject *p_func, char const *funcname)
Thread safe call to a python function.
Definition: rlm_python.c:607
static conf_parser_t const python_global_config[]
Definition: rlm_python.c:103
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition: rlm_python.c:1023
static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
Definition: rlm_python.c:902
static int python_function_load(module_inst_ctx_t const *mctx, python_func_def_t *def)
Import a user module and load a function from it.
Definition: rlm_python.c:657
static libpython_global_config_t libpython_global_config
Definition: rlm_python.c:98
python_func_def_t authorize
Definition: rlm_python.c:64
char const * function_name
String name of function in module.
Definition: rlm_python.c:51
static module_ctx_t const * current_mctx
Used for communication with inittab functions.
Definition: rlm_python.c:95
PyObject * function
Python reference to function in module.
Definition: rlm_python.c:48
static CONF_SECTION * current_conf
Used for communication with inittab functions.
Definition: rlm_python.c:96
static unlang_action_t do_python_single(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request, PyObject *p_func, char const *funcname)
Definition: rlm_python.c:476
#define LOAD_INFO(_fmt,...)
#define PYTHON_FUNC_LOAD(_x)
python_func_def_t authenticate
Definition: rlm_python.c:65
static void * python_dlhandle
Definition: rlm_python.c:92
static void python_error_log(module_ctx_t const *mctx, request_t *request)
Print out the current error.
Definition: rlm_python.c:231
static int python_interpreter_init(module_inst_ctx_t const *mctx)
Definition: rlm_python.c:854
char const * path
Path to search for python files in.
Definition: rlm_python.c:79
#define PYTHON_FUNC_DESTROY(_x)
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition: rlm_python.c:1041
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_python.c:927
python_func_def_t preacct
Definition: rlm_python.c:66
static int python_module_import_constants(module_inst_ctx_t const *mctx, PyObject *module)
Import integer constants into the module we're initialising.
Definition: rlm_python.c:813
global_lib_autoinst_t const *const rlm_python_lib[]
Definition: rlm_python.c:121
static conf_parser_t module_config[]
Definition: rlm_python.c:147
static PyMethodDef module_methods[]
Definition: rlm_python.c:218
python_func_def_t instantiate
Definition: rlm_python.c:63
Global config for python library.
Definition: rlm_python.c:78
Specifies the module.function to load for processing a section.
Definition: rlm_python.c:46
An instance of the rlm_python module.
Definition: rlm_python.c:57
Tracks a python module inst/thread state pair.
Definition: rlm_python.c:88
static char const * name
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
static unlang_action_t mod_preacct(rlm_rcode_t *p_result, module_ctx_t const *mctx, UNUSED request_t *request)
Definition: rlm_test.c:246
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Named methods exported by a module.
Definition: module.h:173
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition: tmpl.h:812
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
int tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
Definition: tmpl_eval.c:169
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
Definition: pair_inline.c:151
#define FR_TYPE_NON_LEAF
Definition: types.h:298
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5352