Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rlm_python3 config parameter 'utf8_fail_as_bytes' #8

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions raddb/mods-available/python3
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ python3 {
# This option prevales over "pass_all_vps"
# pass_all_vps_dict = no

# Added by Foxpass:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make these lines start with tab so they match the others

# Return a byte string if it a string can't be interpreted as UTF8
# utf8_fail_as_bytes = no

# mod_instantiate = ${.module}
# func_instantiate = instantiate

Expand Down
56 changes: 38 additions & 18 deletions src/modules/rlm_python3/rlm_python3.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static CONF_PARSER module_config[] = {
{ "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
{ "pass_all_vps", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps), "no" },
{ "pass_all_vps_dict", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps_dict), "no" },
{ "utf8_fail_as_bytes", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, utf8_fail_as_bytes), "no" },

CONF_PARSER_TERMINATOR
};
Expand Down Expand Up @@ -370,7 +371,7 @@ static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyO
* Pass the value-pair print strings in a tuple.
*
*/
static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp, bool utf8_fail_as_bytes)
{
PyObject *pStr = NULL;
char buf[1024];
Expand Down Expand Up @@ -399,9 +400,28 @@ static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
pStr = PyUnicode_FromString(buf);

if (pStr == NULL) {
ERROR("%s:%d, vp->da->name: %s", __func__, __LINE__, vp->da->name);
if (PyErr_Occurred()) {
python_error_log();
if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
if (utf8_fail_as_bytes) {
DEBUG("Conversion to Unicode failed, returning %s as bytes", vp->da->name);
PyErr_Clear();
pStr = PyBytes_FromString(buf);
if (pStr == NULL) {
ERROR("%s:%d, vp->da->name: %s", __func__, __LINE__, vp->da->name);
if (PyErr_Occurred()) {
python_error_log();
}
return -1;
}
} else {
DEBUG("String is invalid utf8, use 'utf8_fail_as_bytes' config to return as bytes");
return -1;
}
} else {
ERROR("%s:%d, vp->da->name: %s", __func__, __LINE__, vp->da->name);
python_error_log();
return -1;
}
}
return -1;
}
Expand All @@ -416,7 +436,7 @@ static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
* the indicated position in the tuple pArgs.
* Returns false on error.
*/
static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps)
static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps, bool utf8_fail_as_bytes)
{
PyObject *vps_tuple = NULL;
int tuplelen = 0;
Expand Down Expand Up @@ -449,7 +469,7 @@ static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps)
/* The inside tuple has two only: */
if ((pPair = PyTuple_New(2)) == NULL) goto error;

if (mod_populate_vptuple(pPair, vp) == 0) {
if (mod_populate_vptuple(pPair, vp, utf8_fail_as_bytes) == 0) {
/* Put the tuple inside the container */
PyTuple_SET_ITEM(vps_tuple, i, pPair);
} else {
Expand All @@ -465,7 +485,7 @@ static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps)
return false;
}

static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname, bool pass_all_vps, bool pass_all_vps_dict)
static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname, bool pass_all_vps, bool pass_all_vps_dict, bool utf8_fail_as_bytes)
{
PyObject *pRet = NULL;
PyObject *pArgs = NULL;
Expand All @@ -488,10 +508,10 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons

/* If there is a request, fill in the first 4 attribute lists */
if (request != NULL) {
if (!mod_populate_vps(pArgs, 0, request->packet->vps) ||
!mod_populate_vps(pArgs, 1, request->reply->vps) ||
!mod_populate_vps(pArgs, 2, request->config) ||
!mod_populate_vps(pArgs, 3, request->state)) {
if (!mod_populate_vps(pArgs, 0, request->packet->vps, utf8_fail_as_bytes) ||
!mod_populate_vps(pArgs, 1, request->reply->vps, utf8_fail_as_bytes) ||
!mod_populate_vps(pArgs, 2, request->config, utf8_fail_as_bytes) ||
!mod_populate_vps(pArgs, 3, request->state, utf8_fail_as_bytes)) {

ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
ret = RLM_MODULE_FAIL;
Expand All @@ -501,34 +521,34 @@ static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char cons
#ifdef WITH_PROXY
/* fill proxy vps */
if (request->proxy) {
if (!mod_populate_vps(pArgs, 4, request->proxy->vps)) {
if (!mod_populate_vps(pArgs, 4, request->proxy->vps, utf8_fail_as_bytes)) {
ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
ret = RLM_MODULE_FAIL;
goto finish;
}
} else
#endif
{
mod_populate_vps(pArgs, 4, NULL);
mod_populate_vps(pArgs, 4, NULL, utf8_fail_as_bytes);
}

#ifdef WITH_PROXY
/* fill proxy_reply vps */
if (request->proxy_reply) {
if (!mod_populate_vps(pArgs, 5, request->proxy_reply->vps)) {
if (!mod_populate_vps(pArgs, 5, request->proxy_reply->vps, utf8_fail_as_bytes)) {
ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
ret = RLM_MODULE_FAIL;
goto finish;
}
} else
#endif
{
mod_populate_vps(pArgs, 5, NULL);
mod_populate_vps(pArgs, 5, NULL, utf8_fail_as_bytes);
}

}
/* If there is no request, set all the elements to None */
else for (i = 0; i < 6; i++) mod_populate_vps(pArgs, i, NULL);
else for (i = 0; i < 6; i++) mod_populate_vps(pArgs, i, NULL, utf8_fail_as_bytes);

/*
* Call Python function. If pass_all_vps_dict is true, a dictionary with the
Expand Down Expand Up @@ -804,7 +824,7 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
RDEBUG3("Using thread state %p", this_thread->state);

PyEval_RestoreThread(this_thread->state); /* Swap in our local thread state */
ret = do_python_single(request, pFunc, funcname, inst->pass_all_vps, inst->pass_all_vps_dict);
ret = do_python_single(request, pFunc, funcname, inst->pass_all_vps, inst->pass_all_vps_dict, inst->utf8_fail_as_bytes);
PyEval_SaveThread();

return ret;
Expand Down Expand Up @@ -1264,7 +1284,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
*/
if (inst->instantiate.module_name && inst->instantiate.function_name) {

code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict);
code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict, inst->utf8_fail_as_bytes);
if (code < 0) {
error:
python_error_log(); /* Needs valid thread with GIL */
Expand All @@ -1287,7 +1307,7 @@ static int mod_detach(void *instance)
*/
PyEval_RestoreThread(inst->sub_interpreter);

if (inst->detach.function) 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, inst->utf8_fail_as_bytes);

#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
PYTHON_FUNC_DESTROY(instantiate);
Expand Down
1 change: 1 addition & 0 deletions src/modules/rlm_python3/rlm_python3.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef struct rlm_python_t {
//!< made available to the python script.
bool pass_all_vps; //!< Pass all VPS lists (request, reply, config, state, proxy_req, proxy_reply)
bool pass_all_vps_dict; //!< Pass all VPS lists as a dictionary rather than a tuple
bool utf8_fail_as_bytes; //!< If not UTF8 string, convert it into bytes
} rlm_python_t;

/** Tracks a python module inst/thread state pair
Expand Down