2011-04-21 24 views
5

¿Qué debo hacer para que aparezca un cuadro de diálogo de elevación de privilegios en mi aplicación Python? Quiero el diálogo de UAC en Windows y el cuadro de diálogo de autenticación de contraseña en Mac.Obtener el cuadro de diálogo raíz en Python en Mac OS X, Windows?

Básicamente, necesito privilegios de root para parte de mi aplicación y necesito obtener esos privilegios a través de la GUI. Estoy usando wxPython. ¿Algunas ideas?

+0

No estoy seguro si puede hacerlo a través de la secuencia de comandos python en OSX. Bajo algún sistema operativo tipo Unix (OS X incluido), los scripts (como shell, perl, python, ...) no pueden ser otorgados para llamar a chown/chgrp, que le da otros privilegios. – Drake

Respuesta

4

En Windows no puede obtener el cuadro de diálogo UAC sin iniciar un nuevo proceso, y ni siquiera puede iniciar ese proceso con CreateProcess.

El cuadro de diálogo UAC se puede generar ejecutando otra aplicación que tenga el archivo de manifiesto apropiado; consulte Running compiled python (py2exe) as administrator in Vista para ver un ejemplo de cómo hacerlo con py2exe.

También puede utilizar mediante programación el verbo de runa con la API de Win32 ShellExecute http://msdn.microsoft.com/en-us/library/bb762153(v=vs.85).aspx - se puede llamar a esto mediante el uso ctypes http://python.net/crew/theller/ctypes/ que es parte de la biblioteca estándar de Python 2.5+ IIRC.

Lo siento no sé sobre Mac. Si proporciona más detalles sobre lo que desea lograr en Windows, podría brindarle ayuda más específica.

1

Estoy teniendo el mismo problema en Mac OS X. Tengo una solución de trabajo, pero no es óptima. Explicaré mi solución aquí y continuaré buscando una mejor.

Al comienzo del programa puedo comprobar si estoy o no de la raíz mediante la ejecución de

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

os.setuid (0) fallará si ya no soy la raíz y que activará _mac_elevate() que relanzar mi programa desde el principio como administrador con la ayuda de osascript. osascript se puede usar para ejecutar applescript y otras cosas. Yo lo uso como esto:

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) 

El problema con esto es si uso subprocess.call que el anterior sigo la corriente de funcionamiento del proceso y habrá dos instancias de mi aplicación se ejecuta dando dos iconos de base. Si utilizo subprocess.Popen en su lugar y dejo que el proceso no privilegiado muera instantáneamente, no puedo usar el código de salida, ni puedo buscar las corrientes stdout/stderr y propagarme al terminal comenzando el proceso original.

2

Sé que la publicación es un poco antigua, pero escribí lo siguiente como una solución a mi problema (ejecutar un script de python como root en Linux y OS X).

me escribió lo siguiente bash script para ejecutar secuencias de comandos bash/pitón con privilegios de administrador (funciona en los sistemas Linux y 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 

Básicamente, la forma en que puedo configurar mi sistema es que sigo subcarpetas dentro de los directorios bin (por ejemplo,/usr/local/bin/pyscripts en/usr/local/bin) y crear enlaces simbólicos a los ejecutables. Esto tiene tres beneficios para mí:

(1) Si tengo diferentes versiones, puedo cambiar fácilmente cuál se ejecuta cambiando el enlace simbólico y mantiene el directorio bin más limpio (por ejemplo/usr/local/bin/gcc -versions/4.9 /, /usr/local/bin/gcc-versions/4.8/,/usr/local/bin/gcc -> gcc-versions/4.8/gcc)

(2) Puedo almacenar el scripts con su extensión (útil para resaltar la sintaxis en IDE), pero los ejecutables no los contienen porque me gusta de esa manera (por ejemplo, svn-tools -> pyscripts/svn-tools.PY)

(3) La razón por la que voy a mostrar a continuación:

i el nombre del script "run-as-root-contenedor" y colocarlo en un camino muy común (por ejemplo,/usr/local/bin) entonces Python no necesita nada especial para localizarlo. Entonces tengo el siguiente módulo 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 

En mi script en Python real, tengo la siguiente función:

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) 

Así que si tengo un script llamado TrackingBlocker.py (guión real que utilizar para modificar el archivo/etc/hosts para redirigir dominios de rastreo conocidos a 127.0.0.1), cuando llamo "sudo /usr/local/bin/pyscripts/TrackingBlocker.py --prefix/usr/local --name ModifyTrackingBlocker instalar"(argumentos manejados a través de argparse módulo), se instala "/ usr/local/bin/ModifyTrackingBlocker", que es un script bash ejecutar

/usr/local/bin/run-as-root-wrapper /usr/local/bin/pyscripts/TrackingBlocker.py [args] 

por ejemplo

ModifyTrackingBlocker add tracker.ads.com 

ejecuta:

/usr/local/bin/run-as-root-wrapper /usr/local/bin/pyscripts/TrackingBlocker.py add tracker.ads.com 

que luego se muestra el diálogo de autentificación necesaria para obtener los privilegios de añadir:

127.0.0.1 tracker.ads.com 

a mi archivo de hosts (que sólo puede ser escrito por un superusuario) .

Si desea simplificar/modificarlo para que se ejecute sólo ciertos comandos como root, simplemente puede añadir esto a su script (con las importaciones necesarias se señaló anteriormente subproceso + importación):

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) 

Usando los anteriores (en el módulo run_command):

>>> ret = run_command.run_as_root("/usr/local/bin/pyscripts/TrackingBlocker.py", ["status", "display"]) 
>>> /etc/hosts is blocking approximately 16147 domains