Thomas “Cakeisalie5” Touhey


Logs de connexion sur UNIX-like

Sur systèmes type UNIX (respectant la norme POSIX), il y a plusieurs fichiers historiques qui contiennent des données importantes pour le système. Le plus connu est sans doute /etc/passwd, qui donne la liste des utilisateurs locaux et des donées les caractérisant, comme leur numéro d’utilisateur (uid), le nom complet, le shell par défaut, le dossier personnel, aussi nommé “home” ou “home directory”. Il existe d’autres types d’identification sur UNIX-like à présent, mais celui-ci reste celui par défaut.

Parmi d’autres fichiers un peu moins connus, on trouve /etc/group, qui donne la liste des groupes ainsi que les utilisateurs en faisant partie, ou /etc/shadow, qui donne le hash des mots de passe pour les utilisateurs dans /etc/passwd, mais qui n’est accessible qu’à root, qui est ainsi le seul à pouvoir déterminer si un mot de passe est le bon pour un utilisateur (alors que tout le monde peut lire /etc/passwd pour découvrir les utilisateurs locaux existants).

Mais si vous avez déjà lancé who ou, plus improbable, finger, vous verrez quelques champs qui ne s’obtiennent pas avec ces fichiers-là : le login time (quand l’utilisateur s’est-il connecté pour la dernière fois ?),, le TTY sur lequel l’utilisateur est connecté, et l’idle time (de combien de temps date la dernière action de l’utilisateur ?). Pour trouver ces informations-là, il faut aller farfouiller du côté de quelques fichiers : l’utmp, le wtmp, et le btmp.

Ces fichiers sont ceux où sont archivés les détails de tous les évènements de connexion et de déconnexion. Ceux-ci y sont inscrits non pas par un programme centralisé (un daemon de poil quelconque), mais par tout programme procédant à une connexion – cela induit d’ailleurs qu’il est impossible de savoir tous les utilisateurs connectés, puisqu’un programme authentifiant peut ne pas alimenter le fichier. En général, les utilisateurs touchant à ces fichiers sont dans un groupe particulier, utmp par exemple.

Les trois fichiers ont le même format, mais trois différents rôles :

  • l’utmp présente le statut actuel de la machine et de l’ensemble des utilisateurs connectés ;
  • le wtmp est un historique des connexions ;
  • le btmp est un historique des connexions non réussies.

À noter qu’il existe deux versions de ces fichiers :

  • la version non standardisée, obsolète sauf dans quelques cas ;
  • la version standardisée dans POSIX et la [Single Unix Specification][utmp], qui définit utmpx, wtmpx et btmpx au lieu des trois par défaut.

La version Linux est un peu spéciale, puisqu’elle est conforme au standard tout en reprenant les éléments de System V et de BSD, rendant indistinguable les deux versions sur cette plateforme.

Le chemin de ces fichiers varie entre les plateformes (non standardisés), mais la page Wikipédia recense ceux-ci pour quelques plateformes répandues. Nous nous intéresserons au cas Linux, où les chemins sont /var/run/utmp, /var/log/wtmp et /var/log/btmp.

Au passage, plusieurs choses sont intéressantes à noter avec ces chemins : puisque la structure est la même entre les deux versions des fichiers sous distributions Linux, il n’y a pas de version ‘x’ de ces fichiers. De plus, les dossiers ont du sens : /var/log est persistent, et /var/run est un dossier temporaire (tmpfs est monté dessus comme sur /run).

Le format de ce fichier, au cas où vous ne vous en doutiez pas déjà, est binaire et non textuel (pour rappel, les trois fichiers ont le même). Il est décrit dans la définition du header utmp.h prévu pour les programmes en langage C. À noter que les programmes doivent parcourir le fichier eux-mêmes, puisqu’il n’y a pas de fonction standardisée (pas de libutmp non plus, mais ça ne m’étonne qu’à moitié, puisque ces fichiers ne sont pas tant utilisés que ça).

En Python pour Linux (puisque c’est le contexte dans lequel je voulais l’utiliser), le module utmp est plutôt bien fait, mais “hardcode” la structure, donc n’est utilisable que pour Linux. Une idée serait donc de faire un module équivalent en natif pour CPython (l’implémentation de référence de Python), qui utiliserait donc le header <utmp.h> standard (bien que le chemin vers les fichiers devra donc être caché derrière des OS-specific macros, type __linux__ ou autre).

Un dernier point avant de terminer cet article : l’idle time n’est pas contenu dans une entrée. Pour l’obtenir, si l’utilisateur n’utilise pas Xorg ou quelque chose d’équivalent (donc généralement un shell directement), il suffit de récupérer le tty sur lequel l’utilisateur est connecté depuis l’entrée correspondante dans l’utmp, puis faire un stat dessus (en n’oubliant pas de préfixer la chaîne obtenu de l’entrée d’utmp par /dev/, non inclus dans l’entrée pour garder de la place). La date de dernier accès, accessible sous la forme d’un timestamp sur st_atime, correspond à la dernière fois où l’utilisateur a entré quelque chose sur le terminal.

Je n’entrerai pas davantage dans les détails, mais si vous souhaitez vous servir de ces fichiers plutôt utiles, la page de manuel est bien faite ! Si vous avez une question, une idée d’amélioration ou une remarque quelconque, mes moyens de contact sont dans ma page de description, comme d’habitude :)