508938df8ab82a59117a9e645c6990e34b2e63cb
[freeradius.git] / src / modules / rlm_python / rlm_python.c
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$
19  * @file rlm_python.c
20  * @brief Translates requests between the server an a python interpreter.
21  *
22  * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
23  *
24  * @copyright 2000,2006  The FreeRADIUS server project
25  * @copyright 2002  Miguel A.L. Paraz <mparaz@mparaz.com>
26  * @copyright 2002  Imperium Technology, Inc.
27  */
28 RCSID("$Id$")
29
30 #include <freeradius-devel/radiusd.h>
31 #include <freeradius-devel/modules.h>
32
33 #include <Python.h>
34 #include <dlfcn.h>
35
36 #ifdef HAVE_PTHREAD_H
37 #define Pyx_BLOCK_THREADS    {PyGILState_STATE __gstate = PyGILState_Ensure();
38 #define Pyx_UNBLOCK_THREADS   PyGILState_Release(__gstate);}
39 #else
40 #define Pyx_BLOCK_THREADS
41 #define Pyx_UNBLOCK_THREADS
42 #endif
43
44 /*
45  *      TODO: The only needed thing here is function. Anything else is
46  *      required for initialization only. I will remove it, putting a
47  *      symbolic constant here instead.
48  */
49 struct py_function_def {
50         PyObject        *module;
51         PyObject        *function;
52
53         char const      *module_name;
54         char const      *function_name;
55 };
56
57 typedef struct rlm_python_t {
58         void            *libpython;
59         PyThreadState   *main_thread_state;
60         char const      *python_path;
61
62         struct py_function_def
63         instantiate,
64         authorize,
65         authenticate,
66         preacct,
67         accounting,
68         checksimul,
69         pre_proxy,
70         post_proxy,
71         post_auth,
72 #ifdef WITH_COA
73         recv_coa,
74         send_coa,
75 #endif
76         detach;
77 } rlm_python_t;
78
79 /*
80  *      A mapping of configuration file names to internal variables.
81  */
82 static CONF_PARSER module_config[] = {
83
84 #define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), NULL }, \
85         { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
86
87         A(instantiate)
88         A(authorize)
89         A(authenticate)
90         A(preacct)
91         A(accounting)
92         A(checksimul)
93         A(pre_proxy)
94         A(post_proxy)
95         A(post_auth)
96 #ifdef WITH_COA
97         A(recv_coa)
98         A(send_coa)
99 #endif
100         A(detach)
101
102 #undef A
103
104         { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
105         CONF_PARSER_TERMINATOR
106 };
107
108 static struct {
109         char const *name;
110         int  value;
111 } radiusd_constants[] = {
112
113 #define A(x) { #x, x },
114
115         A(L_DBG)
116         A(L_AUTH)
117         A(L_INFO)
118         A(L_ERR)
119         A(L_PROXY)
120         A(L_WARN)
121         A(L_ACCT)
122         A(L_DBG_WARN)
123         A(L_DBG_ERR)
124         A(L_DBG_WARN_REQ)
125         A(L_DBG_ERR_REQ)
126         A(RLM_MODULE_REJECT)
127         A(RLM_MODULE_FAIL)
128         A(RLM_MODULE_OK)
129         A(RLM_MODULE_HANDLED)
130         A(RLM_MODULE_INVALID)
131         A(RLM_MODULE_USERLOCK)
132         A(RLM_MODULE_NOTFOUND)
133         A(RLM_MODULE_NOOP)
134         A(RLM_MODULE_UPDATED)
135         A(RLM_MODULE_NUMCODES)
136
137 #undef A
138
139         { NULL, 0 },
140 };
141
142 /*
143  *      This allows us to initialise PyThreadState on a per thread basis
144  */
145 fr_thread_local_setup(PyThreadState *, local_thread_state)      /* macro */
146
147
148 /*
149  *      Let assume that radiusd module is only one since we have only
150  *      one intepreter
151  */
152
153 static PyObject *radiusd_module = NULL;
154
155 /*
156  *      radiusd Python functions
157  */
158
159 /* radlog wrapper */
160 static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
161 {
162         int status;
163         char *msg;
164
165         if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
166                 return NULL;
167         }
168
169         radlog(status, "%s", msg);
170         Py_INCREF(Py_None);
171
172         return Py_None;
173 }
174
175 static PyMethodDef radiusd_methods[] = {
176         { "radlog", &mod_radlog, METH_VARARGS,
177           "radiusd.radlog(level, msg)\n\n" \
178           "Print a message using radiusd logging system. level should be one of the\n" \
179           "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
180         },
181         { NULL, NULL, 0, NULL },
182 };
183
184
185 static void mod_error(void)
186 {
187         PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
188
189         /* This will be called with the GIL lock held */
190
191         PyErr_Fetch(&pType, &pValue, &pTraceback);
192         if (!pType || !pValue)
193                 goto failed;
194         if (((pStr1 = PyObject_Str(pType)) == NULL) ||
195             ((pStr2 = PyObject_Str(pValue)) == NULL))
196                 goto failed;
197
198         ERROR("rlm_python:EXCEPT:%s: %s", PyString_AsString(pStr1), PyString_AsString(pStr2));
199
200 failed:
201         Py_XDECREF(pStr1);
202         Py_XDECREF(pStr2);
203         Py_XDECREF(pType);
204         Py_XDECREF(pValue);
205         Py_XDECREF(pTraceback);
206 }
207
208 static int mod_init(rlm_python_t *inst)
209 {
210         int i;
211         static char name[] = "radiusd";
212
213         if (radiusd_module) return 0;
214
215         /*
216          *      Explicitly load libpython, so symbols will be available to lib-dynload modules
217          */
218         inst->libpython = dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
219                                  RTLD_NOW | RTLD_GLOBAL);
220         if (!inst->libpython) {
221                 WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
222         }
223
224         Py_SetProgramName(name);
225 #ifdef HAVE_PTHREAD_H
226         Py_InitializeEx(0);                             /* Don't override signal handlers */
227         PyEval_InitThreads();                           /* This also grabs a lock */
228         inst->main_thread_state = PyThreadState_Get();  /* We need this for setting up thread local stuff */
229 #endif
230         if (inst->python_path) {
231                 char *path;
232
233                 memcpy(&path, &inst->python_path, sizeof(path));
234                 PySys_SetPath(path);
235         }
236
237         if ((radiusd_module = Py_InitModule3("radiusd", radiusd_methods,
238                                              "FreeRADIUS Module")) == NULL)
239                 goto failed;
240
241         for (i = 0; radiusd_constants[i].name; i++) {
242                 if ((PyModule_AddIntConstant(radiusd_module, radiusd_constants[i].name,
243                                              radiusd_constants[i].value)) < 0) {
244                         goto failed;
245                 }
246         }
247
248 #ifdef HAVE_PTHREAD_H
249         PyThreadState_Swap(NULL);       /* We have to swap out the current thread else we get deadlocks */
250         PyEval_ReleaseLock();           /* Drop lock grabbed by InitThreads */
251 #endif
252         DEBUG("mod_init done");
253         return 0;
254
255 failed:
256         Py_XDECREF(radiusd_module);
257
258 #ifdef HAVE_PTHREAD_H
259         PyEval_ReleaseLock();
260 #endif
261
262         Pyx_BLOCK_THREADS
263         mod_error();
264         Pyx_UNBLOCK_THREADS
265
266         radiusd_module = NULL;
267
268         Py_Finalize();
269         return -1;
270 }
271
272 #if 0
273
274 static int mod_destroy(void)
275 {
276         Pyx_BLOCK_THREADS
277         Py_XDECREF(radiusd_module);
278         Py_Finalize();
279         Pyx_UNBLOCK_THREADS
280
281         return 0;
282 }
283
284 /*
285  *      This will need reconsidering in a future. Maybe we'll need to
286  *      have our own reference counting for radiusd_module
287  */
288 #endif
289
290 /* TODO: Convert this function to accept any iterable objects? */
291
292 static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
293                         char const *funcname, char const *list_name)
294 {
295         int          i;
296         int          tuplesize;
297         vp_tmpl_t       dst;
298         VALUE_PAIR      *vp;
299         REQUEST         *current = request;
300
301         memset(&dst, 0, sizeof(dst));
302
303         /*
304          *      If the Python function gave us None for the tuple,
305          *      then just return.
306          */
307         if (pValue == Py_None)
308                 return;
309
310         if (!PyTuple_CheckExact(pValue)) {
311                 ERROR("rlm_python:%s: non-tuple passed to %s", funcname, list_name);
312                 return;
313         }
314         /* Get the tuple tuplesize. */
315         tuplesize = PyTuple_GET_SIZE(pValue);
316         for (i = 0; i < tuplesize; i++) {
317                 PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
318                 PyObject *pStr1;
319                 PyObject *pStr2;
320                 PyObject *pOp;
321                 int pairsize;
322                 char const *s1;
323                 char const *s2;
324                 FR_TOKEN op = T_OP_EQ;
325
326                 if (!PyTuple_CheckExact(pTupleElement)) {
327                         ERROR("rlm_python:%s: tuple element %d of %s is not a tuple", funcname, i, list_name);
328                         continue;
329                 }
330                 /* Check if it's a pair */
331
332                 pairsize = PyTuple_GET_SIZE(pTupleElement);
333                 if ((pairsize < 2) || (pairsize > 3)) {
334                         ERROR("rlm_python:%s: tuple element %d of %s is a tuple of size %d. Must be 2 or 3.", funcname, i, list_name, pairsize);
335                         continue;
336                 }
337
338                 if (pairsize == 2) {
339                         pStr1   = PyTuple_GET_ITEM(pTupleElement, 0);
340                         pStr2   = PyTuple_GET_ITEM(pTupleElement, 1);
341                 } else {
342                         pStr1   = PyTuple_GET_ITEM(pTupleElement, 0);
343                         pStr2   = PyTuple_GET_ITEM(pTupleElement, 2);
344                         pOp = PyTuple_GET_ITEM(pTupleElement, 1);
345                         if (PyInt_Check(pOp)) {
346                                 op      = PyInt_AsLong(pOp);
347                                 if (!fr_int2str(fr_tokens, op, NULL)) {
348                                         ERROR("rlm_python:%s: Invalid operator '%i', falling back to '='", funcname, op);
349                                         op = T_OP_EQ;
350                                 }
351                         } else if (PyString_CheckExact(pOp)) {
352                                 if (!(op = fr_str2int(fr_tokens, PyString_AsString(pOp), 0))) {
353                                         ERROR("rlm_python:%s: Invalid operator '%s', falling back to '='", funcname, PyString_AsString(pOp));
354                                         op = T_OP_EQ;
355                                 }
356                         } else {
357                                 ERROR("rlm_python:%s: Invalid operator type, using default '='", funcname);
358                         }
359                 }
360
361                 if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
362                         ERROR("rlm_python:%s: tuple element %d of %s must be as (str, str)", funcname, i, list_name);
363                         continue;
364                 }
365                 s1 = PyString_AsString(pStr1);
366                 s2 = PyString_AsString(pStr2);
367
368                 if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
369                         DEBUG("rlm_python:%s: Failed to find attribute %s:%s", funcname, list_name, s1);
370                         continue;
371                 }
372
373                 if (radius_request(&current, dst.tmpl_request) < 0) {
374                         DEBUG("rlm_python:%s: Attribute name %s:%s refers to outer request but not in a tunnel, skipping...", funcname, list_name, s1);
375                 }
376
377                 if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
378                         DEBUG("rlm_python:%s: Failed to create attribute %s:%s", funcname, list_name, s1);
379                         continue;
380                 }
381
382                 vp->op = op;
383                 if (fr_pair_value_from_str(vp, s2, -1) < 0) {
384                         DEBUG("rlm_python:%s: Failed: '%s:%s' %s '%s'", funcname, list_name, s1, fr_int2str(fr_tokens, op, "="), s2);
385                 } else {
386                         DEBUG("rlm_python:%s: '%s:%s' %s '%s'", funcname, list_name, s1, fr_int2str(fr_tokens, op, "="), s2);
387                 }
388
389                 radius_pairmove(current, vps, vp, false);
390         }
391 }
392
393
394 /*
395  *      This is the core Python function that the others wrap around.
396  *      Pass the value-pair print strings in a tuple.
397  *
398  *      FIXME: We're not checking the errors. If we have errors, what
399  *      do we do?
400  */
401 static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
402 {
403         PyObject *pStr = NULL;
404         char buf[1024];
405
406         /* Look at the vp_print_name? */
407
408         if (vp->da->flags.has_tag)
409                 pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
410         else
411                 pStr = PyString_FromString(vp->da->name);
412
413         if (!pStr)
414                 goto failed;
415
416         PyTuple_SET_ITEM(pPair, 0, pStr);
417
418         vp_prints_value(buf, sizeof(buf), vp, '"');
419
420         if ((pStr = PyString_FromString(buf)) == NULL)
421                 goto failed;
422         PyTuple_SET_ITEM(pPair, 1, pStr);
423
424         return 0;
425
426 failed:
427         return -1;
428 }
429
430 #ifdef HAVE_PTHREAD_H
431 /** Cleanup any thread local storage on pthread_exit()
432  */
433 static void do_python_cleanup(void *arg)
434 {
435         PyThreadState   *my_thread_state = arg;
436
437         PyEval_AcquireLock();
438         PyThreadState_Swap(NULL);       /* Not entirely sure this is needed */
439         PyThreadState_Clear(my_thread_state);
440         PyThreadState_Delete(my_thread_state);
441         PyEval_ReleaseLock();
442 }
443 #endif
444
445 static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker)
446 {
447         vp_cursor_t     cursor;
448         VALUE_PAIR      *vp;
449         PyObject        *pRet = NULL;
450         PyObject        *pArgs = NULL;
451         int             tuplelen;
452         int             ret;
453
454         PyGILState_STATE gstate;
455         PyThreadState   *prev_thread_state = NULL;      /* -Wuninitialized */
456         memset(&gstate, 0, sizeof(gstate));             /* -Wuninitialized */
457
458         /* Return with "OK, continue" if the function is not defined. */
459         if (!pFunc)
460                 return RLM_MODULE_NOOP;
461
462 #ifdef HAVE_PTHREAD_H
463         gstate = PyGILState_Ensure();
464         if (worker) {
465                 PyThreadState *my_thread_state;
466                 my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup);
467                 if (!my_thread_state) {
468                         my_thread_state = PyThreadState_New(inst->main_thread_state->interp);
469                         RDEBUG3("Initialised new thread state %p", my_thread_state);
470                         if (!my_thread_state) {
471                                 REDEBUG("Failed initialising local PyThreadState on first run");
472                                 PyGILState_Release(gstate);
473                                 return RLM_MODULE_FAIL;
474                         }
475
476                         ret = fr_thread_local_set(local_thread_state, my_thread_state);
477                         if (ret != 0) {
478                                 REDEBUG("Failed storing PyThreadState in TLS: %s", fr_syserror(ret));
479                                 PyThreadState_Clear(my_thread_state);
480                                 PyThreadState_Delete(my_thread_state);
481                                 PyGILState_Release(gstate);
482                                 return RLM_MODULE_FAIL;
483                         }
484                 }
485                 RDEBUG3("Using thread state %p", my_thread_state);
486                 prev_thread_state = PyThreadState_Swap(my_thread_state);        /* Swap in our local thread state */
487         }
488 #endif
489
490         /* Default return value is "OK, continue" */
491         ret = RLM_MODULE_OK;
492
493         /*
494          *      We will pass a tuple containing (name, value) tuples
495          *      We can safely use the Python function to build up a
496          *      tuple, since the tuple is not used elsewhere.
497          *
498          *      Determine the size of our tuple by walking through the packet.
499          *      If request is NULL, pass None.
500          */
501         tuplelen = 0;
502         if (request != NULL) {
503                 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
504                      vp;
505                      vp = fr_cursor_next(&cursor)) {
506                         tuplelen++;
507                 }
508         }
509
510         if (tuplelen == 0) {
511                 Py_INCREF(Py_None);
512                 pArgs = Py_None;
513         } else {
514                 int i = 0;
515                 if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
516                         ret = RLM_MODULE_FAIL;
517                         goto finish;
518                 }
519
520                 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
521                      vp;
522                      vp = fr_cursor_next(&cursor), i++) {
523                         PyObject *pPair;
524
525                         /* The inside tuple has two only: */
526                         if ((pPair = PyTuple_New(2)) == NULL) {
527                                 ret = RLM_MODULE_FAIL;
528                                 goto finish;
529                         }
530
531                         if (mod_populate_vptuple(pPair, vp) == 0) {
532                                 /* Put the tuple inside the container */
533                                 PyTuple_SET_ITEM(pArgs, i, pPair);
534                         } else {
535                                 Py_INCREF(Py_None);
536                                 PyTuple_SET_ITEM(pArgs, i, Py_None);
537                                 Py_DECREF(pPair);
538                         }
539                 }
540         }
541
542         /* Call Python function. */
543         pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
544
545         if (!pRet) {
546                 ret = RLM_MODULE_FAIL;
547                 goto finish;
548         }
549
550         if (!request)
551                 goto finish;
552
553         /*
554          *      The function returns either:
555          *  1. (returnvalue, replyTuple, configTuple), where
556          *   - returnvalue is one of the constants RLM_*
557          *   - replyTuple and configTuple are tuples of string
558          *      tuples of size 2
559          *
560          *  2. the function return value alone
561          *
562          *  3. None - default return value is set
563          *
564          * xxx This code is messy!
565          */
566         if (PyTuple_CheckExact(pRet)) {
567                 PyObject *pTupleInt;
568
569                 if (PyTuple_GET_SIZE(pRet) != 3) {
570                         ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
571                         ret = RLM_MODULE_FAIL;
572                         goto finish;
573                 }
574
575                 pTupleInt = PyTuple_GET_ITEM(pRet, 0);
576                 if (!PyInt_CheckExact(pTupleInt)) {
577                         ERROR("rlm_python:%s: first tuple element not an integer", funcname);
578                         ret = RLM_MODULE_FAIL;
579                         goto finish;
580                 }
581                 /* Now have the return value */
582                 ret = PyInt_AsLong(pTupleInt);
583                 /* Reply item tuple */
584                 mod_vptuple(request->reply, request, &request->reply->vps,
585                             PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
586                 /* Config item tuple */
587                 mod_vptuple(request, request, &request->config,
588                             PyTuple_GET_ITEM(pRet, 2), funcname, "config");
589
590         } else if (PyInt_CheckExact(pRet)) {
591                 /* Just an integer */
592                 ret = PyInt_AsLong(pRet);
593
594         } else if (pRet == Py_None) {
595                 /* returned 'None', return value defaults to "OK, continue." */
596                 ret = RLM_MODULE_OK;
597         } else {
598                 /* Not tuple or None */
599                 ERROR("rlm_python:%s: function did not return a tuple or None", funcname);
600                 ret = RLM_MODULE_FAIL;
601                 goto finish;
602         }
603
604 finish:
605         Py_XDECREF(pArgs);
606         Py_XDECREF(pRet);
607
608 #ifdef HAVE_PTHREAD_H
609         if (worker) {
610                 PyThreadState_Swap(prev_thread_state);
611         }
612         PyGILState_Release(gstate);
613 #endif
614
615         return ret;
616 }
617
618 /*
619  *      Import a user module and load a function from it
620  */
621
622 static int mod_load_function(struct py_function_def *def)
623 {
624         char const *funcname = "mod_load_function";
625         PyGILState_STATE gstate;
626
627         gstate = PyGILState_Ensure();
628
629         if (def->module_name != NULL && def->function_name != NULL) {
630                 if ((def->module = PyImport_ImportModule(def->module_name)) == NULL) {
631                         ERROR("rlm_python:%s: module '%s' is not found", funcname, def->module_name);
632                         goto failed;
633                 }
634
635                 if ((def->function = PyObject_GetAttrString(def->module, def->function_name)) == NULL) {
636                         ERROR("rlm_python:%s: function '%s.%s' is not found", funcname, def->module_name, def->function_name);
637                         goto failed;
638                 }
639
640                 if (!PyCallable_Check(def->function)) {
641                         ERROR("rlm_python:%s: function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
642                         goto failed;
643                 }
644         }
645         PyGILState_Release(gstate);
646         return 0;
647
648 failed:
649         mod_error();
650         ERROR("rlm_python:%s: failed to import python function '%s.%s'", funcname, def->module_name, def->function_name);
651         Py_XDECREF(def->function);
652         def->function = NULL;
653         Py_XDECREF(def->module);
654         def->module = NULL;
655         PyGILState_Release(gstate);
656         return -1;
657 }
658
659
660 static void mod_objclear(PyObject **ob)
661 {
662         if (*ob != NULL) {
663                 Pyx_BLOCK_THREADS
664                 Py_DECREF(*ob);
665                 Pyx_UNBLOCK_THREADS
666                 *ob = NULL;
667         }
668 }
669
670 static void mod_funcdef_clear(struct py_function_def *def)
671 {
672         mod_objclear(&def->function);
673         mod_objclear(&def->module);
674 }
675
676 static void mod_instance_clear(rlm_python_t *inst)
677 {
678 #define A(x) mod_funcdef_clear(&inst->x)
679
680         A(instantiate);
681         A(authorize);
682         A(authenticate);
683         A(preacct);
684         A(accounting);
685         A(checksimul);
686         A(detach);
687
688 #undef A
689 }
690
691 /*
692  *      Do any per-module initialization that is separate to each
693  *      configured instance of the module.  e.g. set up connections
694  *      to external databases, read configuration files, set up
695  *      dictionary entries, etc.
696  *
697  *      If configuration information is given in the config section
698  *      that must be referenced in later calls, store a handle to it
699  *      in *instance otherwise put a null pointer there.
700  *
701  */
702 static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
703 {
704         rlm_python_t *inst = instance;
705
706         if (mod_init(inst) != 0) {
707                 return -1;
708         }
709
710 #define A(x) if (mod_load_function(&inst->x) < 0) goto failed
711
712         A(instantiate);
713         A(authenticate);
714         A(authorize);
715         A(preacct);
716         A(accounting);
717         A(checksimul);
718         A(pre_proxy);
719         A(post_proxy);
720         A(post_auth);
721 #ifdef WITH_COA
722         A(recv_coa);
723         A(send_coa);
724 #endif
725         A(detach);
726
727 #undef A
728
729         /*
730          *      Call the instantiate function.  No request.  Use the
731          *      return value.
732          */
733         return do_python(inst, NULL, inst->instantiate.function, "instantiate", false);
734 failed:
735         Pyx_BLOCK_THREADS
736         mod_error();
737         Pyx_UNBLOCK_THREADS
738         mod_instance_clear(inst);
739         return -1;
740 }
741
742 static int mod_detach(void *instance)
743 {
744         rlm_python_t *inst = instance;
745         int          ret;
746
747         /*
748          *      Master should still have no thread state
749          */
750         ret = do_python(inst, NULL, inst->detach.function, "detach", false);
751
752         mod_instance_clear(inst);
753         dlclose(inst->libpython);
754
755         return ret;
756 }
757
758 #define A(x) static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
759                 return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x, true);\
760         }
761
762 A(authenticate)
763 A(authorize)
764 A(preacct)
765 A(accounting)
766 A(checksimul)
767 A(pre_proxy)
768 A(post_proxy)
769 A(post_auth)
770 #ifdef WITH_COA
771 A(recv_coa)
772 A(send_coa)
773 #endif
774
775 #undef A
776
777 /*
778  *      The module name should be the only globally exported symbol.
779  *      That is, everything else should be 'static'.
780  *
781  *      If the module needs to temporarily modify it's instantiation
782  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
783  *      The server will then take care of ensuring that the module
784  *      is single-threaded.
785  */
786 extern module_t rlm_python;
787 module_t rlm_python = {
788         .magic          = RLM_MODULE_INIT,
789         .name           = "python",
790         .type           = RLM_TYPE_THREAD_SAFE,
791         .inst_size      = sizeof(rlm_python_t),
792         .config         = module_config,
793         .instantiate    = mod_instantiate,
794         .detach         = mod_detach,
795         .methods = {
796                 [MOD_AUTHENTICATE]      = mod_authenticate,
797                 [MOD_AUTHORIZE]         = mod_authorize,
798                 [MOD_PREACCT]           = mod_preacct,
799                 [MOD_ACCOUNTING]        = mod_accounting,
800                 [MOD_SESSION]           = mod_checksimul,
801                 [MOD_PRE_PROXY]         = mod_pre_proxy,
802                 [MOD_POST_PROXY]        = mod_post_proxy,
803                 [MOD_POST_AUTH]         = mod_post_auth,
804 #ifdef WITH_COA
805                 [MOD_RECV_COA]          = mod_recv_coa,
806                 [MOD_SEND_COA]          = mod_send_coa
807 #endif
808         }
809 };