renatodamas
renatodamas

Reputation: 19475

Write to a file as a different user in Python

I am trying to write bytes to a file. Generally, one could simply do:

...
fb = file.read() # this contains the bytes to copy

with open("/tmp/", "wb") as out:
    out.write(fb)

It works perfectly, but I am trying to make it work with subprocess. Why? Because I need the output file to be created under the ownership of a different user - say userA. And the only way possible I am seeing is user impersonation. An example below:

# runs as root

import subprocess

def run(cmd, **kwargs):
    popen = subprocess.Popen(
        cmd.split(),
        stdout=kwargs.pop("stdout", subprocess.PIPE),
        stderr=kwargs.pop("stderr", subprocess.PIPE),
        user=kwargs.get("user")
    )
    popen.communicate()


dst = "/data/userA" # special (network) location that only userA can access (not even root)
byte_data = file.read() # this contains the bytes to copy
user = "userA"

with open(dst, mode="wb") as out_f:
    cmd = f"echo -n {byte_data}"
    run(cmd=cmd, user=user, stdout=out_f)

If I send a txt file, my content is b"text content".

My limitations:

Upvotes: 2

Views: 872

Answers (1)

chepner
chepner

Reputation: 531165

In shell, sudo tee is sometimes used to replace output redirection to ensure that the correct user opens the file.

# Instead of sudo -u user foo > tmp.txt
foo | sudo -u user tee tmp.txt > /dev/null

You can do the same thing in Python. Note that subprocess.Popen itself can read directly from your input file; you don't need to construct an artificial command.

# tee writes to any named files *and* standard output; by default,
# you probably want to redirect standard output to /dev/null
# or the equivalent.
def copy_to(src, dest_name, user, *, stdout=subprocess.devnull, **kwargs):
    subprocess.run(["tee", dest_name], user=user, stdin=src, **kwargs)

copy_to(file, "/data/userA", "userA")

Essentially, this copy_to is just a wrapper around subprocess.run that runs tee using the given input file, output file name, and user. Any other keyword arguments will be passed directly to subprocess.run.

The key is that tee opens the output file for writing, not your Python script.

Upvotes: 1

Related Questions