The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: d95112933fa9772537bca04090d3cb7cfcf2ea51 $
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 */
28RCSID("$Id: d95112933fa9772537bca04090d3cb7cfcf2ea51 $")
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 */
46typedef 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 */
57typedef 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.
74
75/** Global config for python library
76 *
77 */
78typedef 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 */
88typedef struct {
89 PyThreadState *state; //!< Module instance/thread specific state.
91
92static void *python_dlhandle;
93static PyThreadState *global_interpreter; //!< Our first interpreter.
94
95static module_ctx_t const *current_mctx; //!< Used for communication with inittab functions.
96static 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
109static int libpython_init(void);
110static void libpython_free(void);
111
113 .name = "python",
114 .config = python_global_config,
115 .init = libpython_init,
116 .free = libpython_free,
118};
119
120extern global_lib_autoinst_t const * const rlm_python_lib[];
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
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
165static struct {
166 char const *name;
167 int value;
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)
178 A(L_DBG_ERR)
191
192#undef A
193
194 { NULL, 0 },
196
197/*
198 * radiusd Python functions
199 */
200
201/** Allow fr_log to be called from python
202 *
203 */
204static 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
218static 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 */
231static 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
273failed:
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
281static 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 */
373static 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
439 case FR_TYPE_DATE:
440 case FR_TYPE_IFID:
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 {
466 fr_pair_t *child_vp;
467 int child_len, i = 0;
468
469 child_len = fr_pair_list_num_elements(&vp->vp_group);
470 if (child_len == 0) {
471 Py_INCREF(Py_None);
472 value = Py_None;
473 break;
474 }
475
476 if ((value = PyTuple_New(child_len)) == NULL) goto error;
477
478 for (child_vp = fr_pair_list_head(&vp->vp_group);
479 child_vp;
480 child_vp = fr_pair_list_next(&vp->vp_group, child_vp), i++) {
481 PyObject *child_pp;
482
483 if ((child_pp = PyTuple_New(2)) == NULL) {
484 Py_DECREF(value);
485 goto error;
486 }
487
488 if (mod_populate_vptuple(mctx, request, child_pp, child_vp) == 0) {
489 PyTuple_SET_ITEM(value, i, child_pp);
490 } else {
491 Py_INCREF(Py_None);
492 PyTuple_SET_ITEM(value, i, Py_None);
493 Py_DECREF(child_pp);
494 }
495 }
496 }
497 break;
498 }
499
500 if (value == NULL) goto error;
501
502 PyTuple_SET_ITEM(pp, 0, attribute);
503 PyTuple_SET_ITEM(pp, 1, value);
504
505 return 0;
506}
507
509 request_t *request, PyObject *p_func, char const *funcname)
510{
511 fr_pair_t *vp;
512 PyObject *p_ret = NULL;
513 PyObject *p_arg = NULL;
514 int tuple_len;
516
517 /*
518 * We will pass a tuple containing (name, value) tuples
519 * We can safely use the Python function to build up a
520 * tuple, since the tuple is not used elsewhere.
521 *
522 * Determine the size of our tuple by walking through the packet.
523 * If request is NULL, pass None.
524 */
525 tuple_len = 0;
526 if (request != NULL) {
527 tuple_len = fr_pair_list_num_elements(&request->request_pairs);
528 }
529
530 if (tuple_len == 0) {
531 Py_INCREF(Py_None);
532 p_arg = Py_None;
533 } else {
534 int i = 0;
535 if ((p_arg = PyTuple_New(tuple_len)) == NULL) {
536 rcode = RLM_MODULE_FAIL;
537 goto finish;
538 }
539
540 for (vp = fr_pair_list_head(&request->request_pairs);
541 vp;
542 vp = fr_pair_list_next(&request->request_pairs, vp), i++) {
543 PyObject *pp;
544
545 /* The inside tuple has two only: */
546 if ((pp = PyTuple_New(2)) == NULL) {
547 rcode = RLM_MODULE_FAIL;
548 goto finish;
549 }
550
551 if (mod_populate_vptuple(mctx, request, pp, vp) == 0) {
552 /* Put the tuple inside the container */
553 PyTuple_SET_ITEM(p_arg, i, pp);
554 } else {
555 Py_INCREF(Py_None);
556 PyTuple_SET_ITEM(p_arg, i, Py_None);
557 Py_DECREF(pp);
558 }
559 }
560 }
561
562 /* Call Python function. */
563 p_ret = PyObject_CallFunctionObjArgs(p_func, p_arg, NULL);
564 if (!p_ret) {
565 python_error_log(mctx, request); /* Needs valid thread with GIL */
566 rcode = RLM_MODULE_FAIL;
567 goto finish;
568 }
569
570 if (!request) {
571 // check return code at module instantiation time
572 if (PyNumber_Check(p_ret)) rcode = PyLong_AsLong(p_ret);
573 goto finish;
574 }
575
576 /*
577 * The function returns either:
578 * 1. (returnvalue, replyTuple, configTuple), where
579 * - returnvalue is one of the constants RLM_*
580 * - replyTuple and configTuple are tuples of string
581 * tuples of size 2
582 *
583 * 2. the function return value alone
584 *
585 * 3. None - default return value is set
586 *
587 * xxx This code is messy!
588 */
589 if (PyTuple_CheckExact(p_ret)) {
590 PyObject *p_tuple_int;
591
592 if (PyTuple_GET_SIZE(p_ret) != 3) {
593 ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
594 rcode = RLM_MODULE_FAIL;
595 goto finish;
596 }
597
598 p_tuple_int = PyTuple_GET_ITEM(p_ret, 0);
599 if (!PyNumber_Check(p_tuple_int)) {
600 ERROR("%s - First tuple element not an integer", funcname);
601 rcode = RLM_MODULE_FAIL;
602 goto finish;
603 }
604 /* Now have the return value */
605 rcode = PyLong_AsLong(p_tuple_int);
606 /* Reply item tuple */
607 mod_vptuple(request->reply_ctx, mctx, request, &request->reply_pairs,
608 PyTuple_GET_ITEM(p_ret, 1), funcname, "reply");
609 /* Config item tuple */
610 mod_vptuple(request->control_ctx, mctx, request, &request->control_pairs,
611 PyTuple_GET_ITEM(p_ret, 2), funcname, "config");
612
613 } else if (PyNumber_Check(p_ret)) {
614 /* Just an integer */
615 rcode = PyLong_AsLong(p_ret);
616
617 } else if (p_ret == Py_None) {
618 /* returned 'None', return value defaults to "OK, continue." */
619 rcode = RLM_MODULE_OK;
620 } else {
621 /* Not tuple or None */
622 ERROR("%s - Function did not return a tuple or None", funcname);
623 rcode = RLM_MODULE_FAIL;
624 goto finish;
625 }
626
627finish:
628 if (rcode == RLM_MODULE_FAIL) python_error_log(mctx, request);
629 Py_XDECREF(p_arg);
630 Py_XDECREF(p_ret);
631
632 RETURN_MODULE_RCODE(rcode);
633}
634
635/** Thread safe call to a python function
636 *
637 * Will swap in thread state specific to module/thread.
638 */
639static unlang_action_t do_python(rlm_rcode_t *p_result, module_ctx_t const *mctx,
640 request_t *request, PyObject *p_func, char const *funcname)
641{
642 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
643 rlm_rcode_t rcode;
644
645 /*
646 * It's a NOOP if the function wasn't defined
647 */
648 if (!p_func) RETURN_MODULE_NOOP;
649
650 RDEBUG3("Using thread state %p/%p", mctx->mi->data, t->state);
651
652 PyEval_RestoreThread(t->state); /* Swap in our local thread state */
653 do_python_single(&rcode, mctx, request, p_func, funcname);
654 (void)fr_cond_assert(PyEval_SaveThread() == t->state);
655
656 RETURN_MODULE_RCODE(rcode);
657}
658
659#define MOD_FUNC(x) \
660static unlang_action_t CC_HINT(nonnull) mod_##x(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) \
661{ \
662 rlm_python_t const *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_python_t); \
663 return do_python(p_result, mctx, request, inst->x.function, #x);\
664}
665
666MOD_FUNC(authenticate)
667MOD_FUNC(authorize)
668MOD_FUNC(preacct)
669MOD_FUNC(accounting)
670MOD_FUNC(post_auth)
671
672static void python_obj_destroy(PyObject **ob)
673{
674 if (*ob != NULL) {
675 Py_DECREF(*ob);
676 *ob = NULL;
677 }
678}
679
681{
683 python_obj_destroy(&def->module);
684}
685
686/** Import a user module and load a function from it
687 *
688 */
690{
691 char const *funcname = "python_function_load";
692
693 if (def->module_name == NULL || def->function_name == NULL) return 0;
694
695 LSAN_DISABLE(def->module = PyImport_ImportModule(def->module_name));
696 if (!def->module) {
697 ERROR("%s - Module '%s' load failed", funcname, def->module_name);
698 error:
700 Py_XDECREF(def->function);
701 def->function = NULL;
702 Py_XDECREF(def->module);
703 def->module = NULL;
704
705 return -1;
706 }
707
708 def->function = PyObject_GetAttrString(def->module, def->function_name);
709 if (!def->function) {
710 ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
711 goto error;
712 }
713
714 if (!PyCallable_Check(def->function)) {
715 ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
716 goto error;
717 }
718
719 DEBUG2("Loaded function '%s.%s'", def->module_name, def->function_name);
720 return 0;
721}
722
723/*
724 * Parse a configuration section, and populate a dict.
725 * This function is recursively called (allows to have nested dicts.)
726 */
727static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
728{
729 int indent_section = (lvl * 4);
730 int indent_item = (lvl + 1) * 4;
731 int ret = 0;
732 CONF_ITEM *ci = NULL;
733
734 if (!cs || !dict) return -1;
735
736 DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
737
738 while ((ci = cf_item_next(cs, ci))) {
739 /*
740 * This is a section.
741 * Create a new dict, store it in current dict,
742 * Then recursively call python_parse_config with this section and the new dict.
743 */
744 if (cf_item_is_section(ci)) {
745 CONF_SECTION *sub_cs = cf_item_to_section(ci);
746 char const *key = cf_section_name1(sub_cs); /* dict key */
747 PyObject *sub_dict, *p_key;
748
749 p_key = PyUnicode_FromString(key);
750 if (!p_key) {
751 ERROR("Failed converting config key \"%s\" to python string", key);
752 return -1;
753 }
754
755 if (PyDict_Contains(dict, p_key)) {
756 WARN("Ignoring duplicate config section '%s'", key);
757 continue;
758 }
759
760 MEM(sub_dict = PyDict_New());
761 (void)PyDict_SetItem(dict, p_key, sub_dict);
762
763 ret = python_parse_config(mctx, sub_cs, lvl + 1, sub_dict);
764 if (ret < 0) break;
765 } else if (cf_item_is_pair(ci)) {
766 CONF_PAIR *cp = cf_item_to_pair(ci);
767 char const *key = cf_pair_attr(cp); /* dict key */
768 char const *value = cf_pair_value(cp); /* dict value */
769 PyObject *p_key, *p_value;
770
771 if (!value) {
772 WARN("Skipping \"%s\" as it has no value", key);
773 continue;
774 }
775
776 p_key = PyUnicode_FromString(key);
777 p_value = PyUnicode_FromString(value);
778 if (!p_key) {
779 ERROR("Failed converting config key \"%s\" to python string", key);
780 return -1;
781 }
782 if (!p_value) {
783 ERROR("Failed converting config value \"%s\" to python string", value);
784 return -1;
785 }
786
787 /*
788 * This is an item.
789 * Store item attr / value in current dict.
790 */
791 if (PyDict_Contains(dict, p_key)) {
792 WARN("Ignoring duplicate config item '%s'", key);
793 continue;
794 }
795
796 (void)PyDict_SetItem(dict, p_key, p_value);
797
798 DEBUG("%*s%s = \"%s\"", indent_item, " ", key, value);
799 }
800 }
801
802 DEBUG("%*s}", indent_section, " ");
803
804 return ret;
805}
806
807/** Make the current instance's config available within the module we're initialising
808 *
809 */
810static int python_module_import_config(module_inst_ctx_t const *mctx, CONF_SECTION *conf, PyObject *module)
811{
812 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
813 CONF_SECTION *cs;
814
815 /*
816 * Convert a FreeRADIUS config structure into a python
817 * dictionary.
818 */
819 inst->pythonconf_dict = PyDict_New();
820 if (!inst->pythonconf_dict) {
821 ERROR("Unable to create python dict for config");
822 error:
823 Py_XDECREF(inst->pythonconf_dict);
824 inst->pythonconf_dict = NULL;
826 return -1;
827 }
828
829 cs = cf_section_find(conf, "config", NULL);
830 if (cs) {
831 DEBUG("Inserting \"config\" section into python environment as radiusd.config");
832 if (python_parse_config(mctx, cs, 0, inst->pythonconf_dict) < 0) goto error;
833 }
834
835 /*
836 * Add module configuration as a dict
837 */
838 if (PyModule_AddObject(module, "config", inst->pythonconf_dict) < 0) goto error;
839
840 return 0;
841}
842
843/** Import integer constants into the module we're initialising
844 *
845 */
846static int python_module_import_constants(module_inst_ctx_t const *mctx, PyObject *module)
847{
848 size_t i;
849
850 for (i = 0; freeradius_constants[i].name; i++) {
851 if ((PyModule_AddIntConstant(module, freeradius_constants[i].name, freeradius_constants[i].value)) < 0) {
852 ERROR("Failed adding constant to module");
854 return -1;
855 }
856 }
857
858 return 0;
859}
860
861/*
862 * Python 3 interpreter initialisation and destruction
863 */
864static PyObject *python_module_init(void)
865{
866 PyObject *module;
867
868 static struct PyModuleDef py_module_def = {
869 PyModuleDef_HEAD_INIT,
870 .m_name = "freeradius",
871 .m_doc = "freeRADIUS python module",
872 .m_size = -1,
873 .m_methods = module_methods
874 };
875
877
878 module = PyModule_Create(&py_module_def);
879 if (!module) {
881 Py_RETURN_NONE;
882 }
883
884 return module;
885}
886
888{
889 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
890 CONF_SECTION *conf = mctx->mi->conf;
891 PyObject *module;
892
893 /*
894 * python_module_init takes no args, so we need
895 * to set these globals so that when it's
896 * called during interpreter initialisation
897 * it can get at the current instance config.
898 */
901
902 PyEval_RestoreThread(global_interpreter);
903 LSAN_DISABLE(inst->interpreter = Py_NewInterpreter());
904 if (!inst->interpreter) {
905 ERROR("Failed creating new interpreter");
906 return -1;
907 }
908 DEBUG3("Created new interpreter %p", inst->interpreter);
909 PyEval_SaveThread(); /* Unlock GIL */
910
911 PyEval_RestoreThread(inst->interpreter);
912
913 /*
914 * Import the radiusd module into this python
915 * environment. Each interpreter gets its
916 * own copy which it can mutate as much as
917 * it wants.
918 */
919 module = PyImport_ImportModule("freeradius");
920 if (!module) {
921 ERROR("Failed importing \"freeradius\" module into interpreter %p", inst->interpreter);
922 return -1;
923 }
924 if ((python_module_import_config(mctx, conf, module) < 0) ||
925 (python_module_import_constants(mctx, module) < 0)) {
926 Py_DECREF(module);
927 return -1;
928 }
929 inst->module = module;
930 PyEval_SaveThread();
931
932 return 0;
933}
934
935static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
936{
937 /*
938 * We incremented the reference count earlier
939 * during module initialisation.
940 */
941 Py_XDECREF(inst->module);
942
943 PyEval_RestoreThread(interp); /* Switches thread state and locks GIL */
944 Py_EndInterpreter(interp); /* Destroys interpreter (GIL still locked) - sets thread state to NULL */
945 PyThreadState_Swap(global_interpreter); /* Get a none-null thread state */
946 PyEval_SaveThread(); /* Unlock GIL */
947}
948
949/*
950 * Do any per-module initialization that is separate to each
951 * configured instance of the module. e.g. set up connections
952 * to external databases, read configuration files, set up
953 * dictionary entries, etc.
954 *
955 * If configuration information is given in the config section
956 * that must be referenced in later calls, store a handle to it
957 * in *instance otherwise put a null pointer there.
958 *
959 */
960static int mod_instantiate(module_inst_ctx_t const *mctx)
961{
962 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
963
964 if (python_interpreter_init(mctx) < 0) return -1;
965
966 /*
967 * Switch to our module specific interpreter
968 */
969 PyEval_RestoreThread(inst->interpreter);
970
971 /*
972 * Process the various sections
973 */
974#define PYTHON_FUNC_LOAD(_x) if (python_function_load(mctx, &inst->_x) < 0) goto error
976 PYTHON_FUNC_LOAD(authenticate);
977 PYTHON_FUNC_LOAD(authorize);
978 PYTHON_FUNC_LOAD(preacct);
979 PYTHON_FUNC_LOAD(accounting);
980 PYTHON_FUNC_LOAD(post_auth);
981 PYTHON_FUNC_LOAD(detach);
982
983 /*
984 * Call the instantiate function.
985 */
986 if (inst->instantiate.function) {
987 rlm_rcode_t rcode;
988
989 do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->instantiate.function, "instantiate");
990 switch (rcode) {
991 case RLM_MODULE_FAIL:
993 error:
994 fr_cond_assert(PyEval_SaveThread() == inst->interpreter);
995 python_interpreter_free(inst, inst->interpreter);
996 return -1;
997
998 default:
999 break;
1000 }
1001 }
1002
1003 /*
1004 * Switch back to the global interpreter
1005 */
1006 if (!fr_cond_assert(PyEval_SaveThread() == inst->interpreter)) goto error;
1007
1008 return 0;
1009}
1010
1011static int mod_detach(module_detach_ctx_t const *mctx)
1012{
1013 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
1014
1015 /*
1016 * If we don't have a interpreter
1017 * we didn't get far enough into
1018 * instantiation to generate things
1019 * we need to clean up...
1020 */
1021 if (!inst->interpreter) return 0;
1022
1023 /*
1024 * Call module destructor
1025 */
1026 PyEval_RestoreThread(inst->interpreter);
1027
1028 /*
1029 * We don't care if this fails.
1030 */
1031 if (inst->detach.function) {
1032 rlm_rcode_t rcode;
1033
1034 (void)do_python_single(&rcode, MODULE_CTX_FROM_INST(mctx), NULL, inst->detach.function, "detach");
1035 }
1036
1037#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
1039 PYTHON_FUNC_DESTROY(authorize);
1040 PYTHON_FUNC_DESTROY(authenticate);
1041 PYTHON_FUNC_DESTROY(preacct);
1042 PYTHON_FUNC_DESTROY(accounting);
1043 PYTHON_FUNC_DESTROY(post_auth);
1044 PYTHON_FUNC_DESTROY(detach);
1045
1046 Py_XDECREF(inst->pythonconf_dict);
1047 PyEval_SaveThread();
1048
1049 /*
1050 * Free the module specific interpreter
1051 */
1052 python_interpreter_free(inst, inst->interpreter);
1053
1054 return 0;
1055}
1056
1058{
1059 PyThreadState *state;
1060 rlm_python_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_python_t);
1061 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1062
1063 state = PyThreadState_New(inst->interpreter->interp);
1064 if (!state) {
1065 ERROR("Failed initialising local PyThreadState");
1066 return -1;
1067 }
1068
1069 DEBUG3("Initialised new thread state %p", state);
1070 t->state = state;
1071
1072 return 0;
1073}
1074
1076{
1077 rlm_python_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_python_thread_t);
1078
1079 PyEval_RestoreThread(t->state); /* Swap in our local thread state */
1080 PyThreadState_Clear(t->state);
1081 PyEval_SaveThread();
1082
1083 PyThreadState_Delete(t->state); /* Don't need to hold lock for this */
1084
1085 return 0;
1086}
1087
1088static int libpython_init(void)
1089{
1090#define LOAD_INFO(_fmt, ...) fr_log(LOG_DST, L_INFO, __FILE__, __LINE__, "rlm_python - " _fmt, ## __VA_ARGS__)
1091#define LOAD_WARN(_fmt, ...) fr_log_perror(LOG_DST, L_WARN, __FILE__, __LINE__, \
1092 &(fr_log_perror_format_t){ \
1093 .first_prefix = "rlm_python - ", \
1094 .subsq_prefix = "rlm_python - ", \
1095 }, \
1096 _fmt, ## __VA_ARGS__)
1097 PyConfig config;
1098 PyStatus status;
1099 wchar_t *wide_name;
1100 char *path;
1101
1102 fr_assert(!Py_IsInitialized());
1103
1104 LOAD_INFO("Python version: %s", Py_GetVersion());
1105 dependency_version_number_add(NULL, "python", Py_GetVersion());
1106
1107 /*
1108 * Load python using RTLD_GLOBAL and dlopen.
1109 * This fixes issues where python C extensions
1110 * can't find the symbols they need.
1111 */
1112 python_dlhandle = dl_open_by_sym("Py_IsInitialized", RTLD_NOW | RTLD_GLOBAL);
1113 if (!python_dlhandle) LOAD_WARN("Failed loading libpython symbols into global symbol table");
1114
1115 PyConfig_InitPythonConfig(&config);
1116
1117 /*
1118 * Set program name (i.e. the software calling the interpreter)
1119 * The value of argv[0] as a wide char string
1120 */
1121 wide_name = Py_DecodeLocale(main_config->name, NULL);
1122 status = PyConfig_SetString(&config, &config.program_name, wide_name);
1123 PyMem_RawFree(wide_name);
1124
1125 if (PyStatus_Exception(status)) {
1126 fail:
1127 LOAD_WARN("%s", status.err_msg);
1128 PyConfig_Clear(&config);
1129 return -1;
1130 }
1131
1132 /*
1133 * Python 3 introduces the concept of a
1134 * "inittab", i.e. a list of modules which
1135 * are automatically created when the first
1136 * interpreter is spawned.
1137 */
1138 PyImport_AppendInittab("freeradius", python_module_init);
1139
1141 wchar_t *wide_path = Py_DecodeLocale(libpython_global_config.path, NULL);
1142
1144 /*
1145 * The path from config is to be used in addition to the default.
1146 * Set it in the pythonpath_env.
1147 */
1148 status = PyConfig_SetString(&config, &config.pythonpath_env, wide_path);
1149 } else {
1150 /*
1151 * Only the path from config is to be used.
1152 * Setting module_search_paths_set to 1 disables any automatic paths.
1153 */
1154 config.module_search_paths_set = 1;
1155 status = PyWideStringList_Append(&config.module_search_paths, wide_path);
1156 }
1157 PyMem_RawFree(wide_path);
1158 if (PyStatus_Exception(status)) goto fail;
1159 }
1160
1161 config.install_signal_handlers = 0; /* Don't override signal handlers - noop on subs calls */
1162
1163 LSAN_DISABLE(status = Py_InitializeFromConfig(&config));
1164 if (PyStatus_Exception(status)) goto fail;
1165
1166 PyConfig_Clear(&config);
1167
1168 /*
1169 * Report the path
1170 */
1171 path = Py_EncodeLocale(Py_GetPath(), NULL);
1172 LOAD_INFO("Python path set to \"%s\"", path);
1173 PyMem_Free(path);
1174
1175 global_interpreter = PyEval_SaveThread(); /* Store reference to the main interpreter and release the GIL */
1176
1177 return 0;
1178}
1179
1180static void libpython_free(void)
1181{
1182 PyThreadState_Swap(global_interpreter); /* Swap to the main thread */
1183
1184 /*
1185 * PyImport_Cleanup - Leaks memory in python 3.6
1186 * should check once we require 3.8 that this is
1187 * still needed.
1188 */
1189 LSAN_DISABLE(Py_Finalize()); /* Ignore leaks on exit, we don't reload modules so we don't care */
1190 if (python_dlhandle) dlclose(python_dlhandle); /* dlclose will SEGV on null handle */
1191}
1192
1193/*
1194 * The module name should be the only globally exported symbol.
1195 * That is, everything else should be 'static'.
1196 *
1197 * If the module needs to temporarily modify it's instantiation
1198 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
1199 * The server will then take care of ensuring that the module
1200 * is single-threaded.
1201 */
1204 .common = {
1205 .magic = MODULE_MAGIC_INIT,
1206 .name = "python",
1207
1208 .inst_size = sizeof(rlm_python_t),
1209 .thread_inst_size = sizeof(rlm_python_thread_t),
1210
1211 .config = module_config,
1212
1213 .instantiate = mod_instantiate,
1214 .detach = mod_detach,
1215
1216 .thread_instantiate = mod_thread_instantiate,
1217 .thread_detach = mod_thread_detach
1218 },
1219 .method_group = {
1220 .bindings = (module_method_binding_t[]){
1221 /*
1222 * Hack to support old configurations
1223 */
1224 { .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
1225 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
1226 { .section = SECTION_NAME("authorize", CF_IDENT_ANY), .method = mod_authorize },
1227
1228 { .section = SECTION_NAME("recv", "accounting-request"), .method = mod_preacct },
1229 { .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
1230
1231 { .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_post_auth },
1233 }
1234 }
1235};
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:576
log_entry msg
Definition acutest.h:794
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:483
#define UNUSED
Definition build.h:315
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#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:579
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
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1171
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
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
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_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1594
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1578
#define cf_item_next(_ci, _curr)
Definition cf_util.h:92
#define CF_IDENT_ANY
Definition cf_util.h:78
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
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.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_FLOAT64
Double precision floating point.
long int ssize_t
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
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
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
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 fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define DEBUG2(fmt,...)
Definition radclient.h:43
#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:375
static int libpython_init(void)
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)
PyObject *python_func_def_t authenticate
Definition rlm_python.c:65
static void python_function_destroy(python_func_def_t *def)
Definition rlm_python.c:680
static int python_parse_config(module_inst_ctx_t const *mctx, CONF_SECTION *cs, int lvl, PyObject *dict)
Definition rlm_python.c:727
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:810
PyObject *python_func_def_t accounting
Definition rlm_python.c:67
#define A(x)
PyObject *python_func_def_t preacct
Definition rlm_python.c:66
static struct @167 freeradius_constants[]
static global_lib_autoinst_t rlm_python_autoinst
Definition rlm_python.c:112
static void libpython_free(void)
PyThreadState * interpreter
The interpreter used for this instance of rlm_python.
Definition rlm_python.c:59
module_rlm_t rlm_python
PyObject *python_func_def_t detach
Definition rlm_python.c:69
static void python_obj_destroy(PyObject **ob)
Definition rlm_python.c:672
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
PyObject *python_func_def_t instantiate
< Local, interpreter specific module.
Definition rlm_python.c:63
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:659
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
#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:639
static PyObject * python_module_init(void)
Definition rlm_python.c:864
PyObject *PyObject * function
< Python reference to module.
Definition rlm_python.c:48
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)
static void python_interpreter_free(rlm_python_t *inst, PyThreadState *interp)
Definition rlm_python.c:935
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:689
PyObject *python_func_def_t post_auth
Definition rlm_python.c:68
static libpython_global_config_t libpython_global_config
Definition rlm_python.c:98
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
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:508
#define LOAD_INFO(_fmt,...)
#define PYTHON_FUNC_LOAD(_x)
static void * python_dlhandle
Definition rlm_python.c:92
PyObject *python_func_def_t authorize
Definition rlm_python.c:64
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:887
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)
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_python.c:960
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:846
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
static PyObject * mod_log(UNUSED PyObject *module, PyObject *args)
Allow fr_log to be called from python.
Definition rlm_python.c:204
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:1310
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
size_t inst_size
Size of the module's instance data.
Definition module.h:203
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
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
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:812
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:341
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_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
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
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
#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