web-dev-qa-db-fra.com

Quel est le meilleur moyen de vérifier si l'utilisateur d'un script a des privilèges de type racine?

J'ai un script Python qui fera beaucoup de choses nécessitant des privilèges de niveau racine, tels que le déplacement de fichiers dans/etc, l'installation avec apt-get, etc. J'ai actuellement:

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

Est-ce la meilleure façon de faire le contrôle? Existe-t-il d'autres bonnes pratiques?

55
Paul Hoffman

En vertu du principe "Plus facile de demander pardon que la permission":

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 vous êtes préoccupé par la non-transférabilité de os.geteuid(), vous ne devriez probablement pas utiliser le /etc de toute façon.

29
msw

os.geteuid obtient l'identifiant d'utilisateur effectif, qui correspond exactement à ce que vous souhaitez. Je ne vois donc pas de meilleur moyen de procéder à une telle vérification. Ce qui est incertain, c’est que le titre ressemble à «de la racine»: votre code vérifie exactement root, pas de «comme», et je ne saurais dire quoi de «racine, mais pas à la racine» signifierait - donc, si vous voulez dire quelque chose de différent de "exactement root", peut-être que vous pouvez clarifier, merci!

56
Alex Martelli

Vous pouvez demander à l'utilisateur l'accès à 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?

Le commutateur Sudo -v met à jour les informations d'identification en cache de l'utilisateur (voir man Sudo).

8
jcarballo

Si vous voulez vraiment que votre code soit robuste sur une grande variété de configurations Linux, je vous suggérerais de considérer les cas où quelqu'un pourrait utiliser SELinux, des ACL de système de fichiers ou les fonctionnalités "fonctionnalités" qui existaient déjà dans le noyau Linux. depuis v. 2.2 ou plus. Votre processus peut s'exécuter sous un wrapper ayant utilisé SELinux ou une bibliothèque de fonctionnalités Linux, telle que libcap2libcap-ng ou fscaps ou elfcap via un format plus exotique comme le merveilleux systrace système de Niels Provos.

Toutes ces méthodes permettent à votre code de s'exécuter en tant que non-root. Pourtant, votre processus peut se voir déléguer l'accès nécessaire pour effectuer son travail sans EUID == 0.

Je suggérerais donc que vous envisagiez d'écrire votre code de manière plus pythonique, en encapsulant des opérations pouvant échouer en raison d'autorisations ou d'autres problèmes liés au code de gestion des exceptions. Si vous devez effectuer diverses opérations (par exemple, en utilisant le module subprocess), vous pouvez proposer de préfixer tous ces appels avec le préfixe Sudo (par exemple, une option de ligne de commande, d'environnement ou de fichier .rc). S'il est exécuté de manière interactive, vous pouvez proposer de réexécuter toutes les commandes soulevant des exceptions liées aux autorisations à l'aide de Sudo (éventuellement uniquement si vous trouvez Sudo sur os.environ ['PATH']).

Dans l’ensemble, c’est vrai que la plupart des systèmes Linux et UNIX ont encore une grande partie de l’administration effectuée par un utilisateur privilégié «root». Cependant, c'est la vieille école et nous, en tant que programmeurs, devrions essayer de supporter les nouveaux modèles. Essayer vos opérations et laisser la gestion des exceptions faire son travail permet à votre code de fonctionner sous n’importe quel système autorisant de manière transparente les opérations dont vous avez besoin, et être au courant et prêt à l’utiliser Sudo est une touche agréable (comme c’est de loin le plus outil répandu pour la délégation contrôlée des privilèges système).

7
Jim Dennis

Réponse à la deuxième partie de la question

(désolé la boîte de commentaire était trop petite)

Paul Hoffman, vous avez raison, je n'ai abordé qu'une partie de votre question concernant les éléments intrinsèques, mais ce ne serait pas un langage de script digne de ce nom s'il ne pouvait pas gérer apt-get. La bibliothèque préférée est un peu bavarde mais elle fait le travail:

>>> 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'

Mais Popen est un outil généralisé et peut être encapsulé pour plus de commodité:

$ 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

Et maintenant, nous revenons à la gestion des exceptions. Je vais refuser de commenter la sur-généralité du module de sous-processus semblable à Java.

3
msw

J'aime vérifier Sudo dans les variables environnementales:

 si pas 'Sudo_UID' dans os.environ.keys (): 
 print "ce programme nécessite un super utilisateur privé." 
 sys.exit (1) 
2
vossman77

Mon application fonctionne avec ce code:

import os
user = os.getenv("Sudo_USER")
if user is None:
    print "This program need 'Sudo'"
    exit()
2
Guillaume

Pour linux:

def is_root():
    return os.geteuid() == 0
0
dimon4eg

Tout dépend de la portabilité que vous souhaitez pour votre application. Si vous voulez dire entreprise, nous devons supposer que le compte d’administrateur n’est pas toujours égal à 0. Cela signifie que la vérification de euid 0 ne suffit pas. Le problème, c'est qu'il y a des situations où une commande se comportera comme si vous étiez root et que la prochaine échouera avec permission refusée (pensez à SELinux & co.). Par conséquent, il est vraiment préférable d’échouer en douceur et de rechercher l’erreur EPERM errno chaque fois que cela est approprié.

0
Stan