Add LSaddon view feature
[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);
674       }
675       elseif (!empty($username)) {
676         $result = $authobject -> searchObject(
677                     $username,
678                     self :: $topDn,
679                     self :: $ldapServer['authObjectFilter']
680                   );
681       }
682       else {
683         return $recoveryPasswordInfos;
684       }
685       
686       $nbresult=count($result);
687       
688       if ($nbresult==0) {
689         LSdebug('hash/username incorrect');
690         LSerror :: addErrorCode('LSsession_06');  
691       }
692       elseif ($nbresult>1) {
693         LSerror :: addErrorCode('LSsession_07');
694       }
695       else {
696         $rdn = $result[0] -> getValue('rdn');
697         $username = $rdn[0];
698         LSdebug('Recover : Id trouvé : '.$username);
699         if (self :: $ldapServer['recoverPassword']) {
700           if (self :: loadLSaddon('mail')) {
701             LSdebug('Récupération active');
702             $user=$result[0];
703             $emailAddress = $user -> getValue(self :: $ldapServer['recoverPassword']['mailAttr']);
704             $emailAddress = $emailAddress[0];
705             
706             if (checkEmail($emailAddress)) {
707               LSdebug('Email : '.$emailAddress);
708               self :: $dn = $user -> getDn();
709               
710               // 1ère étape : envoie du recoveryHash
711               if (empty($recoveryHash)) {
712                 $hash=self :: recoverPasswdFirstStep($user);
713                 if ($hash) {
714                   if (self :: recoverPasswdSendMail($emailAddress,1,$hash)) {
715                     // Mail a bien été envoyé
716                     $recoveryPasswordInfos['recoveryHashMail']=$emailAddress;
717                   }
718                 }
719               }
720               // 2nd étape : génération du mot de passe + envoie par mail
721               else {
722                 $pwd=self :: recoverPasswdSecondStep($user);
723                 if ($pwd) {
724                   if (self :: recoverPasswdSendMail($emailAddress,2,$pwd)){
725                     // Mail a bien été envoyé
726                     $recoveryPasswordInfos['newPasswordMail']=$emailAddress;
727                   }
728                 }
729               }
730             }
731             else {
732               LSerror :: addErrorCode('LSsession_19');
733             }
734           }
735         }
736         else {
737           LSerror :: addErrorCode('LSsession_18');
738         }
739       }
740     }
741     return $recoveryPasswordInfos;
742   }
743   
744   /**
745    * Send recover password mail
746    * 
747    * @param[in] $mail string The user's mail
748    * @param[in] $step integer The step
749    * @param[in] $info string The info for formatted message
750    * 
751    * @retval boolean True on success or False
752    **/
753   private static function recoverPasswdSendMail($mail,$step,$info) {
754     // Header des mails
755     $sendParams=array();
756     if (self :: $ldapServer['recoverPassword']['recoveryEmailSender']) {
757       $sendParams['From']=self :: $ldapServer['recoverPassword']['recoveryEmailSender'];
758     }
759     
760     if ($step==1) {
761       if ($_SERVER['HTTPS']=='on') {
762         $recovery_url='https://';
763       }
764       else {
765         $recovery_url='http://';
766       }
767       $recovery_url .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].'&recoveryHash='.$info;
768       
769       $subject = self :: $ldapServer['recoverPassword']['recoveryHashMail']['subject'];
770       $msg = getFData(
771         self :: $ldapServer['recoverPassword']['recoveryHashMail']['msg'],
772         $recovery_url
773       );
774     }
775     else {
776       $subject = self :: $ldapServer['recoverPassword']['newPasswordMail']['subject'];
777       $msg = getFData(
778         self :: $ldapServer['recoverPassword']['newPasswordMail']['msg'],
779         $info
780       );
781     }
782     
783     if (!sendMail($mail,$subject,$msg,$sendParams)) {
784       LSdebug("Problème durant l'envoie du mail");
785       LSerror :: addErrorCode('LSsession_20',4);
786       return;
787     }
788     return true;
789   }
790   
791   
792   /**
793    * Do first step of recovering password
794    * 
795    * @param[in] $user LSldapObject The LSldapObject of the user
796    * 
797    * @retval string|False The recory hash on success or False
798    **/
799   private static function recoverPasswdFirstStep($user) {
800     // Generer un hash
801     $rdn=$user -> getValue('rdn');
802     $rdn = $rdn[0];
803     $recovery_hash = md5($rdn . strval(time()) . strval(rand()));
804     
805     $lostPasswdForm = $user -> getForm('lostPassword');
806     $lostPasswdForm -> setPostData(
807       array(
808         self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => $recovery_hash
809       )
810       ,true
811     );
812       
813     if($lostPasswdForm -> validate()) {
814       if ($user -> updateData('lostPassword')) {
815         // recoveryHash de l'utilisateur mis à jour
816         return $recovery_hash;
817       }
818       else {
819         // Erreur durant la mise à jour de l'objet
820         LSdebug("Erreur durant la mise à jour de l'objet");
821         LSerror :: addErrorCode('LSsession_20',6);
822       }
823     }
824     else {
825       // Erreur durant la validation du formulaire de modification de perte de password
826       LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
827       LSerror :: addErrorCode('LSsession_20',5);
828     }
829     return;
830   }
831
832   /**
833    * Do second step of recovering password
834    * 
835    * @param[in] $user LSldapObject The LSldapObject of the user
836    * 
837    * @retval string|False The new password on success or False
838    **/
839   private static function recoverPasswdSecondStep($user) {
840     $attr=$user -> attrs[self :: $ldapServer['authObjectTypeAttrPwd']];
841     if ($attr instanceof LSattribute) {
842       $mdp = generatePassword(
843        $attr -> config['html_options']['chars'],
844        $attr -> config['html_options']['lenght']
845       );
846       LSdebug('Nvx mpd : '.$mdp);
847       $lostPasswdForm = $user -> getForm('lostPassword');
848       $lostPasswdForm -> setPostData(
849         array(
850           self :: $ldapServer['recoverPassword']['recoveryHashAttr'] => array(''),
851           self :: $ldapServer['authObjectTypeAttrPwd'] => array($mdp)
852         )
853         ,true
854       );
855       if($lostPasswdForm -> validate()) {
856         if ($user -> updateData('lostPassword')) {
857           return $mdp;
858         }
859         else {
860           // Erreur durant la mise à jour de l'objet
861           LSdebug("Erreur durant la mise à jour de l'objet");
862           LSerror :: addErrorCode('LSsession_20',3);
863         }
864       }
865       else {
866         // Erreur durant la validation du formulaire de modification de perte de password
867         LSdebug("Erreur durant la validation du formulaire de modification de perte de password");
868         LSerror :: addErrorCode('LSsession_20',2);
869       }
870     }
871     else {
872       // l'attribut password n'existe pas
873       LSdebug("L'attribut password n'existe pas");
874       LSerror :: addErrorCode('LSsession_20',1);
875     }
876     return;
877   }
878   
879  /**
880   * Retourne les informations du contexte
881   *
882   * @author Benjamin Renard <brenard@easter-eggs.com
883   * 
884   * @retval array Tableau associatif des informations du contexte
885   */
886   private static function getContextInfos() {
887     return array(
888       'tmp_file' => self :: $tmp_file,
889       'topDn' => self :: $topDn,
890       'dn' => self :: $dn,
891       'rdn' => self :: $rdn,
892       'userLDAPcreds' => self :: $userLDAPcreds,
893       'ldapServerId' => self :: $ldapServerId,
894       'ldapServer' => self :: $ldapServer,
895       'LSprofiles' => self :: $LSprofiles,
896       'LSaccess' => self :: $LSaccess,
897       'LSaddonsViewsAccess' => self :: $LSaddonsViewsAccess
898     );
899   }
900   
901   /**
902   * Retourne l'objet de l'utilisateur connecté
903   *
904   * @author Benjamin Renard <brenard@easter-eggs.com
905   * 
906   * @retval mixed L'objet de l'utilisateur connecté ou false si il n'a pas put
907   *               être créé
908   */
909   public static function getLSuserObject($dn=null) {
910     if ($dn) {
911       self :: $dn = $dn;
912     }
913     if (!self :: $LSuserObject) {
914       if (self :: loadLSobject(self :: $ldapServer['authObjectType'])) {
915         self :: $LSuserObject = new self :: $ldapServer['authObjectType']();
916         self :: $LSuserObject -> loadData(self :: $dn);
917       }
918       else {
919         return;
920       }
921     }
922     return self :: $LSuserObject;
923   }
924   
925  /**
926   * Retourne le DN de l'utilisateur connecté
927   *
928   * @author Benjamin Renard <brenard@easter-eggs.com
929   * 
930   * @retval string Le DN de l'utilisateur connecté
931   */
932   public static function getLSuserObjectDn() {
933     return self :: $dn;
934   }
935
936  /**
937   * Modifie l'utilisateur connecté à la volé
938   * 
939   * @param[in] $object Mixed  L'objet Ldap du nouvel utilisateur
940   *                           le type doit correspondre à
941   *                           self :: $ldapServer['authObjectType']
942   * 
943   * @retval boolean True en cas de succès, false sinon
944   */
945  public static function changeAuthUser($object) {
946   if ($object instanceof self :: $ldapServer['authObjectType']) {
947     self :: $dn = $object -> getDn();
948     $rdn = $object -> getValue('rdn');
949     if(is_array($rdn)) {
950       $rdn = $rdn[0];
951     }
952     self :: $rdn = $rdn;
953     self :: $LSuserObject = $object;
954     
955     if(self :: loadLSprofiles()) {
956       self :: loadLSaccess();
957       self :: loadLSaddonsViewsAccess();
958       $_SESSION['LSsession']=self :: getContextInfos();
959       return true;
960     }
961   }
962   return;
963  }
964
965  /**
966   * Définition du serveur Ldap de la session
967   *
968   * Définition du serveur Ldap de la session Ã  partir de son ID dans 
969   * le tableau LSconfig :: get('ldap_servers').
970   *
971   * @param[in] integer Index du serveur Ldap
972   *
973   * @retval boolean True sinon false.
974   */
975   public static function setLdapServer($id) {
976     $conf = LSconfig :: get("ldap_servers.$id");
977     if ( is_array($conf) ) {
978       self :: $ldapServerId = $id;
979       self :: $ldapServer = $conf;
980       self :: setLocale();
981       self :: setGlobals();
982       return true;
983     }
984     else {
985       return;
986     }
987   }
988
989  /**
990   * Connexion au serveur Ldap
991   *
992   * @retval boolean True sinon false.
993   */
994   public static function LSldapConnect() {
995     if (self :: $ldapServer) {
996       self :: includeFile(LSconfig :: get('NetLDAP2'));
997       if (!self :: loadLSclass('LSldap')) {
998         return;
999       }
1000       if (self :: $dn && isset(self :: $ldapServer['useUserCredentials']) && self :: $ldapServer['useUserCredentials']) {
1001         LSldap :: reconnectAs(self :: $userLDAPcreds['dn'], self :: $userLDAPcreds['pwd'],self :: $ldapServer['ldap_config']);
1002       }
1003       else {
1004         LSldap :: connect(self :: $ldapServer['ldap_config']);
1005       }
1006       if (LSldap :: isConnected()) {
1007         return true;
1008       }
1009       else {
1010         return;
1011       }
1012     }
1013     else {
1014       LSerror :: addErrorCode('LSsession_03');
1015       return;
1016     }
1017   }
1018
1019   /**
1020    * Use this function to know if subDn is enabled for the curent LdapServer
1021    * 
1022    * @retval boolean
1023    **/
1024   public static function subDnIsEnabled() {
1025     if (!isset(self :: $ldapServer['subDn'])) {
1026       return;
1027     }
1028     if ( !is_array(self :: $ldapServer['subDn']) ) {
1029       return;
1030     }
1031     return true;
1032   }
1033
1034  /**
1035   * Retourne les sous-dns du serveur Ldap courant
1036   *
1037   * @retval mixed Tableau des subDn, false si une erreur est survenue.
1038   */
1039   public static function getSubDnLdapServer($login=false) {
1040     $login=(bool)$login;
1041     if (self :: cacheSudDn() && isset(self :: $_subDnLdapServer[self :: $ldapServerId][$login])) {
1042       return self :: $_subDnLdapServer[self :: $ldapServerId][$login];
1043     }
1044     if (!self::subDnIsEnabled()) {
1045       return;
1046     }
1047     $return=array();
1048     foreach(self :: $ldapServer['subDn'] as $subDn_name => $subDn_config) {
1049       if ($login && isset($subDn_config['nologin']) && $subDn_config['nologin']) continue;
1050       if ($subDn_name == 'LSobject') {
1051         if (is_array($subDn_config)) {
1052           foreach($subDn_config as $LSobject_name => $LSoject_config) {
1053             if (isset($LSoject_config['basedn']) && !empty($LSoject_config['basedn'])) {
1054               $basedn = $LSoject_config['basedn'];
1055             }
1056             else {
1057               $basedn = self::getRootDn();
1058             }
1059             if (isset($LSoject_config['displayName']) && !empty($LSoject_config['displayName'])) {
1060               $displayName = $LSoject_config['displayName'];
1061             }
1062             else {
1063               $displayName = NULL;
1064             }
1065             if( self :: loadLSobject($LSobject_name) ) {
1066               if ($subdnobject = new $LSobject_name()) {
1067                 $tbl_return = $subdnobject -> getSelectArray(NULL,$basedn,$displayName);
1068                 if (is_array($tbl_return)) {
1069                   $return=array_merge($return,$tbl_return);
1070                 }
1071                 else {
1072                   LSerror :: addErrorCode('LSsession_17',3);
1073                 }
1074               }
1075               else {
1076                 LSerror :: addErrorCode('LSsession_17',2);
1077               }
1078             }
1079           }
1080         }
1081         else {
1082           LSerror :: addErrorCode('LSsession_17',1);
1083         }
1084       }
1085       else {
1086         if ((isCompatibleDNs($subDn_config['dn'],self :: $ldapServer['ldap_config']['basedn']))&&($subDn_config['dn']!="")) {
1087           $return[$subDn_config['dn']] = __($subDn_name);
1088         }
1089       }
1090     }
1091     if (self :: cacheSudDn()) {
1092       self :: $_subDnLdapServer[self :: $ldapServerId][$login]=$return;
1093       $_SESSION['LSsession_subDnLdapServer'] = self :: $_subDnLdapServer;
1094     }
1095     return $return;
1096   }
1097   
1098   /**
1099    * Retourne la liste de subDn du serveur Ldap utilise
1100    * trié par la profondeur dans l'arboressence (ordre décroissant)
1101    * 
1102    * @return array() Tableau des subDn trié
1103    */  
1104   public static function getSortSubDnLdapServer($login=false) {
1105     $subDnLdapServer = self :: getSubDnLdapServer($login);
1106     if (!$subDnLdapServer) {
1107       return array();
1108     }
1109     uksort($subDnLdapServer,"compareDn");
1110     return $subDnLdapServer;
1111   }
1112
1113  /**
1114   * Retourne les options d'une liste déroulante pour le choix du topDn
1115   * de connexion au serveur Ldap
1116   *
1117   * Liste les subdn (self :: $ldapServer['subDn'])
1118   *
1119   * @retval string Les options (<option>) pour la sélection du topDn.
1120   */
1121   public static function getSubDnLdapServerOptions($selected=NULL,$login=false) {
1122     $list = self :: getSubDnLdapServer($login);
1123     if ($list) {
1124       asort($list);
1125       $display='';
1126       foreach($list as $dn => $txt) {
1127         if ($selected && ($selected==$dn)) {
1128           $selected_txt = ' selected';
1129         }
1130         else {
1131           $selected_txt = '';
1132         }
1133         $display.="<option value=\"".$dn."\"$selected_txt>".$txt."</option>\n"; 
1134       }
1135       return $display;
1136     }
1137     return;
1138   }
1139
1140  /**
1141   * Vérifie qu'un subDn est déclaré
1142   *
1143   * @param[in] string Un subDn
1144   * 
1145   * @retval boolean True si le subDn existe, False sinon
1146   */
1147   public static function validSubDnLdapServer($subDn) {
1148     $listTopDn = self :: getSubDnLdapServer();
1149     if(is_array($listTopDn)) {
1150       foreach($listTopDn as $dn => $txt) {
1151         if ($subDn==$dn) {
1152           return true;
1153         } // end if
1154       } // end foreach
1155     } // end if
1156     return;
1157   }
1158
1159  /**
1160   * Test un couple LSobject/pwd
1161   *
1162   * Test un bind sur le serveur avec le dn de l'objet et le mot de passe fourni.
1163   *
1164   * @param[in] LSobject L'object "user" pour l'authentification
1165   * @param[in] string Le mot de passe Ã  tester
1166   *
1167   * @retval boolean True si l'authentification Ã  réussi, false sinon.
1168   */
1169   public static function checkUserPwd($object,$pwd) {
1170     return LSldap :: checkBind($object -> getValue('dn'),$pwd);
1171   }
1172
1173  /**
1174   * Affiche le formulaire de login
1175   *
1176   * Défini les informations pour le template Smarty du formulaire de login.
1177   *
1178   * @retval void
1179   */
1180   public static function displayLoginForm() {
1181     LStemplate :: assign('pagetitle',_('Connection'));
1182     if (isset($_GET['LSsession_logout'])) {
1183       LStemplate :: assign('loginform_action','index.php');
1184     }
1185     else {
1186       LStemplate :: assign('loginform_action',$_SERVER['REQUEST_URI']);
1187     }
1188     if (count(LSconfig :: get('ldap_servers'))==1) {
1189       LStemplate :: assign('loginform_ldapserver_style','style="display: none"');
1190     }
1191     LStemplate :: assign('loginform_label_ldapserver',_('LDAP server'));
1192     $ldapservers_name=array();
1193     $ldapservers_index=array();
1194     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1195       $ldapservers_index[]=$id;
1196       $ldapservers_name[]=__($infos['name']);
1197     }
1198     LStemplate :: assign('loginform_ldapservers_name',$ldapservers_name);
1199     LStemplate :: assign('loginform_ldapservers_index',$ldapservers_index);
1200
1201     LStemplate :: assign('loginform_label_level',_('Level'));
1202     LStemplate :: assign('loginform_label_user',_('Identifier'));
1203     LStemplate :: assign('loginform_label_pwd',_('Password'));
1204     LStemplate :: assign('loginform_label_submit',_('Connect'));
1205     LStemplate :: assign('loginform_label_recoverPassword',_('Forgot your password ?'));
1206     
1207     self :: setTemplate('login.tpl');
1208     self :: addJSscript('LSsession_login.js');
1209   }
1210
1211  /**
1212   * Affiche le formulaire de récupération de mot de passe
1213   *
1214   * Défini les informations pour le template Smarty du formulaire de 
1215   * récupération de mot de passe
1216   * 
1217   * @param[in] $infos array() Information sur le status du processus de 
1218   *                           recouvrement de mot de passe
1219   *
1220   * @retval void
1221   */
1222   public static function displayRecoverPasswordForm($recoveryPasswordInfos) {
1223     LStemplate :: assign('pagetitle',_('Recovery of your credentials'));
1224     LStemplate :: assign('recoverpasswordform_action','index.php?LSsession_recoverPassword');
1225     
1226     if (count(LSconfig :: get('ldap_servers'))==1) {
1227       LStemplate :: assign('recoverpasswordform_ldapserver_style','style="display: none"');
1228     }
1229     
1230     LStemplate :: assign('recoverpasswordform_label_ldapserver',_('LDAP server'));
1231     $ldapservers_name=array();
1232     $ldapservers_index=array();
1233     foreach(LSconfig :: get('ldap_servers') as $id => $infos) {
1234       $ldapservers_index[]=$id;
1235       $ldapservers_name[]=$infos['name'];
1236     }
1237     LStemplate :: assign('recoverpasswordform_ldapservers_name',$ldapservers_name);
1238     LStemplate :: assign('recoverpasswordform_ldapservers_index',$ldapservers_index);
1239
1240     LStemplate :: assign('recoverpasswordform_label_user',_('Identifier'));
1241     LStemplate :: assign('recoverpasswordform_label_submit',_('Validate'));
1242     LStemplate :: assign('recoverpasswordform_label_back',_('Back'));
1243     
1244     $recoverpassword_msg = _('Please fill the identifier field to proceed recovery procedure');
1245     
1246     if (isset($recoveryPasswordInfos['recoveryHashMail'])) {
1247       $recoverpassword_msg = getFData(
1248         _("An email has been sent to  %{mail}. " .
1249         "Please follow the instructions on it."),
1250         $recoveryPasswordInfos['recoveryHashMail']
1251       );
1252     }
1253     
1254     if (isset($recoveryPasswordInfos['newPasswordMail'])) {
1255       $recoverpassword_msg = getFData(
1256         _("Your new password has been sent to %{mail}. "),
1257         $recoveryPasswordInfos['newPasswordMail']
1258       );
1259     }
1260     
1261     LStemplate :: assign('recoverpassword_msg',$recoverpassword_msg);
1262     
1263     self :: setTemplate('recoverpassword.tpl');
1264     self :: addJSscript('LSsession_recoverPassword.js');
1265   }
1266
1267  /**
1268   * Défini le template Smarty Ã  utiliser
1269   *
1270   * Remarque : les fichiers de templates doivent se trouver dans le dossier 
1271   * templates/.
1272   *
1273   * @param[in] string Le nom du fichier de template
1274   *
1275   * @retval void
1276   */
1277   public static function setTemplate($template) {
1278     self :: $template = $template;
1279   }
1280
1281  /**
1282   * Ajoute un script JS au chargement de la page
1283   *
1284   * Remarque : les scripts doivents Ãªtre dans le dossier LS_JS_DIR.
1285   *
1286   * @param[in] $script Le nom du fichier de script Ã  charger.
1287   *
1288   * @retval void
1289   */
1290   public static function addJSscript($file,$path=NULL) {
1291     $script=array(
1292       'file' => $file,
1293       'path' => $path
1294     );
1295     self :: $JSscripts[$path.$file]=$script;
1296   }
1297
1298  /**
1299   * Ajouter un paramètre de configuration Javascript
1300   * 
1301   * @param[in] $name string Nom de la variable de configuration
1302   * @param[in] $val mixed Valeur de la variable de configuration
1303   *
1304   * @retval void
1305   */
1306   public static function addJSconfigParam($name,$val) {
1307     self :: $_JSconfigParams[$name]=$val;
1308   }
1309
1310  /**
1311   * Ajoute une feuille de style au chargement de la page
1312   *
1313   * @param[in] $script Le nom du fichier css Ã  charger.
1314   *
1315   * @retval void
1316   */
1317   public static function addCssFile($file,$path=NULL) {
1318     if ($path) {
1319       $file = $path.$file;
1320     }
1321     else {
1322       $file = LStemplate :: getCSSPath($file);
1323     }
1324     self :: $CssFiles[$file]=$file;
1325   }
1326
1327  /**
1328   * Affiche le template Smarty
1329   *
1330   * Charge les dépendances et affiche le template Smarty
1331   *
1332   * @retval void
1333   */
1334   public static function displayTemplate() {
1335     // JS
1336     $JSscript_txt='';
1337     foreach ($GLOBALS['defaultJSscipts'] as $script) {
1338       $JSscript_txt.="<script src='".LS_JS_DIR.$script."' type='text/javascript'></script>\n";
1339     }
1340
1341     foreach (self :: $JSscripts as $script) {
1342       if (!$script['path']) {
1343         $script['path']=LS_JS_DIR;
1344       }
1345       else {
1346         $script['path'].='/';
1347       }
1348       $JSscript_txt.="<script src='".$script['path'].$script['file']."' type='text/javascript'></script>\n";
1349     }
1350
1351     $KAconf = LSconfig :: get('keepLSsessionActive');
1352     if ( 
1353           (
1354             (!isset(self :: $ldapServer['keepLSsessionActive']))
1355             &&
1356             (!($KAconf === false))
1357           )
1358           ||
1359           (self :: $ldapServer['keepLSsessionActive'])
1360         ) {
1361       self :: addJSconfigParam('keepLSsessionActive',ini_get('session.gc_maxlifetime'));
1362     }
1363
1364     LStemplate :: assign('LSjsConfig',json_encode(self :: $_JSconfigParams));
1365     
1366     if (LSdebug) {
1367       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 1;</script>\n";
1368     }
1369     else {
1370       $JSscript_txt.="<script type='text/javascript'>LSdebug_active = 0;</script>\n";
1371     }
1372     
1373     LStemplate :: assign('LSsession_js',$JSscript_txt);
1374
1375     // Css
1376     self :: addCssFile("LSdefault.css");
1377     if (isset($GLOBALS['defaultCSSfiles']) && is_array($GLOBALS['defaultCSSfiles'])) {
1378       foreach ($GLOBALS['defaultCSSfiles'] as $file) {
1379         self :: addCssFile($file);
1380       }
1381     }
1382     $Css_txt='';
1383     foreach (self :: $CssFiles as $file) {
1384       $Css_txt.="<link rel='stylesheet' type='text/css' href='".$file."' />\n";
1385     }
1386     LStemplate :: assign('LSsession_css',$Css_txt);
1387   
1388     if (isset(self :: $LSaccess[self :: $topDn])) {
1389       LStemplate :: assign('LSaccess',self :: $LSaccess[self :: $topDn]);
1390     }
1391     LStemplate :: assign('LSaddonsViewsAccess',self :: $LSaddonsViewsAccess);
1392     
1393     // Niveau
1394     $listTopDn = self :: getSubDnLdapServer();
1395     if (is_array($listTopDn)) {
1396       asort($listTopDn);
1397       LStemplate :: assign('label_level',self :: getSubDnLabel());
1398       LStemplate :: assign('_refresh',_('Refresh'));
1399       $LSsession_topDn_index = array();
1400       $LSsession_topDn_name = array();
1401       foreach($listTopDn as $index => $name) {
1402         $LSsession_topDn_index[]  = $index;
1403         $LSsession_topDn_name[]   = $name;
1404       }
1405       LStemplate :: assign('LSsession_subDn_indexes',$LSsession_topDn_index);
1406       LStemplate :: assign('LSsession_subDn_names',$LSsession_topDn_name);
1407       LStemplate :: assign('LSsession_subDn',self :: $topDn);
1408       LStemplate :: assign('LSsession_subDnName',self :: getSubDnName());
1409     }
1410     
1411     LStemplate :: assign('LSlanguages',self :: getLangList());
1412     LStemplate :: assign('LSlang',self :: $lang);
1413     LStemplate :: assign('LSencoding',self :: $encoding);
1414     LStemplate :: assign('lang_label',_('Language'));
1415     
1416     LStemplate :: assign('displayLogoutBtn',LSauth :: displayLogoutBtn());
1417     LStemplate :: assign('displaySelfAccess',LSauth :: displaySelfAccess());
1418
1419     // Infos
1420     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1421       $txt_infos="<ul>\n";
1422       foreach($_SESSION['LSsession_infos'] as $info) {
1423         $txt_infos.="<li>$info</li>\n";
1424       }
1425       $txt_infos.="</ul>\n";
1426       LStemplate :: assign('LSinfos',$txt_infos);
1427       $_SESSION['LSsession_infos']=array();
1428     }
1429     
1430     if (self :: $ajaxDisplay) {
1431       LStemplate :: assign('LSerror_txt',LSerror :: getErrors());
1432       LStemplate :: assign('LSdebug_txt',LSdebug_print(true));
1433     }
1434     else {
1435       LSerror :: display();
1436       LSdebug_print();
1437     }
1438     if (!self :: $template)
1439       self :: setTemplate('empty.tpl');
1440       
1441     LStemplate :: assign('connected_as',_("Connected as"));
1442     
1443     LStemplate :: display(self :: $template);
1444   }
1445   
1446  /**
1447   * Défini que l'affichage se fera ou non via un retour Ajax
1448   * 
1449   * @param[in] $val boolean True pour que l'affichage se fasse par un retour
1450   *                         Ajax, false sinon
1451   * @retval void
1452   */
1453   public static function setAjaxDisplay($val=true) {
1454     self :: $ajaxDisplay = (boolean)$val;
1455   }
1456   
1457  /**
1458   * Affiche un retour Ajax
1459   *
1460   * @retval void
1461   */
1462   public static function displayAjaxReturn($data=array()) {
1463     if (isset($data['LSredirect']) && (!LSdebugDefined()) ) {
1464       echo json_encode($data);
1465       return;
1466     }
1467     
1468     $data['LSjsConfig'] = self :: $_JSconfigParams;
1469     
1470     // Infos
1471     if((!empty($_SESSION['LSsession_infos']))&&(is_array($_SESSION['LSsession_infos']))) {
1472       $txt_infos="<ul>\n";
1473       foreach($_SESSION['LSsession_infos'] as $info) {
1474         $txt_infos.="<li>$info</li>\n";
1475       }
1476       $txt_infos.="</ul>\n";
1477       $data['LSinfos'] = $txt_infos;
1478       $_SESSION['LSsession_infos']=array();
1479     }
1480     
1481     if (LSerror :: errorsDefined()) {
1482       $data['LSerror'] = LSerror :: getErrors();
1483     }
1484
1485     if (isset($_REQUEST['imgload'])) {
1486       $data['imgload'] = $_REQUEST['imgload'];
1487     }
1488
1489     if (LSdebugDefined()) {
1490       $data['LSdebug'] = LSdebug_print(true,false);
1491     }
1492
1493     echo json_encode($data);  
1494   }
1495  
1496  /**
1497   * Retournne un template Smarty compilé
1498   *
1499   * @param[in] string $template Le template à retourner
1500   * @param[in] array $variables Variables Smarty à assigner avant l'affichage
1501   * 
1502   * @retval string Le HTML compilé du template
1503   */
1504   public static function fetchTemplate($template,$variables=array()) {
1505     foreach($variables as $name => $val) {
1506       LStemplate :: assign($name,$val);
1507     }
1508     return LStemplate :: fetch($template);
1509   }
1510   
1511   /**
1512    * Prend un tableau de LSobject et le réduit en utilisant un filtre de
1513    * recherche sur un autre type de LSobject.
1514    *
1515    * Si une erreur est présente dans le tableau de définition du filtre, un
1516    * tableau vide est renvoyé.
1517    *
1518    * @param[in] string $LSobject le type LSobject par défaut
1519    * @param[in] array $set tableau de LSobject
1520    * @param[in] array $filter_def définition du filtre de recherche pour la réduction
1521    * @param[in] string $basend basedn pour la recherche, null par défaut
1522    *
1523    * @retval array le nouveau tableau de LSobject
1524    */
1525   private static function reduceLdapSet($LSobject, $set, $filter_def, $basedn=null) {
1526     if (empty($set)) {
1527       return array();
1528     }
1529
1530     if (! isset($filter_def['filter']) &&
1531           (! isset($filter_def['attr']) ||
1532            ! isset($filter_def['attr_value']))) {
1533       LSdebug("Filtre de profil LSobject invalide " . var_export($filter_def, true));
1534       return array();
1535     }
1536
1537     LSdebug('LSsession :: reducing set of');
1538     foreach ($set as $object) {
1539       LSdebug('LSsession :: -> ' . $object -> getDn());
1540     }
1541
1542     $LSobject = isset($filter_def['LSObject']) ? $filter_def['LSobject'] : $LSobject;
1543     LSdebug('LSobject :: ' . $LSobject);
1544     $filters = array();
1545     foreach ($set as $object) {
1546       if (isset($filter_def['filter'])) {
1547         $filters[] = $object -> getFData($filter_def['filter']);
1548       }
1549       else {
1550         $value = $object -> getFData($filter_def['attr_value']);
1551         $filters[] = Net_LDAP2_Filter::create($filter_def['attr'], 'equals', $value);
1552       }
1553     }
1554     $filter = LSldap::combineFilters('or', $filters);
1555     $params = array(
1556       'basedn' => isset($filter_def['basedn']) ? $filter_def['basedn'] : $basedn,
1557       'filter' => $filter,
1558     );
1559     if (isset($filter_def['params']) && is_array($filter_def['params'])) {
1560       $params = array_merge($filter_def['params'],$params);
1561     }
1562     $LSsearch = new LSsearch($LSobject,'LSsession :: loadLSprofiles',$params,true);
1563     $LSsearch -> run(false);
1564
1565     $set = $LSsearch -> listObjects();
1566     LSdebug('LSsession :: reduced set to');
1567     foreach ($set as $object) {
1568       LSdebug('LSsession :: -> ' . $object -> getDn());
1569     }
1570     return $set;
1571   }
1572
1573   /**
1574    * Charge les droits LS de l'utilisateur : uniquement du type LSobjects
1575    *
1576    * @param[in] string $
1577    *
1578    * @retval void
1579    */
1580   private static function loadLSprofilesLSobjects($profile, $LSobject, $listInfos) {
1581     if (! self :: loadLSclass('LSsearch')) {
1582       LSdebug('Impossible de charger la classe LSsearch');
1583       return;
1584     }
1585     # we are gonna grow a set of objects progressively, we start from the user
1586     $set = array(self :: getLSuserObject());
1587     $basedn = isset($listInfos['basedn']) ? $listInfos['basedn'] : null;
1588     $LSobject = isset($listInfos['LSobject']) ? $listInfos['LSobject'] : $LSobject;
1589
1590     if (isset($listInfos['filters']) && is_array($listInfos['filters'])) {
1591       foreach ($listInfos['filters'] as $filter_def) {
1592         $set = self :: reduceLdapSet($LSobject, $set, $filter_def, $basedn);
1593       }
1594     }
1595     if (isset($listInfos['filter']) || (isset($listInfos['attr']) && isset($listInfos['attr_value']))) {
1596       # support legacy profile definition
1597       $set = self :: reduceLdapSet($LSobject, $set, $listInfos, $basedn);
1598     }
1599
1600     $DNs = [];
1601     foreach ($set as $object) {
1602       $DNs[] = $object -> getDn();
1603     }
1604     if (!is_array(self :: $LSprofiles[$profile])) {
1605       self :: $LSprofiles[$profile]=$DNs;
1606     }
1607     else {
1608       foreach($DNs as $dn) {
1609         if (!in_array($dn,self :: $LSprofiles[$profile])) {
1610           self :: $LSprofiles[$profile][] = $dn;
1611         }
1612       }
1613     }
1614   }
1615
1616   /**
1617    * Charge les droits LS de l'utilisateur
1618    * 
1619    * @retval boolean True si le chargement Ã  réussi, false sinon.
1620    **/
1621   private static function loadLSprofiles() {
1622     if (is_array(self :: $ldapServer['LSprofiles'])) {
1623       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1624         if (is_array($profileInfos)) {
1625           foreach ($profileInfos as $topDn => $rightsInfos) {
1626             /*
1627              * If $topDn == 'LSobject', we search for each LSobject type to find
1628              * all items on witch the user will have powers.
1629              */
1630             if ($topDn == 'LSobjects') {
1631               if (is_array($rightsInfos)) {
1632                 foreach ($rightsInfos as $LSobject => $listInfos) {
1633                   LSdebug('loading LSprofile ' . $profile . ' for LSobject ' . $LSobject . ' with params ' . var_export($listInfos, true));
1634                   self :: loadLSprofilesLSobjects($profile, $LSobject, $listInfos);
1635                 }
1636               }
1637               else {
1638                 LSdebug('LSobjects => [] doit etre un tableau');
1639               }
1640             }
1641             else {
1642               if (is_array($rightsInfos)) {
1643                 foreach($rightsInfos as $dn => $conf) {
1644                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1645                     if( self :: loadLSobject($conf['LSobject']) ) {
1646                       if ($object = new $conf['LSobject']()) {
1647                         if ($object -> loadData($dn)) {
1648                           $listDns=$object -> getValue($conf['attr']);
1649                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1650                           $val = self :: getLSuserObject() -> getFData($valKey);
1651                           if (is_array($listDns)) {
1652                             if (in_array($val,$listDns)) {
1653                               self :: $LSprofiles[$profile][] = $topDn;
1654                             }
1655                           }
1656                         }
1657                         else {
1658                           LSdebug('Impossible de chargé le dn : '.$dn);
1659                         }
1660                       }
1661                       else {
1662                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1663                       }
1664                     }
1665                   }
1666                   else {
1667                     if (self :: $dn == $dn) {
1668                       self :: $LSprofiles[$profile][] = $topDn;
1669                     }
1670                   }
1671                 }
1672               }
1673               else {
1674                 if ( self :: $dn == $rightsInfos ) {
1675                   self :: $LSprofiles[$profile][] = $topDn;
1676                 }
1677               }
1678             } // fin else ($topDn == 'LSobjects')
1679           } // fin foreach($profileInfos)
1680         } // fin is_array($profileInfos)
1681       } // fin foreach LSprofiles
1682       LSdebug(self :: $LSprofiles);
1683       return true;
1684     }
1685     else {
1686       return;
1687     }
1688   }
1689   
1690   /**
1691    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1692    *
1693    * @retval void
1694    */
1695   private static function loadLSaccess() {
1696     $LSaccess=array();
1697     if (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn'])) {
1698       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1699         if ($name=='LSobject') {
1700           if (is_array($config)) {
1701
1702             // Définition des subDns 
1703             foreach($config as $objectType => $objectConf) {
1704               if (self :: loadLSobject($objectType)) {
1705                 if ($subdnobject = new $objectType()) {
1706                   $tbl = $subdnobject -> getSelectArray(NULL,self::getRootDn(),NULL,NULL,false);
1707                   if (is_array($tbl)) {
1708                     // Définition des accès
1709                     $access=array();
1710                     if (is_array($objectConf['LSobjects'])) {
1711                       foreach($objectConf['LSobjects'] as $type) {
1712                         if (self :: loadLSobject($type)) {
1713                           if (self :: canAccess($type)) {
1714                             $access[$type] = LSconfig :: get('LSobjects.'.$type.'.label');
1715                           }
1716                         }
1717                       }
1718                     }
1719                     foreach($tbl as $dn => $dn_name) {
1720                       $LSaccess[$dn]=$access;
1721                     }
1722                   }
1723                 }
1724               }
1725             }
1726           }
1727         }
1728         else {
1729           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1730             $access=array();
1731             if (is_array($config['LSobjects'])) {
1732               foreach($config['LSobjects'] as $objectType) {
1733                 if (self :: loadLSobject($objectType)) {
1734                   if (self :: canAccess($objectType)) {
1735                     $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1736                   }
1737                 }
1738               }
1739             }
1740             $LSaccess[$config['dn']]=$access;
1741           }
1742         }
1743       }
1744     }
1745     else {
1746       if(is_array(self :: $ldapServer['LSaccess'])) {
1747         $access=array();
1748         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1749           if (self :: loadLSobject($objectType)) {
1750             if (self :: canAccess($objectType)) {
1751                 $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1752             }
1753           }
1754         }
1755         $LSaccess[self :: $topDn] = $access;
1756       }
1757     }
1758     if (LSauth :: displaySelfAccess()) {
1759       foreach($LSaccess as $dn => $access) {
1760         $LSaccess[$dn] = array_merge(
1761           array(
1762             'SELF' => 'My account'
1763           ),
1764           $access
1765         );
1766       }
1767     }
1768     self :: $LSaccess = $LSaccess;
1769     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1770   }
1771
1772   /**
1773    * Load user access to LSaddons views
1774    *
1775    * @retval void
1776    */
1777   private static function loadLSaddonsViewsAccess() {
1778     $LSaddonsViewsAccess=array();
1779     foreach (self :: $LSaddonsViews as $addon => $conf) {
1780       foreach ($conf as $viewId => $viewConf) {
1781         if (self :: canAccessLSaddonView($addon,$viewId)) {
1782           $LSaddonsViewsAccess[]=array (
1783             'LSaddon' => $addon,
1784             'id' => $viewId,
1785             'label' => $viewConf['label']
1786           );
1787         }
1788       }
1789     }
1790     self :: $LSaddonsViewsAccess = $LSaddonsViewsAccess;
1791     $_SESSION['LSsession']['LSaddonsViewsAccess'] = $LSaddonsViewsAccess;
1792   }
1793
1794
1795   /**
1796    * Dit si l'utilisateur est du profil pour le DN spécifié
1797    *
1798    * @param[in] string $profile de l'objet
1799    * @param[in] string $dn DN de l'objet
1800    * 
1801    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1802    */
1803   public static function isLSprofile($dn,$profile) {
1804     if (is_array(self :: $LSprofiles[$profile])) {
1805       foreach(self :: $LSprofiles[$profile] as $topDn) {
1806         if($dn == $topDn) {
1807           return true;
1808         }
1809         else if ( isCompatibleDNs($dn,$topDn) ) {
1810           return true;
1811         }
1812       }
1813     }
1814     return;
1815   }
1816   
1817   /**
1818    * Retourne qui est l'utilisateur par rapport Ã  l'object
1819    *
1820    * @param[in] string Le DN de l'objet
1821    * 
1822    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1823    */
1824   public static function whoami($dn) {
1825     $retval = array('user');
1826     
1827     foreach(self :: $LSprofiles as $profile => $infos) {
1828       if(self :: isLSprofile($dn,$profile)) {
1829        $retval[]=$profile;
1830       }
1831     }
1832     
1833     if (self :: $dn == $dn) {
1834       $retval[]='self';
1835     }
1836     
1837     return $retval;
1838   }
1839   
1840   /**
1841    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1842    * 
1843    * @param[in] string $LSobject Le type de l'objet
1844    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1845    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1846    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1847    *
1848    * @retval boolean True si l'utilisateur a accès, false sinon
1849    */
1850   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1851     if (!self :: loadLSobject($LSobject)) {
1852       return;
1853     }
1854     if ($dn) {
1855       $whoami = self :: whoami($dn);
1856       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1857         if (!self :: in_menu('SELF')) {
1858           return;
1859         }
1860       }
1861       else {
1862         $obj = new $LSobject();
1863         $obj -> dn = $dn;
1864         if (!self :: in_menu($LSobject,$obj -> subDnValue)) {
1865           return;
1866         }
1867       }
1868     }
1869     else {
1870       $objectdn=LSconfig :: get('LSobjects.'.$LSobject.'.container_dn').','.self :: $topDn;
1871       $whoami = self :: whoami($objectdn);
1872     }
1873     
1874     // Pour un attribut particulier
1875     if ($attr) {
1876       if ($attr=='rdn') {
1877         $attr=LSconfig :: get('LSobjects.'.$LSobject.'.rdn');
1878       }
1879       if (!is_array(LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr))) {
1880         return;
1881       }
1882
1883       $r = 'n';
1884       foreach($whoami as $who) {
1885         $nr = LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr.'.rights.'.$who);
1886         if($nr == 'w') {
1887           $r = 'w';
1888         }
1889         else if($nr == 'r') {
1890           if ($r=='n') {
1891             $r='r';
1892           }
1893         }
1894       }
1895       
1896       if (($right=='r')||($right=='w')) {
1897         if ($r==$right) {
1898           return true;
1899         }
1900         return;
1901       }
1902       else {
1903         if ( ($r=='r') || ($r=='w') ) {
1904           return true;
1905         }
1906         return;
1907       }
1908     }
1909     
1910     // Pour un attribut quelconque
1911     $attrs_conf=LSconfig :: get('LSobjects.'.$LSobject.'.attrs');
1912     if (is_array($attrs_conf)) {
1913       if (($right=='r')||($right=='w')) {
1914         foreach($whoami as $who) {
1915           foreach ($attrs_conf as $attr_name => $attr_config) {
1916             if (isset($attr_config['rights'][$who]) && $attr_config['rights'][$who]==$right) {
1917               return true;
1918             }
1919           }
1920         }
1921       }
1922       else {
1923         foreach($whoami as $who) {
1924           foreach ($attrs_conf as $attr_name => $attr_config) {
1925             if ( (isset($attr_config['rights'][$who])) && ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) ) {
1926               return true;
1927             }
1928           }
1929         }
1930       }
1931     }
1932     return;
1933   }
1934   
1935   /**
1936    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1937    * 
1938    * @param[in] string $LSobject Le type de l'objet
1939    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1940    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1941    *
1942    * @retval boolean True si l'utilisateur a accès, false sinon
1943    */
1944   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1945     return self :: canAccess($LSobject,$dn,'w',$attr);
1946   }
1947
1948   /**
1949    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1950    * 
1951    * @param[in] string $LSobject Le type de l'objet
1952    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1953    *
1954    * @retval boolean True si l'utilisateur a accès, false sinon
1955    */  
1956   public static function canRemove($LSobject,$dn) {
1957     return self :: canAccess($LSobject,$dn,'w','rdn');
1958   }
1959   
1960   /**
1961    * Retourne le droit de l'utilisateur Ã  créer un objet
1962    * 
1963    * @param[in] string $LSobject Le type de l'objet
1964    *
1965    * @retval boolean True si l'utilisateur a accès, false sinon
1966    */    
1967   public static function canCreate($LSobject) {
1968     if (!self :: loadLSobject($LSobject)) {
1969       return;
1970     }
1971     if (LSconfig :: get("LSobjects.$LSobject.disable_creation")) {
1972       return;
1973     }
1974     return self :: canAccess($LSobject,NULL,'w','rdn');
1975   }
1976   
1977   /**
1978    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
1979    * 
1980    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1981    * @param[in] string $LSobject Le type de l'objet
1982    * @param[in] string $relationName Le nom de la relation avec l'objet
1983    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
1984    *
1985    * @retval boolean True si l'utilisateur a accès, false sinon
1986    */
1987   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
1988     $relConf=LSconfig :: get('LSobjects.'.$LSobject.'.LSrelation.'.$relationName);
1989     if (!is_array($relConf))
1990       return;
1991     $whoami = self :: whoami($dn);
1992
1993     if (($right=='w') || ($right=='r')) {
1994       $r = 'n';
1995       foreach($whoami as $who) {
1996         $nr = ((isset($relConf['rights'][$who]))?$relConf['rights'][$who]:'');
1997         if($nr == 'w') {
1998           $r = 'w';
1999         }
2000         else if($nr == 'r') {
2001           if ($r=='n') {
2002             $r='r';
2003           }
2004         }
2005       }
2006       
2007       if ($r == $right) {
2008         return true;
2009       }
2010     }
2011     else {
2012       foreach($whoami as $who) {
2013         if ((isset($relConf['rights'][$who])) && ( ($relConf['rights'][$who] == 'w') || ($relConf['rights'][$who] == 'r') ) ) {
2014           return true;
2015         }
2016       }
2017     }
2018     return;
2019   }
2020
2021   /**
2022    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
2023    * 
2024    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
2025    * @param[in] string $LSobject Le type de l'objet
2026    * @param[in] string $relationName Le nom de la relation avec l'objet
2027    *
2028    * @retval boolean True si l'utilisateur a accès, false sinon
2029    */  
2030   public static function relationCanEdit($dn,$LSobject,$relationName) {
2031     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
2032   }
2033
2034   /**
2035    * Retourne le droit de l'utilisateur a executer une customAction
2036    * 
2037    * @param[in] string $dn Le DN de l'objet
2038    * @param[in] string $LSobject Le type de l'objet
2039    * @param[in] string $customActionName Le nom de la customAction
2040    *
2041    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2042    */
2043   public static function canExecuteCustomAction($dn,$LSobject,$customActionName) {
2044     $conf=LSconfig :: get('LSobjects.'.$LSobject.'.customActions.'.$customActionName);
2045     if (!is_array($conf))
2046       return;
2047     $whoami = self :: whoami($dn);
2048
2049     if (isset($conf['rights']) && is_array($conf['rights'])) {
2050       foreach($whoami as $who) {
2051         if (in_array($who,$conf['rights'])) {
2052           return True;
2053         }
2054       }
2055     }
2056     
2057     return;
2058   }
2059
2060   /**
2061    * Retourne le droit de l'utilisateur a executer une customAction
2062    * sur une recherche
2063    *
2064    * @param[in] string $LSsearch L'objet LSsearch
2065    * @param[in] string $customActionName Le nom de la customAction
2066    *
2067    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2068    */
2069   public static function canExecuteLSsearchCustomAction($LSsearch,$customActionName) {
2070     $conf=LSconfig :: get('LSobjects.'.$LSsearch -> LSobject.'.LSsearch.customActions.'.$customActionName);
2071     if (!is_array($conf))
2072       return;
2073     $dn=$LSsearch -> basedn;
2074     if (is_null($dn)) $dn=self::getTopDn();
2075
2076     $whoami = self :: whoami($dn);
2077
2078     if (isset($conf['rights']) && is_array($conf['rights'])) {
2079       foreach($whoami as $who) {
2080         if (in_array($who,$conf['rights'])) {
2081           return True;
2082         }
2083       }
2084     }
2085
2086     return;
2087   }
2088
2089   /**
2090    * Return user right to access to a LSaddon view
2091    *
2092    * @param[in] string $LSaddon The LSaddon
2093    * @param[in] string $viewId The LSaddon view ID
2094    *
2095    * @retval boolean True if user is allowed, false otherwise
2096    */
2097   public static function canAccessLSaddonView($LSaddon,$viewId) {
2098     if (self :: loadLSaddon($LSaddon)) {
2099       if (!isset(self :: $LSaddonsViews[$LSaddon]) || !isset(self :: $LSaddonsViews[$LSaddon][$viewId]))
2100       return;
2101       if (!is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2102         return true;
2103       }
2104       $whoami = self :: whoami(self :: $topDn);
2105
2106       if (isset(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles']) && is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2107         foreach($whoami as $who) {
2108           if (in_array($who,self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2109             return True;
2110           }
2111         }
2112       }
2113     }
2114     return;
2115   }
2116
2117
2118   /**
2119    * Ajoute un fichier temporaire
2120    * 
2121    * @author Benjamin Renard <brenard@easter-eggs.com>
2122    * 
2123    * @retval void
2124    **/
2125   public static function addTmpFile($value,$filePath) {
2126     $hash = mhash(MHASH_MD5,$value);
2127     self :: $tmp_file[$filePath] = $hash;
2128     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
2129   }
2130   
2131   /**
2132    * Retourne le chemin du fichier temporaire si l'existe
2133    * 
2134    * @author Benjamin Renard <brenard@easter-eggs.com>
2135    * 
2136    * @param[in] $value La valeur du fichier
2137    * 
2138    * @retval mixed 
2139    **/
2140   public static function tmpFileExist($value) {
2141     $hash = mhash(MHASH_MD5,$value);
2142     foreach(self :: $tmp_file as $filePath => $contentHash) {
2143       if ($hash == $contentHash) {
2144         return $filePath;
2145       }
2146     }
2147     return false;
2148   }
2149   
2150   /**
2151    * Retourne le chemin du fichier temporaire
2152    * 
2153    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
2154    * s'il n'existe pas déjà.
2155    * 
2156    * @author Benjamin Renard <brenard@easter-eggs.com>
2157    * 
2158    * @param[in] $value La valeur du fichier
2159    * 
2160    * @retval mixed 
2161    **/
2162   public static function getTmpFile($value) {
2163     $exist = self :: tmpFileExist($value);
2164     if (!$exist) {
2165       $img_path = LS_TMP_DIR .rand().'.tmp';
2166       $fp = fopen($img_path, "w");
2167       fwrite($fp, $value);
2168       fclose($fp);
2169       self :: addTmpFile($value,$img_path);
2170       return $img_path;
2171     }
2172     else {
2173       return $exist;
2174     }
2175   }
2176   
2177   /**
2178    * Supprime les fichiers temporaires
2179    * 
2180    * @author Benjamin Renard <brenard@easter-eggs.com>
2181    * 
2182    * @retval void
2183    **/
2184   public static function deleteTmpFile($filePath=NULL) {
2185     if ($filePath) {
2186         @unlink($filePath);
2187         unset(self :: $tmp_file[$filePath]);
2188         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
2189     }
2190     else {
2191       foreach(self :: $tmp_file as $file => $content) {
2192         @unlink($file);
2193       }
2194       self :: $tmp_file = array();
2195       $_SESSION['LSsession']['tmp_file'] = array();
2196     }
2197   }
2198
2199   /**
2200    * Retourne true si le cache des droits est activé
2201    *
2202    * @author Benjamin Renard <brenard@easter-eggs.com>
2203    * 
2204    * @retval boolean True si le cache des droits est activé, false sinon.
2205    */
2206   public static function cacheLSprofiles() {
2207     return ( (LSconfig :: get('cacheLSprofiles')) || (self :: $ldapServer['cacheLSprofiles']) );
2208   }
2209
2210   /**
2211    * Retourne true si le cache des subDn est activé
2212    *
2213    * @author Benjamin Renard <brenard@easter-eggs.com>
2214    * 
2215    * @retval boolean True si le cache des subDn est activé, false sinon.
2216    */
2217   public static function cacheSudDn() {
2218     return ( (LSconfig :: get('cacheSubDn')) || (self :: $ldapServer['cacheSubDn']));
2219   }
2220   
2221   /**
2222    * Retourne true si le cache des recherches est activé
2223    *
2224    * @author Benjamin Renard <brenard@easter-eggs.com>
2225    * 
2226    * @retval boolean True si le cache des recherches est activé, false sinon.
2227    */
2228   public static function cacheSearch() {
2229     return ( (LSconfig :: get('cacheSearch')) || (self :: $ldapServer['cacheSearch']));
2230   }
2231   
2232   /**
2233    * Retourne le label des niveaux pour le serveur ldap courant
2234    * 
2235    * @author Benjamin Renard <brenard@easter-eggs.com>
2236    * 
2237    * @retval string Le label des niveaux pour le serveur ldap dourant
2238    */
2239   public static function getSubDnLabel() {
2240     return (self :: $ldapServer['subDnLabel']!='')?__(self :: $ldapServer['subDnLabel']):_('Level');
2241   }
2242   
2243   /**
2244    * Retourne le nom du subDn
2245    * 
2246    * @param[in] $subDn string subDn
2247    * 
2248    * @retval string Le nom du subDn ou '' sinon
2249    */
2250   public static function getSubDnName($subDn=false) {
2251     if (!$subDn) {
2252       $subDn = self :: $topDn;
2253     }
2254     if (self :: getSubDnLdapServer(false)) {
2255       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn])) {
2256         return self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn];
2257       }
2258     }
2259     return '';
2260   }
2261
2262   /**
2263    * L'objet est t-il utilisé pour listé les subDnS
2264    * 
2265    * @param[in] $type string Le type d'objet
2266    * 
2267    * @retval boolean true si le type d'objet est un subDnObject, false sinon
2268    */
2269   public static function isSubDnLSobject($type) {
2270     $result = false;
2271     if (isset(self :: $ldapServer['subDn']['LSobject']) && is_array(self :: $ldapServer['subDn']['LSobject'])) {
2272       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
2273         if ($key==$type) {
2274           $result=true;
2275         }
2276       }
2277     }
2278     return $result;
2279   }
2280   
2281   /**
2282    * Indique si un type d'objet est dans le menu courant
2283    * 
2284    * @retval boolean true si le type d'objet est dans le menu, false sinon
2285    */
2286   public static function in_menu($LSobject,$topDn=NULL) {
2287     if (!$topDn) {
2288       $topDn=self :: $topDn;
2289     }
2290     return isset(self :: $LSaccess[$topDn][$LSobject]);
2291   }
2292   
2293   /**
2294    * Indique si le serveur LDAP courant a des subDn
2295    * 
2296    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
2297    */
2298   public static function haveSubDn() {
2299     return (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn']));
2300   }
2301
2302   /**
2303    * Ajoute une information à afficher
2304    * 
2305    * @param[in] $msg string Le message à afficher
2306    * 
2307    * @retval void
2308    */
2309   public static function addInfo($msg) {
2310     $_SESSION['LSsession_infos'][]=$msg;
2311   }
2312   
2313   /**
2314    * Redirection de l'utilisateur vers une autre URL
2315    * 
2316    * @param[in] $url string L'URL
2317    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
2318    * 
2319    * @retval void
2320    */  
2321   public static function redirect($url,$exit=true) {
2322     LStemplate :: assign('url',$url);
2323     LStemplate :: display('redirect.tpl');
2324     if ($exit) {
2325       exit();
2326     }
2327   }
2328   
2329   /**
2330    * Retourne l'adresse mail d'emission configurée pour le serveur courant
2331    * 
2332    * @retval string Adresse mail d'emission
2333    */
2334   public static function getEmailSender() {
2335     return self :: $ldapServer['emailSender'];  
2336   }
2337   
2338   /**
2339    * Ajout d'une information d'aide
2340    * 
2341    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
2342    *                          celle-ci
2343    * @param[in] $infos array  Tableau array(name => value) des infos
2344    * 
2345    * @retval void
2346    */
2347   public static function addHelpInfos($group,$infos) {
2348     if (is_array($infos)) {
2349       if (isset(self :: $_JSconfigParams['helpInfos'][$group]) && is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
2350         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
2351       }
2352       else {
2353         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
2354       }
2355     }
2356   }
2357   
2358  /**
2359   * Défini les codes erreur relative à la classe LSsession
2360   * 
2361   * @retval void
2362   */  
2363   private static function defineLSerrors() {
2364     /*
2365      * Error Codes
2366      */
2367     LSerror :: defineError('LSsession_01',
2368     _("LSsession : The constant %{const} is not defined.")
2369     );
2370     LSerror :: defineError('LSsession_02',
2371     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
2372     );
2373     LSerror :: defineError('LSsession_03',
2374     _("LSsession : LDAP server's configuration data are invalid. Can't connect.")
2375     );
2376     LSerror :: defineError('LSsession_04',
2377     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
2378     );
2379     LSerror :: defineError('LSsession_05',
2380     _("LSsession : Failed to load LSclass %{class}.")
2381     );
2382     LSerror :: defineError('LSsession_06',
2383     _("LSsession : Login or password incorrect.")
2384     );
2385     LSerror :: defineError('LSsession_07',
2386     _("LSsession : Impossible to identify you : Duplication of identities.")
2387     );
2388     LSerror :: defineError('LSsession_08',
2389     _("LSsession : Can't load class of authentification (%{class}).")
2390     );
2391     LSerror :: defineError('LSsession_09',
2392     _("LSsession : Can't connect to LDAP server.")
2393     );
2394     LSerror :: defineError('LSsession_10',
2395     _("LSsession : Impossible to authenticate you.")
2396     );
2397     LSerror :: defineError('LSsession_11',
2398     _("LSsession : Your are not authorized to do this action.")
2399     );
2400     LSerror :: defineError('LSsession_12',
2401     _("LSsession : Some informations are missing to display this page.")
2402     );
2403     LSerror :: defineError('LSsession_13',
2404     _("LSsession : The function of the custom action %{name} does not exists or is not configured.")
2405     );
2406     LSerror :: defineError('LSsession_14',
2407     _("LSsession : Fail to retreive user's LDAP credentials from LSauth.")
2408     );
2409     LSerror :: defineError('LSsession_15',
2410     _("LSsession : Fail to reconnect to LDAP server with user's LDAP credentials.")
2411     );
2412     LSerror :: defineError('LSsession_16',
2413     _("LSsession : No import/export format define for this object type.")
2414     );
2415     LSerror :: defineError('LSsession_17',
2416     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
2417     );
2418     LSerror :: defineError('LSsession_18',
2419     _("LSsession : The password recovery is disabled for this LDAP server.")
2420     );
2421     LSerror :: defineError('LSsession_19',
2422     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
2423     );
2424     LSerror :: defineError('LSsession_20',
2425     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
2426     );
2427     LSerror :: defineError('LSsession_21',
2428     _("LSsession : call function %{func} do not provided from LSaddon %{addon}.")
2429     );
2430     LSerror :: defineError('LSsession_22',
2431     _("LSsession : problem during initialisation.")
2432     );
2433     LSerror :: defineError('LSsession_23',
2434     _("LSsession : view function %{func} for LSaddon %{addon} doet not exist.")
2435     );
2436   }
2437
2438   /**
2439    * Ajax method when change ldapserver on login form
2440    * 
2441    * @param[in] $data array The return data address
2442    * 
2443    * @retval void
2444    **/
2445   public static function ajax_onLdapServerChangedLogin(&$data) {  
2446     if ( isset($_REQUEST['server']) ) {
2447       self :: setLdapServer($_REQUEST['server']);
2448       $data = array();
2449       if ( self :: LSldapConnect() ) {
2450         if (session_id()=="") session_start();
2451         if (isset($_SESSION['LSsession_topDn'])) {
2452           $sel = $_SESSION['LSsession_topDn'];
2453         }
2454         else {
2455           $sel = NULL;
2456         }
2457         $list = self :: getSubDnLdapServerOptions($sel,true);
2458         if (is_string($list)) {
2459           $data['list_topDn'] = "<select name='LSsession_topDn' id='LSsession_topDn'>".$list."</select>";
2460           $data['subDnLabel'] = self :: getSubDnLabel();
2461         }
2462       }
2463       $data['recoverPassword'] = isset(self :: $ldapServer['recoverPassword']);
2464     }
2465   }
2466   
2467   /**
2468    * Ajax method when change ldapserver on recoverPassword form
2469    * 
2470    * @param[in] $data array The return data address
2471    * 
2472    * @retval void
2473    **/
2474   public static function ajax_onLdapServerChangedRecoverPassword(&$data) {  
2475     if ( isset($_REQUEST['server']) ) {
2476       self :: setLdapServer($_REQUEST['server']);
2477       $data=array('recoverPassword' => isset(self :: $ldapServer['recoverPassword']));
2478     }
2479   }
2480
2481   /**
2482    * Set globals from the ldap server
2483    *
2484    * @retval void
2485    */
2486   public static function setGlobals() {
2487     if ( isset(self :: $ldapServer['globals'])) {
2488       foreach(self :: $ldapServer['globals'] as $key => $value) {
2489         $GLOBALS[$key] = $value;
2490       }
2491     }
2492   }
2493
2494   /**
2495    * Register a LSaddon view
2496    *
2497    * @param[in] $LSaddon string The LSaddon
2498    * @param[in] $viewId string The view ID
2499    * @param[in] $label string The view's label
2500    * @param[in] $viewFunction string The view's function name
2501    * @param[in] $allowedLSprofiles array|null Array listing allowed profiles.
2502    *                                          If null, no access control will
2503    *                                          be done for this view.
2504    * @retval bool True is the view have been registred, false otherwise
2505    **/
2506   public static function registerLSaddonView($LSaddon,$viewId,$label,$viewFunction,$allowedLSprofiles=null) {
2507     if (function_exists($viewFunction)) {
2508       $func = new ReflectionFunction($viewFunction);
2509       if (basename($func->getFileName())=="LSaddons.$LSaddon.php") {
2510         self :: $LSaddonsViews[$LSaddon][$viewId]=array (
2511           'LSaddon' => $LSaddon,
2512           'label' => $label,
2513           'function' => $viewFunction,
2514           'allowedLSprofiles' => $allowedLSprofiles
2515         );
2516         return True;
2517       }
2518       else {
2519         LSerror :: addErrorCode('LSsession_21',array('func' => $func -> getName(),'addon' => $addon));
2520       }
2521     }
2522     else {
2523       LSerror :: addErrorCode('LSsession_23',array('func' => $viewFunction,'addon' => $LSaddon));
2524     }
2525     return False;
2526   }
2527
2528   /**
2529    * Show LSaddon view
2530    *
2531    * @param[in] $LSaddon string The LSaddon
2532    * @param[in] $viewId string The view ID
2533    *
2534    * @retval void
2535    **/
2536   public static function showLSaddonView($LSaddon,$viewId) {
2537     if (self :: canAccessLSaddonView($LSaddon,$viewId)) {
2538       call_user_func(self :: $LSaddonsViews[$LSaddon][$viewId]['function']);
2539     }
2540   }
2541 }