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.
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.
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
19 * Copyright 2000 The FreeRADIUS server project
20 * Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
21 * Copyright 2002 Imperium Technology, Inc.
27 #include "libradius.h"
36 static const char rcsid[] = "$Id$";
39 * Define a structure for our module configuration.
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.
45 typedef struct rlm_python_t {
48 /* Names of modules */
58 /* Names of functions */
68 /* End Config section */
71 /* Python objects for modules */
76 *pModule_authenticate,
96 * A mapping of configuration file names to internal variables.
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
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},
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},
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},
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},
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},
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},
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},
141 { NULL, -1, 0, NULL, NULL } /* end the list */
145 * radiusd Python functions
149 static PyObject *radlog_py(const PyObject *self, PyObject *args) {
153 if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
161 static PyMethodDef radiusd_methods[] = {
162 {"radlog", (PyCFunction)radlog_py, METH_VARARGS, "freeradius radlog()."},
163 {NULL, NULL, 0, NULL}
167 * Do any per-module initialization. e.g. set up connections
168 * to external databases, read configuration files, set up
169 * dictionary entries, etc.
171 * Try to avoid putting too much stuff in here - it's better to
172 * do it in instantiate() where it is not global.
174 static int python_init(void)
177 * Initialize Python interpreter. Fatal error if this fails.
181 radlog(L_DBG, "python_init done");
186 /* Extract string representation of Python error. */
187 static void python_error(void) {
188 PyObject *pType, *pValue, *pTraceback, *pStr1, *pStr2;
190 PyErr_Fetch(&pType, &pValue, &pTraceback);
191 pStr1 = PyObject_Str(pType);
192 pStr2 = PyObject_Str(pValue);
194 radlog(L_ERR, "%s: %s\n",
195 PyString_AsString(pStr1), PyString_AsString(pStr2));
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;
204 /* If the Python function gave us None for the tuple, then just return. */
205 if (pValue == Py_None) {
209 if (!PyTuple_Check(pValue)) {
210 radlog(L_ERR, "%s: non-tuple passed", function_name);
213 /* Get the tuple size. */
214 outertuplesize = PyTuple_Size(pValue);
216 for (i = 0; i < outertuplesize; i++) {
217 PyObject *pTupleElement = PyTuple_GetItem(pValue, i);
219 if ((pTupleElement != NULL) &&
220 (PyTuple_Check(pTupleElement))) {
222 /* Check if it's a pair */
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,
231 PyObject *pString1, *pString2;
233 pString1 = PyTuple_GetItem(pTupleElement, 0);
234 pString2 = PyTuple_GetItem(pTupleElement, 1);
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)) {
245 /* pairmake() will convert and find any
246 * errors in the pair.
249 s1 = PyString_AsString(pString1);
250 s2 = PyString_AsString(pString2);
252 if ((s1 != NULL) && (s2 != NULL)) {
253 radlog(L_DBG, "%s: %s = %s ",
254 function_name, s1, s2);
256 /* xxx Might need to support other T_OP */
257 vp = pairmake(s1, s2, T_OP_EQ);
260 radlog(L_DBG, "%s: s1, s2 OK\n",
264 radlog(L_DBG, "%s: s1, s2 FAILED\n",
269 radlog(L_ERR, "%s: string conv failed\n",
275 radlog(L_ERR, "%s: tuple element %d must be "
276 "(string, string)", function_name, i);
281 radlog(L_ERR, "%s: tuple element %d is not a tuple\n",
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?
293 static int python_function(REQUEST *request,
294 PyObject *pFunc, const char *function_name)
296 #define BUF_SIZE 1024
298 char buf[BUF_SIZE]; /* same size as vp_print buffer */
302 PyObject *pValue, *pValuePairContainer, **pValueHolder, **pValueHolderPtr;
303 int i, n_tuple, return_value;
305 /* Return with "OK, continue" if the function is not defined. */
307 return RLM_MODULE_OK;
310 /* Default return value is "OK, continue" */
311 return_value = RLM_MODULE_OK;
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.
317 * Determine the size of our tuple by walking through the packet.
318 * If request is NULL, pass None.
322 if (request != NULL) {
323 for (vp = request->packet->vps; vp; vp = vp->next) {
328 /* Create the tuple and a holder for the pointers, so that we can
329 * decref more efficiently later without the overhead of reading
332 * We use malloc() instead of the Python memory allocator since we
336 if (NULL == (pValueHolder = pValueHolderPtr =
337 malloc(sizeof(PyObject *) * n_tuple))) {
339 radlog(L_ERR, "%s: malloc of %d bytes failed\n",
340 function_name, sizeof(PyObject *) * n_tuple);
346 pValuePairContainer = Py_None;
349 pValuePairContainer = PyTuple_New(n_tuple);
352 for (vp = request->packet->vps; vp; vp = vp->next) {
353 PyObject *pValuePair, *pString1, *pString2;
355 /* The inside tuple has two only: */
356 pValuePair = PyTuple_New(2);
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);
363 strcpy(buf, vp->name);
366 pString1 = PyString_FromString(buf);
367 PyTuple_SetItem(pValuePair, 0, pString1);
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);
375 /* Put the tuple inside the container */
376 PyTuple_SetItem(pValuePairContainer, i++, pValuePair);
378 /* Store the pointer in our malloc() storage */
379 *pValueHolderPtr++ = pValuePair;
384 /* Call Python function.
387 if (pFunc && PyCallable_Check(pFunc)) {
390 /* call the function with a singleton tuple containing the
394 if ((pArgs = PyTuple_New(1)) == NULL) {
395 radlog(L_ERR, "%s: could not create tuple", function_name);
398 if ((PyTuple_SetItem(pArgs, 0, pValuePairContainer)) != 0) {
399 radlog(L_ERR, "%s: could not set tuple item", function_name);
403 if ((pValue = PyObject_CallObject(pFunc, pArgs)) == NULL) {
404 radlog(L_ERR, "%s: function call failed", function_name);
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))
415 * 2. the function return value alone
417 * 3. None - default return value is set
419 * xxx This code is messy!
422 if (PyTuple_Check(pValue)) {
425 if (PyTuple_Size(pValue) != 3) {
426 radlog(L_ERR, "%s: tuple must be " \
427 "(return, replyTuple, configTuple)",
432 pTupleInt = PyTuple_GetItem(pValue, 0);
434 if ((pTupleInt == NULL) || !PyInt_Check(pTupleInt)) {
435 radlog(L_ERR, "%s: first tuple element not an integer",
439 /* Now have the return value */
440 return_value = PyInt_AsLong(pTupleInt);
442 /* Reply item tuple */
443 add_vp_tuple(&request->reply->vps,
444 PyTuple_GetItem(pValue, 1), function_name);
446 /* Config item tuple */
447 add_vp_tuple(&request->config_items,
448 PyTuple_GetItem(pValue, 2), function_name);
452 else if (PyInt_Check(pValue)) {
453 /* Just an integer */
454 return_value = PyInt_AsLong(pValue);
456 else if (pValue == Py_None) {
457 /* returned 'None', return value defaults to "OK, continue." */
458 return_value = RLM_MODULE_OK;
461 /* Not tuple or None */
462 radlog(L_ERR, "%s function did not return a tuple or None\n",
467 /* Decrease reference counts for the argument and return tuple */
472 /* Decrease reference count for the tuples passed, the
473 * container tuple, and the return value.
476 pValueHolderPtr = pValueHolder;
479 /* Can't write as pValueHolderPtr since Py_DECREF is a macro */
480 Py_DECREF(*pValueHolderPtr);
484 Py_DECREF(pValuePairContainer);
486 /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */
488 /* Free pairs if we are rejecting.
489 * xxx Shouldn't the core do that?
492 if ((return_value == RLM_MODULE_REJECT) && (request != NULL)) {
493 pairfree(&(request->reply->vps));
496 /* Return the specified by the Python module */
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.
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.
512 static int python_instantiate(CONF_SECTION *conf, void **instance)
515 PyObject *pName, *module;
518 * Set up a storage area for instance data
520 data = rad_malloc(sizeof(*data));
523 * If the configuration parameters can't be parsed, then
526 if (cf_section_parse(conf, data, module_config) < 0) {
535 * Setup our 'radiusd' module.
539 if ((module = data->pModule_builtin =
540 Py_InitModule3("radiusd", radiusd_methods,
541 "FreeRADIUS Module.")) == NULL) {
543 radlog(L_ERR, "Python Py_InitModule3 failed");
548 * xxx Find a way to automatically update this when C source changes.
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)) {
577 radlog(L_ERR, "Python AddIntConstant failed");
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?
588 if ((data->mod_instantiate == NULL) || (data->func_instantiate == NULL)) {
589 data->pFunc_instantiate = NULL;
592 pName = PyString_FromString(data->mod_instantiate);
593 data->pModule_instantiate = PyImport_Import(pName);
594 if (data->pModule_instantiate != NULL) {
597 pDict = PyModule_GetDict(data->pModule_instantiate);
598 /* pDict: borrowed reference */
600 data->pFunc_instantiate =
601 PyDict_GetItemString(pDict, data->func_instantiate);
602 /* pFunc: Borrowed reference */
608 /* No need to decrement references because we are exiting. */
610 radlog(L_ERR, "Failed to import python module \"%s\"\n",
611 data->mod_instantiate);
616 if ((data->mod_authenticate == NULL) || (data->func_authenticate == NULL)) {
617 data->pFunc_authenticate = NULL;
620 pName = PyString_FromString(data->mod_authenticate);
623 data->pModule_authenticate = PyImport_Import(pName);
624 if (data->pModule_authenticate != NULL) {
627 pDict = PyModule_GetDict(data->pModule_authenticate);
628 /* pDict: borrowed reference */
630 data->pFunc_authenticate =
631 PyDict_GetItemString(pDict, data->func_authenticate);
632 /* pFunc: Borrowed reference */
637 /* No need to decrement references because we are exiting. */
639 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
640 data->mod_authenticate);
646 if ((data->mod_authorize == NULL) || (data->func_authorize == NULL)) {
647 data->pFunc_authorize = NULL;
650 pName = PyString_FromString(data->mod_authorize);
651 data->pModule_authorize = PyImport_Import(pName);
652 if (data->pModule_authorize != NULL) {
655 pDict = PyModule_GetDict(data->pModule_authorize);
656 /* pDict: borrowed reference */
658 data->pFunc_authorize =
659 PyDict_GetItemString(pDict, data->func_authorize);
660 /* pFunc: Borrowed reference */
666 /* No need to decrement references because we are exiting. */
668 radlog(L_ERR, "Failed to import python module \"%s\"\n",
669 data->mod_authorize);
674 if ((data->mod_authenticate == NULL) || (data->func_authenticate == NULL)) {
675 data->pFunc_authenticate = NULL;
678 pName = PyString_FromString(data->mod_authenticate);
681 data->pModule_authenticate = PyImport_Import(pName);
682 if (data->pModule_authenticate != NULL) {
685 pDict = PyModule_GetDict(data->pModule_authenticate);
686 /* pDict: borrowed reference */
688 data->pFunc_authenticate =
689 PyDict_GetItemString(pDict, data->func_authenticate);
690 /* pFunc: Borrowed reference */
695 /* No need to decrement references because we are exiting. */
697 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
698 data->mod_authenticate);
703 if ((data->mod_preacct == NULL) || (data->func_preacct == NULL)) {
704 data->pFunc_preacct = NULL;
707 pName = PyString_FromString(data->mod_preacct);
710 data->pModule_preacct = PyImport_Import(pName);
711 if (data->pModule_preacct != NULL) {
714 pDict = PyModule_GetDict(data->pModule_preacct);
715 /* pDict: borrowed reference */
717 data->pFunc_preacct =
718 PyDict_GetItemString(pDict, data->func_preacct);
719 /* pFunc: Borrowed reference */
724 /* No need to decrement references because we are exiting. */
726 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
733 if ((data->mod_accounting == NULL) || (data->func_accounting == NULL)){
734 data->pFunc_accounting = NULL;
737 pName = PyString_FromString(data->mod_accounting);
740 data->pModule_accounting = PyImport_Import(pName);
741 if (data->pModule_accounting != NULL) {
744 pDict = PyModule_GetDict(data->pModule_accounting);
745 /* pDict: borrowed reference */
747 data->pFunc_accounting =
748 PyDict_GetItemString(pDict, data->func_accounting);
749 /* pFunc: Borrowed reference */
754 /* No need to decrement references because we are exiting. */
756 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
757 data->mod_accounting);
762 if ((data->mod_checksimul == NULL) || (data->func_checksimul == NULL)){
763 data->pFunc_checksimul = NULL;
766 pName = PyString_FromString(data->mod_checksimul);
769 data->pModule_checksimul = PyImport_Import(pName);
770 if (data->pModule_checksimul != NULL) {
773 pDict = PyModule_GetDict(data->pModule_checksimul);
774 /* pDict: borrowed reference */
776 data->pFunc_checksimul =
777 PyDict_GetItemString(pDict, data->func_checksimul);
778 /* pFunc: Borrowed reference */
783 /* No need to decrement references because we are exiting. */
785 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
786 data->mod_checksimul);
792 if ((data->mod_detach == NULL) || (data->func_detach == NULL)) {
793 data->func_detach = NULL;
796 pName = PyString_FromString(data->mod_detach);
799 data->pModule_detach = PyImport_Import(pName);
800 if (data->pModule_detach != NULL) {
803 pDict = PyModule_GetDict(data->pModule_detach);
804 /* pDict: borrowed reference */
807 PyDict_GetItemString(pDict, data->func_detach);
808 /* pFunc: Borrowed reference */
813 /* No need to decrement references because we are exiting. */
815 radlog(L_ERR, "Failed to import Python module \"%s\"\n",
822 /* Call the instantiate function. No request. Use the return value. */
823 return python_function(NULL, data->pFunc_instantiate, "instantiate");
826 /* Wrapper functions */
827 static int python_authorize(void *instance, REQUEST *request)
829 return python_function(request,
830 ((struct rlm_python_t *)instance)->pFunc_authorize,
834 static int python_authenticate(void *instance, REQUEST *request)
836 return python_function(
838 ((struct rlm_python_t *)instance)->pFunc_authenticate,
842 static int python_preacct(void *instance, REQUEST *request)
844 return python_function(
846 ((struct rlm_python_t *)instance)->pFunc_preacct,
850 static int python_accounting(void *instance, REQUEST *request)
852 return python_function(
854 ((struct rlm_python_t *)instance)->pFunc_accounting,
858 static int python_checksimul(void *instance, REQUEST *request)
860 return python_function(
862 ((struct rlm_python_t *)instance)->pFunc_checksimul,
867 static int python_detach(void *instance)
871 /* Default return value is failure */
874 if (((rlm_python_t *)instance)->pFunc_detach &&
875 PyCallable_Check(((rlm_python_t *)instance)->pFunc_detach)) {
877 PyObject *pArgs, *pValue;
879 /* call the function with an empty tuple */
881 pArgs = PyTuple_New(0);
882 pValue = PyObject_CallObject(((rlm_python_t *)instance)->pFunc_detach,
885 if (pValue == NULL) {
890 if (!PyInt_Check(pValue)) {
891 radlog(L_ERR, "detach: return value not an integer");
894 return_value = PyInt_AsLong(pValue);
898 /* Decrease reference counts for the argument and return tuple */
906 /* xxx test delete module object so it will be reloaded later.
907 * xxx useless since we can't SIGHUP reliably, anyway.
909 PyObject_Del(((struct rlm_python_t *)instance)->pModule_accounting);
912 radlog(L_DBG, "python_detach done");
914 /* Return the specified by the Python module */
919 * The module name should be the only globally exported symbol.
920 * That is, everything else should be 'static'.
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.
927 module_t rlm_python = {
929 RLM_TYPE_THREAD_SAFE, /* type */
930 python_init, /* initialization */
931 python_instantiate, /* instantiation */
933 python_authenticate, /* authentication */
934 python_authorize, /* authorization */
935 python_preacct, /* preaccounting */
936 python_accounting, /* accounting */
937 python_checksimul /* checksimul */
939 python_detach, /* detach */