plugins/python/sudo_python_module.c: use IntEnums instead of constants
It is a bit more code, but it is more "pythonic" and easier to debug as the enum values also know their names. It is also an API break, eg. sudo.RC_OK becomes sudo.RC.OK as sudo.RC will be the "type" of the enum, but I guess that is acceptable before the initial release.
This commit is contained in:

committed by
Todd C. Miller

parent
67ab6fd5d6
commit
21c02e1732
@@ -12,20 +12,20 @@ class ReasonLoggerIOPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
sudo.ConvMessage has the following fields (see help(sudo.ConvMessage)):
|
sudo.ConvMessage has the following fields (see help(sudo.ConvMessage)):
|
||||||
msg_type: int Specifies the type of the conversation.
|
msg_type: int Specifies the type of the conversation.
|
||||||
See sudo.CONV_* constants below.
|
See sudo.CONV.* constants below.
|
||||||
timeout: int The maximum amount of time for the conversation in seconds.
|
timeout: int The maximum amount of time for the conversation in seconds.
|
||||||
After the timeout exceeds, the "sudo.conv" function will
|
After the timeout exceeds, the "sudo.conv" function will
|
||||||
raise sudo.ConversationInterrupted exception.
|
raise sudo.ConversationInterrupted exception.
|
||||||
msg: str The message to display for the user.
|
msg: str The message to display for the user.
|
||||||
|
|
||||||
To specify the conversion type you can use the following constants:
|
To specify the conversion type you can use the following constants:
|
||||||
sudo.CONV_PROMPT_ECHO_OFF
|
sudo.CONV.PROMPT_ECHO_OFF
|
||||||
sudo.CONV_PROMPT_ECHO_ON
|
sudo.CONV.PROMPT_ECHO_ON
|
||||||
sudo.CONV_ERROR_MSG
|
sudo.CONV.ERROR_MSG
|
||||||
sudo.CONV_INFO_MSG
|
sudo.CONV.INFO_MSG
|
||||||
sudo.CONV_PROMPT_MASK
|
sudo.CONV.PROMPT_MASK
|
||||||
sudo.CONV_PROMPT_ECHO_OK
|
sudo.CONV.PROMPT_ECHO_OK
|
||||||
sudo.CONV_PREFER_TTY
|
sudo.CONV.PREFER_TTY
|
||||||
"""
|
"""
|
||||||
def open(self, argv, command_info):
|
def open(self, argv, command_info):
|
||||||
try:
|
try:
|
||||||
@@ -36,8 +36,8 @@ class ReasonLoggerIOPlugin(sudo.Plugin):
|
|||||||
# can hide a hidden message in case of criminals are forcing him for
|
# can hide a hidden message in case of criminals are forcing him for
|
||||||
# running the command.
|
# running the command.
|
||||||
# You can either specify the arguments in strict order (timeout being optional), or use named arguments.
|
# You can either specify the arguments in strict order (timeout being optional), or use named arguments.
|
||||||
message1 = sudo.ConvMessage(sudo.CONV_PROMPT_ECHO_ON, "Reason: ", conv_timeout)
|
message1 = sudo.ConvMessage(sudo.CONV.PROMPT_ECHO_ON, "Reason: ", conv_timeout)
|
||||||
message2 = sudo.ConvMessage(msg="Secret reason: ", timeout=conv_timeout, msg_type=sudo.CONV_PROMPT_MASK)
|
message2 = sudo.ConvMessage(msg="Secret reason: ", timeout=conv_timeout, msg_type=sudo.CONV.PROMPT_MASK)
|
||||||
reply1, reply2 = sudo.conv(message1, message2,
|
reply1, reply2 = sudo.conv(message1, message2,
|
||||||
on_suspend=self.on_conversation_suspend,
|
on_suspend=self.on_conversation_suspend,
|
||||||
on_resume=self.on_conversation_resume)
|
on_resume=self.on_conversation_resume)
|
||||||
@@ -49,7 +49,7 @@ class ReasonLoggerIOPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
except sudo.ConversationInterrupted:
|
except sudo.ConversationInterrupted:
|
||||||
sudo.log_error("You did not answer in time")
|
sudo.log_error("You did not answer in time")
|
||||||
return sudo.RC_REJECT
|
return sudo.RC.REJECT
|
||||||
|
|
||||||
def on_conversation_suspend(self, signum):
|
def on_conversation_suspend(self, signum):
|
||||||
# This is just an example of how to do something on conversation suspend.
|
# This is just an example of how to do something on conversation suspend.
|
||||||
|
@@ -26,14 +26,14 @@ class DebugDemoPlugin(sudo.Plugin):
|
|||||||
load logs python plugin loading / unloading
|
load logs python plugin loading / unloading
|
||||||
|
|
||||||
Log levels
|
Log levels
|
||||||
crit sudo.DEBUG_CRIT --> only cricital messages
|
crit sudo.DEBUG.CRIT --> only cricital messages
|
||||||
err sudo.DEBUG_ERROR
|
err sudo.DEBUG.ERROR
|
||||||
warn sudo.DEBUG_WARN
|
warn sudo.DEBUG.WARN
|
||||||
notice sudo.DEBUG_NOTICE
|
notice sudo.DEBUG.NOTICE
|
||||||
diag sudo.DEBUG_DIAG
|
diag sudo.DEBUG.DIAG
|
||||||
info sudo.DEBUG_INFO
|
info sudo.DEBUG.INFO
|
||||||
trace sudo.DEBUG_TRACE
|
trace sudo.DEBUG.TRACE
|
||||||
debug sudo.DEBUG_DEBUG --> very extreme verbose debugging
|
debug sudo.DEBUG.DEBUG --> very extreme verbose debugging
|
||||||
|
|
||||||
See the sudo.conf manual for more details ("man sudo.conf").
|
See the sudo.conf manual for more details ("man sudo.conf").
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@ class DebugDemoPlugin(sudo.Plugin):
|
|||||||
# Specify: "py_calls@info" debug option to show the call to this constructor and the arguments passed in
|
# Specify: "py_calls@info" debug option to show the call to this constructor and the arguments passed in
|
||||||
|
|
||||||
# Specifying "plugin@err" debug option will show this message (or any more verbose level)
|
# Specifying "plugin@err" debug option will show this message (or any more verbose level)
|
||||||
sudo.debug(sudo.DEBUG_ERROR, "My demo purpose plugin shows this ERROR level debug message")
|
sudo.debug(sudo.DEBUG.ERROR, "My demo purpose plugin shows this ERROR level debug message")
|
||||||
|
|
||||||
# Specifying "plugin@info" debug option will show this message (or any more verbose level)
|
# Specifying "plugin@info" debug option will show this message (or any more verbose level)
|
||||||
sudo.debug(sudo.DEBUG_INFO, "My demo purpose plugin shows this INFO level debug message")
|
sudo.debug(sudo.DEBUG.INFO, "My demo purpose plugin shows this INFO level debug message")
|
||||||
|
|
||||||
# If you raise the level to info or below, the call of the debug will also be logged.
|
# If you raise the level to info or below, the call of the debug will also be logged.
|
||||||
# An example output you will see in the debug log file:
|
# An example output you will see in the debug log file:
|
||||||
|
@@ -15,14 +15,14 @@ class SudoGroupPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
Most functions can express error or reject through their "int" return value
|
Most functions can express error or reject through their "int" return value
|
||||||
as documented in the manual. The sudo module also has constants for these:
|
as documented in the manual. The sudo module also has constants for these:
|
||||||
sudo.RC_ACCEPT / sudo.RC_OK 1
|
sudo.RC.ACCEPT / sudo.RC.OK 1
|
||||||
sudo.RC_REJECT 0
|
sudo.RC.REJECT 0
|
||||||
sudo.RC_ERROR -1
|
sudo.RC.ERROR -1
|
||||||
sudo.RC_USAGE_ERROR -2
|
sudo.RC.USAGE_ERROR -2
|
||||||
|
|
||||||
If the function returns "None" (for example does not call return), it will
|
If the function returns "None" (for example does not call return), it will
|
||||||
be considered sudo.RC_OK. If an exception is raised, its backtrace will be
|
be considered sudo.RC.OK. If an exception is raised, its backtrace will be
|
||||||
shown to the user and the plugin function returns sudo.RC_ERROR. If that is
|
shown to the user and the plugin function returns sudo.RC.ERROR. If that is
|
||||||
not acceptable, catch it.
|
not acceptable, catch it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -39,4 +39,4 @@ class SudoGroupPlugin(sudo.Plugin):
|
|||||||
}
|
}
|
||||||
|
|
||||||
group_has_user = user in hardcoded_user_groups.get(group, [])
|
group_has_user = user in hardcoded_user_groups.get(group, [])
|
||||||
return sudo.RC_ACCEPT if group_has_user else sudo.RC_REJECT
|
return sudo.RC.ACCEPT if group_has_user else sudo.RC.REJECT
|
||||||
|
@@ -24,14 +24,14 @@ class SudoIOPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
Most functions can express error or reject through their "int" return value
|
Most functions can express error or reject through their "int" return value
|
||||||
as documented in the manual. The sudo module also has constants for these:
|
as documented in the manual. The sudo module also has constants for these:
|
||||||
sudo.RC_ACCEPT / sudo.RC_OK 1
|
sudo.RC.ACCEPT / sudo.RC.OK 1
|
||||||
sudo.RC_REJECT 0
|
sudo.RC.REJECT 0
|
||||||
sudo.RC_ERROR -1
|
sudo.RC.ERROR -1
|
||||||
sudo.RC_USAGE_ERROR -2
|
sudo.RC.USAGE_ERROR -2
|
||||||
|
|
||||||
If the function returns "None" (for example does not call return), it will
|
If the function returns "None" (for example does not call return), it will
|
||||||
be considered sudo.RC_OK. If an exception is raised, its backtrace will be
|
be considered sudo.RC.OK. If an exception is raised, its backtrace will be
|
||||||
shown to the user and the plugin function returns sudo.RC_ERROR. If that is
|
shown to the user and the plugin function returns sudo.RC.ERROR. If that is
|
||||||
not acceptable, catch it.
|
not acceptable, catch it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class SudoIOPlugin(sudo.Plugin):
|
|||||||
self._log("EXEC", " ".join(argv))
|
self._log("EXEC", " ".join(argv))
|
||||||
self._log("EXEC info", json.dumps(command_info, indent=4))
|
self._log("EXEC info", json.dumps(command_info, indent=4))
|
||||||
|
|
||||||
return sudo.RC_ACCEPT
|
return sudo.RC.ACCEPT
|
||||||
|
|
||||||
def log_ttyout(self, buf: str) -> int:
|
def log_ttyout(self, buf: str) -> int:
|
||||||
return self._log("TTY OUT", buf.strip())
|
return self._log("TTY OUT", buf.strip())
|
||||||
@@ -116,7 +116,7 @@ class SudoIOPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
Works the same as close() from C API (see sudo_plugin manual), except
|
Works the same as close() from C API (see sudo_plugin manual), except
|
||||||
that it only gets called if there was a command execution trial (open()
|
that it only gets called if there was a command execution trial (open()
|
||||||
returned with sudo.RC_ACCEPT).
|
returned with sudo.RC.ACCEPT).
|
||||||
"""
|
"""
|
||||||
if error == 0:
|
if error == 0:
|
||||||
self._log("CLOSE", "Command returned {}".format(exit_status))
|
self._log("CLOSE", "Command returned {}".format(exit_status))
|
||||||
@@ -133,4 +133,4 @@ class SudoIOPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
def _log(self, type, message):
|
def _log(self, type, message):
|
||||||
print(type, message, file=self._log_file)
|
print(type, message, file=self._log_file)
|
||||||
return sudo.RC_ACCEPT
|
return sudo.RC.ACCEPT
|
||||||
|
@@ -30,14 +30,14 @@ class SudoPolicyPlugin(sudo.Plugin):
|
|||||||
|
|
||||||
Most functions can express error or reject through their "int" return value
|
Most functions can express error or reject through their "int" return value
|
||||||
as documented in the manual. The sudo module also has constants for these:
|
as documented in the manual. The sudo module also has constants for these:
|
||||||
sudo.RC_ACCEPT / sudo.RC_OK 1
|
sudo.RC.ACCEPT / sudo.RC.OK 1
|
||||||
sudo.RC_REJECT 0
|
sudo.RC.REJECT 0
|
||||||
sudo.RC_ERROR -1
|
sudo.RC.ERROR -1
|
||||||
sudo.RC_USAGE_ERROR -2
|
sudo.RC.USAGE_ERROR -2
|
||||||
|
|
||||||
If the function returns "None" (for example does not call return), it will
|
If the function returns "None" (for example does not call return), it will
|
||||||
be considered sudo.RC_OK. If an exception is raised, its backtrace will be
|
be considered sudo.RC.OK. If an exception is raised, its backtrace will be
|
||||||
shown to the user and the plugin function returns sudo.RC_ERROR. If that is
|
shown to the user and the plugin function returns sudo.RC.ERROR. If that is
|
||||||
not acceptable, catch it.
|
not acceptable, catch it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ class SudoPolicyPlugin(sudo.Plugin):
|
|||||||
# Example for a simple reject:
|
# Example for a simple reject:
|
||||||
if not self._is_command_allowed(cmd):
|
if not self._is_command_allowed(cmd):
|
||||||
sudo.log_error("You are not allowed to run this command!")
|
sudo.log_error("You are not allowed to run this command!")
|
||||||
return sudo.RC_REJECT
|
return sudo.RC.REJECT
|
||||||
|
|
||||||
# The environment the command will be executed with (we allow any here)
|
# The environment the command will be executed with (we allow any here)
|
||||||
user_env_out = sudo.options_from_dict(self.user_env) + env_add
|
user_env_out = sudo.options_from_dict(self.user_env) + env_add
|
||||||
@@ -83,9 +83,9 @@ class SudoPolicyPlugin(sudo.Plugin):
|
|||||||
})
|
})
|
||||||
except SudoPluginError as error:
|
except SudoPluginError as error:
|
||||||
sudo.log_error(str(error))
|
sudo.log_error(str(error))
|
||||||
return sudo.RC_ERROR
|
return sudo.RC.ERROR
|
||||||
|
|
||||||
return (sudo.RC_ACCEPT, command_info_out, argv, user_env_out)
|
return (sudo.RC.ACCEPT, command_info_out, argv, user_env_out)
|
||||||
|
|
||||||
def init_session(self, user_pwd: Tuple, user_env: Tuple[str, ...]):
|
def init_session(self, user_pwd: Tuple, user_env: Tuple[str, ...]):
|
||||||
"""Perform session setup
|
"""Perform session setup
|
||||||
@@ -97,10 +97,10 @@ class SudoPolicyPlugin(sudo.Plugin):
|
|||||||
user_pwd = pwd.struct_passwd(user_pwd) if user_pwd else None
|
user_pwd = pwd.struct_passwd(user_pwd) if user_pwd else None
|
||||||
|
|
||||||
# This is how you change the user_env:
|
# This is how you change the user_env:
|
||||||
return (sudo.RC_OK, user_env + ("PLUGIN_EXAMPLE_ENV=1",))
|
return (sudo.RC.OK, user_env + ("PLUGIN_EXAMPLE_ENV=1",))
|
||||||
|
|
||||||
# If you do not want to change user_env, you can also just return (or None):
|
# If you do not want to change user_env, you can also just return (or None):
|
||||||
# return sudo.RC_OK
|
# return sudo.RC.OK
|
||||||
|
|
||||||
def list(self, argv: Tuple[str, ...], is_verbose: int, user: str):
|
def list(self, argv: Tuple[str, ...], is_verbose: int, user: str):
|
||||||
cmd = argv[0] if argv else None
|
cmd = argv[0] if argv else None
|
||||||
|
@@ -518,3 +518,33 @@ py_object_set_attr_string(PyObject *py_object, const char *attr_name, const char
|
|||||||
PyObject_SetAttrString(py_object, attr_name, py_value);
|
PyObject_SetAttrString(py_object, attr_name, py_value);
|
||||||
Py_CLEAR(py_value);
|
Py_CLEAR(py_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
py_dict_create_string_int(size_t count, struct key_value_str_int *key_values)
|
||||||
|
{
|
||||||
|
debug_decl(py_dict_create_string_int, PYTHON_DEBUG_INTERNAL);
|
||||||
|
|
||||||
|
PyObject *py_value = NULL;
|
||||||
|
PyObject *py_dict = PyDict_New();
|
||||||
|
if (py_dict == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
py_value = PyLong_FromLong(key_values[i].value);
|
||||||
|
if (py_value == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (PyDict_SetItemString(py_dict, key_values[i].key, py_value) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
Py_CLEAR(py_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
Py_CLEAR(py_dict);
|
||||||
|
}
|
||||||
|
Py_CLEAR(py_value);
|
||||||
|
|
||||||
|
debug_return_ptr(py_dict);
|
||||||
|
}
|
||||||
|
@@ -62,6 +62,14 @@ char *py_create_string_rep(PyObject *py_object);
|
|||||||
|
|
||||||
char *py_join_str_list(PyObject *py_str_list, const char *separator);
|
char *py_join_str_list(PyObject *py_str_list, const char *separator);
|
||||||
|
|
||||||
|
struct key_value_str_int
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
PyObject *py_dict_create_string_int(size_t count, struct key_value_str_int *key_values);
|
||||||
|
|
||||||
PyObject *py_from_passwd(const struct passwd *pwd);
|
PyObject *py_from_passwd(const struct passwd *pwd);
|
||||||
|
|
||||||
PyObject *py_str_array_to_tuple_with_count(Py_ssize_t count, char * const strings[]);
|
PyObject *py_str_array_to_tuple_with_count(Py_ssize_t count, char * const strings[]);
|
||||||
|
@@ -243,6 +243,15 @@ _python_plugin_register_plugin_in_py_ctx(void)
|
|||||||
PyImport_AppendInittab("sudo", sudo_module_init);
|
PyImport_AppendInittab("sudo", sudo_module_init);
|
||||||
Py_InitializeEx(0);
|
Py_InitializeEx(0);
|
||||||
py_ctx.py_main_interpreter = PyThreadState_Get();
|
py_ctx.py_main_interpreter = PyThreadState_Get();
|
||||||
|
|
||||||
|
// This ensures we import "sudo" module in the main interpreter,
|
||||||
|
// each subinterpreter will have a shallow copy.
|
||||||
|
// (This makes the C sudo module able to eg. import other modules.)
|
||||||
|
PyObject *py_sudo = NULL;
|
||||||
|
if ((py_sudo = PyImport_ImportModule("sudo")) == NULL) {
|
||||||
|
debug_return_int(SUDO_RC_ERROR);
|
||||||
|
}
|
||||||
|
Py_CLEAR(py_sudo);
|
||||||
} else {
|
} else {
|
||||||
PyThreadState_Swap(py_ctx.py_main_interpreter);
|
PyThreadState_Swap(py_ctx.py_main_interpreter);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
sudo.debug was called with arguments: (2, 'My demo purpose plugin shows this ERROR level debug message')
|
sudo.debug was called with arguments: (<DEBUG.ERROR: 2>, 'My demo purpose plugin shows this ERROR level debug message')
|
||||||
sudo.debug was called with arguments: (6, 'My demo purpose plugin shows this INFO level debug message')
|
sudo.debug was called with arguments: (<DEBUG.INFO: 6>, 'My demo purpose plugin shows this INFO level debug message')
|
||||||
sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),)
|
sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),)
|
||||||
sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'}
|
sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
__init__ @ SRC_DIR/example_debugging.py:45 calls C function:
|
__init__ @ SRC_DIR/example_debugging.py:45 calls C function:
|
||||||
sudo.debug was called with arguments: (2, 'My demo purpose plugin shows this ERROR level debug message')
|
sudo.debug was called with arguments: (<DEBUG.ERROR: 2>, 'My demo purpose plugin shows this ERROR level debug message')
|
||||||
__init__ @ SRC_DIR/example_debugging.py:48 calls C function:
|
__init__ @ SRC_DIR/example_debugging.py:48 calls C function:
|
||||||
sudo.debug was called with arguments: (6, 'My demo purpose plugin shows this INFO level debug message')
|
sudo.debug was called with arguments: (<DEBUG.INFO: 6>, 'My demo purpose plugin shows this INFO level debug message')
|
||||||
__init__ @ SRC_DIR/example_debugging.py:58 calls C function:
|
__init__ @ SRC_DIR/example_debugging.py:58 calls C function:
|
||||||
sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),)
|
sudo.options_as_dict was called with arguments: (('ModulePath=SRC_DIR/example_debugging.py', 'ClassName=DebugDemoPlugin'),)
|
||||||
sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'}
|
sudo.options_as_dict returned result: {'ModulePath': 'SRC_DIR/example_debugging.py', 'ClassName': 'DebugDemoPlugin'}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
SudoGroupPlugin.__init__ was called with arguments: () {'args': ('ModulePath=SRC_DIR/example_group_plugin.py', 'ClassName=SudoGroupPlugin'), 'version': '1.0'}
|
SudoGroupPlugin.__init__ was called with arguments: () {'args': ('ModulePath=SRC_DIR/example_group_plugin.py', 'ClassName=SudoGroupPlugin'), 'version': '1.0'}
|
||||||
SudoGroupPlugin.__init__ returned result: <example_group_plugin.SudoGroupPlugin object>
|
SudoGroupPlugin.__init__ returned result: <example_group_plugin.SudoGroupPlugin object>
|
||||||
SudoGroupPlugin.query was called with arguments: ('user', 'group', ('pw_name', 'pw_passwd', 1001, 101, 'pw_gecos', 'pw_dir', 'pw_shell'))
|
SudoGroupPlugin.query was called with arguments: ('user', 'group', ('pw_name', 'pw_passwd', 1001, 101, 'pw_gecos', 'pw_dir', 'pw_shell'))
|
||||||
SudoGroupPlugin.query returned result: 0
|
SudoGroupPlugin.query returned result: RC.REJECT
|
||||||
|
@@ -498,6 +498,44 @@ cleanup:
|
|||||||
debug_return_ptr(py_class);
|
debug_return_ptr(py_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sudo_module_register_enum(PyObject *py_module, const char *enum_name, PyObject *py_constants_dict)
|
||||||
|
{
|
||||||
|
// pseudo code:
|
||||||
|
// return IntEnum('MyEnum', {'DEFINITION_NAME': DEFINITION_VALUE, ...})
|
||||||
|
|
||||||
|
debug_decl(sudo_module_register_enum, PYTHON_DEBUG_INTERNAL);
|
||||||
|
|
||||||
|
if (py_constants_dict == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PyObject *py_enum_class = NULL;
|
||||||
|
{
|
||||||
|
PyObject *py_enum_module = PyImport_ImportModule("enum");
|
||||||
|
if (py_enum_module == NULL) {
|
||||||
|
Py_CLEAR(py_constants_dict);
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_enum_class = PyObject_CallMethod(py_enum_module,
|
||||||
|
"IntEnum", "sO", enum_name,
|
||||||
|
py_constants_dict);
|
||||||
|
|
||||||
|
Py_CLEAR(py_constants_dict);
|
||||||
|
Py_CLEAR(py_enum_module);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (py_enum_class == NULL) {
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyModule_AddObject(py_module, enum_name, py_enum_class) < 0) {
|
||||||
|
Py_CLEAR(py_enum_class);
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
sudo_module_init(void)
|
sudo_module_init(void)
|
||||||
@@ -525,35 +563,41 @@ sudo_module_init(void)
|
|||||||
MODULE_ADD_EXCEPTION(SudoException, NULL);
|
MODULE_ADD_EXCEPTION(SudoException, NULL);
|
||||||
MODULE_ADD_EXCEPTION(ConversationInterrupted, EXC_VAR(SudoException));
|
MODULE_ADD_EXCEPTION(ConversationInterrupted, EXC_VAR(SudoException));
|
||||||
|
|
||||||
|
#define MODULE_REGISTER_ENUM(name, key_values) \
|
||||||
|
sudo_module_register_enum(py_module, name, py_dict_create_string_int(\
|
||||||
|
sizeof(key_values) / sizeof(struct key_value_str_int), key_values))
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
#define MODULE_ADD_INT_CONSTANT(constant) \
|
struct key_value_str_int constants_rc[] = {
|
||||||
do { \
|
{"OK", SUDO_RC_OK},
|
||||||
if (PyModule_AddIntConstant(py_module, #constant, SUDO_ ## constant) != 0) \
|
{"ACCEPT", SUDO_RC_ACCEPT},
|
||||||
goto cleanup; \
|
{"REJECT", SUDO_RC_REJECT},
|
||||||
} while(0)
|
{"ERROR", SUDO_RC_ERROR},
|
||||||
|
{"USAGE_ERROR", SUDO_RC_USAGE_ERROR}
|
||||||
|
};
|
||||||
|
MODULE_REGISTER_ENUM("RC", constants_rc);
|
||||||
|
|
||||||
MODULE_ADD_INT_CONSTANT(RC_OK);
|
struct key_value_str_int constants_conv[] = {
|
||||||
MODULE_ADD_INT_CONSTANT(RC_ACCEPT);
|
{"PROMPT_ECHO_OFF", SUDO_CONV_PROMPT_ECHO_OFF},
|
||||||
MODULE_ADD_INT_CONSTANT(RC_REJECT);
|
{"PROMPT_ECHO_ON", SUDO_CONV_PROMPT_ECHO_ON},
|
||||||
MODULE_ADD_INT_CONSTANT(RC_ERROR);
|
{"INFO_MSG", SUDO_CONV_INFO_MSG},
|
||||||
MODULE_ADD_INT_CONSTANT(RC_USAGE_ERROR);
|
{"PROMPT_MASK", SUDO_CONV_PROMPT_MASK},
|
||||||
|
{"PROMPT_ECHO_OK", SUDO_CONV_PROMPT_ECHO_OK},
|
||||||
|
{"PREFER_TTY", SUDO_CONV_PREFER_TTY}
|
||||||
|
};
|
||||||
|
MODULE_REGISTER_ENUM("CONV", constants_conv);
|
||||||
|
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_OFF);
|
struct key_value_str_int constants_debug[] = {
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_ON);
|
{"CRIT", SUDO_DEBUG_CRIT},
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_ERROR_MSG);
|
{"ERROR", SUDO_DEBUG_ERROR},
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_INFO_MSG);
|
{"WARN", SUDO_DEBUG_WARN},
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_MASK);
|
{"NOTICE", SUDO_DEBUG_NOTICE},
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_OK);
|
{"DIAG", SUDO_DEBUG_DIAG},
|
||||||
MODULE_ADD_INT_CONSTANT(CONV_PREFER_TTY);
|
{"INFO", SUDO_DEBUG_INFO},
|
||||||
|
{"TRACE", SUDO_DEBUG_TRACE},
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_CRIT);
|
{"DEBUG", SUDO_DEBUG_DEBUG}
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_ERROR);
|
};
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_WARN);
|
MODULE_REGISTER_ENUM("DEBUG", constants_debug);
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_NOTICE);
|
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_DIAG);
|
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_INFO);
|
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_TRACE);
|
|
||||||
MODULE_ADD_INT_CONSTANT(DEBUG_DEBUG);
|
|
||||||
|
|
||||||
// classes
|
// classes
|
||||||
if (sudo_module_register_conv_message(py_module) != SUDO_RC_OK)
|
if (sudo_module_register_conv_message(py_module) != SUDO_RC_OK)
|
||||||
|
Reference in New Issue
Block a user