2011-04-21 100 views
5

我将如何获得一个特权提升对话框,以在我的Python应用程序中弹出?我需要Windows上的UAC对话框和Mac上的密码认证对话框。在Mac OS X,Windows上获取Python中的root对话框?

基本上,我需要部分应用程序的root权限,我需要通过GUI获得这些权限。我正在使用wxPython。有任何想法吗?

+0

不知道,如果你能在OSX做到这一点,通过Python脚本。在一些类Unix操作系统(包括OS X)下,不能授予脚本(如shell,perl,python等)来调用chown/chgrp,这会给你其他特权。 – Drake 2011-04-21 16:33:08

回答

4

在Windows上,如果不启动新进程就无法获得UAC对话框,甚至无法使用CreateProcess启动该进程。

可以通过运行具有相应清单文件的另一个应用程序来实现UAC对话框 - 有关如何使用py2exe执行此操作的示例,请参阅Running compiled python (py2exe) as administrator in Vista

您也可以通过编程使用runas动词用的Win32 API的ShellExecute http://msdn.microsoft.com/en-us/library/bb762153(v=vs.85).aspx - 您可以通过使用ctypes的http://python.net/crew/theller/ctypes/这是蟒蛇2.5+ IIRC标准库的一部分调用它。

对不起,不知道Mac。如果您在Windows上提供更多关于您想要完成的细节,我可能会提供更具体的帮助。

1

我在Mac OS X上遇到了同样的问题。我有一个工作解决方案,但它不是最优的。我会在这里解释我的解决方案,并继续寻找更好的解决方案。

在节目的一开始我检查我的根或不执行

def _elevate(): 
    """Elevate user permissions if needed""" 
    if platform.system() == 'Darwin': 
     try: 
      os.setuid(0) 
     except OSError: 
      _mac_elevate() 

os.setuid如果我没有根(0)将失败,将触发_mac_elevate()从osascript的帮助下,以管理员身份重新启动我的程序。 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流并传播到启动原始进程的终端。

2

我知道这个帖子有点旧了,但是我写了以下内容作为我的问题的解决方案(在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 [email protected] 
fi 

基本上,我建立了我的系统的方式就是,我不断bin目录内的子文件夹(例如/ usr/local/bin中的/ usr/local/bin/pyscripts),并创建与可执行文件的符号链接。这对我有三个好处:(1)如果我有不同的版本,我可以通过更改符号链接轻松切换执行哪个版本,并保持bin目录清洁(例如/ usr/local/bin/gcc -version/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)的原因我下面会显示:

我的名字脚本“运行为根 - 包装”,并将其放置在一个很普通的路径(例如,/ 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 + " [email protected]\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(实际脚本脚本我当我调用“sudo /usr/local/bin/pyscripts/TrackingBlocker.py --prefix/usr/local --name ModifyTrackingBlocker时,使用修改/ etc/hosts文件将已知跟踪域重新路由到127.0.0.1)安装“(参数通过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