Salta al contenuto principale

id: chi sei e a quali gruppi appartieni

Inviato da tuxsa il

"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. Qui enzo è anche nel gruppo sudo (può usare sudo, vedi l'articolo relativo), in www-data (il gruppo dei file del sito web) e in docker.

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-data per il web server, mysql per 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 docker

Le 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-data

Il 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 user

Con 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.php

Nell'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
$ exit

Con 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"
fi

Tre 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, -g o -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 -aG l'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 usare newgrp.
  • Senza -a, usermod -G cancella gli altri gruppi: scrivere usermod -G docker enzo lascia l'utente solo nel gruppo docker, togliendogli per esempio sudo. 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 di docker può avviare un container con la radice del disco montata e fare quello che vuole sul sistema, di fatto senza password. Lo stesso vale per sudo e, in modo meno diretto, per gruppi come disk. Controlla con id chi 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 (enzo con UID 1000 su una e 1001 su un'altra). Con rsync, tar o cartelle condivise in rete, i file portano il numero, e il proprietario può risultare sbagliato o mostrato come un numero senza nome (ls -l mostra 1001). 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 su find).
  • Utente reale ed effettivo: alcuni programmi (come passwd o sudo) sono "setuid": girano con l'identità del proprietario, cioè root, anche se li lancia un utente normale. id -u mostra l'identità effettiva, id -ru quella reale, di chi ha lanciato il programma. Di solito coincidono.
  • Nei container gli utenti sono relativi: dentro un container id mostra gli utenti definiti nel container. L'utente 0 (root) del container può corrispondere a un altro numero sul server, secondo la configurazione.
  • $UID e $EUID sono solo di bash: negli script scritti per la shell più semplice (sh) conviene usare id -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 sudo o docker). Nelle richieste di aiuto pubbliche, incolla solo quello che serve.

Riepilogo

ComandoCosa fa
idMostra UID, GID e gruppi dell'utente attuale
id utenteMostra l'identità di un altro utente
id -uSolo lo UID (0 vuol dire root)
id -unSolo il nome dell'utente
id -GnNomi di tutti i gruppi
groupsCome id -Gn
sudo idVerifica che sudo funzioni e mostra l'identità di root
sudo -u utente idMostra l'identità di un altro utente, eseguendo come lui
getent passwd utenteRiga dell'utente: UID, cartella personale, shell
ls -lnProprietario e gruppo dei file, in numeri
sudo usermod -aG gruppo utenteAggiunge un utente a un gruppo
newgrp gruppoApre una shell con il nuovo gruppo, senza riaccedere