Jak sprawdzić, czy działa jako root w skrypcie bash

274

Piszę skrypt, który wymaga uprawnień na poziomie administratora, i chcę go wykonać, aby jeśli skrypt nie był uruchamiany jako root, po prostu powtarza „Uruchom jako root”. i wychodzi.

Oto pseudokod tego, czego szukam:

if (whoami != root)
  then echo "Please run as root"

  else (do stuff)
fi

exit

Jak mogę najlepiej (czysto i bezpiecznie) to osiągnąć? Dzięki!

Ach, dla wyjaśnienia: część (zrób rzeczy) wymagałaby wykonywania poleceń, które same w sobie wymagają rootowania. Tak więc uruchomienie go jako zwykłego użytkownika spowoduje błąd. Ma to na celu wyłącznie uruchomienie skryptu, który wymaga poleceń roota, bez używania sudo wewnątrz skryptu, szukam tylko cukru syntaktycznego.

Nathan
źródło
8
(1) spraw, aby nie był wykonywalny przez nic innego, niż root (2) również ustaw dalsze uprawnienia. (3) id -uzwraca 0root.
Wrikken,

Odpowiedzi:

403

Zmienna środowiskowa $ EUID przechowuje identyfikator UID bieżącego użytkownika. Identyfikator UID roota to 0. Użyj w skrypcie czegoś takiego:

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

Uwaga: jeśli dostaniesz, 2: [: Illegal number:sprawdź, czy masz #!/bin/shna górze i zmień na #!/bin/bash.

ptierno
źródło
Wydaje się, że dobre uprawnienia i posiadanie tego jest podwójną warstwą bezpieczeństwa
Kanion Kolob
25
Myślę, że lepiej jest porównać ciąg ze sznurkiem, liczbę z liczbą. używając podwójnych nawiasów, możesz użyć> bezpośrednio bez cytatu [[$ EUID> 0]]
Sergio Abreu
7
Dostałem 2: [: Illegal number:ostrzeżenie, dopóki nie zmieniłem go na wersję Sergio.
alexeydemin
1
@ thekiwi5000 Średnik jest wymagany tylko wtedy, gdy thenjest w tej samej linii co warunek ...
ptierno
1
@StephenAngelico Sudo powinien działać. Jeśli testujesz to, wykonując $ sudo echo $ EUID; to zły test i zakończy się niepowodzeniem, ponieważ $ EUID jest rozszerzany przed przekazaniem polecenia do sudo. Spróbuj umieścić echo $ EUID w skrypcie testowym i uruchomić go z sudo.
user1169420
79

W skrypcie bash istnieje kilka sposobów sprawdzenia, czy działający użytkownik jest rootem.

Jako ostrzeżenie , nie sprawdzaj, czy użytkownik jest rootem, używając rootnazwy użytkownika. Nic nie gwarantuje, że użytkownik o identyfikatorze 0 zostanie wywołany root. Jest to bardzo silna konwencja, która jest szeroko stosowana, ale każdy może zmienić nazwę administratora na inną nazwę.

Myślę, że najlepszym sposobem korzystania z bash jest użycie $EUIDstrony man:

EUID   Expands to the effective user ID of the current  user,  initialized
       at shell startup.  This variable is readonly.

Jest to lepszy sposób niż ten, $UIDktóry można zmienić i nie odzwierciedla rzeczywistego użytkownika uruchamiającego skrypt.

if (( $EUID != 0 )); then
    echo "Please run as root"
    exit
fi

Podchodzę do tego rodzaju problemu przez wstrzykiwanie sudomoich poleceń, gdy nie są uruchamiane jako root. Oto przykład:

SUDO=''
if (( $EUID != 0 )); then
    SUDO='sudo'
fi
$SUDO a_command

W ten sposób moje polecenie jest uruchamiane przez użytkownika root podczas korzystania z administratora lub przez sudozwykłego użytkownika.

Jeśli twój skrypt ma być zawsze uruchamiany przez root, po prostu ustaw odpowiednio uprawnienia ( 0500).

Sberder
źródło
Jeśli osoba, która próbuje uruchomić skrypt, nie ma uprawnień sudo, spowoduje to wygenerowanie błędu i polecenie się nie uruchomi? Chcę się tylko upewnić, że rozumiem poprawnie.
Caperneoignis,
1
Nie jestem pewien, czy ta odpowiedź jest w 100% całkowicie poprawna. Na RHEL7.2 przy użyciu Bash 4.2.46 ... jeśli używam printf $EUIDsudo lub bez niego, odzyskuję własny identyfikator UID. Jeśli użyję id -u, dostaję swój identyfikator UID, a gdy wywołuję go za pomocą sudo, otrzymuję 0. Czy zrobiłem coś złego?
0xSheepdog
4
@ 0xSheepdog, możliwe jest, że w bash cli najpierw rozwiązywane jest rozszerzenie zmiennej $ EUID, a następnie sudo zmienia użytkownika. Dlatego dostaniesz takie zachowanie, ale w skryptach wszystko nadal działałoby dobrze.
Alexander Bird
@AlexanderBird Dobra uwaga, dziękuję! Nie przeprowadzałem żadnych prawdziwych testów, po prostu zgłosiłem swoje doświadczenie.
0x Owczarek
3
Użyj „ciągu znaków” do testu, aby zapobiec rozszerzeniu zmiennej lokalnej przez powłokę. Porównaj sudo bash <<<'echo $EUID'z bash <<<'echo $EUID'. Więcej informacji na temat hestrocopodobnego herestringu na tldp.org/LDP/abs/html/x17837.html
Bruno Bronosky
75

Podano kilka odpowiedzi, ale wydaje się, że najlepszą metodą jest użycie:

  • id -u
  • Jeśli zostanie uruchomiony jako root, zwróci identyfikator 0.

Wydaje się to być bardziej niezawodne niż inne metody i wydaje się, że zwraca identyfikator 0, nawet jeśli skrypt zostanie uruchomiony sudo.

Nathan
źródło
1
Świetnie, to najlepsza odpowiedź
Dan Ortega
59
if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

lub

if [[ `id -u` -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi

:)

Dale_Reagan
źródło
Możesz rozważyć zintegrowanie odpowiedzi Jeremy'ego J Starchera z tą częścią, w końcu zawsze jest to to samo ...
naprawdęnice
Wiem, że z terminala, kiedy zapominam o prefiksie czegoś sudo, mogę po prostu pisać sudo !!i to działa dla mnie, zamiast naciskać strzałkę W GÓRĘ, przechodzić na początek wiersza i dodawać sudo ręcznie. Nie jestem pewien, czy to jest PODSTAWA, czy SUDO, czy coś innego, ale działa to przez cały czas.
0x Owczarek
@ 0xSheepdog: To sprawa Bash (i cecha niektórych innych powłok, takich jak csh, skąd pochodzi IIRC).
Wstrzymano do odwołania.
Podsumowując, usunęłbym fragment zaznaczony jako całość i ponownie napisałem ok linię if [ "$(id -u)" -ne 0 ]; then echo 'Please run as root.' >&2; exit 1; fi. Twoje zdrowie.
LinuxSecurityFreak
29

Jak wspomniano w jego komentarzach @wrikken, id -ujest znacznie lepszym sprawdzeniem roota.

Ponadto przy właściwym użyciu sudomożesz sprawdzić skrypt i sprawdzić, czy działa on jako root. Jeśli nie, poproś o ponowne wywołanie, sudoa następnie uruchom z uprawnieniami administratora.

W zależności od tego, co robi skrypt, inną opcją może być ustawienie sudopozycji dla wszelkich specjalistycznych poleceń, których skrypt może potrzebować.

Jeremy J Starcher
źródło
Czy istnieje wdzięczny sposób, aby program sam się przywołał? Być może istnieje jakaś zmienna bash z absolutną ścieżką do programu?
Nathan
1
Nie jestem teraz w pobliżu monitu BASH do przetestowania, ale $0ma nazwę działającego skryptu. Oto kilka przykładów , które mogą ci pomóc.
Jeremy J Starcher
25

Istnieje proste sprawdzenie, czy użytkownik jest rootem.

[[ stuff ]]Składnia jest standardowym sposobem prowadzenia sprawdzić w bash.

error() {
  printf '\E[31m'; echo "$@"; printf '\E[0m'
}

if [[ $EUID -eq 0 ]]; then
    error "Do not run this as the root user"
    exit 1
fi

Zakłada się również, że chcesz wyjść z 1, jeśli ci się nie powiedzie. Ta errorfunkcja ma pewien talent, który ustawia tekst wyjściowy na czerwony (niepotrzebny, ale dość elegancki, jeśli mnie zapytasz).

Slater Victoroff
źródło
Co to za errorpolecenie? Mój system chyba tego nie ma. . .
ruakh
Och, to tylko mały talent. Nie ma to aż tak wielkiego znaczenia, ale dołączę to.
Slater Victoroff,
4
To fajnie! Jeśli mogę zasugerować kilka ulepszeń: (1) przenieś nową linię do końca; (2) zapis do standardowego błędu zamiast standardowego wyjścia; (3) ustaw kolor tylko wtedy, gdy standardowym błędem jest terminal (zamiast ryzykować zapisywanie znaków specjalnych w plikach dziennika lesslub tym podobne); i (4) ustaw kolor tła, dzięki czemu tekst będzie czytelny niezależnie od koloru tła terminala użytkownika. Coś w stylu function error () { if [[ -t 2 ]] ; then echo $'\033[31;2;47m'"$@"$'\033[0m' ; else echo "$@" ; fi >&2 ; }. (Dostosuj zgodnie z życzeniem.)
ruakh
3
Czy nie powinno to być „-ne” zamiast „-eq”?
Carlos Rendon
2
@CarlosRendon Kod Slatera uniemożliwia uruchomienie czegoś jako root. (Jest to przeciwieństwo tego, o co prosił PO, ale metoda sprawdzania byłaby taka sama.)
Joshua Taylor
11

Bardzo prosty sposób po prostu:

if [ "$(whoami)" == "root" ] ; then
    # you are root
else
    # you are not root
fi

Zaletą korzystania z tego zamiast idjest to, że możesz sprawdzić, czy pewien użytkownik inny niż root również uruchamia polecenie; na przykład.

if [ "$(whoami)" == "john" ] ; then
    # you are john
else
    # you are not john
fi
Matthew Trotter
źródło
jeśli testujesz użytkownika za pomocą ciągu „root”, czy nie pozwalasz na uruchamianie kogoś, kto nazywa się „root”?
pcarvalho
Zapomniałeś ';' po if
Triskeldeian
1
@peteroak, kto jeszcze miałby nazywać się root inny niż root?
ptierno
3
+1 za faktyczne udzielenie odpowiedzi na pytanie whoamizamiast używania id; whoamikomenda może być również używany do sprawdzenia innych użytkowników niż root, po imieniu.
Jez
10

0- Przeczytaj oficjalną dokumentację GNU Linux, istnieje wiele sposobów, aby zrobić to poprawnie.

1- upewnij się, że umieściłeś podpis powłoki, aby uniknąć błędów w interpretacji:

 #!/bin/bash

2 - to jest mój skrypt

#!/bin/bash 

if [[ $EUID > 0 ]]; then # we can compare directly with this syntax.
  echo "Please run as root/sudo"
  exit 1
else
  #do your stuff
fi
Sergio Abreu
źródło
10

W tej odpowiedzi, niech będzie jasne, zakładam, że czytelnik jest w stanie czytać, basha skrypty powłoki POSIX- a takie dash.

Uważam, że nie ma tu wiele do wyjaśnienia, ponieważ wysoko głosowane odpowiedzi dobrze tłumaczą wiele z nich.

Jeśli jednak jest coś, co można wyjaśnić dalej, nie wahaj się komentować, zrobię co w mojej mocy, aby wypełnić luki.


Zoptymalizowane kompleksowe (nie tylko bash) rozwiązanie zapewniające wydajność i niezawodność; kompatybilne z wszystkimi powłokami

Nowe rozwiązanie:

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

Benchmark (zapisz do pliku is_user_root__benchmark)

###############################################################################
##                          is_user_root() benchmark                         ##
##                  Bash is fast while Dash is slow in this                  ##
##          Tested with Dash version 0.5.8 and Bash version 4.4.18           ##
##                     Copyright: 2020 Vlastimil Burian                      ##
##                      E-mail: [email protected]                      ##
##                             License: GPL-3.0                              ##
##                               Revision: 1.0                               ##
###############################################################################

# intentionally, the file does not have executable bit, nor it has no shebang
# to use it, please call the file directly with your shell interpreter like:

# bash is_user_root__benchmark
# dash is_user_root__benchmark

# bool function to test if the user is root or not
is_user_root () { [ ${EUID:-$(id -u)} -eq 0 ]; }

# helper functions
print_time   () { date +"%T.%2N"; }
print_start  () { printf '%s' 'Start  : '; print_time; }
print_finish () { printf '%s' 'Finish : '; print_time; }

readonly iterations=10000

printf '%s\n' '______BENCHMARK_____'
print_start

i=1; while [ $i -lt $iterations ]; do
    is_user_root
    i=$((i + 1))
done

print_finish

Oryginalne rozwiązanie:

#!/bin/bash

is_user_root()
# function verified to work on Bash version 4.4.18
# both as root and with sudo; and as a normal user
{
    ! (( ${EUID:-0} || $(id -u) ))
}

if is_user_root; then
    echo 'You are the almighty root!'
else
    echo 'You are just an ordinary user.'
fi

^^^ Udowodniono, że przekreślone rozwiązanie nie przyspiesza, ale działa już od dłuższego czasu, więc zamierzam go tu trzymać tak długo, jak będzie to konieczne.


Wyjaśnienie

Ponieważ odczytanie zmiennej $EUIDstandardowej bash, efektywnego numeru identyfikatora użytkownika jest wiele razy szybsze niż wykonanie id -upolecenia POSIX -lyby znaleźć identyfikator użytkownika, to rozwiązanie łączy obie funkcje w ładnie zapakowaną funkcję. Jeśli i tylko wtedy, gdy $EUIDz jakiegokolwiek powodu nie jest dostępny, id -upolecenie zostanie wykonane, zapewniając, że otrzymamy odpowiednią wartość zwracaną bez względu na okoliczności .


Dlaczego publikuję to rozwiązanie po tylu latach, o które pytał OP

Cóż, jeśli dobrze widzę, powyżej brakuje fragmentu kodu.

Widzisz, istnieje wiele zmiennych, które należy wziąć pod uwagę, a jedną z nich jest połączenie wydajności i niezawodności .


Przenośne rozwiązanie POSIX + Przykład użycia powyższej funkcji

#!/bin/sh

# bool function to test if the user is root or not (POSIX only)
is_user_root() { [ "$(id -u)" -eq 0 ]; }

if is_user_root; then
    echo 'You are the almighty root!'
    exit 0 # unnecessary, but here it serves the purpose to be explicit for the readers
else
    echo 'You are just an ordinary user.' >&2
    exit 1
fi

Wniosek

O ile ci się to nie podoba, środowisko Unix / Linux jest bardzo zróżnicowane. Oznacza to, że są ludzie, którzy bashtak bardzo lubią , nawet nie myślą o przenośności ( powłoki POSIX ). Inni, tacy jak ja, wolą powłoki POSIX . Obecnie jest to kwestia osobistego wyboru i potrzeb.

LinuxSecurityFreak
źródło
6

Jeśli skrypt naprawdę wymaga dostępu do konta root, jego uprawnienia do plików powinny to odzwierciedlać. Posiadanie skryptu root wykonywalnego przez użytkowników innych niż root byłoby czerwoną flagą. Zachęcam do nie kontrolowania dostępu ifczekiem.

chown root:root script.sh
chmod u=rwx,go=r script.sh
John Kugelman
źródło
4
Jeśli ktoś ma swoje uprawnienia, aby to działało świetnie, ale mam wrażenie, że nadużywanie 777bomby powoduje, że ta kontrola jest trochę wadliwa dla użytkowników, którzy popełniliby błąd.
Slater Victoroff,
7
Zakłada się, że użytkownik uruchamia skrypt wykonywalny. Jeśli użytkownik po prostu zadzwoni bash /path/to/script, nadal można go uruchomićo=r
ptierno
5

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
Jestem ciekawy, dlaczego ta odpowiedź nie została wybrana wyżej? Wygląda na najprostszy i najczystszy. Czy są tu wady?
Bassinator,
@Bassinator Wierzę, że niektórzy twierdzą, że nie będzie działał na niektórych nixach, ale jak dotąd działa bezbłędnie na moim Linuksie. Spróbuj! Być może ta odpowiedź spóźniła się na wyścig, ale staram się dodać wiedzę, która jest prosta dla społeczności (zamiast dawać podobne odpowiedzi, jak większość w tym wątku: /) Głosuj, jeśli masz szczęście, żeby to przeczytać i to działa na twoim komputerze
alexandre1985
@TamusJRoyce Jeśli celem jest sprawdzenie, czy działasz jako root i nie zmuszanie skryptu do uruchamiania się tylko jako root, to dlaczego w każdej odpowiedzi, po sprawdzeniu, czy działa jako root, tworzą skrypt exit? Nadal te odpowiedzi są oceniane? Myślę, że ludzie domyślnie nie chcą, aby skrypt był uruchamiany jako root. Więc podążam za tym sposobem myślenia, z prostszą odpowiedzią. Ale tak, możesz także uczyć się z pełniejszych odpowiedzi powyżej
alexandre1985
@ alexandre1985 Dokładnie. Scenariusz: jeśli działa jako root, być może chcesz, aby skrypt domyślnie instalował program globalnie, gdy zapyta, jak chcesz go zainstalować. W przeciwnym razie ustawienie domyślne jest ustawione na instalację lokalną. Zamiast naciskać klawisz Enter użytkownik może zainstalować go globalnie lub lokalnie. Ale jeśli podoba im się domyślny, mogą nacisnąć Enter. I nie zostanie wyświetlony monit o hasło. Twój shebang nigdy nie „sprawdzi”, czy jesteś rootem (według tytułu). Ale nadal uważam, że ta odpowiedź jest przydatna.
TamusJRoyce,
@TamusJRoyce całkowicie ma sens Twój komentarz. Rzeczywiście jest to problem, a to rozwiązanie nie dotyczy tego przypadku użycia. Otworzyłeś moje perspektywy. Masz rację. Dzięki
alexandre1985
4

spróbuj następującego kodu:

if [ "$(id -u)" != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi

LUB

if [ `id -u` != "0" ]; then
    echo "Sorry, you are not root."
    exit 1
fi
MLSC
źródło
3

O ile wiem, poprawnym sposobem sprawdzenia jest:

if [ $(id -u) = "0" ]; then
    echo "You are root"
else
    echo "You are NOT root"
fi

Zobacz sekcję „Testowanie rootowania” tutaj:

http://linuxcommand.org/lc3_wss0080.php

WebBrother
źródło
1
wymienić = "0"z-eq 0
LinuxSecurityFreak
1
@LinuxSecurityFreak, zastąpię go, jeśli wyjaśnisz, dlaczego mam to zrobić.
WebBrother
2

id -ujest znacznie lepszy niż whoami, ponieważ niektóre systemy, takie jak Android, mogą nie zapewniać słowa root.

Przykład:

# whoami
whoami
whoami: unknown uid 0
Smeterlink
źródło
0
#!/bin/bash

# GNU bash, version 4.3.46
# Determine if the user executing this script is the root user or not

# Display the UID
echo "Your UID is ${UID}"

if [ "${UID}" -eq 0 ]
then
    echo "You are root"
else
    echo "You are not root user"
fi

Uwaga edytora: Jeśli nie potrzebujesz podwójnych nawiasów, użyj pojedynczych nawiasów do przenoszenia kodu.

Pramod Kharade
źródło
3
Nie wyjaśniłeś, dlaczego udzieliłeś alternatywnej odpowiedzi na pięcioletnie pytanie, na które jest już kilka odpowiedzi.
Styphon
0

Sprawdź, czy jesteś rootem i wyjdź, jeśli nie jesteś:

if ((EUID != 0)); then
    echo "Root or Sudo  Required for script ( $(basename $0) )"
    exit
fi

Lub w tym przykładzie spróbuj utworzyć katalog w lokalizacji głównej, a następnie spróbuj po podniesieniu uprawnień.

Sprawdź, czy jesteś rootem, a jeśli nie, to jeśli to możliwe:

# Fails to create these dirs (needs sudo)
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)

if ((EUID != 0)); then
    echo "Granting root privileges for script ( $(basename $0) )"
    if [[ -t 1 ]]; then
        sudo "$0" "$@"
    else
        exec 1> output_file
        gksu "$0" "$@"
    fi
    exit
fi
echo "Root privileges granted..."
# Creates Dirs as it now has rights
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)
Mike Q
źródło
-1

Sprawdź root:

ROOT_UID=0   # Root has $UID 0.

if [ "$UID" -eq "$ROOT_UID" ]
then
  echo "You are root."
else
  echo "You are just an ordinary user."
fi

exit 0

Testowane i działające w katalogu głównym.

fvillalba89
źródło