Code

Updated management
[gosa.git] / gosa-core / plugins / admin / users / class_userManagement.inc
1 <?php
2 /*
3  * This code is part of GOsa (http://www.gosa-project.org)
4  * Copyright (C) 2003-2008 GONICUS GmbH
5  *
6  * ID: $$Id$$
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
23 class userManagement extends management
24 {
25   var $plHeadline     = "Users";
26   var $plDescription  = "Manage users";
27   var $plIcon  = "plugins/users/images/user.png";
29   var $sn = "";
30   var $givenName = "";
31   var $uid = "";
32   var $got_uid = "";
33   var $edit_uid = "";
35   var $pwd_change_queue = array();
37   // Tab definition 
38   protected $tabClass = "usertabs";
39   protected $tabType = "USERTABS";
40   protected $aclCategory = "users";
41   protected $aclPlugin   = "user";
42   protected $objectName   = "user";
44   function __construct($config,$ui)
45   {
46     $this->config = $config;
47     $this->ui = $ui;
48     
49     // Build filter
50     $filter = new filter(get_template_path("user-filter.xml", true));
51     $filter->setObjectStorage("ou=people,");
52     $this->setFilter($filter);
54     // Build headpage
55     $headpage = new listing(get_template_path("user-list.xml", true));
56     $headpage->registerElementFilter("lockLabel", "userManagement::filterLockLabel");
57     $headpage->registerElementFilter("lockImage", "userManagement::filterLockImage");
58     $headpage->setFilter($filter);
60     // Add copy&paste and snapshot handler.
61     if ($this->config->boolValueIsTrue("main", "copyPaste")){
62       $this->cpHandler = new CopyPasteHandler($this->config);
63     }
64     if($this->config->get_cfg_value("enableSnapshots") == "true"){
65       $this->snapHandler = new SnapshotHandler($this->config);
66     }
68     parent::__construct($config, $ui, "users", $headpage);
70     $this->registerAction("new",    "newEntry");
71     $this->registerAction("edit",   "editEntry");
72     $this->registerAction("apply",  "applyChanges");
73     $this->registerAction("save",   "saveChanges");
74     $this->registerAction("cancel", "cancelEdit");
75     $this->registerAction("remove", "removeEntryRequested");
76     $this->registerAction("removeConfirmed", "removeEntryConfirmed");
78     $this->registerAction("copy",   "copyPasteHandler");
79     $this->registerAction("cut",    "copyPasteHandler");
80     $this->registerAction("paste",  "copyPasteHandler");
82     // Register special user actions 
83     $this->registerAction("lock",   "lockEntry");
84     $this->registerAction("lockUsers",   "lockUsers");
85     $this->registerAction("unlockUsers", "lockUsers");
86     $this->registerAction("new_template", "newTemplate");
87     $this->registerAction("newfromtpl", "newUserFromTemplate");
88     $this->registerAction("templateContinue", "templateContinue");
89     $this->registerAction("templatize", "templatizeUsers");
90     $this->registerAction("templatizeContinue", "templatizeContinue");
92     $this->registerAction("password", "changePassword");
93     $this->registerAction("passwordQueue", "handlePasswordQueue");
94     $this->registerAction("passwordCancel", "closeDialogs");
96     $this->registerAction("sendMessage", "sendMessage");
97     $this->registerAction("saveEventDialog", "saveEventDialog");
98     $this->registerAction("abortEventDialog", "closeDialogs");
99   }
102   // Inject user actions 
103   function detectPostActions()
104   {
105     $action = management::detectPostActions();
106     if(isset($_POST['template_continue'])) $action['action'] = "templateContinue";
107     if(isset($_POST['templatize_continue'])) $action['action'] = "templatizeContinue";
108     if(isset($_POST['save_event_dialog'])) $action['action'] = "saveEventDialog";
109     if(isset($_POST['abort_event_dialog'])) $action['action'] = "abortEventDialog";
110     if(isset($_POST['password_cancel'])){
111       $action['action'] = "passwordCancel";
112     }elseif((count($this->pwd_change_queue) || isset($_POST['password_finish']))){
113       $action['action'] = "passwordQueue";
114     }
115     return($action);
116   }
119   function closeDialogs()
120   {
121     management::closeDialogs();
122     $this->pwd_change_queue = array();
123   }
124     
126   /*! \brief  Sends a message to a set of users using gosa-si events.
127    */ 
128   function sendMessage($action="",$target=array(),$all=array())
129   {
130     if(class_available("DaemonEvent")){
131       $uids = array();
132       $ldap = $this->config->get_ldap_link();
133       $ldap->cd($this->config->current['BASE']);
134       foreach($target as $dn){
135         $ldap->cat($dn,array('uid'));
136         $attrs = $ldap->fetch();
137         if(isset($attrs['uid'][0])){
138           $uids[] = $attrs['uid'][0];
139         }
140       }
141       if(count($uids)){
142         $events = DaemonEvent::get_event_types(USER_EVENT);
143         $event = "DaemonEvent_notify";
144         if(isset($events['BY_CLASS'][$event])){
145           $type = $events['BY_CLASS'][$event];
146           $this->dialogObject = new $type['CLASS_NAME']($this->config);
147           $this->dialogObject->add_users($uids);
148           $this->dialogObject->set_type(SCHEDULED_EVENT);
149         }
150       }
151     }
152   }
155   /*! \brief  Sends a message to a set of users using gosa-si events.
156    */ 
157   function saveEventDialog()
158   {
159     $this->dialogObject->save_object();
160     $msgs = $this->dialogObject->check();
161     if(count($msgs)){
162       msg_dialog::displayChecks($msgs);
163     }else{
164       $o_queue = new gosaSupportDaemon();
165       $o_queue->append($this->dialogObject);
166       if($o_queue->is_error()){
167         msg_dialog::display(_("Infrastructure error"), msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
168       }
169       $this->closeDialogs();
170     }
171   }
174   /*! \brief  Intiates template creation. 
175    */ 
176   function newTemplate($action,$entry)
177   {
178     $this->newEntry();
179     $this->tabObject->set_template_mode ();
180   }
183   /*! \brief  Queues a set of users for password changes
184    */ 
185   function changePassword($action="",$target=array(),$all=array())
186   {
187     $this->dn ="";
188     $this->pwd_change_queue = $target;
190     // Check permisions
191     $disallowed = array();
192     foreach($this->pwd_change_queue as $key => $dn){
193       if(!preg_match("/w/",$this->ui->get_permissions($dn,$this->aclCategory."/password"))){
194         unset($this->pwd_change_queue[$key]);
195         $disallowed[] = $dn; 
196       }
197     }
198     if(count($disallowed)){
199       msg_dialog::display(_("Permission"),msgPool::permModify($disallowed),INFO_DIALOG);
200     }
202     // Now display change dialog.
203     return($this->handlePasswordQueue()); 
204   }
207   function handlePasswordQueue()
208   {
209     // Get next entry from queue.
210     if(empty($this->dn) && count($this->pwd_change_queue)){
211       $this->dn = array_pop($this->pwd_change_queue);
212       set_object_info($this->dn);
213       $smarty = get_smarty();
214       return ($smarty->fetch(get_template_path('password.tpl', TRUE)));
215     }
217     // Check permissions
218     $dn  = $this->dn;
219     $acl = $this->ui->get_permissions($dn, "users/password");
220     $cacl= $this->ui->get_permissions($dn, "users/user");
221     if (preg_match('/w/', $acl) || preg_match('/c/', $cacl)){
222       $message= array();
223       if ($_POST['new_password'] != $_POST['repeated_password']){
224         $message[]= _("The passwords you've entered as 'New password' and 'Repeated new password' do not match.");
225       } else {
226         if ($_POST['new_password'] == ""){
227           $message[] = msgPool::required(_("New password"));
228         }
229       }
231       // Display errors
232       if (count($message) != 0){
233         msg_dialog::displayChecks($message);
234         $smarty = get_smarty();
235         return($smarty->fetch(get_template_path('password.tpl', TRUE)));
236       }
238       // Change cassword 
239       if(!change_password ($this->dn, $_POST['new_password'])){
240         return($smarty->fetch(get_template_path('password.tpl', TRUE)));
241       }
242       if ($this->config->get_cfg_value("passwordHook") != ""){
243         exec($this->config->get_cfg_value("passwordHook")." ".$username." ".$_POST['new_password'], $resarr);
244       }
245       new log("modify","users/".get_class($this),$this->dn,array(),"Password has been changed");
246       $this->dn ="";
247       
248     } else {
249       msg_dialog::display(_("Password change"),
250           _("You have no permission to change this users password!"),
251           WARNING_DIALOG);
252     }
254     // Cleanup
255     if(!count($this->pwd_change_queue)){
256       $this->remove_lock();
257       $this->closeDialogs();
258     }else{
259       return($this->handlePasswordQueue());
260     }
261   }
264   /*! \brief  Save user modifications. 
265    *          Whenever we save a 'new' user, request a password change for him.
266    */ 
267   function saveChanges()
268   {
269     management::saveChanges();
270     if($this->last_dn == "new"){
271       $this->pwd_change_queue[] = $this->last_tabObject->dn;
272       return($this->handlePasswordQueue());
273     }
274   }
277   /*! \brief  Intiates user creation. 
278    *          If we've user templates, then the user will be asked to use to use one. 
279    *          -> See 'templateContinue' for further handling.
280    */ 
281   function newUserFromTemplate($action="",$target=array(),$all=array())
282   {
283     // Call parent method, it knows whats to do, locking and so on ...
284     management::newEntry($action,$target,$all);
286     // Reset uid selection.
287     $this->got_uid= "";
289     // Use template if there are any of them 
290     $templates = array();
291     $templates['none']= _("none");
292     $templates = array_merge($templates,$this->get_templates());
294     // We've templates, so preset the current template and display the input dialog.
295     if (count($templates)){
296       $smarty = get_smarty();
297       foreach(array("sn", "givenName", "uid", "got_uid") as $attr){
298         $smarty->assign("$attr", "");
299       }
300       $smarty->assign("template",  array_pop($target));
301       $smarty->assign("templates", $templates);
302       $smarty->assign("edit_uid", "");
303       return($smarty->fetch(get_template_path('template.tpl', TRUE)));
305       // -> See 'templateContinue' for further handling!
306     }
307   }
311   /*! \brief  Intiates user creation. 
312    *          If we've user templates, then the user will be asked 
313    *           if he wants to use one. 
314    *          -> See 'templateContinue' for further handling.
315    */ 
316   function newEntry($action="",$target=array(),$all=array())
317   {
318   
319     // Call parent method, it manages everything, locking, object creation...
320     management::newEntry($action,$target,$all);
321     
322     // If we've at least one template, then ask the user if he wants to use one?
323     $templates = array();
324     $templates['none']= _("none");
325     $templates = array_merge($templates,$this->get_templates());
327     // Display template selection
328     if (count($templates)){
329       $smarty = get_smarty();
330   
331       // Set default variables, normally empty.
332       foreach(array("sn", "givenName", "uid", "got_uid") as $attr){
333         $smarty->assign($attr, "");
334       }
335       $smarty->assign("template", "none");
336       $smarty->assign("templates", $templates);
337       $smarty->assign("edit_uid", "");
338       return($smarty->fetch(get_template_path('template.tpl', TRUE)));
340       // -> See 'templateContinue' for further handling!
341     }
342   }
345   /* !\brief  This method is called whenever a template selection was displayed.
346    *          Here we act on the use selection. 
347    *          - Does the user want to create a user from template?
348    *          - Create user without template?
349    *          - Input correct, every value given and valid? 
350    */ 
351   function templateContinue()
352   {
353     // Get the list of available templates.
354     $templates = array();
355     $templates['none']= _("none");
356     $templates = array_merge($templates,$this->get_templates());
358     // Input validation, if someone wants to create a user from a template
359     //  then validate the given values.
360     $message = array();
361     if(!isset($_POST['template']) || (empty($_POST['template']))){
362       $message[]= msgPool::invalid(_("Template"));
363     }
364     if(!isset($_POST['sn']) || (empty($_POST['sn']))){
365       $message[]= msgPool::required(_("Name"));
366     }
367     if(!isset($_POST['givenName']) || (empty($_POST['givenName']))){
368       $message[]= msgPool::required(_("Given name"));
369     }
371     /********************
372      * 1   We've had input errors - Display errors and show input dialog again. 
373      ********************/
375     if (count($message) > 0){
376       msg_dialog::displayChecks($message);
378       // Preset input fields with user input. 
379       $smarty = get_smarty();
380       foreach(array("sn", "givenName", "uid", "template") as $attr){
381         if(isset($_POST[$attr])){
382           $smarty->assign("$attr", get_post($attr));
383         }else{
384           $smarty->assign("$attr", "");
385         }
386       }
388       $smarty->assign("templates",$templates);
389       $smarty->assign("got_uid", $this->got_uid);
390       $smarty->assign("edit_uid",false);
391       return($smarty->fetch(get_template_path('template.tpl', TRUE)));
392     }
395     /********************
396      * 2   There was a template selected, now ask for the uid.
397      ********************/
399     if ($_POST['template'] != 'none' && !isset($_POST['uid'])){
401       // Remember user input.
402       $smarty = get_smarty();
403       $this->sn             = $_POST['sn'];
404       $this->givenName      = $_POST['givenName'];
406       // Avoid duplicate entries, check if such a user already exists.
407       $dn= preg_replace("/^[^,]+,/i", "", $_POST['template']);
408       $ldap= $this->config->get_ldap_link();
409       $ldap->cd ($dn);
410       $ldap->search ("(&(sn=".normalizeLdap($this->sn).")(givenName=".normalizeLdap($this->givenName)."))", array("givenName"));
411       if ($ldap->count () != 0){
412         msg_dialog::displayChecks(array(msgPool::duplicated(_("Name"))));
413       }else{
415         // Preset uid field by using the idGenerator 
416         $attributes= array('sn' => $this->sn, 'givenName' => $this->givenName);
417         if ($this->config->get_cfg_value("idGenerator") != ""){
418           $uids= gen_uids ($this->config->get_cfg_value("idGenerator"), $attributes);
419           if (count($uids)){
420             $smarty->assign("edit_uid", "false");
421             $smarty->assign("uids", $uids);
422             $this->uid= current($uids);
423           }
424         } else {
425           $smarty->assign("edit_uid", "");
426           $this->uid= "";
427         }
428         $this->got_uid= true;
429       }
431       // Assign user input 
432       foreach(array("sn", "givenName", "uid", "got_uid") as $attr){
433         $smarty->assign("$attr", $this->$attr);
434       }
435       if (isset($_POST['template'])){
436         $smarty->assign("template", $_POST['template']);
437       }
438       $smarty->assign("templates",$templates); 
439       return($smarty->fetch(get_template_path('template.tpl', TRUE)));
440     }
443     /********************
444      * 3   No template - Ok. Lets fill the data into the user object and skip templating here. 
445      ********************/
446     if ($_POST['template'] == 'none'){
447       foreach(array("sn", "givenName", "uid") as $attr){
448         if (isset($_POST[$attr])){
449           $this->tabObject->by_object['user']->$attr= $_POST[$attr];
450         }
451       }
452       
453       // The user Tab object is already instantiated, so just go back and let the 
454       //  management class do the rest.
455       return("");
456     }
459     /********************
460      * 4   Template selected and uid given - Ok, then lets adapt tempalte values. 
461      ********************/
462     if(isset($_POST['uid'])){
464       // Move user supplied data to sub plugins 
465       foreach(array("uid","sn","givenName") as $attr){
466         $this->$attr = $_POST[$attr];
467         $this->tabObject->$attr       = $this->$attr;
468         $this->tabObject->by_object['user']->$attr = $this->$attr;
469       }
471       // Adapt template values.
472       $template_dn              = $_POST['template'];
473       $this->tabObject->adapt_from_template($template_dn, array("uid","cn","givenName","sn"));
474       $template_base            = preg_replace("/^[^,]+,".preg_quote(get_people_ou(), '/')."/", '', $template_dn);
475       $this->tabObject->by_object['user']->base= $template_base;
477       // The user Tab object is already instantiated, so just go back and let the 
478       //  management class do the rest.
479       return("");
480     }
481   }
484   /* !\brief  This method applies a template to a set of users.
485    */ 
486   function templatizeUsers($action="",$target=array(),$all=array())
487   {
488     $this->dns = array();
489     if(count($target)){
491       // Get the list of available templates.
492       $templates = $this->get_templates();
494       // Check entry locking
495       foreach($target as $dn){
496         if (($user= get_lock($dn)) != ""){
497           return(gen_locked_message ($user, $dn));
498         }
499         $this->dns[] = $dn;
500       }
501           
502       // Display template
503       $smarty = get_smarty();
504       $smarty->assign("templates", $templates);
505       return($smarty->fetch(get_template_path('templatize.tpl', TRUE)));
506     }
507   }
510   /* !\brief  This method is called whenever the templatize dialog was used.
511    */ 
512   function templatizeContinue()
513   {
514     // Template readable? 
515     $template= get_post('template');
516     $acl = $this->ui->get_permissions($template, $this->aclCategory."/".$this->aclPlugin);
517     if (preg_match('/r/', $acl)){
518       $tab = $this->tabClass;
519       foreach ($this->dns as $dn){
521         // User writeable
522         $acl = $this->ui->get_permissions($dn,  $this->aclCategory."/".$this->aclPlugin);
523         if (preg_match('/w/', $acl)){
524           $this->tabObject= new $tab($this->config, $this->config->data['TABS'][$this->tabType], $dn, $this->aclCategory);
525           $this->tabObject->adapt_from_template($template, array("sn", "givenName", "uid"));
526           $this->tabObject->save();
527         } else {
528           msg_dialog::display(_("Permission error"), msgPool::permModify($dn), ERROR_DIALOG);
529         }
530       }
531     } else {
532       msg_dialog::display(_("Permission error"), msgPool::permView($template), ERROR_DIALOG);
533     }
535     // Cleanup!
536     $this->remove_lock(); 
537     $this->closeDialogs();
538   }
541   /* !\brief  Lock/unlock multiple users.
542    */ 
543   function lockUsers($action,$target,$all)
544   {
545     if($action == "lockUsers"){
546       $this->lockEntry($action,$target, $all, "lock");
547     }else{
548       $this->lockEntry($action,$target, $all, "unlock");
549     }
550   }
552   
553   /* !\brief  Locks/unlocks the given user(s).
554    */ 
555   function lockEntry($action,$entry, $all, $type = "toggle")
556   {
557     
558     // Filter out entries we are not allowed to modify
559     $disallowed = array();
560     $dns = array();
561     foreach($entry as $dn){
562       if (!preg_match("/w/",$this->ui->get_permissions($dn,"users/password"))){
563         $disallowed[] = $dn;
564       }else{
565         $allowed[] = $dn;
566       }
567     }
568     if(count($disallowed)){
569       msg_dialog::display(_("Permission"),msgPool::permDelete($disallowed),INFO_DIALOG);
570     }
572     // Try to lock/unlock the rest of the entries.
573     $ldap = $this->config->get_ldap_link();
574     foreach($allowed as $dn){
575       $ldap->cat($dn, array('userPassword'));
576       if($ldap->count() == 1){
578         // We can't lock empty passwords.
579         $val = $ldap->fetch();
580         if(!isset($val['userPassword'])){
581           continue;
582         }
584         // Detect the password method and try to lock/unlock.
585         $pwd = $val['userPassword'][0];
586         $method = passwordMethod::get_method($pwd,$val['dn']);
587         $success= true;
588         if($method instanceOf passwordMethod){
589           if($type == "toggle"){
590             if($method->is_locked($this->config,$val['dn'])){
591               $success= $method->unlock_account($this->config,$val['dn']);
592             }else{
593               $success= $method->lock_account($this->config,$val['dn']);
594             }
595           }elseif($type == "lock" && !$method->is_locked($this->config,$val['dn'])){
596             $success= $method->lock_account($this->config,$val['dn']);
597           }elseif($type == "unlock" && $method->is_locked($this->config,$val['dn'])){
598             $success= $method->unlock_account($this->config,$val['dn']);
599           }
601           // Check if everything went fine.
602           if (!$success){
603             $hn= $method->get_hash_name();
604             if (is_array($hn)){
605               $hn= $hn[0];
606             }
607             msg_dialog::display(_("Account locking"),
608                 sprintf(_("Password method '%s' does not support locking. Account (%s) has not been locked!"), 
609                   $hn,$dn),WARNING_DIALOG);
610           }
611         }else{
612           // Can't lock unknown methods.
613         }
614       }
615     }
616   }
619   /* !\brief  This method returns a list of all available templates.
620    */ 
621   function get_templates()
622   {
623     $templates= array();
624     $ldap= $this->config->get_ldap_link();
625     foreach ($this->config->departments as $key => $value){
626       $acl = $this->ui->get_permissions($value,$this->aclCategory."/".$this->aclPlugin);
627       if (preg_match("/c/",$acl)){
629         // Search all templates from the current dn.
630         $ldap->cd (get_people_ou().$value);
631         $ldap->search ("(objectClass=gosaUserTemplate)", array("uid"));
632         if ($ldap->count() != 0){
633           while ($attrs= $ldap->fetch()){
634             $templates[$ldap->getDN()]= $attrs['uid'][0]." - ".LDAP::fix($key);
635           }
636         }
637       }
638     }
639     natcasesort ($templates);
640     reset ($templates);
641     return($templates);
642   }
645   static function filterLockImage($userPassword)
646   {
647     $image= "images/empty.png";
648     if(isset($userPassword[0]) && preg_match("/^\{[^\}]/",$userPassword[0])){
649       if(preg_match("/^[^\}]*+\}!/",$userPassword[0])){
650         $image= "images/lists/locked.png";
651       }else{
652         $image= "images/lists/unlocked.png";
653       }
654     }
655     return $image;
656   }
659   static function filterLockLabel($userPassword)
660   {
661     $label= "";
662     if(isset($userPassword[0]) && preg_match("/^\{[^\}]/",$userPassword[0])){
663       if(preg_match("/^[^\}]*+\}!/",$userPassword[0])){
664         $label= _("Unlock account");
665       }else{
666         $label= _("Lock account");
667       }
668     }
669     return $label;
670   }
671
672 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
673 ?>