be sudo and a user in a script

Viewed 111

I have a python script that has to be run in a sequence with and without sudo and with differing command switches.

The sequence is due to each section relying on changes made by the previous section, and the parts that are run with sudo require sudo to run, and the other parts should not be run with sudo.

A much reduced 3 section sample script to illustrate the sections and requiring root/sudo, requiring not root/sudo

#!/usr/bin/env python

import os
import sys


def update():
    if os.geteuid() != 0:
        print("The --config function must run as root.")
        raise SystemExit(0)

    print("About to upgrade your OS")
    os.system("apt-get -y update; apt-get -y dist-upgrade")


def build():
    if os.geteuid() == 0:
        print("This function should not be run as root.")
        raise SystemExit(0)

    if not os.path.isdir("source"):
        os.system("git clone https://path.to/source/source.git")
    else:
        os.system("(chdir source; git pull)")
    os.chdir("source")
    os.system("make")


def install():
    "Install software & start service " \
        "once everything has been tested."
    if os.geteuid() != 0:
        print("The --install function must run as root.")
        raise SystemExit(0)

    os.chdir("source")
    os.system("make install")
    os.system("systemctl daemon-reload")
    os.system("systemctl enable software.service")
    
if __name__ == "__main__":
    if len(sys.argv) < 2 or sys.argv[1] not in ("--update", "--build", "--install":
        raise SystemExit(1)
    
    if sys.argv[1] == "--update":
        update()
    if sys.argv[1] == "--build":
        build()
    if sys.argv[1] == "--install":
        install()

# end

Current method

sudo ./script --update
./script --build
sudo ./script --install

Is there a way to have a single script that can be run with sudo, but then can execute some parts as the non root user that used sudo to run the script?

What I would like to acheive

sudo ./script

Which then runs "update" under sudo, "build" as the user that ran "sudo ./script", "install" under sudo etc.

Using another script to call each of the existing command is not possible as the sudo timeout is reached while running one of the sections and altering the timeout is not possible for political reasons.

tl:dr is is possible to run a python script using sudo, have the python script drop to a normal user to run part of the script, then go back to running as sudo?

1 Answers

You can use subprocess.call(command, user = "me") if python >= 3.9 or prefix your command with sudo -U normal_user if not.

# start with sudo ./script

from os.path import realpath
import sys, subprocess

script = realpath(sys.argv[0])

# parsing command line for sections omitted

# execute_section functions omitted

if section:
    return execute_section(section)

# execution of sections

# python >= 3.9
execute_section("section1") # executed as root
subprocess.call([script, "--session2"], user = "me")
execute_section("section3") # executed as root
subprocess.call([script, "--session4"], user = "me")
execute_section("section5") # executed as root

For python < 3.9, use something like:

subprocess.call(["sudo", "-U", "me", script, "--session2"])

You can also use the Invoke library from fabric.

For a complete, efficient build system in python, I use waf

Related