我将如何去得到一个特权提升对话框popup我的Python应用程序? 我需要Windows上的UAC对话框和Mac上的密码authentication对话框。
基本上,我需要部分应用程序的root权限,我需要通过GUI获得这些权限。 我正在使用wxPython。 有任何想法吗?
在Windows上,如果不启动新进程,就无法获得UAC对话框,甚至无法使用CreateProcess启动该进程。
UAC对话框可以通过运行具有相应清单文件的另一个应用程序来实现 – 请参阅在Vista中以管理员身份运行编译的python(py2exe),以获取如何使用py2exe执行此操作的示例。
您也可以编程方式使用win32 api ShellExecute的runas动词http://msdn.microsoft.com/en-us/library/bb762153(v=vs.85).aspx – 您可以通过使用ctypes http:/ /python.net/crew/theller/ctypes/是python 2.5+ iirc标准库的一部分。
对不起,不知道关于Mac。 如果您在Windows上提供更多关于您想要完成的细节,我可能会提供更具体的帮助。
我知道这个帖子有点旧了,但是我写了下面的内容作为我的问题的解决方案(在Linux和OS X上以root身份运行python脚本)。
我写了下面的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
基本上,我设置系统的方式是将bin目录下的子文件夹(例如/ usr / local / bin中的/ usr / local / bin / pyscript)保存在内,并创建可执行文件的符号链接。 这对我有三个好处:
(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)我可以存储这些脚本的扩展名(IDE中有助于语法突出显示),但是可执行文件不包含它们,因为我喜欢它(例如svn-tools – > pyscripts / svn-tools.py)
(3)我将在下面展示的原因是:
我将脚本命名为“run-as-root-wrapper”,并将其放在一个非常普通的路径中(例如/ usr / local / bin),这样python就不需要任何特殊的东西来定位它了。 然后我有以下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
在我的实际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)
因此,如果我有一个名为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]
例如
ModifyTrackingBlocker add tracker.ads.com
执行:
/usr/local/bin/run-as-root-wrapper /usr/local/bin/pyscripts/TrackingBlocker.py add tracker.ads.com
然后显示需要获得授权添加的认证对话框:
127.0.0.1 tracker.ads.com
我的主机文件(这是只有超级用户可写)。
如果你想简化/修改它只以root身份运行某些命令,你可以简单地把它添加到你的脚本中(必要的导入在上面注明+导入子进程):
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)
使用上面的(在run_command模块中):
>>> ret = run_command.run_as_root("/usr/local/bin/pyscripts/TrackingBlocker.py", ["status", "display"]) >>> /etc/hosts is blocking approximately 16147 domains
我在Mac OS X上有同样的问题。我有一个工作解决方案,但它不是最佳的。 我会在这里解释我的解决方案,并继续寻找更好的解决方案。
在程序开始时,我通过执行来检查我是否是root用户
def _elevate(): """Elevate user permissions if needed""" if platform.system() == 'Darwin': try: os.setuid(0) except OSError: _mac_elevate()
os.setuid(0)将失败,如果我还不是root的,这将触发_mac_elevate()重新启动我的程序从管理员的帮助下开始我的程序。 osascript可以用来执行applescript和其他的东西。 我这样使用它:
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)
这个问题是,如果我使用上面的subprocess.call我保持当前进程运行,将有两个我的应用程序运行给出两个停靠栏图标的实例。 如果我使用subprocess.Popen,并让非特权进程立即死亡,我不能使用退出代码,也不能获取stdout / stderr流并传播到终端启动原始进程。