af64a77fb2da5b24f25ee296091678200594e79a
[freeradius.git] / src / modules / rlm_python / rlm_python.c
1 /*
2  * rlm_python.c 
3  *
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Copyright 2000  The FreeRADIUS server project
20  * Copyright 2002  Miguel A.L. Paraz <mparaz@mparaz.com>
21  * Copyright 2002  Imperium Technology, Inc.
22  */
23
24 #include <Python.h>
25
26 #include "autoconf.h"
27 #include "libradius.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "radiusd.h"
33 #include "modules.h"
34 #include "conffile.h"
35
36 static const char rcsid[] = "$Id$";
37
38 /*
39  *      Define a structure for our module configuration.
40  *
41  *      These variables do not need to be in a structure, but it's
42  *      a lot cleaner to do so, and a pointer to the structure can
43  *      be used as the instance handle.
44  */
45 typedef struct rlm_python_t {
46     /* Config section */
47
48     /* Names of modules */
49     char
50         *mod_instantiate,
51         *mod_authorize, 
52         *mod_authenticate,
53         *mod_preacct,
54         *mod_accounting,
55         *mod_checksimul,
56         *mod_detach,
57
58     /* Names of functions */
59         *func_instantiate,
60         *func_authorize, 
61         *func_authenticate,
62         *func_preacct,
63         *func_accounting,
64         *func_checksimul,
65         *func_detach;
66
67
68     /* End Config section */
69
70
71     /* Python objects for modules */
72     PyObject
73         *pModule_builtin,
74         *pModule_instantiate,
75         *pModule_authorize,
76         *pModule_authenticate,
77         *pModule_preacct,
78         *pModule_accounting,
79         *pModule_checksimul,
80         *pModule_detach,
81
82
83         /* Functions */
84
85         *pFunc_instantiate,
86         *pFunc_authorize,
87         *pFunc_authenticate,
88         *pFunc_preacct,
89         *pFunc_accounting,
90         *pFunc_checksimul,
91         *pFunc_detach;
92
93 } rlm_python_t;
94
95 /*
96  *      A mapping of configuration file names to internal variables.
97  *
98  *      Note that the string is dynamically allocated, so it MUST
99  *      be freed.  When the configuration file parse re-reads the string,
100  *      it free's the old one, and strdup's the new one, placing the pointer
101  *      to the strdup'd string into 'config.string'.  This gets around
102  *      buffer over-flows.
103  */
104 static CONF_PARSER module_config[] = {
105   { "mod_instantiate",  PW_TYPE_STRING_PTR,
106     offsetof(rlm_python_t, mod_instantiate), NULL,  NULL},
107   { "func_instantiate",  PW_TYPE_STRING_PTR,
108     offsetof(rlm_python_t, func_instantiate), NULL,  NULL},
109
110   { "mod_authorize",  PW_TYPE_STRING_PTR,
111     offsetof(rlm_python_t, mod_authorize), NULL,  NULL},
112   { "func_authorize",  PW_TYPE_STRING_PTR,
113     offsetof(rlm_python_t, func_authorize), NULL,  NULL},
114
115   { "mod_authenticate",  PW_TYPE_STRING_PTR,
116     offsetof(rlm_python_t, mod_authenticate), NULL,  NULL},
117   { "func_authenticate",  PW_TYPE_STRING_PTR,
118     offsetof(rlm_python_t, func_authenticate), NULL,  NULL},
119
120   { "mod_preacct",  PW_TYPE_STRING_PTR,
121     offsetof(rlm_python_t, mod_preacct), NULL,  NULL},
122   { "func_preacct",  PW_TYPE_STRING_PTR,
123     offsetof(rlm_python_t, func_preacct), NULL,  NULL},
124
125   { "mod_accounting",  PW_TYPE_STRING_PTR,
126     offsetof(rlm_python_t, mod_accounting), NULL,  NULL},
127   { "func_accounting",  PW_TYPE_STRING_PTR,
128     offsetof(rlm_python_t, func_accounting), NULL,  NULL},
129
130   { "mod_checksimul",  PW_TYPE_STRING_PTR,
131     offsetof(rlm_python_t, mod_checksimul), NULL,  NULL},
132   { "func_checksimul",  PW_TYPE_STRING_PTR,
133     offsetof(rlm_python_t, func_checksimul), NULL,  NULL},
134
135   { "mod_detach",  PW_TYPE_STRING_PTR,
136     offsetof(rlm_python_t, mod_detach), NULL,  NULL},
137   { "func_detach",  PW_TYPE_STRING_PTR,
138     offsetof(rlm_python_t, func_detach), NULL,  NULL},
139
140
141   { NULL, -1, 0, NULL, NULL }           /* end the list */
142 };
143
144 /*
145  * radiusd Python functions
146  */
147
148 /* radlog wrapper */
149 static PyObject *radlog_py(const PyObject *self, PyObject *args) {
150     int status;
151     char *msg;
152
153     if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
154         return NULL;
155     }
156
157     radlog(status, msg);
158     return Py_None;
159 }
160
161 static PyMethodDef radiusd_methods[] = {
162     {"radlog", (PyCFunction)radlog_py, METH_VARARGS, "freeradius radlog()."},
163     {NULL, NULL, 0, NULL}
164 };
165
166 /*
167  *      Do any per-module initialization.  e.g. set up connections
168  *      to external databases, read configuration files, set up
169  *      dictionary entries, etc.
170  *
171  *      Try to avoid putting too much stuff in here - it's better to
172  *      do it in instantiate() where it is not global.
173  */
174 static int python_init(void)
175 {
176     /*
177      * Initialize Python interpreter. Fatal error if this fails.
178      */
179     Py_Initialize();
180
181     radlog(L_DBG, "python_init done");
182
183     return 0;
184 }
185
186 /* Extract string representation of Python error. */
187 static void python_error(void) {
188     PyObject *pType, *pValue, *pTraceback, *pStr1, *pStr2;
189
190     PyErr_Fetch(&pType, &pValue, &pTraceback);
191     pStr1 = PyObject_Str(pType);
192     pStr2 = PyObject_Str(pValue);
193     
194     radlog(L_ERR, "%s: %s\n",
195            PyString_AsString(pStr1), PyString_AsString(pStr2));
196 }
197
198 /* Tuple to value pair conversion */
199 static void add_vp_tuple(VALUE_PAIR **vpp, PyObject *pValue,
200                          const char *function_name) {
201     int i, outertuplesize;
202     VALUE_PAIR  *vp;
203
204     /* If the Python function gave us None for the tuple, then just return. */
205     if (pValue == Py_None) {
206         return;
207     }
208     
209     if (!PyTuple_Check(pValue)) {
210         radlog(L_ERR, "%s: non-tuple passed", function_name);
211     }
212
213     /* Get the tuple size. */
214     outertuplesize = PyTuple_Size(pValue);
215     
216     for (i = 0; i < outertuplesize; i++) {
217         PyObject *pTupleElement = PyTuple_GetItem(pValue, i);
218                     
219         if ((pTupleElement != NULL) &&
220             (PyTuple_Check(pTupleElement))) {
221
222             /* Check if it's a pair */
223             int tuplesize;
224                         
225             if ((tuplesize = PyTuple_Size(pTupleElement)) != 2) {
226                 radlog(L_ERR, "%s: tuple element %d is a tuple "
227                        " of size %d. must be 2\n", function_name,
228                        i, tuplesize);
229             }
230             else {
231                 PyObject *pString1, *pString2;
232                             
233                 pString1 = PyTuple_GetItem(pTupleElement, 0);
234                 pString2 = PyTuple_GetItem(pTupleElement, 1);
235
236                 /* xxx PyString_Check does not compile here */
237                 if  ((pString1 != NULL) &&
238                      (pString2 != NULL) &&
239                      PyObject_TypeCheck(pString1,&PyString_Type) &&
240                      PyObject_TypeCheck(pString2,&PyString_Type)) {
241
242
243                     const char *s1, *s2;
244                                 
245                     /* pairmake() will convert and find any
246                      * errors in the pair.
247                      */
248
249                     s1 = PyString_AsString(pString1);
250                     s2 = PyString_AsString(pString2);
251
252                     if ((s1 != NULL) && (s2 != NULL)) {
253                         radlog(L_DBG, "%s: %s = %s ",
254                                function_name, s1, s2);
255
256                         /* xxx Might need to support other T_OP */
257                         vp = pairmake(s1, s2, T_OP_EQ);
258                         if (vp != NULL) {
259                             pairadd(vpp, vp);
260                             radlog(L_DBG, "%s: s1, s2 OK\n",
261                                    function_name);
262                         }
263                         else {
264                             radlog(L_DBG, "%s: s1, s2 FAILED\n",
265                                    function_name);
266                         }
267                     }
268                     else {
269                         radlog(L_ERR, "%s: string conv failed\n",
270                                function_name);
271                     }
272
273                 }
274                 else {
275                     radlog(L_ERR, "%s: tuple element %d must be "
276                            "(string, string)", function_name, i);
277                 }
278             }
279         }
280         else {
281             radlog(L_ERR, "%s: tuple element %d is not a tuple\n",
282                    function_name, i);
283         }
284     }
285
286 }
287
288 /* This is the core Python function that the others wrap around.
289  * Pass the value-pair print strings in a tuple.
290  * xxx We're not checking the errors. If we have errors, what do we do?
291  */
292
293 static int python_function(REQUEST *request,
294                            PyObject *pFunc, const char *function_name)
295 {
296 #define BUF_SIZE 1024
297
298     char buf[BUF_SIZE];         /* same size as vp_print buffer */
299
300     VALUE_PAIR  *vp;
301
302     PyObject *pValue, *pValuePairContainer, **pValueHolder, **pValueHolderPtr;
303     int i, n_tuple, return_value;
304     
305     /* Return with "OK, continue" if the function is not defined. */
306     if (pFunc == NULL) {
307         return RLM_MODULE_OK;
308     }
309
310     /* Default return value is "OK, continue" */
311     return_value = RLM_MODULE_OK;
312     
313     /* We will pass a tuple containing (name, value) tuples 
314      * We can safely use the Python function to build up a tuple,
315      * since the tuple is not used elsewhere.
316      *
317      * Determine the size of our tuple by walking through the packet.
318      * If request is NULL, pass None.
319      */
320     n_tuple = 0;
321
322     if (request != NULL) {
323         for (vp = request->packet->vps; vp; vp = vp->next) {
324             n_tuple++;
325         }
326     }
327         
328     /* Create the tuple and a holder for the pointers, so that we can
329      * decref more efficiently later without the overhead of reading
330      * the tuple.
331      *
332      * We use malloc() instead of the Python memory allocator since we
333      * are not embedded.
334      */
335
336     if (NULL == (pValueHolder = pValueHolderPtr =
337                  malloc(sizeof(PyObject *) * n_tuple))) {
338             
339         radlog(L_ERR, "%s: malloc of %d bytes failed\n",
340                function_name, sizeof(PyObject *) * n_tuple);
341             
342         return -1;
343     }
344
345     if (n_tuple == 0) {
346         pValuePairContainer = Py_None;
347     }
348     else {
349         pValuePairContainer = PyTuple_New(n_tuple);
350     
351         i = 0;
352         for (vp = request->packet->vps; vp; vp = vp->next) {
353             PyObject *pValuePair, *pString1, *pString2;
354         
355             /* The inside tuple has two only: */
356             pValuePair = PyTuple_New(2);
357         
358             /* The name. logic from vp_prints, lib/print.c */
359             if (vp->flags.has_tag) {
360                 snprintf(buf, BUF_SIZE, "%s:%d", vp->name, vp->flags.tag);
361             }
362             else {
363                 strcpy(buf, vp->name);
364             }
365         
366             pString1 = PyString_FromString(buf);
367             PyTuple_SetItem(pValuePair, 0, pString1);
368         
369         
370             /* The value. Use delimiter - don't know what that means */
371             vp_prints_value(buf, sizeof(buf), vp, 1);
372             pString2 = PyString_FromString(buf);
373             PyTuple_SetItem(pValuePair, 1, pString2);
374         
375             /* Put the tuple inside the container */
376             PyTuple_SetItem(pValuePairContainer, i++, pValuePair);
377         
378             /* Store the pointer in our malloc() storage */
379             *pValueHolderPtr++ = pValuePair;
380         }
381     }
382
383     
384     /* Call Python function.
385      */
386     
387     if (pFunc && PyCallable_Check(pFunc)) {
388         PyObject *pArgs;
389         
390         /* call the function with a singleton tuple containing the
391          * container tuple.
392          */
393
394         if ((pArgs = PyTuple_New(1)) == NULL) {
395             radlog(L_ERR, "%s: could not create tuple", function_name);
396             return -1;
397         }
398         if ((PyTuple_SetItem(pArgs, 0, pValuePairContainer)) != 0) {
399             radlog(L_ERR, "%s: could not set tuple item", function_name);
400             return -1;
401         }
402         
403         if ((pValue = PyObject_CallObject(pFunc, pArgs)) == NULL) {
404             radlog(L_ERR, "%s: function call failed", function_name);
405             python_error();
406             return -1;
407         }
408         
409         /* The function returns either:
410          *  1. tuple containing the integer return value,
411          *  then the integer reply code (or None to not set),
412          *  then the string tuples to build the reply with.
413          *     (returnvalue, (p1, s1), (p2, s2))
414          *
415          *  2. the function return value alone
416          *
417          *  3. None - default return value is set
418          *
419          * xxx This code is messy!
420          */
421
422         if (PyTuple_Check(pValue)) {
423             PyObject *pTupleInt;
424
425             if (PyTuple_Size(pValue) != 3) {
426                 radlog(L_ERR, "%s: tuple must be " \
427                        "(return, replyTuple, configTuple)",
428                        function_name);
429
430             }
431             else {
432                 pTupleInt = PyTuple_GetItem(pValue, 0);
433
434                 if ((pTupleInt == NULL) || !PyInt_Check(pTupleInt)) {
435                     radlog(L_ERR, "%s: first tuple element not an integer",
436                            function_name);
437                 }
438                 else {
439                     /* Now have the return value */
440                     return_value = PyInt_AsLong(pTupleInt);
441                     
442                     /* Reply item tuple */
443                     add_vp_tuple(&request->reply->vps,
444                                  PyTuple_GetItem(pValue, 1), function_name);
445
446                     /* Config item tuple */
447                     add_vp_tuple(&request->config_items,
448                                  PyTuple_GetItem(pValue, 2), function_name);
449                 }
450             }
451         }
452         else if (PyInt_Check(pValue)) {
453             /* Just an integer */
454             return_value = PyInt_AsLong(pValue);
455         }
456         else if (pValue == Py_None) {
457             /* returned 'None', return value defaults to "OK, continue." */
458             return_value = RLM_MODULE_OK;
459         }
460         else {
461             /* Not tuple or None */
462             radlog(L_ERR, "%s function did not return a tuple or None\n",
463                    function_name);
464         }
465
466
467         /* Decrease reference counts for the argument and return tuple */
468         Py_DECREF(pArgs);
469         Py_DECREF(pValue);
470     }
471
472     /* Decrease reference count for the tuples passed, the
473      * container tuple, and the return value.
474      */
475             
476     pValueHolderPtr = pValueHolder;
477     i = n_tuple;
478     while (i--) {
479         /* Can't write as pValueHolderPtr since Py_DECREF is a macro */
480         Py_DECREF(*pValueHolderPtr);
481         pValueHolderPtr++;
482     }
483     free(pValueHolder);
484     Py_DECREF(pValuePairContainer);
485     
486     /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
487
488     /* Free pairs if we are rejecting.
489      * xxx Shouldn't the core do that?
490      */
491     
492     if ((return_value == RLM_MODULE_REJECT) && (request != NULL)) {
493         pairfree(&(request->reply->vps));
494     }
495     
496     /* Return the specified by the Python module */
497     return return_value;
498 }
499
500
501 /*
502  *      Do any per-module initialization that is separate to each
503  *      configured instance of the module.  e.g. set up connections
504  *      to external databases, read configuration files, set up
505  *      dictionary entries, etc.
506  *
507  *      If configuration information is given in the config section
508  *      that must be referenced in later calls, store a handle to it
509  *      in *instance otherwise put a null pointer there.
510  *
511  */
512 static int python_instantiate(CONF_SECTION *conf, void **instance)
513 {
514     rlm_python_t *data;
515     PyObject *pName, *module;
516
517     /*
518          *      Set up a storage area for instance data
519          */
520     data = rad_malloc(sizeof(*data));
521
522     /*
523          *      If the configuration parameters can't be parsed, then
524          *      fail.
525          */
526     if (cf_section_parse(conf, data, module_config) < 0) {
527         free(data);
528         return -1;
529     }
530         
531     *instance = data;
532
533
534     /*
535      * Setup our 'radiusd' module.
536      */
537     
538     /* Code */
539     if ((module = data->pModule_builtin =
540          Py_InitModule3("radiusd", radiusd_methods,
541                         "FreeRADIUS Module.")) == NULL) {
542
543         radlog(L_ERR, "Python Py_InitModule3 failed");
544     }
545     
546     /*
547      * Constants
548      * xxx Find a way to automatically update this when C source changes.
549      */
550     if ((PyModule_AddIntConstant(module, "L_DBG", L_DBG) == -1) ||
551         (PyModule_AddIntConstant(module, "L_AUTH", L_AUTH) == -1) ||
552         (PyModule_AddIntConstant(module, "L_INFO", L_INFO) == -1) ||
553         (PyModule_AddIntConstant(module, "L_ERR", L_ERR) == -1) ||
554         (PyModule_AddIntConstant(module, "L_PROXY", L_PROXY) == -1) ||
555         (PyModule_AddIntConstant(module, "L_CONS", L_CONS) == -1) ||
556         (PyModule_AddIntConstant(module, "RLM_MODULE_REJECT",
557                                  RLM_MODULE_REJECT) == -1) ||
558         (PyModule_AddIntConstant(module, "RLM_MODULE_FAIL",
559                                  RLM_MODULE_FAIL) == -1) ||
560         (PyModule_AddIntConstant(module, "RLM_MODULE_OK",
561                                  RLM_MODULE_OK) == -1) ||
562         (PyModule_AddIntConstant(module, "RLM_MODULE_HANDLED",
563                                  RLM_MODULE_HANDLED) == -1) ||
564         (PyModule_AddIntConstant(module, "RLM_MODULE_INVALID",
565                                  RLM_MODULE_INVALID) == -1) ||
566         (PyModule_AddIntConstant(module, "RLM_MODULE_USERLOCK",
567                                  RLM_MODULE_USERLOCK) == -1) ||
568         (PyModule_AddIntConstant(module, "RLM_MODULE_NOTFOUND",
569                                  RLM_MODULE_NOTFOUND) == -1) ||
570         (PyModule_AddIntConstant(module, "RLM_MODULE_NOOP",
571                                  RLM_MODULE_NOOP) == -1) ||
572         (PyModule_AddIntConstant(module, "RLM_MODULE_UPDATED",
573                                  RLM_MODULE_UPDATED) == -1) ||
574         (PyModule_AddIntConstant(module, "RLM_MODULE_NUMCODES",
575                                  RLM_MODULE_NUMCODES) == -1)) {
576
577         radlog(L_ERR, "Python AddIntConstant failed");
578         return -1;
579     }
580
581
582     /*
583      * Import user modules.
584      * xxx There should be a more elegant way of writing this.
585      * xxx Loop through a pointer array for the objects and name strings?
586      */
587
588     if ((data->mod_instantiate == NULL) || (data->func_instantiate == NULL)) {
589         data->pFunc_instantiate = NULL;
590     }
591     else {
592         pName = PyString_FromString(data->mod_instantiate);     
593         data->pModule_instantiate = PyImport_Import(pName);
594         if (data->pModule_instantiate != NULL) {
595             PyObject *pDict;
596
597             pDict = PyModule_GetDict(data->pModule_instantiate);
598             /* pDict: borrowed reference */
599
600             data->pFunc_instantiate =
601                 PyDict_GetItemString(pDict, data->func_instantiate);
602             /* pFunc: Borrowed reference */
603         }
604
605         else {
606             python_error();
607
608             /* No need to decrement references because we are exiting. */
609
610             radlog(L_ERR, "Failed to import python module \"%s\"\n",
611                    data->mod_instantiate);
612             return -1;
613         }
614     }
615
616     if ((data->mod_authenticate == NULL) || (data->func_authenticate == NULL)) {
617         data->pFunc_authenticate = NULL;
618     }
619     else {
620         pName = PyString_FromString(data->mod_authenticate);
621
622         /* Import modules */
623         data->pModule_authenticate = PyImport_Import(pName);
624         if (data->pModule_authenticate != NULL) {
625             PyObject *pDict;
626
627             pDict = PyModule_GetDict(data->pModule_authenticate);
628             /* pDict: borrowed reference */
629
630             data->pFunc_authenticate =
631                 PyDict_GetItemString(pDict, data->func_authenticate);
632             /* pFunc: Borrowed reference */
633         }
634         else {
635             python_error();
636
637             /* No need to decrement references because we are exiting. */
638
639             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
640                    data->mod_authenticate);
641             return -1;
642         }
643     }
644
645     
646     if ((data->mod_authorize == NULL) || (data->func_authorize == NULL)) {
647         data->pFunc_authorize = NULL;
648     }
649     else {
650         pName = PyString_FromString(data->mod_authorize);       
651         data->pModule_authorize = PyImport_Import(pName);
652         if (data->pModule_authorize != NULL) {
653             PyObject *pDict;
654
655             pDict = PyModule_GetDict(data->pModule_authorize);
656             /* pDict: borrowed reference */
657
658             data->pFunc_authorize =
659                 PyDict_GetItemString(pDict, data->func_authorize);
660             /* pFunc: Borrowed reference */
661         }
662
663         else {
664             python_error();
665
666             /* No need to decrement references because we are exiting. */
667
668             radlog(L_ERR, "Failed to import python module \"%s\"\n",
669                    data->mod_authorize);
670             return -1;
671         }
672     }
673
674     if ((data->mod_authenticate == NULL) || (data->func_authenticate == NULL)) {
675         data->pFunc_authenticate = NULL;
676     }
677     else {
678         pName = PyString_FromString(data->mod_authenticate);
679
680         /* Import modules */
681         data->pModule_authenticate = PyImport_Import(pName);
682         if (data->pModule_authenticate != NULL) {
683             PyObject *pDict;
684
685             pDict = PyModule_GetDict(data->pModule_authenticate);
686             /* pDict: borrowed reference */
687
688             data->pFunc_authenticate =
689                 PyDict_GetItemString(pDict, data->func_authenticate);
690             /* pFunc: Borrowed reference */
691         }
692         else {
693             python_error();
694
695             /* No need to decrement references because we are exiting. */
696
697             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
698                    data->mod_authenticate);
699             return -1;
700         }
701     }
702
703     if ((data->mod_preacct == NULL) || (data->func_preacct == NULL)) {
704         data->pFunc_preacct = NULL;
705     }
706     else {
707         pName = PyString_FromString(data->mod_preacct);
708
709         /* Import modules */
710         data->pModule_preacct = PyImport_Import(pName);
711         if (data->pModule_preacct != NULL) {
712             PyObject *pDict;
713                 
714             pDict = PyModule_GetDict(data->pModule_preacct);
715             /* pDict: borrowed reference */
716                 
717             data->pFunc_preacct =
718                 PyDict_GetItemString(pDict, data->func_preacct);
719             /* pFunc: Borrowed reference */
720         }
721         else {
722             python_error();
723
724             /* No need to decrement references because we are exiting. */
725                 
726             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
727                    data->mod_preacct);
728             return -1;
729         }
730     }
731
732
733     if ((data->mod_accounting == NULL) || (data->func_accounting == NULL)){
734         data->pFunc_accounting = NULL;
735     }
736     else {
737         pName = PyString_FromString(data->mod_accounting);
738
739         /* Import modules */
740         data->pModule_accounting = PyImport_Import(pName);
741         if (data->pModule_accounting != NULL) {
742             PyObject *pDict;
743                 
744             pDict = PyModule_GetDict(data->pModule_accounting);
745             /* pDict: borrowed reference */
746
747             data->pFunc_accounting =
748                 PyDict_GetItemString(pDict, data->func_accounting);
749             /* pFunc: Borrowed reference */
750         }
751         else {
752             python_error();
753
754             /* No need to decrement references because we are exiting. */
755                 
756             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
757                    data->mod_accounting);
758             return -1;
759         }
760     }
761
762     if ((data->mod_checksimul == NULL) || (data->func_checksimul == NULL)){
763         data->pFunc_checksimul = NULL;
764     }
765     else {
766         pName = PyString_FromString(data->mod_checksimul);
767
768         /* Import modules */
769         data->pModule_checksimul = PyImport_Import(pName);
770         if (data->pModule_checksimul != NULL) {
771             PyObject *pDict;
772                 
773             pDict = PyModule_GetDict(data->pModule_checksimul);
774             /* pDict: borrowed reference */
775
776             data->pFunc_checksimul =
777                 PyDict_GetItemString(pDict, data->func_checksimul);
778             /* pFunc: Borrowed reference */
779         }
780         else {
781             python_error();
782                 
783             /* No need to decrement references because we are exiting. */
784                 
785             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
786                    data->mod_checksimul);
787             return -1;
788         }
789     }
790
791
792     if ((data->mod_detach == NULL) || (data->func_detach == NULL)) {
793         data->func_detach = NULL;
794     }
795     else {
796         pName = PyString_FromString(data->mod_detach);
797
798         /* Import modules */
799         data->pModule_detach = PyImport_Import(pName);
800         if (data->pModule_detach != NULL) {
801             PyObject *pDict;
802                 
803             pDict = PyModule_GetDict(data->pModule_detach);
804             /* pDict: borrowed reference */
805
806             data->pFunc_detach =
807                 PyDict_GetItemString(pDict, data->func_detach);
808             /* pFunc: Borrowed reference */
809         }
810         else {
811             python_error();
812                 
813             /* No need to decrement references because we are exiting. */
814                 
815             radlog(L_ERR, "Failed to import Python module \"%s\"\n",
816                    data->mod_detach);
817             return -1;
818         }
819     }
820
821
822     /* Call the instantiate function.  No request.  Use the return value. */
823     return python_function(NULL, data->pFunc_instantiate, "instantiate");
824 }
825
826 /* Wrapper functions */
827 static int python_authorize(void *instance, REQUEST *request)
828 {
829     return python_function(request, 
830                            ((struct rlm_python_t *)instance)->pFunc_authorize,
831                            "authorize");
832 }
833
834 static int python_authenticate(void *instance, REQUEST *request)
835 {
836     return python_function(
837         request, 
838         ((struct rlm_python_t *)instance)->pFunc_authenticate,
839         "authenticate");
840 }
841
842 static int python_preacct(void *instance, REQUEST *request)
843 {
844     return python_function(
845         request, 
846         ((struct rlm_python_t *)instance)->pFunc_preacct,
847         "preacct");
848 }
849
850 static int python_accounting(void *instance, REQUEST *request)
851 {
852     return python_function(
853         request, 
854         ((struct rlm_python_t *)instance)->pFunc_accounting,
855         "accounting");
856 }
857
858 static int python_checksimul(void *instance, REQUEST *request)
859 {
860     return python_function(
861         request, 
862         ((struct rlm_python_t *)instance)->pFunc_checksimul,
863         "checksimul");
864 }
865
866
867 static int python_detach(void *instance)
868 {
869     int return_value;
870     
871     /* Default return value is failure */
872     return_value = -1;
873
874     if (((rlm_python_t *)instance)->pFunc_detach &&
875         PyCallable_Check(((rlm_python_t *)instance)->pFunc_detach)) {
876         
877         PyObject *pArgs, *pValue;
878         
879         /* call the function with an empty tuple */
880
881         pArgs = PyTuple_New(0);
882         pValue = PyObject_CallObject(((rlm_python_t *)instance)->pFunc_detach,
883                                      pArgs);
884         
885         if (pValue == NULL) {
886             python_error();
887             return -1;
888         }
889         else {
890             if (!PyInt_Check(pValue)) {
891                 radlog(L_ERR, "detach: return value not an integer");
892             }
893             else {
894                 return_value = PyInt_AsLong(pValue);
895             }
896         }
897
898         /* Decrease reference counts for the argument and return tuple */
899         Py_DECREF(pArgs);
900         Py_DECREF(pValue);
901     }
902
903     free(instance);
904
905 #if 0
906     /* xxx test delete module object so it will be reloaded later.
907      * xxx useless since we can't SIGHUP reliably, anyway.
908      */
909     PyObject_Del(((struct rlm_python_t *)instance)->pModule_accounting);
910 #endif
911
912     radlog(L_DBG, "python_detach done");
913     
914     /* Return the specified by the Python module */
915     return return_value;
916 }
917
918 /*
919  *      The module name should be the only globally exported symbol.
920  *      That is, everything else should be 'static'.
921  *
922  *      If the module needs to temporarily modify it's instantiation
923  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
924  *      The server will then take care of ensuring that the module
925  *      is single-threaded.
926  */
927 module_t rlm_python = {
928         "python",       
929         RLM_TYPE_THREAD_SAFE,           /* type */
930         python_init,                    /* initialization */
931         python_instantiate,             /* instantiation */
932         {
933                 python_authenticate,    /* authentication */
934                 python_authorize,       /* authorization */
935                 python_preacct,         /* preaccounting */
936                 python_accounting,      /* accounting */
937                 python_checksimul       /* checksimul */
938         },
939         python_detach,                  /* detach */
940         NULL,                           /* destroy */
941 };