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;
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 }
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 ="";
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 {
319 // Call parent method, it manages everything, locking, object creation...
320 management::newEntry($action,$target,$all);
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();
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 }
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 }
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 }
553 /* !\brief Locks/unlocks the given user(s).
554 */
555 function lockEntry($action,$entry, $all, $type = "toggle")
556 {
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 ?>