|
|
Linux paper Lastlog 
|
di SDNS
|
L'utility lastlog permette di esaminare il file /var/log/lastlog, attraverso il
quale si puo visualizzare l'ultimo login effettuato di ogni user. Le stesse
informazioni sono memorizzate sul file /var/log/lastlog.
Il file lastlog e' una sorta di database sul quale, come detto in precedenza,
viene memorizzato l'ultimo accesso di ogni user (non ci dilungheremo sulla
sua funzionalita', per maggiori dettagli visualizzare il relativo manual page).
L'output del comando è il seguente:
| bash-3.1# lastlog |
| Username | Port | From | Latest |
| root | pts/8 | osiris.. | Fri Jul 11 22:24:14 +0200 2008 |
| bin | **Never logged in** |
| daemon | **Never logged in** |
| adm | **Never logged in** |
| lp | **Never logged in** |
| sync | **Never logged in** |
| shutdown | **Never logged in** |
| halt | **Never logged in** |
| mail | **Never logged in** |
| news | **Never logged in** |
| uucp | **Never logged in** |
| operator | **Never logged in** |
| games | **Never logged in** |
| ftp | **Never logged in** |
| smmsp | **Never logged in** |
| mysql | **Never logged in** |
| rpc | **Never logged in** |
| sshd | **Never logged in** |
| gdm | **Never logged in** |
| apache | **Never logged in** |
| messagebus | **Never logged in** |
| haldaemon | **Never logged in** |
| pop | **Never logged in** |
| nobody | **Never logged in** |
Ogni Username puo essere considerato come un'entry del database.
La memorizzazione su tale file avviene per mezzo di una struttura definita in
/usr/include/bits/utmp.h:
|
#define UT_LINESIZE 32
#define UT_NAMESIZE 32
#define UT_HOSTSIZE 256
/* The structure describing an entry in the database of previous logins.*/
struct lastlog
{
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
int32_t ll_time;
#else
__time_t ll_time;
#endif
char ll_line[UT_LINESIZE];
char ll_host[UT_HOSTSIZE];
};
|
tale struttura, costituisce la dimensione effettiva dell'entry riguardante
l'user. La memorizzazione all'interno del file avviene in base alla dimensione
della struttura, precedentemente indicata, e all'uid (User ID). Per ogni user
(o entry) viene dedicata una certa quantità di spazio, precisamente 292 byte,
che corrisponde alla dimensione della struttura lastlog (sizeof(struct lastlog)).
Il posizionamento delle rispettive entry nel file non sono lasciate al caso, per
esempio scritte in coda come avverrebbe in un normale database, la sua posizione
all'interno del file è calcolata da "sizeof(struct lastlog) * uid".
Per capire meglio possiamo procedere con un esempio:
Supponiamo di volerci loggare sul sistema mediante l'utility di amministrazione
OpenSSH utilizzando il relativo client e proviamo a loggarci con l'user avente
uid 1000, nello stesso momento possiamo vedere cosa avviene durante l'esecuzione
del processo preso in considerazione, mediante il comando "strace -p pid"
(per pid si intente il process ID del processo del demone sshd che si occupa della
procedura di login).
Quindi, dopo esserci assicurati di avere il demone avviato, avviare una sessione
di login con il seguente comando:
| bash-3.1$ ssh username@192.168.1.3 |
in seguito verra richiesta la password, lasciarlo vuoto in quanto dobbiamo trovare
il pid del processo che prenderemo in considerazione.
Per ottenere il seguente pid digitare il seguente comando:
bash-3.1$ ps aux | grep sshd
root 2456 0.0 0.0 3856 984 ? Ss Jul28 0:00 /usr/sbin/sshd
root 28485 0.1 0.0 5204 1784 ? Ss 18:38 0:00 sshd: username [priv]
sshd 28488 0.0 0.0 5204 1100 ? S 18:38 0:00 sshd: username [net]
|
il processo che prenderemo in considerazione è quello con il pid 28485, avviare in seguito
l'utility strace relativa al processo, e procedere con il login, inserendo la password
richiesta in modo tale che la scrittura del file /var/log/lastlog sia avvenuta.
Supponendo che l'user "username" abbia uid 1000 abbiamo ricavato dall'utility strace
il seguente output:
user con uid 1000
|
stat64("/var/log/lastlog", {st_mode=S_IFREG|0644, st_size=292584, ...}) = 0
open("/var/log/lastlog", O_RDWR|O_CREAT|O_LARGEFILE, 0600) = 7
_llseek(7, 292000, [292000], SEEK_SET) = 0
write(7, "|\271wHpts/8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 292) = 292
close(7)
|
Come si puo vedere, si accedere al file in scrittura, poi si posiziona alla posizione 292000,
che corrisponde a sizeof(struct lastlog) * uid, ovvero 292 * 1000 = 292000, che come potete
vedere corrisponde alla posizione dove si trovano le informazioni dell'user richiesto.
Ulteriori prove sono state fatte con appositi user creati con uid 1001, 1003, 10013 e 60000
(il massimo uid definito in /etc/login.defs).
user con uid 1001
|
stat64("/var/log/lastlog", {st_mode=S_IFREG|0644, st_size=292584, ...}) = 0
open("/var/log/lastlog", O_RDWR|O_CREAT|O_LARGEFILE, 0600) = 7
_llseek(7, 292292, [292292], SEEK_SET) = 0
write(7, "\23\274wHpts/5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 292) = 292
|
user con uid 1003
|
stat64("/var/log/lastlog", {st_mode=S_IFREG|0644, st_size=292584, ...}) = 0
open("/var/log/lastlog", O_RDWR|O_CREAT|O_LARGEFILE, 0600) = 7
_llseek(7, 292876, [292292], SEEK_SET) = 0
write(7, "\23\274wHpts/5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 292) = 292
|
user con uid 1013
|
stat64("/var/log/lastlog", {st_mode=S_IFREG|0644, st_size=292584, ...}) = 0
open("/var/log/lastlog", O_RDWR|O_CREAT|O_LARGEFILE, 0600) = 7
_llseek(7, 295796, [292292], SEEK_SET) = 0
write(7, "\23\274wHpts/5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 292) = 292
|
Si puo' notare che l'offset tra l'user con 1003 e l'user con uid 1013 varia di circa 2920 byte:
uid 1003 = 292876 -
uid 1013 = 295796 = 2920
|
che corrisponde a 292 * 10, ovvero lo spazio degli altri 10 user mancanti!!
E' da notare anche la differenza del file con user uid consegutivi e con uid uguale a 60000:
bash-3.1# du -b /var/log/lastlog
| 296088 /var/log/lastlog
|
bash-3.1# du -b /var/log/lastlog
| 17520292 /var/log/lastlog
|
Puo' sembrare che la memorizzazione del lastlog avvenga parallelamente al file /etc/passwd, ma
è da precisare che la memorizzazione del lastlog avviene in ordine parallelo agli uid occupati,
l'utilizzo del valore univoco UID per il calcolo dell'offset, permette di avere uno spazio
dedicato per ogni user, ordinato, permettendo cosi ai programmi che utilizzano tale file
di posizionarsi in maniera corretta alla posizione desiderata senza dover effettuare operazioni
di ricerca.
E' da sottolineare che durante la prova con uid massimo consentito, lo spazio viene allocato alla
posizione derivata da sizeof(struct lastlog) * uid, come detto in precedenza, ma nel caso in cui
volessimo aggiungere un user con uid 5000, è da ricordare che lo spazio per tale user è gia stato
allocato, quindi non ci sarebbe un'ulteriore utilizzo di memoria.
In breve, viene dedicato uno spazio per ogni user di 292 byte, nel caso in cui l'uid sia superiore
ma non consecutivo all'ultimo presente, viene allocato spazio per gli user mancanti con i possibili
uid non utilizzati.
Per poter aggiornare il file lastlog, quindi si puo procedere con l'apertura del file in scrittura
e lettura , posizionarsi sulla posizione dell'user preso in considerazione, riempire la struttura
manualmente o leggendo direttamente dal file, cambiare gli appositi valori, riposizionarsi
sull'offset desiderato e in seguito scrivere sul file.
|
|