0

I have a python app that run bash shell commands that require root priviledges. In terminal I type "sudo python3 main.py" then load python app file. Python app run mostly sudo commands so I always have to run it with sudo python3 main.py. In the main.py file in the beginning I have import settings.py file that save some important settings. settings.py file read and write INI File in home folder /home/username/.config/myapp/config.ini. So when I run the main.py app the settings.py create a folder myapp inside /home/username/.config/ and then create the config.ini filename.

The problem is tha because I run the main.py app with sudo the folder myapp and config.ini file created with root owner. How can I avoid that?

I would like to import whole file settings.py as normal user.

main.py

#!/usr/bin/python3
import os
import sys
import subprocess
import settings

....
....

settings.py

import configparser

# Create directory
dirName = '/home/username/.config/myapp'

# Create target directory & all intermediate directories if don't exists
try:
    os.makedirs(dirName)
    print("Directory ", dirName, " Created ")
except FileExistsError:
    print("Directory ", dirName, " already exists")

filename = "/home/username/.config/myapp/config.ini"

# Writing Data
config = configparser.ConfigParser()
config.read(filename)

try:
    config.add_section("ethernet")
except configparser.DuplicateSectionError:
    pass

config.set("ethernet", "wired", "")
config.set("ethernet", "wired_mac_address", "")

try:
    config.add_section("wifi")
except configparser.DuplicateSectionError:
    pass

config.set("wifi", "wireless", "")
config.set("wifi", "wireless_mac_address", "")

with open(filename, "w") as config_file:
    config.write(config_file)

# Reading Data
config.read(filename)
keys = [
    "wired",
    "wired_mac_address"
]
for key in keys:
    try:
        value = config.get("ethernet", key)
        print(f"{key}:", value)
    except configparser.NoOptionError:
        print(f"No option '{key}' in section 'ethernet'")

# Reading Data
config.read(filename)
keys = [
    "wireless",
    "wireless_mac_address"
]

for key in keys:
    try:
        value = config.get("wifi", key)
        print(f"{key}:", value)
    except configparser.NoOptionError:
        print(f"No option '{key}' in section 'wifi'")
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • You could change the owner of the file before exiting the script. You can't execute it as normal user, due to the super user permissions needed to run network commands, – scmanjarrez Apr 30 '22 at 15:53
  • @Sr.S Which file? settings.py? I don't understand what do you mean. – user14795102 Apr 30 '22 at 16:12
  • I'm talking about config.ini, that file will be created with root owner because of sudo. Look at this https://stackoverflow.com/questions/25791311/creating-a-file-with-python-using-sudo-makes-its-owner-root – scmanjarrez Apr 30 '22 at 16:17

1 Answers1

1

One approach is to use os.chown() method in the built-in os module. Using this method you can save, create, and edit files and directories as the root user and then change the ownership immediately afterwards to whatever user you want.

import os  #  <---  import the module
import configparser

# change this to the UID of the user you
# want owning the files/directories
uid = 1000 # non-privileged user
ugid = 1000  # non-priveleged user's group


# Create directory
dirName = '/home/username/.config/myapp'

# Create target directory & all intermediate directories if don't exists
try:
    os.makedirs(dirName)
    os.chown(dirName, uid, ugid)
    print("Directory ", dirName, " Created ")
except FileExistsError:
    os.chown(dirName, uid, ugid)
    print("Directory ", dirName, " already exists")

filename = "/home/username/.config/myapp/config.ini"

if os.path.exists(filename):
    os.chown(filename, uid, ugid)  

# Writing Data
config = configparser.ConfigParser()
config.read(filename)

try:
    config.add_section("ethernet")
except configparser.DuplicateSectionError:
    pass

config.set("ethernet", "wired", "")
config.set("ethernet", "wired_mac_address", "")

try:
    config.add_section("wifi")
except configparser.DuplicateSectionError:
    pass

config.set("wifi", "wireless", "")
config.set("wifi", "wireless_mac_address", "")

with open(filename, "w") as config_file:
    config.write(config_file)  # <--- write the file as root
os.chown(filename, uid, ugid)  # <--- change ownership 

# Reading Data
config.read(filename)
keys = [
    "wired",
    "wired_mac_address"
]
for key in keys:
    try:
        value = config.get("ethernet", key)
        print(f"{key}:", value)
    except configparser.NoOptionError:
        print(f"No option '{key}' in section 'ethernet'")

# Reading Data
config.read(filename)
keys = [
    "wireless",
    "wireless_mac_address"
]

for key in keys:
    try:
        value = config.get("wifi", key)
        print(f"{key}:", value)
    except configparser.NoOptionError:
        print(f"No option '{key}' in section 'wifi'")

Just run that same method os.chown(path, uid, gid) anytime you create a new file or folder as root, and it will change the ownership to a non-privileged user of your choice.

Hopefully this helps.

Alexander
  • 16,091
  • 5
  • 13
  • 29
  • I put it in the beginning of the settings.py file. I didn't work. I cannot understand the link with docs. There isn't examples! – user14795102 Apr 30 '22 at 18:25
  • @user14795102 I changed my answer because the previous method doesn't work for all flavors of unix... See the current example for a more universal method. – Alexander Apr 30 '22 at 20:55
  • It doesn't work.It shows the error message `οs.chown(dirName, userid, userid) NameError: name 'οs' is not defined` – user14795102 May 01 '22 at 05:24
  • did you include the `import os` line at the very top? – Alexander May 01 '22 at 06:03
  • Yes, there is on top. I think It needs gid for folders. This line `os.chown(dirName, uid, gid)` is the problem. – user14795102 May 02 '22 at 10:56
  • @user14795102 I made some changes to the script. If you are still getting errors please post the whole traceback along with error message. – Alexander May 02 '22 at 21:25