Получить корневой диалог в Python на Mac OS X, Windows? - PullRequest
5 голосов
/ 21 апреля 2011

Как бы я мог получить диалоговое окно повышения привилегий в моем приложении Python?Мне нужен диалог UAC в Windows и диалог аутентификации по паролю в Mac.

По сути, мне нужны привилегии root для части моего приложения, и мне нужно получить эти привилегии через графический интерфейс.Я использую wxPython.Есть идеи?

Ответы [ 3 ]

4 голосов
/ 25 апреля 2011

В Windows вы не можете получить диалоговое окно UAC без запуска нового процесса, и вы даже не можете запустить этот процесс с помощью CreateProcess.

Диалог UAC можно вызвать, запустив другое приложение с соответствующим файлом манифеста.- см. Запуск скомпилированного python (py2exe) от имени администратора в Vista , чтобы узнать, как сделать это с py2exe.

Вы также можете программно использовать глагол 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.

Извините, не знаю, как работает Mac.Если вы дадите больше подробностей о том, что вы хотите сделать в Windows, я мог бы предоставить более конкретную помощь.

2 голосов
/ 19 января 2016

Я знаю, что пост немного устарел, но я написал следующее в качестве решения моей проблемы (запуск сценария python от имени root как в Linux, так и в OS X).

Я написал следующий 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 / pyscripts в / usr / local / bin) и создайте символические ссылки на исполняемые файлы.Для меня это имеет три преимущества:

(1) Если у меня есть разные версии, я легко могу выбрать, какая из них выполняется, изменив символическую ссылку, и она сохранит каталог bin более чистым (например, / usr / local / bin/gcc-versions/4.9/, /usr/local/bin/gcc-versions/4.8/, / usr / local / bin / gcc -> gcc-version / 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

в мой файл hosts (который доступен для записи только суперпользователю).

Если вы хотите упростить / изменить его для запуска только определенных команд от имени пользователя 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)

Используя вышеупомянутое (в rмодуль un_command):

>>> ret = run_command.run_as_root("/usr/local/bin/pyscripts/TrackingBlocker.py", ["status", "display"])
>>> /etc/hosts is blocking approximately 16147 domains
1 голос
/ 13 августа 2015

У меня та же проблема в 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.osascript можно использовать для запуска яблочного сценария и других вещей.Я использую его следующим образом:

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 и передать их на терминал, запускающий оригинальный процесс.

...