我正在为PyQt5应用程序添加功能。此新功能涉及复制、链接和删除可能位于受保护目录中的文件(和链接(,因此os.symlink
或shutil.copyfile
等命令将失败。
当然,主应用程序不是以root权限运行的(要求用户这样做是不可能的(,所以我需要一个变通方法。
第一件事当然是将关键代码封装在try/except块中,并调查任何异常。如果缺少root权限是问题所在,我会在对话框中询问密码(大概是在当前对话框处于活动状态时存储密码(。
但我不确定如何使用根密码重复步骤。我强烈希望在Python域中进行(或者Qt是否为文件操作提供了一些支持?我敢打赌,它确实提供了,但我找不到它(。我认为在shell命令中执行文件操作并以某种方式将密码传递给它应该是可能的,但由于Python和PyQt的设计是为了保护程序员免受操作系统差异的复杂性的影响,我更愿意避免这种途径。
一些伪代码应该能清楚地说明这个问题:
def my_copy(source, dest):
try:
os.path.symlink(source, dest)
except: # check for permission problem:
# use dialog to ask for password
# repeat the symlink procedure with password
在大多数现代操作系统上,您尝试在这里做的事情基本上是不可能的,这是有充分理由的。
想象一下,一个典型的macOS或Windows用户希望能够通过使用指纹读取器而不是键入密码进行身份验证。或者是一个盲人用户。或者有人有理由偏执于你的应用程序将他们的密码以明文形式存储在非内核内存中的Python字符串中(更不用说在Windows对话框中,其事件可以被任何进程钩住(。这就是为什么现代平台带有像libPAM
/XSSO
这样的授权服务框架。等
权限升级的工作方式在Windows和POSIX之间,甚至在macOS和Linux之间都有很大的不同,更不用说发展如此之快,据我所知,还没有跨平台的框架可以做到这一点
事实上,大多数系统一开始就不鼓励应用程序驱动的权限提升。在Windows上,您经常要求操作系统以提升的权限运行助手应用程序(然后操作系统将应用适当的策略并决定要求什么(。在macOS上,您通常会编写一个LaunchServices守护程序,在安装时(使用特殊的安装程序API(而不是运行时获得该守护程序的权限。对于传统的非服务器POSIX应用程序,您通常会做类似的事情,但使用setuid
助手,您可以在安装时创建该助手,因为安装是以root身份运行的。对于传统的POSIX服务器,通常以root身份启动,然后在派生和执行类似的助手守护进程后删除privas。
如果这一切看起来比你想处理的工作多得多……那么,老实说,这可能就是你的意图。操作系统设计者不希望应用程序设计者引入安全漏洞,所以他们确保你必须了解平台想要什么,以及如何使用它而不是对抗它,然后你才能尝试来做一些事情,比如移动你没有权限的文件。
用计数器将try/except代码包装在循环中:
def my_copy(source, dest):
for attempts in [1, 2]:
try:
os.path.symlink(source, dest)
# we succeeded, so don't try any more
break
except: # check for permission problem:
if attempts == 1:
# use dialog to ask for password
# repeat the symlink procedure with password
else:
# we already tried as root, and failed again
break