Comment un script peut-il vérifier s'il est exécuté en tant que root?

105

J'écris un script bash simple, mais j'en ai besoin pour vérifier s'il est exécuté en tant que root ou non. Je sais qu'il existe probablement un moyen très simple de le faire, mais je ne sais pas comment.

Pour être clair:
Quelle est une façon simple d'écrire un script foo.sh , de sorte que la commande des ./foo.shsorties 0et la commande des sudo ./foo.shsorties 1?

Malabarba
la source

Réponses:

151
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi
aneeshep
la source
7
J'accepte cette cause (après quelques tests) en utilisant la variable système EUID s'est avérée être (environ 100 fois) plus rapide que d'exécuter une commande (id -u), mais toutes les réponses ont bien fonctionné.
Malabarba
18
Aussi, $UIDet $EUIDsont bashismes. Seuls les shells compatibles POSIX n'ont pas ces variables et vous devez les utiliser id(1).
David Foerster
3
dans un script bash, vous pouvez utiliser if ((EUID)); then, voir le commentaire de @ geirha
jfs
7
@Andrew: Les variables sont substituées avant d'être passées à sudo. Si vous courez, sudo sh -c 'echo $EUID'vous verrez vos résultats escomptés.
M. Dudley
6
@ Andrew - Je sais que je suis bien en retard ici, mais pour la postérité: $EUIDest un bashisme (comme mentionné ci-dessus par @DavidFoerster), et vous êtes /bin/shprobablement un lien vers /bin/dash, pas /bin/bash. sudo bash -c 'echo $EUID'donnera le résultat attendu.
Adrian Günter
118

Un utilisateur root ne doit pas nécessairement s'appeler "root". whoamirenvoie le premier nom d'utilisateur avec l'ID utilisateur 0. $USERcontient le nom de l'utilisateur connecté, qui peut avoir un ID utilisateur 0mais un nom différent.

Le seul programme fiable permettant de vérifier si le compte est connecté en tant que root ou non:

id -u

J'utilise -upour l' ID utilisateur effectif , pas -rpour l' ID utilisateur réel . Les autorisations sont déterminées par l' ID utilisateur effectif et non par le véritable .

Des tests

/etc/passwdcontient les noms d'utilisateur suivants avec l'ID utilisateur 0dans l'ordre donné:

rootx
root2

Connecté en tant que root2, donne les résultats suivants:

  • whoami: rootx
  • echo $USER: root2(cela retourne une chaîne vide si le programme a été démarré dans un environnement vide, par exemple env -i sh -c 'echo $USER')
  • id -u: 0 Comme vous pouvez le constater, les autres programmes ont échoué lors de cette vérification, mais ont été id -uacceptés.

Le script mis à jour ressemblerait à ceci:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   echo "I am not root!"
   exit 1
fi
Lekensteyn
la source
5
Vous n'avez pas besoin id -ude demander
jfs
5
J'essaie toujours de rester aussi compatible POSIX que possible, en utilisant sh( dash) comme interprète au lieu de bash. Mais bon coup, sauve une autre fourchette :)
Lekensteyn
Après avoir été froid pendant un moment, je suis revenu et j'ai jeté un coup d'œil. La méthode de Lekensteyn semble en effet être meilleure. Sa réponse est maintenant la nouvelle réponse acceptée. +1 à vous, Lekensteyn, esp. pour avoir obtenu ce badge difficile à obtenir sur cette question;)
Thomas Ward
Merci d'avoir attendu aussi longtemps pour avoir accepté ma question: DI a obtenu un badge or Populist et une médaille de bronze Belle réponse pour cette réponse :) Je me demande comment cette question a eu un tel succès, 345 vues en une journée!
Lekensteyn
3
J'ai vu des versions plus courtes, [ -w / ]. L'idée reste la même. Remarque: dans certains chroots, [ -w /etc/shadow ]échouera car /etc/shadowinexistant, l’approche avec /est préférable. Un moyen plus efficace serait de vérifier le besoin réel d'autorisations root. Si le script doit écrire /etc/someconfig, vérifiez si ce fichier est accessible en écriture OU si le fichier n'existe pas et /etcest accessible en écriture.
Lekensteyn
30

Comme @Lekensteyn a dit que vous devriez utiliser un ID utilisateur efficace. Vous n'avez pas besoin d'appeler id -uen bash:

#!/bin/bash

if [[ $EUID -ne 0 ]]; then
   echo "You must be root to do this." 1>&2
   exit 100
fi

La suggestion de @ geirha à partir des commentaires utilise l'évaluation arithmétique:

#!/bin/bash

if (( EUID != 0 )); then
   echo "You must be root to do this." 1>&2
   exit 100
fi
jfs
la source
8
En général, on devrait utiliser ((..))pour tester les nombres, et [[..]]pour tester les chaînes et les fichiers, donc je le ferais à la if (( EUID != 0 )); thenplace, ou tout simplementif ((EUID)); then
geirha
@geirha: J'ai ajouté votre suggestion.
Jfs
2
EUIDdevrait devenir $EUID. Au lieu d'utiliser (( $EUID != 0 )), utilisez [ $EUID != 0 ]. Cela fonctionnera dashaussi.
Lekensteyn
2
@Lekensteyn: EUIDfonctionne très bien. La question est étiquetée bashpas dash. La commande env -i sh -c '[ $EUID != 0 ]'échoue, mais env -i bash -c '(( EUID != 0 ))'fonctionne. Au fait, dashcela ne fonctionne pas pour certains caractères non-ASCII sur Ubuntu stackoverflow.com/questions/5160125/… Nous sommes en 2011 et il y a des gens qui utilisent d'autres langues.
Jfs
Après avoir passé en revue tout cela en étant terriblement ennuyé et en mettant à l’essai, je vais utiliser cette méthode, comme indiqué ici, avec ce qui $EUIDsuit à partir de maintenant. J'ai donc changé la réponse acceptée.
Thomas Ward
20

Vous pouvez accomplir cela en utilisant la whoamicommande, qui renvoie l'utilisateur actuel:

#!/bin/bash

if [ `whoami` != 'root' ]
  then
    echo "You must be root to do this."
    exit
fi

...

L'exécution de ce qui précède imprimera You must be root to do this.si l'utilisateur actuel n'est pas root.


Remarque: une alternative dans certains cas consiste simplement à vérifier la $USERvariable:

if [ $USER != 'root' ]
Nathan Osman
la source
Je vais regarder le code, voir si cela ne fait pas échouer le script ou quelque chose du genre. Si cela fonctionne, j'accepterai votre réponse :)
Thomas Ward
4
@ George Edison: Je recommande de ne pas utiliser $USER, en particulier de cette façon. $USERest défini par le shell de connexion, il n'est pas nécessaire de le propager au programme ( env -i sh -c 'echo $USER'). De cette façon, $USERest vide et une erreur de syntaxe se produit.
Lekensteyn
1
@Lekensteyn Non seulement est $USERdéfini par le shell, mais il est également facile de parodier. Whoami retournera l'utilisateur réel.
Paul de Vrieze
2
@PauldeVrieze Quel est l'intérêt de tromper cette vérification?
Htorque
1
@ andrewsomething: $USERest interprété par votre shell, votre exemple devrait sudo sh -c 'echo $USER'être significatif. @ George: il fait la fausse hypothèse qui whoamireviendra toujours rootpour UID 0.
Sam Hocevar
10

En prenant en compte l'efficacité, vous pouvez tester d'abord la EUIDvariable d'environnement puis, si elle n'existe pas, appeler la idcommande standard :

if ((${EUID:-0} || "$(id -u)")); then
  echo You are not root.
else
  echo Hello, root.
fi

De cette manière, en raison du raccourci OU , vous évitez d'appeler une commande système, en donnant la priorité à la requête d'une variable en mémoire.

Réutilisation du code:

function amIRoot() {
  ! ((${EUID:-0} || "$(id -u)"))
}
Luchostein
la source
1
J'ai bien peur que vous ne l'ayez pas comparé, eh bien je l'ai fait et cela prend le même temps que id -u. Voir le script de banc avec les résultats ci-dessous ici: pastebin.com/srC3LWQy
LinuxSecurityFreak
((${EUID:-0} || "$(id -u)"))fonctionne toujoursid -u , tout comme ((1 || $(echo hi >&2; echo 1)))et les ((0 || $(echo hi >&2; echo 1)))deux imprimer hi. En dehors de l' arithmétique shell, &&et ||sont des opérateurs de contrôle; dans a || "$(b)", bne fonctionne que si "$(b)"fonctionne. La plupart des extensions, y compris la substitution de commande, sont régies par la sémantique de court-circuitage des opérateurs de contrôle. Arithmétique Shell a des opérateurs qui se passent à l' épeautre &&et ||aussi - qui court-circuite dans ce ((1 || 0/0))n'est pas une erreur - mais SHELL arithmétique se produit après les substitutions de commandes imbriquées sont étendues.
Eliah Kagan Il y a
9
#!/bin/bash
[[ $(id -u) != 0 ]] 
echo $?
João Pinto
la source
2

Un moyen simple de rendre le script exécutable uniquement par root est de démarrer le script avec la ligne suivante:
#!/bin/su root

alexandre1985
la source
1
Ne fais pas ça. Il tente de se connecter directement en tant que root, alors que sudo peut être requis sur de nombreux systèmes car le premier est interdit. De plus, le shebang est destiné à garantir que votre script s'exécute dans celui pour lequel il a été conçu, tandis que votre méthode le fera s'exécuter dans le shell par défaut de root, ce qui ne peut pas être prédit si le script est exécuté par une personne autre que l'auteur. Par conséquent, l'utilisation du shebang pour élever les privilèges d'un script va sérieusement briser sa portabilité et entraîner des erreurs sur de nombreux systèmes. (su: échec d'authentification)
StarCrashr
1
#!/bin/bash
uid=`id -u`
if [ "$uid" == "0" ]
then
    echo 1
else
    echo 0
fi
Delan Azabani
la source
1

Cet extrait va:

  • Vérifiez les différentes sessions
  • suggère d'utiliser sudo !!
  • et renvoyer une erreur
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      ensuite
      echo "Vous devez être root pour exécuter ce script!"
      echo "use 'sudo !!'"
      sortie 1
Fi
rubo77
la source
1

Cette réponse est juste pour enregistrer une idée avec peut être utile pour certains d'entre vous. Si vous avez besoin d'un script exécuté à partir de l'interface graphique du bureau et nécessitant des privilèges root, procédez comme suit:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   gksudo -w $0 $@
   exit
fi

#here go superuser commands, e.g. (switch intel cpu into powersave mode):
echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
cpupower frequency-set -g powersave

De cette façon, vous obtiendrez une belle fenêtre de dialogue vous demandant le mot de passe de l'utilisateur root. Juste comme avec sudo en ligne de commande.

Le gksudopeut ne pas être disponible sur votre système puis installez-le avec sudo apt-get install gksu.

Gertas
la source
0

Ce code fonctionne à la fois sous Bash et dans le stock Bourne sh (testé sous FreeBSD) qui ne définit pas EUID. Si EUID existe, sa valeur est renvoyée, sinon la commande 'id' est exécutée. C'est un peu plus court que l'exemple "ou" ci-dessus, car il utilise un shell intégré ": -".

Racine dans sh:

# echo $EUID

# euid=${EUID:-`id -u`}
# echo $euid
0

In bash:
[chaapala@tenfwd2 ese]$ euid=${EUID:-`id -u`}
[chaapala@tenfwd2 ese]$ echo $euid
10260
Clayton Haapala
la source