我必须打开一个系统文件并从中读取。此文件通常只能由root(超级用户)读取。我有办法向用户询问超级用户密码。我想使用此凭据打开文件并从中读取,而不必将整个程序作为超级用户进程运行。有没有办法以多平台方式实现这一目标?
答案 0 :(得分:4)
您正在寻找的是特权升级,它在很大程度上取决于您运行的平台。通常,您的程序必须执行的操作是以超级用户身份运行一部分。例如,在unix系统上,您可以使用sudo
来读取文件的内容。
但如上所述,这实际上取决于您正在运行的系统。
答案 1 :(得分:4)
由于特权在类Unix系统和Windows上的工作方式完全不同,因此您需要具有特定于平台的代码。在任何情况下,您都需要将程序分解为两个单独的程序,其中一个程序以提升的权限运行,另一个程序以标准/减少的权限运行。
在类Unix系统(包括Linux和Mac OS X)中,使用提升权限运行的可执行文件应该这样做:
setreuid(2)
和setregid(2)
将您的用户ID和组ID设置回非特权用户。exec(3)
函数之一执行非特权可执行文件。sudo
的情况下运行此程序,请将其归为root所有,并使其成为chown root the-program; chmod +s the-program
的set-user-ID可执行文件。现在,无权限的程序将以正常权限运行,但是当它启动时,它将具有一个打开的文件描述符(文件描述符#3),可用于从您的特殊文件中读取。
对于Windows,它类似但略有不同:
CreateFile
打开文件进行阅读。不要使用默认安全属性 - 创建SECURITY_ATTRIBUTES
结构,bInheritHandle
设置为TRUE
,以便句柄将由子进程继承。如果打开文件失败,请输出错误消息并退出。CreateProcess
启动子进程。在命令行上面的句柄中传递(例如打印为数值);你也可以use a shared memory region,但这比这个问题的价值更大。requireAdministrator
设置为true
。执行此操作后,当您运行该程序时,您将收到一个UAC提示,询问您是否要允许程序进行更改。子进程然后通过解析命令行来抓取继承的句柄,然后它可以随意读取数据。
这种方法的一个问题是,当你继承一个句柄时,你必须使用低级系统调用(在Unix上为read(2)
,在Windows上为ReadFile
)来读取它 - 你不能使用更高级别的函数,比如C fread(3)
或C ++ iostream
s(确定,Unix有fdopen(3)
,但据我所知,在Windows上没有相应的功能。)< / p>
我确信你已经注意到了,上面的所有内容都是在C语言中。在Unix中,这很简单地转换为Python,因为os
module有许多好处,如setreuid
, exec*
和fdopen
。在Windows上,您可以使用ctypes
模块和/或Pywin32来完成这些工作,但是可能更容易使用C语言。
答案 2 :(得分:3)
我会把程序分成两部分。
添加一个配置条目,该条目描述如何exec
或subprocess
需要额外权限的命令。即
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,那么你根本不需要输入密码