Automating the transition from the normal user to the root with subprocessing in python

advertisements

Question:

I am trying to execute a cmd which reads from a PostgreSQL db. I am able to manually switch to root, then switch to the postgre user and access the information I desire.

The problem I have is that when I run this, it just hangs and nothing happens.

I have the root password and will need this when switching from the current user But I am not being prompted to enter it.

How can I get this not to hang and the password be prompted?

The code below only executes 'ls' for simplicity.

Code:

def popen_cmd_shell(command):
    print command
    process = subprocess.Popen(command,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT,
                               shell=True)

    proc_stdout = process.communicate()[0].strip()
    return proc_stdout

if __name__ == '__main__':
    querylist = popen_cmd_shell('su - root; ls;')

    print querylist

Update One:

I am unable to use any library that dose not come with python 2.7 on Linux SUSE. I just need to execute a command and exit.

Update Two:

I am unable to run the script as root as I need to perform other tasks which require me not to be root.

Update Three:

As per LeBarton suggestions I have got the script to log into root, although the the ls command never gets executed as root, it gets executed as the user I originally was. When I run the command I get prompted to enter the root password and get transfered from "@host" to "host" who cannot execute any command other than exit. When I exit all the commands executed output appears.

I do not wish to store the user password in the code as LeBarton has it. How can I execute a command as root and return back and continue the rest of the script, without getting locked into the new users and needing to type 'exit'.

The "stderr=subprocess.STDOUT" seems to have been what was causing it to hang.

Code:

if __name__ == '__main__':
    def subprocess_cmd(command):
        process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
        proc_stdout = process.communicate()[0].strip()
        print proc_stdout

    subprocess_cmd('echo a; su - root; ls; cd;ls;')

...continue with rest of script where I execute commands as original user

Answer:

Thanks to tripleee for his excellent answer.

I Have achieved what I set out to do with the follwoing code:

if __name__ == '__main__':
    def subprocess_cmd(command):
        process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=False)
        proc_stdout = process.communicate()[0].strip()
        print proc_stdout

    subprocess_cmd(['su','-','root','-c','su -s /bin/sh  postgres -c \'psql -U msa ..........])

I just needed to the place the command I was executing as root after -c. So it now switches to the postgres user and finds the data it needs from root returning to the normal user after.


You are misunderstanding what su does. su creates a privileged subprocess; it does not change the privileges of your current process. The commands after su will be executed after su finishes, with your normal privileges.

Instead, you want to pass a -c option to specify the commands you want to run with elevated privileges. (See also the su man page.)

popen_cmd_shell('su -c ls - root')

sudo was specifically designed to simplify this sort of thing, so you should probably be using that instead.

Scripted access to privileged commands is a sticky topic. One common approach is to have your command perform the privileged operation, then drop its privileges. Both from a security and a design point of view, this approach tends to simplify the overall logic. You need to make sure your privileged code is as simple and short as possible--no parsing in the privileged section, for example.

Once the privileged code is properly tested, audited, and frozen, bestowing the script with the required privileges should be a simple matter (although many organizations are paranoid, and basically unable to establish a workable policy for this sort of thing).

Regardless of which approach you take, you should definitely avoid anything with shell=True in any security-sensitive context, and instead pass any external commands as a list, not as a single string.

popen_cmd_shell(['su', '-c', 'ls', '-', 'root'])

(Maybe also rename the function, since you specifically do not want a shell. Obviously, also change the function to specify shell=False.)

Again, these security concerns hold whether you go with dropping privileges, or requesting privilege escalation via su or sudo.