使用Python中的sudo权限写入文件

时间:2016-09-14 20:34:55

标签: python file-writing ioerror

如果非root用户针对root拥有的文件运行以下代码,则会抛出错误,即使非root用户具有sudo权限:

try:
  f = open(filename, "w+")
except IOError:
  sys.stderr.write('Error: Failed to open file %s' % (filename))
f.write(response + "\n" + new_line)
f.close()

有没有办法使用sudo权限运行open(filename, "w+"),或者执行此操作的替代函数?

5 个答案:

答案 0 :(得分:6)

您有几个选择:

  • 以root身份或使用sudo
  • 运行脚本
  • 设置setuid位并让root拥有该脚本(尽管在许多系统上这不适用于脚本,然后脚本可以被任何人调用)
  • 检测到您没有以root用户身份运行(os.geteuid() != 0),然后使用sudo infront(要求用户输入密码)自行呼叫并退出:

import os
import sys
import subprocess

if os.geteuid() == 0:
    print("We're root!")
else:
    print("We're not root.")
    subprocess.call(['sudo', 'python3', *sys.argv])

调用它看起来像这样:

$ python3 be_root.py
We're not root.
Password:
We're root!

答案 1 :(得分:5)

TL; DR:

L3viathan's reply 有一个SynaxError 编辑:在Python 3.5+上运行正常。这是Python 3.4.3的一个版本(在Ubuntu 16.04上默认发布)及以下版本:

if os.geteuid() == 0:
    # do root things
else:
    subprocess.call(['sudo', 'python3'] + sys.argv)  # modified

但是,我采用了不同的方法,因为它使我的用例中的代码更简单:

if os.geteuid() != 0:
    os.execvp('sudo', ['sudo', 'python3'] + sys.argv)
# do root things

L3viathan's reply取决于PEP 448,它包含在Python 3.5中,并引入了允许星形参数扩展的其他上下文。对于Python 3.4及更低版本,列表连接可用于执行相同的操作:

import os
import sys
import subprocess

if os.geteuid() == 0:
    print("We're root!")
else:
    print("We're not root.")
    subprocess.call(['sudo', 'python3'] + sys.argv)  # modified

注意: subprocess.call()启动子进程,这意味着在root完成运行脚本后,原始用户也将继续运行其脚本。这意味着您需要将提升的逻辑放在if/else块的一侧,这样当原始脚本完成时,它不会尝试运行任何需要提升的逻辑(L3viathan&'s示例)这样做。)

这不一定是坏事 - 这意味着正常/提升的逻辑可以写在同一个脚本中并且很好地分开 - 但是我的任务需要所有逻辑的根。如果另一个块空无一人,我不想浪费一个缩进级别,我还没有意识到使用子进程会影响事情,所以我尝试了这个:

import os
import sys
import subprocess

if os.geteuid() != 0:
    subprocess.call(['sudo', 'python3'] + sys.argv)

# do things that require root

...它当然打破了,因为在root完成后,普通用户恢复执行其脚本并尝试运行需要root的语句。

然后我发现this Gist推荐os.execvp() - 它取代了正在运行的进程,而不是启动一个孩子:

import os
import sys

if os.geteuid() != 0:
    os.execvp('sudo', ['sudo', 'python3'] + sys.argv)  # final version

# do things that require root

这看似按预期运行,保存缩进级别和3行代码。

警告:我十分钟前都不知道os.execvp(),并且对于使用它可能存在的陷阱或细微之处一无所知。 YMMV。

答案 2 :(得分:1)

如果您实际上没有使用它,则有可能使用sudo不会给您任何特权。因此,正如其他人建议您可能应该使用sudo启动您的程序。但如果你不喜欢这个想法(我没有看到任何理由),你可以做其他的伎俩。

您的脚本可以检查是否以root权限运行,或者它是否仅以用户权限运行。比脚本实际上可以使用更高的权限运行自己。这里有一个例子(请注意,在源代码中存储密码不是一个好主意)。

import os.path
import subprocess

password_for_sudo = 'pass'

def started_as_root():
    if subprocess.check_output('whoami').strip() == 'root':
        return True
    return False

def runing_with_root_privileges():
    print 'I have the power!'

def main():
    if started_as_root():
        print 'OK, I have root privileges. Calling the function...'
        runing_with_root_privileges()
    else:
        print "I'm just a user. Need to start new process with root privileges..."
        current_script = os.path.realpath(__file__)
        os.system('echo %s|sudo -S python %s' % (password_for_sudo, current_script))

if __name__ == '__main__':
    main()

输出:

$ python test.py
I'm just a user. Need to start new process with root privileges...
OK, I have root privileges. Calling the function...
I have the power!

$ sudo python test.py
OK, I have root privileges.
Calling the function...
I have the power!

答案 3 :(得分:0)

您的脚本仅限于运行它的权限,因为您无法在没有root权限的情况下更改用户。

正如Rob所说,在不更改文件权限的情况下执行此操作的唯一方法是使用sudo运行。

sudo python ./your_file.py

答案 4 :(得分:0)

另一种选择是将文件写入您有权访问的目录,然后sudo mv将文件写入您无权访问的目录。