2

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:

  • File can be of any format: text, images, video, etc. therefore I can't decode it.
  • I can't create the file as root and chown it to userA since not even root can access that location.
6
  • 1
    Your context manager is in the main process. i.e with open("/tmp/", mode="wb") , so your file is opened and closed by the main user itself. So file will be created by that user. Commented Mar 23, 2022 at 14:35
  • @Kris ok that was my fear too .. in that case the whole approach needs to be rethought Commented Mar 23, 2022 at 14:36
  • Would you perhaps share some code snippet? :) I am not fully following your train of thought Commented Mar 23, 2022 at 14:40
  • A normal user usually cannot "give away" files to someone else on a UNIX system. The solution is to use group permissions (i.e. create the file with a group containing both the file creator and userA, and appropriate file modes) or ACLs. Arguably this is unrelated to Python or subprocess. Commented Mar 23, 2022 at 14:49
  • Location /data/ is a mounted network share where ACLs are managed externally so the assumption is that no other user than userA can rw into /data/userA Commented Mar 23, 2022 at 14:56

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

7 Comments

If this works, this is the accepted answer !
It won't work yet; fixing it ...
Isn't sudo likely to require a password?
Worst case I get a new trail to follow :)
@ArthurKing I use user parameter which works with setuid but sudo is also possible
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.