LDAP présentation et implémentation
Jehan Procaccia MCI INT-EVRY- jehan.procaccia@int-evry.fr
12 mars 2003
Table des matières
Résumé : Ceci est un document de travail en cours
d'évolution (le qualificatif ``new'' indique les rubriques dernierement mises
à jour) , cela explique la présence, notament dans les cadres d'exemple de la
partie exploitation, de noms de machines, répertoires ... qui peuvent être
différents d'un exemple à l'autre.
Il s'agit dans un premier temps d'une
présentation des concepts, suivi d'un decription détaillée de la mise en
oeuvre d'un serveur OpenLdap pour la gestion système des services Unix.
Il
existe beaucoup d'autres documentations sur le sujet, celle-ci recenses
l'ensembles des étapes de la mise en oeuvre de l'annuaire LDAP à l'INT-Evry.
1 Introduction
Le
système d'information implique un nombre important d'annuaires. Par annuaire
nous entendons un ensemble d'information utile à la réalisation de services. Ce
peut être la liste du personnel pour les applications RH (payes, congés ...),
une liste de compte pour l'accès aux ressources informatiques, se déclinant
souvent en une liste par type de service (comptes Unix, comptes NT/2000, comptes
RAS ...) chacun faisant référence à une base propre ( respectivement , Nis,
SAM/Active Directory, radius ...), ou encore des informations pour
l'autocommutateur, répertoriages de ressources immeubles; salles, prises ...,
meubles: mobilier, matériels informatique ... .
On le voit les besoins sont
immenses et souvent redondants. Des solutions existent, elle sont souvent
propriétaires et dépendantes des services.
Face à ces faits, des standards ont été
érigées, c'est notament le cas de la norme X.500, normalisation ISO dédiées aux
annuaires électroniques. Elle reste cependant très lourde à mettre en oeuvre,
est n'est pas adaptée aux réseaux réellement mis en productions (TCP/IP et non
OSI !). C'est ici qu'intervient LDAP
(Lightweight Directory Acces Protocol), qui comme son nom l'indique apporte de
la souplesse aux normes X.500. L'objectif est le même: fédérer les informations
dans une base unique dont l'accès est normalisé et indépendant de tout
constructeur. Il apporte essentiellement une solution exploitable sur des
réseaux que nous utilisons ( technologies Internet) et une mise en oeuvre
abordable. Bien qu'il puisse répondre à
l'ensemble des besoins d'un système d'information complexe, il n'est pas de
notre volonté d'aboutir directement à ce point. Il conviendra avant tout de
concrétiser son utilisation sur des services limités et déjà bien adaptés. Ce
sera le cas, par exemple, de l'authentification des utilisateurs sur les
différentes ressources informatiques de l'établissement.
2 l'existant
Le standard X.500
définis en 1988 puis dans sa deuxième version en 1993 comprend plusieurs normes:
- X500 concepts, modèles, services
- X501 modèles associés aux annuaires X500
- X509 identification et authentification
- X511 détails des services offerts
- X518 les services ditribués entre plusieurs annuaires
- X519 protocoles de communication entre clients/serveurs
- X520 attributs d'enregistrement prédéfinis
- X521 classes d'objets prédéfinies
- X525 réplication sur les serveurs
2.2 les annuaires en exploitation
2.2.1 systèmes d'exploitation Windows
Windows NT: l'information est disséminée dans
plusieurs outils et bases de données (gestionnaires de serveurs, gestionnaire
wins, gestionnaire des utilisateurs ...).
Windows 2000: l'ensemble est regroupé dans
un annuaire propriétaire ; Active Directory, mais compatible avec le protocole
LDAP, il sera donc possible d'y accéder en lecture/écriture via LDAP grâce
notament à l'interface de programmation ADSI.
2.2.2 Novell NDS
Novell à
rendu son système d'annuaire indépendant du système d'exploitation (Netware).
Novell Directory Service est un annuaire object disponible sur Netware, Solaris
et Windows. Il supporte le standard LDAP v3 et les données au format LDIF ( Ldap
Data Interchange Format, format texte de données d'import/export dans un
annuaire LDAP ).
Dès 1985 Sun à
introduit le Network Information Service, déjà destiné à centraliser
l'administration des informations système. Les informations sont stockées sous
forme de map (table de correspondance entre une clé et une valeur: clé titan ,
valeur 192.163.12.43) dans de simples bases indexées (db, dbm ...), accessibles
par des appels RPC (Remote Procedure Call).
Dans un premier temps les map s'ajoutaient
aux fichiers locaux (ajout d'un caractère ``+'' dans le fichier concerné pour
rediriger la recherche vers les nis, remarque: depuis solaris 2 ce signe n'a
plus cet effet. Avec solaris 2 et toutes ses sources d'information système (dns,
nis+ ...) il devenait difficile de programmer dans chaque service ou utilitaire
système, le mode de recherche. Sun a créé une API qui se place entre ces
programmes et les différentes sources d'information sur lesquelles ils
s'appuient, cette API est le Name Service Switch. Avec cette API les programmes
n'ont plus a connaître les détails d'implémentation des services d'information
qu'ils contactent. Les appels à cette API sont du type getXbyY (gethostbyname),
lisent le fichier /etc/nsswitch.conf
dans lequel est associé à
chaque type de service de nom une liste des sources disponibles;
exemple:
passwd: files nis nisplus, host: files nis nisplus dns
. La
recherche se fait d'une source à l'autre dans l'ordre définis tant qu'une
correspondance n'est pas trouvée, ce qui abouti à une erreur
NOTFOUND
en cas d'échec sur toutes les sources listées. On peut
d'ailleurs utiliser l'option [NOTFOUND=return]
afin d'indiquer aux
programmes de consulter uniquement les sources listées à gauche de cette entrée,
seulement en cas de disfonctionnement de ces sources celles de droite seront
consultées. Exemple: networks: nis [NOTFOUND=return] files
. Les NIS fonctionnent sur un système
maître-esclave (les modifications se font sur le maître, elles sont répercutées
sur le(s) esclave(s) du domaine nis), seulement ils ne sont pas adaptés à des
volumes important de données, à chaque modification c'est l'ensemble de la base
qui est transférée entre maitre-esclave. Il y à également un manque
d'organisation des données sous forme hiérarchique. Enfin la sécurité d'accès à
ce service est très faible
Sun à réagit aux
défauts de NIS par l'introduction dans solaris 2 des NIS+. Ils répondent aux
trois remarques ci-dessus en introduisant un propagation des données entre
maître-esclave de manière incrémentale, en ajoutant la notion de root domain
master en haut de l'arbre hiérarchique sous lequel de trouvent des subdmain
master pouvant eux-mêmes être au-dessus d'autres subdomain-master. Enfin la
notion de ``certificat, identité'' (credential) via une paire de clé
privée/publique vient combler le problème de sécurité. L'imposition d'une
architecture hiérarchique de haut en bas des nis+ qui implique une coopération
entre les administrateurs systèmes des différents départements d'une
organisation, ainsi que la gestion des paires clé privée/public fut finalement
un frein au passage des nis aux nis+. Pourtant ces derniers préfigurent
beaucoups de concepts utilisés par la suite dans LDAP.
Le Domain Name
Service à été crée pour palier à l'élargissement des échanges de fichiers hosts
et à la répartition de leur administration déjà conséquente dans le réseau
ARPANET, précurseur de l'Internet. C'est un système de nommage hiérarchique à
l'échelle de l'Internet. Il dispose d'une redondance et depuis peu d'un minimum
de sécurité/contrôle d'accès. Bien que très performant et adapté dans son rôle
de service de noms IP, il est reste aussi très spécialisé.
2.2.6 logiciels du
marché
Microsoft MS-exchange, Lotus cc:Mail, Novell
Groupewise ou Netscape Messaging server utilisent des annuaires propriétaires ,
souvent liés à une base de donnée propre à leurs besoins pour la gestion de
leurs ressources. Des interfaces d'accès (API) à ces bases sont disponibles
(ADSI pour Microsoft, VIM pour Lotus).
2.2.7 logiciels spécifiques
Il existe souvent dans l'entreprise un nombre
important de produits ``maison'' basés la plupart du temps sur des SGBD
(Oracles, DB2, MySQL, Access ...). Encore une fois, bien souvent une base de
comptes est définis pour chacune de ces applications et les interfaces d'accès
ne sont pas toujours simples (C, cobol ...) et uniques.
3 LDAP
Après le succès des
NIS et beaucoup plus modérément des NIS+ par SUN, le CCITT et l'ISO se sont
attelés à définir un standard d'annuaire, dont l'accès serait indépendant des
RPC (SUN), il créèrent le protocole X.500. Bien qu'ayant de très bonnes
spécifications, les détails d'implémentations n'étaient en revanche pas très
heureux que se soit au niveau de la rigidité des règles d'implémentation ou de
la pile de protocole envisagée (ISO plutôt que TCP/IP !). C'est dans ces
conditions qu'est née une version allégée de X.500 basée sur TCP/IP; Lightweight
Directory Acces Protocol qui peut être définis comme étant un protocole de
réseaux standard spécialisé dans la manipulation d'annuaires adapté aux réseaux
et systèmes en exploitation sur l'Internet.
3.1 Modèles
Ce standard
définis 4 modèles.
- Le modèle d'information
- qui définis la nature des données: classe, attribut, types..., l'arbre de
données (DIT: Directory Information Tree).
- Le modèle de nommage
- qui organise et définis des règles de nommages des éléments de l'annuaire.
Exemple; l'annuaire dispose d'un schéma, une classe d'objet doit être unique
dans l'annuaire, elle est identifiée par un OID.
- Le modèle fonctionnel
- qui définis les services offerts, comment accéder aux informations et
comment les mettre à jours.
- Le modèle de sécurité
- qui définis les droits d'accès et l'identification.
3.2 Réplication
LDAP
Mécanisme qui permet de copier automatiquement les
données d'un annuaire vers un autre serveur d'annuaire. Cela permet d'améliorer
les performance en répartissant plusieurs annuaires identiques sur un domaine,
un client sera au plus près de son serveur, cela permet aussi une répartition de
la charge.
3.3 Subschema
Dans la norme
V3 de LDAP le schéma doit être définis dans l'annuaire lui même. Par
l'utilisation de classes (subschema) et attributs spécifiques on permet de lire
et modifier le schéma de l'annuaire au moyen du protocole LDAP lui même.
On
peut lire le schéma via
l'URL:
ldap://localhost:port/cn=schema??base?obectclass=*
3.4 RootDSE
On parle de
RootDSE (Directory Server Agent (Dsa), Specific Entry). Il comprendra des
attributs de type: NamingContext, SupportedExtensions,
SupportedControl,SupportedSALMechanism,SupportedLDAPVersion. C'est le seul objet
qui n'a pas de nom.
3.5 Définitions
Règles
règles de comparaison d'attributs identifiés par
un oid.
Règles:(caseignorematch,CaseExactMatch,TelephoneNumberMatch,
IntegerMatch,BouleanMatch,DNMatch,OctetStringMatch ...) cf RFC 2252.
Classes
Elles décrivent les entrées, entrées qui sont
composées d'attributs. Elles peuvent être de différents types:
- abstrait
- n'ont pas d'instance, elles servent de réservoir de définition pour les
autres classes (grâce à l'héritage): exemple classe top.
- structurel
- définis des objets instanciés, se sont les plus classiques: exemple
Person.
- auxiliaire
- elles sont utilisées pour compléter les classes structurelles (afin de ne
pas modifier directement ces dernières), pour ajouter des attributs à une
classe déjà définie par exemple. Elles hérites de top.
L'ordre
d'utilisation des classes n'est pas obligatoire avec LDAP. Ce n'est pas le cas
dans X500: exemple country->organization->organizationalUnit, avec LDAP on
peut avoir organization->country .
Extension
ce sont les opérations conformes LDAP V3 en
plus des 9 opérations de base. Exemple: association de signature électronique à
toute modification de l'annuaire, ou bien le support de Transaction à la façon
SGBDR.
Scope
sélectionne la profondeur de recherche dans l'arbre
(DIT).
- BASE
- indique une recherche uniquement sur la base sélectionnée (recherche sur
une seule entrée)
- ONELEVEL
- toutes entrées se trouvants au niveau juste inférieur à la base
sélectionnée
- SUBTREE
- recherche à partir de la base sélectionnée et parcoure toutes les branches
en dessous.
URL
On peut interroger un annuaire Ldap avec un
navigateur Internet. L'URL utilise la syntaxe suivante:
protocol://server:port/base?attributs à extraire?type de
scope?critères
.
Exemple:
ldap://corbeau.int-evry.fr:389/dc=int-evry,dc=fr?host?sub?uid=test
test
host corne.int-evry.fr
3.6 habilitations
Les
controles sont de la forme: accès à quoi, par qui -> type d'accès pour cette
paire. exemple: accès à l'attribut telephoneNumber par l'utilisateur lui même
-> écriture.
Dans la partie
quoi, on peut spécifier ;
- une expression régulière
- correspondant à un dn:
dn=<regular expression>
- une liste d'attributs
attrs=<attribute list>
- un filtre
filter=<ldap filter>
L'accès à l'entrée elle
même (attribut "entry") est nécessaire pour donner des accès à un attribut
individuel.
- *
- tous les utilisateurs, autant les anonymes que les authetnifiés
- anonymous
- utilisateur non authentifiés
- users
- utilisateurs authentifiés
- dn=<regex>
- utilisateurs correspondants à une expression régulière, le dn ne doit pas
contenir de blancs (il est "normalized")
remarque: toute directive de
type d'accès (access to
) finie par un by * none
implicite ainsi que toute ACL (access list
) finie par un
access to * by * none
implicite.
3.6.3 Type d'accès
- none
- pas d'accès
- auth
- = x permet de faire un bind authentifié,
- compare
- = cx pour la comparaison,
- search
- =scx pour l'application de filtre de recherche,
- read
- =rscx pour lire les resulats de recherche,
- write
- =wrscx pour modifier ou renommer.
3.6.4 Evaluation
L'évaluation des
controles d'accès se fait dans l'odre ou les regles sont définies dans le
fichier de configuration avec un arret d'évaluation à la première correspondance
("first match"). slapd
compare d'abord le quoi
, puis
le qui
et décide enfin si la requête du client est confome
(inférieure ou égale) au type d'accès
définis dans ces
circonstances (quoi/qui).
3.7 Connexion à l'annuaire (bind)
3.7.1 Authentification Simple
Il suffit de fournir à l'annuaire un Distinguish Name
(dn) et le mot de passe associé (ou bien se connecter en annonymous), on parle
d'attachement au serveur ou Bind
. Par défaut cette authentification
simple laisse circuler en clair les échanges LDAP avec le serveur sur le réseau.
Il faut ajouter des mécanismes de sécurité comme SSL ou SASL pour crypter ces
échanges.
4 Compilation, Installation d'Openldap 2.1.X
(NEW)
4.1 Contraintes de migration 2.0.X à 2.1.X
(NEW)
Un certains nombre de contraintes ont été ajouté dans
les versions 2.1.x pour un meilleurs respet des RFC . Voici la liste de celles
que j'ai rencontré:
- objectclass strutural
- un objet (une entrée) ne peut dépendre que d'une seule objectclass
structurelle, sauf si ces objectclass sont dans la même descendance ,
- attribut systeme structuralObjectClass
- cet attribut apparait sur chaque nouvelle entrée ldap, cela explique
pourquoi on ne peux avoir un master en 2.0.X et un slave en 2.1.X ->
error: "No structuralObjectClass operational attribute"
,
- bind v2
- n'est plus disponible par défaut, il faut le forcer dans le slapd.conf si
nécessaire:
allow bind_v2
,
- bind non dn et defaultaccess
- par défaut il y a maintenant un
disallow bind_anon_dn
et
defaultaccess none
est positionné par défaut,
- entryUUID/entryCSN
- ces deux nouveaux attributs opérationnels sont automatiquement mis à jour
-> utiles pour un futur multi-master ...
- RDN
- la valeur de l'attribut RDN doit être reprise a l'identique dans l'entrée,
exp:
dn: cn=JP_Bar,ou=people,dc=int-evry,dc=fr
puis dans les
attrribut de cet objet -> cn: Jean-Pierre Bar
, ne sera pas
valide ! il doit être identique au RDN -> cn: JP_Bar
.
4.2 Berkeley DB
La base
LDAP est ici au format berkeley DB (BDB),
cf http://www.sleepycat.com/, qui
peut être utilisée dans un backend-bdb
ou backend-ldbm
with-ldapm-api=berkeley
4.2.1 L'essentiel de
BDB
Sur ce lien je reprend les principales caracteristiques
de BDB, et les notions fondamentales, c'est un copier-collé de la doc sleepycat
qui résume ce qui m'a semblé important, pour ma propre information mais aussi
pour le lecteur ... http://www.int-evry.fr/mci/user/procacci/ldap/BDB.txt
4.2.2 Compilation et installation BDB
Afin de rendre les binaires openldap indépendants des
modifications de versions des librairies BDB système (BDB étant utilisé par
ailleurs par le système) nous prenons une version à jour de BDB et l'installons
à part. La compilation d'openldap fera par la suite référence à cette
installation: cf CPPFLAGS et LDFLAGS
de la configuration de la
compilation d'openldap ci-après.
[jehan@corbeau /usr/local/src/db-4.1.24.NC/dist]
$./configure
$make
[jehan@corbeau /usr/local/src/db-4.1.24.NC/dist]
$make install prefix=/usr/local/jehan/bdb-4.1.24
|
4.3 Openldap
Exemple de
compilation et installation dans une arborescence de test, dans l'objectif par
la suite de construire un package RPM pour une installation système propre.
[jehan@corbeau /usr/local/src/openldap-2.1.8]
$ CPPFLAGS=-I/usr/local/jehan/bdb-4.1.24/include \
LDFLAGS=-L/usr/local/jehan/bdb-4.1.24/lib \
./configure --enable-debug --enable-crypt --enable-bdb --enable-ldbm \
--with-ldbm-api=berkeley --enable-monitor --enable-local --enable-cldap \
--disable-rlookups --with-tls --with-cyrus-sasl --enable-passwd \
--enable-shell --enable-cleartext --enable-spasswd --enable-meta --enable-ldap --enable-rewrite
$ make depend
$ make
$ make test
$ make install prefix=/usr/local/src/jehan/openldap-2.1.8
|
4.3.1 Configuration
Adaptation du schema
Penser (pour une config redhat avec
autofs et kerberos) à recréer l'arborenscence de schema redhat pour les schemas
autofs et kerberos aisni que de modifier le schema de base afin de tenir compte
du fait qu'une entrée ldap ne peu dépendre que d'une classe structurelle (sauf
si cette classe hérite d'une autre classe structurelle de la meme lignée ->
Person -> InetOrgPerson )
[jehan@corbeau /usr/local/src/jehan/openldap-2.1.8/etc/openldap/schema]
$ mkdir redhat
$ cp /tmp/autofs.schema ./redhat/
$ cp /tmp/kerberosobject.schema ./redhat/
$ cp /tmp/int-evry.schema .
Ajout de l'attribut krbName a kerberosobject.schema,
attribut qui était avant définit dans core.schema et reclassement
en AUXILIARY de l'objectclass kerberosSecurityObject qui etait STRUCTURAL !.
attributetype ( 1.3.6.1.4.1.250.1.32
NAME ( 'krbName' 'kerberosName' )
DESC 'Kerberos Name'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
SINGLE-VALUE )
objectclass ( 1.3.6.1.4.1.2312.4.2.4 NAME 'kerberosSecurityObject'
SUP top AUXILIARY
DESC 'A uid with an associated Kerberos principal'
MUST ( krbName ) )
Redéfinition de l'objectclass account de STRUCTURAL vers AUXILIARY
$ vi cosine.schema
objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
SUP top AUXILIARY
|
Adaptation du fichier de configuration
Modification du
slapd.conf
pour s'adapter à l'arborescence de test
ucdata-path /usr/local/src/jehan/openldap-2.1.8/share/openldap/ucdata
include /usr/local/src/jehan/openldap-2.1.8/etc/openldap/schema/core.schema
include ....
allow bind_v2
database bdb
directory /usr/local/src/jehan/openldap-2.1.8/var/openldap-data/int
|
Test
Restauration d'une base
[jehan@corbeau /usr/local/src/jehan/openldap-2.1.8]
$ ./sbin/slapadd -l /tmp/dump_int.ldif21Nov200219:59:03
-f ./etc/openldap/slapd.conf
$ ls var/openldap-data/int/
cn.bdb __db.005 IntEPersInetServ.bdb log.0000000005 uid.bdb
__db.001 dn2id.bdb log.0000000001 log.0000000006 uidNumber.bdb
__db.002 gidNumber.bdb log.0000000002 mail.bdb
__db.003 givenName.bdb log.0000000003 objectClass.bdb
__db.004 id2entry.bdb log.0000000004 sn.bdb
|
Lancement du serveur
[jehan@corbeau /usr/local/src/jehan/openldap-2.1.8]
$ ./libexec/slapd -4 -d 256 -f etc/openldap/slapd.conf \
-h ldap://localhost:9009/
bdb_open: Sleepycat Software: Berkeley DB 4.1.24: (September 13, 2002)
...
|
Requête
[jehan@corbeau /usr/local/src/jehan/openldap-2.1.8]
$ ./bin/ldapsearch -x uid=procacci -b "dc=int-evry,dc=fr" -p 9009 -h localhost
|
Utilitaires BDB
[jehan@corbeau /usr/local/src/jehan/openldap-2.1.8/var/openldap-data/int]
$ /usr/local/src/jehan/bdb/bin/db_stat -m
....
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Pool File: id2entry.bdb
16384 Page size.
0 Requested pages mapped into the process' address space.
12 Requested pages found in the cache (1%).
1405 Requested pages not found in the cache.
0 Pages created in the cache.
1405 Pages read into the cache.
3 Pages written from the cache to the backing file.
$ /usr/local/src/jehan/bdb/bin/db_verify id2entry.bdb -o
$ /usr/local/src/jehan/bdb/bin/db_dump -f mail.bdb.dump mail.bdb
$ rm mail.bdb
$ /usr/local/src/jehan/bdb/bin/db_load -f mail.bdb.dump mail.bdb
db_load: Lock table is out of available locks
db_load: Cannot allocate memory
???
$ /usr/local/src/jehan/bdb/bin/db_recover -v
db_recover: Finding last valid log LSN: file: 6 offset 6567774
db_recover: Recovery starting from [6][6567605]
db_recover: Recovery complete at Sun Nov 17 19:49:04 2002
db_recover: Maximum transaction ID 80001453 Recovery checkpoint [6][6567774]
db_recover: Recovery complete at Sun Nov 17 19:49:04 2002
db_recover: Maximum transaction id 80000000 Recovery checkpoint [6][6567774]
|
4.4 Package Openldap RPM (NEW)
Installation d'openldap à partir de source RPM. Partir
des packages source permet entre autre de modifier le mode de compilation
d'openldap. On voudra par exemple forcer la compilation avec les supports des
threads (pas de threads par defaut dans les versions 2.0.1x des packages RedHat
d'openldap !) ou bien avec le support des berkeley DB ou des fonctionnalité méta
etc ... On retrouve donc toutes les options de compilation des sources au format
tar.gz, puisque qu'un package source n'est autre qu'une automatisation de la
configuration-compilation-installation d'une application. cf RPM-HOWTO: http://www.linux.org/docs/ldp/howto/RPM-HOWTO/
Ici nous sommes partis d'un package source 2.1.3 RedHat, en y incluant
régulièrement les différentes version openldap, dernièrement le tar.gz 2.1.15
d'openldap, avec les adaptations qui vont bien, cf commentaires ci-dessous.
$ rpm -i /home/jehan/openldap-2.1.3-4-RH.src.rpm
|
Modification des options de
compilation et adaptation du package source 2.1.3 vers 2.1.15. Essentiellement,
il s'agit de prendre en compte les berkeley DB
-> backend
berkeley
puis quelques modifications (patch de la 2.1.3 devenus inutiles,
ou idéfinis !? en 2.1.15) et options de compilation pour la prise en charge de
fonctionnalitées supplémentaires: --enable-monitor --enable-meta etc
...
$ vi /usr/src/redhat/SPECS/openldap-2.1.15.spec
%define migtools_ver 44
%define db_version 4.1.25.NC
#%define backend gdbm
%define backend berkeley
Summary: The configuration files, libraries, and documentation for OpenLDAP.
Name: openldap
#Version: 2.1.3
Version: 2.1.15
#Release: 4
Release: 1
...
#Modification des patch de la 2.1.3 vers la 2.1.8; on en retire 2 !.
Patch0: openldap-2.1.3-config.patch
#Patch1: openldap-2.1.2-redhat.patch
Patch2: openldap-1.2.11-cldap.patch
#Patch3: openldap-2.1.2-syslog.patch
Patch3: openldap-2.1.13-syslog.patch
Patch4: openldap-2.1.2-sendbuf.patch
Patch5: openldap-2.0.11-ldaprc.patch
Patch7: openldap-2.1.12-subdir.patch
...
%setup -q -a 1 -a 3
%patch0 -p1 -b .config
#%patch1 -p1 -b .redhat
%patch2 -p1 -b .cldap
%patch3 -p1 -b .syslog
%patch4 -p1 -b .sendbuf
%patch5 -p1 -b .ldaprc
#%patch6 -p1 -b .debug
%patch7 -p1 -b .subdir
...
%configure \
--with-slapd --with-slurpd --without-ldapd \
--with-threads=posix --enable-static \
\
--enable-local --enable-cldap --disable-rlookups \
\
--with-tls \
--with-cyrus-sasl \
\
--enable-wrappers \
\
--enable-passwd \
--enable-shell \
--enable-cleartext \
--enable-crypt \
--enable-spasswd \
--enable-modules \
--enable-lmpasswd \
--enable-monitor \
--enable-rewrite \
--enable-ldap \
--enable-meta \
--enable-shell \
--enable-password \
--enable-debug \
\
--libexecdir=%{_sbindir} \
--localstatedir=/%{_var}/run \
$@ \$@
|
Construction des packages openldap,
attention depuis la version 8.0 de RedHat la commande est maintenant
rpmbuild -ba
et non plus rpm -ba
!.
[root@corbeau /usr/src/redhat/SPECS]
$ rpmbuild -ba openldap-2.1.15.spec
...
Wrote: /usr/src/redhat/SRPMS/openldap-2.1.15-1.src.rpm
Wrote: /usr/src/redhat/RPMS/i386/openldap-2.1.15-1.i386.rpm
Wrote: /usr/src/redhat/RPMS/i386/openldap-devel-2.1.15-1.i386.rpm
Wrote: /usr/src/redhat/RPMS/i386/openldap-servers-2.1.15-1.i386.rpm
Wrote: /usr/src/redhat/RPMS/i386/openldap-clients-2.1.15-1.i386.rpm
liste des packages ldap sur la machine
$ rpm -qa | grep ldap
openldap-devel-2.1.15-1
nss_ldap-198-3
php-ldap-4.2.2-8.0.5
openldap-2.1.15-1
openldap-clients-2.1.15-1
openldap-servers-2.1.15-1
|
Installation des packages binaires
$ cd /usr/src/redhat/RPMS/i386/
[root@corbeau /usr/src/redhat/RPMS/i386]
$ rpm -Uvh openldap-*2.1.15-1.i386.rpm
Preparing... ########################################### [100%]
1:openldap ########################################### [ 25%]
2:openldap-servers ########################################### [ 50%]
3:openldap-clients ########################################### [ 75%]
4:openldap-devel ########################################### [100%]
|
4.5 Disponibilite des
RPM
Je met régulièrement en ligne mes compilations de RPM
sur: http://www.int-evry.fr/mci/user/procacci/SRPMS/
5 Exploitation
5.1 Modifier le schéma
Il
est possible de personnaliser le schéma par ajout
d'attribut/objectclass.
5.1.1 Définition
d'objets
Une syntaxe particulière est utilisée pour définir
des attributs/objectclass. Ici nous employons la syntaxe LdapV3. il existe aussi
une syntaxe ASN1, ou X500 .
Cela commence par le mot clé
attributetype
ou objectclass
suivi de son
oid
du nom NAME
et d'une éventuelle
DESC
ription.
On trouve ensuite la règle de comparaison entre
attributs, EQUALITY caseIgnoreMatch
par exemple éventuellement
suivit d'une règle de correspondance sur les opérations de recherche,
SUBSTR caseIgnoreSubstringsMatch
par exemple.
Enfin une
SYNTAXE
identifiée par un oid
définit le type d'un
attribut.
Types:(binary,boolean,dn,diretory string (chaine UTF8), integer,
telephoneNumber...) cf RFC 2252 et 2256.
5.1.2 Exemple de schema
Ici
nous utilisons une objectclass auxiliary dont l'objectif est d'apporter des
modifications à une classe structurelle standard.
[root@mci21056 /etc/openldap/schema]
$ more int-evry.schema
#definitions propres à l'int
attributetype (1.3.6.1.4.1.7391.2.2.1.1.1.5
NAME ('IntEPersInetServDemande')
DESC 'Services Internet autorises'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
)
objectclass ( 1.3.6.1.4.1.7391.2.1.1.1.1.1
NAME 'IntE-user'
SUP TOP
AUXILIARY
MAY ( IntEPersInetServDemande )
)
|
OID
L'INT-Evry s'est vu attribué par l'IANA
(http://www.iana.org/) l'oid 7391, donc la branche d'oid 1.3.6.1.4.1.7391. Ici
suivant l'exemple de la doc openldap nous commençons l'arbre privé par 2 (pour
ldap, 1 pour snmp) puis 2 pour les attributs ou 1 pour les objectclass. Ensuite
on peut imaginer une branche système_informatique 1, mci 1, comptes
1
; d'où le 7391.2.1.1.1.1.1 pour l'attribut
IntEPersInetServDemande.
Autre exemple; utilisation du SubstringsMatch
pour matcher une sous-chaine dans une liste ou aussi des types boolean;
attention la case est importante: TRUE ou FALSE ou ON et OFF
$more /etc/openldap/schema/int-evry.schema
#definitions propres à l'int
attributetype (1.3.6.1.4.1.7391.2.2.1.1.1.4
NAME ('IntEPersInetServ')
DESC 'Services Internet autorises'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
)
attributetype (1.3.6.1.4.1.7391.2.2.1.1.1.9
NAME ('IntEPersPublic')
DESC 'Services Internet demandes'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
)
|
5.1.3 Exemple
d'entrée
Exemple d'entrée ldif pour un compte utilisateur
INT-evry. Dans cet exemple les attributs IntEPersxxxx (Int Evry Personne nom
d'attribut) sont propres au schéma interne de l'INT.
dn: uid=procacci,ou=People,dc=int-evry,dc=fr
uid: procacci
cn: Jehan PROCACCIA
telephoneNumber: 01 60 76
givenName: Jehan
sn: PROCACCIA
objectClass: inetLocalMailRecipient
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: account
objectClass: posixAccount
objectClass: IntE-user
objectClass: labeledURIObject
objectClass: strongAuthenticationUser
objectClass: certificationAuthority
objectClass: top
objectClass: kerberosSecurityObject
objectClass: shadowAccount
mail: Jehan.Procaccia@int-evry.fr
mailLocalAddress: procacci@mci.int-evry.fr
mailRoutingAddress: email@email
mailHost: smtp-mci
departmentNumber: MCI
employeeType: permanent
IntEPersUserQuota: 10000
IntEPersUserParrain: Eric.Collery
IntEPersUserExpire: 2999/12/31
IntEPersUserPTM: mci
IntEPersCreationDate: 2001/07/31-17:22:20
IntEPersLastModificationDate: 2001/07/31-17:22:20
IntEPersUserNature: permanent
IntEPersUserLogin: procacci
IntEPersUserUid: 145032
IntEPersUserGroup: mci
IntEPersUserShell: ksh
IntEPersUserPrenom: Jehan
IntEPersUserNom: PROCACCIA
IntEPersUserGecos: Jehan PROCACCIA
IntEPersUserEntite: MCI
IntEPersUserEmail: Jehan.Procaccia
IntEPersUserSmtp: smtp-mci
IntEPersUserMailLogin: procacci
IntEPersUserMbox: pop-mci
IntEPersUserMX: mci
o: INT Evry FRANCE
ou: MCI
shadowLastChange: 10000
krbName: procacci@INT-EVRY.FR
loginShell: /usr/local/bin/ksh
uidNumber: 145032
gidNumber: 145
homeDirectory: /mci/mci/procacci
gecos: Jehan PROCACCIA
host: .int-evry.fr
title: procacci
roomNumber: B001
jpegPhoto;binary:: /9j/4AAQSkZJRgABAQEAAQABAAD/2w......
labeledURI: http://www.int-evry.fr
facsimileTelephoneNumber: 01 60 76 xx xx
postalCode: 91011 EVRY CEDEX
postalAddress: 9 rue Charles Fourier
homePhone: 00 00 00 00 00
homePostalAddress: xx xxx
secretary: uid=secretary-name,ou=People,dc=int-evry,dc=fr
userCertificate;binary:: YWJjZGVmZ2hpamts
authorityRevocationList;binary:: YWJjZGVmZ2hpamts
certificateRevocationList;binary:: YWJjZGVmZ2hpamts
cACertificate;binary:: YWJjZGVmZ2hpamts
IntEPersInetServ: unix-int mail-int
IntEPersInetServDemande: unix-int mail-int ras-int
IntEPersACLDroit: telephoneNumber homePostalAddress
IntEPersPublic: FALSE
IntEPersUserPasswordFlag: FALSE
IntEPersUserLastPasswordChange: 1900/01/01-00:00:00
|
5.2 Modifier une entrée, outils shell
ldap*
syntaxe
changetype:
<[modify|add|delete|modrdn]>
Après la prise en compte de
l'objectclass ci-dessus ( slapd.conf: include int-evry.schema
) il
est possible d'ajouter l'attribut IntEPersInetServ:
$ more add_IntEPersInetServ.ldif
dn: uid=testlinu,ou=staff,ou=People,dc=int-evry,dc=fr
changetype: modify
add: objectclass
objectclass: int-evry-user
-
add: IntEPersInetServ
IntEPersInetServ: unix-int mail-int
$ ldapmodify -D "cn=admin,dc=int-evry,dc=fr" -W -p 9009 -h corbeau -x \
-f ./add_IntEPersInetServ.ldif
Enter LDAP Password:
modifying entry "uid=testlinu,ou=staff,ou=People,dc=int-evry,dc=fr"
|
Suppression:
$ more del_IntEPersInetServ.ldif
dn: uid=testlinu,ou=staff,ou=People,dc=int-evry,dc=fr
changetype: modify
delete: IntEPersInetServ
IntEPersInetServ: unix-int mail-int
-
delete: objectclass
objectclass: int-evry-user
$ ldapmodify -D "cn=admin,dc=int-evry,dc=fr" -W -p 9009 \
-h corbeau -x -f ./del_IntEPersInetServ.ldif
Enter LDAP Password:
modifying entry "uid=testlinu,ou=staff,ou=People,dc=int-evry,dc=fr"
|
Pour supprimer une entrée
complète:
dn: uid=testlinu,ou=staff,ou=People,dc=int-evry,dc=fr
changetype: delete
|
5.3 Dump et restore de la base
Après avoir
arreter le serveur, du moins pour les backend ldbm, normalement cela n'est plus
nécessaire avec back-bdb (openldap 2.1.X), on peux faire un dump de la base au
format ldif.
$ /etc/init.d/ldap stop
Stopping slapd: [OK]
$/usr/sbin/slapcat -l /tmp/dump_int.ldif \
-f /etc/openldap/slapd.conf -b "dc=int-evry,dc=fr"
$more /tmp/dump_int.ldif
dn: dc=int-evry,dc=fr
dc: int-evry
objectClass: top
objectClass: domain
objectClass: domainRelatedObject
associatedDomain: int-evry.fr
creatorsName: cn=admin, dc=int-evry, dc=fr
createTimestamp: 20010718150911Z
modifiersName: cn=admin, dc=int-evry, dc=fr
modifyTimestamp: 20010730082211Z
...
|
Si on
remplace une base existante, on commence par la supprimer. Méthode rapide:
supprimer les fichiers
$ /etc/init.d/ldap stop
Stopping slapd: [ OK ]
[root@openldap /var/lib/ldap/int]
$ rm -f *
|
Insertion sous forme de fichiers
.gdbm, .dbb ou .bdb du dump.
$ /usr/sbin/slapadd -l /tmp/dump_int.ldif -f /etc/openldap/slapd.conf \
-b "dc=int-evry,dc=fr"
[root@corbeau /var/lib/ldap/int]
$ ls -al
total 11130
drwxr-xr-x 2 ldap ldap 1024 Aug 2 17:46 .
drwx------ 6 ldap ldap 1024 Aug 2 17:15 ..
-rw------- 1 root root 1716224 Aug 2 17:46 cn.dbb
-rw------- 1 root root 700416 Aug 2 17:46 dn2id.dbb
-rw------- 1 root root 31304 Aug 2 17:46 gidNumber.dbb
-rw------- 1 root root 495920 Aug 2 17:46 givenName.dbb
-rw------- 1 root root 7448938 Aug 2 17:46 id2entry.dbb
-rw------- 1 root root 1728600 Aug 2 17:46 mail.dbb
-rw------- 1 root root 12296 Aug 2 17:46 nextid.dbb
-rw------- 1 root root 421909 Aug 2 17:46 objectClass.dbb
-rw------- 1 root root 860200 Aug 2 17:46 sn.dbb
-rw------- 1 root root 188416 Aug 2 17:46 uid.dbb
-rw------- 1 root root 196608 Aug 2 17:46 uidNumber.dbb
|
Remarque: l'insertion c'est faite sous
le compte root, il faut rendre ldap propiétaire des fichiers sans quoi slapd ne
pourra rien lire !.
$ chown ldap:ldap *
[root@corbeau /var/lib/ldap/int]
$ ls -l
total 11128
-rw------- 1 ldap ldap 1716224 Aug 2 17:46 cn.dbb
-rw------- 1 ldap ldap 700416 Aug 2 17:46 dn2id.dbb
-rw------- 1 ldap ldap 31304 Aug 2 17:46 gidNumber.dbb
-rw------- 1 ldap ldap 495920 Aug 2 17:46 givenName.dbb
-rw------- 1 ldap ldap 7448938 Aug 2 17:46 id2entry.dbb
-rw------- 1 ldap ldap 1728600 Aug 2 17:46 mail.dbb
-rw------- 1 ldap ldap 12296 Aug 2 17:46 nextid.dbb
-rw------- 1 ldap ldap 421909 Aug 2 17:46 objectClass.dbb
-rw------- 1 ldap ldap 860200 Aug 2 17:46 sn.dbb
-rw------- 1 ldap ldap 188416 Aug 2 17:46 uid.dbb
-rw------- 1 ldap ldap 196608 Aug 2 17:46 uidNumber.dbb
$ /etc/init.d/ldap start
Starting slapd: [ OK ]
|
et c'est reparti .
6 Développement
API Ldap en
C cf draft-ietf-ldap-c-api-01.txt
6.1 concepts
Toute
interaction avec un serveur se fait sur la base d'une recherche. Il n'y a pas de
fonction de navigation ou d'interrogation. Les fonctions peuvent être
synchrones, dans ce cas le programme client est bloqué en l'attente d'une
réponse du serveur LDAP. Elle peuvent être asynchrones, le programme client peut
alors faire autre chose en attendant que le serveur réponde, il faudra cependant
"poller" régulièrement pour vérifier la presence d'une réponse. Les fonctions
synchrones finissent toujours par un s: ldap_simple_bind_s
6.1.1 code de connexion
0 #include <stdio.h>
1 #include <ldap.h>
2
3 main (int argc, int **argv) {
4 // Structure de donnée LDAP qui enregistre la connexion
5 LDAP *ld;
6 int rc = 0;
7 printf("Test de connexion Ldap en C\n");
8 /* initialisation de la connexion,
9 retour d'un handle de connexion dans la structure LDAP.
10 l'init est tj synchrone. */
11 if ((ld = ldap_init("corbeau", 9009) )== NULL)
12 {
13 perror ("ldap_init");
14 }
15 printf("Connecté à ldap\n");
16 // Bind au serveur, bind synchrone
17 rc = ldap_simple_bind_s(ld,"cn=admin,dc=int-evry,dc=fr","password");
18
19 if (rc != LDAP_SUCCESS)
20 {
21 fprintf(stderr,"Ldap error: %s\n", ldap_err2string(rc));
22 }
23 else
24 {
25 printf("Bind OK!\n");
26 }
27 // défaire le bind
28 if ( ldap_unbind(ld) != LDAP_SUCCESS )
29 {
30 perror("ldap_unbind");
31 }
32 }
6.1.2 code de recherche
33
34 #include <stdio.h>
35 #include <ldap.h>
36
37
38 #define HOST "corbeau"
39 #define PORT 9009
40 #define BASE "dc=int-evry,dc=fr"
41 #define SCOPE LDAP_SCOPE_SUBTREE //autres: LDAP_SCOPE_ONELEVEL LDAP_SCOPE_BASE
42 //filtre: l'uid = procacci ou testlinu et pour l'un ou l'autre le gid est 145
43 #define FILTER "(&(|(uid=procacci)(uid=testlinu))(gidNumber=145))"
44
45 main (int argc, int **argv) {
46
47 // handle de connexion
48 LDAP *ld;
49 // structure contenant les données d'une entry + un pointeur vers l'entrée
50 // suivante ou NULL s'il n'y en a pas
51 LDAPMessage *result,*e;
52 // structure de données Basic Encoding Rules (BER), règles définies pour
53 // transmettre des données binaires sur l'Internet
54 BerElement *ber;
55 char *attribute,**vals;
56 int i,rc,parse_rc =0;
57 char *attribs[3];
58 attribs[0]="cn";
59 attribs[1]="mail";
60 attribs[2]=NULL;
61
62 // initialisation de la connexion
63 printf("Initialisation de la connexion\n");
64 if ((ld = ldap_init(HOST, PORT) )== NULL)
65 {
66 perror ("ldap_init");
67 exit(1);
68 }
69 printf("Connecté au serveur ldap %s sur le port %d\n",HOST,PORT);
70
71 /* fonction de recherche, parametres non NULL: handle de connexion, base, scope
72 , filtre de recherche.
73 parametres optionnels: attributs à selectionner (LDAP_NO_ATTRS pour aucuns),
74 entier 0 pour retourner le nom des attributs en plus de leur valeur (1 sinon),
75 extended operations, controles clients, time-out limite dans une structure
76 timeval ici pas de limite, combien d'entrées nous voulons sélectionner, et
77 enfin un pointeu sur une structure LDAPMessage pour le resultat du search */
78
79 rc = ldap_search_ext_s(ld,BASE,SCOPE,FILTER,attribs,0,
80 NULL,NULL,LDAP_NO_LIMIT,0,&result);
81
82 if (rc != LDAP_SUCCESS )
83 {
84 fprintf(stderr, "ldap_search_ext: %s\n", ldap_err2string(rc));
85 ldap_unbind(ld);
86 exit(1);
87 }
88
89 printf("Nombre d'entrées sélectionnées: %d\n", ldap_count_entries(ld,result));
90
91 //parcours des entrées
92 for (e=ldap_first_entry(ld,result); e !=NULL; e=ldap_next_entry(ld,e))
93 {
94 //fonction spécifique pour le dn
95 printf("DN: %s\n",ldap_get_dn(ld,e));
96 //parcours des attributs<->valeurs d'une entrée
97 for (attribute = ldap_first_attribute(ld,e,&ber);
98 attribute != NULL; attribute = ldap_next_attribute(ld,e,ber))
99 {
100 //valeur(s) d'attribut, handle connexion, entrée, attribut
101 if ((vals = ldap_get_values(ld,e,attribute)) != NULL)
102 {
103 //parcours eventuel des attributs multivalués,sinon une seule valeur
104 for (i=0; vals[i] != NULL; i++)
105 {
106 printf ("\t%s: %s\n",attribute,vals[i]);
107 }
108 //libération de la mémoire allouée aux valeurs d'attribut
109 ldap_value_free(vals);
110 }
111 //liberation de la mémoire allouée à l'attribut
112 ldap_memfree(attribute);
113 }
114
115 //libération de la mémoire utilisée pour stocker
116 la structure de valeur (ber) de l'attribut
117 if (ber != NULL)
118 {
119 ber_free (ber, 0);
120 }
121
122 }
123
124 // test du rc de for (e=ldap_first_entry(ld,result)... ci dessus
125 if (rc != LDAP_SUCCESS)
126 {
127 fprintf(stderr, "ldap_search_ext: %s\n", ldap_err2string(rc));
128 }
129
130 ldap_msgfree ( result);
131 printf ("Search réussi !\n");
132 }
133
compilation
$ gcc ldap_search.c -lldap -llber -o ldap_search.bin
|
exécution
$ ./ldap_search.bin
Initialisation de la connexion
Connecté au serveur ldap corbeau sur le port 9009
Nombre d'entrées sélectionnées: 2
DN: uid=testlinu,ou=Staff,ou=People,dc=int-evry,dc=fr
cn: Compte_test LINUX
mail: Compte_test.LINUX@int-evry.fr
DN: uid=procacci,ou=Staff,ou=People,dc=int-evry,dc=fr
cn: Jehan PROCACCIA
mail: Jehan.PROCACCIA@int-evry.fr
Search réussi !
|
7 Authentification système Unix, connexion à
un système
7.1 Objectifs
l'authentification
système par un annuaire LDAP permet d'unifier les bases de données utilisateur.
De plus le système de répartition et de réplication que procure ce type
d'annuaire permet une meilleure tolérance aux pannes. Enfin d'autres services
peuvent tirer partie de cette base commune d'authentification (email, accès web,
ftp, carnet d'adresse ...). C'est aussi la disponibilité d'outils
d'administration et de surveillance de la journalisation.
7.2 Authentification système traditionnelle
Unix
Le système unix utilise depuis longtemps un système
d'authentification basé sur une algorithme de hachage nommé
crypt(3)
disponible aux programmeurs C par la librairie
libcrypt.a
, a ne pas confondre avec l'application
d'encryptage/décryptage de fichiers /usr/bin/crypt
. Avec
crypt(3)
la chaine texte saisie par l'utilisateur est hachée
(one-way-encrypted) par l'algorithme crypt
qui introduit en plus de
cette chaîne un grain de sel (il s'agit des 2 premiers caractères de la version
cryptée des 13 caractères ASCII du password, ils sont choisis aléatoirement afin
de différencier différente occurrence d'une même chaine: salt).
Lors de
l'authentification l'utilisateur saisi son login, ce qui permet au système de
rechercher la chaine cryptée (password) qui est associée à ce login. Ensuite
l'utilisateur est invité à saisir son password, celui ci sera crypté par
l'algorithme crypt(3)
avec les 2 premiers caractères du password
crypté récupéré lors du login comme salt. Enfin une correspondance positive
entre ce cryptage de la saisie et la chaîne cryptée récupérée lors du login
attestera de l'identité de l'utilisateur.
7.3 Authentification système NIS+
La méthode ci-dessus ne permet pas de contrôler d'où se
connecte l'utilisateur puisque cette information n'est stockée nulle part, de
plus elle est basée sur un algorithme qui utilise une clé sur 56 bit
relativement ancien. Dans NIS+ des ``certificats'' (user credentials) sont crées
sous une forme unix.userid@domainname
et stockés dans la table
cred
. Quand un utilisateur se connecte, les credentials sont
retirés depuis la table cred
. Cette table contient le mot de passe
réseau de l'utilisateur sous forme de paire clé privée/publique.
Tout comme les Name
Service Switch NSS viennent s'intercaler entre les programmes faisant accès à
des sources d'information et ces sources, Pluggable Authentification Module
fournis un cadre permettant à de nouvelles technologies d'authentification de
s'interfacer avec les programmes qui les utilisent. On va par exemple avec un
module PAM_LDAP
, permettre à des programmes tels que login, telnet,
ftp..., d'aller chercher et vérifier l'information d'authentification auprès
d'un annuaire LDAP. Ces programmes doivent être ``pam-enabled'' c'est à dire lié
à la librairie pam libpam.so
pour utiliser ce cadre
d'authentification. Reste à l'administrateur du système de définir les modules à
utiliser, ce qui peut être définis de manière individuelle pour chaque
application, ou communément pour un ensemble d'application. L'administrateur
pourra empiler et définir un ordre d'importance à chacun des modules d'une
manière propre pour chacun des programmes. C'est une structure
d'authentification extrêmement modulaire et donc très évolutive.
7.4.1 Type de modules
PAM
On distingue 4 fonctions qui peuvent être implémentés par
un module.
- authentification
- ce type de module permet l'authentification et positionne l'identité d'un
utilisateur.
- account managment
- une fois authentifier, ce type de module permet de valider l'accès de
l'utilisateur aux ressources sur des critères tels que le vieillisement du mot
de passe, l'expiration du compte, heures de restriction....
- session management
- gère certaines fonctions pendant la session de l'utilisateur, notament
lors de l'ouverture et la fermeture de la session.
- password management
- gère les modifications de mot de passe.
7.4.2 Empilage et drapeaux de contrôle
Pour un service donné (ou plusieurs) différent
modules peuvent être empilés, un mécanisme de drapeaux de contrôle (control
flags) permet de donner plus ou moins d'importance au succès ou échec
d'authentification sur chacun des modules empilés.
- required
- dans le cas d'un module déclaré required, en cas d'échec sur celui-ci le
reste de la pile est consulté,mais le retour final sera un échec quelquesoit
le résultat des modules suivants traversés.
- requisite
- en cas d'échec sur un module déclaré requisite, une erreur est
immédiatement retournée sans poursuivre l'empilement des modules.
- sufficient
- si ce module retourne un succès, alors un succès général est immédiatement
retourné sans poursuivre l'empilement.
- optional
- si ce module échoue, un autre peut retourner un succès, cet échec ne sera
pas pris en compte dans le résultat final.
7.4.3 pam.conf ou pam.d/service
Exemple de fichier
/etc/pam.d/login
commenté
#%PAM-1.0
###############################################################################
#auth: actual authentification, ask and check password and set credentials as
#group membership or kerberos tickets
#securetty check that root logs from the console
auth required /lib/security/pam_securetty.so
#warn log info to syslog
auth required /lib/security/pam_warn.so
#check presence of /etc/nologin file
auth required /lib/security/pam_nologin.so
#pam ldap
auth sufficient /lib/security/pam_ldap.so debug
#pam_unix: This is the standard Unix authentication module.
# It uses standard calls from the system's libraries to retrieve
#and set account information as well as authentication
#arguments: debug; audit; use_first_pass; try_first_pass; nullok; nodelay
auth required /lib/security/pam_unix_auth.so try_first_pass audit
#############################################################################
#Account: non-authentification account management
#restrict access on time of day, available system ressources ...
account required /lib/security/pam_warn.so
account sufficient /lib/security/pam_ldap.so
#pam_unix: Recognized arguments: debug; audit
account required /lib/security/pam_unix_acct.so audit
##############################################################################
#password: for updating the authentification, if an auth module has determined
#that the password needs to be changed e.g expired ...
#if pam_unix present in the module type password
#arguments: debug; audit; nullok; not_set_pass; use_authtok; try_first_pass;
use_first_pass; md5; bigcrypt; shadow; nis; remember
password required /lib/security/pam_warn.so
#cracklib, checks tha newly entered password does not appear in a dictionnary
password required /lib/security/pam_cracklib.so
password sufficient /lib/security/pam_ldap.so debug
#pwdb modules: is a pluggable replacement for the pam_unix_.. modules.
#Based on the following pwdb_elements: expire; last_change; max_change;
#defer_change; warn_change,
# this module performs the task of establishing the status of the user's
#account and password
#The default action of this module is to not permit the user access to a
#service if their official password is blank.
#The nullok argument overrides this default.
#the argument try_first_pass, before prompting the user for their password,
#the module first tries the previous stacked auth-module's password in case
#that satisfies this module as well.
#The argument use_first_pass forces the module to use such a recalled password
#and will never prompt the user - if no password is available or the password
#is not appropriate, the user will be denied access.
#arguments: debug; nullok; not_set_pass; use_authtok; try_first_pass;
#use_first_pass; md5; bigcrypt; shadow; radius; unix
password required /lib/security/pam_pwdb.so use_first_pass debug
###########################################################################
#session: for doing things before/after users can be given a service
#e.g: logging of information, mounting directory ...
session required /lib/security/pam_warn.so
session required /lib/security/pam_unix_session.so
session optional /lib/security/pam_console.so
|
7.4.4 configuration PAM sous RedHat (NEW)
Exemple de la version RH 8.0, pam-0.75-40, l'empilement
des modules pam pour la plupart des services est centralisé dans le fichier
system-auth
.
$ cat /etc/pam.d/login
#%PAM-1.0
auth required /lib/security/pam_securetty.so
auth required /lib/security/pam_stack.so service=system-auth
auth required /lib/security/pam_nologin.so
account required /lib/security/pam_stack.so service=system-auth
password required /lib/security/pam_stack.so service=system-auth
session required /lib/security/pam_stack.so service=system-auth
session optional /lib/security/pam_console.so
$ cat /etc/pam.d/system-auth
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required /lib/security/pam_env.so
auth sufficient /lib/security/pam_unix.so likeauth nullok
auth sufficient /lib/security/pam_ldap.so use_first_pass
auth required /lib/security/pam_deny.so
account required /lib/security/pam_unix.so
#ajouter pour la connexion de compte locaux quand il n'y a pas de serveur LDAP
account sufficient /lib/security/pam_localuser.so
account [default=bad success=ok user_unknown=ignore \
service_err=ignore system_err=ignore] /lib/security/pam_ldap.so
password required /lib/security/pam_cracklib.so retry=3 type=
password sufficient /lib/security/pam_unix.so nullok use_authtok md5 \
shadow
password sufficient /lib/security/pam_ldap.so use_authtok
password required /lib/security/pam_deny.so
session required /lib/security/pam_limits.so
session required /lib/security/pam_unix.so
session optional /lib/security/pam_ldap.so
|
7.5 NSS et Pam ldap, outils d'authentification
système par LDAP
NSS et PAM ldap
Il existe deux outils sous unix pour
authentifier via un annuaire ldap, il s'agit de nss_ldap
et
pam_ldap
.
Le premier est utilisé par les services/programmes
qui ne sont pas compatibles PAM; exemple /usr/bin/id
qui fait un
appel getpwent() (accès à /etc/passwd
et
/etc/shadow
).
Les Name Service Switch
(/etc/nsswitch.conf
) redirigent cet appel vers différentes sources:
files, nis, dns et grâce à nss_ldap
vers ldap . Pour les
applications compatibles PAM (pam-enabled) il est possible d'utiliser
pam_ldap
, cela permet d'individualiser le fichier de configuration
d'accès à l'annuaire par service, donc d'utiliser aussi une méthode
d'authentification différente suivant le service, il apporte pour cela d'autres
méthodes d'authentification que crypt.
8 Mise en oeuvre de l'authentification système
par LDAP
Certaines versions
de packages sont ou peuvent être compilées avec la libwrap
, donc
utilise les tcp-wrappers. Il faut penser à configurer les fichiers de contrôle
d'accès en conséquence.
$vi /etc/hosts.allow
slapd: .int-evry.fr
|
Sans cette ligne slapd
, nous
aurions un "access denied "
.
8.2 lancement
$more /etc/rc.d/init.d/ldap
daemon ${slapd} -u ldap -f /etc/openldap/slapd.conf \
-h "ldap://ldap1.int-evry.fr:389/" -l LOCAL3 $OPTIONS $SLAPD_OPTIONS
|
Les log seront dans local3 redirigés
vers /var/log/ldap.log
par /etc/syslog.conf
, le port
standard en 389 sur le host ldap1.
8.3 configuration
Personnalisation
du fichier de configuration slapd.conf
Ajouts aux directives
par défaut:
#et les attributs/objectclass propre à l'INT
include /etc/openldap/schema/int-evry.schema
#check du schema
schemacheck on
# The next line allows LDAPv2 bind requests, which are disabled by default.
allow bind_v2
#on augmente le nombre max d'entré retourné lors d'une requète 'large'
sizelimit 15000
#le directory et les index seront dans
directory /var/lib/ldap/int
# modif performance ed
cachesize 10000
dbcachesize 1500000
|
8.4 Mot de passe administrateur
Définition du password "root":
[root@openldap ~]
$perl -e 'print crypt("plaintext", "somerandomsalt"), qq(\n)'
$perl -e 'print crypt("padle", "gd"), qq(\n)'
gdRK6cNklXSV6
|
donc dans slapd.conf
rootdn "cn=admin,dc=int-evry, dc=fr"
rootpw {crypt}abcd123XQ1234
|
Il faut définir les droits unix sur ce
directory personnalisé:
$chown ldap:ldap /var/lib/ldap/int
|
8.5 Première initialisation des données
Format utf8
Il faut avant tout convertir le fichier ldif
en utf8 (accents sur ``télécom'' par exemple...)
[root@openldap /usr/local/Migratemci/Ldif]
$iconv arbre.ldif -f LATIN1 -t UTF8 -o arbre_utf8.ldif --verbose
|
Démarrage du serveur
On démarre le serveur afin d'y
insérer les données.
$/etc/rc.d/init.d/ldap start
Starting slapd: [ OK ]
|
Ossature
On ajoute l'ossature du DIT (arbre).
[root@servfax /usr/local/Migratemci/Ldif]
$ldapadd -f arbre_utf8.ldif -x -D "cn=admin,dc=int-evry,dc=fr" -W -p
389 -h ldap1
Enter LDAP Password:
adding new entry "dc=int-evry,dc=fr"
adding new entry "ou=People,dc=int-evry,dc=fr"
adding new entry "ou=Group,dc=int-evry,dc=fr"
adding new entry "ou=Staff,ou=People,dc=int-evry,dc=fr"
adding new entry "ou=Students,ou=People,dc=int-evry,dc=fr"
adding new entry "ou=Stagiaires,ou=People,dc=int-evry,dc=fr"
adding new entry "ou=Thesards,ou=People,dc=int-evry,dc=fr"
|
Contrôle avec un browser LDAP
Visualisation avec le ldap
browser (java): http://www.iit.edu/ gawojar/ldap
$cd /usr/local/ldapbrowser/
[root@ldap1 /usr/local/ldapbrowser]
$./lbe.sh
|
8.6 Migration des Données système (nis) vers
ldap
Exemple restreint
Migration de /etc/passwd
et /etc/shadow
(depuis /var/yp/src/passwd
et
shadow
.
[root@ldap1 /usr/local/MigrationToolsJP]
$./migrate_passwd_staff.pl ./Files/passwd.mci ./Ldif/passwd_mci.ldif
|
Le nom des fichiers est important (cf
source perl des scripts). Le script déduit de la chaine
passwd_staff
le namingcontext du fichier
migrate_common_mci.ph
(gestion de l'ou=staff dans notre exemple de
schéma personnalisé). La presence d'un fichier shadow (ici dans
./Files/shadow.mci
) est importante aussi pour qu'il intègre les
attributs d'authentification shadowaccount
.
Exploitation
Finalement en exploitation nous utiliserons
un schema standard (ou=people, puis tout les login à plat dessous): Migration
depuis ypcat passwd
.
[root@ldap1 /usr/local/Migratemci]
$./migrate_passwd.pl ./Files/yppasswd ./Ldif/people.ldif
|
Ajout des entrées utilisateurs
[root@ldap1 /usr/local/MigrationToolsJP]
$ldapadd -f ./Ldif/passwd_mci.ldif -x -D "cn=admin,dc=int-evry,dc=fr"
-W -p 389 -h ldap1
Enter LDAP Password:
adding new entry "uid=gilles,ou=Staff,ou=People,dc=int-evry,dc=fr"
adding new entry "uid=petit,ou=Staff,ou=People,dc=int-evry,dc=fr"
...
|
Migration des groups
[root@ldap1 /usr/local/MigrationToolsJP]
$./migrate_group.pl ./Files/group ./Ldif/groups.ldif
|
Ajout à l'annuaire
[root@ldap1 /usr/local/MigrationToolsJP]
$ldapadd -f ./Ldif/groups.ldif -x -D "cn=admin,dc=int-evry,dc=fr" -W -p
9009 -h ldap1
Enter LDAP Password:
adding new entry "cn=admins,ou=Group,dc=int-evry,dc=fr"
adding new entry "cn=guests,ou=Group,dc=int-evry,dc=fr"
....
|
8.6.3 L'ensemble dans un fichier ldif
global
Plutot que de migrer les fichiers sources un a un ,
l'esemble de la migration peut se faire via migrate_all_offline.sh
.
[mciadmin@openldap /usr/local/Migratemci]
$./migrate_all_offline.sh
Creating naming context entries...
Migrating aliases...
Migrating groups...
Migrating hosts...
Migrating networks...
Migrating users...
Migrating protocols...
Migrating rpcs...
Migrating services...
Migrating netgroups...
Importing into LDAP...
Migrating netgroups (by user)...
Migrating netgroups (by host)...
Preparing LDAP database...
/etc/openldap/slapd.conf: Permission denied
No databases found in config file
|
A partir de "Importing into LDAP" le
script plante volontairement, dans la phase de debuggage nous voulions disposer
d'un ficher ldif, puis de l'inserer dans l'annuaire mannuellement.
$ls -ltra /tmp | tail -1
-rw------- 1 mciadmin mciadmin 3578259 aoû 1 13:42 nis.ldif.DRnZGR
$more /tmp/nis.ldif.DRnZGR
dn: dc=int-evry,dc=fr
dc: int-evry
objectClass: top
objectClass: domain
objectClass: domainRelatedObject
associatedDomain: int-evry.fr
dn: ou=People,dc=int-evry,dc=fr
ou: People
objectClass: top
objectClass: organizationalUnit
objectClass: domainRelatedObject
associatedDomain: int-evry.fr
dn: ou=Rpc,ou=System,dc=int-evry,dc=fr
ou: Rpc,ou
objectClass: top
objectClass: organizationalUnit
objectClass: domainRelatedObject
associatedDomain: int-evry.fr
.....
|
Il ne reste plus qu'a faire
l'insertion manuelle:
$ldapadd -f/tmp/nis.ldif.DRnZGR -x -W -D"cn=admin,dc=int-evry,dc=fr" -h ldap1
ldap_bind:
....
|
8.7 Authentification système
8.7.1 Installation
Installation de
nss_ldap
et éventuellement pam_ldap
. Avec la
distribution RedHat, le module pam_ldap
est intégré dans le package
nss_ldap
.
$ rpm -qli nss_ldap-198-3 | grep pam_ldap
This package includes two LDAP access clients: nss_ldap and pam_ldap.
/lib/security/pam_ldap.so
des exemples de configuration pam pour les services sont disponibles:
/usr/share/doc/nss_ldap-198/pam.d/login
/usr/share/doc/nss_ldap-198/pam.d/passwd
/usr/share/doc/nss_ldap-198/pam.d/pop
....
Pour connaitre la version de pam_ldap incluse dans le package nss_ldap RedHat:
$ rpm -q nss_ldap --changelog | grep pam_ldap
- update to nss_ldap 197, pam_ldap 150
...
[root@servfax /etc]
$vi ldap.conf
host ldap1.int-evry.fr ldap2.int-evry.fr
base dc=int-evry,dc=fr
ldap_version 3
port 389
binddn cn=binduser,ou=system,dc=int-evry,dc=fr
bindpw secret
pam_password crypt #pour la commande/usr/bin/passwd.
pam_filter IntEPersInetServ=*unix-int* #filtre propre à l'INT
[root@servfax /etc]
$vi nsswitch.conf
passwd: files nisplus ldap
shadow: files nisplus ldap
group: files nisplus ldap
automount: files nisplus ldap
|
8.7.2 Exemple d'authentification
$telnet servfax
Connected to servfax.int-evry.fr.
Escape character is '^]'.
Red Hat Linux release 7.2 (Enigma)
Kernel 2.4.14 on an i686
login: procacci
Password:
Last login: Sun Jan 27 18:06:53 on :0
No directory /mci/mci/procacci!
Logging in with home = "/".
ksh-2.04$
|
Sans automount pas de home directory !
cf ci-dessous pour l'automount.
8.8 Automount (NEW)
Nous
prenons ici l'option de ne monter que le homedir complet d'un utilisateur et non
son directory parent. Cette implémentation non documentée a été réalisé en
étroite collaboration avec Nalin Dahyabhai <nalin@redhat.com>. Cela
suppose de créer un automounter "master", exemple /citi
ici, qui
lancera un automounter par sous-répertoire; /citi/citi1
ou
/citi/citi2
, enfin un wildcard sur cn=/
montera le
directory prorpre à l'utilisateur; /citi/citi1/testciti
par
exemple.
Après modification de migrate_automount.pl
nous
arrivons à ce qui est décrit ci-dessus.
8.8.2 Mise en oeuvre
[mciadmin@openldap /usr/local/Migratemci]
$./migrate_automount.pl /usr/local/Migratemci/Files/auto.citi \
./Ldif/auto-citi-tree.ldif
$more ./Ldif/auto-citi-tree.ldif
#The auto.master
dn: ou=auto.master,dc=int-evry,dc=fr
objectClass: top
objectClass: automountMap
ou: auto.master
#auto.master points to cn /citi, that latest managing subdirectories
dn: cn=/citi,ou=auto.master,dc=int-evry,dc=fr
objectClass: top
objectClass: automount
automountInformation: ldap:ou=auto.citi,ou=automount,dc=int-evry,dc=fr
cn: /citi
# This entry is more or less a place-holder for automount entries for directories \
#which get mounted under /citi.
dn: ou=auto.citi,ou=automount,dc=int-evry,dc=fr
objectClass: top
objectClass: organizationalUnit
ou: auto.citi
# This entry causes autofs to start up another automounter on /citi/citi1.
Dn: cn=citi1,ou=auto.citi,ou=automount,dc=int-evry,dc=fr
objectClass: top
objectClass: automount
cn: citi1
automountInformation: -fstype=autofs \
ldap:ou=auto.citi.citi1,ou=auto.citi,ou=automount,dc=int-evry,dc=fr
# This entry is more or less a place-holder for automount entries for directories \
#which get mounted under /citi/citi1.
dn: ou=auto.citi.citi1,ou=auto.citi,ou=automount,dc=int-evry,dc=fr
objectClass: top
objectClass: organizationalUnit
ou: auto.citi.citi1
# This is a wildcard entry for any user whose home directory is under
# /citi/citi1
dn: cn=/,ou=auto.citi.citi1,ou=auto.citi,ou=automount,dc=int-evry,dc=fr
objectClass: top
objectClass: automount
cn: /
automountInformation: -rw,intr,soft,quota nfsserver:/home/&
|
8.8.3 Configuration système
Ici nous prenons en compte la presence de replicas.
On trouvera dans /etc/ldap.conf
la liste des serveurs LDAP à
interroger pour l'authentification pam, et dans
/etc/openldap/ldap.conf
la liste des serveurs LDAP (les même) pour
automount , ainsi que pour les outils shell openldap (ldapsearch, ldapmodify
...) .
$grep host /etc/ldap.conf
host ldap1.int-evry.fr ldap2.int-evry.fr
$grep HOST /etc/openldap/ldap.conf
HOST ldap1.int-evry.fr ldap2.int-evry.fr
|
8.8.4 Exemple d'utilisation
#L'utilisateur testciti (nfs-automount homedir) se connecte:
$ pwd
/citi/citi1/testciti
#Autofs status
$ /etc/init.d/autofs status
Configured Mount Points:
------------------------
/usr/sbin/automount /citi ldap ou=auto.citi,ou=automount,dc=int-evry,dc=fr
Active Mount Points:
--------------------
/usr/sbin/automount /citi ldap ou=auto.citi,ou=automount,dc=int-evry,dc=fr
/usr/sbin/automount --submount /citi/citi1 ldap \
ou=auto.citi.citi1,ou=auto.citi,ou=automount,dc=int-evry,dc=fr
ldap log
Mar 14 11:19:52 corne automount[2670]: starting automounter version 3.1.7, \
path = /mci/mci, maptype = ldap, mapname = \
ou=auto.citi.citi1,ou=automount,dc=int-evry,dc=fr
Mar 14 11:19:52 corne automount[2670]: Map argc = 1
Mar 14 11:19:52 corne automount[2670]: Map argv[0] = \
ou=auto.citi.citi1,ou=automount,dc=int-evry,dc=fr
Mar 14 11:19:52 corne automount[2670]: lookup(ldap): server = "(default)", \
base dn = "ou=auto.citi.citi1,ou=automount,dc=int-evry,dc=fr"
|
8.8.5 Contrôle d'accès aux stations et
serveurs NFS
Sur le principe décrit dans la section suivante
``contrôle d'acces aux services'', on ajoute un filtre pam dans le fichier
/etc/ldap.conf
pour contrôler les accès login et NFS sur le
stations. Ce filtre diffèrera suivant que l'on se trouve sur une station salles
TP ou une station dans un département par exemple:
stations département citi
$ grep pam_filter /etc/ldap.conf
pam_filter IntEPersInetServ=*unix-citi*
stations salles TP
$ grep pam_filter /etc/ldap.conf
pam_filter IntEPersInetServ=*unix-int*
|
8.8.6 Gestion de differents homedir
L'objectif est de mettre à disposition des
utlisateurs des répertoires d'accueil (homedir) sur different serveurs NFS. Le
serveur NFS (homedir) sera choisi en fonction de la localité de la station de
travail où l'utilisteur se connecte, dans un département ou en salle de TP par
exemple.
#A user ldap entry can contain 2 (or more ) homeDirectory attributes
homeDirectory: /mci/citi/testciti
homeDirectoryDept: /citi/citi1/testciti
#On departement citi client machines, the homeDirectory attr is remapped,
#so that users get their homes from the citi nfsserver.
$ grep homeDirectoryDept /etc/ldap.conf
nss_map_attribute homeDirectory homeDirectoryDept
$ ssh testciti@citi_client_machine
$ pwd
/citi/citi1/testciti
#On departement mci client machines, traditional homeDirectory attr is seacrh,\
#they get their homes from mci nfsserfer (cf ldap automount maps)
$ ssh testciti@mci_client_machine
$ pwd
/mci/citi/testciti
|
8.9 Contrôle d'accès
host
On desire contrôler sur quels hosts un utilisateur peut
se connecter. On peut utiliser l'attribut host (objectclass account de
cosine.schema) pour cela, il suffit de lister les serveurs (un par occurence de
l'attribut) sur lesquels un utilisateurs peut se connecter. Restera sur les
serveurs en question à definir un filtre sur leur propre nom dans
/etc/ldap.conf. Depuis pam_ldap
130 voir l'option
pam_check_host_attr
. Entre les versions pam_ldap
125
et 129, la simple présence de l'attribut host dans une entrée ldap impossait le
contrôle du nom de host sur lequel l'utilisateur se connecte.
8.9.1 exemple d'entrée ldif
$ ldapsearch -h ldap1 -p 9009 -x -b"dc=int-evry,dc=fr" "(host=*)"
....
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
....
host: mci21056.int-evry.fr
host: servfax.int-evry.fr
#host: *.int-evry.fr #* dans l'entree ne fonctionne pas
#en revanche cela fonctionne dans le filtre /etc/ldap.conf
|
8.9.2 Configuration du serveur
Version ancienne de pam_ldap
(< 125 ?)
[root@mci21056 /usr/local/Migratemci/Ldif]
$ more /etc/ldap.conf
...
# Filter to AND with uid=%s
#pam_filter objectclass=account
pam_filter host=servfax.int-evry.fr
...
|
Puis, contrôle par défaut pour les
versions pam_ldap
124 à 129, depuis la version
pam_ldap
130 utilisation de la directive
pam_check_host_attr
dans /etc/ldap.conf.
Du fait de
l'empilement des modules pam, le module pam_unix
basé sur les nss,
contourne le filtre pam_ldap
definit dans
/etc/ldap.conf
. En effet , nss_ldap
va directement
lire l'annuaire te ne tiens pas compte des filtres de pam_ldap
,
ainsi l'utilisateur sera authentifié par pam_unix,
même si
pam_ldap
échoue grâce au contrôle d'accès host !. Il faut alors
interdir à nss_ldap
d'authentifier en tant qu'anonymous (car le
bind ce fait en anonymous au login). Pour cela on spécifie des ACL dans le
slapd.conf
afin de ne pas permettre au compte
anonymous
l'accès read
sur l'attribut
userpassword
mais seulement le droit auth
(nécessaire
pour faire un bind).
access to attr=userPassword
by self write
by anonymous auth
by dn="cn=root,dc=int-evry,dc=fr" write
by * none
access to *
by self write
by dn="cn=root,dc=int-evry,dc=fr" write
by * read
|
8.9.4 démonstration
Avant
et après changement des ACL.
[procacci@mci21056 ~]
$su - testlinu
Password:
su: incorrect password
#changement ACL
[procacci@mci21056 ~]
$su - testlinu
Password:
ksh-2.04$
|
Remarque: le message d'erreur
su: incorrect password
peut être trompeur !
Les log confirment
le filtre demandé dans /etc/ldap.conf
:
Jun 25 14:22:08 mci21056 slapd[8205]: conn=1 op=1 SRCH base="dc=int-evry,dc=fr"
scope=2 filter="(&(host=servfax.int-evry.fr)(uid=testlinu))"
|
9 Contrôle d'accés aux services (NEW)
Ici nous gérons l'accés aux différents services basés sur
ldap (connexion unix, mountage nfs, accés web, accés messagerie etc ...) par le
biais d'un attribut (perso) multivalué (IntEPersInetServ
)qui liste
l'ensemble des services ouverts à un individu:
$ ldapsearch -x uid=testciti -D "cn=admin,dc=int-evry,dc=fr" -W IntEPersInetServ -LLL
Enter LDAP Password:
dn: uid=testciti,ou=People,dc=int-evry,dc=fr
IntEPersInetServ: unix-int mail-int unix-citi unix-citi cours
|
Dans cet exemple, l'individu a accés
aux services de connexion et de disque (NFS) sur le machines unix central
(unix-int) , au mail central (mail-int) , aux services de connexion et disque du
département citi (unix-citi) et enfin à la publication de cours en ligne
(cours-int).
C'est un filtre (SubStringMatch !) sur une des valeures de
cet attribut qui donnera ou non accés au service. Pour pam le filtre est realisé
dans /etc/ldap.conf
, pour le web dans la configuration du module
apache en question, et pour toute application interne -> à définir dans le
code source !. La plupart des applications ``ldap enable'' proposants l'ajout
d'un filtre aux requètes de base, nous pouvons largement étendre les
fonctionnalités de cet attribut.
Avertissement
La combinaison de pam et nss ldap peut
provoquer des résultats inattendus. Par exemple pam_unix
peut
valider une connexion via ldap (/etc/nsswitch.conf
-> passwd:
ldap) alors que l'on voulais forcer un filtre via pam_ldap
(/etc/ldap.conf ->pam_filter IntEPersInetServ=*unix-int*
). Cela
impose donc une grande rigueur sur l'empilement des modules dans pam et sur la
qualité des controles qu'on leur applique (required, sufficient ....).
10 Replication
10.1 Compte de
replication
Nous utiliserons un compte pour la replication
different du rootdn.
$ cat Replicator.ldif
dn: cn=replicator,ou=System,dc=int-evry,dc=fr
cn: replicator
sn: REPLICATOR SN
objectClass: person
userPassword: {crypt}fgtyp5LztXllw
$ ldapadd -f ./Replicator.ldif -x -D"cn=admin,dc=int-evry,dc=fr" -W -h corne
Enter LDAP Password:
adding new entry "cn=replicator,ou=System,dc=int-evry,dc=fr"
|
10.2 Configuration du maître
Les sections ACL et database du fichier de
configuration slapd sont modifiés. attention dans la section replica avec une
bindmethod=simple (ce serai different avec kerberos) le mot de passe qui suit
dans credentials doit être en clair !.
$ cat /etc/openldap/slapd.conf
access to attr=userPassword
by self write
by anonymous auth
by dn="cn=admin,dc=int-evry,dc=fr" write
by dn="cn=replicator,ou=System,dc=int-evry,dc=fr" write
by * none
access to *
by self read
by dn="cn=admin,dc=int-evry,dc=fr" write
by dn="cn=replicator,ou=System,dc=int-evry,dc=fr" write
by * read
database ldbm
suffix "dc=int-evry, dc=fr"
rootdn "cn=admin, dc=int-evry, dc=fr"
rootpw {crypt}REYTjkmLCELfk
directory /var/lib/ldap/int
replica host=esclave.int-evry.fr
binddn="cn=replicator,ou=System,dc=int-evry,dc=fr"
bindmethod=simple credentials=pass
replogfile /var/lib/ldap/replica/replogfile
index objectClass,uid,uidNumber,gidNumber,IntEPersInetServ eq
index cn,mail,surname,givenname eq,subinitial
|
10.3 Configuration de l'esclave
Sur l'esclave on modifie également les ACL pour
donner tous les droits au compte de réplication. la section database est
modifiée afin de prendre en compte le dn du compte de replica definit dans la
section replica du maitre (binddn=) .
$ cat /etc/openldap/slapd.conf
#ACL
access to ...
...
by dn="cn=replicator,ou=System,dc=int-evry,dc=fr" write
...
database ldbm
suffix "dc=int-evry, dc=fr"
rootdn "cn=admin, dc=int-evry, dc=fr"
rootpw {crypt}REYTjkmLCELfk
directory /var/lib/ldap/int
updatedn "cn=replicator,ou=System,dc=int-evry,dc=fr"
updateref "ldap://maitre.int-evry.fr:389"
index objectClass,uid,uidNumber,gidNumber,IntEPersInetServ eq
index cn,mail,surname,givenname eq,subinitial
|
10.4 Mise en place
Apres
avoir prédéfinis les fichiers de configuration ci-dessus, et crée le compte de
réplication, il faut maintenant arrêter le serveur maître afin de récuperer la
base ldap.
$ /etc/init.d/ldap stop
Arrêt de slapd : [ OK ]
|
On récupère les fichiers de la base ldap
du maître sur l'esclave
$ cd /var/lib/ldap/int
$ ftp maitre
>cd /var/lib/ldap/int
>mget *.dbb # dans le cas d'un ldap utilisant db3 au lieu de gdbm !
>bye
$ chown ldap:ldap *.dbb
|
Enfin on relance ldap sur le maître et
sur l'esclave.
#Maître
$ /etc/init.d/ldap start
Starting slapd: [ OK ]
Starting slurpd: [ OK ]
#Esclave
$ /etc/init.d/ldap start
Starting slapd: [ OK ]
|
10.5 Démonstration
10.5.1 Lancement d'une modification sur le
maître.
#Maître
$ ldapmodify -f ./replace-host.ldif -x -W -D "cn=admin,dc=int-evry,dc=fr"
Enter LDAP Password:
modifying entry "uid=test,ou=People,dc=int-evry,dc=fr"
#log Maître
Jan 25 18:39:39 openldap slapd[5988]: daemon: conn=52 fd=24 connection from
IP=157.159.10.16:33986 (IP=157.159.10.16:34049) accepted.
Jan 25 18:39:39 openldap slapd[5995]: conn=52 op=0 BIND
dn="CN=ADMIN,DC=INT-EVRY,DC=FR" method=128
Jan 25 18:39:39 openldap slapd[5995]: conn=52 op=0 RESULT tag=97 err=0 text=
Jan 25 18:39:39 openldap slapd[6003]: conn=52 op=1
MOD dn="uid=test,ou=People,dc=int-evry,dc=fr"
Jan 25 18:39:40 openldap slapd[6003]: conn=52 op=1 RESULT tag=103 err=0 text=
Jan 25 18:39:40 openldap slapd[5995]: conn=52 op=2 UNBIND
Jan 25 18:39:40 openldap slapd[5995]: conn=-1 fd=24 closed
#log esclave
Jan 25 18:39:40 ur slapd[6369]: conn=1 op=5
MOD dn="uid=test,ou=People,dc=int-evry,dc=fr"
Jan 25 18:39:41 ur slapd[6369]: conn=1 op=5 RESULT tag=103 err=0 text=
|
10.5.2 Fichiers de replication,
explication
Explication: Merci à Vincent MATHIEU
<Vincent.Mathieu@univ-nancy2.fr>
- 1
- slurpd utilise comme répertoire de travail le sous-répertoire replica du
répertoire précisé par l'option -t du lancement du démon.
- 2
- slapd met les informations de modification dans le fichier indiqué par la
directive replogfile du fichier de conf.
- 3
- slurpd puise ses infos et vide ce fichier, qui sert ainsi de
communicationentre les 2 processus. Ca permet un fonctionnement asynchrone, et
l'arrêt-relance non synchronisé des 2 processus.
- 4
- slurpd inscrit les infos de mises à jour dans le fichier slurp.replog de
sonrépertoire de travail, avec un marqueur de temps (time). C'est un fichier
qui s'agrandit indéfiniment.
- 5
- slurpd tente de mettre à jour les réplicas. En cas d'erreur, il va créer
un fichier de nom NomDuReplica.rej (reject). Il est possible ultérieurement de
rejouer ce fichier des rejets.
- 6
- Il met à jour à chaque traitement le fichier slurpd.status. Ce fichier
contient une ligne par esclave. la ligne comprend un indicateur de temps
identique au marqueur de temps du fichier slurpd.replog. C'est grâce à ce
fichier qu'il sait pour chaque esclave où il en est des mises à jour.
A noter que le fichier des reject n'est mis à jour que lors de
tentative de maj défectueuse d'un esclave LDAP (par exemple, incohérence dans
les schémas, ...); si l'esclave n'est pas dispo, ce n'est pas considéré comme
une erreur, slurpd tentera une mise à jour plus tard pour cet esclave.
A
noter également qu'il faut prévoir une moulinette qui nettoie de temps en temps
le fichier slurpd.replog.
[root@openldap /var/lib/ldap/replica]
$ ls -al
total 16
drwxr-xr-x 2 root root 4096 Jan 25 17:29 .
drwx------ 7 ldap ldap 4096 Jan 25 17:08 ..
-rw-r--r-- 1 ldap root 0 Jan 25 18:39 replogfile
-rw-r--r-- 1 ldap root 0 Jan 25 18:39 replogfile.lock
-rw-r--r-- 1 root root 3678 Jan 25 18:39 slurpd.replog
-rw-r--r-- 1 root root 0 Jan 25 18:39 slurpd.replog.lock
-rw-r--r-- 1 root root 30 Jan 25 18:39 slurpd.status
-rw-r--r-- 1 root root 0 Jan 25 18:34 slurpd.status.lock
[root@openldap /var/lib/ldap/replica]
$ tail -14 slurpd.replog
replica: ur.int-evry.fr
time: 1011980380
dn: uid=test,ou=People,dc=int-evry,dc=fr
changetype: modify
replace: host
host: hostname0.int-evry.fr
-
replace: modifiersName
modifiersName: cn=admin, dc=int-evry, dc=fr
-
replace: modifyTimestamp
modifyTimestamp: 20020125173939Z
-
[root@openldap /var/lib/ldap/replica]
$ cat slurpd.status
ur.int-evry.fr:0:1011980380:0
|
10.5.3 Rejouer une réplication rejetée
Il se peut que la réplication ne se fasse pas, c'est
le cas par exemple quand on modifie le schema sur le master pour ajouter de
nouvelles objectclass/attribut et qu'on ne le fait pas sur le slave !.
[root@corbeau /var/lib/ldap/replica]
-rw-r----- 1 root root 2990 Mar 13 19:42 corne.int-evry.fr:0.rej
[root@corbeau /var/lib/ldap/replica]
$ more corne.int-evry.fr:0.rej
ERROR: Undefined attribute type
replica: corne.int-evry.fr:0
time: 1015551248.0
dn: uid=doutrele,ou=People,dc=int-evry,dc=fr
changetype: modify
add: maildeliveryoption
maildeliveryoption: mailbox
-
replace: modifiersName
modifiersName: cn=admin, dc=int-evry, dc=fr
-
replace: modifyTimestamp
modifyTimestamp: 20020308013406Z
-
$ slurpd -r ./corne.int-evry.fr\:0.rej -o
Processing in one-shot mode:
9 total replication records in file,
9 replication records to process.
|
ici un problème de timestamp lié à une
difference de date entre le master et le slave ainsi qu'une application
peut-etre trop tardive du fichier, refuse de repliquer ... !? .
[root@corbeau /var/lib/ldap/replica]
$ slurpd -r ./corne.int-evry.fr\:0.rej -o -d 65535
Config: opening config file "/etc/openldap/slapd.conf"
Config:....
...
begin replication thread for corne.int-evry.fr:0
Replica corne.int-evry.fr:0, skip repl record for uid=doutrele,ou=People,dc=int-evry,dc=fr (old)
.... 9 fois ...
end replication thread for corne.int-evry.fr:0
slurpd: terminated.
|
10.6 Configuration
PAM
L'une des utilisations d'un réplica, est de permettre aux
clients de s'authentifier sur l'un ou l'autre des serveurs. Cela repond au
problême de panne, et permet aussi en exploitation normale de répartir la
charge. En ce qui concerne PAM, il suffit de modifier le fichier de
configuaration /etc/ldap.conf
en conséquence:
$ cat /etc/ldap.conf | grep host
host openldap.int-evry.fr ur.int-evry.fr
|
il suffit donc lister les serveurs ldap
(séparés par un espace) dans la directive host
de
/etc/ldap.conf
.
Pour d'autres programmes comme les commandes
shell openldap (ldapsearch, ldapmodify ..) ou automount par exemple, c'est
/etc/openldap/ldap.conf
qui sera lu !
$ grep HOST /etc/openldap/ldap.conf
HOST openldap.int-evry.fr ur.int-evry.fr
|
11 Réplication Partielle (NEW)
11.1 Principes
Il peut être
interessent d'avoir un replica contenant seulement une partie du DIT et/ou une
partie des atrributs/objectclass du master. Dans cet exemple nous allons créer
un replica dédié pages blanches, contenant uniquement la branche
ou=people,dc=int-evry,dc=fr dépourvue des fonctionnalitées authentification
système unix, donc dépourvue des objectclass PosixAccount
et
shadowAccount
ainsi que les attributs associés (sauf ceux
necessaires ``MUST'' des autres objectclass; exp: uid !).
11.2 Initialisation du replica
11.3 Compte de replication partiel
Insertion du compte de replication partiel dans
l'oberescence réduite à ou=people.
$ cat /usr/local/Migratemci/Ldif/replicator-partial.ldif
dn: ou=System,ou=people,dc=int-evry,dc=fr
ou: System
objectClass: top
objectClass: organizationalUnit
dn: cn=replicator,ou=System,ou=people,dc=int-evry,dc=fr
objectClass: person
sn: REPLICATOR SN
cn: replicator
userPassword:: e0NSWVBUfVg4aHUseU9UUjRlb1E=
$slapadd -f /etc/openldap/slapd.conf -l Ldif/replicator-partial.ldif
|
11.4 Extraction du subtree ou=people
Le replica partiel doit être initialialisé avec une
base partielle !. On va donc extraire du master un ldif contenant uniquement
l'arborescence desirée. (l'option -s de slapcat est un patch de la commande
originale, je pense qu'elle devrait etre intégré dans les futures versions
openldap, cf liste openldap-software ).
$ /usr/sbin/slapcat -b dc=int-evry,dc=fr -s ou=people,dc=int-evry,dc=fr \
-f /etc/openldap/slapd.conf > dump-ou=people.ldif
|
Puis on retire les attributs non
desirables sur le replica pages blanches:
$ cat remove-posix-account.pl
#!/usr/bin/perl
open (F1,"<dump-ou=people.ldif") || die " pb $!";
open (FOUT,">dump-no-posix.ldif");
while ($ligne1 = <F1>) {
if ($ligne1 =~ /Account|uidNumber|gidNumber|loginShell|homeDirectory|\
gecos|shadowLastChange/ )
{next;}
else {
print FOUT ( $ligne1 );}
}
$ ./remove-posix-account.pl
|
11.5 Initialisation du replica
Sur le replica on récupère le fichier ldif travaillés
ci-dessus et on crée la base ldap:
sftp> get dump-no-posix.ldif
[root@ldaptux /var/lib/ldap/int-evry]
$ slapadd -f /etc/openldap/slapd_int-evry.conf -l ./dump-no-posix.ldif
$ chown ldap:ldap *
|
11.6 Configuration du master
database bdb
suffix "dc=int-evry, dc=fr"
rootdn "cn=root, dc=int-evry, dc=fr"
rootpw {crypt}rfG0trfN67nDn6
directory /var/lib/ldap/int
#cachesize 6000
#checkpoint 100000 360
#dbnosync
#readonly on
replica host=ldaptux.int-evry.fr:3006
#suffix limité a ou=people
suffix="ou=people,dc=int-evry,dc=fr"
#on retire les objectclass/attributs indésirables
attr!="posixAccount,shadowAccount,loginShell,homeDirectory,\
uidNumber,gidNumber,gecos"
binddn="cn=replicator,ou=System,ou=people,dc=int-evry,dc=fr"
bindmethod=simple credentials=secret
replogfile /var/lib/ldap/replica/replogfile
|
11.7 Configuration du replica partiel
access to attr=userPassword
by self write
by anonymous auth
by dn="cn=replicator,ou=System,ou=people,dc=int-evry,dc=fr" write
by * none
access to *
by self read
by dn="uid=procacci,ou=people,dc=int-evry,dc=fr" write
by dn="cn=replicator,ou=system,ou=people,dc=int-evry,dc=fr" write
by * none
schemacheck on
database bdb
suffix "ou=people,dc=int-evry,dc=fr"
rootdn "uid=procacci,ou=people,dc=int-evry,dc=fr
rootpw {crypt}ttG0lY6U7nDn6
directory /var/lib/ldap/int-evry
updatedn "cn=replicator,ou=system,ou=people,dc=int-evry,dc=fr"
updateref "ldap://corbeau.int-evry.fr:389"
#cachesize 100
#checkpoint 10 5
index objectClass,uid,uidNumber,gidNumber,IntEPersInetServ eq
index cn,mail,surname,givenname eq,subinitial
|
11.8 Demarrage et test
[root@ldaptux /var/lib/ldap/int-evry]
$ /etc/init.d/ldap_int-evry start
|
Modification des attributs
telephoneNumber et loginShell sur le master slapd logs:
Master
Mar 7 18:12:36 corbeau slapd[4796]: conn=8 op=5 MOD dn="uid=test, ou=People, \
dc=int-evry,dc=fr"
Mar 7 18:12:36 corbeau slapd[4796]: conn=8 op=5 MOD attr=telephoneNumber \
loginShell userPassword
Mar 7 18:12:36 corbeau slapd[4796]: conn=8 op=5 RESULT tag=103 err=0 text=
Mar 7 18:12:36 corbeau slapd[4806]: conn=8 op=6 SRCH base="uid=test,ou=People,\
dc=int-evry,dc=fr" scope=0 filter="(objectClass=*)"
Mar 7 18:12:36 corbeau slapd[4806]: conn=8 op=6 SEARCH RESULT tag=101 err=0 \
nentries=1 text=
replica
Mar 7 18:47:44 ldaptux slapd[22618]: conn=0 op=3 MOD dn="uid=test,ou=People,\
dc=int-evry,dc=fr"
Mar 7 18:47:44 ldaptux slapd[22618]: conn=0 op=3 RESULT tag=103 err=0 text=
|
[root@corbeau /var/lib/ldap/replica]
tail slurpd.replog
replica: ldaptux.int-evry.fr:3006
time: 1047057156
dn: uid=test,ou=People,dc=int-evry,dc=fr
changetype: modify
replace: telephoneNumber
telephoneNumber: 4408
-
replace: entryCSN
entryCSN: 2003030717:12:36Z#0x0001#0#0000
-
replace: modifiersName
modifiersName: cn=root,dc=int-evry,dc=fr
-
replace: modifyTimestamp
modifyTimestamp: 20030307171236Z
-
|
Verification
$ ldapsearch -x uid=test -h corbeau -D "uid=test,ou=people,dc=int-evry,dc=fr" \
-W telephoneNumber loginShell -LLL
Enter LDAP Password:
dn: uid=test,ou=People,dc=int-evry,dc=fr
telephoneNumber: 4408
loginShell: /usr/local/bin/bash
$ ldapsearch -x uid=test -h ldaptux -p 3006 -b ou=people,dc=int-evry,dc=fr \
-D "uid=test,ou=people,dc=int-evry,dc=fr" -W telephoneNumber loginShell -LLL
Enter LDAP Password:
dn: uid=test,ou=People,dc=int-evry,dc=fr
telephoneNumber: 4408
|
Ok :-)
12 Groups
Mise en place de
groupes afin de déléguer l'administration des données de l'annuaire.
12.1 Création des
groupes
Définition ldif de 2 groupes afin de gérer d'une part
les attributs concernants les services géneraux, d'autre part les attributs
relatifs aux Ressources Humaines.
$ cat group-servG.ldif
dn: cn=servG,ou=Groups,dc=int-evry,dc=fr
cn: administrateurs services generaux
objectclass: groupOfNames
objectclass: top
member: uid=test,ou=people,dc=int-evry,dc=fr
member: uid=riquet,ou=people,dc=int-evry,dc=fr
$ cat group-RH2.ldif
dn: cn=RH2,ou=Groups,dc=int-evry,dc=fr
cn: administrateurs RH2
objectclass: groupOfNames
objectclass: top
Member: uid=savoye,ou=People,dc=int-evry,dc=fr
Member: uid=herve,ou=People,dc=int-evry,dc=fr
$ ldapadd -x -D "cn=admin,dc=int-evry,dc=fr" -W -f ./group-servG.ldif
$ ldapadd -x -D "cn=admin,dc=int-evry,dc=fr" -W -f ./group-RH2.ldif
|
Définition dans
le fichier slapd.conf
d'ACL utilisants ces groupes. Ici on autorise
le groupe servG
à modifier le numero de téléphone, la pièce, le
code postal et l'adresse postale, de même le groupe RH
pourra
modifier le type d'employé, le département ... .
access to dn="ou=people,dc=int-evry,dc=fr"
attrs=telephoneNumber,roomNumber,postalCode,postalAddress
by group="cn=servG,ou=Groups,dc=int-evry,dc=fr" write
by dn="cn=admin,dc=int-evry,dc=fr" write
by dn="cn=replicator,ou=System,dc=int-evry,dc=fr" write
by * read
access to dn="ou=people,dc=int-evry,dc=fr"
attrs=employeeType,departmentNumber,title,cn,givenName,sn
by group="cn=RH2,ou=Groups,dc=int-evry,dc=fr" write
by dn="cn=admin,dc=int-evry,dc=fr" write
by dn="cn=replicator,ou=System,dc=int-evry,dc=fr" write
by * read
|
12.3 Exemple d'utilisation
Ici un employé des ressources humaines va
s'authentifier sur le serveur ldap (bind individuel) pour modifier le titre
d'une personne et ajouter l'attribut de département (détruit au préalable, cf
#
du fichier ldif) de cette personne.
$ cat modify-rh.ldif
dn: uid=procacci,ou=People,dc=int-evry,dc=fr
changetype: modify
replace: title
title: Ingenieur
#-
#delete: departmentNumber
-
add: departmentNumber
departmentNumber: MCI
#-
#changetype: modify
#replace: mailHost
#mailHost: bidon
$ ldapmodify -x -D "uid=herve,ou=people,dc=int-evry,dc=fr" -W -f ./modify-rh.ldif -h corbeau
Enter LDAP Password:
modifying entry "uid=procacci,ou=People,dc=int-evry,dc=fr"
$ldapsearch -x uid=procacci departmentNumber title
dn: uid=procacci,ou=People,dc=int-evry,dc=fr
title: Ingenieur
departmentNumber: MCI
|
Si on revient sur le fichier
modify-rh.ldif
ci dessus, en décommentant le remplacement du
mailHost
, attribut pour lequel le groupe RH n'a pas le droit
d'écriture (cf ACL), le serveur répond ldap_modify: Insufficient
access
et annule entierement l'opération (pas de modification du
title).
13 Trucs et astuces
Remarque sur
l'indexation à posteriori d'un annuaire.
ajouter une indexation après
avoir "populé" la base: il faut detruire les fichier d'index existant, puis
lancer slapindex
. Il est recommendé d'arreter le serveur ldap
pendant cette opération
slapd.conf
#ajout des index sur sn,mail en pres et sub
index cn,sn,mail pres,eq,sub
#ou dans l'exemple ci-dessus, suite a des pb d'index, reconstruction totale:
index objectClass,uid,uidNumber,gidNumber,IntEPersInetServ eq
index cn,mail,surname,givenname eq,subinitial
$ /etc/init.d/ldap stop
Arrêt de slapd :
[root@ur /var/lib/ldap/int]
$ ls -al
total 25128
drwxr-xr-x 2 ldap ldap 4096 aoû 1 17:07 .
drwx------ 3 ldap ldap 4096 jan 25 2002 ..
-rw-r--r-- 1 ldap ldap 1617920 aoû 1 17:56 cn.dbb
-rw-r--r-- 1 ldap ldap 827392 aoû 1 15:39 dn2id.dbb
-rw-r--r-- 1 ldap ldap 49152 aoû 1 17:56 gidNumber.dbb
-rw-r--r-- 1 ldap ldap 536576 aoû 1 17:56 givenName.dbb
-rw-r--r-- 1 ldap ldap 19894272 aoû 1 17:56 id2entry.dbb
-rw-r--r-- 1 ldap ldap 20480 aoû 1 17:56 IntEPersInetServ.dbb
-rw-r--r-- 1 ldap ldap 1306624 aoû 1 17:56 mail.dbb
-rw-r--r-- 1 ldap ldap 8192 aoû 1 15:39 nextid.dbb
-rw------- 1 ldap ldap 253952 aoû 1 17:56 objectClass.dbb
-rw-r--r-- 1 ldap ldap 876544 aoû 1 17:56 sn.dbb
-rw-r--r-- 1 ldap ldap 139264 aoû 1 17:56 uid.dbb
-rw-r--r-- 1 ldap ldap 135168 aoû 1 17:56 uidNumber.dbb
[root@ur /var/lib/ldap/int]
$ rm cn.dbb gidNumber.dbb givenName.dbb IntEPersInetServ.dbb mail.dbb \
objectClass.dbbsn.dbb uid.dbb uidNumber.dbb
[root@ur /var/lib/ldap/int]
$ ls -ltra
total 20280
drwx------ 3 ldap ldap 4096 jan 25 2002 ..
-rw-r--r-- 1 ldap ldap 8192 aoû 1 15:39 nextid.dbb
-rw-r--r-- 1 ldap ldap 827392 aoû 1 15:39 dn2id.dbb
-rw-r--r-- 1 ldap ldap 19894272 aoû 1 17:56 id2entry.dbb
drwxr-xr-x 2 ldap ldap 4096 aoû 1 18:02 .
#On garde id2entry qui est la base elle meme, ainsi que nextid et dn2id.
$ slapindex -f /etc/openldap/slapd.conf
# redonner les droits au compte ldap sur ces fichiers
[root@ur /var/lib/ldap/int]
$ chown ldap:ldap *
#et c'est reparti
$ /etc/init.d/ldap start
Démarrage de slapd: [ OK ]
|
13.2 Récuperer le champs userPassword
Via les commandes shell ; ldapsearch, avec un
bind administrateur ou l'utilisateur du compte concerné. Le champs userPassword
est retourné encodé en base 64, il faut donc le decoder .
$ldapsearch -x -D "uid=test,ou=people,dc=int-evry,dc=fr" \
-W "uid=test" -LLL userPassword
Enter LDAP Password:
dn: uid=test,ou=People,dc=int-evry,dc=fr
userPassword:: e2NyeXB0fTgybmhJTTcuUGtFODY=
ajouter de le décodage
$ldapsearch -x -D "uid=test,ou=people,dc=int-evry,dc=fr" \
-W "uid=test" -LLL userPassword | grep userPassword | \
cut --delimiter=" " -f2 | openssl base64 -d ; echo
Enter LDAP Password:
{crypt}82nhIM7.PkE86
verification de la concordance de la chaine cryptée et du password en clair
$python -c "import crypt; print crypt.crypt('motdepas','82nhIM7.PkE86')"
82nhIM7.PkE86
|
13.3 Acces au schema par ldap
Attention, suivant les ACL, il faut faire ces recherches
avec un bind administrateur -D ``cn=admin,dc=int-evry,dc=fr'' -W
.
get RootDSE without SASL
$ ldapsearch -x -H ldap://corbeau:389 -b '' -s base -LLL + -D "cn=admin,dc=int-evry,dc=fr" -W
Enter LDAP Password:
dn:
structuralObjectClass: OpenLDAProotDSE
namingContexts: dc=int-evry,dc=fr
monitorContext: cn=Monitor
supportedControl: 2.16.840.1.113730.3.4.2
supportedControl: 1.3.6.1.4.1.4203.1.10.2
supportedControl: 1.2.826.0.1.334810.2.3
supportedExtension: 1.3.6.1.4.1.4203.1.11.3
supportedExtension: 1.3.6.1.4.1.4203.1.11.1
supportedExtension: 1.3.6.1.4.1.1466.20037
supportedFeatures: 1.3.6.1.4.1.4203.1.5.1
supportedFeatures: 1.3.6.1.4.1.4203.1.5.2
supportedFeatures: 1.3.6.1.4.1.4203.1.5.3
supportedFeatures: 1.3.6.1.4.1.4203.1.5.4
supportedFeatures: 1.3.6.1.4.1.4203.1.5.5
supportedLDAPVersion: 2
supportedLDAPVersion: 3
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: CRAM-MD5
subschemaSubentry: cn=Subschema
get supported attributes from subschema entry
$ldapsearch -x -H ldap://corne:389 -b 'cn=Subschema' -s base -LLL \
objectclass=subschema attributeTypes
dn: cn=Subschema
attributeTypes: ( 2.5.18.1 NAME 'createTimestamp' EQUALITY generalizedTimeMatc
h ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.2 NAME 'modifyTimestamp' EQUALITY generalizedTimeMatc
h ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
attributeTypes: ( 2.5.18.3 NAME 'creatorsName' EQUALITY distinguishedNameMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE
directoryOperation )
...
attributeTypes: ( 1.3.6.1.4.1.7391.2.2.1.1.2.8 NAME 'vacationaddress' DESC 'Ad
resse de vacation' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
.15 )
get supported objectclasses from subschema entry
$ldapsearch -x -H ldap://corne:389 -b 'cn=Subschema' -s base -LLL \
objectclass=subschema objectClasses
objectClasses: ( 2.5.20.1 NAME 'subschema' DESC 'RFC2252: controlling subschem
a' AUXILIARY MAY ( dITStructureRules $ nameForms $ ditContentRules $ objectCl
asses $ attributeTypes $ matchingRules $ matchingRuleUse ) )
objectClasses: ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass )
...
objectClasses: ( 1.3.6.1.4.1.7391.2.2.2.1 NAME 'Vacation' DESC 'Users vacation
status information' STRUCTURAL MUST ( vacationActive $ maildeliveryoption $
uid ) MAY ( vacationInfo $ vacationStart $ vacationEnd $ vacationaddress $ ma
ilforwardingaddress ) )
|
13.4 Erreurs stupides
!
Après avoir perdu du temps sur cette erreur, j'en note la
raison.
fichier ldif contenant:
objectclass: groupOfNames
ajout par ldapadd retourne:
ldap_add: Invalid syntax
additional info: objectclass: value #0 invalid per syntax
|
Ici j'avais laissé trainer un espace
derrière groupOfNames
dans le fichier ldif, ce qui donne ce genre
d'erreur !.
Références
- [1]
- Administrator's Guide du site openldap, http://www.openldap.org/doc/admin/
- [2]
- Archives de la liste de discussion openldap, http://www.openldap.org/lists/openldap-software/
- [3]
- Pam ldap, http://www.padl.com/pam_ldap.html
- [4]
- Open-IT project, http://kodama.open-it.org/metadot/index.pl
- [5]
- Ldap au CRU, http://www.cru.fr/ldap/
- [6]
- Ldap schema repository, http://www.hklc.com/ldapschema/
Ce document a été traduit de LATEX par
HEVEA.