                    Pluggable Authentication Modules

  Dag-Erling Smo/rgrav

   Copyright (c) 2001, 2002, 2003 Networks Associates Technology,
   Inc.

   $FreeBSD: release/9.1.0/fr_FR.ISO8859-1/articles/pam/article.sgml
   38826 2012-05-17 19:12:14Z hrs $

   Cet article a ete ecrit pour le Projet FreeBSD par ThinkSec AS et
   les laboratoires de Networks Associates, la division de recherche
   en securite de Networks Associates, Inc. sous le contrat
   DARPA/SPAWAR N66001-01-C-8035 ("CBOSS"), en tant que partie du
   programme de recherche DARPA CHATS.

   Cet article decrit les principes sous-jacent et les mecanismes de
   la bibliotheque PAM, il explique comment configurer PAM,
   l'integrer dans les applications, et ecrire ses propres modules
   PAM.

   Version franc,aise de Clement Mathieu <cykl@mAdchAt.org>.

     --------------------------------------------------------------

1. Introduction

   La bibliotheque PAM est une API generalisee pour les services
   relevant de l'authentification permettant `a un administrateur
   systeme d'ajouter une nouvelle methode d'authentification en
   ajoutant simplement un nouveau module PAM, ainsi que de modifier
   les regles d'authentification en editant les fichiers de
   configuration.

   PAM a ete conc,u et developpe en 1995 par Vipin Samar et Charlie
   Lai de Sun Microsystems, et n'a pas beaucoup evolue depuis. En
   1997 l'Open Group publie les premieres specifications XSSO qui
   standardisent l'API PAM et ajoute des extensions pour un simple
   (ou plutot integre) "sign-on". Lors de l'ecriture de cet article,
   la specification n'a toujours pas ete adoptee comme standard.

   Bien que cet article se concentre principalement sur FreeBSD 5.x,
   qui utilise OpenPAM, il devrait egalement etre applicable `a
   FreeBSD 4.x qui utilise Linux-PAM, ainsi qu'`a d'autres systemes
   d'exploitations tels que Linux ou Solaris.

     --------------------------------------------------------------

  1.1. Marques deposees

   Sun, Sun Microsystems, SunOS and Solaris are trademarks or
   registered trademarks of Sun Microsystems, Inc.

   UNIX and The Open Group are trademarks or registered trademarks of
   The Open Group.

   All other brand or product names mentioned in this document may be
   trademarks or registered trademarks of their respective owners.

     --------------------------------------------------------------

2. Termes et conventions

  2.1. Definitions

   La terminologie de PAM est plutot confuse. Ni la publication
   originale de Samar et Lai, ni la specification XSSO n'ont essaye
   de definir formellement des termes pour les acteurs et les entites
   intervenant dans PAM, les termes qu'ils utilisent (mais ne
   definissent pas) sont parfois trompeurs et ambigus. Le premier
   essai d'etablir une terminologie consistante et non ambigue fut un
   papier ecrit par Andrew G. Morgan (l'auteur de Linux-PAM) en 1999.
   Bien que les choix de Morgan furent un enorme pas en avant, ils ne
   sont pas parfait d'apres l'auteur de ce document. Ce qui suit,
   largement inspire par Morgan, est un essai de definir precisement
   et sans ambiguite des termes pour chaque acteur ou entite utilise
   dans PAM.

   compte

           L'ensemble de permissions que le demandeur demande a
           l'arbitre.

   demandeur

           L'utilisateur ou l'entite demandant authentification.

   arbitre

           L'utilisateur ou l'entite possedant les privileges
           necessaires pour verifier la requete du demandeur ainsi
           que l'autorite d'accorder ou de rejeter la requete.

   chaine

           Une sequence de modules qui sera invoquee pour repondre `a
           une requete PAM. La chaine comprend les informations
           concernant l'ordre dans lequel invoquer les modules, les
           arguments `a leur passer et la fac,on d'interpreter les
           resultats.

   client

           L'application responsable de la requete d'authentification
           au nom du demandeur et de recueillir l'information
           d'authentification necessaire.

   mecanisme

           Il s'agit de l'un des quatre groupes basiques de
           fonctionnalites fournit par PAM : authentification,
           gestion de compte, gestion de session et mise `a jour du
           jeton d'authentification.

   module

           Une collection d'une ou plusieurs fonctions implementant
           un service d'authentification particulier, rassemblees
           dans un fichier binaire (normalement chargeable
           dynamiquement) et identifie par un nom unique.

   regles

           Le jeu complet de configuration des regles decrivant
           comment traiter les requetes PAM pour un service
           particulier. Une regle consiste normalement en quatre
           chaines, une pour chaque mecanisme, bien que quelques
           services n'utilisent pas les quatre mecanismes.

   serveur

           L'application agissant au nom de l'arbitre pour converser
           avec le client, recuperer les informations
           d'authentification, verifier les droits du demandeur et
           autoriser ou rejeter la requete.

   service

           Un ensemble de serveurs fournissant des fonctionnalites
           similaires ou liees et necessitant une authentification
           similaire. Les regles de PAM sont definies sur un le
           principe de par-service; ainsi tous les serveurs qui
           demandent le meme nom de service seront soumis aux memes
           regles.

   session

           Le contexte dans lequel le service est delivre au
           demandeur par le serveur. L'un des quatre mecanismes de
           PAM, la gestion de session, s'en occupe exclusivement par
           la mise en place et le relachement de ce contexte.

   jeton

           Un morceau d'information associe avec un compte tel qu'un
           mot de passe ou une passphrase que le demandeur doit
           fournir pour prouver son identite.

   transaction

           Une sequence de requetes depuis le meme demandeur vers la
           meme instance du meme serveur, commenc,ant avec
           l'authentification et la mise en place de la session et se
           terminant avec le demontage de la session.

     --------------------------------------------------------------

  2.2. Exemples d'utilisation

   Cette section a pour but d'illustrer quelques-uns des termes
   definis precedemment `a l'aide d'exemples basiques.

     --------------------------------------------------------------

    2.2.1. Client et serveurs ne font qu'un

   Cet exemple simple montre alice utilisant su(1) pour devenir root.

 % whoami
 alice
 % ls -l `which su`
 -r-sr-xr-x  1 root  wheel  10744 Dec  6 19:06 /usr/bin/su
 % su -
 Password: xi3kiune
 # whoami
 root

     * Le demandeur est alice.

     * Le compte est root.

     * Le processus su(1) est `a la fois client et serveur.

     * Le jeton d'authentification est xi3kiune.

     * L'arbitre est root, ce qui explique pourquoi su(1) est setuid
       root.

     --------------------------------------------------------------

    2.2.2. Client et serveur sont distincts.

   L'exemple suivant montre eve essayant d'initier une connexion
   ssh(1) vers login.exemple.com, en demandant `a se logguer en tant
   que bob. La connexion reussit. Bob aurait du choisir un meilleur
   mot de passe !

 % whoami
 eve
 % ssh bob@login.example.com
 bob@login.example.com's password: god
 Last login: Thu Oct 11 09:52:57 2001 from 192.168.0.1
 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
         The Regents of the University of California.  All rights reserved.
 FreeBSD 4.4-STABLE (LOGIN) #4: Tue Nov 27 18:10:34 PST 2001

 Welcome to FreeBSD!
 %

     * Le demandeur est eve.

     * Le client d'eve est represente par les processus ssh(1)

     * Le serveur est le processus sshd(8) sur login.example.com

     * Le compte est bob.

     * Le jeton d'identification est god.

     * Bien que cela ne soit pas montre dans cet exemple, l'arbitre
       est root.

     --------------------------------------------------------------

    2.2.3. Exemple de regles

   Les lignes qui suivent sont les regles par defaut de sshd:

 sshd    auth            required        pam_nologin.so  no_warn
 sshd    auth            required        pam_unix.so     no_warn try_first_pass
 sshd    account         required        pam_login_access.so
 sshd    account         required        pam_unix.so
 sshd    session         required        pam_lastlog.so  no_fail
 sshd    password        required        pam_permit.so

     * Cette politique s'applique au service sshd (qui n'est pas
       necessairement restreint au serveur sshd(8))

     * auth, account, session et password sont des mecanismes.

     * pam_nologin.so, pam_unix.so, pam_login_access.so,
       pam_lastlog.so et pam_permit.so sont des modules. Il est clair
       dans cet exemple que pam_unix.so fournit au moins deux
       mecanismes ( authentification et gestion de compte).

     --------------------------------------------------------------

  2.3. Conventions

   Cette section n'a pas encore ete ecrite.

     --------------------------------------------------------------

3. Les bases de PAM

  3.1. Mecanismes et primitives

   L'API PAM fournit six primitives d'authentification differentes
   regroupees dans quatre mecanismes qui seront decrits dans la
   partie suivante.

   auth

           Authentification. Ce mecanisme concerne l'authentification
           du demandeur et etablit les droits du compte. Il fournit
           deux primitives :

              * pam_authenticate(3) authentifie le demandeur,
                generalement en demandant un jeton d'identification
                et en le comparant a une valeur stockee dans une base
                de donnees ou obtenue par le biais d'un serveur
                d'authentification.

              * pam_setcred(3) etabli les parametres du compte tel
                que l'uid, les groupes dont le compte fait parti ou
                les limites sur l'utilisation des ressources.

   account

           Gestion de compte. Ce mecanisme concerne la disponibilite
           du compte pour des raisons autres que l'authentification.
           Par exemple les restrictions basees sur l'heure courante
           ou la charge du serveur. Il fournit une seule primitive:

              * pam_acct_mgmt(3) verifie que le compte demande est
                disponible.

   session

           Gestion de session. Ce mecanisme concerne la mise en place
           de la session et sa terminaison, par exemple
           l'enregistrement de la session dans les journaux. Il
           fournit deux primitives:

              * pam_open_session(3) accomplie les taches associees `a
                la mise en place d'une session : ajouter une entree
                dans les bases utmp et wtmp, demarrer un agent SSH...

              * pam_close_session(3) accomplie les taches associees
                `a la terminaison d'une session : ajouter une entree
                dans les bases utmp et wtmp, arreter l'agent SSH...

   password

           Gestion des mots de passe. Ce mecanisme est utilise pour
           modifier le jeton d'authentification associe `a un compte,
           soit parce qu'il a expire, soit parce que l'utilisateur
           desire le changer. Il fournit une seule primitive:

              * pam_chauthtok(3) modifie le jeton d'authentification,
                et eventuellement verifie que celui-ci est assez
                robuste pour ne pas etre devine facilement ou qu'il
                n'a pas dej`a utilise.

     --------------------------------------------------------------

  3.2. Modules

   Les modules sont le concept clef de PAM; apres tout ils
   constituent le "M" de PAM. Un module PAM est lui-meme un morceau
   de code qui implemente les primitives d'un ou plusieurs mecanismes
   pour une forme particuliere d'authentification; par exemple, les
   bases de mots de passe UNIX que sont NIS, LDAP et Radius.

     --------------------------------------------------------------

    3.2.1. Nom des modules

   FreeBSD implemente chaque mecanismes dans un module distinct nomme
   pam_mecanisme.so (par exemple pam_unix.so pour le mecanisme Unix
   .) Les autres implementations possedent parfois des modules
   separes pour des mecanismes separes et incluent aussi bien le nom
   du service que celui du mecanisme dans le nom du module. Un
   exemple est le module pam_dial_auth.so.1 de Solaris qui est
   utilise pour authentifier les utilisateurs dialup.

     --------------------------------------------------------------

    3.2.2. Gestion des versions de module

   L'implementation originale de PAM par FreeBSD, basee sur
   Linux-PAM, n'utilisait pas de numero de version pour les modules
   PAM. Ceci peut poser des problemes avec les applications tiers qui
   peuvent etre liees avec d'anciennes bibliotheques systemes,
   puisqu'il n'y a pas possibilite de charger la version
   correspondante du module desire.

   Pour sa part, OpenPAM cherche les modules qui ont la meme version
   que la bibliotheque PAM (pour le moment 2) et se rabat sur un
   module sans version si aucun module avec version n'a put etre
   charge. Ainsi les anciens modules peuvent etre fournis pour les
   anciennes applications, tout en permettant aux nouvelles
   applications (ou bien nouvellement compilees) de tirer parti des
   modules les plus recents.

   Bien que les modules PAM de Solaris possedent generalement un
   numero de version, ils ne sont pas reellement versionnes car le
   numero correspond `a une partie du nom du module et doit etre
   inclus dans la configuration.

     --------------------------------------------------------------

  3.3. Chaines et politiques

   Lorsqu'un serveur initie une transaction PAM, la bibliotheque PAM
   essaie de charger une politique pour le service specifie dans
   l'appel a pam_start(3) . La politique indique comment la requete
   d'authentification doit etre traitee et est definie dans un
   fichier de configuration. Il s'agit de l'autre concept clef de PAM
   : la possibilite pour l'administrateur de configurer la politique
   de securite d'un systeme en editant simplement une fichier texte.

   Une politique consiste en quatre chaines, une pour chacune des
   quatre mecanismes de PAM. Chaque chaine est une suite de regles de
   configuration, chacune specifiant un module `a invoquer, des
   parametres, options, `a passer au module et un drapeau de controle
   qui decrit comment interpreter le code de retour du module.

   Comprendre le drapeau de controle est essentiel pour comprendre
   les fichiers de configuration de PAM. Il existe quatre drapeaux de
   controle differents :

   binding

           Si le module reussit et qu'aucun module precedent de la
           chaine n'a echoue, la chaine s'interrompt immediatement et
           la requete est autorisee. Si le module echoue le reste de
           la chaine est execute, mais la requete est rejetee au
           final.

           Ce drapeau de controle a ete introduit par Sun Solaris
           dans la version 9 (SunOS 5.9); il est aussi supporte par
           OpenPAM.

   required

           Si le module reussit, le reste de la chaine est execute,
           et la requete est autorisee si aucun des autres modules
           n'echoue. Si le module echoue, le reste de la chaine est
           execute, mais au final la requete est rejetee.

   requisite

           Si le module reussit le reste de la chaine est execute, et
           la requete est autorisee sauf si d'autres modules echoues.
           Si le module echoue la chaine est immediatement terminee
           et la requete est rejetee.

   sufficient

           Si le module reussit et qu'aucun des modules precedent n'a
           echoue la chaine est immediatement terminee et la requete
           est allouee. Si le module echoue il est ignore et le reste
           de la chaine est execute.

           Puisque la semantique de ce drapeau peut etre un peu
           confuse, specialement lorsqu'il s'agit de celui du dernier
           module de la chaine, il est recommande d'utiliser le
           drapeau binding `a la place de celui-ci sous la condition
           que l'implementation le supporte.

   optional

           Le module est execute mais le resultat est ignore. Si tout
           les modules de la chaine sont marques optional, toutes les
           requetes seront toujours acceptees.

   Lorsqu'un serveur invoque l'une des six primitives PAM, PAM
   recupere la chaine du mecanisme `a laquelle la requete correspond
   et invoque chaque module de la chaine dans l'ordre indique,
   jusqu'`a ce que la fin soit atteinte ou qu'aucune execution
   supplementaire ne soit necessaire (soit `a cause du succes d'un
   module en binding ou sufficient, soit `a cause de l'echec d'un
   module requisite). La requete est acceptee si et seulement si au
   moins un module a ete invoque, et que tout les modules non
   optionnels ont reussi.

   Notez qu'il est possible, bien que peu courant, d'avoir le meme
   module liste plusieurs fois dans la meme chaine. Par exemple un
   module qui determine le nom utilisateur et le mot de passe `a
   l'aide d'un serveur directory peut etre invoque plusieurs fois
   avec des parametres specifiant differents serveurs a contacter.
   PAM considere les differentes occurrences d'un meme module dans
   une meme chaine comme des modules differents et non lies.

     --------------------------------------------------------------

  3.4. Transactions

   Le cycle de vie d'une transaction PAM typique est decrit
   ci-dessous. Notez que si l'une de ces etapes echoue, le serveur
   devrait reporter un message d'erreur au client et arreter la
   transaction.

    1. Si necessaire, le serveur obtient les privileges de l'arbitre
       par le biais d'un mecanisme independant de PAM -- generalement
       en ayant ete demarre par root ou en etant setuid root.

    2. Le serveur appel pam_start(3) afin d'initialiser la
       bibliotheque PAM et indique le service et le compte cible, et
       enregistre une fonction de conversation appropriee.

    3. Le serveur obtient diverses informations concernant la
       transaction (tel que le nom d'utilisateur du demandeur et le
       nom d'hote de la machine sur lequel le client tourne) et les
       soumet `a PAM en utilisant la fonction pam_set_item(3).

    4. Le serveur appel pam_authenticate(3) pour authentifier le
       demandeur.

    5. Le serveur appel la fonction pam_acct_mgmt(3) qui verifie que
       le compte est valide et disponible. Si le mot de passe est
       correct mais a expire, pam_acct_mgmt(3) retournera
       PAM_NEW_AUTHTOK_REQD `a la place de PAM_SUCCESS.

    6. Si l'etape precedente a retourne PAM_NEW_AUTHTOK_REQD, le
       serveur appel maintenant pam_chauthtok(3) pour obliger
       l'utilisateur `a changer le jeton d'authentification du compte
       desire.

    7. Maintenant que le demandeur a ete correctement authentifie, le
       serveur appelle pam_setcred(3) pour obtenir les privileges du
       compte desire. Il lui est possible de faire ceci parce qu'il
       agit au nom de l'arbitre dont il possede les privileges.

    8. Lorsque les privileges corrects ont ete etabli le serveur
       appelle pam_open_session(3) pour mettre en place la session.

    9. Maintenant le serveur effectue les services demandes par le
       client -- par exemple fournir un shell au demandeur.

   10. Lorsque le serveur a fini de servir le client, il appelle
       pam_close_session(3) afin de terminer la session.

   11. Pour finir, le serveur appelle pam_end(3) afin signaler `a la
       bibliotheque PAM que la transaction se termine et qu'elle peut
       liberer les ressources qu'elle a alloue au cours de la
       transaction.

     --------------------------------------------------------------

4. Configuration de PAM

  4.1. Emplacement des fichiers de configuration

   Le fichier de configuration de PAM est traditionnellement
   /etc/pam.conf. Ce fichier contient toutes les politiques de PAM
   pour votre systeme. Chaque ligne du fichier decrit une etape dans
   une chaine, tel que nous allons le voir ci-dessous:

 login   auth    required        pam_nologin.so  no_warn

   Les champs sont respectivement, le service, le nom du mecanisme,
   le drapeau de controle, le nom du module et les arguments du
   module. Tout champ additionnel est considere comme argument du
   module.

   Une chaine differente est construite pour chaque couple
   service/mecanisme; ainsi, alors que l'ordre des lignes est
   important lorsqu'il s'agit des memes services ou mecanismes,
   l'ordre dans lequel les differents services et mecanismes
   apparaissent ne l'est pas -- excepte l'entree pour le service
   other, qui sert de reference par defaut et doit etre place `a la
   fin. L'exemple du papier original sur PAM regroupait les lignes de
   configurations par mecanisme et le fichier pam.conf de Solaris le
   fait toujours, mais FreeBSD groupe les lignes de configuration par
   service. Toutefois il ne s'agit pas de la seule possibilite et les
   autres possedent aussi un sens.

   OpenPAM et Linux-PAM offrent un mecanisme de configuration
   alternatif ou les politiques sont placees dans des fichiers
   separes portant le nom du service auquel ils s'appliquent. Ces
   fichiers sont situes dans /etc/pam.d/ et ne contiennent que quatre
   champs `a la place de cinq -- le champ contenant le nom du service
   est omis. Il s'agit du mode par defaut dans FreeBSD 4.x. Notez que
   si le fichier /etc/pam.conf existe et contient des informations de
   configuration pour des services qui n'ont pas de politique
   specifiee dans /etc/pam.d, ils seront utilises pour ces services.

   Le gros avantage de /etc/pam.d/ sur /etc/pam.conf est qu'il est
   possible d'utiliser la meme politique pour plusieurs services en
   liant chaque nom de service `a un fichier de configuration. Par
   exemple pour utiliser la meme politique pour les services su et
   sudo, nous pouvons faire comme ceci :

 # cd /etc/pam.d
 # ln -s su sudo

   Ceci fonctionne car le nom de service est determine a partir du
   nom de fichier plutot qu'indique `a l'interieur du fichier de
   configuration, ainsi le meme fichier peut etre utilise pour des
   services nommes differemment.

   Un autre avantage est qu'un logiciel tiers peu facilement
   installer les politiques pour ses services sans avoir besoin
   d'editer /etc/pam.conf. Pour continuer la tradition de FreeBSD,
   OpenPAM regardera dans /usr/local/etc/pam.d pour trouver les
   fichiers de configurations; puis si aucun n'est trouve pour le
   service demande, il cherchera dans /etc/pam.d/ ou /etc/pam.conf.

   Finalement, quelque soit le mecanisme que vous choisissiez, la
   politique "magique" other est utilisee par defaut pour tous les
   services qui n'ont pas leur propre politique.

     --------------------------------------------------------------

  4.2. Breakdown of a configuration line

   Comme explique dans la section Emplacement des fichiers de
   configuration, chaque ligne de pam.conf consiste en quatre champs
   ou plus: le nom de service, le nom du mecanisme, le drapeau de
   controle, le nom du module et la presence ou non d'arguments pour
   le module.

   Le nom du service est generalement, mais pas toujours, le nom de
   l'application auquelle les regles s'appliquent. Si vous n'etes pas
   sur, referez vous `a la documentation de l'application pour
   determiner quel nom de service elle utilise.

   Notez que si vous utilisez /etc/pam.d/ `a la place de
   /etc/pam.conf, le nom du service est specifie par le nom du
   fichier de configuration et n'est pas indique dans les lignes de
   configuration qui, des lors, commencent par le nom du mecanisme.

   Le mecanisme est l'un des quatre mots clef decrit dans la section
   Mecanismes et primitives

   De meme, le drapeau de controle est l'un des quatre mots clef
   decrits dans la section Chaines et politiques et decrit comment le
   module doit interpreter le code de retour du module. Linux-PAM
   supporte une syntaxe alternative qui vous laisse specifier
   l'action `a associer `a chaque code de retour possible; mais ceci
   devrait etre evite puisque ce n'est pas standard et etroitement
   lie `a la fac,on dont Linux-PAM appelle les services (qui differe
   grandement de la fac,on de Solaris et OpenPAM). C'est sans
   etonnement que l'on apprend qu'OpenPAM ne supporte pas cette
   syntaxe.

     --------------------------------------------------------------

  4.3. Politiques

   Pour configurer PAM correctement, il est essentiel de comprendre
   comment les politiques sont interpretees.

   Lorsqu'une application appelle pam_start(3) la bibliotheque PAM
   charge la politique du service specifie et construit les quatre
   chaines de module (une pour chaque mecanisme). Si une ou plusieurs
   chaines sont vides, les chaines de la politique du service other
   sont utilisees.

   Plus tard, lorsque l'application appelle l'une des six primitives
   PAM, la bibliotheque PAM recupere la chaine du mecanisme
   correspondant et appelle la fonction appropriee avec chaque module
   liste dans la chaine. Apres chaque appel d'une fonction de
   service, le type du module et le code d'erreur sont retournes par
   celle-ci pour determiner quoi faire. A quelques exceptions pres,
   dont nous parlerons plus tard, la table suivante s'applique:

   Table 1. Resume de la chaine d'execution PAM

   +----------------------------------------------------------------+
   |            |    PAM_SUCCESS    | PAM_IGNORE |      other       |
   |------------+-------------------+------------+------------------|
   | binding    | if (!fail) break; | -          | fail = true;     |
   |------------+-------------------+------------+------------------|
   | required   | -                 | -          | fail = true;     |
   |------------+-------------------+------------+------------------|
   | requisite  | -                 | -          | fail = true;     |
   |            |                   |            | break;           |
   |------------+-------------------+------------+------------------|
   | sufficient | if (!fail) break; | -          | -                |
   |------------+-------------------+------------+------------------|
   | optional   | -                 | -          | -                |
   +----------------------------------------------------------------+

   Si fail est vrai `a la fin de la chaine, ou lorsqu'un "break" est
   atteint, le dispatcheur retourne le code d'erreur renvoye par le
   premier module qui a echoue. Autrement PAM_SUCCESS est retourne.

   La premiere exception est que le code d'erreur PAM_NEW_AUTHOK_REQD
   soit considere comme un succes, sauf si aucun module n'echoue et
   qu'au moins un module retourne PAM_NEW_AUTHOK_REQD le dispatcheur
   retournera PAM_NEW_AUTHOK_REQD.

   La seconde exception est que pam_setcred(3) considere les modules
   binding et sufficient comme s'ils etaient required.

   La troisieme et derniere exception est que pam_chauthtok(3)
   execute la totalite de la chaine deux fois (la premiere pour des
   verifications preliminaires et la deuxieme pour mettre le mot de
   passe) et lors de la premiere execution il considere les modules
   binding et sufficient comme s'ils etaient required.

     --------------------------------------------------------------

5. Les modules PAM de FreeBSD

  5.1. pam_deny(8)

   Le module pam_deny(8) est l'un des modules disponibles les plus
   simples; il repond `a n'importe qu'elle requete par PAM_AUTH_ERR.
   Il est utile pour desactiver rapidement un service (ajoutez-le au
   debut de chaque chaine), ou pour terminer les chaines de modules
   sufficient.

     --------------------------------------------------------------

  5.2. pam_echo(8)

   Le module pam_echo(8) passe simplement ses arguments `a la
   fonction de conversation comme un message PAM_TEXT_INFO. Il est
   principalement utilise pour le debogage mais il peut aussi servir
   `a afficher un message tel que "Les acces illegaux seront
   poursuivits" avant de commencer la procedure d'authentification.

     --------------------------------------------------------------

  5.3. pam_exec(8)

   Le module pam_exec(8) prend comme premier argument le nom du
   programme `a executer, les arguments restant etant utilises comme
   arguments pour ce programme. L'une des applications possibles est
   d'utiliser un programme qui monte le repertoire de l'utilisateur
   lors du login.

     --------------------------------------------------------------

  5.4. pam_ftp(8)

   Le module pam_ftp(8)

     --------------------------------------------------------------

  5.5. pam_ftpusers(8)

   Le module pam_ftpusers(8)

     --------------------------------------------------------------

  5.6. pam_group(8)

   Le module pam_group(8) accepte ou rejette le demandeur `a partir
   de son appartenance `a un groupe particulier (generalement wheel
   pour su(1)). Il a pour but premier de conserver le comportement
   traditionnel de su(1) mais possede d'autres applications comme par
   exemple exclure un certain groupe d'utilisateurs d'un service
   particulier.

     --------------------------------------------------------------

  5.7. pam_krb5(8)

   Le module pam_krb5(8)

     --------------------------------------------------------------

  5.8. pam_ksu(8)

   Le module pam_ksu(8)

     --------------------------------------------------------------

  5.9. pam_lastlog(8)

   Le module pam_lastlog(8)

     --------------------------------------------------------------

  5.10. pam_login_access(8)

   Le module pam_login_access(8)

     --------------------------------------------------------------

  5.11. pam_nologin(8)

   Le module pam_nologin(8)

     --------------------------------------------------------------

  5.12. pam_opie(8)

   Le module pam_opie(8) implemente la methode d'authentification
   opie(4). Le systeme opie(4) est un mecanisme de challenge-response
   ou la reponse `a chaque challenge est une fonction directe du
   challenge et une phrase de passe, ainsi la reponse peut facilement
   etre calculee "en temps voulu" par n'importe qui possedant la
   phrase de passe ce qui elimine le besoin d'une liste de mots de
   passe. De plus, puisque opie(4) ne reutilise jamais un mot de
   passe qui a rec,u une reponse correcte, il n'est pas vulnerable
   aux attaques basee sur le rejouage.

     --------------------------------------------------------------

  5.13. pam_opieaccess(8)

   Le module pam_opieaccess(8) est un compagnon du module
   pam_opie(8). Son but est de renforcer les restrictions codifiees
   dans opieaccess(5), il regule les conditions sous lesquelles un
   utilisateur qui normalement devrait s'authentifier par opie(4) est
   amene `a utiliser d'autres methodes. Ceci est generalement utilise
   pour interdire l'authentification par mot de passe depuis des
   hotes non digne de confiance.

   Pour etre reellement effectif, le module pam_opieaccess(8) doit
   etre liste comme requisite immediatement apres une entree
   sufficient pour pam_opie(8) et avant tout autre module, dans la
   chaine auth.

     --------------------------------------------------------------

  5.14. pam_passwdqc(8)

   Le module pam_passwdqc(8)

     --------------------------------------------------------------

  5.15. pam_permit(8)

   Le module pam_permit(8) est l'un des modules disponibles les plus
   simples; il repond `a n'importe quelle requete par PAM_SUCCESS. Il
   est utile pour les services ou une ou plusieurs chaines auraient
   autrement ete vides.

     --------------------------------------------------------------

  5.16. pam_radius(8)

   Le module pam_radius(8)

     --------------------------------------------------------------

  5.17. pam_rhosts(8)

   Le module pam_rhosts(8)

     --------------------------------------------------------------

  5.18. pam_rootok(8)

   Le module pam_rootok(8) retourne un succes si et seulement si
   l'identifiant d'utilisateur reel du processus appelant est 0. Ceci
   est utile pour les services non bases sur le reseau tel que su(1)
   ou passwd(1) ou l'utilisateur root doit avoir un acces
   automatique.

     --------------------------------------------------------------

  5.19. pam_securetty(8)

   Le module pam_securetty(8)

     --------------------------------------------------------------

  5.20. pam_self(8)

   Le module pam_self(8) retourne un succes si et seulement si le nom
   du demandeur correspond au nom du compte desire. Il est utile pour
   les services non bases sur le reseau tel que su(1) ou l'identite
   du demandeur peut etre verifiee facilement .

     --------------------------------------------------------------

  5.21. pam_ssh(8)

   Le module pam_ssh(8)

     --------------------------------------------------------------

  5.22. pam_tacplus(8)

   Le module pam_tacplus(8)

     --------------------------------------------------------------

  5.23. pam_unix(8)

   Le module pam_unix(8) implemente l'authentification Unix
   traditionnelle par mot de passe, il utilise getpwnam(3) pour
   obtenir le mot de passe du compte vise et le compare avec celui
   fournit par le demandeur. Il fournit aussi des services de gestion
   de compte (desactivation du compte et date d'expiration) ainsi que
   des services pour le changement de mot de passe. Il s'agit
   certainement du module le plus utile car la plupart des
   administrateurs desirent garder le comportement historique pour
   quelques services.

     --------------------------------------------------------------

6. Programmation d'applications PAM

   Cette section n'a pas encore ete ecrite.

     --------------------------------------------------------------

7. Programmation de modules PAM

   Cette section n'a pas ete encore ecrite.

     --------------------------------------------------------------

                     A. Exemples d'application PAM

   Ce qui suit est une implementation minimale de su(1) en utilisant
   PAM. Notez qu'elle utilise la fonction de conversation
   openpam_ttyconv(3) specifique `a OpenPAM qui est prototypee dans
   security/openpam.h. Si vous desirez construire cette application
   sur un systeme utilisant une bibliotheque PAM differente vous
   devrez fournir votre propre fonction de conversation. Une fonction
   de conversation robuste est etonnamment difficile `a implementer;
   celle presentee dans l'appendiceExemple d'une fonction de
   conversation PAM est un bon point de depart, mais ne devrait pas
   etre utilisee dans des applications reelles.

 #include <sys/param.h>
 #include <sys/wait.h>

 #include <err.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>

 #include <security/pam_appl.h>
 #include <security/openpam.h>   /* for openpam_ttyconv() */

 extern char **environ;

 static pam_handle_t *pamh;
 static struct pam_conv pamc;

 static void
 usage(void)
 {

         fprintf(stderr, "Usage: su [login [args]]\n");
         exit(1);
 }

 int
 main(int argc, char *argv[])
 {
         char hostname[MAXHOSTNAMELEN];
         const char *user, *tty;
         char **args, **pam_envlist, **pam_env;
         struct passwd *pwd;
         int o, pam_err, status;
         pid_t pid;

         while ((o = getopt(argc, argv, "h")) != -1)
                 switch (o) {
                 case 'h':
                 default:
                         usage();
                 }

         argc -= optind;
         argv += optind;

         if (argc > 0) {
                 user = *argv;
                 --argc;
                 ++argv;
         } else {
                 user = "root";
         }

         /* initialize PAM */
         pamc.conv = &openpam_ttyconv;
         pam_start("su", user, &pamc, &pamh);

         /* set some items */
         gethostname(hostname, sizeof(hostname));
         if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
                 goto pamerr;
         user = getlogin();
         if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
                 goto pamerr;
         tty = ttyname(STDERR_FILENO);
         if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
                 goto pamerr;

         /* authenticate the applicant */
         if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
                 goto pamerr;
         if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
                 pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
         if (pam_err != PAM_SUCCESS)
                 goto pamerr;

         /* establish the requested credentials */
         if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
                 goto pamerr;

         /* authentication succeeded; open a session */
         if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
                 goto pamerr;

         /* get mapped user name; PAM may have changed it */
         pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
         if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
                 goto pamerr;

         /* export PAM environment */
         if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
                 for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
                         putenv(*pam_env);
                         free(*pam_env);
                 }
                 free(pam_envlist);
         }

         /* build argument list */
         if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
                 warn("calloc()");
                 goto err;
         }
         *args = pwd->pw_shell;
         memcpy(args + 1, argv, argc * sizeof *args);

         /* fork and exec */
         switch ((pid = fork())) {
         case -1:
                 warn("fork()");
                 goto err;
         case 0:
                 /* child: give up privs and start a shell */

                 /* set uid and groups */
                 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
                         warn("initgroups()");
                         _exit(1);
                 }
                 if (setgid(pwd->pw_gid) == -1) {
                         warn("setgid()");
                         _exit(1);
                 }
                 if (setuid(pwd->pw_uid) == -1) {
                         warn("setuid()");
                         _exit(1);
                 }
                 execve(*args, args, environ);
                 warn("execve()");
                 _exit(1);
         default:
                 /* parent: wait for child to exit */
                 waitpid(pid, &status, 0);

                 /* close the session and release PAM resources */
                 pam_err = pam_close_session(pamh, 0);
                 pam_end(pamh, pam_err);

                 exit(WEXITSTATUS(status));
         }

 pamerr:
         fprintf(stderr, "Sorry\n");
 err:
         pam_end(pamh, pam_err);
         exit(1);
 }

     --------------------------------------------------------------

                       B. Exemple d'un module PAM

   Ce qui suit est une implementation minimale de pam_unix(8) offrant
   uniquement les services d'authentification. Elle devrait compiler
   et tourner avec la plupart des implementations PAM, mais tire
   parti des extensions d'OpenPAM si elles sont disponibles : notez
   l'utilisation de pam_get_authtok(3) qui simplifie enormement
   l'affichage de l'invite pour demander le mot de passe `a
   l'utilisateur.

 #include <sys/param.h>

 #include <pwd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>

 #include <security/pam_modules.h>
 #include <security/pam_appl.h>

 #ifndef _OPENPAM
 static char password_prompt[] = "Password:";
 #endif

 #ifndef PAM_EXTERN
 #define PAM_EXTERN
 #endif

 PAM_EXTERN int
 pam_sm_authenticate(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {
 #ifndef _OPENPAM
         struct pam_conv *conv;
         struct pam_message msg;
         const struct pam_message *msgp;
         struct pam_response *resp;
 #endif
         struct passwd *pwd;
         const char *user;
         char *crypt_password, *password;
         int pam_err, retry;

         /* identify user */
         if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
                 return (pam_err);
         if ((pwd = getpwnam(user)) == NULL)
                 return (PAM_USER_UNKNOWN);

         /* get password */
 #ifndef _OPENPAM
         pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
         if (pam_err != PAM_SUCCESS)
                 return (PAM_SYSTEM_ERR);
         msg.msg_style = PAM_PROMPT_ECHO_OFF;
         msg.msg = password_prompt;
         msgp = &msg;
 #endif
         for (retry = 0; retry < 3; ++retry) {
 #ifdef _OPENPAM
                 pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
                     (const char **)&password, NULL);
 #else
                 resp = NULL;
                 pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
                 if (resp != NULL) {
                         if (pam_err == PAM_SUCCESS)
                                 password = resp->resp;
                         else
                                 free(resp->resp);
                         free(resp);
                 }
 #endif
                 if (pam_err == PAM_SUCCESS)
                         break;
         }
         if (pam_err == PAM_CONV_ERR)
                 return (pam_err);
         if (pam_err != PAM_SUCCESS)
                 return (PAM_AUTH_ERR);

         /* compare passwords */
         if ((!pwd->pw_passwd[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
             (crypt_password = crypt(password, pwd->pw_passwd)) == NULL ||
             strcmp(crypt_password, pwd->pw_passwd) != 0)
                 pam_err = PAM_AUTH_ERR;
         else
                 pam_err = PAM_SUCCESS;
 #ifndef _OPENPAM
         free(password);
 #endif
         return (pam_err);
 }

 PAM_EXTERN int
 pam_sm_setcred(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_open_session(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_close_session(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SUCCESS);
 }

 PAM_EXTERN int
 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
         int argc, const char *argv[])
 {

         return (PAM_SERVICE_ERR);
 }

 #ifdef PAM_MODULE_ENTRY
 PAM_MODULE_ENTRY("pam_unix");
 #endif

     --------------------------------------------------------------

             C. Exemple d'une fonction de conversation PAM

   La fonction de conversation presentee ci-dessous est une version
   grandement simplifiee de la fonction openpam_ttyconv(3) d'OpenPAM.
   Elle est pleinement fonctionnelle et devrait donner au lecteur une
   bonne idee de comment doit se comporter une fonction de
   conversation, mais elle est trop simple pour une utilisation
   reelle. Meme si vous n'utilisez pas OpenPAM, N'hesitez pas `a
   telecharger le code source et d'adapter openpam_ttyconv(3) `a vos
   besoins, nous pensons qu'elle est raisonnablement aussi robuste
   qu'une fonction de conversation orientee tty peut l'etre.

 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>

 #include <security/pam_appl.h>

 int
 converse(int n, const struct pam_message **msg,
         struct pam_response **resp, void *data)
 {
         struct pam_response *aresp;
         char buf[PAM_MAX_RESP_SIZE];
         int i;

         data = data;
         if (n <= 0 || n > PAM_MAX_NUM_MSG)
                 return (PAM_CONV_ERR);
         if ((aresp = calloc(n, sizeof *aresp)) == NULL)
                 return (PAM_BUF_ERR);
         for (i = 0; i < n; ++i) {
                 aresp[i].resp_retcode = 0;
                 aresp[i].resp = NULL;
                 switch (msg[i]->msg_style) {
                 case PAM_PROMPT_ECHO_OFF:
                         aresp[i].resp = strdup(getpass(msg[i]->msg));
                         if (aresp[i].resp == NULL)
                                 goto fail;
                         break;
                 case PAM_PROMPT_ECHO_ON:
                         fputs(msg[i]->msg, stderr);
                         if (fgets(buf, sizeof buf, stdin) == NULL)
                                 goto fail;
                         aresp[i].resp = strdup(buf);
                         if (aresp[i].resp == NULL)
                                 goto fail;
                         break;
                 case PAM_ERROR_MSG:
                         fputs(msg[i]->msg, stderr);
                         if (strlen(msg[i]->msg) > 0 &&
                             msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                                 fputc('\n', stderr);
                         break;
                 case PAM_TEXT_INFO:
                         fputs(msg[i]->msg, stdout);
                         if (strlen(msg[i]->msg) > 0 &&
                             msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                                 fputc('\n', stdout);
                         break;
                 default:
                         goto fail;
                 }
         }
         *resp = aresp;
         return (PAM_SUCCESS);
  fail:
         for (i = 0; i < n; ++i) {
                 if (aresp[i].resp != NULL) {
                         memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                         free(aresp[i].resp);
                 }
         }
         memset(aresp, 0, n * sizeof *aresp);
         *resp = NULL;
         return (PAM_CONV_ERR);
 }

     --------------------------------------------------------------

                        Lectures complementaires

     Ceci est une liste de documents concernant PAM et les domaines
     gravitant autours. Elle n'a pas la pretention d'etre complete.

     --------------------------------------------------------------

Publications

   Rendre les services de connexion independants des technologies
   d'authentification , Vipin Samar and Charlie Lai, Sun
   Microsystems.

   X/Open Single Sign-on Preliminary Specification, The Open Group,
   1-85912-144-6, June 1997.

   Pluggable Authentication Modules, Andrew G. Morgan, October 6,
   1999.

     --------------------------------------------------------------

Guides utilisateur

   Administration de PAM , Sun Microsystems.

     --------------------------------------------------------------

Page internet liees

   La page d'OpenPAM, Dag-Erling Smo/rgrav, ThinkSec AS.

   La page de Linux-PAM, Andrew G. Morgan.

   La page de Solaris PAM, Sun Microsystems.

     --------------------------------------------------------------

        Ce document, ainsi que d'autres peut etre telecharge sur
                   ftp.FreeBSD.org/pub/FreeBSD/doc/.

Pour toutes questions `a propos de FreeBSD, lisez la documentation avant
                 de contacter <questions@FreeBSD.org>.
Pour les questions sur cette documentation, contactez <doc@FreeBSD.org>.
