UTMP(5)

NAZWA
utmp, wtmp - zapisy o logowaniu

SKŁADNIA
#include <utmp.h>

OPIS
Plik utmp umożliwia znalezienie informacji o tym, kto w danej chwili korzysta z systemu. Z systemu może korzystać więcej użytkowników, ponieważ nie wszystkie programy zapisują informacje do utmp.

Ostrzeżenie: utmp musi być niezapisywalnym plikiem, ponieważ wiele programów systemowych (głupio) polega na jego integralności. Istnieje ryzyko sfałszowania logów systemowych i modyfikacji plików systemowych, jeśli utmp będzie zapisywalny dla użytkowników.

Plik ten jest sekwencją wpisów o postaci następującej struktury zdeklarowanej w pliku nagłówkowym (należy zwrócić uwagę, że jest to jedna z wielu definicji; szczegóły zależą od wersji libc):

#define UT_UNKNOWN      0
#define RUN_LVL         1
#define BOOT_TIME       2
#define NEW_TIME        3
#define OLD_TIME        4
#define INIT_PROCESS    5
#define LOGIN_PROCESS   6
#define USER_PROCESS    7
#define DEAD_PROCESS    8
#define ACCOUNTING      9
#define UT_LINESIZE     12
#define UT_NAMESIZE     32
#define UT_HOSTSIZE     256
struct exit_status {
  short int e_termination;    /* kod przerwania procesu. */
  short int e_exit;           /* kod zakończenia procesu. */
};
struct utmp {
  short ut_type;              /* rodzaj logowania */
  pid_t ut_pid;               /* PID procesu logującego */
  char ut_line[UT_LINESIZE];  /* nazwa urządzenia tty - "/dev/" */
  char ut_id[4];              /* id init lub skrót nazwy tty */
  char ut_user[UT_NAMESIZE];  /* nazwa użytkownika */
  char ut_host[UT_HOSTSIZE];  /* nazwa hosta dla zdalnego logowania */
  struct exit_status ut_exit; /* kod zakończenia procesu
                                 oznaczonego jako DEAD_PROCESS */

  /* Pola ut_session i ut_tv muszą mieć ten sam rozmiar, gdy są
     kompilowane 32- i 64-bitowo.Pozwala to dzielenie plików danych
     pamięci współdzielonej pomiędzy aplikacjami 32- i 64-bitowymi*/
#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
  int32_t ut_session;         /* ID sesji, służy do okienkowania */
  struct {
    int32_t tv_sec;           /* Sekundy */
    int32_t tv_usec;          /* Mikrosekundy */
  } ut_tv;                    /* Czas utworzenia wpisu */
#else
   long int ut_session;       /* ID sesji, służy do okienkowania */
   struct timeval ut_tv;      /* Czas utworzenia wpisu */
#endif
  int32_t ut_addr_v6[4];      /* Adres IP zdalnego komputera */
  char __unused[20];          /* Zarezerwowane na przyszłość */
};
/* Dla zgodności w wcześniejszymi wersjami */
#define ut_name ut_user
#ifndef _NO_UT_TIME
#define ut_time ut_tv.tv_sec
#endif
#define ut_xtime ut_tv.tv_sec
#define ut_addr ut_addr_v6[0]

Struktura ta podaje nazwę pliku specjalnego skojarzonego z terminalem użytkownika, nazwę użytkownika i czas zalogowania w postaci time(2). Pola tekstowe są zakończone przez '\0', jeżeli są krótsze niż rozmiar pola.

Pierwsze wpisy, jakie kiedykolwiek utworzono, pochodzą od init(8) przetwarzającego inittab(5). Zanim jakikolwiek wpis zostanie utworzony, init(8) czyści utmp przez wpisanie DEAD_PROCESS do ut_type, wypełniając ut_user, ut_host i ut_time bajtami null we wszystkich rekordach, w których ut_type nie jest ustawione na DEAD_PROCESS lub RUN_LVL i dla których nie istnieje proces o PID równym ut_pid. Jeśli nie znajdzie się żaden pusty rekord z wymaganym ut_id, init tworzy nowy. Wpisuje do niego ut_id z inittab, ut_pid i ut_time nadaje bieżące wartości, a ut_type nadaje wartość INIT_PROCESS.

getty(8) lokalizuje wpis po numerze PID, zmienia ut_type na LOGIN_PROCESS, zmienia ut_time, ustawia ut_line i czeka na zestawienie połączenia. Po autentykacji użytkownika, login(8) zmienia ut_type na USER_PROCESS, zmienia ut_time i nadaje wartości ut_host i ut_addr. Zależnie od wersji getty(8) i login(8), rekordy mogą być wyszukiwane na podstawie ut_line zamiast preferowanego ut_pid.

Gdy init(8) stwierdzi, że proces zakończył pracę, to znajduje jego wpis utmp według ut_pid, ustawia ut_type na DEAD_PROCESS i wypełnia ut_user, ut_host oraz ut_time bajtami null.

xterm(1) i inne emulatory terminali tworzą bezpośrednio rekord USER_PROCESS i generują ut_id, używając ostatnich dwóch liter /dev/ttyp%c lub używając p%d dla /dev/pts/%d. Jeśli znajdą dla tego id wpis DEAD_PROCESS, utylizują go, w innym wypadku tworzą nowy wpis. Jeśli mogą, zaznaczają go jako DEAD_PROCESS podczas kończenia pracy i jest zalecane, by zerowały również ut_line, ut_time, ut_user oraz ut_host.

xdm(1) nie powinien tworzyć rekordu w utmp, ponieważ nie ma przydzielonego terminala. Pozwalanie mu na utworzenie takowego spowoduje błędy takie jak 'finger: cannot stat /dev/machine.dom'. Jednak powinien on tworzyć wpisy wtmp, tak jak to czyni ftpd(8).

telnetd(8) ustawia wpis LOGIN_PROCESS i zostawia po prostu resztę programowi login(8). Po zakończeniu sesji telnetu, telnetd(8) czyści utmp w opisany sposób.

Plik wtmp śledzi wszystkie zalogowania i wylogowania. Jego format jest taki jak utmp, poza tym, że pusta nazwa użytkownika wskazuje na jego wylogowanie z odpowiedniego terminala. Co więcej, nazwa terminala ~ w połączeniu z nazwą użytkownika shutdown czy reboot wskazuje na zamknięcie lub restart systemu, a para nazw terminali |/} loguje nowy/stary czas systemowy w przypadku jego zmiany za pomocą date(1). wtmp jest obsługiwane przez login(1), init(1) oraz niektóre wersje getty(1). Żaden z tych programów nie tworzy tego pliku, więc jeśli zostanie on usunięty, zapisy do niego zostaną wyłączone.

Proszę zauważyć, że na platformach, które mogą uruchamiać zarówno 32-bitowe, jaki 64-bitowe aplikacje (x86-64, ppc64, s390x itd.), rozmiary pola ut_tvmusi być taki same w trybie 32-bitowym, co w 64-bitowym. Podobnie jest z polami ut_session i ut_time, jeśli są obecne. Pozwala to na dzielenie plików danych i pamięci współdzielonej pomiędzy aplikacjami 32- i 64-bitowymi. Ponieważ ut_tv może nie być takie samo jak struct timeval, to zamiast wywoływania:

    gettimeofday((struct timeval *) &ut.ut_tv, NULL);
zaleca się używanie poniższej metody do ustawiania wartości w tym polu:

    struct utmp ut;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    ut.ut_tv.tv_sec = tv.tv_sec;
    ut.ut_tv.tv_usec = tv.tv_usec;

PLIKI
/var/run/utmp
/var/log/wtmp

ZGODNE Z
Wpisy utmp Linuksa nie są zgodne ani z v7/BSD ani z Systemem V, ale są mieszaniną tych dwóch. v7/BSD ma mniej pól; najważniejszym problemem jest brak ut_type, który powoduje że natywne programy v7/BSD wyświetlają (na przykład) wpisy dead lub login. Co więcej, nie ma pliku konfiguracyjnego, który przydziela rekordy sesjom. BSD tak robi, ponieważ nie ma on pól ut_id. W Linuksie (tak jak w Systemie V), pole ut_id rekordu nigdy nie ulega zmianie, kiedy raz zostanie mu nadana wartość, co rezerwuje ten rekord bez potrzeby pliku konfiguracyjnego. Czyszczenie ut_id może prowadzić do sytuacji wyścigu, których skutkiem będą uszkodzone wpisy w utmp i potencjalne dziury w bezpieczeństwie. Czyszczenie wymienionych wyżej pól przez wypełnianie ich bajtami null nie jest wymagane przy semantyce Systemu V, lecz pozwala na uruchamianie wielu programów, które zakładają semantykę BSD a nie modyfikują utmp. Linux używa konwencji BSD dla zawartości pola line, jak opisano wyżej.

System V używa pola type tylko do ich zaznaczania i loguje komunikaty informacyjne, takie jak np. "new time" w polu line. UT_UNKNOWN wydaje się być wymyślone w Linuksie. System V nie ma pól ut_host czy ut_addr_v6.

W przeciwieństwie do wielu innych systemów, gdzie utmp można wyłączyć przez usunięcie tego pliku, w Linuksie utmp zawsze musi istnieć. W celu wyłączenia who(1) należy jedynie uniemożliwić odczyt utmp dla całego świata.

Trzeba zwrócić uwagę, że struktura utmp z libc5 uległa zmianie w libc6. Z tego powodu binaria korzystające ze starej struktury libc5 będą uszkadzać /var/run/utmp i/lub /var/log/wtmp. System Debian zawiera połataną wersję libc5, która korzysta z nowego formatu utmp. Natomiast wciąż istnieje problem z wtmp, gdyż dostęp do tego pliku odbywa się w libc5 bezpośrednio.

OGRANICZENIA
Format pliku jest zależny od maszyny, więc jest zalecane, by plik był przetwarzany tylko na maszynie na której został utworzony.

Proszę zauważyć, że na platformach, które mogą uruchamiać zarówno 32-bitowe, jaki 64-bitowe aplikacje (x86-64, ppc64, s390x itd.), rozmiary pól w strukturze utmp muszą być takie same w trybie 32-bitowym, co w 64-bitowym, Osiąga się to przez zmianę typu ut_session na int32_t, ut_tv na strukturę z dwoma polami typu int32_t: tv_sec i tv_usec (Dlatego, aby ją wypełnić, należy najpierw pobrać czas do rzeczywistej struktury timeval, a następnie skopiować oba pola do ut_tv.)

BŁĘDY
Ta strona podręcznika została oparta na stronie z wersji libc5, rzeczy mogą obecnie działać inaczej.

ZOBACZ TAKŻE
ac(1), date(1), last(1), login(1), who(1), getutent(3), updwtmp(3), init(8)