- LSerror : Déclaration des messages d'erreurs avec la méthode statique
[ldapsaisie.git] / trunk / includes / class / class.LSsession.php
1 <?php
2 /*******************************************************************************
3  * Copyright (C) 2007 Easter-eggs
4  * http://ldapsaisie.labs.libre-entreprise.org
5  *
6  * Author: See AUTHORS file in top-level directory.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 ******************************************************************************/
22
23 define('LS_DEFAULT_CONF_DIR','conf');
24 require_once 'includes/functions.php';
25
26 /**
27  * Gestion des sessions
28  *
29  * Cette classe gère les sessions d'utilisateurs.
30  *
31  * @author Benjamin Renard <brenard@easter-eggs.com>
32  */
33 class LSsession {
34
35   // La configuration du serveur Ldap utilisé
36   public static $ldapServer = NULL;
37   
38   // L'id du serveur Ldap utilisé
39   private static $ldapServerId = NULL;
40   
41   // Le topDn courant
42   private static $topDn = NULL;
43   
44   // Le DN de l'utilisateur connecté
45   private static $dn = NULL;
46   
47   // Le RDN de l'utilisateur connecté (son identifiant)
48   private static $rdn = NULL;
49   
50   // Les LSprofiles de l'utilisateur
51   private static $LSprofiles = array();
52   
53   // Les droits d'accès de l'utilisateur
54   private static $LSaccess = array();
55   
56   // Les fichiers temporaires
57   private static $tmp_file = array();
58   
59   /*
60    * Constante de classe non stockée en session
61    */
62   // Le template à afficher
63   private static $template = NULL;
64   
65   // Les subDn des serveurs Ldap
66   private static $_subDnLdapServer = array();
67   
68   // Affichage Ajax
69   private static $ajaxDisplay = false;
70
71   // Les fichiers JS à charger dans la page
72   private static $JSscripts = array();
73   
74   // Les paramètres JS à communiquer dans la page
75   private static $_JSconfigParams = array();
76   
77   // Les fichiers CSS à charger dans la page
78   private static $CssFiles = array();
79
80   // L'objet de l'utilisateur connecté
81   private static $LSuserObject = NULL;
82
83  /**
84   * Include un fichier PHP
85   *
86   * @author Benjamin Renard <brenard@easter-eggs.com>
87   *
88   * @retval true si tout c'est bien passé, false sinon
89   */
90   public static function includeFile($file) {
91     if (!file_exists($file)) {
92       return;
93     }
94     if ($GLOBALS['LSdebug']['active']) {
95       return include_once($file);
96     }
97     else {
98       return @include_once($file);
99     }
100     return;
101   }
102
103  /**
104   * Chargement de la configuration
105   *
106   * Chargement des fichiers de configuration et création de l'objet Smarty.
107   *
108   * @author Benjamin Renard <brenard@easter-eggs.com>
109   *
110   * @retval true si tout c'est bien passé, false sinon
111   */
112   private static function loadConfig() {
113     if (loadDir(LS_DEFAULT_CONF_DIR, '^config\..*\.php$')) {
114       if ( self :: includeFile($GLOBALS['LSconfig']['Smarty']) ) {
115         $GLOBALS['Smarty'] = new Smarty();
116         $GLOBALS['Smarty'] -> template_dir = LS_TEMPLATES_DIR;
117         $GLOBALS['Smarty'] -> compile_dir = LS_TMP_DIR;
118         
119         $GLOBALS['Smarty'] -> assign('LS_CSS_DIR',LS_CSS_DIR);
120         $GLOBALS['Smarty'] -> assign('LS_IMAGES_DIR',LS_IMAGES_DIR);
121         
122         self :: addJSconfigParam('LS_IMAGES_DIR',LS_IMAGES_DIR);
123         return true;
124       }
125       else {
126         die("ERROR : Can't load configuration file.");
127         return;
128       }
129       return true;
130     }
131     else {
132       return;
133     }
134     
135   }
136   
137   public static function getTopDn() {
138     return self :: $topDn;
139   }
140
141  /**
142   * Initialisation de la gestion des erreurs
143   *
144   * Création de l'objet LSerror
145   *
146   * @author Benjamin Renard <brenard@easter-eggs.com
147   *
148   * @retval boolean true si l'initialisation a réussi, false sinon.
149   */
150   private static function startLSerror() {
151     if(!self :: loadLSclass('LSerror')) {
152       return;
153     }
154     self :: defineLSerrors();
155     return true;
156   }
157
158  /**
159   * Chargement d'une classe d'LdapSaisie
160   *
161   * @param[in] $class Nom de la classe Ã  charger (Exemple : LSeepeople)
162   * @param[in] $type (Optionnel) Type de classe Ã  charger (Exemple : LSobjects)
163   *
164   * @author Benjamin Renard <brenard@easter-eggs.com
165   * 
166   * @retval boolean true si le chargement a réussi, false sinon.
167   */
168   public static function loadLSclass($class,$type='') {
169     if (class_exists($class))
170       return true;
171     if($type!='')
172       $type=$type.'.';
173     return self :: includeFile(LS_CLASS_DIR .'class.'.$type.$class.'.php');
174   }
175
176  /**
177   * Chargement d'un object LdapSaisie
178   *
179   * @param[in] $object Nom de l'objet Ã  charger
180   *
181   * @retval boolean true si le chargement a réussi, false sinon.
182   */
183   public static function loadLSobject($object) {
184     $error = 0;
185     self :: loadLSclass('LSldapObject');
186     if (!self :: loadLSclass($object,'LSobjects')) {
187       $error = 1;
188     }
189     if (!self :: includeFile( LS_OBJECTS_DIR . 'config.LSobjects.'.$object.'.php' )) {
190       $error = 1;
191     }
192     if ($error) {
193       LSerror :: addErrorCode('LSsession_04',$object);
194       return;
195     }
196     return true;
197   }
198
199  /**
200   * Chargement d'un addons d'LdapSaisie
201   *
202   * @param[in] $addon Nom de l'addon Ã  charger (Exemple : samba)
203   *
204   * @author Benjamin Renard <brenard@easter-eggs.com
205   * 
206   * @retval boolean true si le chargement a réussi, false sinon.
207   */
208   public static function loadLSaddon($addon) {
209     if(self :: includeFile(LS_ADDONS_DIR .'LSaddons.'.$addon.'.php')) {
210       self :: includeFile(LS_CONF_DIR."LSaddons/config.LSaddons.".$addon.".php");
211       if (!call_user_func('LSaddon_'. $addon .'_support')) {
212         LSerror :: addErrorCode('LSsession_02',$addon);
213         return;
214       }
215       return true;
216     }
217     return;
218   }
219
220  /**
221   * Chargement des addons LdapSaisie
222   *
223   * Chargement des LSaddons contenue dans la variable
224   * $GLOBALS['LSaddons']['loads']
225   *
226   * @retval boolean true si le chargement a réussi, false sinon.
227   */
228   public static function loadLSaddons() {
229     if(!is_array($GLOBALS['LSaddons']['loads'])) {
230       LSerror :: addErrorCode('LSsession_01',"LSaddons['loads']");
231       return;
232     }
233
234     foreach ($GLOBALS['LSaddons']['loads'] as $addon) {
235       self :: loadLSaddon($addon);
236     }
237     return true;
238   }
239
240 /**
241   * Initialisation LdapSaisie
242   *
243   * @retval boolean True si l'initialisation à réussi, false sinon.
244   */
245   public static function initialize() {
246     if (!self :: loadConfig()) {
247       return;
248     }   
249     self :: startLSerror();
250     self :: loadLSaddons();
251     return true;
252   }
253
254  /**
255   * Initialisation de la session LdapSaisie
256   *
257   * Initialisation d'une LSsession :
258   * - Authentification et activation du mécanisme de session de LdapSaisie
259   * - ou Chargement des paramètres de la session Ã  partir de la variable 
260   *   $_SESSION['LSsession'].
261   * - ou Destruction de la session en cas de $_GET['LSsession_logout'].
262   *
263   * @retval boolean True si l'initialisation Ã  réussi (utilisateur authentifié), false sinon.
264   */
265   public static function startLSsession() {
266     if (!self :: initialize()) {
267       return;
268     }   
269
270     session_start();
271
272     // Déconnexion
273     if (isset($_GET['LSsession_logout'])||isset($_GET['LSsession_recoverPassword'])) {
274       session_destroy();
275       
276       if (is_array($_SESSION['LSsession']['tmp_file'])) {
277         self :: $tmp_file = $_SESSION['LSsession']['tmp_file'];
278       }
279       self :: deleteTmpFile();
280       unset($_SESSION['LSsession']);
281     }
282     
283     // Récupération de mot de passe
284     if (isset($_GET['recoveryHash'])) {
285       $_POST['LSsession_user'] = 'a determiner plus tard';
286     }
287     
288     if(isset($_SESSION['LSsession'])) {
289       // Session existante
290       self :: $topDn        = $_SESSION['LSsession']['topDn'];
291       self :: $dn           = $_SESSION['LSsession']['dn'];
292       self :: $rdn          = $_SESSION['LSsession']['rdn'];
293       self :: $ldapServerId = $_SESSION['LSsession']['ldapServerId'];
294       self :: $tmp_file     = $_SESSION['LSsession']['tmp_file'];
295       
296       if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) {
297         self :: setLdapServer(self :: $ldapServerId);
298         self :: $LSprofiles   = $_SESSION['LSsession']['LSprofiles'];
299         self :: $LSaccess   = $_SESSION['LSsession']['LSaccess'];
300         if (!self :: LSldapConnect())
301           return;
302       }
303       else {
304         self :: setLdapServer(self :: $ldapServerId);
305         if (!self :: LSldapConnect())
306           return;
307         self :: loadLSprofiles();
308       }
309       
310       if ( self :: cacheSudDn() && (!isset($_REQUEST['LSsession_refresh'])) ) {
311         self :: $_subDnLdapServer = $_SESSION['LSsession_subDnLdapServer'];
312       }
313       
314       if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
315         return;
316       }
317       
318       self :: getLSuserObject();
319       
320       if ( !self :: cacheLSprofiles() || isset($_REQUEST['LSsession_refresh']) ) {
321         self :: loadLSaccess();
322       }
323       
324       $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
325       
326       if ($_POST['LSsession_topDn']) {
327         if (self :: validSubDnLdapServer($_POST['LSsession_topDn'])) {
328           self :: $topDn = $_POST['LSsession_topDn'];
329           $_SESSION['LSsession']['topDn'] = $_POST['LSsession_topDn'];
330         } // end if
331       } // end if
332       
333       return true;
334       
335     }
336     else {
337       // Session inexistante
338       $recoveryPasswordInfos=array();
339
340       if (isset($_POST['LSsession_user'])) {
341         if (isset($_POST['LSsession_ldapserver'])) {
342           self :: setLdapServer($_POST['LSsession_ldapserver']);
343         }
344         else {
345           self :: setLdapServer(0);
346         }
347         
348         // Connexion au serveur LDAP
349         if (self :: LSldapConnect()) {
350
351           // topDn
352           if ( $_POST['LSsession_topDn'] != '' ){
353             self :: $topDn = $_POST['LSsession_topDn'];
354           }
355           else {
356             self :: $topDn = self :: $ldapServer['ldap_config']['basedn'];
357           }
358           $_SESSION['LSsession_topDn']=self :: $topDn;
359
360           if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) {
361             $authobject = new self :: $ldapServer['authObjectType']();
362             $find=true;
363             if (isset($_GET['recoveryHash'])) {
364               $filter=self :: $ldapServer['recoverPassword']['recoveryHashAttr']."=".$_GET['recoveryHash'];
365               $result = $authobject -> listObjects($filter,self :: $topDn);
366               $nbresult=count($result);
367               if ($nbresult==1) {
368                 $rdn = $result[0] -> getValue('rdn');
369                 $rdn = $rdn[0];
370                 $_POST['LSsession_user'] = $rdn;
371                 $find=false;
372               }
373             }
374             if ($find) {
375               $result = $authobject -> searchObject($_POST['LSsession_user'],self :: $topDn);
376               $nbresult=count($result);
377             }
378             if ($nbresult==0) {
379               // identifiant incorrect
380               LSdebug('identifiant incorrect');
381               LSerror :: addErrorCode('LSsession_06');
382             }
383             else if ($nbresult>1) {
384               // duplication d'authentité
385               LSerror :: addErrorCode('LSsession_07');
386             }
387             else {
388               if (isset($_GET['LSsession_recoverPassword'])) {
389                 LSdebug('Recover : Id trouvé');
390                 if (self :: $ldapServer['recoverPassword']) {
391                   if (self :: loadLSaddon('mail')) {
392                     LSdebug('Récupération active');
393                     $user=$result[0];
394                     $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
395                     $emailAddress = $emailAddress[0];
396                     
397                     // Header des mails
398                     $sendParams=array();
399                     if (self :: $ldapServer['recoverPassword']['recoveryEmailSender']) {
400                       $sendParams['From']=self :: $ldapServer['recoverPassword']['recoveryEmailSender'];
401                     }
402                     
403                     if (checkEmail($emailAddress)) {
404                       LSdebug('Email : '.$emailAddress);
405                       self :: $dn = $user -> getDn();
406                       // 1ère étape : envoie du recoveryHash
407                       if (!isset($_GET['recoveryHash'])) {
408                         // Generer un hash
409                         $rdn=$user -> getValue('rdn');
410                         $rdn = $rdn[0];
411                         $recovery_hash = md5($rdn . strval(time()) . strval(rand()));
412                         
413                         $lostPasswdForm = $user -> getForm('lostPassword');
414                         $lostPasswdForm -> setPostData(
415                           array(
416                             self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => $recovery_hash
417                           )
418                           ,true
419                         );
420                         
421                         if($lostPasswdForm -> validate()) {
422                           if ($user -> updateData('lostPassword')) {
423                             // recoveryHash de l'utilisateur mis à jour
424                             if ($_SERVER['HTTPS']=='on') {
425                               $recovery_url='https://';
426                             }
427                             else {
428                               $recovery_url='http://';
429                             }
430                             $recovery_url .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'&recoveryHash='.$recovery_hash;
431
432                             if (
433                               sendMail(
434                                 $emailAddress,
435                                 self :: $ldapServer['recoverPassword']['recoveryHashMail']['subject'],
436                                 getFData(self :: $ldapServer['recoverPassword']['recoveryHashMail']['msg'],$recovery_url),
437                                 $sendParams
438                               )
439                             ){
440                               // Mail a bien été envoyé
441                               $recoveryPasswordInfos['recoveryHashMail']=$emailAddress;
442                             }
443                             else {
444                               // Problème durant l'envoie du mail
445                               LSdebug("Problème durant l'envoie du mail");
446                               LSerror :: addErrorCode('LSsession_20',7);
447                             }
448                           }
449                           else {
450                             // Erreur durant la mise à jour de l'objet
451                             LSdebug("Erreur durant la mise à jour de l'objet");
452                             LSerror :: addErrorCode('LSsession_20',6);
453                           }
454                         }
455                         else {
456                           // Erreur durant la validation du formulaire de modification de perte de password
457                           LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
458                           LSerror :: addErrorCode('LSsession_20',5);
459                         }
460                       }
461                       // 2nd étape : génération du mot de passe + envoie par mail
462                       else {
463                         $attr=$user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']];
464                         if ($attr instanceof LSattribute) {
465                           $mdp = generatePassword($attr -> config['html_options']['chars'],$attr -> config['html_options']['lenght']);
466                           LSdebug('Nvx mpd : '.$mdp);
467                           $lostPasswdForm = $user -> getForm('lostPassword');
468                           $lostPasswdForm -> setPostData(
469                             array(
470                               self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
471                               self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp)
472                             )
473                             ,true
474                           );
475                           if($lostPasswdForm -> validate()) {
476                             if ($user -> updateData('lostPassword')) {
477                               if (
478                                 sendMail(
479                                   $emailAddress,
480                                   self :: $ldapServer['recoverPassword']['newPasswordMail']['subject'],
481                                   getFData(self :: $ldapServer['recoverPassword']['newPasswordMail']['msg'],$mdp),
482                                   $sendParams
483                                 )
484                               ){
485                                 // Mail a bien été envoyé
486                                 $recoveryPasswordInfos['newPasswordMail']=$emailAddress;
487                               }
488                               else {
489                                 // Problème durant l'envoie du mail
490                                 LSdebug("Problème durant l'envoie du mail");
491                                 LSerror :: addErrorCode('LSsession_20',4);
492                               }
493                             }
494                             else {
495                               // Erreur durant la mise à jour de l'objet
496                               LSdebug("Erreur durant la mise à jour de l'objet");
497                               LSerror :: addErrorCode('LSsession_20',3);
498                             }
499                           }
500                           else {
501                             // Erreur durant la validation du formulaire de modification de perte de password
502                             LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
503                             LSerror :: addErrorCode('LSsession_20',2);
504                           }
505                         }
506                         else {
507                           // l'attribut password n'existe pas
508                           LSdebug("L'attribut password n'existe pas");
509                           LSerror :: addErrorCode('LSsession_20',1);
510                         }
511                       }
512                     }
513                     else {
514                       LSerror :: addErrorCode('LSsession_19');
515                     }
516                   }
517                 }
518                 else {
519                   LSerror :: addErrorCode('LSsession_18');
520                 }
521               }
522               else {
523                 if ( self :: checkUserPwd($result[0],$_POST['LSsession_pwd']) ) {
524                   // Authentification réussi
525                   self :: $LSuserObject = $result[0];
526                   self :: $dn = $result[0]->getValue('dn');
527                   self :: $rdn = $_POST['LSsession_user'];
528                   self :: loadLSprofiles();
529                   self :: loadLSaccess();
530                   $GLOBALS['Smarty'] -> assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
531                   $_SESSION['LSsession']=self :: getContextInfos();
532                   return true;
533                 }
534                 else {
535                   LSerror :: addErrorCode('LSsession_06');
536                   LSdebug('mdp incorrect');
537                 }
538               }
539             }
540           }
541           else {
542             LSerror :: addErrorCode('LSsession_10');
543           }
544         }
545         else {
546           LSerror :: addErrorCode('LSsession_09');
547         }
548       }
549       if (self :: $ldapServerId) {
550         $GLOBALS['Smarty'] -> assign('ldapServerId',self :: $ldapServerId);
551       }
552       $GLOBALS['Smarty'] -> assign('topDn',self :: $topDn);
553       if (isset($_GET['LSsession_recoverPassword'])) {
554         self :: displayRecoverPasswordForm($recoveryPasswordInfos);
555       }
556       else {
557         self :: displayLoginForm();
558       }
559       return;
560     }
561   }
562   
563  /**
564   * Retourne les informations du contexte
565   *
566   * @author Benjamin Renard <brenard@easter-eggs.com
567   * 
568   * @retval array Tableau associatif des informations du contexte
569   */
570   private static function getContextInfos() {
571     return array(
572       'tmp_file' => self :: $tmp_file,
573       'topDn' => self :: $topDn,
574       'dn' => self :: $dn,
575       'rdn' => self :: $rdn,
576       'ldapServerId' => self :: $ldapServerId,
577       'ldapServer' => self :: $ldapServer,
578       'LSprofiles' => self :: $LSprofiles,
579       'LSaccess' => self :: $LSaccess
580     );
581   }
582   
583   /**
584   * Retourne l'objet de l'utilisateur connecté
585   *
586   * @author Benjamin Renard <brenard@easter-eggs.com
587   * 
588   * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
589   *               être créé
590   */
591   public static function getLSuserObject($dn=null) {
592     if ($dn) {
593       self :: $dn = $dn;
594     }
595     if (!self :: $LSuserObject) {
596       if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
597         self :: $LSuserObject = new self :: $ldapServer['authObjectType']();
598         self :: $LSuserObject -> loadData(self :: $dn);
599       }
600       else {
601         return;
602       }
603     }
604     return self :: $LSuserObject;
605   }
606   
607  /**
608   * Retourne le DN de l'utilisateur connecté
609   *
610   * @author Benjamin Renard <brenard@easter-eggs.com
611   * 
612   * @retval string Le DN de l'utilisateur connecté
613   */
614   public static function getLSuserObjectDn() {
615     return self :: $dn;
616   }
617
618  /**
619   * Modifie l'utilisateur connecté à la volé
620   * 
621   * @param[in] $object Mixed  L'objet Ldap du nouvel utilisateur
622   *                           le type doit correspondre à
623   *                           self :: $ldapServer['authObjectType']
624   * 
625   * @retval boolean True en cas de succès, false sinon
626   */
627  public static function changeAuthUser($object) {
628   if ($object instanceof self :: $ldapServer['authObjectType']) {
629     self :: $dn = $object -> getDn();
630     $rdn = $object -> getValue('rdn');
631     if(is_array($rdn)) {
632       $rdn = $rdn[0];
633     }
634     self :: $rdn = $rdn;
635     self :: $LSuserObject = $object;
636     
637     if(self :: loadLSprofiles()) {
638       self :: loadLSaccess();
639       $_SESSION['LSsession']=self :: getContextInfos();
640       return true;
641     }
642   }
643   return;
644  }
645
646  /**
647   * Définition du serveur Ldap de la session
648   *
649   * Définition du serveur Ldap de la session Ã  partir de son ID dans 
650   * le tableau $GLOBALS['LSconfig']['ldap_servers'].
651   *
652   * @param[in] integer Index du serveur Ldap
653   *
654   * @retval boolean True sinon false.
655   */
656   public static function setLdapServer($id) {
657     if ( isset($GLOBALS['LSconfig']['ldap_servers'][$id]) ) {
658       self :: $ldapServerId = $id;
659       self :: $ldapServer=$GLOBALS['LSconfig']['ldap_servers'][$id];
660       return true;
661     }
662     else {
663       return;
664     }
665   }
666
667  /**
668   * Connexion au serveur Ldap
669   *
670   * @retval boolean True sinon false.
671   */
672   public static function LSldapConnect() {
673     if (self :: $ldapServer) {
674       self :: includeFile($GLOBALS['LSconfig']['NetLDAP2']);
675       if (!self :: loadLSclass('LSldap')) {
676         return;
677       }
678       LSldap :: connect(self :: $ldapServer['ldap_config']);
679       if (LSldap :: isConnected()) {
680         return true;
681       }
682       else {
683         return;
684       }
685     }
686     else {
687       LSerror :: addErrorCode('LSsession_03');
688       return;
689     }
690   }
691
692  /**
693   * Retourne les sous-dns du serveur Ldap courant
694   *
695   * @retval mixed Tableau des subDn, false si une erreur est survenue.
696   */
697   public static function getSubDnLdapServer() {
698     if (self :: cacheSudDn() && isset(self :: $_subDnLdapServer[self :: $ldapServerId])) {
699       return self :: $_subDnLdapServer[self :: $ldapServerId];
700     }
701     if (!isset(self :: $ldapServer['subDn'])) {
702       return;
703     }
704     if ( !is_array(self :: $ldapServer['subDn']) ) {
705       return;
706     }
707     $return=array();
708     foreach(self :: $ldapServer['subDn'] as $subDn_name => $subDn_config) {
709       if ($subDn_name == 'LSobject') {
710         if (is_array($subDn_config)) {
711           foreach($subDn_config as $LSobject_name => $LSoject_config) {
712             if ($LSoject_config['basedn']) {
713               $basedn = $LSoject_config['basedn'];
714             }
715             else {
716               $basedn = NULL;
717             }
718             if ($LSoject_config['displayName']) {
719               $displayName = $LSoject_config['displayName'];
720             }
721             else {
722               $displayName = NULL;
723             }
724             if( self :: loadLSobject($LSobject_name) ) {
725               if ($subdnobject = new $LSobject_name()) {
726                 $tbl_return = $subdnobject -> getSelectArray(NULL,$basedn,$displayName);
727                 if (is_array($tbl_return)) {
728                   $return=array_merge($return,$tbl_return);
729                 }
730                 else {
731                   LSerror :: addErrorCode('LSsession_17',3);
732                 }
733               }
734               else {
735                 LSerror :: addErrorCode('LSsession_17',2);
736               }
737             }
738           }
739         }
740         else {
741           LSerror :: addErrorCode('LSsession_17',1);
742         }
743       }
744       else {
745         if ((isCompatibleDNs($subDn_config['dn'],self :: $ldapServer['ldap_config']['basedn']))&&($subDn_config['dn']!="")) {
746           $return[$subDn_config['dn']] = $subDn_name;
747         }
748       }
749     }
750     if (self :: cacheSudDn()) {
751       self :: $_subDnLdapServer[self :: $ldapServerId]=$return;
752       $_SESSION['LSsession_subDnLdapServer'] = self :: $_subDnLdapServer;
753     }
754     return $return;
755   }
756   
757   /**
758    * Retourne la liste de subDn du serveur Ldap utilise
759    * trié par la profondeur dans l'arboressence (ordre décroissant)
760    * 
761    * @return array() Tableau des subDn trié
762    */  
763   public static function getSortSubDnLdapServer() {
764     $subDnLdapServer = self :: getSubDnLdapServer();
765     if (!$subDnLdapServer) {
766       return array();
767     }
768     uksort($subDnLdapServer,"compareDn");
769     return $subDnLdapServer;
770   }
771
772  /**
773   * Retourne les options d'une liste déroulante pour le choix du topDn
774   * de connexion au serveur Ldap
775   *
776   * Liste les subdn (self :: $ldapServer['subDn'])
777   *
778   * @retval string Les options (<option>) pour la sélection du topDn.
779   */
780   public static function getSubDnLdapServerOptions($selected=NULL) {
781     $list = self :: getSubDnLdapServer();
782     if ($list) {
783       asort($list);
784       $display='';
785       foreach($list as $dn => $txt) {
786         if ($selected && ($selected==$dn)) {
787           $selected_txt = ' selected';
788         }
789         else {
790           $selected_txt = '';
791         }
792         $display.="<option value=\"".$dn."\"$selected_txt>".$txt."</option>\n"; 
793       }
794       return $display;
795     }
796     return;
797   }
798
799  /**
800   * Vérifie qu'un subDn est déclaré
801   *
802   * @param[in] string Un subDn
803   * 
804   * @retval boolean True si le subDn existe, False sinon
805   */
806   public static function validSubDnLdapServer($subDn) {
807     $listTopDn = self :: getSubDnLdapServer();
808     if(is_array($listTopDn)) {
809       foreach($listTopDn as $dn => $txt) {
810         if ($subDn==$dn) {
811           return true;
812         } // end if
813       } // end foreach
814     } // end if
815     return;
816   }
817
818  /**
819   * Test un couple LSobject/pwd
820   *
821   * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni.
822   *
823   * @param[in] LSobject L'object "user" pour l'authentification
824   * @param[in] string Le mot de passe Ã  tester
825   *
826   * @retval boolean True si l'authentification Ã  réussi, false sinon.
827   */
828   public static function checkUserPwd($object,$pwd) {
829     return LSldap :: checkBind($object -> getValue('dn'),$pwd);
830   }
831
832  /**
833   * Affiche le formulaire de login
834   *
835   * Défini les informations pour le template Smarty du formulaire de login.
836   *
837   * @retval void
838   */
839   public static function displayLoginForm() {
840     $GLOBALS['Smarty'] -> assign('pagetitle',_('Connexion'));
841     if (isset($_GET['LSsession_logout'])) {
842       $GLOBALS['Smarty'] -> assign('loginform_action','index.php');
843     }
844     else {
845       $GLOBALS['Smarty'] -> assign('loginform_action',$_SERVER['REQUEST_URI']);
846     }
847     if (count($GLOBALS['LSconfig']['ldap_servers'])==1) {
848       $GLOBALS['Smarty'] -> assign('loginform_ldapserver_style','style="display: none"');
849     }
850     $GLOBALS['Smarty'] -> assign('loginform_label_ldapserver',_('Serveur LDAP'));
851     $ldapservers_name=array();
852     $ldapservers_index=array();
853     foreach($GLOBALS['LSconfig']['ldap_servers'] as $id => $infos) {
854       $ldapservers_index[]=$id;
855       $ldapservers_name[]=$infos['name'];
856     }
857     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_name',$ldapservers_name);
858     $GLOBALS['Smarty'] -> assign('loginform_ldapservers_index',$ldapservers_index);
859
860     $GLOBALS['Smarty'] -> assign('loginform_label_level',_('Niveau'));
861     $GLOBALS['Smarty'] -> assign('loginform_label_user',_('Identifiant'));
862     $GLOBALS['Smarty'] -> assign('loginform_label_pwd',_('Mot de passe'));
863     $GLOBALS['Smarty'] -> assign('loginform_label_submit',_('Connexion'));
864     $GLOBALS['Smarty'] -> assign('loginform_label_recoverPassword',_('Mot de passe oublié ?'));
865     
866     self :: setTemplate('login.tpl');
867     self :: addJSscript('LSsession_login.js');
868   }
869
870  /**
871   * Affiche le formulaire de récupération de mot de passe
872   *
873   * Défini les informations pour le template Smarty du formulaire de 
874   * récupération de mot de passe
875   * 
876   * @param[in] $infos array() Information sur le status du processus de 
877   *                           recouvrement de mot de passe
878   *
879   * @retval void
880   */
881   public static function displayRecoverPasswordForm($recoveryPasswordInfos) {
882     $GLOBALS['Smarty'] -> assign('pagetitle',_('Récupération de votre mot de passe'));
883     $GLOBALS['Smarty'] -> assign('recoverpasswordform_action','index.php?LSsession_recoverPassword');
884     
885     if (count($GLOBALS['LSconfig']['ldap_servers'])==1) {
886       $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapserver_style','style="display: none"');
887     }
888     
889     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_ldapserver',_('Serveur LDAP'));
890     $ldapservers_name=array();
891     $ldapservers_index=array();
892     foreach($GLOBALS['LSconfig']['ldap_servers'] as $id => $infos) {
893       $ldapservers_index[]=$id;
894       $ldapservers_name[]=$infos['name'];
895     }
896     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_name',$ldapservers_name);
897     $GLOBALS['Smarty'] -> assign('recoverpasswordform_ldapservers_index',$ldapservers_index);
898
899     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_user',_('Identifiant'));
900     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_submit',_('Valider'));
901     $GLOBALS['Smarty'] -> assign('recoverpasswordform_label_back',_('Retour'));
902     
903     $recoverpassword_msg = _('Veuillez saisir votre identifiant pour poursuivre le processus de récupération de votre mot de passe');
904     
905     if (isset($recoveryPasswordInfos['recoveryHashMail'])) {
906       $recoverpassword_msg = getFData(
907         _("Un mail vient de vous être envoyé à l'adresse %{mail}. " .
908         "Merci de suivre les indications contenus dans ce mail."),
909         $recoveryPasswordInfos['recoveryHashMail']
910       );
911     }
912     
913     if (isset($recoveryPasswordInfos['newPasswordMail'])) {
914       $recoverpassword_msg = getFData(
915         _("Votre nouveau mot de passe vient de vous être envoyé à l'adresse %{mail}. "),
916         $recoveryPasswordInfos['newPasswordMail']
917       );
918     }
919     
920     $GLOBALS['Smarty'] -> assign('recoverpassword_msg',$recoverpassword_msg);
921     
922     self :: setTemplate('recoverpassword.tpl');
923     self :: addJSscript('LSsession_recoverPassword.js');
924   }
925
926  /**
927   * Défini le template Smarty Ã  utiliser
928   *
929   * Remarque : les fichiers de templates doivent se trouver dans le dossier 
930   * templates/.
931   *
932   * @param[in] string Le nom du fichier de template
933   *
934   * @retval void
935   */
936   public static function setTemplate($template) {
937     self :: $template = $template;
938   }
939
940  /**
941   * Ajoute un script JS au chargement de la page
942   *
943   * Remarque : les scripts doivents Ãªtre dans le dossier LS_JS_DIR.
944   *
945   * @param[in] $script Le nom du fichier de script Ã  charger.
946   *
947   * @retval void
948   */
949   public static function addJSscript($file,$path=NULL) {
950     $script=array(
951       'file' => $file,
952       'path' => $path
953     );
954     self :: $JSscripts[$path.$file]=$script;
955   }
956
957  /**
958   * Ajouter un paramètre de configuration Javascript
959   * 
960   * @param[in] $name string Nom de la variable de configuration
961   * @param[in] $val mixed Valeur de la variable de configuration
962   *
963   * @retval void
964   */
965   public static function addJSconfigParam($name,$val) {
966     self :: $_JSconfigParams[$name]=$val;
967   }
968
969  /**
970   * Ajoute une feuille de style au chargement de la page
971   *
972   * Remarque : les scripts doivents Ãªtre dans le dossier LS_CSS_DIR.
973   *
974   * @param[in] $script Le nom du fichier css Ã  charger.
975   *
976   * @retval void
977   */
978   public static function addCssFile($file,$path=NULL) {
979     $cssFile=array(
980       'file' => $file,
981       'path' => $path
982     );
983     self :: $CssFiles[$path.$file]=$cssFile;
984   }
985
986  /**
987   * Affiche le template Smarty
988   *
989   * Charge les dépendances et affiche le template Smarty
990   *
991   * @retval void
992   */
993   public static function displayTemplate() {
994     // JS
995     $JSscript_txt='';
996     foreach ($GLOBALS['defaultJSscipts'] as $script) {
997       $JSscript_txt.="<script src='".LS_JS_DIR.$script."' type='text/javascript'></script>\n";
998     }
999
1000     foreach (self :: $JSscripts as $script) {
1001       if (!$script['path']) {
1002         $script['path']=LS_JS_DIR;
1003       }
1004       else {
1005         $script['path'].='/';
1006       }
1007       $JSscript_txt.="<script src='".$script['path'].$script['file']."' type='text/javascript'></script>\n";
1008     }
1009
1010     $GLOBALS['Smarty'] -> assign('LSjsConfig',json_encode(self :: $_JSconfigParams));
1011     
1012     if ($GLOBALS['LSdebug']['active']) {
1013       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 1;</script>\n";
1014     }
1015     else {
1016       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 0;</script>\n";
1017     }
1018     
1019     $GLOBALS['Smarty'] -> assign('LSsession_js',$JSscript_txt);
1020
1021     // Css
1022     self :: addCssFile("LSdefault.css");
1023     $Css_txt='';
1024     foreach (self :: $CssFiles as $file) {
1025       if (!$file['path']) {
1026         $file['path']=LS_CSS_DIR.'/';
1027       }
1028       $Css_txt.="<link rel='stylesheet' type='text/css' href='".$file['path'].$file['file']."' />\n";
1029     }
1030     $GLOBALS['Smarty'] -> assign('LSsession_css',$Css_txt);
1031   
1032     if (isset(self :: $LSaccess[self :: $topDn])) {
1033       $GLOBALS['Smarty'] -> assign('LSaccess',self :: $LSaccess[self :: $topDn]);
1034     }
1035     
1036     // Niveau
1037     $listTopDn = self :: getSubDnLdapServer();
1038     if (is_array($listTopDn)) {
1039       asort($listTopDn);
1040       $GLOBALS['Smarty'] -> assign('label_level',self :: getSubDnLabel());
1041       $GLOBALS['Smarty'] -> assign('_refresh',_('Rafraîchir'));
1042       $LSsession_topDn_index = array();
1043       $LSsession_topDn_name = array();
1044       foreach($listTopDn as $index => $name) {
1045         $LSsession_topDn_index[]  = $index;
1046         $LSsession_topDn_name[]   = $name;
1047       }
1048       $GLOBALS['Smarty'] -> assign('LSsession_subDn_indexes',$LSsession_topDn_index);
1049       $GLOBALS['Smarty'] -> assign('LSsession_subDn_names',$LSsession_topDn_name);
1050       $GLOBALS['Smarty'] -> assign('LSsession_subDn',self :: $topDn);
1051       $GLOBALS['Smarty'] -> assign('LSsession_subDnName',self :: getSubDnName());
1052     }
1053
1054     // Infos
1055     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1056       $txt_infos="<ul>\n";
1057       foreach($_SESSION['LSsession_infos'] as $info) {
1058         $txt_infos.="<li>$info</li>\n";
1059       }
1060       $txt_infos.="</ul>\n";
1061       $GLOBALS['Smarty'] -> assign('LSinfos',$txt_infos);
1062       $_SESSION['LSsession_infos']=array();
1063     }
1064     
1065     if (self :: $ajaxDisplay) {
1066       $GLOBALS['Smarty'] -> assign('LSerror_txt',LSerror :: getErrors());
1067       $GLOBALS['Smarty'] -> assign('LSdebug_txt',LSdebug_print(true));
1068     }
1069     else {
1070       LSerror :: display();
1071       LSdebug_print();
1072     }
1073     if (!self :: $template)
1074       self :: setTemplate('empty.tpl');
1075     $GLOBALS['Smarty'] -> display(self :: $template);
1076   }
1077   
1078  /**
1079   * Défini que l'affichage se fera ou non via un retour Ajax
1080   * 
1081   * @param[in] $val boolean True pour que l'affichage se fasse par un retour
1082   *                         Ajax, false sinon
1083   * @retval void
1084   */
1085   public static function setAjaxDisplay($val=true) {
1086     self :: $ajaxDisplay = (boolean)$val;
1087   }
1088   
1089  /**
1090   * Affiche un retour Ajax
1091   *
1092   * @retval void
1093   */
1094   public static function displayAjaxReturn($data=array()) {
1095     if (isset($data['LSredirect']) && (!LSdebugDefined()) ) {
1096       echo json_encode($data);
1097       return;
1098     }
1099     
1100     $data['LSjsConfig'] = self :: $_JSconfigParams;
1101     
1102     // Infos
1103     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1104       $txt_infos="<ul>\n";
1105       foreach($_SESSION['LSsession_infos'] as $info) {
1106         $txt_infos.="<li>$info</li>\n";
1107       }
1108       $txt_infos.="</ul>\n";
1109       $data['LSinfos'] = $txt_infos;
1110       $_SESSION['LSsession_infos']=array();
1111     }
1112     
1113     if (LSerror :: errorsDefined()) {
1114       $data['LSerror'] = LSerror :: getErrors();
1115     }
1116
1117     if (isset($_REQUEST['imgload'])) {
1118       $data['imgload'] = $_REQUEST['imgload'];
1119     }
1120
1121     if (LSdebugDefined()) {
1122       $data['LSdebug'] = LSdebug_print(true);
1123     }
1124
1125     echo json_encode($data);  
1126   }
1127  
1128  /**
1129   * Retournne un template Smarty compilé
1130   *
1131   * @param[in] string $template Le template à retourner
1132   * @param[in] array $variables Variables Smarty à assigner avant l'affichage
1133   * 
1134   * @retval string Le HTML compilé du template
1135   */
1136   public static function fetchTemplate($template,$variables=array()) {
1137     foreach($variables as $name => $val) {
1138       $GLOBALS['Smarty'] -> assign($name,$val);
1139     }
1140     return $GLOBALS['Smarty'] -> fetch($template);
1141   }
1142   
1143   /**
1144    * Charge les droits LS de l'utilisateur
1145    * 
1146    * @retval boolean True si le chargement Ã  réussi, false sinon.
1147    **/
1148   private static function loadLSprofiles() {
1149     if (is_array(self :: $ldapServer['LSprofiles'])) {
1150       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1151         if (is_array($profileInfos)) {
1152           foreach ($profileInfos as $topDn => $rightsInfos) {
1153             /*
1154              * If $topDn == 'LSobject', we search for each LSobject type to find
1155              * all items on witch the user will have powers.
1156              */
1157             if ($topDn == 'LSobjects') {
1158               if (is_array($rightsInfos)) {
1159                 foreach ($rightsInfos as $LSobject => $listInfos) {
1160                   if (self :: loadLSobject($LSobject)) {
1161                     if ($object = new $LSobject()) {
1162                       if ($listInfos['filter']) {
1163                         $filter = self :: getLSuserObject() -> getFData($listInfos['filter']);
1164                       }
1165                       else {
1166                         $filter = $listInfos['attr'].'='.self :: getLSuserObject() -> getFData($listInfos['attr_value']);
1167                       }
1168                       $list = $object -> search($filter,$listInfos['basedn'],$listInfos['params']);
1169                       foreach($list as $obj) {
1170                         self :: $LSprofiles[$profile][] = $obj['dn'];
1171                       }
1172                     }
1173                     else {
1174                       LSdebug('Impossible de créer l\'objet de type : '.$LSobject);
1175                     }
1176                   }
1177                 }
1178               }
1179               else {
1180                 LSdebug('LSobjects => [] doit etre un tableau');
1181               }
1182             }
1183             else {
1184               if (is_array($rightsInfos)) {
1185                 foreach($rightsInfos as $dn => $conf) {
1186                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1187                     if( self :: loadLSobject($conf['LSobject']) ) {
1188                       if ($object = new $conf['LSobject']()) {
1189                         if ($object -> loadData($dn)) {
1190                           $listDns=$object -> getValue($conf['attr']);
1191                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1192                           $val = self :: getLSuserObject() -> getFData($valKey);
1193                           if (is_array($listDns)) {
1194                             if (in_array($val,$listDns)) {
1195                               self :: $LSprofiles[$profile][] = $topDn;
1196                             }
1197                           }
1198                         }
1199                         else {
1200                           LSdebug('Impossible de chargé le dn : '.$dn);
1201                         }
1202                       }
1203                       else {
1204                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1205                       }
1206                     }
1207                   }
1208                   else {
1209                     if (self :: $dn == $dn) {
1210                       self :: $LSprofiles[$profile][] = $topDn;
1211                     }
1212                   }
1213                 }
1214               }
1215               else {
1216                 if ( self :: $dn == $rightsInfos ) {
1217                   self :: $LSprofiles[$profile][] = $topDn;
1218                 }
1219               }
1220             } // fin else ($topDn == 'LSobjects')
1221           } // fin foreach($profileInfos)
1222         } // fin is_array($profileInfos)
1223       } // fin foreach LSprofiles
1224       LSdebug(self :: $LSprofiles);
1225       return true;
1226     }
1227     else {
1228       return;
1229     }
1230   }
1231   
1232   /**
1233    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1234    *
1235    * @retval void
1236    */
1237   private static function loadLSaccess() {
1238     $LSaccess=array();
1239     if (is_array(self :: $ldapServer['subDn'])) {
1240       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1241         if ($name=='LSobject') {
1242           if (is_array($config)) {
1243
1244             // Définition des subDns 
1245             foreach($config as $objectType => $objectConf) {
1246               if (self :: loadLSobject($objectType)) {
1247                 if ($subdnobject = new $objectType()) {
1248                   $tbl = $subdnobject -> getSelectArray();
1249                   if (is_array($tbl)) {
1250                     // Définition des accès
1251                     $access=array();
1252                     if (is_array($objectConf['LSobjects'])) {
1253                       foreach($objectConf['LSobjects'] as $type) {
1254                         if (self :: loadLSobject($type)) {
1255                           if (self :: canAccess($type)) {
1256                             $access[$type] = $GLOBALS['LSobjects'][$type]['label'];
1257                           }
1258                         }
1259                       }
1260                     }
1261                     foreach($tbl as $dn => $dn_name) {
1262                       $LSaccess[$dn]=$access;
1263                     }
1264                   }
1265                 }
1266               }
1267             }
1268           }
1269         }
1270         else {
1271           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1272             $access=array();
1273             if (is_array($config['LSobjects'])) {
1274               foreach($config['LSobjects'] as $objectType) {
1275                 if (self :: loadLSobject($objectType)) {
1276                   if (self :: canAccess($objectType)) {
1277                     $access[$objectType] = $GLOBALS['LSobjects'][$objectType]['label'];
1278                   }
1279                 }
1280               }
1281             }
1282             $LSaccess[$config['dn']]=$access;
1283           }
1284         }
1285       }
1286     }
1287     else {
1288       if(is_array(self :: $ldapServer['LSaccess'])) {
1289         $access=array();
1290         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1291           if (self :: loadLSobject($objectType)) {
1292             if (self :: canAccess($objectType)) {
1293                 $access[$objectType] = $GLOBALS['LSobjects'][$objectType]['label'];
1294             }
1295           }
1296         }
1297         $LSaccess[self :: $topDn] = $access;
1298       }
1299     }
1300     foreach($LSaccess as $dn => $access) {
1301       $LSaccess[$dn] = array_merge(
1302         array(
1303           'SELF' => _('Mon compte')
1304         ),
1305         $access
1306       );
1307     }
1308     
1309     self :: $LSaccess = $LSaccess;
1310     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1311   }
1312   
1313   /**
1314    * Dit si l'utilisateur est du profil pour le DN spécifié
1315    *
1316    * @param[in] string $profile de l'objet
1317    * @param[in] string $dn DN de l'objet
1318    * 
1319    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1320    */
1321   public static function isLSprofile($dn,$profile) {
1322     if (is_array(self :: $LSprofiles[$profile])) {
1323       foreach(self :: $LSprofiles[$profile] as $topDn) {
1324         if($dn == $topDn) {
1325           return true;
1326         }
1327         else if ( isCompatibleDNs($dn,$topDn) ) {
1328           return true;
1329         }
1330       }
1331     }
1332     return;
1333   }
1334   
1335   /**
1336    * Retourne qui est l'utilisateur par rapport Ã  l'object
1337    *
1338    * @param[in] string Le DN de l'objet
1339    * 
1340    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1341    */
1342   public static function whoami($dn) {
1343     $retval = array('user');
1344     
1345     foreach(self :: $LSprofiles as $profile => $infos) {
1346       if(self :: isLSprofile($dn,$profile)) {
1347        $retval[]=$profile;
1348       }
1349     }
1350     
1351     if (self :: $dn == $dn) {
1352       $retval[]='self';
1353     }
1354     
1355     return $retval;
1356   }
1357   
1358   /**
1359    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1360    * 
1361    * @param[in] string $LSobject Le type de l'objet
1362    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1363    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1364    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1365    *
1366    * @retval boolean True si l'utilisateur a accès, false sinon
1367    */
1368   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1369     if (!self :: loadLSobject($LSobject)) {
1370       return;
1371     }
1372     if ($dn) {
1373       $whoami = self :: whoami($dn);
1374       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1375         if (!self :: in_menu('SELF')) {
1376           return;
1377         }
1378       }
1379       else {
1380         $obj = new $LSobject();
1381         $obj -> dn = $dn;
1382         if (!self :: in_menu($LSobject,$obj -> getSubDnValue())) {
1383           return;
1384         }
1385       }
1386     }
1387     else {
1388       $objectdn=$GLOBALS['LSobjects'][$LSobject]['container_dn'].','.self :: $topDn;
1389       $whoami = self :: whoami($objectdn);
1390     }
1391     
1392     // Pour un attribut particulier
1393     if ($attr) {
1394       if ($attr=='rdn') {
1395         $attr=$GLOBALS['LSobjects'][$LSobject]['rdn'];
1396       }
1397       if (!isset($GLOBALS['LSobjects'][$LSobject]['attrs'][$attr])) {
1398         return;
1399       }
1400
1401       $r = 'n';
1402       foreach($whoami as $who) {
1403         $nr = $GLOBALS['LSobjects'][$LSobject]['attrs'][$attr]['rights'][$who];
1404         if($nr == 'w') {
1405           $r = 'w';
1406         }
1407         else if($nr == 'r') {
1408           if ($r=='n') {
1409             $r='r';
1410           }
1411         }
1412       }
1413       
1414       if (($right=='r')||($right=='w')) {
1415         if ($r==$right) {
1416           return true;
1417         }
1418         return;
1419       }
1420       else {
1421         if ( ($r=='r') || ($r=='w') ) {
1422           return true;
1423         }
1424         return;
1425       }
1426     }
1427     
1428     // Pour un attribut quelconque
1429     if (is_array($GLOBALS['LSobjects'][$LSobject]['attrs'])) {
1430       if (($right=='r')||($right=='w')) {
1431         foreach($whoami as $who) {
1432           foreach ($GLOBALS['LSobjects'][$LSobject]['attrs'] as $attr_name => $attr_config) {
1433             if ($attr_config['rights'][$who]==$right) {
1434               return true;
1435             }
1436           }
1437         }
1438       }
1439       else {
1440         foreach($whoami as $who) {
1441           foreach ($GLOBALS['LSobjects'][$LSobject]['attrs'] as $attr_name => $attr_config) {
1442             if ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) {
1443               return true;
1444             }
1445           }
1446         }
1447       }
1448     }
1449     return;
1450   }
1451   
1452   /**
1453    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1454    * 
1455    * @param[in] string $LSobject Le type de l'objet
1456    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1457    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1458    *
1459    * @retval boolean True si l'utilisateur a accès, false sinon
1460    */
1461   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1462     return self :: canAccess($LSobject,$dn,'w',$attr);
1463   }
1464
1465   /**
1466    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1467    * 
1468    * @param[in] string $LSobject Le type de l'objet
1469    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1470    *
1471    * @retval boolean True si l'utilisateur a accès, false sinon
1472    */  
1473   public static function canRemove($LSobject,$dn) {
1474     return self :: canAccess($LSobject,$dn,'w','rdn');
1475   }
1476   
1477   /**
1478    * Retourne le droit de l'utilisateur Ã  créer un objet
1479    * 
1480    * @param[in] string $LSobject Le type de l'objet
1481    *
1482    * @retval boolean True si l'utilisateur a accès, false sinon
1483    */    
1484   public static function canCreate($LSobject) {
1485     return self :: canAccess($LSobject,NULL,'w','rdn');
1486   }
1487   
1488   /**
1489    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
1490    * 
1491    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1492    * @param[in] string $LSobject Le type de l'objet
1493    * @param[in] string $relationName Le nom de la relation avec l'objet
1494    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
1495    *
1496    * @retval boolean True si l'utilisateur a accès, false sinon
1497    */
1498   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
1499     if (!isset($GLOBALS['LSobjects'][$LSobject]['LSrelation'][$relationName]))
1500       return;
1501     $whoami = self :: whoami($dn);
1502
1503     if (($right=='w') || ($right=='r')) {
1504       $r = 'n';
1505       foreach($whoami as $who) {
1506         $nr = $GLOBALS['LSobjects'][$LSobject]['LSrelation'][$relationName]['rights'][$who];
1507         if($nr == 'w') {
1508           $r = 'w';
1509         }
1510         else if($nr == 'r') {
1511           if ($r=='n') {
1512             $r='r';
1513           }
1514         }
1515       }
1516       
1517       if ($r == $right) {
1518         return true;
1519       }
1520     }
1521     else {
1522       foreach($whoami as $who) {
1523         if (($GLOBALS['LSobjects'][$LSobject]['LSrelation'][$relationName]['rights'][$who] == 'w') || ($GLOBALS['LSobjects'][$LSobject]['LSrelation'][$relationName]['rights'][$who] == 'r')) {
1524           return true;
1525         }
1526       }
1527     }
1528     return;
1529   }
1530
1531   /**
1532    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
1533    * 
1534    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1535    * @param[in] string $LSobject Le type de l'objet
1536    * @param[in] string $relationName Le nom de la relation avec l'objet
1537    *
1538    * @retval boolean True si l'utilisateur a accès, false sinon
1539    */  
1540   public static function relationCanEdit($dn,$LSobject,$relationName) {
1541     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
1542   }
1543
1544   /**
1545    * Ajoute un fichier temporaire
1546    * 
1547    * @author Benjamin Renard <brenard@easter-eggs.com>
1548    * 
1549    * @retval void
1550    **/
1551   public static function addTmpFile($value,$filePath) {
1552     $hash = mhash(MHASH_MD5,$value);
1553     self :: $tmp_file[$filePath] = $hash;
1554     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
1555   }
1556   
1557   /**
1558    * Retourne le chemin du fichier temporaire si l'existe
1559    * 
1560    * @author Benjamin Renard <brenard@easter-eggs.com>
1561    * 
1562    * @param[in] $value La valeur du fichier
1563    * 
1564    * @retval mixed 
1565    **/
1566   public static function tmpFileExist($value) {
1567     $hash = mhash(MHASH_MD5,$value);
1568     foreach(self :: $tmp_file as $filePath => $contentHash) {
1569       if ($hash == $contentHash) {
1570         return $filePath;
1571       }
1572     }
1573     return false;
1574   }
1575   
1576   /**
1577    * Retourne le chemin du fichier temporaire
1578    * 
1579    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
1580    * s'il n'existe pas déjà.
1581    * 
1582    * @author Benjamin Renard <brenard@easter-eggs.com>
1583    * 
1584    * @param[in] $value La valeur du fichier
1585    * 
1586    * @retval mixed 
1587    **/
1588   public static function getTmpFile($value) {
1589     $exist = self :: tmpFileExist($value);
1590     if (!$exist) {
1591       $img_path = LS_TMP_DIR .rand().'.tmp';
1592       $fp = fopen($img_path, "w");
1593       fwrite($fp, $value);
1594       fclose($fp);
1595       self :: addTmpFile($value,$img_path);
1596       return $img_path;
1597     }
1598     else {
1599       return $exist;
1600     }
1601   }
1602   
1603   /**
1604    * Supprime les fichiers temporaires
1605    * 
1606    * @author Benjamin Renard <brenard@easter-eggs.com>
1607    * 
1608    * @retval void
1609    **/
1610   public static function deleteTmpFile($filePath=NULL) {
1611     if ($filePath) {
1612         @unlink($filePath);
1613         unset(self :: $tmp_file[$filePath]);
1614         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
1615     }
1616     else {
1617       foreach(self :: $tmp_file as $file => $content) {
1618         @unlink($file);
1619       }
1620       self :: $tmp_file = array();
1621       $_SESSION['LSsession']['tmp_file'] = array();
1622     }
1623   }
1624
1625   /**
1626    * Retourne true si le cache des droits est activé
1627    *
1628    * @author Benjamin Renard <brenard@easter-eggs.com>
1629    * 
1630    * @retval boolean True si le cache des droits est activé, false sinon.
1631    */
1632   public static function cacheLSprofiles() {
1633     return ( ($GLOBALS['LSconfig']['cacheLSprofiles']) || (self :: $ldapServer['cacheLSprofiles']) );
1634   }
1635
1636   /**
1637    * Retourne true si le cache des subDn est activé
1638    *
1639    * @author Benjamin Renard <brenard@easter-eggs.com>
1640    * 
1641    * @retval boolean True si le cache des subDn est activé, false sinon.
1642    */
1643   public static function cacheSudDn() {
1644     return (($GLOBALS['LSconfig']['cacheSubDn']) || (self :: $ldapServer['cacheSubDn']));
1645   }
1646   
1647   /**
1648    * Retourne true si le cache des recherches est activé
1649    *
1650    * @author Benjamin Renard <brenard@easter-eggs.com>
1651    * 
1652    * @retval boolean True si le cache des recherches est activé, false sinon.
1653    */
1654   public static function cacheSearch() {
1655     return (($GLOBALS['LSconfig']['cacheSearch']) || (self :: $ldapServer['cacheSearch']));
1656   }
1657   
1658   /**
1659    * Retourne le label des niveaux pour le serveur ldap courant
1660    * 
1661    * @author Benjamin Renard <brenard@easter-eggs.com>
1662    * 
1663    * @retval string Le label des niveaux pour le serveur ldap dourant
1664    */
1665   public static function getSubDnLabel() {
1666     return (self :: $ldapServer['subDnLabel']!='')?self :: $ldapServer['subDnLabel']:_('Niveau');
1667   }
1668   
1669   /**
1670    * Retourne le nom du subDn
1671    * 
1672    * @param[in] $subDn string subDn
1673    * 
1674    * @retval string Le nom du subDn ou '' sinon
1675    */
1676   public static function getSubDnName($subDn=false) {
1677     if (!$subDn) {
1678       $subDn = self :: $topDn;
1679     }
1680     if (self :: getSubDnLdapServer()) {
1681       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][$subDn])) {
1682         return self :: $_subDnLdapServer[self :: $ldapServerId][$subDn];
1683       }
1684     }
1685     return '';
1686   }
1687
1688   /**
1689    * L'objet est t-il utilisé pour listé les subDnS
1690    * 
1691    * @param[in] $type string Le type d'objet
1692    * 
1693    * @retval boolean true si le type d'objet est un subDnObject, false sinon
1694    */
1695   public static function isSubDnLSobject($type) {
1696     $result = false;
1697     if (is_array(self :: $ldapServer['subDn']['LSobject'])) {
1698       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
1699         if ($key==$type) {
1700           $result=true;
1701         }
1702       }
1703     }
1704     return $result;
1705   }
1706   
1707   /**
1708    * Indique si un type d'objet est dans le menu courant
1709    * 
1710    * @retval boolean true si le type d'objet est dans le menu, false sinon
1711    */
1712   public static function in_menu($LSobject,$topDn=NULL) {
1713     if (!$topDn) {
1714       $topDn=self :: $topDn;
1715     }
1716     return isset(self :: $LSaccess[$topDn][$LSobject]);
1717   }
1718   
1719   /**
1720    * Indique si le serveur LDAP courant a des subDn
1721    * 
1722    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
1723    */
1724   public static function haveSubDn() {
1725     return (is_array(self :: $ldapServer['subDn']));
1726   }
1727
1728   /**
1729    * Ajoute une information à afficher
1730    * 
1731    * @param[in] $msg string Le message à afficher
1732    * 
1733    * @retval void
1734    */
1735   public static function addInfo($msg) {
1736     $_SESSION['LSsession_infos'][]=$msg;
1737   }
1738   
1739   /**
1740    * Redirection de l'utilisateur vers une autre URL
1741    * 
1742    * @param[in] $url string L'URL
1743    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
1744    * 
1745    * @retval void
1746    */  
1747   public static function redirect($url,$exit=true) {
1748     $GLOBALS['Smarty'] -> assign('url',$url);
1749     $GLOBALS['Smarty'] -> display('redirect.tpl');
1750     if ($exit) {
1751       exit();
1752     }
1753   }
1754   
1755   /**
1756    * Retourne l'adresse mail d'emission configurée pour le serveur courant
1757    * 
1758    * @retval string Adresse mail d'emission
1759    */
1760   public static function getEmailSender() {
1761     return self :: $ldapServer['emailSender'];  
1762   }
1763   
1764   /**
1765    * Ajout d'une information d'aide
1766    * 
1767    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
1768    *                          celle-ci
1769    * @param[in] $infos array  Tableau array(name => value) des infos
1770    * 
1771    * @retval void
1772    */
1773   public static function addHelpInfos($group,$infos) {
1774     if (is_array($infos)) {
1775       if (is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
1776         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
1777       }
1778       else {
1779         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
1780       }
1781     }
1782   }
1783   
1784  /**
1785   * Défini les codes erreur relative à la classe LSsession
1786   * 
1787   * @retval void
1788   */  
1789   private static function defineLSerrors() {
1790     /*
1791      * Error Codes
1792      */
1793     LSerror :: defineError('LSsession_01',
1794     _("LSsession : The constant %{const} is not defined.")
1795     );
1796     LSerror :: defineError('LSsession_02',
1797     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
1798     );
1799     LSerror :: defineError('LSsession_03',
1800     _("LSsession : LDAP server's configuration data are invalid. Impossible d'établir une connexion.")
1801     );
1802     LSerror :: defineError('LSsession_04',
1803     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
1804     );
1805     // no longer used
1806     /*LSerror :: defineError(1005,
1807     _("LSsession : Object type use for authentication is unknow (%{type}).")
1808     );*/
1809     LSerror :: defineError('LSsession_06',
1810     _("LSsession : Login or password incorrect.")
1811     );
1812     LSerror :: defineError('LSsession_07',
1813     _("LSsession : Impossible to identify you : Duplication of identities.")
1814     );
1815     LSerror :: defineError('LSsession_08',
1816     _("LSsession : Can't load Smarty template engine.")
1817     );
1818     LSerror :: defineError('LSsession_09',
1819     _("LSsession : Can't connect to LDAP server.")
1820     );
1821     LSerror :: defineError('LSsession_10',
1822     _("LSsession : Impossible to load authentification objects's class.")
1823     );
1824     LSerror :: defineError('LSsession_11',
1825     _("LSsession : Your are not authorized to do this action.")
1826     );
1827     LSerror :: defineError('LSsession_12',
1828     _("LSsession : Some informations are missing to display this page.")
1829     );
1830     // 13 -> 16 : not yet used
1831     LSerror :: defineError('LSsession_17',
1832     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
1833     );
1834     LSerror :: defineError('LSsession_18',
1835     _("LSsession : The password recovery is disabled for this LDAP server.")
1836     );
1837     LSerror :: defineError('LSsession_19',
1838     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
1839     );
1840     LSerror :: defineError('LSsession_20',
1841     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
1842     );
1843     // 21 : not yet used
1844     LSerror :: defineError('LSsession_22',
1845     _("LSsession : problem during initialisation.")
1846     );
1847
1848
1849     // LSrelations
1850     LSerror :: defineError('LSrelations_01',
1851     _("LSrelations : The listing function for the relation %{relation} is unknow.")
1852     );
1853     LSerror :: defineError('LSrelations_02',
1854     _("LSrelations : The update function of the relation %{relation} is unknow.")
1855     );
1856     LSerror :: defineError('LSrelations_03',
1857     _("LSrelations : Error during relation update of the relation %{relation}.")
1858     );
1859     LSerror :: defineError('LSrelations_04',
1860     _("LSrelations : Object type %{LSobject} unknow (Relation : %{relation}).")
1861     );
1862     LSerror :: defineError('LSrelations_05',
1863     _("LSrelation : Some parameters are missing in the invocation of the methods of handling relations standard (Methode : %{meth}).")
1864     );
1865   }
1866 }
1867
1868 ?>