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
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.
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.
Le standard X.500 définis en 1988 puis dans sa deuxième version en 1993 comprend plusieurs normes:
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.
Novell à rendu son système d'annuaire indépendant du système d'exploitation (Netware). Novell Directory Service est un annuaire object disponible sur Netware, Solaris et Windows. Il supporte le standard LDAP v3 et les données au format LDIF ( Ldap Data Interchange Format, format texte de données d'import/export dans un annuaire LDAP ).
Dès 1985 Sun à introduit le Network Information Service, déjà destiné à centraliser l'administration des informations système. Les informations sont stockées sous forme de map (table de correspondance entre une clé et une valeur: clé titan , valeur 192.163.12.43) dans de simples bases indexées (db, dbm …), accessibles par des appels RPC (Remote Procedure Call). Dans un premier temps les map s'ajoutaient aux fichiers locaux (ajout d'un caractère + dans le fichier concerné pour rediriger la recherche vers les nis, remarque: depuis solaris 2 ce signe n'a plus cet effet. Avec solaris 2 et toutes ses sources d'information système (dns, nis+ …) il devenait difficile de programmer dans chaque service ou utilitaire système, le mode de recherche. Sun a créé une API qui se place entre ces programmes et les différentes sources d'information sur lesquelles ils s'appuient, cette API est le Name Service Switch. Avec cette API les programmes n'ont plus a connaître les détails d'implémentation des services d'information qu'ils contactent. Les appels à cette API sont du type getXbyY (gethostbyname), lisent le fichier /etc/nsswitch.conf dans lequel est associé à chaque type de service de nom une liste des sources disponibles; exemple: passwd: files nis nisplus, host: files nis nisplus dns. La recherche se fait d'une source à l'autre dans l'ordre définis tant qu'une correspondance n'est pas trouvée, ce qui abouti à une erreur NOTFOUND en cas d'échec sur toutes les sources listées. On peut d'ailleurs utiliser l'option [NOTFOUND=return] afin d'indiquer aux programmes de consulter uniquement les sources listées à gauche de cette entrée, seulement en cas de disfonctionnement de ces sources celles de droite seront consultées. Exemple: networks: nis [NOTFOUND=return] files. Les NIS fonctionnent sur un système maître-esclave (les modifications se font sur le maître, elles sont répercutées sur le(s) esclave(s) du domaine nis), seulement ils ne sont pas adaptés à des volumes important de données, à chaque modification c'est l'ensemble de la base qui est transférée entre maitre-esclave. Il y à également un manque d'organisation des données sous forme hiérarchique. Enfin la sécurité d'accès à ce service est très faible
Sun à réagit aux défauts de NIS par l'introduction dans solaris 2 des NIS 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.
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é.
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).
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.
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.
Ce standard définis 4 modèles.
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.
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=*
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
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.