Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python subprocess popen execute as different user

I am trying to execute a command in python 3.6 as a different user with popen from subprocess but it will still execute as the user who called the script (i plan to call it as root). I am using threads and therefore it is important that i don't violate the user rights when 2 threads execute in parallel.

proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                          shell=True,
                          env={'FOO':'bar', 'USER':'www-data'},
                          stdout=subprocess.PIPE)

The example above will still create the myFile.txt with my user_id 1000

I tried different approaches :

  1. tried with as described in Run child processes as different user from a long running Python process by copying the os.environment and changed the user, etc
    (note this is for python 2)

  2. tried with as described in https://docs.python.org/3.6/library/subprocess.html#popen-constructor by using start_new_session=True

My Last option is to prefix the command with sudo -u username command but i don't think this is the elegant way.

like image 947
Chris Avatar asked Oct 18 '25 18:10

Chris


1 Answers

The standard way [POSIX only] would be to use preexec_fn to set gid and uid as described in more detail in this answer

Something like this should do the trick -- for completeness I've also modified your initial snippet to include the other environment variables you'd likely want to set, but just setting preexec_fn should be sufficient for the simple command you are running:

import os, pwd, subprocess

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

def exec_cmd(username):
    # get user info from username
    pw_record = pwd.getpwnam(username)
    homedir = pw_record.pw_dir
    user_uid = pw_record.pw_uid
    user_gid = pw_record.pw_gid
    env = os.environ.copy()
    env.update({'HOME': homedir, 'LOGNAME': username, 'PWD': os.getcwd(), 'FOO': 'bar', 'USER': username})

    # execute the command
    proc = subprocess.Popen(['echo $USER; touch myFile.txt'],
                              shell=True,
                              env=env,
                              preexec_fn=demote(user_uid, user_gid),
                              stdout=subprocess.PIPE)
    proc.wait()


exec_cmd('www-data')

Note that you'll also need to be sure the current working directory is accessible (e.g. for writing) by the demoted user since not overriding it explicitly

like image 70
lemonhead Avatar answered Oct 20 '25 07:10

lemonhead