diff --git a/raddb/mods-available/python3 b/raddb/mods-available/python3 index 246dfd74ce..0593c69f1a 100644 --- a/raddb/mods-available/python3 +++ b/raddb/mods-available/python3 @@ -13,7 +13,7 @@ python3 { # item is GLOBAL TO THE SERVER. That is, you cannot have two # instances of the python module, each with a different path. # -# python_path="/path/to/python/files:/another_path/to/python_files/" +# python_path="${modconfdir}/${.:name}:/another_path/to/python_files" module = example diff --git a/src/modules/rlm_python3/configure.ac b/src/modules/rlm_python3/configure.ac index a00320fda4..295a2486d2 100644 --- a/src/modules/rlm_python3/configure.ac +++ b/src/modules/rlm_python3/configure.ac @@ -8,128 +8,75 @@ if test x$with_[]modname != xno; then AC_PROG_CC AC_PROG_CPP - dnl extra argument: --with-rlm-python3-bin - PYTHON3_BIN= - AC_ARG_WITH(rlm-python3-bin, - [ --with-rlm-python3-bin=PATH Path to python3 binary []], + dnl extra argument: --with-rlm-python3-config-bin + PYTHON3_CONFIG_BIN= + AC_ARG_WITH(rlm-python3-config-bin, + [ --with-rlm-python3-config-bin=PATH Path to python-config3 binary []], [ case "$withval" in no) - AC_MSG_ERROR(Need rlm-python3-bin) + AC_MSG_ERROR(Need rlm-python3-config-bin) ;; yes) ;; *) - PYTHON3_BIN="$withval" + PYTHON3_CONFIG_BIN="$withval" ;; esac ] ) - if test "x$PYTHON3_BIN" = x; then - AC_CHECK_PROGS(PYTHON3_BIN, [ python3 ], not-found, [${PATH}:/usr/bin:/usr/local/bin]) + if test "x$PYTHON3_CONFIG_BIN" = x; then + AC_CHECK_PROGS(PYTHON3_CONFIG_BIN, [ python3-config ], not-found, [${PATH}:/usr/bin:/usr/local/bin]) fi - if test "x$PYTHON3_BIN" = "xnot-found"; then - fail="python-binary" - fi - - dnl extra argument: --with-rlm-python3-lib-dir - PY_LIB_DIR= - AC_ARG_WITH(rlm-python3-lib-dir, - [ --with-rlm-python3-lib-dir=DIR Directory for Python library files []], - [ case "$withval" in - no) - AC_MSG_ERROR(Need rlm-python3-lib-dir) - ;; - yes) - ;; - *) - PY_LIB_DIR="$withval" - ;; - esac ] - ) - - dnl extra argument: --with-rlm-python3-include-dir - PY_INC_DIR= - AC_ARG_WITH(rlm-python3-include-dir, - [ --with-rlm-python3-include-dir=DIR Directory for Python include files []], - [ case "$withval" in - no) - AC_MSG_ERROR(Need rlm-python3-include-dir) - ;; - yes) - ;; - *) - PY_INC_DIR="$withval" - ;; - esac ] - ) - - if test x$fail = x; then - PY_PREFIX=`${PYTHON3_BIN} -c 'import sys ; print(sys.prefix)'` - AC_MSG_NOTICE([Python sys.prefix \"${PY_PREFIX}\"]) - - PY_EXEC_PREFIX=`${PYTHON3_BIN} -c 'import sys ; print(sys.exec_prefix)'` - AC_MSG_NOTICE([Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"]) - - PY_SYS_VERSION=`${PYTHON3_BIN} -c 'import sys ; print(sys.version[[0:3]])'` - AC_MSG_NOTICE([Python sys.version \"${PY_SYS_VERSION}\"]) - - if test "x$PY_LIB_DIR" = "x"; then - PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config" - PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config" - fi - - PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config/Makefile" - if test -f ${PY_MAKEFILE}; then - PY_LOCAL_MOD_LIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'` - AC_MSG_NOTICE([Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"]) - - PY_BASE_MOD_LIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'` - AC_MSG_NOTICE([Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"]) - - PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/ / /g;s/^ *//;s/ *$//'` - PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/ / /g;s/^ *//;s/ *$//'` - AC_MSG_NOTICE([Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"]) - fi - PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASE_MOD_LIBS $PY_OTHER_LIBS" + if test "x$PYTHON3_CONFIG_BIN" = xnot-found; then + fail="$fail python3-config" + else + dnl # + dnl # It is necessary due to a weird behavior with 'python3-config' + dnl # + old_CFLAGS="$CFLAGS" + unset CFLAGS + + python3_cflags=`${PYTHON3_CONFIG_BIN} --cflags` + AC_MSG_NOTICE([${PYTHON3_CONFIG_BIN}'s cflags were \"${python3_cflags}\"]) + + dnl # Convert -I to -isystem to get rid of warnings about issues in Python headers + dnl # Strip -systemroot + dnl # Strip optimisation flags (-O[0-9]?). We decide our optimisation level, not python. + dnl # -D_FORTIFY_SOURCE needs -O. + dnl # Strip debug symbol flags (-g[0-9]?). We decide on debugging symbols, not python + dnl # Strip -W*, we decide what warnings are important + dnl # Strip -DNDEBUG + mod_cflags=`echo $python3_cflags | sed -e '\ + s/-I/-isystem/g;\ + s/-isysroot[[ =]]\{0,1\}[[^-]]*//g;\ + s/-O[[^[[:blank:]]]]*//g;\ + s/-Wp,-D_FORTIFY_SOURCE=[[[:digit:]]]//g;\ + s/-g[[^ ]]*//g;\ + s/-W[[^ ]]*//g;\ + s/-DNDEBUG[[[:blank:]]]*//g; + '` + AC_MSG_NOTICE([Sanitized cflags were \"${mod_cflags}\"]) + + python3_ldflags=`${PYTHON3_CONFIG_BIN} --ldflags` + AC_MSG_NOTICE([${PYTHON3_CONFIG_BIN}'s ldflags were \"$python3_ldflags}\"]) + + dnl # Strip -Wl,-O1... Is -O even a valid linker flag?? + dnl # Strip -Wl,-Bsymbolic-functions as thats not always supported or required + dnl # Strip -Xlinker -export-dynamic as it causes weird linking issues on Linux + dnl # See: https://bugs.python.org/issue36508 + mod_ldflags=`echo $python3_ldflags | sed -e '\ + s/-Wl,-O[[[:digit:]]][[[:blank:]]]*//g;\ + s/-Wl,-Bsymbolic-functions[[[:blank:]]]*//g;\ + s/-Xlinker -export-dynamic//g;\ + s/-Wl,-stack_size,[[[:digit:]]]*[[[:blank:]]]//g; + '` + AC_MSG_NOTICE([Sanitized ldflags were \"${mod_ldflags}\"]) - old_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS $PY_CFLAGS" - smart_try_dir="$PY_PREFIX/include/python$PY_SYS_VERSION" - FR_SMART_CHECK_INCLUDE(Python.h) CFLAGS=$old_CFLAGS - if test "x$ac_cv_header_Python_h" = "xyes"; then - mod_cflags="$SMART_CPPFLAGS" - else - fail="$fail Python.h" - targetname= - fi - - old_LIBS=$LIBS - LIBS="$LIBS $PY_LIB_LOC $PY_EXTRA_LIBS -lm" - smart_try_dir=$PY_LIB_DIR - FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}, Py_Initialize) - LIBS=$old_LIBS - - eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}} - if test "x$t" = "xyes"; then - mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm" - targetname=modname - else - FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}m, Py_Initialize) - eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}} - if test "x$t" = "xyes"; then - mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm" - targetname=modname - else - targetname= - fail="$fail libpython$PY_SYS_VERSION" - fi - fi + targetname="rlm_python3" fi - - AC_CHECK_FUNCS([dl_iterate_phdr]) else targetname= echo \*\*\* module modname is disabled. diff --git a/src/modules/rlm_python3/rlm_python3.c b/src/modules/rlm_python3/rlm_python3.c index 06187e4ffa..8e893a0eaa 100644 --- a/src/modules/rlm_python3/rlm_python3.c +++ b/src/modules/rlm_python3/rlm_python3.c @@ -67,8 +67,10 @@ static CONF_PARSER module_config[] = { A(preacct) A(accounting) A(checksimul) +#ifdef WITH_PROXY A(pre_proxy) A(post_proxy) +#endif A(post_auth) #ifdef WITH_COA A(recv_coa) @@ -98,7 +100,9 @@ static struct { A(L_AUTH) A(L_INFO) A(L_ERR) +#ifdef WITH_PROXY A(L_PROXY) +#endif A(L_ACCT) A(L_DBG_WARN) A(L_DBG_ERR) @@ -510,6 +514,7 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons goto finish; } +#ifdef WITH_PROXY /* fill proxy vps */ if (request->proxy) { if (!mod_populate_vps(pArgs, 4, request->proxy->vps)) { @@ -517,10 +522,13 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons ret = RLM_MODULE_FAIL; goto finish; } - } else { + } else +#endif + { mod_populate_vps(pArgs, 4, NULL); } +#ifdef WITH_PROXY /* fill proxy_reply vps */ if (request->proxy_reply) { if (!mod_populate_vps(pArgs, 5, request->proxy_reply->vps)) { @@ -528,7 +536,9 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons ret = RLM_MODULE_FAIL; goto finish; } - } else { + } else +#endif + { mod_populate_vps(pArgs, 5, NULL); } @@ -550,9 +560,14 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons PyDict_SetItemString(pDictInput, "request", PyTuple_GET_ITEM(pArgs, 0)) || PyDict_SetItemString(pDictInput, "reply", PyTuple_GET_ITEM(pArgs, 1)) || PyDict_SetItemString(pDictInput, "config", PyTuple_GET_ITEM(pArgs, 2)) || - PyDict_SetItemString(pDictInput, "session-state", PyTuple_GET_ITEM(pArgs, 3)) || + PyDict_SetItemString(pDictInput, "session-state", PyTuple_GET_ITEM(pArgs, 3)) +#ifdef WITH_PROXY + || PyDict_SetItemString(pDictInput, "proxy-request", PyTuple_GET_ITEM(pArgs, 4)) || - PyDict_SetItemString(pDictInput, "proxy-reply", PyTuple_GET_ITEM(pArgs, 5))) { + PyDict_SetItemString(pDictInput, "proxy-reply", PyTuple_GET_ITEM(pArgs, 5)) +#endif + ) { + ERROR("%s:%d, %s - PyDict_SetItemString failed", __func__, __LINE__, funcname); ret = RLM_MODULE_FAIL; goto finish; @@ -819,8 +834,10 @@ MOD_FUNC(authorize) MOD_FUNC(preacct) MOD_FUNC(accounting) MOD_FUNC(checksimul) +#ifdef WITH_PROXY MOD_FUNC(pre_proxy) MOD_FUNC(post_proxy) +#endif MOD_FUNC(post_auth) #ifdef WITH_COA MOD_FUNC(recv_coa) @@ -1102,7 +1119,7 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) python_dlhandle = dlopen_libpython(RTLD_NOW | RTLD_GLOBAL); if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table"); -#if PY_VERSION_HEX > 0x03050000 +#if PY_VERSION_HEX >= 0x03050000 { wchar_t *name; @@ -1110,13 +1127,6 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) Py_SetProgramName(name); /* The value of argv[0] as a wide char string */ PyMem_RawFree(name); } -#elif PY_VERSION_HEX > 0x0300000 - { - wchar_t *name; - - MEM(name = _Py_char2wchar(main_config.name, NULL)); - Py_SetProgramName(inst->wide_name); /* The value of argv[0] as a wide char string */ - } #else { char *name; @@ -1163,37 +1173,34 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) * the lifetime of the module. */ if (inst->python_path) { + char *p, *path; + PyObject *sys = PyImport_ImportModule("sys"); + PyObject *sys_path = PyObject_GetAttrString(sys, "path"); + + memcpy(&p, &inst->python_path, sizeof(path)); + + for (path = strtok(p, ":"); path != NULL; path = strtok(NULL, ":")) { #if PY_VERSION_HEX > 0x03050000 - { - wchar_t *path; - PyObject* sys = PyImport_ImportModule("sys"); - PyObject* sys_path = PyObject_GetAttrString(sys,"path"); - - MEM(path = Py_DecodeLocale(inst->python_path, NULL)); - PyList_Append(sys_path, PyUnicode_FromWideChar(path,-1)); - PyObject_SetAttrString(sys,"path",sys_path); - PyMem_RawFree(path); - } + wchar_t *py_path; + + MEM(py_path = Py_DecodeLocale(path, NULL)); + PyList_Append(sys_path, PyUnicode_FromWideChar(py_path, -1)); + PyMem_RawFree(py_path); #elif PY_VERSION_HEX > 0x03000000 - { - wchar_t *path; - PyObject* sys = PyImport_ImportModule("sys"); - PyObject* sys_path = PyObject_GetAttrString(sys,"path"); - - MEM(path = _Py_char2wchar(inst->python_path, NULL)); - PyList_Append(sys_path, PyUnicode_FromWideChar(path,-1)); - PyObject_SetAttrString(sys,"path",sys_path); - } -#else - { - char *path; + wchar_t *py_path; - memcpy(&path, &inst->python_path, sizeof(path)); - Py_SetPath(path); - } + MEM(py_path = _Py_char2wchar(path, NULL)); + PyList_Append(sys_path, PyUnicode_FromWideChar(py_path, -1)); + PyMem_RawFree(py_path); +#else + PyList_Append(sys_path, PyLong_FromString(path)); #endif - } + } + PyObject_SetAttrString(sys, "path", sys_path); + Py_DecRef(sys); + Py_DecRef(sys_path); + } } else { inst->module = main_module; Py_IncRef(inst->module); @@ -1220,7 +1227,7 @@ static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf) static int mod_instantiate(CONF_SECTION *conf, void *instance) { rlm_python_t *inst = instance; - int code = 0; + int code = RLM_MODULE_OK; inst->name = cf_section_name2(conf); if (!inst->name) inst->name = cf_section_name1(conf); @@ -1245,8 +1252,10 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) PYTHON_FUNC_LOAD(preacct); PYTHON_FUNC_LOAD(accounting); PYTHON_FUNC_LOAD(checksimul); +#ifdef WITH_PROXY PYTHON_FUNC_LOAD(pre_proxy); PYTHON_FUNC_LOAD(post_proxy); +#endif PYTHON_FUNC_LOAD(post_auth); #ifdef WITH_COA PYTHON_FUNC_LOAD(recv_coa); @@ -1257,12 +1266,14 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * Call the instantiate function. */ - code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict); - if (code < 0) { - error: - python_error_log(); /* Needs valid thread with GIL */ - PyEval_SaveThread(); - return -1; + if (inst->instantiate.function) { + code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict); + if (code < 0) { + error: + python_error_log(); /* Needs valid thread with GIL */ + PyEval_SaveThread(); + return -1; + } } PyEval_SaveThread(); @@ -1272,22 +1283,31 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) static int mod_detach(void *instance) { rlm_python_t *inst = instance; - int ret; + int ret = RLM_MODULE_OK; /* * Call module destructor */ PyEval_RestoreThread(inst->sub_interpreter); - ret = do_python_single(NULL, inst->detach.function, "detach", inst->pass_all_vps, inst->pass_all_vps_dict); + if (inst->detach.function) ret = do_python_single(NULL, inst->detach.function, "detach", inst->pass_all_vps, inst->pass_all_vps_dict); #define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x) PYTHON_FUNC_DESTROY(instantiate); - PYTHON_FUNC_DESTROY(authorize); PYTHON_FUNC_DESTROY(authenticate); + PYTHON_FUNC_DESTROY(authorize); PYTHON_FUNC_DESTROY(preacct); PYTHON_FUNC_DESTROY(accounting); PYTHON_FUNC_DESTROY(checksimul); +#ifdef WITH_PROXY + PYTHON_FUNC_DESTROY(pre_proxy); + PYTHON_FUNC_DESTROY(post_proxy); +#endif + PYTHON_FUNC_DESTROY(post_auth); +#ifdef WITH_COA + PYTHON_FUNC_DESTROY(recv_coa); + PYTHON_FUNC_DESTROY(send_coa); +#endif PYTHON_FUNC_DESTROY(detach); Py_DecRef(inst->pythonconf_dict); @@ -1313,14 +1333,8 @@ static int mod_detach(void *instance) PyThreadState_Swap(main_interpreter); /* Swap to the main thread */ Py_Finalize(); dlclose(python_dlhandle); - -#if PY_VERSION_HEX > 0x03050000 - //if (inst->wide_name) PyMem_RawFree(inst->wide_name); - //if (inst->wide_path) PyMem_RawFree(inst->wide_path); -#endif } - return ret; } @@ -1348,8 +1362,10 @@ module_t rlm_python3 = { [MOD_PREACCT] = mod_preacct, [MOD_ACCOUNTING] = mod_accounting, [MOD_SESSION] = mod_checksimul, +#ifdef WITH_PROXY [MOD_PRE_PROXY] = mod_pre_proxy, [MOD_POST_PROXY] = mod_post_proxy, +#endif [MOD_POST_AUTH] = mod_post_auth, #ifdef WITH_COA [MOD_RECV_COA] = mod_recv_coa,