Page suivante Page précédente Table des matières Serveur et interface d'administration PingOO 2: Serveur  

3. Serveur

Il ne s'agit ici que de la partie maintenance du serveur sur le travail effectué par Jean-François Giraud.

Il ne tient donc pas compte des développements effectués par Sébastien Delcroix et Laurent Haugeard et Fabien Salvi.

3.1 Arborescence des répertoires

.
|-- etc
|   |-- PingOO
|   |-- cron.weekly
|   |-- init.d
|   `-- openldap
|-- usr
|   |-- doc
|   |   `-- pingoo_server
|   |-- lib
|   |   `-- PingOO
|   |       |-- ML
|   |       |   |-- Common
|   |       |   |   `-- ldap
|   |       |   |-- Driver
|   |       |   |   `-- UGM
|   |       |   |       `-- Structure
|   |       |   `-- Kernel
|   |       |-- java
|   |       `-- perl5
|   |           |-- Common
|   |           |   `-- ldap
|   |           |-- Driver
|   |           |   `-- UGM
|   |           |       `-- Structure
|   |           `-- Kernel
|   |               `-- Analyze
|   `-- sbin
`-- var
    |-- PingOO
    `-- log
        `-- PingOO

Contenu

Répertoire /etc

Ce répertoire contient :

Seul les fichiers servant à la création des fichiers de configuration de la base LDAP sont intéressants. Ils feront partis d'une prochaine section.

Répertoire /usr/lib/PingOO/ML

Il s'agit des fichiers multi-langues des modules perl contenus dans le répertoire /usr/lib/PingOO/perl5.

Ils ont le même nom que le module correspondant à l'extension près '.ML'.

Répertoire /usr/lib/PingOO/java

Ce répertoire contient les fichiers jar du client. Le numéro de version est contenu dans le nom.

Exemple : DLAI-2.0.jar

Pour tout nouvelle version il faudra utiliser le tiret après DLAI et l'extension jar. La version pour cet exemple est 2.0.

La récupération et utilisation du numéro de version s'effectue dans le fichier Driver::Kernel.

Répertoire /usr/lib/PingOO/perl5

Ce répertoire contient les sources du projet côté perl. Il se décompose en plusieurs répertoires :

Répertoire /usr/sbin/

Ce répertoire contient pour le moment generate.pl. C'est l'exécutable appelé après l'installation du package pour créer la base LDAP ou bien pour regénérer les fichiers de configuration.

En ce qui concerne le fichier generate.pl, il serait intéressant de le réécrire en partie pour le rendre plus lisible.

Architecture générale du serveur

Architecture générale du serveur

L'architecture générale du serveur est représentée sur la figure Architecture générale du serveur.

Le serveur PingOOd

Il s'agit ici du logiciel d'aide à l'administration
dialogue avec un client via le réseau. Il utilise aussi le réseau pour accéder à l'annuaire LDAP. Dans notre cas, cet annuaire se situe sur la même machine que le serveur mais il est envisageable qu'il puisse être hébergé sur un ordinateur distinct. Ceci peut être intéressant si l'on désire économiser un maximum de ressources (mémoire, CPU...) sur la machine PingOO.

Le serveur se compose de plusieurs parties. Nous avons tenté de les dissocier de telle manière que la modification de l'une n'implique pas la réécriture totale des autres... Ce qui s'impose étant donné que cette application est vouée à une longue vie.

Voici les parties, présentées de manière sommaire :

PingOOd

Il s'agit de la partie centrale du serveur. Elle s'occupe des connexions et de l'analyse du protocole de bas niveau : taille des messages, est-ce qu'ils sont cryptés ou non, etc. Cette partie comporte donc la séquence d'initialisation du dialogue avec le client. Elle doit être sécurisée le plus possible et interdire l'appel de toute fonction avant authentification complète du client.

Elle fait appel aux modules de cryptage et décryptage pour crypter (respectivement décrypter) les messages sortants (respectivement entrants).

Une fois la requête d'un client reçue, décryptée, PingOOd fait appel à un module d'analyse des requêtes. Ce module, utilisant un protocole de haut niveau, a pour but de transformer une requête en données utilisables par les drivers.

Une fois l'analyse de la requête faite, celle-ci est déléguée au gestionnaire d'appel de fonction qui l'authentifie et agit en conséquent.

Les requêtes sortantes suivent le chemin inverse... Elles sont formatées suivant le protocole de haut niveau, cryptées ou signées puis envoyées au client suivant le protocole de bas niveau.

Cryptage, décryptage

Il s'agit des modules servant au cryptage et décryptage des messages. Dans la version actuelle du client-serveur, il s'agit seulement de "boîtes noires" qui ne font rien. Ces dernières ont été installées dans l'optique d'utiliser un jour un moyen sécurisé pour la transmission de données sur le réseau. En effet, mieux vaut prévoir cette fonctionnalité avant, que d'avoir à la rajouter après. Comme le dit le proverbe, mieux vaut prévenir que guérir !

Analyse requête, formatage réponse

Ce module est utilisé pour le protocole de haut niveau : il transforme les requêtes entrantes dans les structures de données adéquates utilisables dans le reste du programme. De même, il permet de transformer ces mêmes structures de données dans le format tel qu'il sera envoyé au client.

Ce module permet entre autres de coder, décoder des tables de hachage, des tableaux, des fichiers, etc. Il repose sur le module MIME::Base64 qui est utilisé pour encoder et décoder les données en base 64

L'encodage en base 64 est très employé dans la messagerie électronique : une image insérée dans un mél (ou mail en anglais) est par exemple encodée en base 64.
.

Gestionnaire d'appel

Il s'agit ici d'un module très important du point de vue conceptuel. En effet, c'est cette partie du serveur qui authentifie une requête et autorise où non l'appel à la fonction associée à celle-ci. Le gestionnaire d'appel sert en quelque sorte de filtre.

Pour accepter une requête, le gestionnaire vérifie d'une part que le client a accès au driver invoqué et vérifie d'autre part si la fonction du driver est appelable. En effet, toute fonction est visible dans le langage Perl ; il n'existe pas de moyen de protéger celles-ci de l'extérieur par un mot clé tel que private en java ou C++.

Si la requête est acceptée, le gestionnaire d'appel invoque la fonction demandée en lui passant les paramètres et la table de hachage qui contiendra les données à renvoyer au client.

Drivers

Sur la figure Architecture générale du serveur, un seul driver a été représenté par soucis de simplicité. En fait, il y en a évidemment plusieurs.

A chaque driver correspond un esclave du côté client.

Chaque driver comporte une liste de fonctions. Cette liste, consultable par le gestionnaire d'appel, identifie les fonctions qu'un client a le droit d'invoquer.

Toutes les fonctions des drivers qui sont appelables, ont les mêmes spécifications. Elles prennent trois tables de hachages en paramètres.

Les drivers peuvent utiliser les librairies systèmes et les librairies LDAP en fonction de ce qu'ils désirent effectuer comme travail.

Librairies LDAP

Ces librairies permettent d'accéder à l'annuaire LDAP. Elles ont été développées à partir d'une librairie récupérée sur les CPAN

CPAN : Comprehensive Perl Archive Network
qui se nomme Net::LDAPapi.

Cet ensemble comporte aussi des librairies développées lors du stage afin d'analyser les fichiers de configuration de OpenLDAP (la version de LDAP que nous avons utilisée). En effet, il était nécessaire de pouvoir connaître les droits d'accès que possède une personne sur une entrée de l'annuaire LDAP. Les librairies développées pour cet usage se nomment Common::ldap::Parse et Common::ldap::Acl.

Enfin, les attributs d'une entrée de l'annuaire peuvent être filtrés en fonction du driver lors de la création ou modification. C'est le travail de la librairie Common::LDAP qui s'appuie sur les librairies précédentes et sur le fichier de configuration my_slapd.def.conf

Librairies systèmes

Il s'agit des librairies intéragissant avec le système d'exploitation Linux. Ce sont par exemple le cas des librairies développées par Sébastien Delcroix qui ajoutent des utilisateurs et groupes dans les fichiers /etc/password, /etc/group, /etc/shadow et /etc/aliases.

Ces librairies demandent à être très robustes puisque l'intégrité du système repose dessus. En effet, si un fichier venait à être corrompu, le redémarrage de la machine PingOO risquerait d'échouer.

Librairies utilitaires

Ce sont des librairies communes à un peu tous les modules. Il s'agit, en particulier, des modules gérant le changement de langue, la gestion des erreurs...

Dans cet ensemble se trouvent aussi les librairies d'accès à la mémoire partagée.

3.2 Fichiers

Fichiers de /usr/lib/PingOO/perl5/Kernel

Voici la liste des fichiers présents :

PingOOd.pl

Il s'agit de l'exécutable. Le lien /usr/bin/PingOOd est créé lors de l'installation du package pointe sur lui.

Ce package effectue diverses opérations qui sont très IMPORTANTES.

La première est de déterminer le mode de lancement du serveur.

Si le service PingOOd n'est pas dans /etc/servives et /etc/inetd.conf ou bien commenté, le mode est standalone. Le développeur lance le serveur, qui attend puis se forke à chaque nouvelle connexion. Ceci est intéressant lors de la phase de développement. La sortie des erreurs s'effectue sur le device déterminé dans /etc/PingOO/PingOO_server.conf à la section standalone et champs stderr.

Dans le cas contraire, inetd se charge de lancer le programme. La sortie des erreurs s'effectue sur le device déterminé dans /etc/PingOO/PingOO_server.conf à la section inetd et champs stderr.

La seconde est de rediriger les entrées sorties. Dans le mode inetd, la lecture et écriture de messages au client ne s'effectue pas via les sockets mais via les entrées/sorties standard. Donc, le client recevrait toute ce qui est écrit sur STDOUT (d'où caffouillage du protocole de communication).

Enfin, pour faire en sorte que la lecture/écriture sur l'entrée/sortie standard s'effectue de la même manière que sur les sockets. On utilise donc la classe IO::Handle pour le mode inetd. Après dans le reste des modules, aucune distinction entre IO::Socket et IO::Handle n'est faite puisque ces deux classes fournissent les mêmes méthodes.

Fichier Analyze.pm

Ce fichier analyze la requête envoyée par le client et permet de formatter la réponse. Si le protocole de haut niveau venait à changer, ce serait ici qu'il faudrait effectuer les modifications.

Ce fichier fournit deux méthodes importantes : CreateHashTable et CreateResponse.

La première est utilisée pour créer les structures de données lors de la récupération d'un message envoyé par le client. Elle retourne un code d'erreur et deux références à une table de hachage (description de la fonction appelée, paramètres à passer à la fonction).

La seconde est utilisée pour créer le message à renvoyer à partir d'une table de hachage correspondant aux résultats.

La table de hachage utilisée pour contenir les paramètres comme les réponses est structurée de la manière suivante. A une clé correspond une valeur. Cette valeur peut être :

Exemple : (Je suppose les valeurs non encodées en base 64)

simple{toto}:tata
array{tutu}:titi,grosminet
hashkey{titi}:key11.key12,key21
hashvalue{titi}:aaa,bbb
file{fichier}:nom,valeur

Ceci correspond à une table de hachage :

{ 'toto' => 'tata',
  'tutu' => [ 'titi', 'grosminet' ],
  'titi' => { 'key21' => 'bbb',
              'key11' => { 'key12' => 'aaa' } },
  'fichier' => new Kernel::Analyse::File([nom, valeur])
}

Fichier Analyze/File.pm

Il s'agit d'une classe. Celle-ci est utilisée pour récupérer un fichier provenant du client ou lui envoyer.

Elle est donc utilisé par le module Analyze.pm et par le développeur dans son driver.

Pour comprendre son fonctionnement voir la documentation de la classe.

Fichier CallManager.pm

Il s'agit du gestionnaire d'appels.

Il importe les drivers définis dans le fichier de configuration /etc/PingOO/PingOO_server.conf

Il fournit les fonctions suivantes :

Ce module utilise l'évaluation et les pointeurs de fonctions. Je conseille donc de lire le chapitre approprié dans "Programmation avancée en Perl" ].

Fichier Crypt.pm

Il s'agit de la boîte noire pour le cryptage, décryptage des messages. Ce module est essentiellement utilisé par PingOO_IO.

Fichier PingOO_IO.pm

Ce fichier est appelé juste après PingOOd.pl. C'est ce module qui gère le protocole de communication.

Il utilise Crypt.pm pour crypter, décrypter les messages entrants et sortants.

Il utilise Analyze.pm pour transformer les données sortantes et entrantes.

Il utilise Call.pm pour appeler une fonction d'un driver s'il a le droit.

C'est aussi ce module qui a en charge de lire et écrire sur les sockets (ou plutôt sur le handle).

Enfin, PingOO_IO formate les réponses en fonction de la table de hachage que le développeur complète dans le driver et qui remonte jusqu'à lui. Pour plus de détail, voir la section Driver.

Fichiers de /usr/lib/PingOO/perl5/Common

Ce répertoire contient les fichiers communs à un peu tous le modules.

Voici la liste :

Fichier LDAP.pm

Ce fichier fournit des fonctions de haut niveau. Ces fonctions permettent :

Ces fonctions renvoient 1 en cas de succès, 0 sinon. Elles positionnent les erreurs dans ErrorPkg.

D'autre part, il est possible d'effectuer un filtrage des attributs lors de la création, modification, etc. en fournissant le nom du driver. Celui-ci est matché aux options définies dans le fichier /etc/openldap/my_slapd.oc.conf.pingoo

Enfin, des fonctions de Lock peuvent être utilisées pour vérouiller l'accès à la base LDAP. En effet, si l'ajout d'une entrée est une opération atomique, une fonction d'un driver peut avoir besoin de vérouiller la base pour effectuer une série de fonctions atomiques. Il ne faudra pas oublier de lever le vérou après l'avoir déposé.

Fichier SharedData.pm

Ce fichier sert à sauvegarder et récupérer les données inscrites en mémoire partagée.

Il s'appuie sur IPC::Shareable et Storable.

Il peut être intéressant de le réécrire afin d'en améliorer la lisibilité et le fonctionnement.

Fichier Acl.pm

Il s'agit d'une classe représentant une règle du fichier /etc/openldap/slapd.conf

Il n'est utilisé que par Parse.pm

Parse.pm

Module d'analyse des fichiers de configurations de LDAP (à la sauce PingOO c'est-à-dire avec des ajouts d'informations).

Ce fichier est très important. C'est lui qui analyse le fichier de configuration /etc/openldap/slapd.conf généré automatiquement par /usr/sbin/generate.pl.

Il faut signaler que toutes les règles de LDAP ne sont pas comprises par ce fichier de Parsing. Les règles admises sont de la forme :

access to dn="#DN auquel on veut accéder#"
       attrs=#liste des attributs séparés par une virgule#
       by dn="#DN de celui qui y accède#" #type d'accès#
       by dn="#DN de celui qui y accède#" #type d'accès#

Le type d'accès peut être none, read ou write.

Ceci est limité comparé à ce qu'il est possible de faire dans les fichiers de conf de OpenLDAP mais répond largement, à l'heure actuelle, aux nécessités du serveur.

Ce fichier contient la fonction de matching de règles. Elle permet de déterminer les droits d'un utilisateur sur un attribut d'une entrée.

Seuls les attributs écrivables sont conservés lors de la création/modification.

Fichier MyLDAP.pm

Ce fichier correspond à une classe qui permet l'accès à l'annuaire LDAP. Celle-ci est dérivée de Net::LDAPapi et doit-être utilisée dans le logiciel, aussi bien au niveau du noyau que des drivers qui ont besoin d'accéder à l'annuaire LDAP.

Il est utilisé par LDAP.pm.

Aujourd'hui, MyLDAP dérive de Net::LDAPapi. Il serait intéressant que MyLDAP délègue à Net::LDAPapi plutôt que d'en hériter

Déléguer : mécanisme par lequel un objet transfère une requête à un autre objet. Le délégué traite la requêtede la part de l'objet du mandant initial
. Ceci permettrait d'empêcher l'appel des fonctions asynchrones de la classe mère.

Voici un exemple d'utilisation :


    my $ldap = new Common::ldap::MyLDAP('localhost', 389);
    
    if ($ldap->bind_s($user_dn, $userpassword) != LDAP_SUCCESS)
    {
        print STDERR "Unable to connect to ldap server";
        print STDERR $ldap->errstring();
        exit(0);
    }

    # Try to add an entry
    my $hash_to_add = { 'username' => 'jeff',                                         # simple
                        'objectclass' => 'user',                                      # simple
                        'email' => [ 'jf@cur-archamps.fr' ],                          # array
                        'photo' => new Kernel::Analyze::File([$name, $contains]) };   # file

    my $res = $ldap->add_s($entry_dn_to_add, $hash_to_add);

    if ($res != LDAP_SUCCESS)
    {
        print STDERR "Unable to add the entry";
        print STDERR $ldap->errstring();
        exit(0);
    }
    
    # Try to modify an entry
    my $hash_to_mod = { 'email' => [ 'jeff@cur-archamps.fr' ],                        # replace the email address
                        'photo' => new Kernel::Analyze::File([$name, $contains]) };   # if $entry_dn_to_add == $entry_dn_to_mod

    my $res = $ldap->modify_s($entry_dn_to_mod, $hash_to_mod);

    if ($res != LDAP_SUCCESS)
    {
        print STDERR "Unable to modify the entry";
        print STDERR $ldap->errstring();
        exit(0);
    }

    # Search all photo of users (see Net::LDAPapi)
    # To see how create a LDAP search filter see lapd_search manual page
    my $res = $ldap->search_s($organization, LDAP_SCOPE_SUBTREE, "user=*", [ "user", "photo" ], 0);

    if ($res != LDAP_SUCCESS)
    {
        print STDERR "Unable to search";
        print STDERR $ldap->errstring();
        exit(0);
    }

    my $entry = $ldap->first_entry();
    my %hash = ();
    while ($entry)
    {
        my $dn = $ldap->get_dn();
        $hash{$dn} = {};
        print STDERR sprintf("Entry is %s ", $dn);
        my $attr_name = $ldap->first_attribute();
        while ($attr_name)
        {
            $hash{$dn}{$attr_name} = $ldap->get($attr_name);
            $attr_name = $ldap->next_attribute();
        }
        $entry = $ldap->next_entry();
    }

    # After that, we obtain a hash table indexed by user's DN
    # In each sub hashtables, user and/or photo attributes, with
    # value are present
    # WARNING : value in $hash{$a_dn}{'photo'} is a reference to
    # an object Kernel::Analyze::File

    $ldap->unbind();

Fichiers de /usr/lib/PingOO/perl5/Driver

Ce répertoire contient l'ensemble des drivers. Les drivers sont dans ce répertoire. Si un driver se compose de plusieurs modules, un répertoire de même nom est crée et les autres modules à ajouter seront dans ce nouveau répertoire.

Exemple :

|-- Kernel.pm
|-- MLM.pm
|-- Shutdown.pm
|-- UGM
|   |-- Structure
|   |   |-- Admin_Alias.pm
|   |   |-- Organization.pm
|   |   |-- People.pm
|   |   |-- User.pm
|   |   |-- UserGroup.pm
|   |   `-  User_Alias.pm
|   `-- Structure.pm
`-- UGM.pm 

3.3 Fonctionnement d'un driver

La méthode pour créer des drivers est simple. Un exemple de driver suit.


package Driver::Shutdown;

use strict;

use vars qw($VERSION);
use MLPkg;
use ErrorPkg;
use Kernel::Analyze::File;

my $ok;
my $mlpkg;
my $error;
my %prg_desc;

BEGIN
{
    $VERSION = '0.1';

    %prg_desc = ('Version' => $VERSION,
                 'Name' => 'Driver::Shutdown',
                 'Type' => 'driver',
                 'Author' => 'Jean-François Giraud',
                 'Date of creation' => '03/08/1999',
                 'Date of Modification' => '03/08/1999',
                 'License' => 'This Program is distributed under GNU GPL2 License',
                 'Copyright' => '(C) CRI - Archamps\n(C)Jean-François Giraud',
                 'Description' => "Driver to shutdown the computer"
                 );

    $ok = 0;    

    $mlpkg = new MLPkg(\%prg_desc);
    return unless (defined $mlpkg);

    $error = new ErrorPkg(\%prg_desc, $mlpkg);
    return unless (defined $error);
    $ok = 1;
}


sub GetList
{
    return ("Shutdown");
}


sub Shutdown
{
    my ($func, $param, $result) = @_;

    my $time;
    if (exists($param->{'timeout'}) && (defined $param->{'timeout'}) && ($param->{'timeout'} =~ /^\d+$/))
    {
        $time = $param->{'timeout'};
    }
    else
    {
        $time = 2;
    }

    $result->{'comment'} = 'La chaine de commentaires à envoyer'; 
    # par défaut, c'est une chaine vide
    
    $result->{'send'} = 'signed';  
    # Envoie la réponse seulement signée (autre cas 'crypted' (défaut))
    
    $result->{'result'} = { 'toto' => 'tata',
                            'tutu' => [ 'titi', 'grosminet' ],
                            'titi' => { 'key21' => 'bbb',
                            'key11' => { 'key12' => 'aaa' } },
                            'fichier' => new Kernel::Analyse::File([nom, valeur])
                            } ;
    # La table de hachage envoyée au client comme résultat

    return 1; 
    # si 1 est renvoyé, la réponse est considérée comme acceptée
    # si 0 est renvoyé, la réponse est considérée comme refusée. Dans ce cas, $error est utilisé pour
    # remplir automatiquement le commentaire à renvoyer au client
}

$ok;

Tout développeur peut donc programmer un nouveau driver très rapidement.

Avantages de cette méthode :

3.4 Description des fichiers de configuration de LDAP

Le fichier /usr/sbin/generate.pl du package pingoo_server permet de convertir les fichiers de configurations au format "PingOO" au format LDAP.

Ainsi:

                                generate.pl
        my_slapd.oc.conf.pingoo ------------> my_slapd.oc.conf
        my_slapd.at.conf.pingoo ------------> my_slapd.at.conf
                 rien           ------------> slapd.conf

Fichier /etc/openldap/my_slapd.at.conf.pingoo

Voici une portion de ce fichier :

 
attribute       objectclass                             cis:simple
attribute       description                             cis:simple
attribute       creation                                cis:simple 
attribute       expiration                              cis:simple 
attribute       modification                            cis:simple 
attribute       type                                    ces:array 
attribute       workaddress                             ces:array 
attribute       workphone                               ces:array 

Ce fichier présente des ':simple', ':array', ':file' en plus du fichier de configuration habituel de LDAP. Le script generate.pl créé le fichier /etc/openldap/my_slapd.at.conf sans ces extensions.

Ce fichier sert à déterminer la syntaxe des attributs de LDAP. La syntaxe peut être :

Dans le serveur PingOOd, seul est utilisé le type 'bin' pour déterminer si les données sont binaires. Si un attribut a une syntaxe différente de 'bin', elle est considérée comme du texte. En effet, pour lire des données binaires à partir le Net::LDAPapi, il faut utiliser la fonction get_values_len sinon, il faut utiliser la fonction get_values pour les données ascii.

Les extensions 'file', 'array', 'simple' permettent de spécifier qu'un attribut sera une valeur simple, un tableau ou bien un fichier. Les valeurs récupérées par Common::LDAP::Search seront donc un scalaire, une référence à un tableau ou un objet de type Kernel::Analyze::File. Le programmeur utilisera donc des objets de haut niveau définis dans le protocole.

Fichier /etc/openldap/my_slapd.oc.conf.pingoo

Voici une portion de ce fichier :

objectclass user
        requires
                objectclass,
                userpassword{<.*[mo]=skip>},
                active
        allows  
                username{<.*[mo]=skip>},
                webpassword{<.*[mo]=skip>},
                firstname,
                lastname,
                institution,
                uid,
                gid,
                gcos,

Ce fichier présente des extensions en plus du fichier de configuration habituel de LDAP. Celles-ci sont entre accolades à droite d'un attribut. Le script generate.pl créé le fichier /etc/openldap/my_slapd.oc.conf sans ces extensions.

Chaque option ajoutée est entre '<' et '>'. Par exemple, '<.*[mo]=skip>' est une option.

Une option est constituée d'une chaine à matcher, ici '.*' et d'une association des lettres 'c', 'o' ou 'm' entre crochets. La valeur associée peut être skip, keep, write ou read.

La chaine à matcher correspond à un identificateur qui devra être passé aux fonctions de Common::LDAP.pm si l'on désire effectuer un filtrage.

Les lettres signifient :

Les valeurs associées peuvent être :

Voici un exemple de succession de règles : la première matchée est conservée.

         photo{<TEXT[o]=skip>},

Ici, lorsque tous les attributs seront récupérés de la base LDAP, l'attribut photo ne sera pas gardé si l'identifiant est 'TEXT'. Ceci peut être utile si l'on désire économiser la bande passante, cacher des informations, etc.

Fichier /etc/openldap/slapd.conf

Ce fichier est relativement compliqué et est généré automatiquement par generate.pl.

Pour plus de détails, se référer à la page de manuel de slapd.conf.

Ce fichier est très important. Ce sont les règles définies ici, ensuite matchées par le module Parsing.pm qui déterminent le type d'accès d'un utilisateur sur les attributs d'une entrée. Ainsi, c'est ce fichier-ci qui permet au serveur d'informer le client si les champs sont modifiables ou non (dans ce cas ils seront grisés dans l'interface).

Les lignes ajoutées et importantes sont :

Ensuite, il y a des groupement de trois règles :


access to dn="usergroup=([^,]*),people=([^,]*),organization=([^,]*),section=([^,]*),\
dept=([^,]*),c=([^,]*)"
        by dn="adminalias=[^,]*,usergroup=$1,people=$2,organization=$3,section=$4,\
dept=$5,c=$6" write
        by dn="adminalias=[^,]*,people=$2,organization=$3,section=$4,dept=$5,c=$6"\
 write
        by dn=".*,people=$2,organization=$3,section=$4,dept=$5,c=$6" read
        by dn="adminalias=master,organization=$3,section=$4,dept=$5,c=$6" write

access to dn="user=[^,]*,usergroup=([^,]*),people=([^,]*),organization=([^,]*),\
section=([^,]*),dept=([^,]*),c=([^,]*)"
        by dn="adminalias=[^,]*,usergroup=$1,people=$2,organization=$3,section=$4,\
dept=$5,c=$6" write
        by dn="adminalias=[^,]*,people=$2,organization=$3,section=$4,dept=$5,c=$6" write
        by dn=".*,people=$2,organization=$3,section=$4,dept=$5,c=$6" read
        by dn="adminalias=master,organization=$3,section=$4,dept=$5,c=$6" write

access to dn="useralias=[^,]*,usergroup=([^,]*),people=([^,]*),organization=([^,]*),\
section=([^,]*),dept=([^,]*),c=([^,]*)"
        by dn="adminalias=[^,]*,usergroup=$1,people=$2,organization=$3,section=$4,\
dept=$5,c=$6" write
        by dn="adminalias=[^,]*,people=$2,organization=$3,section=$4,dept=$5,c=$6" write
        by dn=".*,people=$2,organization=$3,section=$4,dept=$5,c=$6" read
        by dn="adminalias=master,organization=$3,section=$4,dept=$5,c=$6" write

Dans l'exemple, la première règle définie le type d'accès sur un groupe pour les administrateurs.

Dans l'exemple, la deuxième règle définie le type d'accès sur un utilisateur pour les administrateurs..

Dans l'exemple, la troisième règle définie le type d'accès sur un alias utilisateur pour les administrateurs.

Ces règles utilisent le principe du matching et permettent entre autre la délégation.

Par exemple :


access to dn="uid=.*,ou=([^,]*),o=([^,]*),c=([^,]*)"
        by dn="uid=admin,ou=$1,o=$2,c=$3" write
        by dn="uid=.*,o=$2,c=$3" read
        by dn=".*" none

permet à l'administrateur "uid=admin,ou=profs,o=lycee,c=fr" de modifier l'utilisateur "uid=durand,ou=profs,o=lycee,c=fr" mais pas l'utilisateur "uid=dupont,ou=eleves,o=lycee,c=fr".

3.5 Description du fonctionnement du driver UGM

Arborescence

-- UGM
|   |-- Structure
|   |   |-- Admin_Alias.pm      => administrateur
|   |   |-- Organization.pm     => organisation
|   |   |-- People.pm           => noeud people
|   |   |-- User.pm             => utilisateur
|   |   |-- UserGroup.pm        => groupe (noeud, groupe final, groupe final de travail)
|   |   `-- User_Alias.pm       => alias utilisateur
|   `-- Structure.pm            => chargement dynamique des modules du répertoire Structure

Fonctionnement général

Les fonctions appelables du driver UGM sont les suivantes :

Les fonctions Add, Modify, Delete et Move sont communes pour l'ajout, modification, supression et déplacement des groupes (usergroup), utilisateurs (user), administrateurs (adminalias) et alias utilisateurs (useralias).

Elles utilisent une fonction commune nommée Call qui se charge d'appeler la fonction de l'objet concerné.

La fonction Call effectue donc certains pré-traitements comme la détermination de l'objet (...), utilise une table de hachage initialisée au lancement (dans la clause BEGIN) du programme et appelle la bonne fonction si elle existe.


if (exists($pfunc{$function}{$objectclass}))
{
   # CODE 1 
   ...
   my $res = &{$pfunc{$function}{$objectclass}}($ldap, $dn, $func, $param);
   ...
}
else 
{  
   # CODE 2
   ...
}

Par exemple, supposons que l'on désire supprimer un utilisateur, le programme teste si $pfunc{'Delete'}{'user'} existe. Si c'est le cas, on l'appel ensuite.

Remarques

Le driver UGM repose fortement sur les bibliothèques Common::ldap::MyLDAP et Common::ldap::Parse.

Pour plus de détails, il faudra regarder le code. Une fois compris le fonctionnement général d'UGM, il ne devrait pas y avoir de gros problèmes.