Artisan Numérique

/système/stockage/sécurité/pam/ PAM, monter une partition au login

Si pour la protection de vos données vous avez opté pour l'option d'un dossier sécurisé par encfs ou LUKS, saisir à chaque ouverture de session un mot de passe supplémentaire devient vite pénible. Et comme c'est humain, dés que quelque chose est trop pénible, on a tendance à le contourner. L'objectif est donc ici de n'utiliser qu'un seul et même mot de passe pour se connecter ET ouvrir le dossier protégé dans la foulée.

Montage automatique de dossier chiffré

Si le module LDAP est capable de récupérer le mot de passe saisi via pam_tcb, cela implique que ce mot de passe peut être aussi récupéré par un module qui peut du coup l'utiliser comme clef pour un montage encfs. Faut-il encore qu'un tel module existe...

En réalité il existe trois modules capables de faire cela : pam_encfs, pam_mount et pam_script. pam_encfs n'est plus développé, on va donc éviter. pam_mount semble parfaitement fait pour le job mais reste plus limité dans son champ d'action que pam_script qui va tout simplement nous mettre à disposition trois scripts :

  • /etc/security/onauth qui va être exécuté lorsque l'utilisateur s'authentifie (groupe de gestion "auth"). C'est ici que nous allons récupérer notre mot de passe.
  • /etc/security/onopensession qui va être exécuté lorsque l'utilisateur ouvre une session (groupe de gestion "session").
  • /etc/security/onclosesession qui va être exécuté lorsque l'utilisateur ferme sa session (groupe de gestion "session").

Ce module PAM s'installe très facile par le paquet idoine. Après cela, il va nous falloir modifier /etc/pam.d/system-auth pour prendre en charge notre module :

#%PAM-1.0

auth        required      pam_env.so
auth        [success=2 default=ignore] pam_tcb.so shadow fork nullok prefix=$2a$ count=8
auth        [success=1 default=ignore] pam_ldap.so use_first_pass
auth        requisite pam_deny.so
auth        optional pam_script.so expose=1 runas=root

...

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_tcb.so
session     required      pam_script.so

Pour le groupe de gestion session, c'est relativement simple, on rajoute simplement une règle à la fin avec required comme contrôle. Nous aurions aussi pu mettre optionnal cela n'aurait pas changé grand chose ici. Dans tous les cas deux scripts /etc/security/onsessionopen et /etc/security/onsessionclose seront appelés à l'arrivée et au départ de l'utilisateur.

Le groupe auth est en revanche un peu plus compliqué si vous le comparez à la version originale. A l'origine nos règles 2 et 3 étaient associées à un contrôle sufficient. Le problème de cette approche est que si l'utilisateur réussi son authentification, notre module script ne sera jamais appelé. Nous allons donc utiliser la syntaxe étendue pour régler cela.

Pour ceux qui ont fait un peu d'assembleur dans leur vie, la méthode ne devrait pas trop dépayser. L'idée est d'indiquer que l'action pour success est un saut de 2 modules pour pam_tcb et de 1 module pour pam_ldap. Ainsi nous réglons le problème du sufficient. En cas de succès, le traitement saute sur pam_script, sinon il se poursuit sur pam_deny.

Concernant pam_script dans le groupe auth, le paramètre de module expose=1 permet (attention à ce que vous faite !!) de transmettre le mot de passe dans l'environnement d'exécution script /etc/security/onauth, par la variable $PAM_AUTHTOK. Enfin runas=root lance le module en tant qu'utilisateur privilégié. Normalement rien ne devrait nous obliger à faire cela. Malheureusement pour des raisons qui me sont encore assez obscures, si c'est l'utilisateur se connectant qui lance ce script, le montage se fait une fois sur deux. Plus exactement une fois sur deux encfs déclare que l'utilisateur n'a pas les droits sur /dev/fuse...

Que les scripts soient lancé par root ou pas, ils auront toujours les deux mêmes paramètres. Tout d'abord l'UID de l'utilisateur qui s'authentifie/ouvre sa session, suivi du nom du groupe de gestion (auth ou session). Maintenant ne nous reste maintenant plus qu'à écrire ces scripts. Ils sont auto documentés et j'espère pas trop difficile à comprendre :

#! /bin/sh

# pam_script passe l'UID de l'utlisateur en paramètre
user=$(awk -F : "/:$1:/ {print \$1}" /etc/passwd)

# récupération du mot de passe
password=$PAM_AUTHTOK

# si l'utilisateur est le bon...
if [ $user == "gaston" ] ; then
        # définition du montage
        mount_point="/home/gaston/vault";
        crypt_point="/home/gaston/.vault";

        # vérification de l'existence du montage (pas la peine de faire cela deux fois)
        mount=$(mount | grep "$mount_point");
        if [ -z "$mount" ] ; then
                # montage encfs. -S indique un mot de passe via stdin
                echo "$password" | encfs -S $crypt_point $mount_point --public -o user=$user
        fi
fi

Dans la suite de l'obligation de mettre pam_script en runas=root, il faut du coup rajouter les options --public -o user=$user pour que l'utilisateur gaston puisse voir son dossier protégé.

Ensuite pour la déconnexion

#! /bin/sh

# pam_script passe l'UID de l'utlisateur en paramètre
user=$(awk -F : "/:$1:/ {print \$1}" /etc/passwd)


# si l'utilisateur est le bon...
if [ $user == "gaston" ] ; then
        mount_point="/home/gaston/vault";
        crypt_point="/home/gaston/.vault";
        mount=$(mount | grep "$mount_point");

        # si le montage existe
        if [ ! -z "$mount" ] ; then
                fusermount -u $mount_point
        fi
fi

conclusion

Voilà, à partir de maintenant, toute connection de l'utilisation gaston implique le montage de son dossier protégé (sous réserve que les deux mots de passe soient les mêmes, évidemment). Et lorsque gaston clôture sa session, le dossier est automatiquement démonté. Cette protection ne sert évidemment à rien si gaston oublie de verrouiller sa session lorsqu'il part au petit coin. De même il est plus qu'utile d'ajouter le verrouillage de la console lors du lancement de l'économiseur d'écran.