How to run long Python script without re-prompt for credentials
Asked Answered
A

1

1

I have a Python script, let's say install.py (which I am running as sudo), on OS X that installs homebrew, Xcode, pip, ruby, swig, and, ultimately, salt. The problem is that running and installing everything (Xcode CLI in partituclar) takes so long to run, that sudo times out, requiring another prompt for admin credentials.

Here's the thing. As part of install.py, before kicking off all the installations, I first create a local admin user by opening a subprocess and use:

make_admin_account = {
    "mkdir -p /Users/%(accountname)s",
    "sudo dscl . -create /Users/%(accountname)s",
    "sudo dscl . -create /Users/%(accountname)s UserShell /bin/bash",
    "sudo dscl . -create /Users/%(accountname)s RealName \"%(fullname)s\"",
    "sudo dscl . -create /Users/%(accountname)s UniqueID \"%(uid)s\"",
    "sudo dscl . -create /Users/%(accountname)s PrimaryGroupID 80",
    "sudo dscl . -create /Users/%(accountname)s NFSHomeDirectory /Users/%(accountname)s",
    "sudo dscl . -passwd /Users/%(accountname)s \"%(password)s\"",
    "sudo dscl . -append /Groups/admin GroupMembership%(accountname)s",
    "sudo dscl . -append /Groups/_appserveradm GroupMembership %(accountname)s",
    "sudo dscl . -append /Groups/_appserverusr GroupMembership %(accountname)s",
    "sudo chown -R %(accountname)s /Users/%(accountname)s",
    "sudo createhomedir -c -u %(accountname)s"
}

So, now we have a local admin account. Pretty simply now, run through each of the installers. Let's jump ahead to where Xcode CLI had been installed, now we're kicking off homebrew:

print("Install Homebrew")
execute("sudo -H -u %s ruby homebrew_ruby" % accountname)

(execute() is just a simple function that's calling subprocess.Popen()) As soon as it encounters sudo, it wants admin credentials again. This is not desired behavior. So, how about passing a preexec_fn to the subprocess and running as the newly created admin account?

def demote(user_uid, user_gid):
    def result():
        os.setgid(user_gid)
        os.getuid(user_uid)
    return result


preexec_fn = demote(pwd.getpwnam(accountname).pw_uid, pwd.getpwnam(accountname).pw_gid)

execute("ruby homebrew_ruby", preexec_fn=preexec_fn)

Again, execute is just taking the preexec_fn argument and passing it to subprocess.Popen. What's returned is:

shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
chdir: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
chdir: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: Permission denied

At this point, I'm thinking my new admin account is setup incorrectly. Exit script, and try su'ing to the new admin account I had just created:

shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied

Looks familiar.

So, to put my desire into a sentence: I'm looking for a way to keep a long Python script from prompting for admin creds after it times out in the default 5 minutes. I know that I could just edit /etc/sudoers:

Defaults    timestamp_timeout=15

That ought to fix it...but I feel like there should be a better solution here that either I'm not seeing or haven't yet explored. If we could run it as a python child process with prexec_fn, that would be ideal.

Acceptor answered 12/9, 2013 at 18:4 Comment(3)
Can you run the program itself as sudo and demote (instead of promote) as needed?Renelle
@Arrieta from first paragraph: "I have a Python script, let's say install.py (which I am running as sudo)". Is that what you mean? Because I am demoting from root to an admin account.Acceptor
If you are running the script itself using sudo, it already has admin privileges, as does every process launched from it. Simply don't use sudo to run the subprocesses.Commencement
H
0

In Python, check your os.getcwd(), you're probably running from a funky place.

Try passing cwd='/tmp' to process.Popen(). Everyone has permissions to /tmp!

Hutchens answered 13/9, 2013 at 22:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.