9

i have a simple piece of python script called myCreate.py running on linux:
fo = open("./testFile.txt", "wb")

when i run python ./myCreate.py - the owner of testFile.txt stays my user. when i run sudo python ./myCreate.py - the owner of testFile.txt is now root.

testFile.txt was not run previously to both of the executions

how can i make the owner of the file stay the real user and not the effective user?! Thanks!

iddqd
  • 1,225
  • 2
  • 16
  • 34
  • `chown` it after you create it. – Jim Garrison Sep 11 '14 at 15:32
  • i want it to open as the real user, reagardless of who this is... not something hard-coded – iddqd Sep 11 '14 at 15:36
  • You can determine the current user and chown to that. – Jim Garrison Sep 11 '14 at 15:36
  • 1
    `root` **is** the real user id of your process. The non-root identity is the real user ID of some parent (or grand-parent) process. – Robᵩ Sep 11 '14 at 15:38
  • why is root the real user id of the process? isnt it only the effective user? – iddqd Sep 11 '14 at 15:42
  • 3
    From the [`sudo` man page](http://www.sudo.ws/sudo/sudo.man.html): "When sudo executes a command ... typically, the real and effective uid and gid are set to match those of the target user". – Robᵩ Sep 11 '14 at 15:47
  • See also: `stay_setuid` in [sudoers(5)](http://www.sudo.ws/sudoers.man.html). – Robᵩ Sep 11 '14 at 15:58
  • Alternatively, can you refactor your application so it is like: `def main(): do_root_stuff() ; os.setuid(int(os.environ('SUDO_UID'))) ; do_user_stuff()` ? That way any file created in `do_user_stuff()` will automatically have the correct owner. – Robᵩ Sep 11 '14 at 16:03
  • Instead of relying on environment (what if we are using su or modify privileges in another way?) just use UID of parent directory. – Basilevs Sep 11 '14 at 16:14

3 Answers3

9

Running your script with sudo means you run it as root. So it's normal your file is owned by root.

What you could do is to change the ownership of the file after it is created. In order to do this, you need to know which user runs sudo. Fortunately, there is a SUDO_UID environment variable that is set when you use sudo.

So, you can do:

import os
print(os.environ.get('SUDO_UID'))

Then, you need to change the file ownership:

os.chown("path/to/file", uid, gid)

If we put it together:

import os

uid = int(os.environ.get('SUDO_UID'))
gid = int(os.environ.get('SUDO_GID'))

os.chown("path/to/file", uid, gid)

Of course, you'll want it as a function, because it's more convenient, so:

import os

def fix_ownership(path):
    """Change the owner of the file to SUDO_UID"""

    uid = os.environ.get('SUDO_UID')
    gid = os.environ.get('SUDO_GID')
    if uid is not None:
        os.chown(path, int(uid), int(gid))

def get_file(path, mode="a+"):
    """Create a file if it does not exists, fix ownership and return it open"""

    # first, create the file and close it immediatly
    open(path, 'a').close()

    # then fix the ownership
    fix_ownership(path)

    # open the file and return it
    return open(path, mode)

Usage:

# If you just want to fix the ownership of a file without opening it
fix_ownership("myfile.txt")

# if you want to create a file with the correct rights
myfile = get_file(path)

EDIT: Updated my answer thanks to @Basilevs, @Robᵩ and @5gon12eder

Community
  • 1
  • 1
Agate
  • 3,152
  • 1
  • 19
  • 30
  • Great explanation, but wouldn't `SUDO_UID` be more convenient than `SUDO_USER`? – Robᵩ Sep 11 '14 at 15:57
  • It will be more portable to simply not `chown` the file if `SUDO_USER` is not set. – 5gon12eder Sep 11 '14 at 16:10
  • @Robᵩ, you're right, I've updated my answer with SUDO_UID. Basilevs, does it solve the encoding issue ? 5gon12eder, Ah, thanks for pointing this, I've edited my answer. – Agate Sep 11 '14 at 16:19
  • Assuming you're potentially creating a new file with the line `open(path, 'a').close()` in your `get_file` method, wouldn't you want to use `'a+'`? –  Sep 11 '14 at 16:46
  • @EliotBerriot well, we can't do more here :) – Basilevs Sep 11 '14 at 16:57
  • @iChar, you're right, i'l edit my answer accordingly. Thanks. – Agate Sep 12 '14 at 08:26
  • This only covers if user comes directly from sudo not from _root_. i.e. this won't work if user is root (e.g. via sudo su). @cbrendanprice answer is more correct. – Granitosaurus Feb 18 '18 at 05:58
2

How about using os.stat to first get the permissions of the containing folder and then applying them to the file post creation.

this would look something like (using python2):

import os

path = os.getcwd()
statinfo = os.stat(path)

fo = open("./testFile.txt", "wb")
fo.close()
euid = os.geteuid()
if (euid == 0) # Check if ran as root, and set appropriate permissioning afterwards to avoid root ownership
    os.chown('./testFile.txt', statinfo.st_uid, statinfo.st_gid)

As Elliot pointed out, if you were to be creating several files simultaneously, this would be better structured as a function.

cbrendanprice
  • 420
  • 4
  • 9
2

Use os.chown(), using os.environ to find the appropriate user id:

import os

fo = open("./testFile.txt", "wb")
fo.close()
os.chown('./testFile.txt',
         int(os.environ['SUDO_UID']),
         int(os.environ['SUDO_GID']))
Robᵩ
  • 163,533
  • 20
  • 239
  • 308