¿Cuál es la mejor manera de comprobar si el usuario de un script tiene privilegios de root?


Tengo un script Python que hará muchas cosas que requerirían privilegios de root, como mover archivos en /etc, instalar con apt-get, etc. Actualmente tengo:

if os.geteuid() != 0:
    exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")

Es esta la mejor manera de hacer el cheque? ¿Existen otras mejores prácticas?

Author: martineau, 2010-05-11

9 answers

Bajo el principio de" Más fácil pedir Perdón que Permiso":

try:
    os.rename('/etc/foo', '/etc/bar')
except IOError as e:
    if (e[0] == errno.EPERM):
       print >> sys.stderr, "You need root permissions to do this, laterz!"
       sys.exit(1)

Si le preocupa la no portabilidad de os.geteuid() probablemente no debería estar jugando con /etc de todos modos.

 28
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-10 22:41:07

os.geteuid obtiene el id de usuario efectivo, que es exactamente lo que quieres, así que no puedo pensar en una mejor manera de realizar tal comprobación. El único bit que es incierto es que "root-like" en el título: su código comprueba exactamente root, no hay "me gusta" al respecto, y de hecho no sabría lo que" raíz-como pero no raíz "significaría so así que, si quieres decir algo diferente de "exactamente raíz", tal vez pueda aclarar, gracias!

 51
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-10 22:39:20

Puede solicitar al usuario el acceso a sudo:

import os, subprocess

def prompt_sudo():
    ret = 0
    if os.geteuid() != 0:
        msg = "[sudo] password for %u:"
        ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True)
    return ret

if prompt_sudo() != 0:
    # the user wasn't authenticated as a sudoer, exit?

El conmutador sudo -v actualiza las credenciales en caché del usuario (ver man sudo).

 8
Author: jcarballo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-22 20:26:31

Si realmente desea que su código sea robusto en una amplia variedad de configuraciones de Linux, le sugiero que considere los casos de esquina donde alguien puede estar usando SELinux, o ACL del sistema de archivos, o las características de "capacidades" que han estado en el kernel de Linux desde la versión 2.2 más o menos. Su proceso podría estar ejecutándose bajo algún envoltorio que haya usado SELinux, o alguna biblioteca de capacidades de Linux, como libcap2 libcap-ng , o fscaps o elfcap a través de algo más exótico como el maravilloso y tristemente subestimado sistema systrace de Niels Provos.

Todas estas son formas en las que el código podría estar ejecutándose como no root y, sin embargo, su proceso podría haber sido delegado el acceso necesario para realizar su trabajo sin EUID==0.

Así que le sugiero que considere escribir su código más pitónicamente, empaquetando operaciones que pueden fallar debido a permisos u otros problemas con el manejo de código de excepción. Si usted está bombardeando a cabo para realizar varias operaciones (por ejemplo, usando el módulo subprocess) puede ofrecer prefijar todas estas llamadas con sudo (como línea de comandos, entorno, o .opción de archivo rc, por ejemplo). Si se está ejecutando interactivamente, puede ofrecer volver a ejecutar cualquier comando que genere excepciones relacionadas con permisos usando sudo (opcionalmente solo si encuentra sudo en el sistema operativo.environ ['PATH']).

En general, es cierto que la mayoría de los sistemas Linux y UNIX todavía tienen la mayor parte de su administración hecha por un usuario privilegiado 'root'. Sin embargo, es de la vieja escuela y nosotros, como programadores, deberíamos tratar de soportar modelos más nuevos. Probar sus operaciones y dejar que el manejo de excepciones haga su trabajo permite que su código funcione bajo cualquier sistema que permita de forma transparente las operaciones que necesita, y ser consciente y listo para usar sudo es un buen toque (ya que es, con mucho, la herramienta más extendida para la delegación controlada de privilegios del sistema).

 7
Author: Jim Dennis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-10 23:53:06

Respuesta a la segunda parte de la pregunta

(lo siento, el cuadro de comentarios era demasiado pequeño)

Paul Hoffman, tienes razón, solo he abordado una parte de tu pregunta que trata de los intrínsecos, pero no sería un lenguaje de scripting digno si no pudiera manejar apt-get. La biblioteca preferida es un poco detallada, pero hace el trabajo:

>>> apt_get = ['/usr/bin/apt-get', 'install', 'python']
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> p.wait()
100                 # Houston, we have a problem.
>>> p.stderr.read()
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)'
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n'

Pero Popen es una herramienta generalizada y se puede envolver por conveniencia:

$ cat apt.py
import errno
import subprocess

def get_install(package):
    cmd = '/usr/bin/apt-get install'.split()
    cmd.append(package)
    output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE}
    p = subprocess.Popen(cmd, **output_kw)
    status = p.wait()
    error = p.stderr.read().lower()
    if status and 'permission denied' in error:
        raise OSError(errno.EACCES, 'Permission denied running apt-get')
    # other conditions here as you require
$ python
>>> import apt
>>> apt.get_install('python')
Traceback ...
OSError: [Errno 13] Permission denied running apt-get

Y ahora volvemos al manejo de excepciones. Lo haré declina comentar sobre la sobre generalidad similar a Java del módulo subprocess.

 3
Author: msw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 16:22:41

Me gusta comprobar sudo en las variables ambientales:

if not 'SUDO_UID' in os.environ.keys():
  print "this program requires super user priv."
  sys.exit(1)
 2
Author: vossman77,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-15 13:26:51

Mi aplicación funciona con este código:

import os
user = os.getenv("SUDO_USER")
if user is None:
    print "This program need 'sudo'"
    exit()
 2
Author: Guillaume,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-27 15:00:22

Todo depende de lo portátil que quieras que sea tu aplicación. Si te refieres a negocios, tenemos que asumir que la cuenta de administrador no siempre es igual a 0. Esto significa que la comprobación de euid 0 no es suficiente. El problema es que hay situaciones en las que un comando se comportará como si fuera root y el siguiente fallará con permiso denegado (piense en SELinux & co.). Por lo tanto, es realmente mejor fallar con gracia y comprobar si EPERM errno siempre que sea apropiado.

 0
Author: Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-10 22:52:27

Para linux:

def is_root():
    return os.geteuid() == 0
 0
Author: dimon4eg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-03 08:48:11