"Perché non riesco a scrivere in questa cartella?" "Perché non posso usare Docker?" Quasi sempre la risposta sta in due domande: chi è l'utente con cui stai lavorando e a quali gruppi appartiene. id risponde a entrambe in una riga, con i numeri che il sistema usa davvero per decidere cosa puoi fare.
Cos'è
id fa parte del pacchetto coreutils ed è presente su ogni distribuzione. In Linux ogni utente e ogni gruppo ha un nome, comodo per le persone, e un numero, quello che il kernel usa per confrontare i permessi: lo UID (user ID) per gli utenti e il GID (group ID) per i gruppi. id mostra entrambi, e fa da ponte tra i nomi e i numeri.
Cosa fa
Stampa l'identità di un utente: il suo UID, il suo gruppo principale e l'elenco di tutti i gruppi a cui appartiene. Senza argomenti parla dell'utente con cui stai lavorando; con un nome parla di quell'utente. Con le opzioni mostra solo una parte dei dati, in una forma comoda per gli script.
Come si usa
$ id [opzioni] [utente]Gli esempi mostrano un utente chiamato enzo su un server Debian.
Esempio 1: il comando senza opzioni
$ id
uid=1000(enzo) gid=1000(enzo) groups=1000(enzo),27(sudo),33(www-data),999(docker)Il risultato ha tre parti:
uid=1000(enzo): il numero e il nome dell'utente;gid=1000(enzo): il gruppo principale, quello che di solito viene assegnato ai nuovi file che crei (su Debian e Ubuntu ogni utente ha un gruppo personale con lo stesso nome);groups=...: tutti i gruppi, principale compreso. Quienzoè anche nel grupposudo(può usaresudo, vedi l'articolo relativo), inwww-data(il gruppo dei file del sito web) e indocker.
Esempio 2: capire i numeri
$ id root
uid=0(root) gid=0(root) groups=0(root)
$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ id nobody
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)I numeri seguono una convenzione:
- 0 è sempre
root, l'amministratore: il kernel non guarda il nome, guarda il numero zero; - da 1 a 999: gli utenti "di sistema", usati dai servizi (
www-dataper il web server,mysqlper il database), che non fanno accesso come persone; - da 1000 in poi: gli utenti normali, cioè le persone (su Debian e Ubuntu il primo creato è 1000; su alcune distribuzioni più vecchie si parte da 500);
- 65534 è
nobody, un utente senza alcun privilegio, usato per i processi da isolare.
Esempio 3: una informazione alla volta
$ id -u
1000
$ id -g
1000
$ id -un
enzo
$ id -gn
enzo
$ id -G
1000 27 33 999
$ id -Gn
enzo sudo www-data dockerLe lettere scelgono cosa vedere: -u (user) lo UID, -g (group) il gruppo principale, -G tutti i gruppi. Aggiungendo -n (name) si ottengono i nomi al posto dei numeri. L'output è semplice, senza etichette, e perfetto da usare in uno script.
Esempio 4: i gruppi con groups
$ groups
enzo sudo www-data docker
$ groups www-data
www-data : www-dataIl comando groups elenca i nomi dei gruppi di un utente: è l'equivalente di id -Gn. Con un nome come argomento, ripete il nome e mostra i suoi gruppi.
Esempio 5: un altro utente, e un utente che non esiste
$ id backup
uid=34(backup) gid=34(backup) groups=34(backup)
$ id nonesiste
id: 'nonesiste': no such userCon un nome come argomento id mostra l'identità di quell'utente, anche se non è collegato: non servono privilegi particolari. Se l'utente non esiste, l'errore è di questo tipo (il testo cambia con la lingua del sistema) e il comando restituisce un codice di uscita diverso da zero, utile negli script per verificare l'esistenza di un utente.
Esempio 6: perché i numeri contano, nei permessi
$ ls -l /var/www/html/index.php
-rw-r--r-- 1 www-data www-data 1520 28 ott 10:12 /var/www/html/index.php
$ ls -ln /var/www/html/index.php
-rw-r--r-- 1 33 33 1520 28 ott 10:12 /var/www/html/index.phpNell'output di ls -l (vedi l'articolo su ls e quello su chmod e chown) i nomi del proprietario e del gruppo sono traduzioni dei numeri: con -n si vedono quelli veri, 33 e 33. Il file appartiene a www-data e il suo gruppo può leggerlo ma non modificarlo. Se enzo è nel gruppo www-data, può leggerlo; per modificarlo servirebbero permessi di gruppo in scrittura (g+w). È proprio l'elenco dei gruppi di id che decide.
Esempio 7: dove sono scritte queste informazioni
$ getent passwd enzo
enzo:x:1000:1000:Enzo,,,:/home/enzo:/bin/bash
$ getent group sudo
sudo:x:27:enzo
$ grep enzo /etc/group
sudo:x:27:enzo
www-data:x:33:enzo
docker:x:999:enzo
enzo:x:1000:Gli utenti sono descritti in /etc/passwd e i gruppi in /etc/group: sono file di testo, con campi separati da due punti. La riga di passwd dice, nell'ordine: nome, x (la password è in un altro file protetto), UID, GID principale, nome completo, cartella personale e shell. La riga di group dice nome, x, GID e l'elenco dei membri (il gruppo principale non compare nell'elenco, perché è già indicato in passwd). getent è il modo corretto di interrogarli, perché funziona anche con gli utenti definiti altrove (per esempio un servizio centralizzato di accessi).
Esempio 8: aggiungere un gruppo e vedere l'effetto
$ sudo usermod -aG docker enzo
$ id -Gn
enzo sudo www-data
$ newgrp docker
$ id -Gn
docker enzo sudo www-data
$ exitCon usermod -aG gruppo utente si aggiunge un utente a un gruppo (la -a, append, è fondamentale: senza di essa si sostituisce l'elenco dei gruppi!). Subito dopo, però, id non mostra ancora il nuovo gruppo: i gruppi vengono letti al momento dell'accesso, quindi il cambiamento vale solo per le sessioni nuove. Per usarlo subito si può aprire una shell con newgrp docker (e uscirne con exit), oppure ci si scollega e ci si ricollega.
Esempio 9: cosa cambia con sudo
$ id -un
enzo
$ sudo id
uid=0(root) gid=0(root) groups=0(root)
$ sudo -u www-data id
uid=33(www-data) gid=33(www-data) groups=33(www-data)sudo id è un modo semplice per verificare che sudo funzioni, e mostra che il comando è stato eseguito con un'altra identità. Con sudo -u utente si prova a lavorare come un altro utente: molto comodo per capire se un servizio (come www-data) riesce a leggere o scrivere un file, con un comando come sudo -u www-data ls /var/www/html.
Esempio 10: uso negli script
#!/bin/bash
if [ "$(id -u)" -ne 0 ]; then
echo "Questo script va eseguito come root (usa sudo)." >&2
exit 1
fi
UTENTE="www-data"
if ! id "$UTENTE" >/dev/null 2>&1; then
echo "L'utente $UTENTE non esiste" >&2
exit 1
fi
if id -nG "$SUDO_USER" | grep -qw docker; then
echo "$SUDO_USER usa Docker senza sudo"
fiTre usi tipici. Il primo controlla di essere root, confrontando id -u con zero: lo script si ferma con un messaggio chiaro, scritto sull'errore standard (>&2). Il secondo verifica che un utente esista, usando solo il codice di uscita di id e scartando l'output (>/dev/null). Il terzo controlla l'appartenenza a un gruppo: grep -qw cerca la parola intera, senza stampare niente. La variabile $SUDO_USER contiene il nome di chi ha lanciato sudo, e vale solo quando lo script viene eseguito con sudo.
Opzioni utili
-u: solo lo UID;-g: solo il GID principale;-G: tutti i GID.-n: nomi al posto dei numeri (con-u,-go-G).-r: identità reale invece di quella effettiva (vedi l'avvertenza più sotto).-Z: contesto di sicurezza SELinux (funziona solo dove SELinux è attivo, come in Fedora e RHEL).groups: i nomi dei gruppi;whoami: solo il nome utente;who,w: chi è collegato.getent passwd,getent group: i dati di utenti e gruppi, ovunque siano definiti.usermod -aG,newgrp: aggiungere un utente a un gruppo, usare un gruppo subito.
Attenzione a
- I gruppi si aggiornano al prossimo accesso: dopo
usermod -aGl'utente non ha ancora i nuovi permessi nelle sessioni già aperte. È la causa più frequente di "ho aggiunto il gruppo ma non funziona": basta uscire e rientrare, o usarenewgrp. - Senza
-a,usermod -Gcancella gli altri gruppi: scrivereusermod -G docker enzolascia l'utente solo nel gruppodocker, togliendogli per esempiosudo. Sul server, se non hai un'altra utenza amministrativa, puoi perdere l'accesso privilegiato. Usa sempre-aG. - Alcuni gruppi valgono come
root: chi fa parte didockerpuò avviare un container con la radice del disco montata e fare quello che vuole sul sistema, di fatto senza password. Lo stesso vale persudoe, in modo meno diretto, per gruppi comedisk. Controlla conidchi li ha, e dai questi gruppi solo a chi è fidato. - Un nome non è un'identità: lo è il numero: due macchine possono avere lo stesso nome con numeri diversi (
enzocon UID 1000 su una e 1001 su un'altra). Conrsync,taro cartelle condivise in rete, i file portano il numero, e il proprietario può risultare sbagliato o mostrato come un numero senza nome (ls -lmostra1001). Allinea gli UID quando condividi dati tra più macchine. - Un utente cancellato lascia dei file orfani: se togli un utente senza togliere i suoi file, restano con il numero di prima, e un utente creato in seguito con lo stesso numero ne diventa il proprietario. Trovali con
find / -nouser(vedi l'articolo sufind). - Utente reale ed effettivo: alcuni programmi (come
passwdosudo) sono "setuid": girano con l'identità del proprietario, cioèroot, anche se li lancia un utente normale.id -umostra l'identità effettiva,id -ruquella reale, di chi ha lanciato il programma. Di solito coincidono. - Nei container gli utenti sono relativi: dentro un container
idmostra gli utenti definiti nel container. L'utente 0 (root) del container può corrispondere a un altro numero sul server, secondo la configurazione. $UIDe$EUIDsono solo dibash: negli script scritti per la shell più semplice (sh) conviene usareid -u, che funziona ovunque.- L'output rivela dati sensibili: l'elenco dei gruppi dice, a chi lo legge, quali privilegi ha un account (per esempio se può usare
sudoodocker). Nelle richieste di aiuto pubbliche, incolla solo quello che serve.
Riepilogo
| Comando | Cosa fa |
|---|---|
id | Mostra UID, GID e gruppi dell'utente attuale |
id utente | Mostra l'identità di un altro utente |
id -u | Solo lo UID (0 vuol dire root) |
id -un | Solo il nome dell'utente |
id -Gn | Nomi di tutti i gruppi |
groups | Come id -Gn |
sudo id | Verifica che sudo funzioni e mostra l'identità di root |
sudo -u utente id | Mostra l'identità di un altro utente, eseguendo come lui |
getent passwd utente | Riga dell'utente: UID, cartella personale, shell |
ls -ln | Proprietario e gruppo dei file, in numeri |
sudo usermod -aG gruppo utente | Aggiunge un utente a un gruppo |
newgrp gruppo | Apre una shell con il nuovo gruppo, senza riaccedere |