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