Files
sudo/plugins/python/example_conversation.py
Robert Manner 21c02e1732 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.
2020-02-10 05:24:16 -07:00

75 lines
3.3 KiB
Python

import sudo
import signal
from os import path
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(self._log_file_path(), "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 signal.Signals(signum).name
except Exception:
return "{}".format(signum)
def _log_file_path(self):
log_path = sudo.options_as_dict(self.plugin_options).get("LogPath", "/tmp")
return path.join(log_path, "sudo_reasons.txt")