817b058170de80a98dce8f8668844a1f5cb67c61
[ldapsaisie.git] / public_html / 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 /** 
24  * Gestion des sessions
25  *
26  * Cette classe gère les sessions d'utilisateurs.
27  *
28  * @author Benjamin Renard <brenard@easter-eggs.com>
29  */
30 class LSsession {
31
32   // La configuration du serveur Ldap utilisé
33   public static $ldapServer = NULL;
34   
35   // L'id du serveur Ldap utilisé
36   private static $ldapServerId = NULL;
37   
38   // Le topDn courant
39   private static $topDn = NULL;
40   
41   // Le DN de l'utilisateur connecté
42   private static $dn = NULL;
43   
44   // Le RDN de l'utilisateur connecté (son identifiant)
45   private static $rdn = NULL;
46   
47   // Les LSprofiles de l'utilisateur
48   private static $LSprofiles = array();
49   
50   // Les droits d'accès de l'utilisateur
51   private static $LSaccess = array();
52
53   // LSaddons views
54   private static $LSaddonsViews = array();
55   private static $LSaddonsViewsAccess = array();
56   
57   // Les fichiers temporaires
58   private static $tmp_file = array();
59   
60   // Langue et encodage actuel
61   private static $lang = NULL;
62   private static $encoding = NULL;
63   
64   /*
65    * Constante de classe non stockée en session
66    */
67   // Le template à afficher
68   private static $template = NULL;
69   
70   // Les subDn des serveurs Ldap
71   private static $_subDnLdapServer = array();
72   
73   // Affichage Ajax
74   private static $ajaxDisplay = false;
75
76   // Les fichiers JS à charger dans la page
77   private static $JSscripts = array();
78   
79   // Les paramètres JS à communiquer dans la page
80   private static $_JSconfigParams = array();
81   
82   // Les fichiers CSS à charger dans la page
83   private static $CssFiles = array();
84
85   // L'objet de l'utilisateur connecté
86   private static $LSuserObject = NULL;
87   
88   // The LSauht object of the session
89   private static $LSauthObject = false;
90
91   // User LDAP credentials
92   private static $userLDAPcreds = false;
93
94  /**
95   * Include un fichier PHP
96   *
97   * @author Benjamin Renard <brenard@easter-eggs.com>
98   *
99   * @retval true si tout c'est bien passé, false sinon
100   */
101   public static function includeFile($file) {
102     if (file_exists(LS_LOCAL_DIR.'/'.$file)) {
103       $file=LS_LOCAL_DIR.'/'.$file;
104     }
105     elseif (!file_exists($file)) {
106       return;
107     }
108     if (defined('LSdebug') && constant('LSdebug')) {
109       return include_once($file);
110     }
111     else {
112       return @include_once($file);
113     }
114     return;
115   }
116
117  /**
118   * Lancement de LSconfig
119   *
120   * @author Benjamin Renard <brenard@easter-eggs.com>
121   *
122   * @retval true si tout c'est bien passé, false sinon
123   */
124   private static function startLSconfig() {
125     if (self :: loadLSclass('LSconfig')) {
126       if (LSconfig :: start()) {
127         return true;
128       }
129     }
130     die("ERROR : Can't load configuration files.");
131     return;
132   }
133
134  /**
135   * Lancement et initialisation de Smarty
136   *
137   * @author Benjamin Renard <brenard@easter-eggs.com>
138   *
139   * @retval true si tout c'est bien passé, false sinon
140   */  
141   private static function startLStemplate() {
142     if ( self :: loadLSclass('LStemplate') ) {
143       return LStemplate :: start(
144         array(
145           'smarty_path'  => LSconfig :: get('Smarty'),
146           'template_dir' => LS_TEMPLATES_DIR,
147           'image_dir'    => LS_IMAGES_DIR,
148           'css_dir'    => LS_CSS_DIR,
149           'compile_dir'  => LS_TMP_DIR,
150           'debug'        => LSdebug,
151           'debug_smarty' => (isset($_REQUEST['LStemplate_debug'])),
152         )
153       );
154     }
155     return False;
156   }
157   
158  /**
159   * Retourne le topDn de la session
160   *
161   * @author Benjamin Renard <brenard@easter-eggs.com>
162   *
163   * @retval string le topDn de la session
164   */
165   public static function getTopDn() {
166     if (!is_null(self :: $topDn)) {
167       return self :: $topDn;
168     }
169     else {
170       return self :: getRootDn();
171     }
172   }
173   
174  /**
175   * Retourne le rootDn de la session
176   *
177   * @author Benjamin Renard <brenard@easter-eggs.com>
178   *
179   * @retval string le rootDn de la session
180   */
181   public static function getRootDn() {
182     return self :: $ldapServer['ldap_config']['basedn'];
183   }
184
185  /**
186   * Initialisation de la gestion des erreurs
187   *
188   * Création de l'objet LSerror
189   *
190   * @author Benjamin Renard <brenard@easter-eggs.com
191   *
192   * @retval boolean true si l'initialisation a réussi, false sinon.
193   */
194   private static function startLSerror() {
195     if(!self :: loadLSclass('LSerror')) {
196       return;
197     }
198     set_error_handler(array('LSerror','errorHandler'),E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED & ~E_WARNING);
199     self :: defineLSerrors();
200     return true;
201   }
202
203  /**
204   * Chargement d'une classe d'LdapSaisie
205   *
206   * @param[in] $class Nom de la classe Ã  charger (Exemple : LSpeople)
207   * @param[in] $type (Optionnel) Type de classe Ã  charger (Exemple : LSobjects)
208   *
209   * @author Benjamin Renard <brenard@easter-eggs.com
210   * 
211   * @retval boolean true si le chargement a réussi, false sinon.
212   */
213   public static function loadLSclass($class,$type='') {
214     if (class_exists($class))
215       return true;
216     if($type!='')
217       $type=$type.'.';
218     return self :: includeFile(LS_CLASS_DIR .'class.'.$type.$class.'.php');
219   }
220
221  /**
222   * Chargement d'un object LdapSaisie
223   *
224   * @param[in] $object Nom de l'objet Ã  charger
225   *
226   * @retval boolean true si le chargement a réussi, false sinon.
227   */
228   public static function loadLSobject($object) {
229     if(class_exists($object)) {
230       return true;
231     }
232     $error = 0;
233     self :: loadLSclass('LSldapObject');
234     if (!self :: loadLSclass($object,'LSobjects')) {
235       $error = 1;
236     }
237     if (!self :: includeFile( LS_OBJECTS_DIR . 'config.LSobjects.'.$object.'.php' )) {
238       $error = 1;
239     }
240     else {
241       if (!LSconfig :: set("LSobjects.$object",$GLOBALS['LSobjects'][$object])) {
242         $error = 1;
243       }
244       else if (isset($GLOBALS['LSobjects'][$object]['LSaddons'])){
245         if (is_array($GLOBALS['LSobjects'][$object]['LSaddons'])) {
246           foreach ($GLOBALS['LSobjects'][$object]['LSaddons'] as $addon) {
247             if (!self :: loadLSaddon($addon)) {
248               $error = 1;
249             }
250           }
251         }
252         else {
253           if (!self :: loadLSaddon($GLOBALS['LSobjects'][$object]['LSaddons'])) {
254             $error = 1;
255           }
256         } 
257       }
258     }
259     if ($error) {
260       LSerror :: addErrorCode('LSsession_04',$object);
261       return;
262     }
263     return true;
264   }
265
266  /**
267   * Chargement d'un addons d'LdapSaisie
268   *
269   * @param[in] $addon Nom de l'addon Ã  charger (Exemple : samba)
270   *
271   * @author Benjamin Renard <brenard@easter-eggs.com
272   * 
273   * @retval boolean true si le chargement a réussi, false sinon.
274   */
275   public static function loadLSaddon($addon) {
276     if(self :: includeFile(LS_ADDONS_DIR .'LSaddons.'.$addon.'.php')) {
277       self :: includeFile(LS_CONF_DIR."LSaddons/config.LSaddons.".$addon.".php");
278       if (!call_user_func('LSaddon_'. $addon .'_support')) {
279         LSerror :: addErrorCode('LSsession_02',$addon);
280         return;
281       }
282       return true;
283     }
284     return;
285   }
286
287  /**
288   * Chargement d'une classe d'authentification d'LdapSaisie
289   *
290   * @author Benjamin Renard <brenard@easter-eggs.com
291   * 
292   * @retval boolean true si le chargement a reussi, false sinon.
293   */
294   public static function loadLSauth() {
295     if (self :: loadLSclass('LSauth')) {
296       return true;
297     }
298     else {
299       LSerror :: addErrorCode('LSsession_05','LSauth');
300     }
301     return;
302   }
303
304  /**
305   * Chargement des addons LdapSaisie
306   *
307   * Chargement des LSaddons contenue dans la variable
308   * $GLOBALS['LSaddons']['loads']
309   *
310   * @retval boolean true si le chargement a réussi, false sinon.
311   */
312   public static function loadLSaddons() {
313     $conf=LSconfig :: get('LSaddons.loads');
314     if(!is_array($conf)) {
315       LSerror :: addErrorCode('LSsession_01',"LSaddons['loads']");
316       return;
317     }
318
319     foreach ($conf as $addon) {
320       self :: loadLSaddon($addon);
321     }
322     return true;
323   }
324
325  /**
326   * Défini la locale
327   * 
328   * @retval void
329   */
330   public static function setLocale($lang=null,$encoding=null) {
331     if (is_null($lang)) {
332       if (isset($_REQUEST['lang'])) {
333         $lang = $_REQUEST['lang'];
334       }
335       elseif (isset($_SESSION['LSlang'])) {
336         $lang = $_SESSION['LSlang'];
337       }
338       elseif (isset(self :: $ldapServer['lang'])) {
339         $lang = self :: $ldapServer['lang'];
340       }
341       else {
342         $lang = LSconfig :: get('lang');
343       }
344     }
345     
346     if (is_null($enconding)) {
347       if (isset($_REQUEST['encoding'])) {
348         $encoding = $_REQUEST['encoding'];
349       }
350       elseif (isset($_SESSION['LSencoding'])) {
351         $encoding = $_SESSION['LSencoding'];
352       }
353       elseif (isset(self :: $ldapServer['encoding'])) {
354         $encoding = self :: $ldapServer['encoding'];
355       }
356       else {
357         $encoding = LSconfig :: get('encoding');
358       }
359     }
360     
361     $_SESSION['LSlang']=$lang;
362     self :: $lang=$lang;
363     $_SESSION['LSencoding']=$encoding;
364     self :: $encoding=$encoding;
365     
366
367     if (self :: localeExist($lang,$encoding)) {
368       if ($encoding) {
369         $lang.='.'.$encoding;
370       }
371       setlocale(LC_ALL, $lang);
372       bindtextdomain(LS_TEXT_DOMAIN, LS_I18N_DIR);
373       textdomain(LS_TEXT_DOMAIN);
374       
375       self :: includeFile(LS_I18N_DIR.'/'.$lang.'/lang.php');
376
377       foreach (listFiles(LS_LOCAL_DIR.'/'.LS_I18N_DIR.'/'.$lang,'/^lang.+\.php$/') as $file) {
378         include(LS_LOCAL_DIR.'/'.LS_I18N_DIR."/$lang/$file");
379       }
380     }
381     else {
382       if ($encoding && $lang) {
383         $lang.='.'.$encoding;
384       }
385       LSdebug('La locale "'.$lang.'" n\'existe pas, utilisation de la locale par défaut.');
386     }
387   }
388   
389  /**
390   * Retourne la liste des langues disponibles
391   * 
392   * @retval array Tableau/Liste des langues disponibles
393   **/ 
394   public static function getLangList() {
395     $list=array('en_US');
396     if (self :: $encoding) {
397       $regex = '^([a-zA-Z_]*)\.'.self :: $encoding.'$';
398     }
399     else {
400       $regex = '^([a-zA-Z_]*)$';
401     }
402     if ($handle = opendir(LS_I18N_DIR)) {
403       while (false !== ($file = readdir($handle))) {
404         if(is_dir(LS_I18N_DIR.'/'.$file)) {
405           if (ereg($regex,$file,$regs)) {
406             if (!in_array($regs[1],$list)) {
407               $list[]=$regs[1];
408             }
409           }
410         }
411       }
412     }
413     return $list;
414   }
415
416  /**
417   * Retourne la langue courante de la session
418   * 
419   * @param[in] boolean Si true, le code langue retourné sera court
420   * 
421   * @retval string La langue de la session
422   **/
423   public static function getLang($short=false) {
424     if ($short) {
425       return strtolower(self :: $lang[0].self :: $lang[1]);
426     }
427     return self :: $lang;
428   }
429   
430  /**
431   * Vérifie si une locale est disponible
432   * 
433   * @param[in] $lang string La langue (Ex : fr_FR)
434   * @param[in] $encoding string L'encodage de caractère (Ex : UTF8)
435   * 
436   * @retval boolean True si la locale est disponible, False sinon
437   **/
438   public static function localeExist($lang,$encoding) {
439     if ( !$lang && !$encoding ) {
440       return;
441     }
442     $locale=$lang.(($encoding)?'.'.$encoding:'');
443     if ($locale=='en_US.UTF8') {
444       return true;
445     }
446     return (is_dir(LS_I18N_DIR.'/'.$locale));
447   }
448
449  /**
450   * Initialisation LdapSaisie
451   *
452   * @param[in] $lang string La langue (Ex : fr_FR / Optionnel)
453   * @param[in] $encoding string L'encodage de caractère (Ex : UTF8 / Optionnel)
454   *
455   * @retval boolean True si l'initialisation à réussi, false sinon.
456   */
457   public static function initialize($lang=null,$encoding=null) {
458     try {
459       if (!self :: startLSconfig()) {
460         return;
461       }
462
463       self :: startLSerror();
464       self :: startLStemplate();
465
466       session_start();
467
468       self :: setLocale($lang,$encoding);
469
470       self :: loadLSaddons();
471       self :: loadLSauth();
472     }
473     catch (Exception $e) {
474       die('LSsession : fail to initialize session. Error : '.$e->getMessage());
475     }
476     return true;
477   }
478
479  /**
480   * Initialisation de la session LdapSaisie
481   *
482   * Initialisation d'une LSsession :
483   * - Authentification et activation du mécanisme de session de LdapSaisie
484   * - ou Chargement des paramètres de la session Ã  partir de la variable 
485   *   $_SESSION['LSsession'].
486   * - ou Destruction de la session en cas de $_GET['LSsession_logout'].
487   *
488   * @retval boolean True si l'initialisation Ã  réussi (utilisateur authentifié), false sinon.
489   */
490   public static function startLSsession() {
491     if (!self :: initialize()) {
492       return;
493     }
494     
495     if(isset($_SESSION['LSsession']['dn']) && !isset($_GET['LSsession_recoverPassword'])) {
496       LSdebug('LSsession : Session existente'); 
497       // --------------------- Session existante --------------------- //
498       self :: $topDn         = $_SESSION['LSsession']['topDn'];
499       self :: $dn            = $_SESSION['LSsession']['dn'];
500       self :: $rdn           = $_SESSION['LSsession']['rdn'];
501       self :: $ldapServerId  = $_SESSION['LSsession']['ldapServerId'];
502       self :: $tmp_file      = $_SESSION['LSsession']['tmp_file'];
503       self :: $userLDAPcreds = $_SESSION['LSsession']['userLDAPcreds'];
504       
505       if ( self :: cacheLSprofiles() && !isset($_REQUEST['LSsession_refresh']) ) {
506         self :: setLdapServer(self :: $ldapServerId);
507         if (!LSauth :: start()) {
508           LSdebug("LSsession : can't start LSauth -> stop");
509           return;
510         }
511         self :: $LSprofiles   = $_SESSION['LSsession']['LSprofiles'];
512         self :: $LSaccess   = $_SESSION['LSsession']['LSaccess'];
513         self :: $LSaddonsViewsAccess   = $_SESSION['LSsession']['LSaddonsViewsAccess'];
514         if (!self :: LSldapConnect())
515           return;
516       }
517       else {
518         self :: setLdapServer(self :: $ldapServerId);
519         if (!LSauth :: start()) {
520           LSdebug("LSsession : can't start LSauth -> stop");
521           return;
522         }
523         if (!self :: LSldapConnect())
524           return;
525         self :: loadLSprofiles();
526       }
527       
528       if ( self :: cacheSudDn() && (!isset($_REQUEST['LSsession_refresh'])) ) {
529         self :: $_subDnLdapServer = ((isset($_SESSION['LSsession_subDnLdapServer']))?$_SESSION['LSsession_subDnLdapServer']:NULL);
530       }
531       
532       if (!self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
533         return;
534       }
535       
536       if (isset($_GET['LSsession_logout'])) {
537         LSauth :: logout();
538         session_destroy();
539         
540         if (is_array($_SESSION['LSsession']['tmp_file'])) {
541           self :: $tmp_file = $_SESSION['LSsession']['tmp_file'];
542         }
543         self :: deleteTmpFile();
544         unset($_SESSION['LSsession']);
545         
546         self :: redirect('index.php');
547         return;
548       }
549       
550       if ( !self :: cacheLSprofiles() || isset($_REQUEST['LSsession_refresh']) ) {
551         self :: loadLSprofiles();
552         self :: loadLSaccess();
553         self :: loadLSaddonsViewsAccess();
554         $_SESSION['LSsession']=self :: getContextInfos();
555       }
556       
557       LStemplate :: assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
558       
559       if (isset ($_POST['LSsession_topDn']) && $_POST['LSsession_topDn']) {
560         if (self :: validSubDnLdapServer($_POST['LSsession_topDn'])) {
561           self :: $topDn = $_POST['LSsession_topDn'];
562           $_SESSION['LSsession']['topDn'] = $_POST['LSsession_topDn'];
563         } // end if
564       } // end if
565       
566       return true;
567       
568     }
569     else {
570       // --------------------- Session inexistante --------------------- //
571       if (isset($_GET['LSsession_recoverPassword'])) {
572         session_destroy();
573       }
574       // Session inexistante
575       if (isset($_POST['LSsession_ldapserver'])) {
576         self :: setLdapServer($_POST['LSsession_ldapserver']);
577       }
578       else {
579         self :: setLdapServer(0);
580       }
581       
582       // Connexion au serveur LDAP
583       if (self :: LSldapConnect()) {
584
585         // topDn
586         if (isset($_POST['LSsession_topDn']) && $_POST['LSsession_topDn'] != '' ){
587           self :: $topDn = $_POST['LSsession_topDn'];
588         }
589         else {
590           self :: $topDn = self :: $ldapServer['ldap_config']['basedn'];
591         }
592         $_SESSION['LSsession_topDn']=self :: $topDn;
593        
594         if (!LSauth :: start()) {
595           LSdebug("LSsession : can't start LSauth -> stop");
596           return;
597         }
598         
599         if (isset($_GET['LSsession_recoverPassword'])) {
600           $recoveryPasswordInfos = self :: recoverPasswd(
601                                       $_REQUEST['LSsession_user'],
602                                       $_GET['recoveryHash']
603                                    );
604         }
605         else {
606           $LSuserObject = LSauth :: forceAuthentication();
607           if ($LSuserObject) {
608             // Authentication successful
609             self :: $LSuserObject = $LSuserObject;
610             self :: $dn = $LSuserObject->getValue('dn');
611             self :: $rdn = $LSuserObject->getValue('rdn');
612             if (isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) {
613               self :: $userLDAPcreds = LSauth :: getLDAPcredentials($LSuserObject);
614               if (!is_array(self :: $userLDAPcreds)) {
615                 LSerror :: addErrorCode('LSsession_14');
616                 self :: $userLDAPcreds = false;
617                 return;
618               }
619               if (!LSldap :: reconnectAs(self :: $userLDAPcreds['dn'],self :: $userLDAPcreds['pwd'])) {
620                 LSerror :: addErrorCode('LSsession_15');
621                 return;
622               }
623             }
624             self :: loadLSprofiles();
625             self :: loadLSaccess();
626             self :: loadLSaddonsViewsAccess();
627             LStemplate :: assign('LSsession_username',self :: getLSuserObject() -> getDisplayName());
628             $_SESSION['LSsession']=self :: getContextInfos();
629             return true;
630           }
631         }
632       }
633       else {
634         LSerror :: addErrorCode('LSsession_09');
635       }
636       
637       if (self :: $ldapServerId) {
638         LStemplate :: assign('ldapServerId',self :: $ldapServerId);
639       }
640       LStemplate :: assign('topDn',self :: $topDn);
641       if (isset($_GET['LSsession_recoverPassword'])) {
642         self :: displayRecoverPasswordForm($recoveryPasswordInfos);
643       }
644       elseif(LSauth :: displayLoginForm()) {
645         self :: displayLoginForm();
646       }
647       else {
648         self :: setTemplate('blank.tpl');
649         LSerror :: addErrorCode('LSsession_10');
650       }
651       return;
652     }
653   }
654   
655   /**
656    * Do recover password
657    * 
658    * @param[in] $username string The submited username
659    * @param[in] $recoveryHash string The submited recoveryHash
660    * 
661    * @retval array The recoveryPassword infos for template
662    **/
663   private static function recoverPasswd($username,$recoveryHash) {
664     $recoveryPasswordInfos=array();
665     if ( self :: loadLSobject(self :: $ldapServer['authObjectType']) ) {
666       $authobject = new self :: $ldapServer['authObjectType']();
667       if (!empty($recoveryHash)) {
668         $filter=Net_LDAP2_Filter::create(
669           self :: $ldapServer['recoverPassword']['recoveryHashAttr'],
670           'equals',
671           $recoveryHash
672         );
673         $result = $authobject -> listObjects($filter,self :: $topDn,array('onlyAccessible' => false));
674       }
675       elseif (!empty($username)) {
676         $result = $authobject -> searchObject(
677                     $username,
678                     self :: $topDn,
679                     self :: $ldapServer['authObjectFilter'],
680                     array('onlyAccessible' => false)
681                   );
682       }
683       else {
684         return $recoveryPasswordInfos;
685       }
686       
687       $nbresult=count($result);
688       
689       if ($nbresult==0) {
690         LSdebug('hash/username incorrect');
691         LSerror :: addErrorCode('LSsession_06');  
692       }
693       elseif ($nbresult>1) {
694         LSerror :: addErrorCode('LSsession_07');
695       }
696       else {
697         $rdn = $result[0] -> getValue('rdn');
698         $username = $rdn[0];
699         LSdebug('Recover : Id trouvé : '.$username);
700         if (self :: $ldapServer['recoverPassword']) {
701           if (self :: loadLSaddon('mail')) {
702             LSdebug('Récupération active');
703             $user=$result[0];
704             $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
705             $emailAddress = $emailAddress[0];
706             
707             if (checkEmail($emailAddress)) {
708               LSdebug('Email : '.$emailAddress);
709               self :: $dn = $user -> getDn();
710               
711               // 1ère étape : envoie du recoveryHash
712               if (empty($recoveryHash)) {
713                 $hash=self :: recoverPasswdFirstStep($user);
714                 if ($hash) {
715                   if (self :: recoverPasswdSendMail($emailAddress,1,$hash)) {
716                     // Mail a bien été envoyé
717                     $recoveryPasswordInfos['recoveryHashMail']=$emailAddress;
718                   }
719                 }
720               }
721               // 2nd étape : génération du mot de passe + envoie par mail
722               else {
723                 $pwd=self :: recoverPasswdSecondStep($user);
724                 if ($pwd) {
725                   if (self :: recoverPasswdSendMail($emailAddress,2,$pwd)){
726                     // Mail a bien été envoyé
727                     $recoveryPasswordInfos['newPasswordMail']=$emailAddress;
728                   }
729                 }
730               }
731             }
732             else {
733               LSerror :: addErrorCode('LSsession_19');
734             }
735           }
736         }
737         else {
738           LSerror :: addErrorCode('LSsession_18');
739         }
740       }
741     }
742     return $recoveryPasswordInfos;
743   }
744   
745   /**
746    * Send recover password mail
747    * 
748    * @param[in] $mail string The user's mail
749    * @param[in] $step integer The step
750    * @param[in] $info string The info for formatted message
751    * 
752    * @retval boolean True on success or False
753    **/
754   private static function recoverPasswdSendMail($mail,$step,$info) {
755     // Header des mails
756     $sendParams=array();
757     if (self :: $ldapServer['recoverPassword']['recoveryEmailSender']) {
758       $sendParams['From']=self :: $ldapServer['recoverPassword']['recoveryEmailSender'];
759     }
760     
761     if ($step==1) {
762       if ($_SERVER['HTTPS']=='on') {
763         $recovery_url='https://';
764       }
765       else {
766         $recovery_url='http://';
767       }
768       $recovery_url .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'&recoveryHash='.$info;
769       
770       $subject = self :: $ldapServer['recoverPassword']['recoveryHashMail']['subject'];
771       $msg = getFData(
772         self :: $ldapServer['recoverPassword']['recoveryHashMail']['msg'],
773         $recovery_url
774       );
775     }
776     else {
777       $subject = self :: $ldapServer['recoverPassword']['newPasswordMail']['subject'];
778       $msg = getFData(
779         self :: $ldapServer['recoverPassword']['newPasswordMail']['msg'],
780         $info
781       );
782     }
783     
784     if (!sendMail($mail,$subject,$msg,$sendParams)) {
785       LSdebug("Problème durant l'envoie du mail");
786       LSerror :: addErrorCode('LSsession_20',4);
787       return;
788     }
789     return true;
790   }
791   
792   
793   /**
794    * Do first step of recovering password
795    * 
796    * @param[in] $user LSldapObject The LSldapObject of the user
797    * 
798    * @retval string|False The recory hash on success or False
799    **/
800   private static function recoverPasswdFirstStep($user) {
801     // Generer un hash
802     $rdn=$user -> getValue('rdn');
803     $rdn = $rdn[0];
804     $recovery_hash = md5($rdn . strval(time()) . strval(rand()));
805     
806     $lostPasswdForm = $user -> getForm('lostPassword');
807     $lostPasswdForm -> setPostData(
808       array(
809         self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => $recovery_hash
810       )
811       ,true
812     );
813       
814     if($lostPasswdForm -> validate()) {
815       if ($user -> updateData('lostPassword')) {
816         // recoveryHash de l'utilisateur mis à jour
817         return $recovery_hash;
818       }
819       else {
820         // Erreur durant la mise à jour de l'objet
821         LSdebug("Erreur durant la mise à jour de l'objet");
822         LSerror :: addErrorCode('LSsession_20',6);
823       }
824     }
825     else {
826       // Erreur durant la validation du formulaire de modification de perte de password
827       LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
828       LSerror :: addErrorCode('LSsession_20',5);
829     }
830     return;
831   }
832
833   /**
834    * Do second step of recovering password
835    * 
836    * @param[in] $user LSldapObject The LSldapObject of the user
837    * 
838    * @retval string|False The new password on success or False
839    **/
840   private static function recoverPasswdSecondStep($user) {
841     $attr=$user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']];
842     if ($attr instanceof LSattribute) {
843       $mdp = generatePassword(
844        $attr -> config['html_options']['chars'],
845        $attr -> config['html_options']['lenght']
846       );
847       LSdebug('Nvx mpd : '.$mdp);
848       $lostPasswdForm = $user -> getForm('lostPassword');
849       $lostPasswdForm -> setPostData(
850         array(
851           self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
852           self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp)
853         )
854         ,true
855       );
856       if($lostPasswdForm -> validate()) {
857         if ($user -> updateData('lostPassword')) {
858           return $mdp;
859         }
860         else {
861           // Erreur durant la mise à jour de l'objet
862           LSdebug("Erreur durant la mise à jour de l'objet");
863           LSerror :: addErrorCode('LSsession_20',3);
864         }
865       }
866       else {
867         // Erreur durant la validation du formulaire de modification de perte de password
868         LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
869         LSerror :: addErrorCode('LSsession_20',2);
870       }
871     }
872     else {
873       // l'attribut password n'existe pas
874       LSdebug("L'attribut password n'existe pas");
875       LSerror :: addErrorCode('LSsession_20',1);
876     }
877     return;
878   }
879   
880  /**
881   * Retourne les informations du contexte
882   *
883   * @author Benjamin Renard <brenard@easter-eggs.com
884   * 
885   * @retval array Tableau associatif des informations du contexte
886   */
887   private static function getContextInfos() {
888     return array(
889       'tmp_file' => self :: $tmp_file,
890       'topDn' => self :: $topDn,
891       'dn' => self :: $dn,
892       'rdn' => self :: $rdn,
893       'userLDAPcreds' => self :: $userLDAPcreds,
894       'ldapServerId' => self :: $ldapServerId,
895       'ldapServer' => self :: $ldapServer,
896       'LSprofiles' => self :: $LSprofiles,
897       'LSaccess' => self :: $LSaccess,
898       'LSaddonsViewsAccess' => self :: $LSaddonsViewsAccess
899     );
900   }
901   
902   /**
903   * Retourne l'objet de l'utilisateur connecté
904   *
905   * @author Benjamin Renard <brenard@easter-eggs.com
906   * 
907   * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
908   *               être créé
909   */
910   public static function getLSuserObject($dn=null) {
911     if ($dn) {
912       self :: $dn = $dn;
913     }
914     if (!self :: $LSuserObject) {
915       if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
916         self :: $LSuserObject = new self :: $ldapServer['authObjectType']();
917         self :: $LSuserObject -> loadData(self :: $dn);
918       }
919       else {
920         return;
921       }
922     }
923     return self :: $LSuserObject;
924   }
925   
926  /**
927   * Retourne le DN de l'utilisateur connecté
928   *
929   * @author Benjamin Renard <brenard@easter-eggs.com
930   * 
931   * @retval string Le DN de l'utilisateur connecté
932   */
933   public static function getLSuserObjectDn() {
934     return self :: $dn;
935   }
936
937  /**
938   * Modifie l'utilisateur connecté à la volé
939   * 
940   * @param[in] $object Mixed  L'objet Ldap du nouvel utilisateur
941   *                           le type doit correspondre à
942   *                           self :: $ldapServer['authObjectType']
943   * 
944   * @retval boolean True en cas de succès, false sinon
945   */
946  public static function changeAuthUser($object) {
947   if ($object instanceof self :: $ldapServer['authObjectType']) {
948     self :: $dn = $object -> getDn();
949     $rdn = $object -> getValue('rdn');
950     if(is_array($rdn)) {
951       $rdn = $rdn[0];
952     }
953     self :: $rdn = $rdn;
954     self :: $LSuserObject = $object;
955     
956     if(self :: loadLSprofiles()) {
957       self :: loadLSaccess();
958       self :: loadLSaddonsViewsAccess();
959       $_SESSION['LSsession']=self :: getContextInfos();
960       return true;
961     }
962   }
963   return;
964  }
965
966  /**
967   * Définition du serveur Ldap de la session
968   *
969   * Définition du serveur Ldap de la session Ã  partir de son ID dans 
970   * le tableau LSconfig :: get('ldap_servers').
971   *
972   * @param[in] integer Index du serveur Ldap
973   *
974   * @retval boolean True sinon false.
975   */
976   public static function setLdapServer($id) {
977     $conf = LSconfig :: get("ldap_servers.$id");
978     if ( is_array($conf) ) {
979       self :: $ldapServerId = $id;
980       self :: $ldapServer = $conf;
981       self :: setLocale();
982       self :: setGlobals();
983       return true;
984     }
985     else {
986       return;
987     }
988   }
989
990  /**
991   * Connexion au serveur Ldap
992   *
993   * @retval boolean True sinon false.
994   */
995   public static function LSldapConnect() {
996     if (self :: $ldapServer) {
997       self :: includeFile(LSconfig :: get('NetLDAP2'));
998       if (!self :: loadLSclass('LSldap')) {
999         return;
1000       }
1001       if (self :: $dn && isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) {
1002         LSldap :: reconnectAs(self :: $userLDAPcreds['dn'], self :: $userLDAPcreds['pwd'],self :: $ldapServer['ldap_config']);
1003       }
1004       else {
1005         LSldap :: connect(self :: $ldapServer['ldap_config']);
1006       }
1007       if (LSldap :: isConnected()) {
1008         return true;
1009       }
1010       else {
1011         return;
1012       }
1013     }
1014     else {
1015       LSerror :: addErrorCode('LSsession_03');
1016       return;
1017     }
1018   }
1019
1020   /**
1021    * Use this function to know if subDn is enabled for the curent LdapServer
1022    * 
1023    * @retval boolean
1024    **/
1025   public static function subDnIsEnabled() {
1026     if (!isset(self :: $ldapServer['subDn'])) {
1027       return;
1028     }
1029     if ( !is_array(self :: $ldapServer['subDn']) ) {
1030       return;
1031     }
1032     return true;
1033   }
1034
1035  /**
1036   * Retourne les sous-dns du serveur Ldap courant
1037   *
1038   * @retval mixed Tableau des subDn, false si une erreur est survenue.
1039   */
1040   public static function getSubDnLdapServer($login=false) {
1041     $login=(bool)$login;
1042     if (self :: cacheSudDn() && isset(self :: $_subDnLdapServer[self :: $ldapServerId][$login])) {
1043       return self :: $_subDnLdapServer[self :: $ldapServerId][$login];
1044     }
1045     if (!self::subDnIsEnabled()) {
1046       return;
1047     }
1048     $return=array();
1049     foreach(self :: $ldapServer['subDn'] as $subDn_name => $subDn_config) {
1050       if ($login && isset($subDn_config['nologin']) && $subDn_config['nologin']) continue;
1051       if ($subDn_name == 'LSobject') {
1052         if (is_array($subDn_config)) {
1053           foreach($subDn_config as $LSobject_name => $LSoject_config) {
1054             if (isset($LSoject_config['basedn']) && !empty($LSoject_config['basedn'])) {
1055               $basedn = $LSoject_config['basedn'];
1056             }
1057             else {
1058               $basedn = self::getRootDn();
1059             }
1060             if (isset($LSoject_config['displayName']) && !empty($LSoject_config['displayName'])) {
1061               $displayName = $LSoject_config['displayName'];
1062             }
1063             else {
1064               $displayName = NULL;
1065             }
1066             $sparams = array();
1067             $sparams['onlyAccessible'] = (isset($LSoject_config['onlyAccessible'])?$LSoject_config['onlyAccessible']:False);
1068             if( self :: loadLSobject($LSobject_name) ) {
1069               if ($subdnobject = new $LSobject_name()) {
1070                 $tbl_return = $subdnobject -> getSelectArray(NULL,$basedn,$displayName,false,false,NULL,$sparams);
1071                 if (is_array($tbl_return)) {
1072                   $return=array_merge($return,$tbl_return);
1073                 }
1074                 else {
1075                   LSerror :: addErrorCode('LSsession_17',3);
1076                 }
1077               }
1078               else {
1079                 LSerror :: addErrorCode('LSsession_17',2);
1080               }
1081             }
1082           }
1083         }
1084         else {
1085           LSerror :: addErrorCode('LSsession_17',1);
1086         }
1087       }
1088       else {
1089         if ((isCompatibleDNs($subDn_config['dn'],self :: $ldapServer['ldap_config']['basedn']))&&($subDn_config['dn']!="")) {
1090           $return[$subDn_config['dn']] = __($subDn_name);
1091         }
1092       }
1093     }
1094     if (self :: cacheSudDn()) {
1095       self :: $_subDnLdapServer[self :: $ldapServerId][$login]=$return;
1096       $_SESSION['LSsession_subDnLdapServer'] = self :: $_subDnLdapServer;
1097     }
1098     return $return;
1099   }
1100   
1101   /**
1102    * Retourne la liste de subDn du serveur Ldap utilise
1103    * trié par la profondeur dans l'arboressence (ordre décroissant)
1104    * 
1105    * @return array() Tableau des subDn trié
1106    */  
1107   public static function getSortSubDnLdapServer($login=false) {
1108     $subDnLdapServer = self :: getSubDnLdapServer($login);
1109     if (!$subDnLdapServer) {
1110       return array();
1111     }
1112     uksort($subDnLdapServer,"compareDn");
1113     return $subDnLdapServer;
1114   }
1115
1116  /**
1117   * Retourne les options d'une liste déroulante pour le choix du topDn
1118   * de connexion au serveur Ldap
1119   *
1120   * Liste les subdn (self :: $ldapServer['subDn'])
1121   *
1122   * @retval string Les options (<option>) pour la sélection du topDn.
1123   */
1124   public static function getSubDnLdapServerOptions($selected=NULL,$login=false) {
1125     $list = self :: getSubDnLdapServer($login);
1126     if ($list) {
1127       asort($list);
1128       $display='';
1129       foreach($list as $dn => $txt) {
1130         if ($selected && ($selected==$dn)) {
1131           $selected_txt = ' selected';
1132         }
1133         else {
1134           $selected_txt = '';
1135         }
1136         $display.="<option value=\"".$dn."\"$selected_txt>".$txt."</option>\n"; 
1137       }
1138       return $display;
1139     }
1140     return;
1141   }
1142
1143  /**
1144   * Vérifie qu'un subDn est déclaré
1145   *
1146   * @param[in] string Un subDn
1147   * 
1148   * @retval boolean True si le subDn existe, False sinon
1149   */
1150   public static function validSubDnLdapServer($subDn) {
1151     $listTopDn = self :: getSubDnLdapServer();
1152     if(is_array($listTopDn)) {
1153       foreach($listTopDn as $dn => $txt) {
1154         if ($subDn==$dn) {
1155           return true;
1156         } // end if
1157       } // end foreach
1158     } // end if
1159     return;
1160   }
1161
1162  /**
1163   * Test un couple LSobject/pwd
1164   *
1165   * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni.
1166   *
1167   * @param[in] LSobject L'object "user" pour l'authentification
1168   * @param[in] string Le mot de passe Ã  tester
1169   *
1170   * @retval boolean True si l'authentification Ã  réussi, false sinon.
1171   */
1172   public static function checkUserPwd($object,$pwd) {
1173     return LSldap :: checkBind($object -> getValue('dn'),$pwd);
1174   }
1175
1176  /**
1177   * Affiche le formulaire de login
1178   *
1179   * Défini les informations pour le template Smarty du formulaire de login.
1180   *
1181   * @retval void
1182   */
1183   public static function displayLoginForm() {
1184     LStemplate :: assign('pagetitle',_('Connection'));
1185     if (isset($_GET['LSsession_logout'])) {
1186       LStemplate :: assign('loginform_action','index.php');
1187     }
1188     else {
1189       LStemplate :: assign('loginform_action',$_SERVER['REQUEST_URI']);
1190     }
1191     if (count(LSconfig :: get('ldap_servers'))==1) {
1192       LStemplate :: assign('loginform_ldapserver_style','style="display: none"');
1193     }
1194     LStemplate :: assign('loginform_label_ldapserver',_('LDAP server'));
1195     $ldapservers_name=array();
1196     $ldapservers_index=array();
1197     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1198       $ldapservers_index[]=$id;
1199       $ldapservers_name[]=__($infos['name']);
1200     }
1201     LStemplate :: assign('loginform_ldapservers_name',$ldapservers_name);
1202     LStemplate :: assign('loginform_ldapservers_index',$ldapservers_index);
1203
1204     LStemplate :: assign('loginform_label_level',_('Level'));
1205     LStemplate :: assign('loginform_label_user',_('Identifier'));
1206     LStemplate :: assign('loginform_label_pwd',_('Password'));
1207     LStemplate :: assign('loginform_label_submit',_('Connect'));
1208     LStemplate :: assign('loginform_label_recoverPassword',_('Forgot your password ?'));
1209     
1210     self :: setTemplate('login.tpl');
1211     self :: addJSscript('LSsession_login.js');
1212   }
1213
1214  /**
1215   * Affiche le formulaire de récupération de mot de passe
1216   *
1217   * Défini les informations pour le template Smarty du formulaire de 
1218   * récupération de mot de passe
1219   * 
1220   * @param[in] $infos array() Information sur le status du processus de 
1221   *                           recouvrement de mot de passe
1222   *
1223   * @retval void
1224   */
1225   public static function displayRecoverPasswordForm($recoveryPasswordInfos) {
1226     LStemplate :: assign('pagetitle',_('Recovery of your credentials'));
1227     LStemplate :: assign('recoverpasswordform_action','index.php?LSsession_recoverPassword');
1228     
1229     if (count(LSconfig :: get('ldap_servers'))==1) {
1230       LStemplate :: assign('recoverpasswordform_ldapserver_style','style="display: none"');
1231     }
1232     
1233     LStemplate :: assign('recoverpasswordform_label_ldapserver',_('LDAP server'));
1234     $ldapservers_name=array();
1235     $ldapservers_index=array();
1236     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1237       $ldapservers_index[]=$id;
1238       $ldapservers_name[]=$infos['name'];
1239     }
1240     LStemplate :: assign('recoverpasswordform_ldapservers_name',$ldapservers_name);
1241     LStemplate :: assign('recoverpasswordform_ldapservers_index',$ldapservers_index);
1242
1243     LStemplate :: assign('recoverpasswordform_label_user',_('Identifier'));
1244     LStemplate :: assign('recoverpasswordform_label_submit',_('Validate'));
1245     LStemplate :: assign('recoverpasswordform_label_back',_('Back'));
1246     
1247     $recoverpassword_msg = _('Please fill the identifier field to proceed recovery procedure');
1248     
1249     if (isset($recoveryPasswordInfos['recoveryHashMail'])) {
1250       $recoverpassword_msg = getFData(
1251         _("An email has been sent to  %{mail}. " .
1252         "Please follow the instructions on it."),
1253         $recoveryPasswordInfos['recoveryHashMail']
1254       );
1255     }
1256     
1257     if (isset($recoveryPasswordInfos['newPasswordMail'])) {
1258       $recoverpassword_msg = getFData(
1259         _("Your new password has been sent to %{mail}. "),
1260         $recoveryPasswordInfos['newPasswordMail']
1261       );
1262     }
1263     
1264     LStemplate :: assign('recoverpassword_msg',$recoverpassword_msg);
1265     
1266     self :: setTemplate('recoverpassword.tpl');
1267     self :: addJSscript('LSsession_recoverPassword.js');
1268   }
1269
1270  /**
1271   * Défini le template Smarty Ã  utiliser
1272   *
1273   * Remarque : les fichiers de templates doivent se trouver dans le dossier 
1274   * templates/.
1275   *
1276   * @param[in] string Le nom du fichier de template
1277   *
1278   * @retval void
1279   */
1280   public static function setTemplate($template) {
1281     self :: $template = $template;
1282   }
1283
1284  /**
1285   * Ajoute un script JS au chargement de la page
1286   *
1287   * Remarque : les scripts doivents Ãªtre dans le dossier LS_JS_DIR.
1288   *
1289   * @param[in] $script Le nom du fichier de script Ã  charger.
1290   *
1291   * @retval void
1292   */
1293   public static function addJSscript($file,$path=NULL) {
1294     $script=array(
1295       'file' => $file,
1296       'path' => $path
1297     );
1298     self :: $JSscripts[$path.$file]=$script;
1299   }
1300
1301  /**
1302   * Ajouter un paramètre de configuration Javascript
1303   * 
1304   * @param[in] $name string Nom de la variable de configuration
1305   * @param[in] $val mixed Valeur de la variable de configuration
1306   *
1307   * @retval void
1308   */
1309   public static function addJSconfigParam($name,$val) {
1310     self :: $_JSconfigParams[$name]=$val;
1311   }
1312
1313  /**
1314   * Ajoute une feuille de style au chargement de la page
1315   *
1316   * @param[in] $script Le nom du fichier css Ã  charger.
1317   *
1318   * @retval void
1319   */
1320   public static function addCssFile($file,$path=NULL) {
1321     if ($path) {
1322       $file = $path.$file;
1323     }
1324     else {
1325       $file = LStemplate :: getCSSPath($file);
1326     }
1327     self :: $CssFiles[$file]=$file;
1328   }
1329
1330  /**
1331   * Affiche le template Smarty
1332   *
1333   * Charge les dépendances et affiche le template Smarty
1334   *
1335   * @retval void
1336   */
1337   public static function displayTemplate() {
1338     // JS
1339     $JSscript_txt='';
1340     foreach ($GLOBALS['defaultJSscipts'] as $script) {
1341       $JSscript_txt.="<script src='".LS_JS_DIR.$script."' type='text/javascript'></script>\n";
1342     }
1343
1344     foreach (self :: $JSscripts as $script) {
1345       if (!$script['path']) {
1346         $script['path']=LS_JS_DIR;
1347       }
1348       else {
1349         $script['path'].='/';
1350       }
1351       $JSscript_txt.="<script src='".$script['path'].$script['file']."' type='text/javascript'></script>\n";
1352     }
1353
1354     $KAconf = LSconfig :: get('keepLSsessionActive');
1355     if ( 
1356           (
1357             (!isset(self :: $ldapServer['keepLSsessionActive']))
1358             &&
1359             (!($KAconf === false))
1360           )
1361           ||
1362           (self :: $ldapServer['keepLSsessionActive'])
1363         ) {
1364       self :: addJSconfigParam('keepLSsessionActive',ini_get('session.gc_maxlifetime'));
1365     }
1366
1367     LStemplate :: assign('LSjsConfig',json_encode(self :: $_JSconfigParams));
1368     
1369     if (LSdebug) {
1370       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 1;</script>\n";
1371     }
1372     else {
1373       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 0;</script>\n";
1374     }
1375     
1376     LStemplate :: assign('LSsession_js',$JSscript_txt);
1377
1378     // Css
1379     self :: addCssFile("LSdefault.css");
1380     if (isset($GLOBALS['defaultCSSfiles']) && is_array($GLOBALS['defaultCSSfiles'])) {
1381       foreach ($GLOBALS['defaultCSSfiles'] as $file) {
1382         self :: addCssFile($file);
1383       }
1384     }
1385     $Css_txt='';
1386     foreach (self :: $CssFiles as $file) {
1387       $Css_txt.="<link rel='stylesheet' type='text/css' href='".$file."' />\n";
1388     }
1389     LStemplate :: assign('LSsession_css',$Css_txt);
1390   
1391     if (isset(self :: $LSaccess[self :: $topDn])) {
1392       LStemplate :: assign('LSaccess',self :: $LSaccess[self :: $topDn]);
1393     }
1394     LStemplate :: assign('LSaddonsViewsAccess',self :: $LSaddonsViewsAccess);
1395     
1396     // Niveau
1397     $listTopDn = self :: getSubDnLdapServer();
1398     if (is_array($listTopDn)) {
1399       asort($listTopDn);
1400       LStemplate :: assign('label_level',self :: getSubDnLabel());
1401       LStemplate :: assign('_refresh',_('Refresh'));
1402       $LSsession_topDn_index = array();
1403       $LSsession_topDn_name = array();
1404       foreach($listTopDn as $index => $name) {
1405         $LSsession_topDn_index[]  = $index;
1406         $LSsession_topDn_name[]   = $name;
1407       }
1408       LStemplate :: assign('LSsession_subDn_indexes',$LSsession_topDn_index);
1409       LStemplate :: assign('LSsession_subDn_names',$LSsession_topDn_name);
1410       LStemplate :: assign('LSsession_subDn',self :: $topDn);
1411       LStemplate :: assign('LSsession_subDnName',self :: getSubDnName());
1412     }
1413     
1414     LStemplate :: assign('LSlanguages',self :: getLangList());
1415     LStemplate :: assign('LSlang',self :: $lang);
1416     LStemplate :: assign('LSencoding',self :: $encoding);
1417     LStemplate :: assign('lang_label',_('Language'));
1418     
1419     LStemplate :: assign('displayLogoutBtn',LSauth :: displayLogoutBtn());
1420     LStemplate :: assign('displaySelfAccess',LSauth :: displaySelfAccess());
1421
1422     // Infos
1423     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1424       $txt_infos="<ul>\n";
1425       foreach($_SESSION['LSsession_infos'] as $info) {
1426         $txt_infos.="<li>$info</li>\n";
1427       }
1428       $txt_infos.="</ul>\n";
1429       LStemplate :: assign('LSinfos',$txt_infos);
1430       $_SESSION['LSsession_infos']=array();
1431     }
1432     
1433     if (self :: $ajaxDisplay) {
1434       LStemplate :: assign('LSerror_txt',LSerror :: getErrors());
1435       LStemplate :: assign('LSdebug_txt',LSdebug_print(true));
1436     }
1437     else {
1438       LSerror :: display();
1439       LSdebug_print();
1440     }
1441     if (!self :: $template)
1442       self :: setTemplate('empty.tpl');
1443       
1444     LStemplate :: assign('connected_as',_("Connected as"));
1445     
1446     LStemplate :: display(self :: $template);
1447   }
1448   
1449  /**
1450   * Défini que l'affichage se fera ou non via un retour Ajax
1451   * 
1452   * @param[in] $val boolean True pour que l'affichage se fasse par un retour
1453   *                         Ajax, false sinon
1454   * @retval void
1455   */
1456   public static function setAjaxDisplay($val=true) {
1457     self :: $ajaxDisplay = (boolean)$val;
1458   }
1459   
1460  /**
1461   * Affiche un retour Ajax
1462   *
1463   * @retval void
1464   */
1465   public static function displayAjaxReturn($data=array()) {
1466     if (isset($data['LSredirect']) && (!LSdebugDefined()) ) {
1467       echo json_encode($data);
1468       return;
1469     }
1470     
1471     $data['LSjsConfig'] = self :: $_JSconfigParams;
1472     
1473     // Infos
1474     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1475       $txt_infos="<ul>\n";
1476       foreach($_SESSION['LSsession_infos'] as $info) {
1477         $txt_infos.="<li>$info</li>\n";
1478       }
1479       $txt_infos.="</ul>\n";
1480       $data['LSinfos'] = $txt_infos;
1481       $_SESSION['LSsession_infos']=array();
1482     }
1483     
1484     if (LSerror :: errorsDefined()) {
1485       $data['LSerror'] = LSerror :: getErrors();
1486     }
1487
1488     if (isset($_REQUEST['imgload'])) {
1489       $data['imgload'] = $_REQUEST['imgload'];
1490     }
1491
1492     if (LSdebugDefined()) {
1493       $data['LSdebug'] = LSdebug_print(true,false);
1494     }
1495
1496     echo json_encode($data);  
1497   }
1498  
1499  /**
1500   * Retournne un template Smarty compilé
1501   *
1502   * @param[in] string $template Le template à retourner
1503   * @param[in] array $variables Variables Smarty à assigner avant l'affichage
1504   * 
1505   * @retval string Le HTML compilé du template
1506   */
1507   public static function fetchTemplate($template,$variables=array()) {
1508     foreach($variables as $name => $val) {
1509       LStemplate :: assign($name,$val);
1510     }
1511     return LStemplate :: fetch($template);
1512   }
1513   
1514   /**
1515    * Prend un tableau de LSobject et le réduit en utilisant un filtre de
1516    * recherche sur un autre type de LSobject.
1517    *
1518    * Si une erreur est présente dans le tableau de définition du filtre, un
1519    * tableau vide est renvoyé.
1520    *
1521    * @param[in] string $LSobject le type LSobject par défaut
1522    * @param[in] array $set tableau de LSobject
1523    * @param[in] array $filter_def définition du filtre de recherche pour la réduction
1524    * @param[in] string $basend basedn pour la recherche, null par défaut
1525    *
1526    * @retval array le nouveau tableau de LSobject
1527    */
1528   private static function reduceLdapSet($LSobject, $set, $filter_def, $basedn=null) {
1529     if (empty($set)) {
1530       return array();
1531     }
1532
1533     if (! isset($filter_def['filter']) &&
1534           (! isset($filter_def['attr']) ||
1535            ! isset($filter_def['attr_value']))) {
1536       LSdebug("Filtre de profil LSobject invalide " . var_export($filter_def, true));
1537       return array();
1538     }
1539
1540     LSdebug('LSsession :: reducing set of');
1541     foreach ($set as $object) {
1542       LSdebug('LSsession :: -> ' . $object -> getDn());
1543     }
1544
1545     $LSobject = isset($filter_def['LSObject']) ? $filter_def['LSobject'] : $LSobject;
1546     LSdebug('LSobject :: ' . $LSobject);
1547     $filters = array();
1548     foreach ($set as $object) {
1549       if (isset($filter_def['filter'])) {
1550         $filters[] = $object -> getFData($filter_def['filter']);
1551       }
1552       else {
1553         $value = $object -> getFData($filter_def['attr_value']);
1554         $filters[] = Net_LDAP2_Filter::create($filter_def['attr'], 'equals', $value);
1555       }
1556     }
1557     $filter = LSldap::combineFilters('or', $filters);
1558     $params = array(
1559       'basedn' => isset($filter_def['basedn']) ? $filter_def['basedn'] : $basedn,
1560       'filter' => $filter,
1561       'onlyAccessible' => False
1562     );
1563     if (isset($filter_def['params']) && is_array($filter_def['params'])) {
1564       $params = array_merge($filter_def['params'],$params);
1565     }
1566     $LSsearch = new LSsearch($LSobject,'LSsession :: loadLSprofiles',$params,true);
1567     $LSsearch -> run(false);
1568
1569     $set = $LSsearch -> listObjects();
1570     LSdebug('LSsession :: reduced set to');
1571     foreach ($set as $object) {
1572       LSdebug('LSsession :: -> ' . $object -> getDn());
1573     }
1574     return $set;
1575   }
1576
1577   /**
1578    * Charge les droits LS de l'utilisateur : uniquement du type LSobjects
1579    *
1580    * @param[in] string $
1581    *
1582    * @retval void
1583    */
1584   private static function loadLSprofilesLSobjects($profile, $LSobject, $listInfos) {
1585     if (! self :: loadLSclass('LSsearch')) {
1586       LSdebug('Impossible de charger la classe LSsearch');
1587       return;
1588     }
1589     # we are gonna grow a set of objects progressively, we start from the user
1590     $set = array(self :: getLSuserObject());
1591     $basedn = isset($listInfos['basedn']) ? $listInfos['basedn'] : null;
1592     $LSobject = isset($listInfos['LSobject']) ? $listInfos['LSobject'] : $LSobject;
1593
1594     if (isset($listInfos['filters']) && is_array($listInfos['filters'])) {
1595       foreach ($listInfos['filters'] as $filter_def) {
1596         $set = self :: reduceLdapSet($LSobject, $set, $filter_def, $basedn);
1597       }
1598     }
1599     if (isset($listInfos['filter']) || (isset($listInfos['attr']) && isset($listInfos['attr_value']))) {
1600       # support legacy profile definition
1601       $set = self :: reduceLdapSet($LSobject, $set, $listInfos, $basedn);
1602     }
1603
1604     $DNs = [];
1605     foreach ($set as $object) {
1606       $DNs[] = $object -> getDn();
1607     }
1608     if (!is_array(self :: $LSprofiles[$profile])) {
1609       self :: $LSprofiles[$profile]=$DNs;
1610     }
1611     else {
1612       foreach($DNs as $dn) {
1613         if (!in_array($dn,self :: $LSprofiles[$profile])) {
1614           self :: $LSprofiles[$profile][] = $dn;
1615         }
1616       }
1617     }
1618   }
1619
1620   /**
1621    * Charge les droits LS de l'utilisateur
1622    * 
1623    * @retval boolean True si le chargement Ã  réussi, false sinon.
1624    **/
1625   private static function loadLSprofiles() {
1626     if (is_array(self :: $ldapServer['LSprofiles'])) {
1627       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1628         if (is_array($profileInfos)) {
1629           foreach ($profileInfos as $topDn => $rightsInfos) {
1630             /*
1631              * If $topDn == 'LSobject', we search for each LSobject type to find
1632              * all items on witch the user will have powers.
1633              */
1634             if ($topDn == 'LSobjects') {
1635               if (is_array($rightsInfos)) {
1636                 foreach ($rightsInfos as $LSobject => $listInfos) {
1637                   LSdebug('loading LSprofile ' . $profile . ' for LSobject ' . $LSobject . ' with params ' . var_export($listInfos, true));
1638                   self :: loadLSprofilesLSobjects($profile, $LSobject, $listInfos);
1639                 }
1640               }
1641               else {
1642                 LSdebug('LSobjects => [] doit etre un tableau');
1643               }
1644             }
1645             else {
1646               if (is_array($rightsInfos)) {
1647                 foreach($rightsInfos as $dn => $conf) {
1648                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1649                     if( self :: loadLSobject($conf['LSobject']) ) {
1650                       if ($object = new $conf['LSobject']()) {
1651                         if ($object -> loadData($dn)) {
1652                           $listDns=$object -> getValue($conf['attr']);
1653                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1654                           $val = self :: getLSuserObject() -> getFData($valKey);
1655                           if (is_array($listDns)) {
1656                             if (in_array($val,$listDns)) {
1657                               self :: $LSprofiles[$profile][] = $topDn;
1658                             }
1659                           }
1660                         }
1661                         else {
1662                           LSdebug('Impossible de chargé le dn : '.$dn);
1663                         }
1664                       }
1665                       else {
1666                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1667                       }
1668                     }
1669                   }
1670                   else {
1671                     if (self :: $dn == $dn) {
1672                       self :: $LSprofiles[$profile][] = $topDn;
1673                     }
1674                   }
1675                 }
1676               }
1677               else {
1678                 if ( self :: $dn == $rightsInfos ) {
1679                   self :: $LSprofiles[$profile][] = $topDn;
1680                 }
1681               }
1682             } // fin else ($topDn == 'LSobjects')
1683           } // fin foreach($profileInfos)
1684         } // fin is_array($profileInfos)
1685       } // fin foreach LSprofiles
1686       LSdebug("LSprofiles : ".print_r(self :: $LSprofiles,1));
1687       return true;
1688     }
1689     else {
1690       return;
1691     }
1692   }
1693   
1694   /**
1695    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1696    *
1697    * @retval void
1698    */
1699   private static function loadLSaccess() {
1700     $LSaccess=array();
1701     if (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn'])) {
1702       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1703         if ($name=='LSobject') {
1704           if (is_array($config)) {
1705
1706             // Définition des subDns 
1707             foreach($config as $objectType => $objectConf) {
1708               if (self :: loadLSobject($objectType)) {
1709                 if ($subdnobject = new $objectType()) {
1710                   $tbl = $subdnobject -> getSelectArray(NULL,self::getRootDn(),NULL,NULL,false,NULL,array('onlyAccessible' => False));
1711                   if (is_array($tbl)) {
1712                     // Définition des accès
1713                     $access=array();
1714                     if (is_array($objectConf['LSobjects'])) {
1715                       foreach($objectConf['LSobjects'] as $type) {
1716                         if (self :: loadLSobject($type)) {
1717                           if (self :: canAccess($type)) {
1718                             $access[$type] = LSconfig :: get('LSobjects.'.$type.'.label');
1719                           }
1720                         }
1721                       }
1722                     }
1723                     foreach($tbl as $dn => $dn_name) {
1724                       $LSaccess[$dn]=$access;
1725                     }
1726                   }
1727                 }
1728               }
1729             }
1730           }
1731         }
1732         else {
1733           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1734             $access=array();
1735             if (is_array($config['LSobjects'])) {
1736               foreach($config['LSobjects'] as $objectType) {
1737                 if (self :: loadLSobject($objectType)) {
1738                   if (self :: canAccess($objectType)) {
1739                     $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1740                   }
1741                 }
1742               }
1743             }
1744             $LSaccess[$config['dn']]=$access;
1745           }
1746         }
1747       }
1748     }
1749     else {
1750       if(is_array(self :: $ldapServer['LSaccess'])) {
1751         $access=array();
1752         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1753           if (self :: loadLSobject($objectType)) {
1754             if (self :: canAccess($objectType)) {
1755                 $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1756             }
1757           }
1758         }
1759         $LSaccess[self :: $topDn] = $access;
1760       }
1761     }
1762     if (LSauth :: displaySelfAccess()) {
1763       foreach($LSaccess as $dn => $access) {
1764         $LSaccess[$dn] = array_merge(
1765           array(
1766             'SELF' => 'My account'
1767           ),
1768           $access
1769         );
1770       }
1771     }
1772     self :: $LSaccess = $LSaccess;
1773     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1774   }
1775
1776   /**
1777    * Load user access to LSaddons views
1778    *
1779    * @retval void
1780    */
1781   private static function loadLSaddonsViewsAccess() {
1782     $LSaddonsViewsAccess=array();
1783     foreach (self :: $LSaddonsViews as $addon => $conf) {
1784       foreach ($conf as $viewId => $viewConf) {
1785         if (self :: canAccessLSaddonView($addon,$viewId)) {
1786           $LSaddonsViewsAccess[]=array (
1787             'LSaddon' => $addon,
1788             'id' => $viewId,
1789             'label' => $viewConf['label'],
1790             'showInMenu' => $viewConf['showInMenu']
1791           );
1792         }
1793       }
1794     }
1795     self :: $LSaddonsViewsAccess = $LSaddonsViewsAccess;
1796     $_SESSION['LSsession']['LSaddonsViewsAccess'] = $LSaddonsViewsAccess;
1797   }
1798
1799
1800   /**
1801    * Dit si l'utilisateur est du profil pour le DN spécifié
1802    *
1803    * @param[in] string $dn DN de l'objet
1804    * @param[in] string $profile Profil
1805    *
1806    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1807    */
1808   public static function isLSprofile($dn,$profile) {
1809     if (is_array(self :: $LSprofiles[$profile])) {
1810       foreach(self :: $LSprofiles[$profile] as $topDn) {
1811         if($dn == $topDn) {
1812           return true;
1813         }
1814         else if ( isCompatibleDNs($dn,$topDn) ) {
1815           return true;
1816         }
1817       }
1818     }
1819     return;
1820   }
1821
1822   /**
1823    * Dit si l'utilisateur est d'au moins un des profils pour le DN spécifié
1824    *
1825    * @param[in] string $dn DN de l'objet
1826    * @param[in] string $profiles Profils
1827    *
1828    * @retval boolean True si l'utilisateur est d'au moins un profil sur l'objet, false sinon.
1829    */
1830   public static function isLSprofiles($dn,$profiles) {
1831     foreach ($profiles as $profile) {
1832       if (self :: isLSprofile($dn,$profile))
1833         return true;
1834     }
1835     return false;
1836   }
1837   
1838   /**
1839    * Retourne qui est l'utilisateur par rapport Ã  l'object
1840    *
1841    * @param[in] string Le DN de l'objet
1842    * 
1843    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1844    */
1845   public static function whoami($dn) {
1846     $retval = array('user');
1847     
1848     foreach(self :: $LSprofiles as $profile => $infos) {
1849       if(self :: isLSprofile($dn,$profile)) {
1850        $retval[]=$profile;
1851       }
1852     }
1853     
1854     if (self :: $dn == $dn) {
1855       $retval[]='self';
1856     }
1857     
1858     return $retval;
1859   }
1860   
1861   /**
1862    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1863    * 
1864    * @param[in] string $LSobject Le type de l'objet
1865    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1866    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1867    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1868    *
1869    * @retval boolean True si l'utilisateur a accès, false sinon
1870    */
1871   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1872     if (!self :: loadLSobject($LSobject)) {
1873       return;
1874     }
1875     if ($dn) {
1876       $whoami = self :: whoami($dn);
1877       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1878         if (!self :: in_menu('SELF')) {
1879           return;
1880         }
1881       }
1882       else {
1883         $obj = new $LSobject();
1884         $obj -> dn = $dn;
1885         if (!self :: in_menu($LSobject,$obj -> subDnValue)) {
1886           return;
1887         }
1888       }
1889     }
1890     else {
1891       $objectdn=LSconfig :: get('LSobjects.'.$LSobject.'.container_dn').','.self :: $topDn;
1892       $whoami = self :: whoami($objectdn);
1893     }
1894     
1895     // Pour un attribut particulier
1896     if ($attr) {
1897       if ($attr=='rdn') {
1898         $attr=LSconfig :: get('LSobjects.'.$LSobject.'.rdn');
1899       }
1900       if (!is_array(LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr))) {
1901         return;
1902       }
1903
1904       $r = 'n';
1905       foreach($whoami as $who) {
1906         $nr = LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr.'.rights.'.$who);
1907         if($nr == 'w') {
1908           $r = 'w';
1909         }
1910         else if($nr == 'r') {
1911           if ($r=='n') {
1912             $r='r';
1913           }
1914         }
1915       }
1916       
1917       if (($right=='r')||($right=='w')) {
1918         if ($r==$right) {
1919           return true;
1920         }
1921         return;
1922       }
1923       else {
1924         if ( ($r=='r') || ($r=='w') ) {
1925           return true;
1926         }
1927         return;
1928       }
1929     }
1930     
1931     // Pour un attribut quelconque
1932     $attrs_conf=LSconfig :: get('LSobjects.'.$LSobject.'.attrs');
1933     if (is_array($attrs_conf)) {
1934       if (($right=='r')||($right=='w')) {
1935         foreach($whoami as $who) {
1936           foreach ($attrs_conf as $attr_name => $attr_config) {
1937             if (isset($attr_config['rights'][$who]) && $attr_config['rights'][$who]==$right) {
1938               return true;
1939             }
1940           }
1941         }
1942       }
1943       else {
1944         foreach($whoami as $who) {
1945           foreach ($attrs_conf as $attr_name => $attr_config) {
1946             if ( (isset($attr_config['rights'][$who])) && ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) ) {
1947               return true;
1948             }
1949           }
1950         }
1951       }
1952     }
1953     return;
1954   }
1955   
1956   /**
1957    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1958    * 
1959    * @param[in] string $LSobject Le type de l'objet
1960    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1961    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1962    *
1963    * @retval boolean True si l'utilisateur a accès, false sinon
1964    */
1965   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1966     return self :: canAccess($LSobject,$dn,'w',$attr);
1967   }
1968
1969   /**
1970    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1971    * 
1972    * @param[in] string $LSobject Le type de l'objet
1973    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1974    *
1975    * @retval boolean True si l'utilisateur a accès, false sinon
1976    */  
1977   public static function canRemove($LSobject,$dn) {
1978     return self :: canAccess($LSobject,$dn,'w','rdn');
1979   }
1980   
1981   /**
1982    * Retourne le droit de l'utilisateur Ã  créer un objet
1983    * 
1984    * @param[in] string $LSobject Le type de l'objet
1985    *
1986    * @retval boolean True si l'utilisateur a accès, false sinon
1987    */    
1988   public static function canCreate($LSobject) {
1989     if (!self :: loadLSobject($LSobject)) {
1990       return;
1991     }
1992     if (LSconfig :: get("LSobjects.$LSobject.disable_creation")) {
1993       return;
1994     }
1995     return self :: canAccess($LSobject,NULL,'w','rdn');
1996   }
1997   
1998   /**
1999    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
2000    * 
2001    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
2002    * @param[in] string $LSobject Le type de l'objet
2003    * @param[in] string $relationName Le nom de la relation avec l'objet
2004    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
2005    *
2006    * @retval boolean True si l'utilisateur a accès, false sinon
2007    */
2008   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
2009     $relConf=LSconfig :: get('LSobjects.'.$LSobject.'.LSrelation.'.$relationName);
2010     if (!is_array($relConf))
2011       return;
2012     $whoami = self :: whoami($dn);
2013
2014     if (($right=='w') || ($right=='r')) {
2015       $r = 'n';
2016       foreach($whoami as $who) {
2017         $nr = ((isset($relConf['rights'][$who]))?$relConf['rights'][$who]:'');
2018         if($nr == 'w') {
2019           $r = 'w';
2020         }
2021         else if($nr == 'r') {
2022           if ($r=='n') {
2023             $r='r';
2024           }
2025         }
2026       }
2027       
2028       if ($r == $right) {
2029         return true;
2030       }
2031     }
2032     else {
2033       foreach($whoami as $who) {
2034         if ((isset($relConf['rights'][$who])) && ( ($relConf['rights'][$who] == 'w') || ($relConf['rights'][$who] == 'r') ) ) {
2035           return true;
2036         }
2037       }
2038     }
2039     return;
2040   }
2041
2042   /**
2043    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
2044    * 
2045    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
2046    * @param[in] string $LSobject Le type de l'objet
2047    * @param[in] string $relationName Le nom de la relation avec l'objet
2048    *
2049    * @retval boolean True si l'utilisateur a accès, false sinon
2050    */  
2051   public static function relationCanEdit($dn,$LSobject,$relationName) {
2052     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
2053   }
2054
2055   /**
2056    * Retourne le droit de l'utilisateur a executer une customAction
2057    * 
2058    * @param[in] string $dn Le DN de l'objet
2059    * @param[in] string $LSobject Le type de l'objet
2060    * @param[in] string $customActionName Le nom de la customAction
2061    *
2062    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2063    */
2064   public static function canExecuteCustomAction($dn,$LSobject,$customActionName) {
2065     $conf=LSconfig :: get('LSobjects.'.$LSobject.'.customActions.'.$customActionName);
2066     if (!is_array($conf))
2067       return;
2068     $whoami = self :: whoami($dn);
2069
2070     if (isset($conf['rights']) && is_array($conf['rights'])) {
2071       foreach($whoami as $who) {
2072         if (in_array($who,$conf['rights'])) {
2073           return True;
2074         }
2075       }
2076     }
2077     
2078     return;
2079   }
2080
2081   /**
2082    * Retourne le droit de l'utilisateur a executer une customAction
2083    * sur une recherche
2084    *
2085    * @param[in] string $LSsearch L'objet LSsearch
2086    * @param[in] string $customActionName Le nom de la customAction
2087    *
2088    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2089    */
2090   public static function canExecuteLSsearchCustomAction($LSsearch,$customActionName) {
2091     $conf=LSconfig :: get('LSobjects.'.$LSsearch -> LSobject.'.LSsearch.customActions.'.$customActionName);
2092     if (!is_array($conf))
2093       return;
2094     $dn=$LSsearch -> basedn;
2095     if (is_null($dn)) $dn=self::getTopDn();
2096
2097     $whoami = self :: whoami($dn);
2098
2099     if (isset($conf['rights']) && is_array($conf['rights'])) {
2100       foreach($whoami as $who) {
2101         if (in_array($who,$conf['rights'])) {
2102           return True;
2103         }
2104       }
2105     }
2106
2107     return;
2108   }
2109
2110   /**
2111    * Return user right to access to a LSaddon view
2112    *
2113    * @param[in] string $LSaddon The LSaddon
2114    * @param[in] string $viewId The LSaddon view ID
2115    *
2116    * @retval boolean True if user is allowed, false otherwise
2117    */
2118   public static function canAccessLSaddonView($LSaddon,$viewId) {
2119     if (self :: loadLSaddon($LSaddon)) {
2120       if (!isset(self :: $LSaddonsViews[$LSaddon]) || !isset(self :: $LSaddonsViews[$LSaddon][$viewId]))
2121       return;
2122       if (!is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2123         return true;
2124       }
2125       $whoami = self :: whoami(self :: $topDn);
2126
2127       if (isset(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles']) && is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2128         foreach($whoami as $who) {
2129           if (in_array($who,self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2130             return True;
2131           }
2132         }
2133       }
2134     }
2135     return;
2136   }
2137
2138
2139   /**
2140    * Ajoute un fichier temporaire
2141    * 
2142    * @author Benjamin Renard <brenard@easter-eggs.com>
2143    * 
2144    * @retval void
2145    **/
2146   public static function addTmpFile($value,$filePath) {
2147     $hash = mhash(MHASH_MD5,$value);
2148     self :: $tmp_file[$filePath] = $hash;
2149     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
2150   }
2151   
2152   /**
2153    * Retourne le chemin du fichier temporaire si l'existe
2154    * 
2155    * @author Benjamin Renard <brenard@easter-eggs.com>
2156    * 
2157    * @param[in] $value La valeur du fichier
2158    * 
2159    * @retval mixed 
2160    **/
2161   public static function tmpFileExist($value) {
2162     $hash = mhash(MHASH_MD5,$value);
2163     foreach(self :: $tmp_file as $filePath => $contentHash) {
2164       if ($hash == $contentHash) {
2165         return $filePath;
2166       }
2167     }
2168     return false;
2169   }
2170   
2171   /**
2172    * Retourne le chemin du fichier temporaire
2173    * 
2174    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
2175    * s'il n'existe pas déjà.
2176    * 
2177    * @author Benjamin Renard <brenard@easter-eggs.com>
2178    * 
2179    * @param[in] $value La valeur du fichier
2180    * 
2181    * @retval mixed 
2182    **/
2183   public static function getTmpFile($value) {
2184     $exist = self :: tmpFileExist($value);
2185     if (!$exist) {
2186       $img_path = LS_TMP_DIR .rand().'.tmp';
2187       $fp = fopen($img_path, "w");
2188       fwrite($fp, $value);
2189       fclose($fp);
2190       self :: addTmpFile($value,$img_path);
2191       return $img_path;
2192     }
2193     else {
2194       return $exist;
2195     }
2196   }
2197   
2198   /**
2199    * Supprime les fichiers temporaires
2200    * 
2201    * @author Benjamin Renard <brenard@easter-eggs.com>
2202    * 
2203    * @retval void
2204    **/
2205   public static function deleteTmpFile($filePath=NULL) {
2206     if ($filePath) {
2207         @unlink($filePath);
2208         unset(self :: $tmp_file[$filePath]);
2209         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
2210     }
2211     else {
2212       foreach(self :: $tmp_file as $file => $content) {
2213         @unlink($file);
2214       }
2215       self :: $tmp_file = array();
2216       $_SESSION['LSsession']['tmp_file'] = array();
2217     }
2218   }
2219
2220   /**
2221    * Retourne true si le cache des droits est activé
2222    *
2223    * @author Benjamin Renard <brenard@easter-eggs.com>
2224    * 
2225    * @retval boolean True si le cache des droits est activé, false sinon.
2226    */
2227   public static function cacheLSprofiles() {
2228     return ( (LSconfig :: get('cacheLSprofiles')) || (self :: $ldapServer['cacheLSprofiles']) );
2229   }
2230
2231   /**
2232    * Retourne true si le cache des subDn est activé
2233    *
2234    * @author Benjamin Renard <brenard@easter-eggs.com>
2235    * 
2236    * @retval boolean True si le cache des subDn est activé, false sinon.
2237    */
2238   public static function cacheSudDn() {
2239     return ( (LSconfig :: get('cacheSubDn')) || (self :: $ldapServer['cacheSubDn']));
2240   }
2241   
2242   /**
2243    * Retourne true si le cache des recherches est activé
2244    *
2245    * @author Benjamin Renard <brenard@easter-eggs.com>
2246    * 
2247    * @retval boolean True si le cache des recherches est activé, false sinon.
2248    */
2249   public static function cacheSearch() {
2250     return ( (LSconfig :: get('cacheSearch')) || (self :: $ldapServer['cacheSearch']));
2251   }
2252   
2253   /**
2254    * Retourne le label des niveaux pour le serveur ldap courant
2255    * 
2256    * @author Benjamin Renard <brenard@easter-eggs.com>
2257    * 
2258    * @retval string Le label des niveaux pour le serveur ldap dourant
2259    */
2260   public static function getSubDnLabel() {
2261     return (self :: $ldapServer['subDnLabel']!='')?__(self :: $ldapServer['subDnLabel']):_('Level');
2262   }
2263   
2264   /**
2265    * Retourne le nom du subDn
2266    * 
2267    * @param[in] $subDn string subDn
2268    * 
2269    * @retval string Le nom du subDn ou '' sinon
2270    */
2271   public static function getSubDnName($subDn=false) {
2272     if (!$subDn) {
2273       $subDn = self :: $topDn;
2274     }
2275     if (self :: getSubDnLdapServer(false)) {
2276       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn])) {
2277         return self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn];
2278       }
2279     }
2280     return '';
2281   }
2282
2283   /**
2284    * L'objet est t-il utilisé pour listé les subDnS
2285    * 
2286    * @param[in] $type string Le type d'objet
2287    * 
2288    * @retval boolean true si le type d'objet est un subDnObject, false sinon
2289    */
2290   public static function isSubDnLSobject($type) {
2291     $result = false;
2292     if (isset(self :: $ldapServer['subDn']['LSobject']) && is_array(self :: $ldapServer['subDn']['LSobject'])) {
2293       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
2294         if ($key==$type) {
2295           $result=true;
2296         }
2297       }
2298     }
2299     return $result;
2300   }
2301   
2302   /**
2303    * Indique si un type d'objet est dans le menu courant
2304    * 
2305    * @retval boolean true si le type d'objet est dans le menu, false sinon
2306    */
2307   public static function in_menu($LSobject,$topDn=NULL) {
2308     if (!$topDn) {
2309       $topDn=self :: $topDn;
2310     }
2311     return isset(self :: $LSaccess[$topDn][$LSobject]);
2312   }
2313   
2314   /**
2315    * Indique si le serveur LDAP courant a des subDn
2316    * 
2317    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
2318    */
2319   public static function haveSubDn() {
2320     return (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn']));
2321   }
2322
2323   /**
2324    * Ajoute une information à afficher
2325    * 
2326    * @param[in] $msg string Le message à afficher
2327    * 
2328    * @retval void
2329    */
2330   public static function addInfo($msg) {
2331     $_SESSION['LSsession_infos'][]=$msg;
2332   }
2333   
2334   /**
2335    * Redirection de l'utilisateur vers une autre URL
2336    * 
2337    * @param[in] $url string L'URL
2338    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
2339    * 
2340    * @retval void
2341    */  
2342   public static function redirect($url,$exit=true) {
2343     LStemplate :: assign('url',$url);
2344     LStemplate :: display('redirect.tpl');
2345     if ($exit) {
2346       exit();
2347     }
2348   }
2349   
2350   /**
2351    * Retourne l'adresse mail d'emission configurée pour le serveur courant
2352    * 
2353    * @retval string Adresse mail d'emission
2354    */
2355   public static function getEmailSender() {
2356     return self :: $ldapServer['emailSender'];  
2357   }
2358   
2359   /**
2360    * Ajout d'une information d'aide
2361    * 
2362    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
2363    *                          celle-ci
2364    * @param[in] $infos array  Tableau array(name => value) des infos
2365    * 
2366    * @retval void
2367    */
2368   public static function addHelpInfos($group,$infos) {
2369     if (is_array($infos)) {
2370       if (isset(self :: $_JSconfigParams['helpInfos'][$group]) && is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
2371         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
2372       }
2373       else {
2374         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
2375       }
2376     }
2377   }
2378   
2379  /**
2380   * Défini les codes erreur relative à la classe LSsession
2381   * 
2382   * @retval void
2383   */  
2384   private static function defineLSerrors() {
2385     /*
2386      * Error Codes
2387      */
2388     LSerror :: defineError('LSsession_01',
2389     _("LSsession : The constant %{const} is not defined.")
2390     );
2391     LSerror :: defineError('LSsession_02',
2392     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
2393     );
2394     LSerror :: defineError('LSsession_03',
2395     _("LSsession : LDAP server's configuration data are invalid. Can't connect.")
2396     );
2397     LSerror :: defineError('LSsession_04',
2398     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
2399     );
2400     LSerror :: defineError('LSsession_05',
2401     _("LSsession : Failed to load LSclass %{class}.")
2402     );
2403     LSerror :: defineError('LSsession_06',
2404     _("LSsession : Login or password incorrect.")
2405     );
2406     LSerror :: defineError('LSsession_07',
2407     _("LSsession : Impossible to identify you : Duplication of identities.")
2408     );
2409     LSerror :: defineError('LSsession_08',
2410     _("LSsession : Can't load class of authentification (%{class}).")
2411     );
2412     LSerror :: defineError('LSsession_09',
2413     _("LSsession : Can't connect to LDAP server.")
2414     );
2415     LSerror :: defineError('LSsession_10',
2416     _("LSsession : Impossible to authenticate you.")
2417     );
2418     LSerror :: defineError('LSsession_11',
2419     _("LSsession : Your are not authorized to do this action.")
2420     );
2421     LSerror :: defineError('LSsession_12',
2422     _("LSsession : Some informations are missing to display this page.")
2423     );
2424     LSerror :: defineError('LSsession_13',
2425     _("LSsession : The function of the custom action %{name} does not exists or is not configured.")
2426     );
2427     LSerror :: defineError('LSsession_14',
2428     _("LSsession : Fail to retreive user's LDAP credentials from LSauth.")
2429     );
2430     LSerror :: defineError('LSsession_15',
2431     _("LSsession : Fail to reconnect to LDAP server with user's LDAP credentials.")
2432     );
2433     LSerror :: defineError('LSsession_16',
2434     _("LSsession : No import/export format define for this object type.")
2435     );
2436     LSerror :: defineError('LSsession_17',
2437     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
2438     );
2439     LSerror :: defineError('LSsession_18',
2440     _("LSsession : The password recovery is disabled for this LDAP server.")
2441     );
2442     LSerror :: defineError('LSsession_19',
2443     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
2444     );
2445     LSerror :: defineError('LSsession_20',
2446     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
2447     );
2448     LSerror :: defineError('LSsession_21',
2449     _("LSsession : call function %{func} do not provided from LSaddon %{addon}.")
2450     );
2451     LSerror :: defineError('LSsession_22',
2452     _("LSsession : problem during initialisation.")
2453     );
2454     LSerror :: defineError('LSsession_23',
2455     _("LSsession : view function %{func} for LSaddon %{addon} doet not exist.")
2456     );
2457   }
2458
2459   /**
2460    * Ajax method when change ldapserver on login form
2461    * 
2462    * @param[in] $data array The return data address
2463    * 
2464    * @retval void
2465    **/
2466   public static function ajax_onLdapServerChangedLogin(&$data) {  
2467     if ( isset($_REQUEST['server']) ) {
2468       self :: setLdapServer($_REQUEST['server']);
2469       $data = array();
2470       if ( self :: LSldapConnect() ) {
2471         if (session_id()=="") session_start();
2472         if (isset($_SESSION['LSsession_topDn'])) {
2473           $sel = $_SESSION['LSsession_topDn'];
2474         }
2475         else {
2476           $sel = NULL;
2477         }
2478         $list = self :: getSubDnLdapServerOptions($sel,true);
2479         if (is_string($list)) {
2480           $data['list_topDn'] = "<select name='LSsession_topDn' id='LSsession_topDn'>".$list."</select>";
2481           $data['subDnLabel'] = self :: getSubDnLabel();
2482         }
2483       }
2484       $data['recoverPassword'] = isset(self :: $ldapServer['recoverPassword']);
2485     }
2486   }
2487   
2488   /**
2489    * Ajax method when change ldapserver on recoverPassword form
2490    * 
2491    * @param[in] $data array The return data address
2492    * 
2493    * @retval void
2494    **/
2495   public static function ajax_onLdapServerChangedRecoverPassword(&$data) {  
2496     if ( isset($_REQUEST['server']) ) {
2497       self :: setLdapServer($_REQUEST['server']);
2498       $data=array('recoverPassword' => isset(self :: $ldapServer['recoverPassword']));
2499     }
2500   }
2501
2502   /**
2503    * Set globals from the ldap server
2504    *
2505    * @retval void
2506    */
2507   public static function setGlobals() {
2508     if ( isset(self :: $ldapServer['globals'])) {
2509       foreach(self :: $ldapServer['globals'] as $key => $value) {
2510         $GLOBALS[$key] = $value;
2511       }
2512     }
2513   }
2514
2515   /**
2516    * Register a LSaddon view
2517    *
2518    * @param[in] $LSaddon string The LSaddon
2519    * @param[in] $viewId string The view ID
2520    * @param[in] $label string The view's label
2521    * @param[in] $viewFunction string The view's function name
2522    * @param[in] $allowedLSprofiles array|null Array listing allowed profiles.
2523    *                                          If null, no access control will
2524    *                                          be done for this view.
2525    * @param[in] $showInMenu boolean Show (or not) this view in menu
2526    *
2527    * @retval bool True is the view have been registred, false otherwise
2528    **/
2529   public static function registerLSaddonView($LSaddon,$viewId,$label,$viewFunction,$allowedLSprofiles=null,$showInMenu=True) {
2530     if (function_exists($viewFunction)) {
2531       $func = new ReflectionFunction($viewFunction);
2532       if (basename($func->getFileName())=="LSaddons.$LSaddon.php") {
2533         self :: $LSaddonsViews[$LSaddon][$viewId]=array (
2534           'LSaddon' => $LSaddon,
2535           'label' => $label,
2536           'function' => $viewFunction,
2537           'allowedLSprofiles' => $allowedLSprofiles,
2538           'showInMenu' => (bool)$showInMenu
2539         );
2540         return True;
2541       }
2542       else {
2543         LSerror :: addErrorCode('LSsession_21',array('func' => $func -> getName(),'addon' => $addon));
2544       }
2545     }
2546     else {
2547       LSerror :: addErrorCode('LSsession_23',array('func' => $viewFunction,'addon' => $LSaddon));
2548     }
2549     return False;
2550   }
2551
2552   /**
2553    * Show LSaddon view
2554    *
2555    * @param[in] $LSaddon string The LSaddon
2556    * @param[in] $viewId string The view ID
2557    *
2558    * @retval void
2559    **/
2560   public static function showLSaddonView($LSaddon,$viewId) {
2561     if (self :: canAccessLSaddonView($LSaddon,$viewId)) {
2562       call_user_func(self :: $LSaddonsViews[$LSaddon][$viewId]['function']);
2563     }
2564   }
2565 }