plugins/python: example plugin demonstrating conversation and debug API

This commit is contained in:
Robert Manner
2019-12-05 15:21:25 +01:00
committed by Todd C. Miller
parent 523bcbedb6
commit 4ad362dd8f
2 changed files with 127 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import sudo
import signal
class ReasonLoggerIOPlugin(sudo.Plugin):
"""
An example sudo plugin demonstrating how to use the sudo conversation API.
From the python plugin, you can ask something from the user using the
"sudo.conv" function. It expects one or more "sudo.ConvMessage" instances
which specifies how the interaction has to look like.
sudo.ConvMessage has the following fields (see help(sudo.ConvMessage)):
msg_type: int Specifies the type of the conversation.
See sudo.CONV_* constants below.
timeout: int The maximum amount of time for the conversation in seconds.
After the timeout exceeds, the "sudo.conv" function will
raise sudo.ConversationInterrupted exception.
msg: str The message to display for the user.
To specify the conversion type you can use the following constants:
sudo.CONV_PROMPT_ECHO_OFF
sudo.CONV_PROMPT_ECHO_ON
sudo.CONV_ERROR_MSG
sudo.CONV_INFO_MSG
sudo.CONV_PROMPT_MASK
sudo.CONV_PROMPT_ECHO_OK
sudo.CONV_PREFER_TTY
"""
def open(self, argv, command_info):
try:
conv_timeout = 120 # in seconds
sudo.log_info("Please provide your reason for executing {}".format(argv))
# We ask two questions, the second is not visible on screen, so the user
# can hide a hidden message in case of criminals are forcing him for
# running the command.
# 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)
message2 = sudo.ConvMessage(msg="Secret reason: ", timeout=conv_timeout, msg_type=sudo.CONV_PROMPT_MASK)
reply1, reply2 = sudo.conv(message1, message2,
on_suspend=self.on_conversation_suspend,
on_resume=self.on_conversation_resume)
with open("/tmp/sudo_reasons.txt", "a") as file:
print("Executed", ' '.join(argv), file=file)
print("Reason:", reply1, file=file)
print("Hidden reason:", reply2, file=file)
except sudo.ConversationInterrupted:
sudo.log_error("You did not answer in time")
return sudo.RC_REJECT
def on_conversation_suspend(self, signum):
# This is just an example of how to do something on conversation suspend.
# You can skip specifying 'on_suspend' argument if there is no need
sudo.log_info("conversation suspend: signal", self._signal_name(signum))
def on_conversation_resume(self, signum):
# This is just an example of how to do something on conversation resume.
# You can skip specifying 'on_resume' argument if there is no need
sudo.log_info("conversation resume: signal was", self._signal_name(signum))
# helper functions:
@classmethod
def _signal_name(cls, signum):
try:
return "{} ({})".format(signal.Signals(signum).name, signum)
except Exception:
return "{}".format(signum)

View File

@@ -0,0 +1,58 @@
import sudo
class DebugDemoPlugin(sudo.Plugin):
"""
An example sudo plugin demonstrating the debugging capabilities.
You can install it as an extra IO plugin for example by adding the following line to sudo.conf:
Plugin python_io python_plugin.so ModulePath=<path>/example_debugging.py ClassName=DebugDemoPlugin
To see the plugin's debug output, use the following line in sudo.conf:
Debug python_plugin.so /var/log/sudo_python_debug plugin@trace,c_calls@trace
^ ^-- the options for the logging
^----- the output will be placed here
The options for the logging is in format of multiple "subsystem@level" separated by commas (",").
The most interesting subsystems are:
plugin Shows each call of sudo.debug API in the log
- py_calls Logs whenever a C function calls into the python module. (For example calling this __init__ function.)
c_calls Logs whenever python calls into a C sudo API function
You can also specify "all" as subsystem name to get the debug messages of all subsystems.
Other subsystems available:
internal logs internal functions of the python language wrapper plugin
sudo_cb logs when sudo calls into its plugin API
load logs python plugin loading / unloading
Log levels
crit sudo.DEBUG_CRIT --> only cricital messages
err sudo.DEBUG_ERROR
warn sudo.DEBUG_WARN
notice sudo.DEBUG_NOTICE
diag sudo.DEBUG_DIAG
info sudo.DEBUG_INFO
trace sudo.DEBUG_TRACE
debug sudo.DEBUG_DEBUG --> very extreme verbose debugging
See the sudo.conf manual for more details ("man sudo.conf").
"""
def __init__(self, plugin_options, **kwargs):
# Specify: "py_calls@info" debug option to show the call to this constructor and the arguments passed in
# Specifying "plugin@error" 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")
# 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")
# 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:
# Dec 5 15:19:19 sudo[123040] __init__ @ /.../example_debugging.py:54 debugs:
# Dec 5 15:19:19 sudo[123040] My demo purpose plugin shows this ERROR level debug message
# Specify: "c_calls@diag" debug option to show this call and its arguments
# If you specify info debug level instead ("c_call@info"),
# you will also see the python function and line from which you called the 'options_as_dict' function.
self.plugin_options = sudo.options_as_dict(plugin_options)