[英]Get root dialog in Python on Mac OS X, Windows?
How would I go about getting a privilege elevation dialog to pop up in my Python app? 我如何获得在我的Python应用程序中弹出的权限提升对话框? I want the UAC dialog on Windows and the password authentication dialog on Mac.
我想要Windows上的UAC对话框和Mac上的密码验证对话框。
Basically, I need root privileges for part of my application and I need to get those privileges through the GUI. 基本上,我需要部分应用程序的root权限,我需要通过GUI获得这些权限。 I'm using wxPython.
我正在使用wxPython。 Any ideas?
有任何想法吗?
On Windows you cannot get the UAC dialog without starting a new process, and you cannot even start that process with CreateProcess. 在Windows上,如果不启动新进程,则无法获取UAC对话框,甚至无法使用CreateProcess启动该进程。
The UAC dialog can be brought about by running another application that has the appropriate manifest file - see Running compiled python (py2exe) as administrator in Vista for an example of how to do this with py2exe. 可以通过运行具有相应清单文件的另一个应用程序来实现UAC对话框 - 请参阅在Vista中以管理员身份运行编译的python(py2exe),以获取如何使用py2exe执行此操作的示例。
You can also programatically use the runas verb with the win32 api ShellExecute http://msdn.microsoft.com/en-us/library/bb762153(v=vs.85).aspx - you can call this by using ctypes http://python.net/crew/theller/ctypes/ which is part of the standard library on python 2.5+ iirc. 你也可以编程方式使用runas动词与win32 api ShellExecute http://msdn.microsoft.com/en-us/library/bb762153(v=vs.85).aspx - 你可以通过使用ctypes来调用它:http:/ /python.net/crew/theller/ctypes/是python 2.5+ iirc上标准库的一部分。
Sorry don't know about Mac. 抱歉,不知道Mac。 If you give more detail on what you want to accomplish on Windows I might be able to provide more specific help.
如果您提供有关要在Windows上完成的内容的更多详细信息,我可以提供更具体的帮助。
I know the post is a little old, but I wrote the following as a solution to my problem (running a python script as root on both Linux and OS X). 我知道帖子有点旧,但我写了以下内容作为我的问题的解决方案(在Linux和OS X上以root身份运行python脚本)。
I wrote the following bash-script to execute bash/python scripts with administrator privileges (works on Linux and OS X systems): 我编写了以下bash脚本来执行具有管理员权限的bash / python脚本(适用于Linux和OS X系统):
#!/bin/bash
if [ -z "$1" ]; then
echo "Specify executable"
exit 1
fi
EXE=$1
available(){
which $1 >/dev/null 2>&1
}
platform=`uname`
if [ "$platform" == "Darwin" ]; then
MESSAGE="Please run $1 as root with sudo or install osascript (should be installed by default)"
else
MESSAGE="Please run $1 as root with sudo or install gksu / kdesudo!"
fi
if [ `whoami` != "root" ]; then
if [ "$platform" == "Darwin" ]; then
# Apple
if available osascript
then
SUDO=`which osascript`
fi
else # assume Linux
# choose either gksudo or kdesudo
# if both are avilable check whoch desktop is running
if available gksudo
then
SUDO=`which gksudo`
fi
if available kdesudo
then
SUDO=`which kdesudo`
fi
if ( available gksudo && available kdesudo )
then
if [ $XDG_CURRENT_DESKTOP = "KDE" ]; then
SUDO=`which kdesudo`;
else
SUDO=`which gksudo`
fi
fi
# prefer polkit if available
if available pkexec
then
SUDO=`which pkexec`
fi
fi
if [ -z $SUDO ]; then
if available zenity; then
zenity --info --text "$MESSAGE"
exit 0
elif available notify-send; then
notify-send "$MESSAGE"
exit 0
elif available xmessage notify-send; then
xmessage -buttons Ok:0 "$MESSAGE"
exit 0
else
echo "$MESSAGE"
fi
fi
fi
if [ "$platform" == "Darwin" ]
then
$SUDO -e "do shell script \"$*\" with administrator privileges"
else
$SUDO $@
fi
Basically, the way I set up my system is that I keep subfolders inside the bin directories (eg /usr/local/bin/pyscripts in /usr/local/bin), and create symbolic links to the executables. 基本上,我设置系统的方式是将子文件夹保存在bin目录中(例如/ usr / local / bin中的/ usr / local / bin / pyscripts),并创建指向可执行文件的符号链接。 This has three benefits for me:
这对我有三个好处:
(1) If I have different versions, I can easily switch which one is executed by changing the symbolic link and it keeps the bin directory cleaner (eg /usr/local/bin/gcc-versions/4.9/, /usr/local/bin/gcc-versions/4.8/, /usr/local/bin/gcc --> gcc-versions/4.8/gcc) (1)如果我有不同的版本,我可以通过更改符号链接轻松切换执行哪个版本,并使bin目录保持清洁(例如/usr/local/bin/gcc-versions/4.9/,/ usr / local / bin / gcc-versions / 4.8 /,/ usr / local / bin / gcc - > gcc-versions / 4.8 / gcc)
(2) I can store the scripts with their extension (helpful for syntax highlighting in IDEs), but the executables do not contain them because I like it that way (eg svn-tools --> pyscripts/svn-tools.py) (2)我可以使用它们的扩展名存储脚本(有助于IDE中的语法高亮显示),但可执行文件不包含它们,因为我喜欢它(例如svn-tools - > pyscripts / svn-tools.py)
(3) The reason I will show below: (3)我将在下面显示的原因:
I name the script "run-as-root-wrapper" and place it in a very common path (eg /usr/local/bin) so python doesn't need anything special to locate it. 我将脚本命名为“run-as-root-wrapper”并将其放在一个非常常见的路径中(例如/ usr / local / bin),因此python不需要任何特殊的东西来定位它。 Then I have the following run_command.py module:
然后我有以下run_command.py模块:
import os
import sys
from distutils.spawn import find_executable
#===========================================================================#
def wrap_to_run_as_root(exe_install_path, true_command, expand_path = True):
run_as_root_path = find_executable("run-as-root-wrapper")
if(not run_as_root_path):
return False
else:
if(os.path.exists(exe_install_path)):
os.unlink(exe_install_path)
if(expand_path):
true_command = os.path.realpath(true_command)
true_command = os.path.abspath(true_command)
true_command = os.path.normpath(true_command)
f = open(exe_install_path, 'w')
f.write("#!/bin/bash\n\n")
f.write(run_as_root_path + " " + true_command + " $@\n\n")
f.close()
os.chmod(exe_install_path, 0755)
return True
In my actual python script, I have the following function: 在我的实际python脚本中,我有以下功能:
def install_cmd(args):
exe_install_path = os.path.join(args.prefix,
os.path.join("bin", args.name))
if(not run_command.wrap_to_run_as_root(exe_install_path, sys.argv[0])):
os.symlink(os.path.realpath(sys.argv[0]), exe_install_path)
So if I have a script called TrackingBlocker.py (actual script I use to modify the /etc/hosts file to re-route known tracking domains to 127.0.0.1), when I call "sudo /usr/local/bin/pyscripts/TrackingBlocker.py --prefix /usr/local --name ModifyTrackingBlocker install" (arguments handled via argparse module), it installs "/usr/local/bin/ModifyTrackingBlocker", which is a bash script executing 因此,如果我有一个名为TrackingBlocker.py的脚本(我用来修改/ etc / hosts文件以将已知跟踪域重新路由到127.0.0.1的实际脚本),当我调用“sudo / usr / local / bin / pyscripts /”时TrackingBlocker.py --prefix / usr / local --name ModifyTrackingBlocker install“(通过argparse模块处理的参数),它安装”/ usr / local / bin / ModifyTrackingBlocker“,这是一个bash脚本执行
/usr/local/bin/run-as-root-wrapper /usr/local/bin/pyscripts/TrackingBlocker.py [args]
eg 例如
ModifyTrackingBlocker add tracker.ads.com
executes: 执行:
/usr/local/bin/run-as-root-wrapper /usr/local/bin/pyscripts/TrackingBlocker.py add tracker.ads.com
which then displays the authentification dialog needed to get the privileges to add: 然后显示获取添加权限所需的身份验证对话框:
127.0.0.1 tracker.ads.com
to my hosts file (which is only writable by a superuser). 到我的主机文件(只能由超级用户写入)。
If you want to simplify/modify it to run only certain commands as root, you could simply add this to your script (with the necessary imports noted above + import subprocess): 如果您想简化/修改它以仅以root身份运行某些命令,您只需将其添加到您的脚本中(使用上面提到的必要导入+ import subprocess):
def run_as_root(command, args, expand_path = True):
run_as_root_path = find_executable("run-as-root-wrapper")
if(not run_as_root_path):
return 1
else:
if(expand_path):
command = os.path.realpath(command)
command = os.path.abspath(command)
command = os.path.normpath(command)
cmd = []
cmd.append(run_as_root_path)
cmd.append(command)
cmd.extend(args)
return subprocess.call(' '.join(cmd), shell=True)
Using the above (in run_command module): 使用上面的(在run_command模块中):
>>> ret = run_command.run_as_root("/usr/local/bin/pyscripts/TrackingBlocker.py", ["status", "display"])
>>> /etc/hosts is blocking approximately 16147 domains
I'm having the same problem on Mac OS X. I have a working solution, but it's not optimal. 我在Mac OS X上遇到了同样的问题。我有一个可行的解决方案,但它并不是最佳的。 I will explain my solution here and continue looking for a better one.
我将在这里解释我的解决方案并继续寻找更好的解决方案。
At the beginning of the program I check if I'm root or not by executing 在程序开始时,我通过执行检查我是否是root用户
def _elevate():
"""Elevate user permissions if needed"""
if platform.system() == 'Darwin':
try:
os.setuid(0)
except OSError:
_mac_elevate()
os.setuid(0) will fail if i'm not already root and that will trigger _mac_elevate() which relaunch my program from the start as administrator with the help of osascript. os.setuid(0)将失败,如果我还不是root,那将触发_mac_elevate(),它在管理员的帮助下从osascript开始重新启动我的程序。 osascript can be used to execute applescript and other stuff.
osascript可用于执行applescript和其他东西。 I use it like this:
我这样使用它:
def _mac_elevate():
"""Relaunch asking for root privileges."""
print "Relaunching with root permissions"
applescript = ('do shell script "./my_program" '
'with administrator privileges')
exit_code = subprocess.call(['osascript', '-e', applescript])
sys.exit(exit_code)
The problem with this is if I use subprocess.call as above I keep the current process running and there will be two instances of my app running giving two dock icons. 这个问题是如果我使用subprocess.call,如上所述我保持当前进程运行,我的应用程序将运行两个实例,给出两个停靠图标。 If I use subprocess.Popen instead and let the non-priviledged process die instantly I can't make use of the exit code, nor can I fetch the stdout/stderr streams and propagate to the terminal starting the original process.
如果我使用subprocess.Popen而让非特权进程立即死亡我无法使用退出代码,也无法获取stdout / stderr流并传播到终端开始原始进程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.