简体   繁体   English

在Mac OS X,Windows上用Python获取root对话框?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM