-
Notifications
You must be signed in to change notification settings - Fork 0
/
sudomodule.py
executable file
·52 lines (40 loc) · 1.72 KB
/
sudomodule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""Class to encapsulate privilege escalation of shell commands with sudo
"""
from getpass import getpass, getuser
from subprocess import Popen, PIPE, check_output, CalledProcessError
class SudoCommand:
"""SudoCommand class to encapsulate privilege elevation
"""
def __init__(self):
self.username = getuser()
self.password = getpass(f"[sudo] password for {self.username}: ")
def can_sudo_without_password(self):
"""Method to test if password prompt is necessary
"""
try:
check_output(['sudo', '-n', 'true'])
return True
except CalledProcessError:
return False
def run(self, command, preserve_env=False):
"""Method to handle privilege elevation
:param command: The command to run.
:type command: list
:param preserve_env: Whether to preserve the environment (pass `-E` to `sudo`).
:type preserve_env: bool
"""
sudo_command = ['sudo', '-S']
if preserve_env:
sudo_command.insert(1, '-E')
sudo_command.extend(command)
# Check if sudo requires a password
if not self.can_sudo_without_password() and self.password is None:
self.password = getpass(f"[sudo] password for {self.username}: ")
process = Popen(sudo_command, stdin=PIPE if self.password else None,
stderr=PIPE, universal_newlines=True)
if self.password:
process.stdin.write(self.password + '\n')
process.stdin.flush()
_, stderr = process.communicate() # Ensure process is cleaned up
if process.returncode != 0:
raise CalledProcessError(process.returncode, sudo_command, stderr)