Come può uno script verificare se viene eseguito come root?


105

Sto scrivendo un semplice script bash, ma ne ho bisogno per verificare se viene eseguito come root o meno. So che probabilmente esiste un modo molto semplice per farlo, ma non ho idea di come.

Giusto per essere chiari:
Che cosa è un modo semplice per scrivere uno script foo.sh , in modo che il comando ./foo.shuscite 0e il comando sudo ./foo.shuscite 1?

Risposte:


151
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root" 
   exit 1
fi

7
Sto accettando questa causa (dopo alcuni test) usando la variabile di sistema EUID si è rivelata (circa 100 volte) più veloce dell'esecuzione di un comando (id -u), ma tutte le risposte hanno funzionato alla grande.
Malabarba,

18
Inoltre, $UIDe $EUIDsono bashismi. Solo le shell conformi a POSIX non hanno quelle variabili e devi id(1)invece usarle .
David Foerster,

3
in uno script bash, puoi usare if ((EUID)); then, vedi il commento di @ geirha
jfs,

7
@Andrew: le variabili vengono sostituite prima di essere passate a sudo. Se corri sudo sh -c 'echo $EUID'vedrai i risultati previsti.
M. Dudley,

6
@Andrew - So che sono in ritardo qui, ma per i posteri: $EUIDè un Bashism (come menzionato sopra da @DavidFoerster), e il tuo /bin/shè molto probabilmente un link a /bin/dash, no /bin/bash. sudo bash -c 'echo $EUID'produrrà il risultato atteso.
Adrian Günter,

118

Un utente root non deve essere chiamato "root". whoamirestituisce il primo nome utente con ID utente 0. $USERcontiene il nome dell'utente che ha effettuato l'accesso, che può avere un ID utente 0, ma con un nome diverso.

L'unico programma affidabile per verificare se l'account è connesso come root oppure no:

id -u

Uso -ul' ID utente effettivo , non -rl' ID utente reale . Le autorizzazioni sono determinate dalla effettiva ID utente, non il vero e proprio uno.

test

/etc/passwdcontiene i seguenti nomi utente con ID utente 0nell'ordine indicato:

rootx
root2

Effettuato l'accesso come root2, dà i seguenti risultati:

  • whoami: rootx
  • echo $USER: root2(restituisce una stringa vuota se il programma è stato avviato in un ambiente vuoto, ad es. env -i sh -c 'echo $USER')
  • id -u: 0 Come puoi vedere, gli altri programmi non sono riusciti in questo controllo, ma solo id -upassati.

Lo script aggiornato sarebbe simile al seguente:

#!/bin/bash
if ! [ $(id -u) = 0 ]; then
   echo "I am not root!"
   exit 1
fi


5
Cerco sempre di rimanere il più possibile conforme POSIX, usando sh( dash) come interprete anziché bash. Ma buon tiro, salva un altro fork :)
Lekensteyn

Dopo essere stato fuori per un po ', sono tornato e ho dato un'occhiata. Il metodo di Lekensteyn sembra davvero essere migliore. La sua risposta è ora la nuova risposta accettata. +1 a te, Lekensteyn, esp. per ottenere quel distintivo difficile da ottenere da questa domanda;)
Thomas Ward

Grazie per aver atteso così a lungo per aver accettato la mia domanda: DI ha ottenuto un badge Populista d'oro e un bronzo di Nizza Risposta per questa risposta :) Mi chiedo come questa domanda abbia avuto quella popolarità, 345 visualizzazioni in un giorno!
Lekensteyn,

3
Ho visto le versioni più corte, [ -w / ]. L'idea rimane la stessa. Nota: in alcuni chroot, [ -w /etc/shadow ]fallirà perché /etc/shadowè inesistente, quindi l'approccio con /è preferito. Un modo migliore sarebbe verificare l'effettiva necessità delle autorizzazioni di root. Se lo script deve scrivere /etc/someconfig, basta controllare se quel file è scrivibile OPPURE il file non esiste ed /etcè scrivibile.
Lekensteyn,

30

Come ha detto @Lekensteyn , dovresti usare un ID utente efficace. Non è necessario chiamare id -ubash:

#!/bin/bash

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

Il suggerimento di @ geirha dai commenti usa una valutazione aritmetica:

#!/bin/bash

if (( EUID != 0 )); then
   echo "You must be root to do this." 1>&2
   exit 100
fi

8
In generale si dovrebbe usare ((..))per testare numeri e [[..]]per testare stringhe e file, quindi farei if (( EUID != 0 )); theninvece, o semplicementeif ((EUID)); then
geirha

@geirha: ho aggiunto il tuo suggerimento.
jfs,

2
EUIDdovrebbe diventare $EUID. Invece di usare (( $EUID != 0 )), usa [ $EUID != 0 ]. Funzionerà dashanche con .
Lekensteyn,

2
@Lekensteyn: EUIDfunziona benissimo. La questione è aggiunto bashnon dash. Il comando ha env -i sh -c '[ $EUID != 0 ]'esito negativo, ma env -i bash -c '(( EUID != 0 ))'funziona. tra l'altro, dashnon funziona con alcuni caratteri non ascii su Ubuntu stackoverflow.com/questions/5160125/… È il 2011 e ci sono persone che usano altre lingue.
jfs,

Dopo aver guardato indietro su questo argomento mentre sono orribilmente annoiato e testato, userò questo metodo come elencato qui con le $EUIDcose da questo punto in avanti. Di conseguenza ho modificato la risposta accettata.
Thomas Ward

20

È possibile eseguire ciò utilizzando il whoamicomando, che restituisce l'utente corrente:

#!/bin/bash

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

...

In esecuzione quanto sopra verrà stampato You must be root to do this.se l'utente attuale non lo è root.


Nota: in alcuni casi un'alternativa è semplicemente controllare la $USERvariabile:

if [ $USER != 'root' ]

Dare un'occhiata al codice, vedere se non fa fallire lo script o qualcosa del genere. Se funziona, accetterò la tua risposta :)
Thomas Ward

4
@ George Edison: sconsiglio di utilizzarlo $USER, specialmente in questo modo. $USERè impostato dalla shell di login, non è necessario propagarsi al programma ( env -i sh -c 'echo $USER'). In tal modo, $USERè vuoto e si verifica un errore di sintassi.
Lekensteyn,

1
@Lekensteyn Non solo è $USERimpostato dalla shell, ma è anche qualcosa che è facile da falsificare. Whoami restituirà l'utente effettivo.
Paul de Vrieze,

2
@PauldeVrieze Che senso ha ingannare quel controllo?
htorque,

1
@andrewsomething: $USERè interpretato dalla tua shell, il tuo esempio dovrebbe essere sudo sh -c 'echo $USER'per essere significativo. @Gorge: fa un'ipotesi sbagliata che whoamitornerà sempre rootper UID 0.
sam hocevar

10

Prendendo in considerazione l'efficienza, è possibile testare prima la EUIDvariabile d'ambiente e quindi, se non esiste, chiamare il idcomando standard :

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

In questo modo, a causa del collegamento OR , si evita di chiamare un comando di sistema, dando la priorità alla query di una variabile in memoria.

Riutilizzo del codice:

function amIRoot() {
  ! ((${EUID:-0} || "$(id -u)"))
}

1
Temo che tu non l'abbia confrontato, beh l'ho fatto e questo richiede lo stesso tempo di id -u. Vedi lo script del banco insieme ai risultati sottostanti qui: pastebin.com/srC3LWQy
LinuxSecurityFreak

((${EUID:-0} || "$(id -u)"))funziona sempreid -u , così come entrambi ((1 || $(echo hi >&2; echo 1)))e ((0 || $(echo hi >&2; echo 1)))stampa hi. Aritmetica della shell esterna&& e ||sono operatori di controllo; in a || "$(b)", bviene eseguito solo se "$(b)"viene eseguito. La maggior parte delle espansioni, inclusa la sostituzione dei comandi, sono regolate dalla semantica di cortocircuito degli operatori di controllo. L'aritmetica della shell ha anche degli operatori che sono stati digitati &&e ||, anche in questo caso, ((1 || 0/0))un cortocircuito non è un errore, ma l'aritmetica della shell si verifica dopo l' espansione delle sostituzioni di comandi nidificati.
Eliah Kagan


2

Un modo semplice per rendere lo script eseguibile solo da root è quello di avviare lo script con la riga:
#!/bin/su root


1
Non farlo Tenta di accedere direttamente come root, mentre sudo può essere richiesto su molti sistemi perché il primo è proibito. Inoltre, lo shebang ha lo scopo di garantire che lo script venga eseguito in quello per cui è stato progettato, mentre il metodo farà sì che lo script venga eseguito nella shell predefinita di root, che non può essere prevista se lo script viene eseguito da chiunque non sia l'autore. Pertanto, l'utilizzo di shebang per elevare i privilegi di uno script ne comprometterà gravemente la portabilità e causerà errori su molti sistemi. (su:
Errore di


1

Questo frammento dovrebbe:

  • Controlla sessioni diverse
  • suggerire di usare sudo !!
  • e restituisce un errore
if ["$ (whoami & 2> / dev / null)"! = "root"] && ["$ (id -un & 2> / dev / null)"! = "root"]
      poi
      echo "Devi essere root per eseguire questo script!"
      echo "usa 'sudo !!'"
      uscita 1
fi

1

Questa risposta è solo per salvare un'idea con può essere utile per alcuni di voi. Se hai bisogno di uno script che viene eseguito dalla GUI desktop e richiede i privilegi di root, prova in questo modo:

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

In questo modo otterrai una bella finestra di dialogo che ti chiederà la password dell'utente root. Proprio come con la riga di comando sudo.

L' gksudopotrebbero non essere disponibili nel vostro sistema quindi installarlo con sudo apt-get install gksu.


0

Questo codice funziona sia con Bash che con Bourne sh (testato sotto FreeBSD) che non definisce EUID. Se EUID esiste, viene restituito il suo valore, altrimenti viene eseguito il comando 'id'. È un po 'più breve dell'esempio "o" sopra, poiché usa una shell incorporata ": -".

Radice in 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.