diff --git a/plugins/python/pyhelpers.c b/plugins/python/pyhelpers.c index 894309ab2..b3aafc77e 100644 --- a/plugins/python/pyhelpers.c +++ b/plugins/python/pyhelpers.c @@ -143,7 +143,7 @@ py_log_last_error(const char *context_message) debug_return; } - PyObject *py_type, *py_message, *py_traceback; + PyObject *py_type = NULL, *py_message = NULL, *py_traceback = NULL; PyErr_Fetch(&py_type, &py_message, &py_traceback); char *message = py_message ? py_create_string_rep(py_message) : strdup("(NULL)"); @@ -398,7 +398,7 @@ py_get_current_execution_frame(char **file_name, long *line_number, char **funct PyObject *py_err_type = NULL, *py_err_value = NULL, *py_err_traceback = NULL; PyErr_Fetch(&py_err_type, &py_err_value, &py_err_traceback); - PyObject *py_frame = NULL, *py_lineno = NULL, *py_f_code = NULL, + PyObject *py_frame = NULL, *py_f_code = NULL, *py_filename = NULL, *py_function_name = NULL; PyObject *py_getframe = PySys_GetObject("_getframe"); @@ -409,25 +409,21 @@ py_get_current_execution_frame(char **file_name, long *line_number, char **funct if (py_frame == NULL) goto cleanup; - py_lineno = PyObject_GetAttrString(py_frame, "f_lineno"); - if (py_lineno != NULL) { - *line_number = PyLong_AsLong(py_lineno); - } + *line_number = py_object_get_optional_attr_number(py_frame, "f_lineno"); - py_f_code = PyObject_GetAttrString(py_frame, "f_code"); + py_f_code = py_object_get_optional_attr(py_frame, "f_code", NULL); if (py_f_code != NULL) { - py_filename = PyObject_GetAttrString(py_f_code, "co_filename"); + py_filename = py_object_get_optional_attr(py_f_code, "co_filename", NULL); if (py_filename != NULL) *file_name = strdup(PyUnicode_AsUTF8(py_filename)); - py_function_name = PyObject_GetAttrString(py_f_code, "co_name"); + py_function_name = py_object_get_optional_attr(py_f_code, "co_name", NULL); if (py_function_name != NULL) *function_name = strdup(PyUnicode_AsUTF8(py_function_name)); } cleanup: Py_CLEAR(py_frame); - Py_CLEAR(py_lineno); Py_CLEAR(py_f_code); Py_CLEAR(py_filename); Py_CLEAR(py_function_name); @@ -447,7 +443,8 @@ py_ctx_reset() } int -py_sudo_conv(int num_msgs, const struct sudo_conv_message msgs[], struct sudo_conv_reply replies[], struct sudo_conv_callback *callback) +py_sudo_conv(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[], struct sudo_conv_callback *callback) { /* Enable suspend during password entry. */ struct sigaction sa, saved_sigtstp; @@ -465,3 +462,59 @@ py_sudo_conv(int num_msgs, const struct sudo_conv_message msgs[], struct sudo_co return rc; } + +PyObject * +py_object_get_optional_attr(PyObject *py_object, const char *attr, PyObject *py_default) +{ + if (PyObject_HasAttrString(py_object, attr)) { + return PyObject_GetAttrString(py_object, attr); + } + Py_XINCREF(py_default); // whatever we return will have its refcount incremented + return py_default; +} + +const char * +py_object_get_optional_attr_string(PyObject *py_object, const char *attr_name) +{ + PyObject *py_value = py_object_get_optional_attr(py_object, attr_name, NULL); + if (py_value == NULL) + return NULL; + + const char *value = PyUnicode_AsUTF8(py_value); + Py_CLEAR(py_value); // Note, the object still has reference to the attribute + return value; +} + +long long +py_object_get_optional_attr_number(PyObject *py_object, const char *attr_name) +{ + PyObject *py_value = py_object_get_optional_attr(py_object, attr_name, NULL); + if (py_value == NULL) + return -1; + + long long value = PyLong_AsLongLong(py_value); + Py_CLEAR(py_value); + return value; +} + +void +py_object_set_attr_number(PyObject *py_object, const char *attr_name, long long number) +{ + PyObject *py_number = PyLong_FromLong(number); + if (py_number == NULL) + return; + + PyObject_SetAttrString(py_object, attr_name, py_number); + Py_CLEAR(py_number); +} + +void +py_object_set_attr_string(PyObject *py_object, const char *attr_name, const char *value) +{ + PyObject *py_value = PyUnicode_FromString(value); + if (py_value == NULL) + return; + + PyObject_SetAttrString(py_object, attr_name, py_value); + Py_CLEAR(py_value); +} diff --git a/plugins/python/pyhelpers.h b/plugins/python/pyhelpers.h index 471218797..a64636ba8 100644 --- a/plugins/python/pyhelpers.h +++ b/plugins/python/pyhelpers.h @@ -71,6 +71,13 @@ char **py_str_array_from_tuple(PyObject *py_tuple); CPYCHECKER_RETURNS_BORROWED_REF PyObject *py_tuple_get(PyObject *py_tuple, Py_ssize_t index, PyTypeObject *expected_type); +PyObject *py_object_get_optional_attr(PyObject *py_object, const char *attr, PyObject *py_default); +long long py_object_get_optional_attr_number(PyObject *py_object, const char *attr_name); +const char *py_object_get_optional_attr_string(PyObject *py_object, const char *attr_name); + +void py_object_set_attr_number(PyObject *py_object, const char *attr_name, long long number); +void py_object_set_attr_string(PyObject *py_object, const char *attr_name, const char *value); + PyObject *py_create_version(unsigned int version); void py_debug_python_call(const char *class_name, const char *function_name, diff --git a/plugins/python/python_convmessage.c b/plugins/python/python_convmessage.c index c5849d23e..61e947b53 100644 --- a/plugins/python/python_convmessage.c +++ b/plugins/python/python_convmessage.c @@ -35,7 +35,6 @@ _sudo_ConvMessage__Init(PyObject *py_self, PyObject *py_args, PyObject *py_kwarg PyObject *py_empty = PyTuple_New(0); struct sudo_conv_message conv_message = { 0, 0, NULL }; - PyObject *py_msg_type = NULL, *py_timeout = NULL, *py_msg = NULL; // borrowed references static char *keywords[] = { "self", "msg_type", "msg", "timeout", NULL }; if (!PyArg_ParseTupleAndKeywords(py_args ? py_args : py_empty, py_kwargs, "Ois|i:sudo.ConvMessage", keywords, @@ -46,31 +45,19 @@ _sudo_ConvMessage__Init(PyObject *py_self, PyObject *py_args, PyObject *py_kwarg sudo_debug_printf(SUDO_DEBUG_TRACE, "Parsed arguments: self='%p' msg_type='%d' timeout='%d' msg='%s'", (void *)py_self, conv_message.msg_type, conv_message.timeout, conv_message.msg); - py_msg_type = PyLong_FromLong(conv_message.msg_type); - if (py_msg_type == NULL) + py_object_set_attr_number(py_self, "msg_type", conv_message.msg_type); + if (PyErr_Occurred()) goto cleanup; - py_timeout = PyLong_FromLong(conv_message.timeout); - if (py_timeout == NULL) + py_object_set_attr_number(py_self, "timeout", conv_message.timeout); + if (PyErr_Occurred()) goto cleanup; - py_msg = PyUnicode_FromString(conv_message.msg); - if (py_msg == NULL) - goto cleanup; - - if (PyObject_SetAttrString(py_self, "msg_type", py_msg_type) != 0) - goto cleanup; - - if (PyObject_SetAttrString(py_self, "timeout", py_timeout) != 0) - goto cleanup; - - if (PyObject_SetAttrString(py_self, "msg", py_msg) != 0) + py_object_set_attr_string(py_self, "msg", conv_message.msg); + if (PyErr_Occurred()) goto cleanup; cleanup: - Py_CLEAR(py_msg_type); - Py_CLEAR(py_timeout); - Py_CLEAR(py_msg); Py_CLEAR(py_empty); if (PyErr_Occurred()) @@ -121,31 +108,19 @@ sudo_module_ConvMessage_to_c(PyObject *py_conv_message, struct sudo_conv_message { debug_decl(sudo_module_ConvMessage_to_c, PYTHON_DEBUG_C_CALLS); - int rc = SUDO_RC_ERROR; - PyObject *py_msg_type = NULL, *py_timeout = NULL, *py_msg = NULL; + conv_message->msg_type = (int)py_object_get_optional_attr_number(py_conv_message, "msg_type"); + if (PyErr_Occurred()) + debug_return_int(SUDO_RC_ERROR); - if ((py_msg_type = PyObject_GetAttrString(py_conv_message, "msg_type")) == NULL) - goto cleanup; - conv_message->msg_type = (int)PyLong_AsLong(py_msg_type); + conv_message->timeout = (int)py_object_get_optional_attr_number(py_conv_message, "timeout"); + if (PyErr_Occurred()) + debug_return_int(SUDO_RC_ERROR); - if ((py_timeout = PyObject_GetAttrString(py_conv_message, "timeout")) == NULL) - goto cleanup; - conv_message->timeout = (int)PyLong_AsLong(py_timeout); + conv_message->msg = py_object_get_optional_attr_string(py_conv_message, "msg"); + if (PyErr_Occurred()) + debug_return_int(SUDO_RC_ERROR); - if ((py_msg = PyObject_GetAttrString(py_conv_message, "msg")) == NULL) - goto cleanup; - - conv_message->msg = PyUnicode_AsUTF8(py_msg); - if (conv_message->msg == NULL) - goto cleanup; - - rc = SUDO_RC_OK; - -cleanup: - Py_CLEAR(py_msg_type); - Py_CLEAR(py_timeout); - Py_CLEAR(py_msg); - debug_return_int(rc); + debug_return_int(SUDO_RC_OK); } int