4

I'm writing a script in python 3.6 that uses many sudo commands. The script runs on linux machines, as my user. The script is creating a sort of a report, doing ssh to many servers and running commands like lsof.
I need a way of making python give my password any time I use sudo. Obviously in the first time I'll enter my password, and it can be saved in the script's memory. I've been using python subprocess to run my sudo commands, for example:

cmd = SSH + '-t ' + source + " ' " + SUDO + "-k " +  LSOF + "-p " + pid + " ' "
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, universal_newlines=True)
(out,error) = output.communicate()

Is it possible?

constraints:
Root kit is not allowed
Running the script with sudo is not an option, since the script does ssh to many servers, and for security reasons I'm not allowed to do so.
Can't change anything in sudoers file.

razrilen
  • 43
  • 1
  • 3
  • You could use the -S switch which reads the password from STDIN: `$echo | sudo -S `. However, I have another better way. Don't put your password into source code. – Trần Đức Tâm Dec 19 '17 at 06:59
  • Off topic: but please, check on of Python's various string-formatting options - you are typing twenty-too-many double quotes to assemble your SSH strings. – jsbueno Dec 19 '17 at 15:27
  • Does this answer your question? [running a command as a super user from a python script](https://stackoverflow.com/questions/567542/running-a-command-as-a-super-user-from-a-python-script) – miken32 Aug 31 '21 at 15:44

5 Answers5

5

Spent some hours to figure out how to do it with subprocess.

So enjoy:

import getpass
import subprocess

sudo_password = getpass.getpass(prompt='sudo password: ')
p = subprocess.Popen(['sudo', '-S', 'ls'], stderr=subprocess.PIPE, stdout=subprocess.PIPE,  stdin=subprocess.PIPE)

try:
    out, err = p.communicate(input=(sudo_password+'\n').encode(),timeout=5)

except subprocess.TimeoutExpired:
    p.kill()
Shtefan
  • 742
  • 12
  • 14
3

I suggest you use Python's "pexpect" module which does just that. It's based an "expect" and used to automate interactions with other programs. It's not part of the python standard library mind you, but you do not necessarily need root to install it if you create your own python environment.

Example:

#import the pexpect module
import pexpect
# here you issue the command with "sudo"
child = pexpect.spawn('sudo /usr/sbin/lsof')
# it will prompt something like: "[sudo] password for < generic_user >:"
# you "expect" to receive a string containing keyword "password"
child.expect('password')
# if it's found, send the password
child.sendline('S3crEt.P4Ss')
# read the output
print(child.read())
# the end

More details can be found here:

https://pexpect.readthedocs.io/en/stable/api/index.html

Hope this helps!

AnythingIsFine
  • 1,777
  • 13
  • 11
2

The following answer performs three attempts to verify the access:

  • Check if the current user is root
  • Call sudo without providing password
  • Ask the user for a password and call sudo

The calls to sudo invoke the echo command and check the same test that is supposed to be printed by echo: the word OK.

import os, subprocess
from getpass import getpass

def is_root():
    return os.geteuid() == 0

def test_sudo(pwd=""):
    args = "sudo -S echo OK".split()
    kwargs = dict(stdout=subprocess.PIPE,
                  encoding="ascii")
    if pwd:
        kwargs.update(input=pwd)
    cmd = subprocess.run(args, **kwargs)
    return ("OK" in cmd.stdout)

def prompt_sudo():
    ok = is_root() or test_sudo()
    if not ok:
        pwd = getpass("password: ")
        ok  = test_sudo(pwd)
    return ok

if prompt_sudo():
    print("Access granted !")
else:
    print("Access denied !")
yucer
  • 4,431
  • 3
  • 34
  • 42
  • This is the answer that I liked the most but the code fails to work in python version 3.6.12. @yucer maybe update the answer to working code as it put me on the right track and I think is a great solution. To see the failure, intentionally fail your password multiple times. – Dave Nov 30 '20 at 20:17
  • Or just don't fail your password multiple times. Works for my purposes on Python 3.8. – slumtrimpet Dec 16 '21 at 13:00
0

Because you want to give your python script the sudo password, so I think that's better for create a new user group and set up this group to your script files. Your script does not require sudo password anymore (Still have sudo permission).

Note: (My answer tested on Ubuntu 14.04. Another Linux version should be the same.)

If you are signed in as the root user, you can create a new user at any time by typing:

adduser <newuser>

or

sudo adduser <newuser>

If your new user should have the ability to execute commands with root (administrative) privileges, you will need to give the new user access to sudo.

We can do this by using the visudo command, which opens the appropriate configuration file in your editor. This is the safest way to make these changes.

visudo

or

sudo visudo

Search for the line that looks like this:

root    ALL=(ALL:ALL) ALL

Below this line, copy the format you see here, changing only the word "root" to reference the new user that you would like to give sudo privileges to:

root      ALL=(ALL:ALL) ALL
<newuser> ALL=(ALL) NOPASSWD:ALL

Use chown to change ownership of your python script.

sudo chown <newuser>: <python script>

After that you could run your script under sudo permission without the password.

Note: (I suggest you this way because you want to put your sudo password into source code. However, please careful with your script. It has more powerful...)

Trần Đức Tâm
  • 4,037
  • 3
  • 30
  • 58
0

I think you should do it by using Paramiko library. Make sure you install paramiko before importing it. Check this

Below is a sample code. Test it before you use it.

$pip install paramiko

import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
pid = 12345 # Modify this per your requirement
try:
    ssh_client.connect('source',username='user',password='pwd')
    stdin,stdout,stderr = ssh_client.exec_command('sudo -k lsof -p '+pid)
    stdin.write('pwd\n')
    stdin.flush()
    result = stdout.read.splitlines()
except paramiko.SSHException:
    print('Connection Failed')
    quit()
sulabh chaturvedi
  • 3,608
  • 3
  • 13
  • 25