Comment arrêter l'exécution d'un script s'il n'est pas root (et en écho «Ne pas s'exécuter en tant que root! Quitter…»)

17

Voici ma source:

#!/bin/bash

echo "Running script to free general cached memory!"
echo "";
echo "Script must be run as root!";
echo "";
echo "Clearing swap!";
swapoff -a && swapon -a;
echo "";
echo "Clear inodes and page file!";
echo 1 > /proc/sys/vm/drop_caches;
echo "";

Il efface les caches et les trucs, et il fait écho qu'il doit être exécuté en tant que root dans le terminal. Je veux simplement que le script cesse de fonctionner s'il détecte qu'il n'est pas exécuté en tant que root.

Exemple:

"Running script to free general cached memory!"
"Warning: script must be run as root or with elevated privileges!"
"Error: script not running as root or with sudo! Exiting..."

S'il est exécuté avec des privilèges élevés, il fonctionne comme d'habitude. Des idées? Merci!

M. Knepper
la source
Duplication possible de Comment empêcher root d'exécuter un script
muru
2
@muru, sauf que l'autre question est pour le contraire: échouer le script s'il est exécuté en tant que root.
Stéphane Chazelas
3
@ StéphaneChazelas ah, ma mauvaise. Rétracté
muru
Une alternative consiste à limiter la quantité de travail effectuée rooten préfixant préfixer toutes les commandes qui doivent s'exécuter comme rootavec sudo.
reinierpost

Réponses:

46
#!/bin/sh

if [ "$(id -u)" -ne 0 ]; then
        echo 'This script must be run by root' >&2
        exit 1
fi

cat <<HEADER
Host:          $(hostname)
Time at start: $(date)

Running cache maintenance...
HEADER

swapoff -a && swapon -a
echo 1 >/proc/sys/vm/drop_caches

cat <<FOOTER
Cache maintenance done.
Time at end:   $(date)
FOOTER

L'utilisateur root a l'UID 0 (quel que soit le nom du compte "root"). Si l'UID effectif renvoyé par id -un'est pas nul, l'utilisateur n'exécute pas le script avec les privilèges root. Utilisez id -rupour tester par rapport à l'ID réel (l'UID de l'utilisateur invoquant le script).

Ne pas utiliser $EUIDdans le script car cela peut être modifié par un utilisateur non privilégié:

$ bash -c 'echo $EUID'
1000

$ EUID=0 bash -c 'echo $EUID'
0

Si un utilisateur faisait cela, cela n'entraînerait évidemment pas une escalade de privilèges, mais pourrait conduire à ce que les commandes du script ne puissent pas faire ce qu'elles sont censées faire et que les fichiers soient créés avec le mauvais propriétaire, etc.

Kusalananda
la source
1
Remarque: sur Solaris 5.10, /bin/id -udonne/bin/id: illegal option -- u Usage: id [-ap] [user]
jrw32982 prend en charge Monica
1
@ jrw32982 Vous devriez avoir au /usr/xpg4/bindébut de votre $PATHaccès aux utilitaires POSIX sur Solaris.
Kusalananda
1
Le fait est que l' -uoption de idn'est pas universelle et par conséquent, cette solution n'est universelle qu'avec la mise en garde qu'une version POSIX iddoit apparaître en premier dans votre PATH.
jrw32982 prend en charge Monica
1
@ jrw32982 Pour que votre script récupère les utilitaires POSIX corrects sur Solaris, modifiez- $PATHle en haut du script pour que ce /usr/xpg4/binsoit avant /bin. Si vous insistez pour utiliser non-POSIX id, alors vous devrez évidemment trouver une solution plus portable.
Kusalananda
1
@ Harry Oui, afin que le script puisse utiliser PATH=$( getconf PATH )ou définir un autre chemin par défaut explicite, ou utiliser un chemin explicite pour appeler id.
Kusalananda
19

Je pense que ce que vous voulez, c'est plutôt de vérifier que vous avez des privilèges de super-utilisateur, c'est-à-dire que votre ID utilisateur effectif est 0.

zshet le bashrendre disponible dans la $EUIDvariable, afin que vous puissiez faire:

if ((EUID != 0)); then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

Avec tous les shells de type POSIX, vous pouvez utiliser la idcommande standard:

if [ "$(id -u)" -ne 0 ]; then
  echo >&2 "Error: script not running as root or with sudo! Exiting..."
  exit 1
fi

Notez que tout id -unou whoamiou la $USERNAMEvariable dans zshvous obtiendrez le premier nom d'utilisateur pour l'uid. Sur les systèmes qui ont d'autres utilisateurs avec l'ID 0, cela peut ne pas être le rootcas même si le processus est un descendant de celui qui a été authentifié en tant que root.

$USERserait généralement vous donner à l'utilisateur qui a authentifié, mais compter sur elle est très fragile. Il est pas défini par le shell, mais est généralement définie par la commande d'authentification (comme login, su(sur les systèmes GNU / Linux, pas nécessairement d' autres), sudo, sshd(celui de OpenSSH au moins) ...). Ce n'est pas toujours le cas (le changement de l'uid ne définit pas automatiquement cette variable, cela doit être fait explicitement par l'application qui change l'uid) et il pourrait également avoir été modifié par un autre processus dans l'ascendance du shell. $LOGNAME, avec la même mise en garde est plus fiable que spécifié par POSIX (à l'origine de FIPS 151-2)

Stéphane Chazelas
la source
12

Vous pouvez utiliser $USERou whoamipour vérifier l'utilisateur actuel.

if [[ "$USER" != "root" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi

if [[ $(whoami) != "root" ]]; then
    echo "Warning: script must be run as root or with elevated privileges!"
    exit 1
fi

if [[ $(id -u) != "0" ]]; then
    echo "Error: script not running as root or with sudo! Exiting..."
    exit 1
fi
Jesse_b
la source
1
NP. Je suggère littéralement de lire directement le manuel bash [ gnu.org/software/bash/manual/bashref.html] . C'est en fait un prêt étonnamment facile. Pour cette réponse en particulier je suggère de référencer: 3.2.4.2 Conditional Constructs 3.5.4 Command Substitution
Jesse_b
9
La commande id -uavec ou sans -noption est une alternative à l'utilisation de whoami. Sans -n et la comparaison avec zéro est une meilleure correspondance avec le test que le noyau est en train de faire. Tout le noyau se soucie de l'id, pas du nom du fichier de mot de passe.
icarus
6
Je crois que l'utilisation $(id -u)est meilleure. Dans certains cas (malveillants), cela $USERpourrait être faux.
Basile Starynkevitch
1
Pour ceux qui sont intéressés par le lien fourni par @Jesse_b: il y a une faute de frappe. Ce devrait être gnu.org/software/bash/manual/bashref.html
Kryten
1
Certains systèmes n'utilisent pas "root" comme nom du compte privilégié ayant uid 0. QNAP vient à l'esprit comme un. Vous ne devez donc vérifier que l'uid 0 et non le nom du compte root.
roaima
10

Ce que vous voulez réellement, c'est déterminer si vous avez accès à ces opérations. Il est considéré comme une mauvaise pratique de vérifier si vous êtes root au lieu de cela.

Si le système a été configuré pour permettre à un utilisateur non root de modifier le cache de swap et drop page, pourquoi cet utilisateur ne devrait-il pas exécuter votre script?

Au lieu de cela, vous pouvez simplement essayer l'opération et quitter avec un message utile en cas d'échec:

if ! ( swapoff -a && swapon -a )
then
  echo "Failed to clear swap (rerun as root?)" >&2
  exit 1
fi

if ! echo 1 > /proc/sys/vm/drop_caches
then 
  echo "Failed to free page cache (rerun as root?)" >&2
  exit 1
fi
cet autre gars
la source
Un utilisateur non root désactivant le swap?
Kusalananda
2
Oui. Vous pouvez configurer cela avec SELinux. De même, vous pouvez désactiver un processus racine de le faire.
cet autre gars
1
Vous ne voudrez peut-être pas exitaprès que quelque chose échoue, au cas où l'utilisateur voudrait en faire autant qu'il le peut avec ses privilèges actuels. (Mais pour un système typique où tout cela nécessite un root, sortir serait plus utile / moins bruyant.)
Peter Cordes
2
Je n'irais pas jusqu'à dire que c'est une "mauvaise pratique" de vérifier si vous êtes root ou non. Surtout si c'est exactement ce que vous voulez savoir. Je comprends votre point de vue qu'il est préférable de vérifier si vous disposez des autorisations suffisantes pour faire ce que vous voulez.
Erik Bennett