在python中以超级用户身份打开文件

时间:2011-09-08 21:37:43

标签: python file-io

我必须打开一个系统文件并从中读取。此文件通常只能由root(超级用户)读取。我有办法向用户询问超级用户密码。我想使用此凭据打开文件并从中读取,而不必将整个程序作为超级用户进程运行。有没有办法以多平台方式实现这一目标?

4 个答案:

答案 0 :(得分:4)

您正在寻找的是特权升级,它在很大程度上取决于您运行的平台。通常,您的程序必须执行的操作是以超级用户身份运行一部分。例如,在unix系统上,您可以使用sudo来读取文件的内容。

但如上所述,这实际上取决于您正在运行的系统。

答案 1 :(得分:4)

由于特权在类Unix系统和Windows上的工作方式完全不同,因此您需要具有特定于平台的代码。在任何情况下,您都需要将程序分解为两个单独的程序,其中一个程序以提升的权限运行,另一个程序以标准/减少的权限运行。

在类Unix系统(包括Linux和Mac OS X)中,使用提升权限运行的可执行文件应该这样做:

  1. 假设您以root用户身份运行并打开文件进行阅读。既然你提到文件非常大,你实际上并没有读取整个文件,你只需保留一个打开的文件描述符。如果打开它失败,请输出错误消息并退出。
  2. 使用setreuid(2)setregid(2)将您的用户ID和组ID设置回非特权用户。
  3. 使用exec(3)函数之一执行非特权可执行文件。
  4. 如果您想要在不使用sudo的情况下运行此程序,请将其归为root所有,并使其成为chown root the-program; chmod +s the-program的set-user-ID可执行文件。
  5. 现在,无权限的程序将以正常权限运行,但是当它启动时,它将具有一个打开的文件描述符(文件描述符#3),可用于从您的特殊文件中读取。

    对于Windows,它类似但略有不同:

    1. 假设您以root身份运行并使用CreateFile打开文件进行阅读。不要使用默认安全属性 - 创建SECURITY_ATTRIBUTES结构,bInheritHandle设置为TRUE,以便句柄将由子进程继承。如果打开文件失败,请输出错误消息并退出。
    2. 使用CreateProcess启动子进程。在命令行上面的句柄中传递(例如打印为数值);你也可以use a shared memory region,但这比这个问题的价值更大。
    3. 此可执行文件中的
    4. Embed a manifestrequireAdministrator设置为true。执行此操作后,当您运行该程序时,您将收到一个UAC提示,询问您是否要允许程序进行更改。
    5. 子进程然后通过解析命令行来抓取继承的句柄,然后它可以随意读取数据。

      这种方法的一个问题是,当你继承一个句柄时,你必须使用低级系统调用(在Unix上为read(2),在Windows上为ReadFile)来读取它 - 你不能使用更高级别的函数,比如C fread(3)或C ++ iostream s(确定,Unix有fdopen(3),但据我所知,在Windows上没有相应的功能。)< / p>

      我确信你已经注意到了,上面的所有内容都是在C语言中。在Unix中,这很简单地转换为Python,因为os module有许多好处,如setreuidexec*fdopen。在Windows上,您可以使用ctypes模块和/或Pywin32来完成这些工作,但是可能更容易使用C语言。

答案 2 :(得分:3)

我会把程序分成两部分。

  1. 处理打开文件并访问内容。它可以假设它以所需的权限开始。
  2. 其他不需要特权的东西。
  3. 添加一个配置条目,该条目描述如何execsubprocess需要额外权限的命令。即

      

    access_special_file:sudo access_special_file

      

    access_special_file:runas / user:AccountWithPrivs access_special_file

    这会将特权升级的一些系统细节卸载到系统shell,在那里可能有更方便的方法来获得所需的权限。

答案 3 :(得分:2)

在Linux上它是一个cynch,如@ViktorKerkez showed。这是我传输WiFi密码文件的方式(只能通过root / sudo读取):

import subprocess
import sys

# substitute your Windoze/DOS/PowerlessShell command here:
cat_wifi_pws = 'sudo cat /etc/NetworkManager/system-connections/*'

process = subprocess.Popen(cat_wifi_pws, stdout=subprocess.PIPE, shell=True)
# read one line at a time, as it becomes available
for line in iter(process.stdout.readline, ''):
    sys.stdout.write(line)

当然这会提示您输入sudo密码。如果您使用的是具有它的系统并且您更喜欢对话框,则可以使用gksudo。作为奖励,如果你在timeout_default中有一个不错的/etc/sudoers,并且你最近在启动了python解释器的同一个shell中运行了sudo,那么你根本不需要输入密码