Demander le privilège root à partir d'un script

23

J'ai un script qui peut fonctionner comme sudo script.shoupkexec script.sh

Ce serait beaucoup plus agréable du point de vue de l'utilisateur si le script demandait le mot de passe à l'utilisateur lorsqu'il l'exécutait simplement par son nom script.sh.

Comment puis-je "incorporer" une demande pkexecou sudoexécuter le script entier avec le privilège root?

Notez que tout exécuter avec sudo sh -cn'est peut-être pas la meilleure solution car j'ai des fonctions dans le script.

Sergiy Kolodyazhnyy
la source

Réponses:

55

Cela fonctionnera:

echo "$(whoami)"

[ "$UID" -eq 0 ] || exec sudo "$0" "$@"

Exemple:

./test.sh 
blade
[sudo] password for blade: 
root
blade19899
la source
3
Ce qui est bien, c'est la récursivité avec exec- appeler lui-même mais en même temps remplacer le processus, donc nous ne
générons
1
Récursivité à la rescousse !!! Rappelez-moi d'ajouter une prime à celui-ci dans quelques jours!
Fabby
6
Quelque chose à savoir lorsque vous faites cela est une élévation de privilèges; Fondamentalement, plus vous exécutez de commandes en tant que root, plus il y a de possibilités pour un pirate malveillant d'exploiter quelque chose pour accéder à un compte root. Je ne dis pas qu'il est toujours faux de faire exécuter le script en tant que root, mais cela vaut la peine d'y réfléchir avant de décider de le faire. Je pense que ce serait bien (mais pas nécessaire) que la réponse touche à cela.
David Z
Si vous avez une valeur de délai d'expiration décente définie dans / etc / sudoers, vous pouvez éventuellement mettre sudo devant chaque commande du script qui a vraiment besoin d'un accès root et il ne demandera qu'une seule fois. Une chose que je me trompe souvent est que l'appel d'un tel script à partir d'une interface graphique ne fonctionnera pas parce que sudo obtient / dev / null pour la saisie du mot de passe et échoue. C'est ce que gksudo et kdesudo ont été conçus pour gérer car ils utiliseront l'interface graphique pour demander le mot de passe.
Joe
1
@ Coder256: Je ne pense pas que votre modification était correcte. "$@"s'étendra à plusieurs mots, un pour chaque paramètre.
jwodder
12

Si vous souhaitez une jolie boîte de dialogue, essayez quelque chose comme ça. J'ai arraché ça directement de quelque chose d'autre que j'ai écrit, donc il y a des trucs supplémentaires dont vous pourriez ne pas avoir besoin ou que vous voulez, mais cela montre l'idée générale:

brand="My Software"

# Check that the script is running as root. If not, then prompt for the sudo
# password and re-execute this script with sudo.
if [ "$(id -nu)" != "root" ]; then
    sudo -k
    pass=$(whiptail --backtitle "$brand Installer" --title "Authentication required" --passwordbox "Installing $brand requires administrative privilege. Please authenticate to begin the installation.\n\n[sudo] Password for user $USER:" 12 50 3>&2 2>&1 1>&3-)
    exec sudo -S -p '' "$0" "$@" <<< "$pass"
    exit 1
fi

boîte de dialogue sudo

Cela utilise whiptail, que vous pouvez installer si vous ne l'avez pas déjà:

sudo apt-get install whiptail
Michael Hampton
la source
1
Pourquoi enregistrez-vous le mot de passe dans une variable?
heemayl
10
N'appelle pas exec echo [PASSWORD]! Il engendrera un processus avec le mot de passe sur la ligne de commande que tout utilisateur peut voir. Soit utiliser la commande intégrée echo(forcer la version intégrée avec builtin echo) ou le bashisme <<<(comme ceci :) sudo ... <<< "$pass"; Sh et d'autres obus ont des documents ici pour ces cas. Indiquez également le mot de passe s'il contient des caractères spéciaux.
David Foerster
Alternativement, placez la whiptailcommande dans un script séparé et utilisez quelque chose comme SUDO_ASKPASS=/path/to/askpass-with-whiptail.sh sudo -A -p "My password prompt" -- "$0" "$@"pour sudogérer l'invite de mot de passe personnalisé.
David Foerster
@DavidFoerster Cela pourrait fonctionner, mais vous avez alors besoin de deux scripts ou vous écrivez votre script askpass dans un fichier temporaire, puis vous le passez à sudo.
Michael Hampton
Ok mais d'autres ont déjà noté qu'il n'est pas souhaitable de passer le mot de passe à une variable. La façon dont j'approche cela est de passer la sortie de la boîte de dialogue au canal nommé comme je l'ai montré ici askubuntu.com/a/704643/295286
Sergiy Kolodyazhnyy
11

La réponse de blade19899 est en effet la voie à suivre, mais on pourrait aussi appeler sudo bashle shebang:

#!/usr/bin/sudo bash
# ...

La mise en garde évidente est que cela ne fonctionnera que tant que le script sera appelé avec ./scriptet échouera dès que le script sera appelé avec bash script.

kos
la source
5
C'est l'une des raisons pour lesquelles vous ne devez jamais taper bash scriptsur la ligne de commande pour appeler un script. Si le script spécifie autre chose que bashdans la #!ligne, alors l'invoquer avec bash scriptéchouera. Si j'essayais d'invoquer un script python à l'aide, bash script.pyil échouerait également.
kasperd
1
Vous pouvez cependant l'exécuter avec perl script. Perl, dans un effort pour être vraiment très gentil, vérifie la ligne shebang, et s'il n'invoque pas perl, il exécute le programme correct.
tbodt
C'est mauvais car il exécute toutes les commandes du script avec sudo. Il est préférable d'isoler les quelques commandes qui ont vraiment besoin de sudo et de les ajouter si nécessaire. N'incluez pas l'évaluation des fonctions dans ces appels sudo; elles doivent être aussi claires et minimales que possible.
Douglas s'est tenue
@DouglasHeld Bien que je sois d'accord avec cela, c'est ce que la question demande: "Comment puis-je" incorporer "la demande à pkexec ou sudo pour exécuter le script entier avec le privilège root?". Je suis sûr qu'il y aurait des cas d'utilisation dans lesquels être en mesure de le faire serait utile.
kos
6

Je fais précéder les commandes du script qui nécessitent un accès root avec sudo- si l'utilisateur n'a pas déjà obtenu les autorisations, le script demande un mot de passe à ce stade.

Exemple

#!/bin/sh 
mem=$(free  | awk '/Mem:/ {print $4}')
swap=$(free | awk '/Swap:/ {print $3}')

if [ $mem -lt $swap ]; then
    echo "ERROR: not enough RAM to write swap back, nothing done" >&2
    exit 1
fi

sudo swapoff -a && 
sudo swapon -a

Ce script peut être exécuté en tant que sudo <scriptname>ou en tant que <scriptname>. Dans les deux cas, il ne demandera le mot de passe qu'une seule fois.

Charles Green
la source
2
Le problème ici est qu'il peut y avoir plusieurs commandes qui nécessitent un accès root, ce qui signifie appeler sudo25 commandes différentes redondantes - il est plus facile d'appeler sudo une fois. Ici cependant, la raison pour laquelle votre script n'appelle sudo qu'une seule fois est que sudo a un délai de 15 minutes - les commandes qui prennent plus de temps devront être repromptées. Votre chemin fonctionne juste. . . pas la façon dont j'en ai besoin pour travailler.
Sergiy Kolodyazhnyy
@Serg Pour un petit script, ma façon de faire était rapide et facile - je ne suis vraiment pas un programmeur élégant!
Charles Green
Vous êtes le meilleur programmeur qui poste sur cette page. Vous utilisez sudo exactement comme il doit être utilisé - uniquement lorsque cela est nécessaire et avec des résultats très clairs attendus.
Douglas s'est tenue
4

Il semble que personne d'autre n'ait abordé la question évidente ici. Mettre sudodans votre script que vous distribuez ensuite favorise les mauvaises habitudes des utilisateurs . (Je suppose que vous le distribuez parce que vous mentionnez "d'un point de vue utilisateur.")

La vérité est qu'il existe une directive dans l'utilisation des applications et des scripts qui est similaire au principe de sécurité dans les opérations bancaires de: Ne donnez jamais vos informations personnelles à quelqu'un qui vous appelle et dit qu'il appelle "de votre banque" , et qui existe pour des raisons similaires.

La règle pour les candidatures est:

Ne tapez jamais votre mot de passe lorsque vous y êtes invité, sauf si vous êtes certain de ce qui est fait avec. Cela s'applique trois fois à toute personne ayant sudoaccès.

Si vous saisissez votre mot de passe parce que vous avez exécuté sudosur la ligne de commande, tant mieux. Si vous le saisissez parce que vous avez exécuté une commande SSH, très bien. Si vous le saisissez lorsque vous vous connectez à votre ordinateur, c'est parfait, bien sûr.

Si vous exécutez simplement un script ou un exécutable étranger et saisissez discrètement votre mot de passe lorsque vous y êtes invité, vous n'avez aucune idée de ce que le script fait avec. Il pourrait être en train de le stocker dans un fichier temporaire en clair, pour autant que vous le sachiez, et pourrait même ne pas se nettoyer après lui-même.

Évidemment, il existe des préoccupations distinctes et supplémentaires concernant l'exécution d'un ensemble inconnu de commandes root, mais ce dont je parle ici est de maintenir la sécurité sur le mot de passe lui-même . Même en supposant que l'application / le script n'est pas malveillant, vous souhaitez toujours que votre mot de passe soit traité en toute sécurité pour empêcher d' autres applications de s'en emparer et de l'utiliser de manière malveillante.

Donc, ma réponse personnelle à cela est, la meilleure chose à mettre dans votre script s'il a besoin des privilèges root, est:

#!/bin/bash
[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

# do privileged stuff, etc.
Caractère générique
la source
Bien que je sois entièrement d'accord avec vous, un utilisateur qui exécute quelque chose sans savoir ce qu'il fait sudo script_nameest tout aussi vulnérable, c'est la même chose. Peut-être que cette idée favorise de mauvaises habitudes - je ne dirai rien à ce sujet. Mais la clé est de savoir ce que fait un programme, et c'est la responsabilité de l'utilisateur. C'est toute l'idée derrière les logiciels open source. Quant à mon propre script, eh bien. . . un script est du texte brut - les utilisateurs peuvent le lire s'ils veulent savoir ce qu'il fait
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy, c'est similaire, mais si vous tapez votre mot de passe directement dans le script, c'est en fait pire. Un script exécuté avec sudo ne connaît toujours pas votre mot de passe.
Wildcard
1

Je l'ai fait de cette façon:

echo -n "Enter password for sudo rights: "
read -s pass

echo $pass | sudo -S [your command here]
88 pesé
la source
4
Citez au moins vos variables.
muru
Et citer vos variables pourrait même ne pas aider si votre mot de passe commence par un trait d'union.
Wildcard