Reputation: 19475
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:
root
and chown
it to userA
since not even root can access that location.Upvotes: 2
Views: 872
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