Jak skrypt może sprawdzić, czy jest uruchamiany jako root?

104

Piszę prosty skrypt bash, ale potrzebuję go, aby sprawdzić, czy jest uruchamiany jako root, czy nie. Wiem, że jest to prawdopodobnie bardzo prosty sposób, ale nie mam pojęcia, jak to zrobić.

Żeby było jasne:
Co to jest prosty sposób, aby napisać skrypt foo.sh , tak że polecenie ./foo.shwyjścia 0i polecenie sudo ./foo.shwyjścia 1?

Malabarba
źródło

Odpowiedzi:

148
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi
aneeshep
źródło
7
Akceptuję tę jedną przyczynę (po kilku testach), że użycie zmiennej systemowej EUID okazało się (około 100 razy) szybsze niż uruchomienie polecenia (id -u), ale wszystkie odpowiedzi działały świetnie.
Malabarba,
18
Także $UIDi $EUIDsą bashizmami. Powłoki zgodne tylko z POSIX nie mają tych zmiennych i należy ich użyć id(1).
David Foerster
3
w skrypcie bash można użyć if ((EUID)); then, patrz komentarz @ geirha
jfs
7
@Andrew: Zmienne są zastępowane, zanim zostaną przekazane sudo. Jeśli uruchomisz sudo sh -c 'echo $EUID', zobaczysz oczekiwane wyniki.
M. Dudley,
6
@Andrew - Wiem, że się tu spóźniłem, ale dla potomności: $EUIDjest Baszizmem (jak wspomniano powyżej przez @DavidFoerster), a twój /bin/shlink najprawdopodobniej /bin/dashnie /bin/bash. sudo bash -c 'echo $EUID'przyniesie oczekiwany wynik.
Adrian Günter,
118

Użytkownik root nie musi mieć nazwy „root”. whoamizwraca pierwszą nazwę użytkownika z identyfikatorem użytkownika 0. $USERzawiera nazwę zalogowanego użytkownika, który może mieć identyfikator użytkownika 0, ale może mieć inną nazwę.

Jedyny niezawodny program sprawdzający, czy konto jest zalogowane jako root, czy nie:

id -u

Używam -udo efektywnego identyfikatora użytkownika, a nie -rna prawdziwym identyfikatorem użytkownika. Uprawnienia są określane przez efektywny identyfikator użytkownika, a nie rzeczywisty .

Testy

/etc/passwdzawiera następujące nazwy użytkowników o identyfikatorze użytkownika 0w podanej kolejności:

rootx
root2

Zalogowany jako root2daje kolejne wyniki:

  • whoami: rootx
  • echo $USER: root2(zwraca pusty ciąg, jeśli program został uruchomiony w pustym środowisku, np. env -i sh -c 'echo $USER')
  • id -u: 0 Jak widać, inne programy zakończyły się niepowodzeniem w tej kontroli, tylko id -uprzeszły.

Zaktualizowany skrypt wygląda następująco:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   echo "I am not root!"
   exit 1
fi
Lekensteyn
źródło
5
Nie potrzebujesz id -uw bash askubuntu.com/questions/30148/…
jfs
5
Zawsze staram się zachować jak największą zgodność z POSIX, używając sh( dash) jako interpretera zamiast bash. Ale dobry strzał, oszczędza kolejny widelec :)
Lekensteyn
Po chwilowym chłodzie wróciłem i spojrzałem. Metoda Lekensteyna rzeczywiście wydaje się lepsza. Jego odpowiedź jest teraz nową przyjętą odpowiedzią. +1 dla ciebie, Lekensteyn, esp. za odebranie trudnej do zdobycia odznaki z tego pytania;)
Thomas Ward
Dzięki za tak długie oczekiwanie na zaakceptowanie mojego pytania: DI dostałem złotą odznakę populistyczną i brązową ładną odpowiedź na tę odpowiedź :) Zastanawiam się, jak to pytanie zyskało tak popularne, 345 wyświetleń dziennie!
Lekensteyn,
3
Widziałem krótsze wersje, [ -w / ]. Pomysł pozostaje ten sam. Uwaga: w niektórych chrootach [ -w /etc/shadow ]zawiedzie, ponieważ /etc/shadownie istnieje, dlatego /preferowane jest podejście z . O wiele lepiej byłoby sprawdzić faktyczną potrzebę uprawnień roota. Jeśli skrypt wymaga zapisu /etc/someconfig, po prostu sprawdź, czy ten plik jest zapisywalny LUB plik nie istnieje i /etcmożna go zapisać.
Lekensteyn
30

Jak powiedział @Lekensteyn , powinieneś użyć skutecznego identyfikatora użytkownika. Nie musisz dzwonić id -ubash:

#!/bin/bash

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

Sugestia @ geirha z komentarzy wykorzystuje ocenę arytmetyczną:

#!/bin/bash

if (( EUID != 0 )); then
   echo "You must be root to do this." 1>&2
   exit 100
fi
jfs
źródło
7
Ogólnie rzecz biorąc, należy używać ((..))do testowania liczb oraz [[..]]do testowania ciągów i plików, więc zrobiłbym if (( EUID != 0 )); thenzamiast tego, lub po prostuif ((EUID)); then
geirha
@geirha: Dodałem twoją sugestię.
jfs
2
EUIDpowinien zostać $EUID. Zamiast używać (( $EUID != 0 )), użyj [ $EUID != 0 ]. To też będzie działać dash.
Lekensteyn
2
@Lekensteyn: EUIDdziała dobrze. Pytanie jest oznaczony bashnie dash. Polecenie env -i sh -c '[ $EUID != 0 ]'kończy się niepowodzeniem, ale env -i bash -c '(( EUID != 0 ))'działa. btw, dashnie działa dla niektórych nie-ascii znaków na Ubuntu stackoverflow.com/questions/5160125/... Jest rok 2011 i są ludzie, którzy używają innych języków.
jfs
Po tym, jak strasznie się nudzę, i testowaniu, zamierzam użyć tej metody wymienionej tutaj w $EUIDmateriałach od tego momentu. W rezultacie zmieniłem zaakceptowaną odpowiedź.
Thomas Ward
20

Możesz to zrobić za pomocą whoamipolecenia, które zwraca bieżącego użytkownika:

#!/bin/bash

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

...

Uruchomienie powyższego spowoduje wydrukowanie, You must be root to do this.jeśli bieżący użytkownik nie jest root.


Uwaga: w niektórych przypadkach alternatywą jest po prostu sprawdzenie $USERzmiennej:

if [ $USER != 'root' ]
Nathan Osman
źródło
Rzucę okiem na kod i sprawdzam, czy skrypt nie zawiedzie lub coś takiego. Jeśli to zadziała, przyjmuję twoją odpowiedź :)
Thomas Ward
4
@George Edison: Odradzam używanie $USER, szczególnie w ten sposób. $USERjest ustawiany przez powłokę logowania, nie trzeba go propagować do programu ( env -i sh -c 'echo $USER'). W ten sposób $USERjest pusty i występuje błąd składniowy.
Lekensteyn
1
@ Lekensteyn Nie tylko jest $USERustawiony przez powłokę, ale jest także czymś, co jest łatwe do sfałszowania. Whoami zwróci faktycznego użytkownika.
Paul de Vrieze
2
@PauldeVrieze Jaki jest sens oszukiwania tej kontroli?
htorque 13.03.11
1
@ andrewsomething: $USERjest interpretowany przez twoją powłokę, twój przykład powinien być sudo sh -c 'echo $USER', aby był znaczący. @George: błędne założenie, że whoamizawsze wróci rootdo UID 0.
sam hocevar
11

Biorąc pod uwagę wydajność, możesz najpierw przetestować EUIDzmienną środowiskową, a następnie, jeśli nie istnieje, wywołać standardowe idpolecenie:

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

W ten sposób, ze względu na skrót LUB , unikasz wywoływania polecenia systemowego, priorytetem zapytania dotyczącego zmiennej w pamięci.

Ponowne użycie kodu:

function amIRoot() {
  ! ((${EUID:-0} || "$(id -u)"))
}
Luchostein
źródło
Obawiam się, że nie przeprowadziłeś testu porównawczego, cóż, mam, a to zajmuje tyle samo czasu co id -u. Zobacz skrypt
testowy
9
#!/bin/bash
[[ $(id -u) != 0 ]] 
echo $?
João Pinto
źródło
2

Jednym prostym sposobem, aby skrypt mógł być uruchamiany tylko przez root, jest uruchomienie skryptu za pomocą wiersza:
#!/bin/su root

alexandre1985
źródło
1
Nie rób tego Próbuje zalogować się bezpośrednio jako root, podczas gdy sudo może być wymagane w wielu systemach, ponieważ ten pierwszy jest zabroniony. Co więcej, shebang ma na celu zapewnienie, że skrypt działa w tym, dla którego został zaprojektowany, podczas gdy twoja metoda spowoduje, że skrypt będzie działał w domyślnej powłoce roota, czego nie można przewidzieć, jeśli skrypt jest uruchamiany przez kogoś innego niż autor. Dlatego użycie shebang do podniesienia uprawnień skryptu poważnie zakłóci jego przenośność i spowoduje błędy w wielu systemach. (su:
Błąd
1
#!/bin/bash
uid=`id -u`
if [ "$uid" == "0" ]
then
    echo 1
else
    echo 0
fi
Delan Azabani
źródło
1

Ten fragment kodu:

  • Sprawdź różne sesje
  • sugeruję użyć sudo !!
  • i zwróć błąd
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      następnie
      echo „Aby uruchomić ten skrypt, musisz być rootem!”
      echo „użyj 'sudo !!” ”
      wyjście 1
fi
rubo77
źródło
1

Ta odpowiedź ma na celu zapisanie pomysłu, który może być pomocny dla niektórych z was. Jeśli potrzebujesz skryptu, który jest uruchamiany z graficznego interfejsu użytkownika i wymaga uprawnień administratora, wypróbuj ten sposób:

#!/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

W ten sposób otrzymasz ładne okno dialogowe z pytaniem o hasło użytkownika root. Podobnie jak w sudo z linii poleceń.

gksudoMogą nie być dostępne w systemie, a następnie zainstalować go sudo apt-get install gksu.

gertas
źródło
0

Ten kod działa zarówno pod Bash, jak i giełdowym Bourne sh (testowanym pod FreeBSD), który nie definiuje EUID. Jeśli istnieje identyfikator EUID, zwracana jest jego wartość, w przeciwnym razie uruchamiane jest polecenie „id”. Jest odrobinę krótszy niż w powyższym przykładzie „lub”, ponieważ wykorzystuje wbudowaną powłokę „: -”.

Zrootuj w 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
źródło