Fix problem when onlyAccessible parameter is set to True in LSobject configuration...
[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       'onlyAccessible' => False
1559     );
1560     if (isset($filter_def['params']) && is_array($filter_def['params'])) {
1561       $params = array_merge($filter_def['params'],$params);
1562     }
1563     $LSsearch = new LSsearch($LSobject,'LSsession :: loadLSprofiles',$params,true);
1564     $LSsearch -> run(false);
1565
1566     $set = $LSsearch -> listObjects();
1567     LSdebug('LSsession :: reduced set to');
1568     foreach ($set as $object) {
1569       LSdebug('LSsession :: -> ' . $object -> getDn());
1570     }
1571     return $set;
1572   }
1573
1574   /**
1575    * Charge les droits LS de l'utilisateur : uniquement du type LSobjects
1576    *
1577    * @param[in] string $
1578    *
1579    * @retval void
1580    */
1581   private static function loadLSprofilesLSobjects($profile, $LSobject, $listInfos) {
1582     if (! self :: loadLSclass('LSsearch')) {
1583       LSdebug('Impossible de charger la classe LSsearch');
1584       return;
1585     }
1586     # we are gonna grow a set of objects progressively, we start from the user
1587     $set = array(self :: getLSuserObject());
1588     $basedn = isset($listInfos['basedn']) ? $listInfos['basedn'] : null;
1589     $LSobject = isset($listInfos['LSobject']) ? $listInfos['LSobject'] : $LSobject;
1590
1591     if (isset($listInfos['filters']) && is_array($listInfos['filters'])) {
1592       foreach ($listInfos['filters'] as $filter_def) {
1593         $set = self :: reduceLdapSet($LSobject, $set, $filter_def, $basedn);
1594       }
1595     }
1596     if (isset($listInfos['filter']) || (isset($listInfos['attr']) && isset($listInfos['attr_value']))) {
1597       # support legacy profile definition
1598       $set = self :: reduceLdapSet($LSobject, $set, $listInfos, $basedn);
1599     }
1600
1601     $DNs = [];
1602     foreach ($set as $object) {
1603       $DNs[] = $object -> getDn();
1604     }
1605     if (!is_array(self :: $LSprofiles[$profile])) {
1606       self :: $LSprofiles[$profile]=$DNs;
1607     }
1608     else {
1609       foreach($DNs as $dn) {
1610         if (!in_array($dn,self :: $LSprofiles[$profile])) {
1611           self :: $LSprofiles[$profile][] = $dn;
1612         }
1613       }
1614     }
1615   }
1616
1617   /**
1618    * Charge les droits LS de l'utilisateur
1619    * 
1620    * @retval boolean True si le chargement Ã  réussi, false sinon.
1621    **/
1622   private static function loadLSprofiles() {
1623     if (is_array(self :: $ldapServer['LSprofiles'])) {
1624       foreach (self :: $ldapServer['LSprofiles'] as $profile => $profileInfos) {
1625         if (is_array($profileInfos)) {
1626           foreach ($profileInfos as $topDn => $rightsInfos) {
1627             /*
1628              * If $topDn == 'LSobject', we search for each LSobject type to find
1629              * all items on witch the user will have powers.
1630              */
1631             if ($topDn == 'LSobjects') {
1632               if (is_array($rightsInfos)) {
1633                 foreach ($rightsInfos as $LSobject => $listInfos) {
1634                   LSdebug('loading LSprofile ' . $profile . ' for LSobject ' . $LSobject . ' with params ' . var_export($listInfos, true));
1635                   self :: loadLSprofilesLSobjects($profile, $LSobject, $listInfos);
1636                 }
1637               }
1638               else {
1639                 LSdebug('LSobjects => [] doit etre un tableau');
1640               }
1641             }
1642             else {
1643               if (is_array($rightsInfos)) {
1644                 foreach($rightsInfos as $dn => $conf) {
1645                   if ((isset($conf['attr'])) && (isset($conf['LSobject']))) {
1646                     if( self :: loadLSobject($conf['LSobject']) ) {
1647                       if ($object = new $conf['LSobject']()) {
1648                         if ($object -> loadData($dn)) {
1649                           $listDns=$object -> getValue($conf['attr']);
1650                           $valKey = (isset($conf['attr_value']))?$conf['attr_value']:'%{dn}';
1651                           $val = self :: getLSuserObject() -> getFData($valKey);
1652                           if (is_array($listDns)) {
1653                             if (in_array($val,$listDns)) {
1654                               self :: $LSprofiles[$profile][] = $topDn;
1655                             }
1656                           }
1657                         }
1658                         else {
1659                           LSdebug('Impossible de chargé le dn : '.$dn);
1660                         }
1661                       }
1662                       else {
1663                         LSdebug('Impossible de créer l\'objet de type : '.$conf['LSobject']);
1664                       }
1665                     }
1666                   }
1667                   else {
1668                     if (self :: $dn == $dn) {
1669                       self :: $LSprofiles[$profile][] = $topDn;
1670                     }
1671                   }
1672                 }
1673               }
1674               else {
1675                 if ( self :: $dn == $rightsInfos ) {
1676                   self :: $LSprofiles[$profile][] = $topDn;
1677                 }
1678               }
1679             } // fin else ($topDn == 'LSobjects')
1680           } // fin foreach($profileInfos)
1681         } // fin is_array($profileInfos)
1682       } // fin foreach LSprofiles
1683       LSdebug("LSprofiles : ".print_r(self :: $LSprofiles,1));
1684       return true;
1685     }
1686     else {
1687       return;
1688     }
1689   }
1690   
1691   /**
1692    * Charge les droits d'accès de l'utilisateur pour construire le menu de l'interface
1693    *
1694    * @retval void
1695    */
1696   private static function loadLSaccess() {
1697     $LSaccess=array();
1698     if (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn'])) {
1699       foreach(self :: $ldapServer['subDn'] as $name => $config) {
1700         if ($name=='LSobject') {
1701           if (is_array($config)) {
1702
1703             // Définition des subDns 
1704             foreach($config as $objectType => $objectConf) {
1705               if (self :: loadLSobject($objectType)) {
1706                 if ($subdnobject = new $objectType()) {
1707                   $tbl = $subdnobject -> getSelectArray(NULL,self::getRootDn(),NULL,NULL,false);
1708                   if (is_array($tbl)) {
1709                     // Définition des accès
1710                     $access=array();
1711                     if (is_array($objectConf['LSobjects'])) {
1712                       foreach($objectConf['LSobjects'] as $type) {
1713                         if (self :: loadLSobject($type)) {
1714                           if (self :: canAccess($type)) {
1715                             $access[$type] = LSconfig :: get('LSobjects.'.$type.'.label');
1716                           }
1717                         }
1718                       }
1719                     }
1720                     foreach($tbl as $dn => $dn_name) {
1721                       $LSaccess[$dn]=$access;
1722                     }
1723                   }
1724                 }
1725               }
1726             }
1727           }
1728         }
1729         else {
1730           if ((isCompatibleDNs(self :: $ldapServer['ldap_config']['basedn'],$config['dn']))&&($config['dn']!='')) {
1731             $access=array();
1732             if (is_array($config['LSobjects'])) {
1733               foreach($config['LSobjects'] as $objectType) {
1734                 if (self :: loadLSobject($objectType)) {
1735                   if (self :: canAccess($objectType)) {
1736                     $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1737                   }
1738                 }
1739               }
1740             }
1741             $LSaccess[$config['dn']]=$access;
1742           }
1743         }
1744       }
1745     }
1746     else {
1747       if(is_array(self :: $ldapServer['LSaccess'])) {
1748         $access=array();
1749         foreach(self :: $ldapServer['LSaccess'] as $objectType) {
1750           if (self :: loadLSobject($objectType)) {
1751             if (self :: canAccess($objectType)) {
1752                 $access[$objectType] = LSconfig :: get('LSobjects.'.$objectType.'.label');
1753             }
1754           }
1755         }
1756         $LSaccess[self :: $topDn] = $access;
1757       }
1758     }
1759     if (LSauth :: displaySelfAccess()) {
1760       foreach($LSaccess as $dn => $access) {
1761         $LSaccess[$dn] = array_merge(
1762           array(
1763             'SELF' => 'My account'
1764           ),
1765           $access
1766         );
1767       }
1768     }
1769     self :: $LSaccess = $LSaccess;
1770     $_SESSION['LSsession']['LSaccess'] = $LSaccess;
1771   }
1772
1773   /**
1774    * Load user access to LSaddons views
1775    *
1776    * @retval void
1777    */
1778   private static function loadLSaddonsViewsAccess() {
1779     $LSaddonsViewsAccess=array();
1780     foreach (self :: $LSaddonsViews as $addon => $conf) {
1781       foreach ($conf as $viewId => $viewConf) {
1782         if (self :: canAccessLSaddonView($addon,$viewId)) {
1783           $LSaddonsViewsAccess[]=array (
1784             'LSaddon' => $addon,
1785             'id' => $viewId,
1786             'label' => $viewConf['label'],
1787             'showInMenu' => $viewConf['showInMenu']
1788           );
1789         }
1790       }
1791     }
1792     self :: $LSaddonsViewsAccess = $LSaddonsViewsAccess;
1793     $_SESSION['LSsession']['LSaddonsViewsAccess'] = $LSaddonsViewsAccess;
1794   }
1795
1796
1797   /**
1798    * Dit si l'utilisateur est du profil pour le DN spécifié
1799    *
1800    * @param[in] string $dn DN de l'objet
1801    * @param[in] string $profile Profil
1802    *
1803    * @retval boolean True si l'utilisateur est du profil sur l'objet, false sinon.
1804    */
1805   public static function isLSprofile($dn,$profile) {
1806     if (is_array(self :: $LSprofiles[$profile])) {
1807       foreach(self :: $LSprofiles[$profile] as $topDn) {
1808         if($dn == $topDn) {
1809           return true;
1810         }
1811         else if ( isCompatibleDNs($dn,$topDn) ) {
1812           return true;
1813         }
1814       }
1815     }
1816     return;
1817   }
1818
1819   /**
1820    * Dit si l'utilisateur est d'au moins un des profils pour le DN spécifié
1821    *
1822    * @param[in] string $dn DN de l'objet
1823    * @param[in] string $profiles Profils
1824    *
1825    * @retval boolean True si l'utilisateur est d'au moins un profil sur l'objet, false sinon.
1826    */
1827   public static function isLSprofiles($dn,$profiles) {
1828     foreach ($profiles as $profile) {
1829       if (self :: isLSprofile($dn,$profile))
1830         return true;
1831     }
1832     return false;
1833   }
1834   
1835   /**
1836    * Retourne qui est l'utilisateur par rapport Ã  l'object
1837    *
1838    * @param[in] string Le DN de l'objet
1839    * 
1840    * @retval string 'admin'/'self'/'user' pour Admin , l'utilisateur lui même ou un simple utilisateur
1841    */
1842   public static function whoami($dn) {
1843     $retval = array('user');
1844     
1845     foreach(self :: $LSprofiles as $profile => $infos) {
1846       if(self :: isLSprofile($dn,$profile)) {
1847        $retval[]=$profile;
1848       }
1849     }
1850     
1851     if (self :: $dn == $dn) {
1852       $retval[]='self';
1853     }
1854     
1855     return $retval;
1856   }
1857   
1858   /**
1859    * Retourne le droit de l'utilisateur Ã  accèder Ã  un objet
1860    * 
1861    * @param[in] string $LSobject Le type de l'objet
1862    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1863    * @param[in] string $right Le type de droit d'accès Ã  tester ('r'/'w')
1864    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1865    *
1866    * @retval boolean True si l'utilisateur a accès, false sinon
1867    */
1868   public static function canAccess($LSobject,$dn=NULL,$right=NULL,$attr=NULL) {
1869     if (!self :: loadLSobject($LSobject)) {
1870       return;
1871     }
1872     if ($dn) {
1873       $whoami = self :: whoami($dn);
1874       if ($dn==self :: getLSuserObject() -> getValue('dn')) {
1875         if (!self :: in_menu('SELF')) {
1876           return;
1877         }
1878       }
1879       else {
1880         $obj = new $LSobject();
1881         $obj -> dn = $dn;
1882         if (!self :: in_menu($LSobject,$obj -> subDnValue)) {
1883           return;
1884         }
1885       }
1886     }
1887     else {
1888       $objectdn=LSconfig :: get('LSobjects.'.$LSobject.'.container_dn').','.self :: $topDn;
1889       $whoami = self :: whoami($objectdn);
1890     }
1891     
1892     // Pour un attribut particulier
1893     if ($attr) {
1894       if ($attr=='rdn') {
1895         $attr=LSconfig :: get('LSobjects.'.$LSobject.'.rdn');
1896       }
1897       if (!is_array(LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr))) {
1898         return;
1899       }
1900
1901       $r = 'n';
1902       foreach($whoami as $who) {
1903         $nr = LSconfig :: get('LSobjects.'.$LSobject.'.attrs.'.$attr.'.rights.'.$who);
1904         if($nr == 'w') {
1905           $r = 'w';
1906         }
1907         else if($nr == 'r') {
1908           if ($r=='n') {
1909             $r='r';
1910           }
1911         }
1912       }
1913       
1914       if (($right=='r')||($right=='w')) {
1915         if ($r==$right) {
1916           return true;
1917         }
1918         return;
1919       }
1920       else {
1921         if ( ($r=='r') || ($r=='w') ) {
1922           return true;
1923         }
1924         return;
1925       }
1926     }
1927     
1928     // Pour un attribut quelconque
1929     $attrs_conf=LSconfig :: get('LSobjects.'.$LSobject.'.attrs');
1930     if (is_array($attrs_conf)) {
1931       if (($right=='r')||($right=='w')) {
1932         foreach($whoami as $who) {
1933           foreach ($attrs_conf as $attr_name => $attr_config) {
1934             if (isset($attr_config['rights'][$who]) && $attr_config['rights'][$who]==$right) {
1935               return true;
1936             }
1937           }
1938         }
1939       }
1940       else {
1941         foreach($whoami as $who) {
1942           foreach ($attrs_conf as $attr_name => $attr_config) {
1943             if ( (isset($attr_config['rights'][$who])) && ( ($attr_config['rights'][$who]=='r') || ($attr_config['rights'][$who]=='w') ) ) {
1944               return true;
1945             }
1946           }
1947         }
1948       }
1949     }
1950     return;
1951   }
1952   
1953   /**
1954    * Retourne le droit de l'utilisateur Ã  editer Ã  un objet
1955    * 
1956    * @param[in] string $LSobject Le type de l'objet
1957    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1958    * @param[in] string $attr Le nom de l'attribut auquel on test l'accès
1959    *
1960    * @retval boolean True si l'utilisateur a accès, false sinon
1961    */
1962   public static function canEdit($LSobject,$dn=NULL,$attr=NULL) {
1963     return self :: canAccess($LSobject,$dn,'w',$attr);
1964   }
1965
1966   /**
1967    * Retourne le droit de l'utilisateur Ã  supprimer un objet
1968    * 
1969    * @param[in] string $LSobject Le type de l'objet
1970    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1971    *
1972    * @retval boolean True si l'utilisateur a accès, false sinon
1973    */  
1974   public static function canRemove($LSobject,$dn) {
1975     return self :: canAccess($LSobject,$dn,'w','rdn');
1976   }
1977   
1978   /**
1979    * Retourne le droit de l'utilisateur Ã  créer un objet
1980    * 
1981    * @param[in] string $LSobject Le type de l'objet
1982    *
1983    * @retval boolean True si l'utilisateur a accès, false sinon
1984    */    
1985   public static function canCreate($LSobject) {
1986     if (!self :: loadLSobject($LSobject)) {
1987       return;
1988     }
1989     if (LSconfig :: get("LSobjects.$LSobject.disable_creation")) {
1990       return;
1991     }
1992     return self :: canAccess($LSobject,NULL,'w','rdn');
1993   }
1994   
1995   /**
1996    * Retourne le droit de l'utilisateur Ã  gérer la relation d'objet
1997    * 
1998    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
1999    * @param[in] string $LSobject Le type de l'objet
2000    * @param[in] string $relationName Le nom de la relation avec l'objet
2001    * @param[in] string $right Le type de droit a vérifier ('r' ou 'w')
2002    *
2003    * @retval boolean True si l'utilisateur a accès, false sinon
2004    */
2005   public static function relationCanAccess($dn,$LSobject,$relationName,$right=NULL) {
2006     $relConf=LSconfig :: get('LSobjects.'.$LSobject.'.LSrelation.'.$relationName);
2007     if (!is_array($relConf))
2008       return;
2009     $whoami = self :: whoami($dn);
2010
2011     if (($right=='w') || ($right=='r')) {
2012       $r = 'n';
2013       foreach($whoami as $who) {
2014         $nr = ((isset($relConf['rights'][$who]))?$relConf['rights'][$who]:'');
2015         if($nr == 'w') {
2016           $r = 'w';
2017         }
2018         else if($nr == 'r') {
2019           if ($r=='n') {
2020             $r='r';
2021           }
2022         }
2023       }
2024       
2025       if ($r == $right) {
2026         return true;
2027       }
2028     }
2029     else {
2030       foreach($whoami as $who) {
2031         if ((isset($relConf['rights'][$who])) && ( ($relConf['rights'][$who] == 'w') || ($relConf['rights'][$who] == 'r') ) ) {
2032           return true;
2033         }
2034       }
2035     }
2036     return;
2037   }
2038
2039   /**
2040    * Retourne le droit de l'utilisateur Ã  modifier la relation d'objet
2041    * 
2042    * @param[in] string $dn Le DN de l'objet (le container_dn du type de l'objet par défaut)
2043    * @param[in] string $LSobject Le type de l'objet
2044    * @param[in] string $relationName Le nom de la relation avec l'objet
2045    *
2046    * @retval boolean True si l'utilisateur a accès, false sinon
2047    */  
2048   public static function relationCanEdit($dn,$LSobject,$relationName) {
2049     return self :: relationCanAccess($dn,$LSobject,$relationName,'w');
2050   }
2051
2052   /**
2053    * Retourne le droit de l'utilisateur a executer une customAction
2054    * 
2055    * @param[in] string $dn Le DN de l'objet
2056    * @param[in] string $LSobject Le type de l'objet
2057    * @param[in] string $customActionName Le nom de la customAction
2058    *
2059    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2060    */
2061   public static function canExecuteCustomAction($dn,$LSobject,$customActionName) {
2062     $conf=LSconfig :: get('LSobjects.'.$LSobject.'.customActions.'.$customActionName);
2063     if (!is_array($conf))
2064       return;
2065     $whoami = self :: whoami($dn);
2066
2067     if (isset($conf['rights']) && is_array($conf['rights'])) {
2068       foreach($whoami as $who) {
2069         if (in_array($who,$conf['rights'])) {
2070           return True;
2071         }
2072       }
2073     }
2074     
2075     return;
2076   }
2077
2078   /**
2079    * Retourne le droit de l'utilisateur a executer une customAction
2080    * sur une recherche
2081    *
2082    * @param[in] string $LSsearch L'objet LSsearch
2083    * @param[in] string $customActionName Le nom de la customAction
2084    *
2085    * @retval boolean True si l'utilisateur peut executer cette customAction, false sinon
2086    */
2087   public static function canExecuteLSsearchCustomAction($LSsearch,$customActionName) {
2088     $conf=LSconfig :: get('LSobjects.'.$LSsearch -> LSobject.'.LSsearch.customActions.'.$customActionName);
2089     if (!is_array($conf))
2090       return;
2091     $dn=$LSsearch -> basedn;
2092     if (is_null($dn)) $dn=self::getTopDn();
2093
2094     $whoami = self :: whoami($dn);
2095
2096     if (isset($conf['rights']) && is_array($conf['rights'])) {
2097       foreach($whoami as $who) {
2098         if (in_array($who,$conf['rights'])) {
2099           return True;
2100         }
2101       }
2102     }
2103
2104     return;
2105   }
2106
2107   /**
2108    * Return user right to access to a LSaddon view
2109    *
2110    * @param[in] string $LSaddon The LSaddon
2111    * @param[in] string $viewId The LSaddon view ID
2112    *
2113    * @retval boolean True if user is allowed, false otherwise
2114    */
2115   public static function canAccessLSaddonView($LSaddon,$viewId) {
2116     if (self :: loadLSaddon($LSaddon)) {
2117       if (!isset(self :: $LSaddonsViews[$LSaddon]) || !isset(self :: $LSaddonsViews[$LSaddon][$viewId]))
2118       return;
2119       if (!is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2120         return true;
2121       }
2122       $whoami = self :: whoami(self :: $topDn);
2123
2124       if (isset(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles']) && is_array(self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2125         foreach($whoami as $who) {
2126           if (in_array($who,self :: $LSaddonsViews[$LSaddon][$viewId]['allowedLSprofiles'])) {
2127             return True;
2128           }
2129         }
2130       }
2131     }
2132     return;
2133   }
2134
2135
2136   /**
2137    * Ajoute un fichier temporaire
2138    * 
2139    * @author Benjamin Renard <brenard@easter-eggs.com>
2140    * 
2141    * @retval void
2142    **/
2143   public static function addTmpFile($value,$filePath) {
2144     $hash = mhash(MHASH_MD5,$value);
2145     self :: $tmp_file[$filePath] = $hash;
2146     $_SESSION['LSsession']['tmp_file'][$filePath] = $hash;
2147   }
2148   
2149   /**
2150    * Retourne le chemin du fichier temporaire si l'existe
2151    * 
2152    * @author Benjamin Renard <brenard@easter-eggs.com>
2153    * 
2154    * @param[in] $value La valeur du fichier
2155    * 
2156    * @retval mixed 
2157    **/
2158   public static function tmpFileExist($value) {
2159     $hash = mhash(MHASH_MD5,$value);
2160     foreach(self :: $tmp_file as $filePath => $contentHash) {
2161       if ($hash == $contentHash) {
2162         return $filePath;
2163       }
2164     }
2165     return false;
2166   }
2167   
2168   /**
2169    * Retourne le chemin du fichier temporaire
2170    * 
2171    * Retourne le chemin du fichier temporaire qu'il créera Ã  partir de la valeur
2172    * s'il n'existe pas déjà.
2173    * 
2174    * @author Benjamin Renard <brenard@easter-eggs.com>
2175    * 
2176    * @param[in] $value La valeur du fichier
2177    * 
2178    * @retval mixed 
2179    **/
2180   public static function getTmpFile($value) {
2181     $exist = self :: tmpFileExist($value);
2182     if (!$exist) {
2183       $img_path = LS_TMP_DIR .rand().'.tmp';
2184       $fp = fopen($img_path, "w");
2185       fwrite($fp, $value);
2186       fclose($fp);
2187       self :: addTmpFile($value,$img_path);
2188       return $img_path;
2189     }
2190     else {
2191       return $exist;
2192     }
2193   }
2194   
2195   /**
2196    * Supprime les fichiers temporaires
2197    * 
2198    * @author Benjamin Renard <brenard@easter-eggs.com>
2199    * 
2200    * @retval void
2201    **/
2202   public static function deleteTmpFile($filePath=NULL) {
2203     if ($filePath) {
2204         @unlink($filePath);
2205         unset(self :: $tmp_file[$filePath]);
2206         unset($_SESSION['LSsession']['tmp_file'][$filePath]);
2207     }
2208     else {
2209       foreach(self :: $tmp_file as $file => $content) {
2210         @unlink($file);
2211       }
2212       self :: $tmp_file = array();
2213       $_SESSION['LSsession']['tmp_file'] = array();
2214     }
2215   }
2216
2217   /**
2218    * Retourne true si le cache des droits est activé
2219    *
2220    * @author Benjamin Renard <brenard@easter-eggs.com>
2221    * 
2222    * @retval boolean True si le cache des droits est activé, false sinon.
2223    */
2224   public static function cacheLSprofiles() {
2225     return ( (LSconfig :: get('cacheLSprofiles')) || (self :: $ldapServer['cacheLSprofiles']) );
2226   }
2227
2228   /**
2229    * Retourne true si le cache des subDn est activé
2230    *
2231    * @author Benjamin Renard <brenard@easter-eggs.com>
2232    * 
2233    * @retval boolean True si le cache des subDn est activé, false sinon.
2234    */
2235   public static function cacheSudDn() {
2236     return ( (LSconfig :: get('cacheSubDn')) || (self :: $ldapServer['cacheSubDn']));
2237   }
2238   
2239   /**
2240    * Retourne true si le cache des recherches est activé
2241    *
2242    * @author Benjamin Renard <brenard@easter-eggs.com>
2243    * 
2244    * @retval boolean True si le cache des recherches est activé, false sinon.
2245    */
2246   public static function cacheSearch() {
2247     return ( (LSconfig :: get('cacheSearch')) || (self :: $ldapServer['cacheSearch']));
2248   }
2249   
2250   /**
2251    * Retourne le label des niveaux pour le serveur ldap courant
2252    * 
2253    * @author Benjamin Renard <brenard@easter-eggs.com>
2254    * 
2255    * @retval string Le label des niveaux pour le serveur ldap dourant
2256    */
2257   public static function getSubDnLabel() {
2258     return (self :: $ldapServer['subDnLabel']!='')?__(self :: $ldapServer['subDnLabel']):_('Level');
2259   }
2260   
2261   /**
2262    * Retourne le nom du subDn
2263    * 
2264    * @param[in] $subDn string subDn
2265    * 
2266    * @retval string Le nom du subDn ou '' sinon
2267    */
2268   public static function getSubDnName($subDn=false) {
2269     if (!$subDn) {
2270       $subDn = self :: $topDn;
2271     }
2272     if (self :: getSubDnLdapServer(false)) {
2273       if (isset(self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn])) {
2274         return self :: $_subDnLdapServer[self :: $ldapServerId][false][$subDn];
2275       }
2276     }
2277     return '';
2278   }
2279
2280   /**
2281    * L'objet est t-il utilisé pour listé les subDnS
2282    * 
2283    * @param[in] $type string Le type d'objet
2284    * 
2285    * @retval boolean true si le type d'objet est un subDnObject, false sinon
2286    */
2287   public static function isSubDnLSobject($type) {
2288     $result = false;
2289     if (isset(self :: $ldapServer['subDn']['LSobject']) && is_array(self :: $ldapServer['subDn']['LSobject'])) {
2290       foreach(self :: $ldapServer['subDn']['LSobject'] as $key => $value) {
2291         if ($key==$type) {
2292           $result=true;
2293         }
2294       }
2295     }
2296     return $result;
2297   }
2298   
2299   /**
2300    * Indique si un type d'objet est dans le menu courant
2301    * 
2302    * @retval boolean true si le type d'objet est dans le menu, false sinon
2303    */
2304   public static function in_menu($LSobject,$topDn=NULL) {
2305     if (!$topDn) {
2306       $topDn=self :: $topDn;
2307     }
2308     return isset(self :: $LSaccess[$topDn][$LSobject]);
2309   }
2310   
2311   /**
2312    * Indique si le serveur LDAP courant a des subDn
2313    * 
2314    * @retval boolean true si le serveur LDAP courant a des subDn, false sinon
2315    */
2316   public static function haveSubDn() {
2317     return (isset(self :: $ldapServer['subDn']) && is_array(self :: $ldapServer['subDn']));
2318   }
2319
2320   /**
2321    * Ajoute une information à afficher
2322    * 
2323    * @param[in] $msg string Le message à afficher
2324    * 
2325    * @retval void
2326    */
2327   public static function addInfo($msg) {
2328     $_SESSION['LSsession_infos'][]=$msg;
2329   }
2330   
2331   /**
2332    * Redirection de l'utilisateur vers une autre URL
2333    * 
2334    * @param[in] $url string L'URL
2335    * @param[in] $exit boolean Si true, l'execution script s'arrête après la redirection
2336    * 
2337    * @retval void
2338    */  
2339   public static function redirect($url,$exit=true) {
2340     LStemplate :: assign('url',$url);
2341     LStemplate :: display('redirect.tpl');
2342     if ($exit) {
2343       exit();
2344     }
2345   }
2346   
2347   /**
2348    * Retourne l'adresse mail d'emission configurée pour le serveur courant
2349    * 
2350    * @retval string Adresse mail d'emission
2351    */
2352   public static function getEmailSender() {
2353     return self :: $ldapServer['emailSender'];  
2354   }
2355   
2356   /**
2357    * Ajout d'une information d'aide
2358    * 
2359    * @param[in] $group string Le nom du groupe d'infos dans lequels ajouter
2360    *                          celle-ci
2361    * @param[in] $infos array  Tableau array(name => value) des infos
2362    * 
2363    * @retval void
2364    */
2365   public static function addHelpInfos($group,$infos) {
2366     if (is_array($infos)) {
2367       if (isset(self :: $_JSconfigParams['helpInfos'][$group]) && is_array(self :: $_JSconfigParams['helpInfos'][$group])) {
2368         self :: $_JSconfigParams['helpInfos'][$group] = array_merge(self :: $_JSconfigParams['helpInfos'][$group],$infos);
2369       }
2370       else {
2371         self :: $_JSconfigParams['helpInfos'][$group] = $infos;
2372       }
2373     }
2374   }
2375   
2376  /**
2377   * Défini les codes erreur relative à la classe LSsession
2378   * 
2379   * @retval void
2380   */  
2381   private static function defineLSerrors() {
2382     /*
2383      * Error Codes
2384      */
2385     LSerror :: defineError('LSsession_01',
2386     _("LSsession : The constant %{const} is not defined.")
2387     );
2388     LSerror :: defineError('LSsession_02',
2389     _("LSsession : The %{addon} support is uncertain. Verify system compatibility and the add-on configuration.")
2390     );
2391     LSerror :: defineError('LSsession_03',
2392     _("LSsession : LDAP server's configuration data are invalid. Can't connect.")
2393     );
2394     LSerror :: defineError('LSsession_04',
2395     _("LSsession : Failed to load LSobject type %{type} : unknon type.")
2396     );
2397     LSerror :: defineError('LSsession_05',
2398     _("LSsession : Failed to load LSclass %{class}.")
2399     );
2400     LSerror :: defineError('LSsession_06',
2401     _("LSsession : Login or password incorrect.")
2402     );
2403     LSerror :: defineError('LSsession_07',
2404     _("LSsession : Impossible to identify you : Duplication of identities.")
2405     );
2406     LSerror :: defineError('LSsession_08',
2407     _("LSsession : Can't load class of authentification (%{class}).")
2408     );
2409     LSerror :: defineError('LSsession_09',
2410     _("LSsession : Can't connect to LDAP server.")
2411     );
2412     LSerror :: defineError('LSsession_10',
2413     _("LSsession : Impossible to authenticate you.")
2414     );
2415     LSerror :: defineError('LSsession_11',
2416     _("LSsession : Your are not authorized to do this action.")
2417     );
2418     LSerror :: defineError('LSsession_12',
2419     _("LSsession : Some informations are missing to display this page.")
2420     );
2421     LSerror :: defineError('LSsession_13',
2422     _("LSsession : The function of the custom action %{name} does not exists or is not configured.")
2423     );
2424     LSerror :: defineError('LSsession_14',
2425     _("LSsession : Fail to retreive user's LDAP credentials from LSauth.")
2426     );
2427     LSerror :: defineError('LSsession_15',
2428     _("LSsession : Fail to reconnect to LDAP server with user's LDAP credentials.")
2429     );
2430     LSerror :: defineError('LSsession_16',
2431     _("LSsession : No import/export format define for this object type.")
2432     );
2433     LSerror :: defineError('LSsession_17',
2434     _("LSsession : Error during creation of list of levels. Contact administrators. (Code : %{code})")
2435     );
2436     LSerror :: defineError('LSsession_18',
2437     _("LSsession : The password recovery is disabled for this LDAP server.")
2438     );
2439     LSerror :: defineError('LSsession_19',
2440     _("LSsession : Some informations are missing to recover your password. Contact administrators.")
2441     );
2442     LSerror :: defineError('LSsession_20',
2443     _("LSsession : Error during password recovery. Contact administrators.(Step : %{step})")
2444     );
2445     LSerror :: defineError('LSsession_21',
2446     _("LSsession : call function %{func} do not provided from LSaddon %{addon}.")
2447     );
2448     LSerror :: defineError('LSsession_22',
2449     _("LSsession : problem during initialisation.")
2450     );
2451     LSerror :: defineError('LSsession_23',
2452     _("LSsession : view function %{func} for LSaddon %{addon} doet not exist.")
2453     );
2454   }
2455
2456   /**
2457    * Ajax method when change ldapserver on login form
2458    * 
2459    * @param[in] $data array The return data address
2460    * 
2461    * @retval void
2462    **/
2463   public static function ajax_onLdapServerChangedLogin(&$data) {  
2464     if ( isset($_REQUEST['server']) ) {
2465       self :: setLdapServer($_REQUEST['server']);
2466       $data = array();
2467       if ( self :: LSldapConnect() ) {
2468         if (session_id()=="") session_start();
2469         if (isset($_SESSION['LSsession_topDn'])) {
2470           $sel = $_SESSION['LSsession_topDn'];
2471         }
2472         else {
2473           $sel = NULL;
2474         }
2475         $list = self :: getSubDnLdapServerOptions($sel,true);
2476         if (is_string($list)) {
2477           $data['list_topDn'] = "<select name='LSsession_topDn' id='LSsession_topDn'>".$list."</select>";
2478           $data['subDnLabel'] = self :: getSubDnLabel();
2479         }
2480       }
2481       $data['recoverPassword'] = isset(self :: $ldapServer['recoverPassword']);
2482     }
2483   }
2484   
2485   /**
2486    * Ajax method when change ldapserver on recoverPassword form
2487    * 
2488    * @param[in] $data array The return data address
2489    * 
2490    * @retval void
2491    **/
2492   public static function ajax_onLdapServerChangedRecoverPassword(&$data) {  
2493     if ( isset($_REQUEST['server']) ) {
2494       self :: setLdapServer($_REQUEST['server']);
2495       $data=array('recoverPassword' => isset(self :: $ldapServer['recoverPassword']));
2496     }
2497   }
2498
2499   /**
2500    * Set globals from the ldap server
2501    *
2502    * @retval void
2503    */
2504   public static function setGlobals() {
2505     if ( isset(self :: $ldapServer['globals'])) {
2506       foreach(self :: $ldapServer['globals'] as $key => $value) {
2507         $GLOBALS[$key] = $value;
2508       }
2509     }
2510   }
2511
2512   /**
2513    * Register a LSaddon view
2514    *
2515    * @param[in] $LSaddon string The LSaddon
2516    * @param[in] $viewId string The view ID
2517    * @param[in] $label string The view's label
2518    * @param[in] $viewFunction string The view's function name
2519    * @param[in] $allowedLSprofiles array|null Array listing allowed profiles.
2520    *                                          If null, no access control will
2521    *                                          be done for this view.
2522    * @param[in] $showInMenu boolean Show (or not) this view in menu
2523    *
2524    * @retval bool True is the view have been registred, false otherwise
2525    **/
2526   public static function registerLSaddonView($LSaddon,$viewId,$label,$viewFunction,$allowedLSprofiles=null,$showInMenu=True) {
2527     if (function_exists($viewFunction)) {
2528       $func = new ReflectionFunction($viewFunction);
2529       if (basename($func->getFileName())=="LSaddons.$LSaddon.php") {
2530         self :: $LSaddonsViews[$LSaddon][$viewId]=array (
2531           'LSaddon' => $LSaddon,
2532           'label' => $label,
2533           'function' => $viewFunction,
2534           'allowedLSprofiles' => $allowedLSprofiles,
2535           'showInMenu' => (bool)$showInMenu
2536         );
2537         return True;
2538       }
2539       else {
2540         LSerror :: addErrorCode('LSsession_21',array('func' => $func -> getName(),'addon' => $addon));
2541       }
2542     }
2543     else {
2544       LSerror :: addErrorCode('LSsession_23',array('func' => $viewFunction,'addon' => $LSaddon));
2545     }
2546     return False;
2547   }
2548
2549   /**
2550    * Show LSaddon view
2551    *
2552    * @param[in] $LSaddon string The LSaddon
2553    * @param[in] $viewId string The view ID
2554    *
2555    * @retval void
2556    **/
2557   public static function showLSaddonView($LSaddon,$viewId) {
2558     if (self :: canAccessLSaddonView($LSaddon,$viewId)) {
2559       call_user_func(self :: $LSaddonsViews[$LSaddon][$viewId]['function']);
2560     }
2561   }
2562 }