Ldap Orig

reprise TXT de http://www.telecom-sudparis.eu/dpt/s2ia/user/procacci/ldap/Ldap_int.html

LDAP présentation et implémentation Jehan Procaccia MCI INT-EVRY- jehan.procaccia@int-evry.fr 3 mai 2006 Table des matières

  1  Introduction
  2  l'existant
      2.1  X.500
      2.2  les annuaires en exploitation
          2.2.1  systèmes d'exploitation Windows
          2.2.2  Novell NDS
          2.2.3  NIS
          2.2.4  NIS+
          2.2.5  DNS
          2.2.6  logiciels du marché
          2.2.7  logiciels spécifiques 
  3  LDAP
      3.1  Modèles
      3.2  Réplication LDAP
      3.3  Subschema
      3.4  RootDSE
      3.5  Définitions
      3.6  Habilitations, ACL
          3.6.1  Quoi
          3.6.2  Qui
          3.6.3  Type d'accès
          3.6.4  Evaluation 
      3.7  Connexion à l'annuaire (bind)
          3.7.1  Authentification Simple 
  4  Compilation, Installation d'Openldap 2.X.X
      4.1  Contraintes de migration 2.0.X à 2.1.X et 2.2.X
      4.2  Berkeley DB
          4.2.1  L'essentiel de BDB
          4.2.2  Compilation et installation BDB
          4.2.3  Restauration de la base de donnée en cas de plantage
          4.2.4  Gestion des fichiers de Log 
      4.3  Openldap
          4.3.1  Configuration 
      4.4  Package Openldap RPM
          4.4.1  Introduction
          4.4.2  Configuration avant construction
          4.4.3  Construction
          4.4.4  Installation 
      4.5  Disponibilite des RPM
          4.5.1  Changelog 
  5  Packages 2.2.X relocatable
      5.1  Motivations
      5.2  Relocatable
      5.3  Utilisation
      5.4  Disponibilité
      5.5  Changelog 
  6  Exploitation
      6.1  Modifier le schéma
          6.1.1  Définition d'objets
          6.1.2  Exemple de schema
          6.1.3  Exemple d'entrée 
      6.2  Modifier une entrée, outils shell ldap*
      6.3  Dump et restore de la base
          6.3.1  dump
          6.3.2  Restore 
  7  Développement
      7.1  concepts
          7.1.1  code de connexion
          7.1.2  code de recherche 
  8  Authentification système Unix, connexion à un système
      8.1  Objectifs
      8.2  Authentification système traditionnelle Unix
      8.3  Authentification système NIS+
      8.4  PAM
          8.4.1  Type de modules PAM
          8.4.2  Empilage et drapeaux de contrôle
          8.4.3  pam.conf ou pam.d/service
          8.4.4  configuration PAM sous RedHat 
      8.5  NSS et Pam ldap, outils d'authentification système par LDAP 
  9  Mise en oeuvre de l'authentification système par LDAP
      9.1  Tcpd
      9.2  lancement
      9.3  configuration
      9.4  Mot de passe administrateur
      9.5  Première initialisation des données
      9.6  Migration des Données système (nis) vers ldap
          9.6.1  Users
          9.6.2  Groups
          9.6.3  L'ensemble dans un fichier ldif global 
      9.7  Authentification système
          9.7.1  Installation
          9.7.2  Exemple d'authentification 
      9.8  Automount
          9.8.1  Principes
          9.8.2  Mise en oeuvre
          9.8.3  Configuration système
          9.8.4  Exemple d'utilisation
          9.8.5  Contrôle d'accès aux stations et serveurs NFS
          9.8.6  Gestion de differents homedir 
      9.9  Contrôle d'accès host
          9.9.1  exemple d'entrée ldif
          9.9.2  Configuration du serveur
          9.9.3  ACL
          9.9.4  démonstration 
  10  Contrôle d'accés aux services
  11  Solaris 9
      11.1  modification openldap
          11.1.1  patch LDAP ROOT DSE
          11.1.2  Ajout de schemas
          11.1.3  Ajout ldif 
      11.2  Configuration du client
      11.3  non traité
      11.4  Références 
  12  Replication
      12.1  Compte de replication
      12.2  Configuration du maître
      12.3  Configuration de l'esclave
      12.4  Mise en place
      12.5  Démonstration
          12.5.1  Lancement d'une modification sur le maître.
          12.5.2  Fichiers de replication, explication 
      12.6  Rejouer une réplication rejetée
          12.6.1  Fichier de rejet
          12.6.2  Problematique du timestamp
          12.6.3  Manipulations sur le timestamp
          12.6.4  Rejouer apres modification du timestamp 
      12.7  Problème de Replication
      12.8  Configuration PAM 
  13  Réplication Partielle
      13.1  Principes
      13.2  Initialisation du replica
      13.3  Compte de replication partiel
      13.4  Extraction du subtree ou=people
      13.5  Initialisation du replica
      13.6  Configuration du master
      13.7  Configuration du replica partiel
      13.8  Demarrage et test 
  14  Groups
      14.1  Création des groupes
      14.2  ACL
      14.3  Exemple d'utilisation 
  15  Sécurité SSL TLS
      15.1  Ldaps, start TLS
          15.1.1  Certificat 
      15.2  Configuration TLS de slapd et clients
      15.3  Lancement de slapd avec TLS
      15.4  Verification, avec nmap et lsof
      15.5  Exemple d'utilisation
          15.5.1  Ecoutes réseau
          15.5.2  Echange en clair
          15.5.3  Echange chiffré, start TLS 
  16  Meta annuaire
      16.1  Principes
      16.2  Montage et tests des entités du groupe
          16.2.1  Construction des entités
          16.2.2  Lancement des entités 
      16.3  Base meta
      16.4  Configuration meta de 1er niveau
          16.4.1  Exemple de recherche sur la base meta
          16.4.2  Traces dans les log 
      16.5  Base Meta de 2eme niveau
          16.5.1  Configuration meta
          16.5.2  Recherche sur le groupe
          16.5.3  Recherche meta spécifique à une entité
          16.5.4  Log d'accès de la recherche spécifique 
      16.6  Equivalance d'attributs
          16.6.1  Modification de la maquette
          16.6.2  Modification de la configuration du serveur
          16.6.3  Equivalence d'attribut par entité 
      16.7  Avertissements
          16.7.1  ACL
          16.7.2  Performances 
  17  Migration vers Supann (NEW)
      17.1  Objectif
      17.2  Méthode
      17.3  Script d'insertion
      17.4  Execution
      17.5  Résultat 
  18  Trucs et astuces
      18.1  Index
      18.2  Récuperer le champs userPassword
      18.3  Acces au schema par ldap
      18.4  Erreurs stupides !
      18.5  Sauvegarde en ligne des données PosixAccount 

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

2.1 X.500

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 ).

2.2.3 NIS

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

2.2.4 NIS plus

Sun à réagit aux défauts de NIS par l'introduction dans solaris 2 des NIS plus. 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.

2.2.5 DNS

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. http://www.techgalaxy.net/Docs/Dev/LDAPv3%20RootDSE%20Overview.htm

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
cf RFC 2255: http://rfc.net/rfc2255.html

3.6  Habilitations, ACL
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.

3.6.1  Quoi
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.

3.6.2  Qui

*
    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.X.X
4.1  Contraintes de migration 2.0.X à 2.1.X et 2.2.X
Un certains nombre de contraintes ont été ajoutées dans les versions 2.1.x et 2.2.X pour un meilleurs respet des RFC notament. 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 . 
ACL
    Les valeurs par defaut dans les ACL ont changés entre la 2.1.X et 2.2.X , voir http://www.openldap.org/faq/data/cache/1082.html

Voir a ce sujet http://www.openldap.org/faq/data/cache/35.html

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. On pourra également utiliser des packages RPM qui compilent en statique BDB dans les binaires (c'est ce qui sera utilisé en exploitation !) ainsi openldap et ses utilitaires restent indépendant de la bibiothèque BDB système.

[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.2.3  Restauration de la base de donnée en cas de plantage
Avec un backend de type back-BDB il est possible de restaurer la base de donnée depuis un état stable (le dernier checkpoint valide) grace aux fichiers de log exp: log.0000000007 ... Procédure: arreter le service, lancer un db_recover, ici en verbose (-v) et en conservant l'environement DB (-e), redonner les droits à l'utilisateur ldap sur tous les fichiers (notamment les fichiers d'environement __db* qui passent sous root lors d'un recover en tant que root !), enfin relancer le service.

[root@openldap ~]
$ /etc/init.d/ldap stop
Stopping slapd:                                            [  OK  ]
Stopping slurpd:                                           [  OK  ]
[root@openldap ~]
$ cd /var/lib/ldap/int
[root@openldap /var/lib/ldap/int]
$ /usr/sbin/slapd_db_recover -e -v
db_recover: Finding last valid log LSN: file: 16 offset 8839464
db_recover: Recovery complete at Mon Mar  1 09:39:23 2004
db_recover: Maximum transaction id 80000000 Recovery checkpoint [16][8839416]
[root@openldap /var/lib/ldap/int]
$ chown ldap:ldap *
[root@openldap /var/lib/ldap/int]
$ /etc/init.d/ldap start
Starting slapd:                                            [  OK  ]
Starting slurpd:                                           [  OK  ]


4.2.4  Gestion des fichiers de Log
Ici on utilise les utilitaires db (http://www.sleepycat.com/docs/utility/) notament db_archive fournis par les packages RPM RedHat (pour ma part:http://www.int-evry.fr/mci/user/procacci/SRPMS/), on retrouve en effet les binaires dans /usr/sbin/slapd_db* car ils sont compilées en statique avec la version BDB qui va bien !

$ /usr/sbin/slapd_db_archive -V
Sleepycat Software: Berkeley DB 4.2.52: (December  3, 2003)
$ ldd /usr/sbin/slapd_db_archive
        libpthread.so.0 => /lib/tls/libpthread.so.0 (0x40028000)
        libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)


Lister les fichiers de log

[root@openldap /var/lib/ldap/int]
$ /usr/sbin/slapd_db_archive -l
log.0000000001
log.0000000002
log.0000000003
log.0000000004
log.0000000005
log.0000000006
log.0000000007
log.0000000008
log.0000000009
log.0000000010
log.0000000011
log.0000000012
log.0000000013
log.0000000014
log.0000000015
log.0000000016


Lister les fichiers de log à archiver (ou supprimer ...)

$ /usr/sbin/slapd_db_archive -a
/var/lib/ldap/int/log.0000000001
/var/lib/ldap/int/log.0000000002
/var/lib/ldap/int/log.0000000003
/var/lib/ldap/int/log.0000000004
/var/lib/ldap/int/log.0000000005
/var/lib/ldap/int/log.0000000006
/var/lib/ldap/int/log.0000000007
/var/lib/ldap/int/log.0000000008
/var/lib/ldap/int/log.0000000009
/var/lib/ldap/int/log.0000000010
/var/lib/ldap/int/log.0000000011
/var/lib/ldap/int/log.0000000012
/var/lib/ldap/int/log.0000000013
/var/lib/ldap/int/log.0000000014
/var/lib/ldap/int/log.0000000015


Lister les fichiers de database (bdb) qui doivent être archivés en cas de catastrophic recovery (db_recover -c)

$ /usr/sbin/slapd_db_archive -s
IntEPersInetServ.bdb
cn.bdb
dn2id.bdb
gidNumber.bdb
givenName.bdb
id2entry.bdb
mail.bdb
objectClass.bdb
sn.bdb
uid.bdb
uidNumber.bdb


Supprimer les fichiers de log anciens (attention cela peut empecher de procéder à une catastrophic recovery !) Exemple:

$ /usr/sbin/slapd_db_archive -l
log.0000000005
log.0000000006
log.0000000007

$ /usr/sbin/slapd_db_archive -d

$ /usr/sbin/slapd_db_archive -l
log.0000000007

Ici le log 7 est encore ``actif'' .

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
4.4.1  Introduction
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és 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/
4.4.2  Configuration avant construction
A la base nous sommes partis d'un package source 2.1.3 RedHat, en y incluant régulièrement les différentes versions d'openldap, dernièrement le tar.gz 2.1.20 d'openldap (l'exemple ci-dessous etant sur la 2.1.15 !) , 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 \
        $@ \$@


4.4.3  Construction
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


4.4.4  Installation
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/
4.5.1  Changelog
Ci dessus un extrait du changelog qui indique les modifications realisées dans chaque version de package, il est extrait le fichier openldap-X.X.X.spec que l'on trouve dans les packages source .

%changelog
* Wed May 28 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.20-1
- upgraded to 2.1.20
                                                                                
* Fri May 02 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.17-2
- adapted spec file for RedHat 9:
- 1) resolved pb with kerberos/ssl headers not found
- CFLAGS/LDFLAGS in the clients package
- 2) resolved "error: Installed (but unpackaged) file(s) found:"
- generated by feature of RPM >= 4.1: "/usr/lib/rpm/check-files"
- added missing files in %files section in consequence
* Mon Apr 07 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.17-1
- upgraded to 2.1.17
- remove part of openldap-2.1.3-config.patch regarding default database\
 (bdb vs ldmb) in slapd.conf (see "@@ -43,15 +59,26 @@" in previous patch)
                                                                                
* Tue Mar 18 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.16-1
- upgraded to 2.1.16
                                                                                
* Wed Mar 12 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.15-1
- upgraded to 2.1.15
                                                                                
* Mon Mar 03 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.14-2
- upgraded to 2.1.14
- removed patch for schema-check (already patched in 2.1.14 !)
- removed make test openldap build to accelerate rpmbuild !

* Thu Feb 28 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.13-3
- from Francis Swasey <Frank.Swasey@uvm.edu> 2.1.12-uvm2.8.0:
- sleepycat bdb 4.1.25 plus locking patch
- add patch for schema-check
- add patch for slapd lock-release in group acl processing
- add patch for slapcat a subtree
- add make test to openldap build
                                                                                
* Tue Feb 25 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.13-1
- replace openldap source (tgz) from 2.1.12 to 2.1.13
                                                                                
* Mon Jan 20 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.12-1
- replace openldap source (tgz) from 2.1.11 to 2.1.12
                                                                                
* Wed Jan 08 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.11-2
- compiled with back-monitor not beeing a dynamic module.
- error is with:modulepath /usr/sbin/openldap & moduleload \
back_monitor.la in slapd.conf
slapd[1992]: lt_dlopen failed: (back_monitor.la) back_monitor.a: \
cannot open shared object file: No such file or directory
slapd[1992]: /etc/openldap/slapd.conf: line 33: \
failed to load or initialize module back_monitor.la ??
* Tue Jan 07 2003 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.11-1
- replace openldap source (tgz) from 2.1.9 to 2.1.11
- replace BDB from 4.1.24-NC to 4.1.25-NC
                                                                                
* Wed Dec 11 2002 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.9-3
- added backends, ldap meta shell password without  modules
                                                                                
* Sat Dec 07 2002 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.9-2
- added backends, ldap meta shell password with module=dynamic
                                                                                
* Thu Dec 04 2002 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.9-1
- replace openldap source (tgz) from 2.1.8 to 2.1.9
                                                                                
* Mon Nov 25 2002 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.8-2
- removed offending patch in regards to RFCs on cosine.schema

* Thu Nov 21 2002 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.8-1
- changed kerberosobject.schema to include krbName attr from old core.schema
- changed kerberosobject.schema to AUXILIARY
- patched cosine.schema, account objectclass from STRUCTURAL to AUXILIARY
- Includes --enabled-modules and back-monitor as a dynamic module(didn't test!)
- Includes BDB 4.1.24-NC                                                                                
* Fri Aug  2 2002 Nalin Dahyabhai <nalin@redhat.com> 2.1.3-4
- enable the ldbm/berkeley backend as well
- use an ldbm/berkeley database as the default (fyi bdb's still available)
- don't install slapadd-gdbm


5  Packages 2.2.X relocatable
5.1  Motivations
Depuis la sortie d'openldap 2.2.X, j'ai rencontrer le problème du changement de version majeur des librairies liblber.so.2 et libldap.so.2, ce qui crée un sérieux problème de dependance sur un système à base de RPM; voir à ce sujet le thread de discussion sur la liste openldap (http://www.openldap.org/lists/openldap-software/) ayant pour sujet ``LDAP library version number''.

5.2  Relocatable
Qu'entend t-on par ``relocatable'' ? . cela signifie que le package va pourvoir s'installer dans son entier, dans une sous-arborescence, un peu à la façon d'un tar.gz. Cependant ici on conserve les avantages des packages RPM (installation, desintallation, recompilation, informations etc ...) tout en évitant les problèmes de dépendance. En effet openldap depend d'autres packages (BDB, sasl, etc ...) système sensibles à un upgrade sauvage, et aussi beaucoup d'autres packages dependent d'openldap. Ainsi on conserve les packages openldap qui vont bien avec la distibution, et on peux disposer de la dernière version ``uptodate'' d'openldap afin de profiter des dernieres fonctionnalitées, corrections de bug à des fins de test ou de production !.

5.3  Utilisation
Les packages que j'ai compilé s'installent dans leur intégralité par défaut dans /usr/local. C'est ce chemin qui est modifiable. Exemple ici je vais declarer un prefix sur la commande d'installation.

[root@corbeau /usr/src/redhat/RPMS/i386]
 rpm -ivh --prefix=/usr/local/openldap-2.2.15-1 openldap-*2.2.15-1*.rpm


Ainsi ce package openldap ira dans /usr/local/openldap-2.2.15-1 Cela implique bien entendu un certain nombre d'ajustement sur le fichier configuration slapd.conf et le fichier de demarrage init.d/ldap ainsi que le chargeur de librairie ldconfig; /etc/ld.so.conf . Tout ceci est détaillé dans ce README http://www.int-evry.fr/mci/user/procacci/SRPMS/README-openldap-2.2.15-jehan.txt que je conseil fortement de lire avant d'utiliser ou de recompiler ce package relocatable.

5.4  Disponibilité
Source; http://www.int-evry.fr/mci/user/procacci/SRPMS/
Binaires pour fedora core 2: http://www.int-evry.fr/mci/user/procacci/SRPMS/FC2/

5.5  Changelog
Voici les modifications que j'ai apporté par rapport au package Redhat 2.1.29-1

%changelog
* Thu Aug 05 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.15-2
- added openldap-2.2.15-configure.patch to correct pb of configure
  "checking for Berkeley DB version match" I blindly added
  export LD_LIBRARY_PATH=../db-4.2.52/build-rpm/.libs/
  to use embeded BDB package for ./conftest test !
                                                                                
* Thu Aug 05 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.15-1
- updated to openldap 2.2.15
- effectively include .rpmmacros in SOURCES (forgot in 2.2..14-2)
                                                                                
* Thu Jul 08 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.14-2
- link slapd utilities (slapadd slapindex etc ...) to slapd (done since 2.2.7 !)- added README-jehan.txt and .rpmmacros in SOURCES directory
                                                                                
* Thu Jul 01 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.14-1
- upgraded to 2.2.14
- adjusted some doc files for relocatable
- adapted openldap-2.1.17-syslog.patch to reflect changes in servers/slapd/main.c
* Wed Jun 09 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.12-1
- relocatable package from /usr/local to be system independant
- upgraded to openldap 2.2.12
                                                                                
* Mon Apr 26 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.2.11-1
- upgraded to openldap 2.2.11
                                                                                
* Thu Apr 15 2004 Jehan Procaccia <jehan.procaccia@int-evry.fr> 2.1.29-2
- removed openldap 2.0 and DB 4.0 compatibilities
                                                                                
* Wed Apr 14 2004 Nalin Dahyabhai <nalin@redhat.com> 2.1.29-1
- rebuild
                                                                                
* Tue Apr  6 2004 Nalin Dahyabhai <nalin@redhat.com> 2.1.29-0
- update to 2.1.29 (stable 20040329)

6  Exploitation
6.1  Modifier le schéma
Il est possible de personnaliser le schéma par ajout d'attribut/objectclass.

6.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 DESCription.
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.

6.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
 )


6.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


6.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


6.3  Dump et restore de la base
6.3.1  dump
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
...


6.3.2  Restore
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 .

7  Développement
API Ldap en C cf draft-ietf-ldap-c-api-01.txt

7.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

7.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 }

7.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 !


8  Authentification système Unix, connexion à un système
8.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.

8.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.

8.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.

8.4  PAM
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.

8.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. 

8.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. 

8.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


8.4.4  configuration PAM sous RedHat
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


8.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.

9  Mise en oeuvre de l'authentification système par LDAP
9.1  Tcpd
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 ".

9.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.

9.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


9.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


9.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 


9.6  Migration des Données système (nis) vers ldap
9.6.1  Users
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"
...


9.6.2  Groups
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"

....


9.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:
....


9.7  Authentification système
9.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


9.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.
9.8  Automount
9.8.1  Principes
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.

9.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
#hence /citi is the root directory of homes served by this automount
#this entry points to 'ou=auto.citi,ou=automount,dc=int-evry,dc=fr'
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.
#this is the ou pointed just above by: 'automountInformation: ldap:ou=auto.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.
# Here we create a subautomounter for every [sub]directory on the NFS server
# this 'cn=citi1' is not necesarily related to the real [sub]directory name
# on the nfs server (here it is /home on nfs server)
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.
# it is actually the ou just pointed above: 'ldap:ou=auto.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
# homedir for users here is: /citi/citi1/login
# a equivalent to 'mount nfsserver:/home/login /citi/citi1/login' will
# be done bye autofs, 
# neither /citi nor /citi/citi1 needs to preexist on the client station !
# autofs is in charge of creating them .
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/&


9.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


9.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"


9.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*


9.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


9.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.

9.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


9.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.

9.9.3  ACL
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


9.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))"


10  Contrôle d'accés aux services
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 ....).

11  Solaris 9
L'objectif de ce chapitre est de montrer comment authentifier un client solaris 9 sur un serveur openldap.

11.1  modification openldap
Pour cela il faut apporter quelques modifications sur le serveur openldap.
11.1.1  patch LDAP ROOT DSE
Le client solaris doit avoir un acces particulier (a preciser ?) au root_dse, d'ou la necessité d'appliquer ce patch a la compilation d'openldap

$ cat /usr/src/redhat/SOURCES/openldap-2.1.22-solaris.patch
--- servers/slapd/result.c      2003-02-28 18:07:14.000000000 +0100
+++ servers/slapd/result.c      2003-07-16 15:30:01.000000000 +0200
@@ -885,7 +885,9 @@
                if ( attrs == NULL ) {
                        /* all attrs request, skip operational attributes */
                        if( is_at_operational( desc->ad_type ) ) {
-                               continue;
+                               if (strcasecmp( e->e_dn, LDAP_ROOT_DSE )) {
+                                       continue;
+                               }
                        }
  
                } else {
@@ -1080,7 +1082,9 @@
                if ( attrs == NULL ) {
                        /* all attrs request, skip operational attributes */
                        if( is_at_operational( desc->ad_type ) ) {
-                               continue;
+                               if (strcasecmp( e->e_dn, LDAP_ROOT_DSE )) {
+                                       continue;
+                               }
                        }
  
                } else {

Un package source rpm est disponible sur http://www.int-evry.fr/mci/user/procacci/SRPMS/openldap-2.1.22-2.src.rpm qui comprend l'inclusion de ce patch, cf %patch8 -p0 -b .solaris dans le fichier openldap.spec

11.1.2  Ajout de schemas
Inclure DUAconfig.schema : http://sapiens.wustl.edu/~sysmain/info/openldap/schemas/DUAConfig.schema et solaris.schema : http://www.int-evry.fr/mci/user/procacci/ldap/solaris.schema, une autre version mais qui ne contient pas nisDomain entre autre !?: http://sapiens.wustl.edu/~sysmain/info/openldap/schemas/solaris.schema

$ grep solaris /etc/openldap/slapd.conf
include         /etc/openldap/schema/solaris/solaris.schema
include         /etc/openldap/schema/solaris/DUAConfig.schema

11.1.3  Ajout ldif
Une fois les schemas ci-dessus inclus, on peut ajouter les objects ldap attenduspar les commandes natives ldap de solaris9.

On va créer un profile, de façon à initialiser le service d'authentification ldap sur solaris avec la commande ldapclient init. Pour cela on peut demander à solaris de générer le fichier ldif de ce profile de configuration ldap.

[root@solaris9ldap /]
$ ldapclient genprofile -a profilename=profile-mci -a defaultsearchbase=dc=int-evry,dc=fr \
-a authenticationmethod=simple -a credentiallevel=proxy 157.159.55.199

dn: cn=mciprofile,ou=profile,dc=int-evry,dc=fr
ObjectClass: top
ObjectClass: DUAConfigProfile
defaultServerList: 157.159.55.199
defaultSearchBase: dc=int-evry,dc=fr
authenticationMethod: simple
cn: profile-mci
credentialLevel: proxy


ou bien on crée directement le fichier ldif avec toutes les options qui nous interessent

$ cat solaris-base-profile.ldif
dn: ou=Profile,dc=int-evry,dc=fr
ou: Profile
objectClass: top
objectClass: organizationalUnit

dn: cn=profile-mci,ou=profile,dc=int-evry,dc=fr
ObjectClass: top
ObjectClass: DUAConfigProfile
defaultServerList: 157.159.55.199
defaultSearchBase: dc=int-evry,dc=fr
authenticationMethod: simple
cn: profile-mci
credentialLevel: proxy
followReferrals: true
serviceSearchDescriptor: auto_master:nismapname=auto_master,dc=int-evry,dc=fr
objectclassMap: automount:automountMap=nisMap
objectclassMap: automount:automount=nisObject
attributeMap: automount:automountMapName=nisMapName
attributeMap: automount:automountInformation=nismapentry
attributeMap: automount:automountKey=cn


ajout d'un proxy-agent, qui sert de binddn plutot que de faire un accés anonyme

$ cat solaris-proxyagent.ldif
dn: cn=proxyagent,ou=profile,dc=int-evry,dc=fr
cn: proxyagent
sn: proxyagent
objectClass: top
objectClass: person
userPassword:: secretsecretsecretsecretsecret=


verification du bon fonctionnement du proxy-agent

[root@solaris9ldap /]
$ ldapsearch -b "dc=int-evry,dc=fr" -D "cn=proxyagent,ou=profile,dc=int-evry,dc=fr" -h 157.159.55.199 -p 389 cn=proxyagent
Bind Password:
cn=proxyagent,ou=profile,dc=int-evry,dc=fr
cn=proxyagent
sn=proxyagent
objectClass=top
objectClass=person
userPassword={CRYPT}secretsecret


Enfin, ajout de l'attribut nisdomain à la base de l'annuaire, cela est necéssaire pour la commande ldapclient init

$ cat solaris-add-nisdomain.ldif
dn: dc=int-evry,dc=fr
changetype: modify
add: objectclass
objectclass: nisDomainObject
-
add: nisdomain
nisdomain: int-evry.fr

$ ldapsearch -x objectclass=nisDomainObject -h localhost -LLL
dn: dc=int-evry,dc=fr
dc: int-evry
objectClass: top
objectClass: domain
objectClass: domainRelatedObject
objectClass: nisDomainObject
associatedDomain: int-evry.fr
nisDomain: int-evry.fr


11.2  Configuration du client
Maintenant que tout est préparé coté serveur, il suffit de lancer la commande suivante sur les clients solaris 9

$ ldapclient init -a profileName=profile-mci -a domainName=int-evry.fr -a proxyDn=cn=proxyagent,ou=profile,dc=int-evry,dc=fr 157.159.55.199
credentialLevel requires proxyPassword
Proxy Bind Password:
System successfully configured

cela récupere le profile depuis le serveur et configure en conséquence les fichiers systèmes

/etc/nsswitch.conf
/etc/pam.conf
/var/ldap/ldap_client_file
/var/ldap/ldap_client_cred
lance /usr/lib/ldap/ldap_cachemgr
...


verification

$ ssh procacci@solaris9ldap
procacci@solaris9ldap's password:
Last login: Thu Jul 17 13:31:58 2003 from corbeau.int-evr
Sun Microsystems Inc.   SunOS 5.9       Generic May 2002
solaris9ldap:/mci/mci/procacci>


11.3  non traité
Ici il ne s'agissait que d'une experience, elle n'est pas vraiment mise en exploitation, le montage nfs automount se fait sur des fichiers auto_master/auto_home à plat sur la station, la configuration TLS n'est pas implémentée, l'optimisation des ACL sur le serveur non plus. Pour ces points je renvoie aux références ci-dessous.

11.4  Références
http://docs.sun.com/db/doc/806-4077/6jd6blbeq?a=view http://www.ypass.net/solaris8/openldap/ http://www.cse.sc.edu/~jqu/work/systemadmin/LDAP.html http://sapiens.wustl.edu/~sysmain/info/openldap/

12  Replication
12.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"


12.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


12.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


12.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  ]


12.5  Démonstration
12.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=


12.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


12.6  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 !.

12.6.1  Fichier de rejet

[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.


12.6.2  Problematique du timestamp
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.


12.6.3  Manipulations sur le timestamp
Le fichier slurpd.status maintien la date (en secondes depuis 1900 !) à laquelle à eu lieu la derniere replication pour le replica en question.

[root@openldap /var/lib/ldap/replica]
$ cat slurpd.status
ldap1.int-evry.fr:0:1099929945:0
ldap2.int-evry.fr:0:1099929945:0


Il est parfois interesent de convertir cette date en seconde en une date plus lisible ;

$ perl -e '($s,$m,$h,$dm,$mt,$y,$wday,$yday,$isdst) = localtime(1099929945);printf("%02d:%02d:%02d-%02d/%02d/%04d\n",$h, $m, $s, ,$dm , $mt+1, $y+1900);'
17:05:45-08/11/2004


Inversement, obtenir la date du momment en seconde depuis 1900 :

$ perl -e '$tm=time; print "$tm\n";'
1099931104


12.6.4  Rejouer apres modification du timestamp
Pour rejouer un fichier de rejet, il faudra donc soit retirer ou modifier (antidater) l'entrée timestamp du fichier slurpd.status soit modifier les entrées timestamp du fichier de rejet afin quelles aient une date courante.
Exemple ici où l'on rejoue plus de 7500 modifications (2 par entrées ) apres antidater le slurpd.status et apres avoir arreter le slurpd daemon lancé par /etc/init/ldap ! afin d'eviter qu'il y ait une autre modification en parallele.

Replica ldap1.int-evry.fr:0, skip repl record for uid=test,ou=People,dc=int-evry,dc=fr (old)
 
[root@openldap /var/lib/ldap/replica]
$ /usr/sbin/slurpd -r /var/lib/ldap/replica/ldap1.int-evry.fr:0.rej -o -d 512
@(#) $OpenLDAP: slurpd 2.1.29 (Apr 14 2004 14:57:16) $
        root@tweety.devel.redhat.com:/usr/src/build/387567-i386/BUILD/openldap-2.1.29/build-servers/servers/slurpd
  
Processing in one-shot mode:
13583 total replication records in file,
13583 replication records to process.
request 1 done
request 2 done
...


12.7  Problème de Replication
Attention à la propiété du répertoire de réplication, /var/lib/ldap/replica sur ma config Fedora Core 2 !. Par défaut ce répertoire appartient a root, hors slapd doit écrire son replogfile à cet endroit.

[root@openldap /var/lib/ldap/replica]
$ ls -al
total 16
drwxr-xr-x  2 ldap root 4096 Aug 11 14:23 .
drwx------  5 ldap ldap 4096 Aug 11 14:08 ..
-rw-r--r--  1 ldap ldap    0 Aug 11 14:23 replogfile
-rw-r--r--  1 ldap ldap    0 Aug 11 14:23 replogfile.lock
-rw-r--r--  1 root root  505 Aug 11 14:23 slurpd.replog
-rw-r--r--  1 root root    0 Aug 11 14:23 slurpd.replog.lock
-rw-r--r--  1 root root  160 Aug 11 14:23 slurpd.status
-rw-r--r--  1 root root    0 Aug 11 14:23 slurpd.status.lock


12.8  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 probleme 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


13  Réplication Partielle
13.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 !).

13.2  Initialisation du replica
13.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


13.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


13.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 *


13.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


13.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


13.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 :-)

14  Groups
Mise en place de groupes afin de déléguer l'administration des données de l'annuaire.

14.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


14.2  ACL
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


14.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).

15  Sécurité SSL TLS
Je recommande de suivre http://www.openldap.org/faq/data/cache/185.html ce qui suis est une suite d'étapes pas à pas pour information/aide .

15.1  Ldaps, start TLS
Mettre le serveur openldap en écoute sur un port sécurisé; ldaps port 636 ou start TLS qui utilise a priori le port 389 (!?).

15.1.1  Certificat
Création d'un certificat 'selfsigned'. Ou bien signer avec une autorité de certification préexistante; voir: http://www.int-evry.fr/s2ia/user/procacci/Doc/openssl.html#htoc17

$ mkdir /var/myca
$ cd /var/myca/
[root@corbeau /var/myca]
$ /usr/share/ssl/misc/CA -newca
CA certificate filename (or enter to create)
 
Making CA certificate ...
Generating a 1024 bit RSA private key
...........................................................++++++
...................................................++++++
writing new private key to './demoCA/private/./cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
phrase is too short, needs to be at least 4 chars
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:FR
State or Province Name (full name) [Berkshire]:Essonne
Locality Name (eg, city) [Newbury]:Evry
Organization Name (eg, company) [My Company Ltd]:INT
Organizational Unit Name (eg, section) []:MCI
Common Name (eg, your name or your server's hostname) []:corbeau.int-evry.fr
Email Address []:root@corbeau.int-evry.fr
[root@corbeau /var/myca]
$ ls demoCA/
cacert.pem  certs  crl  index.txt  newcerts  private  serial


Création d'une requête de certificat et d'une clé privée pour le serveur

[root@corbeau /var/myca]
$ openssl req -new -nodes -keyout newreq.pem -out newreq.pem
Generating a 1024 bit RSA private key
...............++++++
.............................++++++
writing new private key to 'newreq.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:FR
State or Province Name (full name) [Berkshire]:Essonne
Locality Name (eg, city) [Newbury]:Evry
Organization Name (eg, company) [My Company Ltd]:INT-Evry
Organizational Unit Name (eg, section) []:MCI
Common Name (eg, your name or your server's hostname) []:corbeau.int-evry.fr
Email Address []:jehan@corbeau.int-evry.fr
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@corbeau /var/myca]
$ ls
demoCA  newreq.pem


Utilisation du CA pour signer le cert request

[root@corbeau /var/myca]
$ /usr/share/ssl/misc/CA -sign
Using configuration from /usr/share/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: May 28 22:01:04 2003 GMT
            Not After : May 27 22:01:04 2004 GMT
        Subject:
            countryName               = FR
            stateOrProvinceName       = Essonne
            localityName              = Evry
            organizationName          = INT-Evry
            organizationalUnitName    = MCI
            commonName                = corbeau.int-evry.fr
            emailAddress              = jehan@corbeau.int-evry.fr
        X509v3 extensions:
            X509v3 Basic Constraints:
            CA:FALSE
            Netscape Comment:
            OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
            97:D2:DF:35:37:A1:45:20:C3:5C:DF:07:08:F3:B5:0A:2A:F6:0B:D4
            X509v3 Authority Key Identifier:
            keyid:6A:EA:69:1F:6C:23:07:02:05:42:D4:53:BB:60:F5:53:0A:78:71:DF
            DirName:/C=FR/ST=Essonne/L=Evry/O=INT/OU=MCI/CN=corbeau.int-evry.fr/emailAddress=root@corbeau.int-evry.fr
            serial:00
 
Certificate is to be certified until May 27 22:01:04 2004 GMT (365 days)
Sign the certificate? [y/n]:y
 
 
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=FR, ST=Essonne, L=Evry, O=INT, OU=MCI, CN=corbeau.int-evry.fr/emailAddress=root@corbeau.int-evry.fr
        Validity
            Not Before: May 28 22:01:04 2003 GMT
            Not After : May 27 22:01:04 2004 GMT
        Subject: C=FR, ST=Essonne, L=Evry, O=INT-Evry, OU=MCI, CN=corbeau.int-evry.fr/emailAddress=jehan@corbeau.int-evry.fr
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:c9:2d:b0:f8:ea:15:f4:4e:54:c0:f8:62:9b:8c:
                    4d:37:1c:1f:c4:c2:1a:b8:d2:a6:7d:b1:24:e6:d5:
                    60:77:05:82:3f:9e:3c:39:e0:6c:84:ae:19:db:33:
                    34:62:43:37:60:68:4a:77:39:ad:c1:00:47:5b:69:
                    63:8d:cb:10:c6:4b:a5:6a:eb:f9:c0:4b:3c:fc:2d:
                    55:95:d4:75:5c:65:34:a9:00:5c:75:77:14:2d:bf:
                    19:d0:87:bb:16:83:fe:c9:13:a6:14:5b:fd:7a:ee:
                    61:b0:f9:53:77:00:64:ff:2e:1f:11:d4:48:42:e9:
                    7c:5e:5a:47:79:58:22:50:e3
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints:
            CA:FALSE
            Netscape Comment:
            OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
            97:D2:DF:35:37:A1:45:20:C3:5C:DF:07:08:F3:B5:0A:2A:F6:0B:D4
            X509v3 Authority Key Identifier:
            keyid:6A:EA:69:1F:6C:23:07:02:05:42:D4:53:BB:60:F5:53:0A:78:71:DF
            DirName:/C=FR/ST=Essonne/L=Evry/O=INT/OU=MCI/CN=corbeau.int-evry.fr/emailAddress=root@corbeau.int-evry.fr
            serial:00
 
    Signature Algorithm: md5WithRSAEncryption
        44:f6:95:f1:38:eb:61:3e:df:92:e4:2d:af:9c:a4:57:45:a9:
        b1:24:6b:c4:e4:bf:ff:b6:41:c4:f3:b8:df:26:07:d3:c7:bc:
        27:19:ca:74:7d:0b:22:c0:ef:05:cd:29:9c:ab:2d:13:b6:3d:
        4f:11:4b:01:66:b7:c8:89:8d:0e:fe:ec:7a:ab:64:9c:af:8b:
        c9:25:30:ca:63:23:64:d6:4b:b3:e0:a2:ee:ba:7c:bd:0b:a3:
        56:5b:43:24:05:51:01:a9:b2:08:09:ad:6f:89:fe:95:f4:7c:
        6c:30:12:18:6e:b7:39:bc:f0:3f:f4:9a:79:ec:de:8f:ee:26:
        a7:bc
-----BEGIN CERTIFICATE-----
MIIDvzCCAyigAwIBAgIBATANBgkqhkiG9w0BAQQFADCBkTELMAkGA1UEBhMCRlIx
EDAOBgNVBAgTB0Vzc29ubmUxDTALBgNVBAcTBEV2cnkxDDAKBgNVBAoTA0lOVDEM
MAoGA1UECxMDTUNJMRwwGgYDVQQDExNjb3JiZWF1LmludC1ldnJ5LmZyMScwJQYJ
KoZIhvcNAQkBFhhyb290QGNvcmJlYXUuaW50LWV2cnkuZnIwHhcNMDMwNTI4MjIw
MTA0WhcNMDQwNTI3MjIwMTA0WjCBlzELMAkGA1UEBhMCRlIxEDAOBgNVBAgTB0Vz
c29ubmUxDTALBgNVBAcTBEV2cnkxETAPBgNVBAoTCElOVC1FdnJ5MQwwCgYDVQQL
EwNNQ0kxHDAaBgNVBAMTE2NvcmJlYXUuaW50LWV2cnkuZnIxKDAmBgkqhkiG9w0B
CQEWGWplaGFuQGNvcmJlYXUuaW50LWV2cnkuZnIwgZ8wDQYJKoZIhvcNAQEBBQAD
gY0AMIGJAoGBAMktsPjqFfROVMD4YpuMTTccH8TCGrjSpn2xJObVYHcFgj+ePDng
bISuGdszNGJDN2BoSnc5rcEAR1tpY43LEMZLpWrr+cBLPPwtVZXUdVxlNKkAXHV3
FC2/GdCHuxaD/skTphRb/XruYbD5U3cAZP8uHxHUSELpfF5aR3lYIlDjAgMBAAGj
ggEdMIIBGTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVy
YXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUl9LfNTehRSDDXN8HCPO1Cir2C9Qw
gb4GA1UdIwSBtjCBs4AUauppH2wjBwIFQtRTu2D1Uwp4cd+hgZekgZQwgZExCzAJ
BgNVBAYTAkZSMRAwDgYDVQQIEwdFc3Nvbm5lMQ0wCwYDVQQHEwRFdnJ5MQwwCgYD
VQQKEwNJTlQxDDAKBgNVBAsTA01DSTEcMBoGA1UEAxMTY29yYmVhdS5pbnQtZXZy
eS5mcjEnMCUGCSqGSIb3DQEJARYYcm9vdEBjb3JiZWF1LmludC1ldnJ5LmZyggEA
MA0GCSqGSIb3DQEBBAUAA4GBAET2lfE462E+35LkLa+cpFdFqbEka8Tkv/+2QcTz
uN8mB9PHvCcZynR9CyLA7wXNKZyrLRO2PU8RSwFmt8iJjQ7+7HqrZJyvi8klMMpj
I2TWS7Pgou66fL0Lo1ZbQyQFUQGpsggJrW+J/pX0fGwwEhhutzm88D/0mnns3o/u
Jqe8
-----END CERTIFICATE-----
Signed certificate is in newcert.pem
[root@corbeau /var/myca]
$ ls
demoCA  newcert.pem  newreq.pem


15.2  Configuration TLS de slapd et clients
Copie des fichiers dans l'arborescence serveur openldap et prise en compte des modes d'acces (slapd tourne sous le user ldap !)

[root@corbeau /var/myca]
$ cp demoCA/cacert.pem /etc/openldap/cacert.pem
$ cp newcert.pem /etc/openldap/servercrt.pem
$ cp newreq.pem /etc/openldap/serverkey.pem
$ chmod 600 /etc/openldap/serverkey.pem
$ chown ldap:ldap /etc/openldap/serverkey.pem


Edition du slapd.conf

$ grep TLS /etc/openldap/slapd.conf
TLSCACertificateFile /etc/openldap/cacert.pem
TLSCertificateFile /etc/openldap/servercrt.pem
TLSCertificateKeyFile /etc/openldap/serverkey.pem


copie du certificat de la CA (certificat d'autorité qui signe ) dans /etc pour les outils clients et configuration en conséquence des outils clients

[root@corbeau /var/myca]
$ cp demoCA/cacert.pem /etc
$ grep TLS /etc/openldap/ldap.conf
TLS_CACERT /etc/cacert.pem


15.3  Lancement de slapd avec TLS

$ /etc/init.d/ldap restart
Stopping slapd:                                            [  OK  ]
Starting slapd:                                            [  OK  ]
## cela lance:
## slapd -f /etc/openldap/slapd.conf -u ldap -h "ldap:/// ldaps:///"


15.4  Verification, avec nmap et lsof


$ nmap -p 636 calaz.int-evry.fr
 
Starting nmap 3.75 ( http://www.insecure.org/nmap/ ) at 2005-01-26 20:07 CET
Interesting ports on calaz.int-evry.fr (157.159.50.197):
PORT    STATE SERVICE
636/tcp open  ldapssl

$ lsof -i tcp:636,389
COMMAND  PID USER   FD   TYPE   DEVICE SIZE NODE NAME
slapd   9259 ldap    6u  IPv6 11523812       TCP *:ldap (LISTEN)
slapd   9259 ldap    7u  IPv4 11523813       TCP *:ldap (LISTEN)
slapd   9259 ldap    8u  IPv6 11523816       TCP *:ldaps (LISTEN)
slapd   9259 ldap    9u  IPv4 11523817       TCP *:ldaps (LISTEN)


15.5  Exemple d'utilisation
Utiliser l'option ``-ZZ'' de ldapsearch pour forcer le start TLS.

$ ldapsearch -x uid=test -H ldap://corbeau.int-evry.fr/ -ZZ


15.5.1  Ecoutes réseau
Verifions que sans et avec le start TLS on ne voit pas passer la meme chose sur le réseau, respctivement échange en clair puis chiffré.

15.5.2  Echange en clair

$ ldapsearch -x uid=test -H ldap://calaz.int-evry.fr -D "cn=admin,dc=int-evry,dc=fr" -W cn -LLL
Enter LDAP Password:

#en parrallele on capture avec ethereal:

$ tethereal -i lo port 389
Capturing on lo
  0.000000 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [SYN] Seq=0 Ack=0 Win=32767 Len=0 MSS=16396 TSV=1415942728 TSER=0 WS=2
  0.021630 157.159.50.197 -> 157.159.50.197 TCP ldap > 50545 [SYN, ACK] Seq=0 Ack=1 Win=32767 Len=0 MSS=16396 TSV=1415942728 TSER=1415942728 WS=2
  0.021960 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [ACK] Seq=1 Ack=1 Win=32768 Len=0 TSV=1415942728 TSER=1415942728
  0.020384 157.159.50.197 -> 157.159.50.197 LDAP MsgId=1 Bind Request, DN=cn=admin,dc=int-evry,dc=fr
  0.020419 157.159.50.197 -> 157.159.50.197 TCP ldap > 50545 [ACK] Seq=1 Ack=48 Win=32768 Len=0 TSV=1415942749 TSER=1415942749
  0.084645 157.159.50.197 -> 157.159.50.197 LDAP MsgId=1 Bind Result
  0.084682 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [ACK] Seq=48 Ack=15 Win=32768 Len=0 TSV=1415942813 TSER=1415942813
  0.085745 157.159.50.197 -> 157.159.50.197 LDAP MsgId=2 Search Request, Base DN=dc=int-evry,dc=fr
  0.085761 157.159.50.197 -> 157.159.50.197 TCP ldap > 50545 [ACK] Seq=15 Ack=108 Win=32768 Len=0 TSV=1415942814 TSER=1415942814
  0.086809 157.159.50.197 -> 157.159.50.197 LDAP MsgId=2 Search Entry
  0.126120 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [ACK] Seq=108 Ack=90 Win=32768 Len=0 TSV=1415942855 TSER=1415942815
  0.176524 157.159.50.197 -> 157.159.50.197 LDAP MsgId=2 Search Result
  0.176569 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [ACK] Seq=108 Ack=104 Win=32768 Len=0 TSV=1415942905 TSER=1415942905
  0.177115 157.159.50.197 -> 157.159.50.197 LDAP MsgId=3 Unbind Request
  0.177157 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [FIN, ACK] Seq=115 Ack=104 Win=32768 Len=0 TSV=1415942906 TSER=1415942905
  0.179402 157.159.50.197 -> 157.159.50.197 TCP ldap > 50545 [FIN, ACK] Seq=104 Ack=116 Win=32768 Len=0 TSV=1415942908 TSER=1415942906
  0.179427 157.159.50.197 -> 157.159.50.197 TCP 50545 > ldap [ACK] Seq=116 Ack=105 Win=32768 Len=0 TSV=1415942908 TSER=1415942908

#retour au resultat ldapsearch:

dn: uid=test,ou=People,dc=int-evry,dc=fr
cn: compte de test mci


L'option follow TCP stream d'ethereal (version graphique) permet de voir clairement le contenue des échanges ldap sur le réseau. En plus du résultat de la requete, on voit ici le binddn suivit de son mot de passe ! :-( .

0-...`(.....cn=admin,dc=int-evry,dc=fr..secret0....a.
......0:...c5..dc=int-evry,dc=fr
..
...............uid..test0...cn0I...dD.$uid=test,ou=People,dc=int-evry,dc=fr0.0...cn1...compte de test mci0....e.
......0....B.


15.5.3  Echange chiffré, start TLS

$ ldapsearch -x uid=test -H ldap://calaz.int-evry.fr -ZZ -D "cn=admin,dc=int-evry,dc=fr" -W cn -LLL
Enter LDAP Password:

#ecoute avec tethereal :
$ tethereal -i lo port 389
Capturing on lo
  0.000000 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [SYN] Seq=0 Ack=0 Win=32767 Len=0 MSS=16396 TSV=1416303614 TSER=0 WS=2
  0.002919 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [SYN, ACK] Seq=0 Ack=1 Win=32767 Len=0 MSS=16396 TSV=1416303614 TSER=1416303614 WS=2
  0.003234 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [ACK] Seq=1 Ack=1 Win=32768 Len=0 TSV=1416303614 TSER=1416303614
  0.004259 157.159.50.197 -> 157.159.50.197 LDAP MsgId=1 Extended Request
  0.004288 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=1 Ack=32 Win=32768 Len=0 TSV=1416303618 TSER=1416303618
  0.037014 157.159.50.197 -> 157.159.50.197 LDAP MsgId=1 Extended Response
  0.037047 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [ACK] Seq=32 Ack=15 Win=32768 Len=0 TSV=1416303651 TSER=1416303651
  0.130895 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  0.145397 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  0.150212 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [ACK] Seq=174 Ack=2797 Win=38332 Len=0 TSV=1416303764 TSER=1416303759
  0.181431 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  0.220684 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=2797 Ack=500 Win=32768 Len=0 TSV=1416303835 TSER=1416303795
  0.365409 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  0.405656 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [ACK] Seq=500 Ack=2856 Win=38332 Len=0 TSV=1416304020 TSER=1416303979
  2.770622 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.770661 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=2856 Ack=622 Win=32768 Len=0 TSV=1416306385 TSER=1416306385
  2.778834 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.778856 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [ACK] Seq=622 Ack=2946 Win=38332 Len=0 TSV=1416306393 TSER=1416306393
  2.798611 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.838266 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=2946 Ack=760 Win=32768 Len=0 TSV=1416306453 TSER=1416306413
  2.931956 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.940468 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.940918 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.940941 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=3174 Ack=834 Win=32768 Len=0 TSV=1416306555 TSER=1416306555
  2.941010 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.941021 157.159.50.197 -> 157.159.50.197 TCP ldap > 50547 [ACK] Seq=3174 Ack=871 Win=32768 Len=0 TSV=1416306555 TSER=1416306555
  2.941056 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [FIN, ACK] Seq=871 Ack=3174 Win=38332 Len=0 TSV=1416306555 TSER=1416306555
  2.966664 157.159.50.197 -> 157.159.50.197 LDAP Invalid LDAP message (Can't parse sequence header: Wrong type for that item)
  2.966715 157.159.50.197 -> 157.159.50.197 TCP 50547 > ldap [RST] Seq=872 Ack=4045731940 Win=0 Len=0

# retoure au resultat de la requete ldapsearch

dn: uid=test,ou=People,dc=int-evry,dc=fr
cn: compte de test mci


Cette fois-ci, l'option de suivit du stream TCP d'ethereal n'affiche plus rien d'utile au niveau échange ldap, seul l'échange de certificat est visible.

0....w...1.3.6.1.4.1.1466.200370....x.
...
.....0?1"0 ..U....MCI Certificate Authority1.0
..U.
..INT1.0...U....FR0..
050126173836Z.
060126173836Z0..1.0...U....FR1.0...U....Essonne1
0...U....Evry1.0...U.
..GET-INT1
0...U....S2IA1.0...U....calaz.int-evry.fr1%0#..*.H..
.....root@calaz.int-evry.fr0.."0
..*.H..
..........0..
...


16  Meta annuaire
16.1  Principes
Le backend meta d'openldap permet de servir de point d'entré vers plusieurs annuaires de contexte (base DN/suffix) differents. Ainsi il est envisageable pour un groupe comprenant plusieurs entités de se servir de ce backend meta comme point d'entré unique aux differents arbres/annuaires de chacune de ses entités.
Il est egalement possible grace au rewrite engine de redéfinir (map) des attributs qui auraient une signification differente dans les entités du groupe -> exemple; l'entité 1 a choisi pour contenir le nom de service d'une personne l'attribut normalisé departmentNumber, l'entité 2 l'attribut normilsé ourganizationalUnit et enfin l'entité 3 l'attribut ``maison'' IntEPersUserEntite .
Dans la suite de ce chapitre nous allons monter une maquette sur le groupe fictif ``meta'' comprenant 3 sous-entités -> get-telecom, enstb, int-evry . Le suffix dc=meta,dc=fr sera le point d'entré des 3 annuaires de chacune des entités du groupe. Voici le schema:

         ----------------dc=meta,dc=fr-------------------
         |                     |                   |
 dc=get-telecom,dc=fr    dc=int-evry,dc=fr  dc=enstb,dc=fr


16.2  Montage et tests des entités du groupe
16.2.1  Construction des entités
Nous créons de toute pièce les annuires des entité get-telecom et enstb, pour l'entité int-evry nous utiliserons une copie de l'annuaire de production à l'INT.

$ slapadd -f /usr/local/openldap-2.2.20-1/etc/openldap/slapd-meta-get.conf -b dc=enstb,dc=fr -l arbre-enstb_meta.ldif

$ slapadd -f /usr/local/openldap-2.2.20-1/etc/openldap/slapd-meta-get.conf -b dc=get-telecom,dc=fr -l arbre-get-telecom_meta.ldif


Pour information, voici le contenu ldif de ces 2 annuaires:

$ cat arbre-enstb_meta.ldif
dn: dc=enstb,dc=fr
dc: enstb
objectClass: top
objectClass: domain
 
dn: ou=People,dc=enstb,dc=fr
ou: People
objectClass: top
objectClass: organizationalUnit
 
dn: sn=brouty,ou=People,dc=enstb,dc=fr
cn: Andre Brouty
sn: Brouty
objectClass: top
objectClass: person
objectClass: inetOrgPerson
mail: Andre.Brouty@enstb.fr
givenName: Andre


$ cat arbre-get-telecom_meta.ldif
dn: dc=get-telecom,dc=fr
dc: get-telecom
objectClass: top
objectClass: domain
objectClass: domainRelatedObject
associatedDomain: get-telecom.fr
 
dn: ou=People,dc=get-telecom,dc=fr
ou: People
objectClass: top
objectClass: organizationalUnit
 
dn: sn=lautraite,ou=People,dc=get-telecom,dc=fr
cn: Isabelle Lautraite
sn: lautraite
objectClass: top
objectClass: person
objectClass: inetOrgPerson
mail: Isabelle.Lautraite@get-telecom.fr
givenName: Isabelle


16.2.2  Lancement des entités
Lancement d'un serveur propre aux deux entités

Acces systeme
Donner l'acces systeme à l'utilisateur ldap:

$ chown ldap /usr/local/openldap-2.2.20-1/etc/openldap/slapd-meta-get.conf
[root@calaz /usr/local/openldap-2.2.20-1/var/lib/ldap]
$ chown -R ldap:ldap ./get/ ./enstb/

lancement slapd
$ /usr/local/openldap-2.2.20-1/sbin/slapd -u ldap -h "ldap://:9000/" -l local6 -f /usr/local/openldap-2.2.20-1/etc/openldap/slapd-meta-get.conf


Test de requete simple directement sur les annuaires d'entite

$ ldapsearch -x "cn=*" -h localhost -p 9000 -b "dc=get-telecom,dc=fr" -LLL cn
dn: sn=lautraite,ou=People,dc=get-telecom,dc=fr
cn: Isabelle Lautraite

$ ldapsearch -x "cn=*" -h localhost -p 9000 -b "dc=enstb,dc=fr" -LLL cn
dn: sn=brouty,ou=People,dc=enstb,dc=fr
cn: Andre Brouty


16.3  Base meta
16.4  Configuration meta de 1er niveau
Voici un fichier de configuration slapd-meta-get.conf gérant à la fois la ``metabase'' et les deux annuaires des entités enstb et get-telecom (pour l'entité int-evry une autre instance de slapd de production est utilisée dans cette maquette).

defaultsearchbase dc=meta,dc=fr

#database meta
database        meta
suffix          "dc=meta,dc=fr"                                                                                
uri           "ldap://localhost:9000/dc=meta,dc=fr"
suffixmassage "dc=meta,dc=fr" "dc=enstb,dc=fr"
                                                                               
uri           "ldap://localhost:9000/dc=meta,dc=fr"
suffixmassage "dc=meta,dc=fr" "dc=get-telecom,dc=fr"
                                                                               
uri           "ldap://localhost/dc=meta,dc=fr"
suffixmassage "dc=meta,dc=fr" "dc=int-evry,dc=fr"
lastmod  off

#database ENSTB
database        bdb
suffix          "dc=enstb, dc=fr"
rootdn          "cn=admin, dc=enstb, dc=fr"
rootpw          {crypt}jpG0l9N67nDn6
directory       /usr/local/openldap-2.2.20-1/var/lib/ldap/enstb
# validation de checkpoint dans les log tous les 200K ou toutes les Heure
checkpoint      200 3600
index   objectClass,uid,uidNumber,gidNumber,IntEPersInetServ,mailHost   eq
index   cn,mail,surname,givenname               eq,subinitial
#
# Nombre d'entree conserver dans le cache
cachesize 3000
                                                                                
#database get-telecom
database        bdb
suffix          "dc=get-telecom, dc=fr"
rootdn          "cn=admin, dc=get-telecom, dc=fr"
rootpw          {crypt}jpG0l9N67nDn6
directory       /usr/local/openldap-2.2.20-1/var/lib/ldap/get
#readonly       on
# validation de checkpoint dans les log tous les 200K ou toutes les Heure
checkpoint      200 3600
index   objectClass,uid,uidNumber,gidNumber,IntEPersInetServ,mailHost   eq
index   cn,mail,surname,givenname               eq,subinitial
#
# Nombre d'entree conserver dans le cache
cachesize 3000


16.4.1  Exemple de recherche sur la base meta
Une recherche sur la base meta parcours bien les differents annuaires/arbres.

$ ldapsearch -x "cn=*laut*" -h localhost -p 9000 -b "dc=meta,dc=fr" -LLL cn
dn: sn=lautraite,ou=People,dc=meta,dc=fr
cn: Isabelle Lautraite
 
dn: uid=vaillaut,ou=People,dc=meta,dc=fr
cn: Julien VAILLAUT


La personne cn: Julien VAILLAUT viens de l'entité int-evry et cn: Isabelle Lautraite de l'entité get-telecom, verification:

$ ldapsearch -x "cn=*laut*" -h localhost -b "dc=int-evry,dc=fr" -LLL cn
dn: uid=vaillaut,ou=People,dc=int-evry,dc=fr
cn: Julien VAILLAUT

$ ldapsearch -x "cn=*laut*" -h localhost -p 9000 -b "dc=get-telecom,dc=fr" -LLL cn
dn: sn=lautraite,ou=People,dc=get-telecom,dc=fr
cn: Isabelle Lautraite


16.4.2  Traces dans les log
On voit bien dans les log de slapd que la recherche initiale sur SRCH base="dc=meta,dc=fr" est aiguillée vers SRCH base="dc=get-telecom,dc=fr" et SRCH base="dc=enstb,dc=fr" , ainsi que vers SRCH base="dc=int-evry,dc=fr" qui tourne sous une autre instance de slapd donc un autre fichier de log non visible ci-dessous !

Jan 19 23:56:21 calaz slapd[29470]: conn=15 fd=12 ACCEPT from IP=127.0.0.1:40761 (IP=0.0.0.0:9000)
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=0 BIND dn="" method=128
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=0 RESULT tag=97 err=0 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=1 SRCH base="dc=meta,dc=fr" scope=2 deref=0 filter="(cn=*laut*)"
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=1 SRCH attr=cn
Jan 19 23:56:21 calaz slapd[29470]: conn=16 fd=14 ACCEPT from IP=127.0.0.1:40762 (IP=0.0.0.0:9000)
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=0 BIND dn="" method=128
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=0 RESULT tag=97 err=0 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=17 fd=16 ACCEPT from IP=127.0.0.1:40763 (IP=0.0.0.0:9000)
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=0 BIND dn="" method=128
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=0 RESULT tag=97 err=0 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=1 SRCH base="dc=get-telecom,dc=fr" scope=2 deref=0 filter="(cn=*laut*)"
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=1 SRCH attr=cn
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=1 SRCH base="dc=enstb,dc=fr" scope=2 deref=0 filter="(cn=*laut*)"
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=1 SRCH attr=cn
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=1 SEARCH RESULT tag=101 err=0 nentries=0 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=1 SEARCH RESULT tag=101 err=0 nentries=2 text=
Jan 19 23:56:21 calaz slapd[29470]: conn=15 op=2 UNBIND
Jan 19 23:56:21 calaz slapd[29470]: conn=15 fd=12 closed
Jan 19 23:56:21 calaz slapd[29470]: conn=16 op=2 UNBIND
Jan 19 23:56:21 calaz slapd[29470]: conn=16 fd=14 closed
Jan 19 23:56:21 calaz slapd[29470]: conn=17 op=2 UNBIND
Jan 19 23:56:21 calaz slapd[29470]: conn=17 fd=16 closed


16.5  Base Meta de 2eme niveau
On peux egalement faire apparaitre chacune des entités du groupe apres le suffix meta, cela rend les entités plus visibles !

16.5.1  Configuration meta

database        meta
suffix          "dc=meta,dc=fr"
                                                                                
uri           "ldap://localhost:9000/dc=enstb,dc=meta,dc=fr"
suffixmassage "dc=enstb,dc=meta,dc=fr" "dc=enstb,dc=fr"
                                                                                
uri           "ldap://localhost:9000/dc=get-telecom,dc=meta,dc=fr"
suffixmassage "dc=get-telecom,dc=meta,dc=fr" "dc=get-telecom,dc=fr"
                                                                                
uri           "ldap://localhost/dc=int-evry,dc=meta,dc=fr"
suffixmassage "dc=int-evry,dc=meta,dc=fr" "dc=int-evry,dc=fr"
lastmod  off


16.5.2  Recherche sur le groupe
Cette fois ci le résultat d'une recherche sur le groupe fait bien apparaitre l'entité d'appartenance de la personne dans le dn:

$ldapsearch -x "cn=*laut*" -h localhost -p 9000 -b "dc=meta,dc=fr" -LLL cn
dn: sn=lautraite,ou=People,dc=get-telecom,dc=meta,dc=fr
cn: Isabelle Lautraite
 
dn: uid=vaillaut,ou=People,dc=int-evry,dc=meta,dc=fr
cn: Julien VAILLAUT


16.5.3  Recherche meta spécifique à une entité

$ ldapsearch -x "cn=*laut*" -h localhost -p 9000 -b "dc=get-telecom,dc=meta,dc=fr" -LLL cn
dn: sn=lautraite,ou=People,dc=get-telecom,dc=meta,dc=fr
cn: Isabelle Lautraite


16.5.4  Log d'accès de la recherche spécifique
La base meta renvoi une requete uniquement sur la base de l'entité get-telecom:

Jan 20 22:37:07 calaz slapd[7780]: conn=10 fd=12 ACCEPT from IP=127.0.0.1:42122 (IP=0.0.0.0:9000)
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=0 BIND dn="" method=128
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=0 RESULT tag=97 err=0 text=
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=1 SRCH base="dc=get-telecom,dc=meta,dc=fr" scope=2 deref=0 filter="(cn=*laut*)"
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=1 SRCH attr=cn
Jan 20 22:37:07 calaz slapd[7780]: conn=11 fd=14 ACCEPT from IP=127.0.0.1:42123 (IP=0.0.0.0:9000)
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=0 BIND dn="" method=128
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=0 RESULT tag=97 err=0 text=
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=1 SRCH base="dc=get-telecom,dc=fr" scope=2 deref=0 filter="(cn=*laut*)"
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=1 SRCH attr=cn
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
Jan 20 22:37:07 calaz slapd[7780]: conn=10 op=2 UNBIND
Jan 20 22:37:07 calaz slapd[7780]: conn=10 fd=12 closed
Jan 20 22:37:07 calaz slapd[7780]: conn=11 op=2 UNBIND
Jan 20 22:37:07 calaz slapd[7780]: conn=11 fd=14 closed


16.6  Equivalance d'attributs
Comme évoqué dans les principes en début de chapitre, il est possible de rendre équivalent (map) des attributs distincts entre entités.

16.6.1  Modification de la maquette
Modifions une entrée dans l'entité get-telecom afin d'y ajouter l'attribut departmentNumber

$ ldapmodify -x -D "cn=admin,dc=get-telecom,dc=fr" -W -f ./add-dept-meta.ldif -p 9000 -h localhost
Enter LDAP Password:
modifying entry "sn=lautraite,ou=People,dc=get-telecom,dc=fr"
$ cat add-dept-meta.ldif
dn: sn=lautraite,ou=People,dc=get-telecom,dc=fr
changetype: modify
add: departmentNumber
departmentNumber: SAG


Verification:

$ ldapsearch -x "cn=*laut*" -h localhost -p 9000 -b "dc=get-telecom,dc=meta,dc=fr" -LLL  cn departmentNumber
dn: sn=lautraite,ou=People,dc=get-telecom,dc=meta,dc=fr
cn: Isabelle Lautraite
departmentNumber: SAG


Modification équivalente sur l'entité enstb , cette entité ayant choisi l'attribut ``ou'' pour contenir l'information de service d'appartenance de la personne

$ ldapmodify -x -D "cn=admin,dc=enstb,dc=fr" -W -f ./add-dept-enstb.ldif -p 9000 -h localhost
Enter LDAP Password:
modifying entry "sn=brouty,ou=People,dc=enstb,dc=fr"
$ cat add-dept-enstb.ldif
dn: sn=brouty,ou=People,dc=enstb,dc=fr
changetype: modify
add: ou
ou: SAG


Verification:

$ ldapsearch -x "cn=*brout*" -h localhost -p 9000 -b "dc=enstb,dc=meta,dc=fr" -LLL  cn ou
dn: sn=brouty,ou=People,dc=enstb,dc=meta,dc=fr
cn: Andre Brouty
ou: SAG


16.6.2  Modification de la configuration du serveur
Nous pouvons maintenant configurer le meta annuaire afin qu'une recherche sur le groupe rende homogene l'attribut d'appartenance au service. Ici nous traduiront l'attribut departementNumber vers ou lors d'une recherche sur l'entite enstb.

database        meta
suffix          "dc=meta,dc=fr"
                                                                               
uri           "ldap://localhost:9000/dc=enstb,dc=meta,dc=fr"
suffixmassage "dc=enstb,dc=meta,dc=fr" "dc=enstb,dc=fr"
map attribute  departmentNumber ou


Test

$ ldapsearch -x "departmentNumber=SAG" -h localhost -p 9000 -b "dc=meta,dc=fr" -LLL  cn departmentNumber ou
dn: sn=brouty,ou=People,dc=enstb,dc=meta,dc=fr
cn: Andre Brouty
departmentNumber: SAG
 
dn: sn=lautraite,ou=People,dc=get-telecom,dc=meta,dc=fr
cn: Isabelle Lautraite
departmentNumber: SAG


L'attribut ou=SAG pour l'annuaire de l'entité enstb a bien été traduit en departmentNumber=SAG .

16.6.3  Equivalence d'attribut par entité
Il est possible de définir une équivalence (map) d'attribut par entité. Ici nous conservons le ``map'' depatmentNumber vers ou pour l'entité enstb et ajoutons le ``map'' depatmentNumber vers IntEPersUserEntite (attribut ``maison'').

Configuration de la database meta

#database meta
database        meta
suffix          "dc=meta,dc=fr"
                                                                               
uri           "ldap://localhost:9000/dc=enstb,dc=meta,dc=fr"
suffixmassage "dc=enstb,dc=meta,dc=fr" "dc=enstb,dc=fr"
map attribute  departmentNumber ou
                                                                               
uri           "ldap://localhost:9000/dc=get-telecom,dc=meta,dc=fr"
suffixmassage "dc=get-telecom,dc=meta,dc=fr" "dc=get-telecom,dc=fr"
                                                                               
uri           "ldap://localhost/dc=int-evry,dc=meta,dc=fr"
suffixmassage "dc=int-evry,dc=meta,dc=fr" "dc=int-evry,dc=fr"
map attribute  departmentNumber IntEPersUserEntite
lastmod  off


Verification des differents attributs de ``services'' sur l'entité int-evry:

$ ldapsearch -x "IntEPersUserEntite=SAG" -h localhost  -b "dc=int-evry,dc=fr" -LLL  cn departmentNumber ou IntEPersUserEntite -D "cn=admin,dc=int-evry,dc=fr" -W
Enter LDAP Password:
dn: uid=procacci,ou=People,dc=int-evry,dc=fr
cn: Jehan PROCACCIA
departmentNumber: S2IA
IntEPersUserEntite: SAG
ou: MCI


Rechecrhe sur la meta base sur l'attribut d'equivalence departmentNumber:

$ /usr/local/openldap-2.2.20-1/bin/ldapsearch -x "departmentNumber=SAG" -h localhost -p 9000 -b "dc=meta,dc=fr" -LLL  cn departmentNumber
dn: sn=brouty,ou=People,dc=enstb,dc=meta,dc=fr
cn: Andre Brouty
departmentNumber: SAG
 
dn: sn=lautraite,ou=People,dc=get-telecom,dc=meta,dc=fr
cn: Isabelle Lautraite
departmentNumber: SAG
 
dn: uid=procacci,ou=People,dc=int-evry,dc=meta,dc=fr
cn: Jehan PROCACCIA
departmentNumber: SAG


Log
Ils font apparaitre une indisponibilité d'index sur l'attribut ``mappé'', ce qui pourrait avoir des consequences en terme de performance !.

Jan 21 10:15:57 calaz slapd[11956]: conn=6 fd=12 ACCEPT from IP=127.0.0.1:42322 (IP=0.0.0.0:9000)
Jan 21 10:15:57 calaz slapd[11956]: conn=6 op=0 BIND dn="" method=128
Jan 21 10:15:57 calaz slapd[11956]: conn=6 op=0 RESULT tag=97 err=0 text=
Jan 21 10:15:57 calaz slapd[11956]: conn=6 op=1 SRCH base="dc=meta,dc=fr" scope=2 deref=0 filter="(departmentNumber=sag)"
Jan 21 10:15:57 calaz slapd[11956]: conn=6 op=1 SRCH attr=cn departmentNumber
Jan 21 10:15:57 calaz slapd[11956]: conn=7 fd=14 ACCEPT from IP=127.0.0.1:42323 (IP=0.0.0.0:9000)
Jan 21 10:15:57 calaz slapd[11956]: conn=7 op=0 BIND dn="" method=128
Jan 21 10:15:57 calaz slapd[11956]: conn=7 op=0 RESULT tag=97 err=0 text=
Jan 21 10:15:57 calaz slapd[11956]: conn=8 fd=16 ACCEPT from IP=127.0.0.1:42324 (IP=0.0.0.0:9000)
Jan 21 10:15:57 calaz slapd[11956]: conn=8 op=0 BIND dn="" method=128
Jan 21 10:15:57 calaz slapd[11956]: conn=8 op=0 RESULT tag=97 err=0 text=
Jan 21 10:15:57 calaz slapd[11956]: conn=7 op=1 SRCH base="dc=enstb,dc=fr" scope=2 deref=0 filter="(ou=sag)"
Jan 21 10:15:57 calaz slapd[11956]: conn=7 op=1 SRCH attr=cn ou
Jan 21 10:15:57 calaz slapd[11956]: <= bdb_equality_candidates: (ou) index_param failed (18)
Jan 21 10:15:57 calaz slapd[11956]: conn=7 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
Jan 21 10:15:57 calaz slapd[11956]: conn=8 op=1 SRCH base="dc=get-telecom,dc=fr" scope=2 deref=0 filter="(departmentNumber=sag)"
Jan 21 10:15:57 calaz slapd[11956]: conn=8 op=1 SRCH attr=cn departmentNumber
Jan 21 10:15:57 calaz slapd[11956]: <= bdb_equality_candidates: (departmentNumber) index_param failed (18)
Jan 21 10:15:57 calaz slapd[11956]: conn=8 op=1 SEARCH RESULT tag=101 err=0 nentries=1 text=
Jan 21 10:15:58 calaz slapd[11956]: conn=6 op=1 SEARCH RESULT tag=101 err=0 nentries=3 text=
Jan 21 10:15:58 calaz slapd[11956]: conn=6 op=2 UNBIND
Jan 21 10:15:58 calaz slapd[11956]: conn=6 fd=12 closed
Jan 21 10:15:58 calaz slapd[11956]: conn=7 op=2 UNBIND
Jan 21 10:15:58 calaz slapd[11956]: conn=7 fd=14 closed
Jan 21 10:15:58 calaz slapd[11956]: conn=8 op=2 UNBIND
Jan 21 10:15:58 calaz slapd[11956]: conn=8 fd=16 closed


16.7  Avertissements
16.7.1  ACL
Ici les attributs recherchés ont été ouverts en read by * !. Il doit y avoir moyen d'affiner ceci avec les directives binddn bindpw du backend meta .

16.7.2  Performances
Ces tests ont été réalisés sur des bases ldap comprenants pour les entités get-telecom et enstb une seule entrée ! (2800 pour int-evry), de plus les instances de slapd sont locales au PC de test -> les resultats ont été instantanés, il faudrait verifier ce que cela donne avec des annuaires distants et plus consequents .

17  Migration vers Supann (NEW)
Presentation de supann: http://www.cru.fr/ldap/supann/

17.1  Objectif
L'objectif est ici de convertir un annuaire existant vers supann. Il s'agit donc d'y ajouter les objectclass de supannPersonn et de eduPerson telles qu'elles sont présentées dans : http://www.cru.fr/ldap/supann/recomm/SUPANN-V10.pdf

Dans un premier temps, j'ai essayé de remplir le maximum d'attributs optionnels en plus des attributs obligatoires .

17.2  Méthode
Il en existe plusieurs, on pourrai simplement faire un dump ldif de l'annuaire et utiliser un script quelconque pour ajouter à froid les attributs et objectclass, puis recharger le ldif completement.
J'ai choisis l'option de modification à chaud (d'abord sur un annuaire de test !) en utilisant la librairie Perl Net::LDAP -> recherche des objects (uid de personnes) , et modification un à un.

17.3  Script d'insertion
voici le script : ./add-supann-eduperson-attr.plou en txt pour le voir dans le navigateur: ./add-supann-eduperson-attr.txt
Ce script est spécifique à l'INT, mais doit pouvoir facilement s'adapter .
Il essais de recuperer le maximum d'information deja existantes dans la base ldap de production (exemple employeeType pour alimenter eduPersonAffiliation) et en recupere d'autres depuis une extraction de base externe (supannCivilite récupéré d'une base SQL des etudiants).
Il gére aussi l'utilisation multiple, je veux dire par là qu'il peux repasser sur un annuaire deja supann en ne faisant que modifier les attributs déja presents sans ajouter à nouveau les objectclass supannPersonn et eduPerson (cf flag dans les commentaires en ligne du script).

17.4  Execution
Relativement rapide, 1mn pour 2000 entrées via le reseau .

[jehan@calaz ~/Procacci/Progs-jp/Perl/Ldap]
$ time ./add-supann-eduperson-attr.pl
...
flag=0 et civ=M
DN,uid=procacci,ou=People,dc=int-evry,dc=fr
...
real    1m11.769s
user    0m30.374s
sys     0m0.532s


17.5  Résultat
Voici un exemple d'entré d'une étudiante:

[root@esup /var/lib/ldap/int]
$ ldapsearch -x uid=sadoo_li
...
supannListeRouge: FALSE
supannEtuId: 17555
supannOrganisme: INT EVRY 0911781S
supannCivilite: Mlle
supannAffectation: EM
supannCodeINE: 17555
supannParrainDN: uid=sadoo_li,ou=People,dc=int-evry,dc=fr
eduPersonAffiliation: student
eduPersonPrimaryAffiliation: student
eduPersonNickname: Linda
eduPersonOrgDN: o=GET-INT,dc=int-evry,dc=fr
eduPersonOrgUnitDN: sn=EM,ou=departements,ou=informations,dc=int-evry,dc=fr
eduPersonPrimaryOrgUnitDN: sn=EM,ou=departements,ou=informations,dc=int-evry,d
 c=fr
eduPersonPrincipalName: Linda.Sadoo@int-evry.fr
eduPersonScopedAffiliation: student@EM


18  Trucs et astuces
18.1  Index
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  ]


18.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


18.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 ) )


18.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 !.

18.5  Sauvegarde en ligne des données PosixAccount
Pour restaurer ou avoir une copie sous un format "traditionnel" des comptes posix :

getent passwd >passwd.back
getent shadow >shadow.back


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/OSS/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://ldap.akbkhome.com/index.php 
[7]
    openldap latest release notes http://www.openldap.org/software/release/ 
[8]
    Fedora Directory Server Project http://directory.fedora.redhat.com/wiki/Main_Page 
[9]
    Red Hat Directory Server http://www.redhat.com/software/rha/directory/ 
[10]
    Red Hat Opens Netscape Directory http://linux.slashdot.org/article.pl?sid=05/05/26/0044247&tid=110&tid=95

    Ce document a été traduit de LATEX par HEVEA.