Code

Updated to reflect ssh
[gosa.git] / gosa-core / plugins / personal / posix / class_posixAccount.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 /*!
24   \brief   posixAccount plugin
25   \author  Cajus Pollmeier <pollmeier@gonicus.de>
26   \version 2.00
27   \date    24.07.2003
29   This class provides the functionality to read and write all attributes
30   relevant for posixAccounts and shadowAccounts from/to the LDAP. It
31   does syntax checking and displays the formulars required.
32  */
34 class posixAccount extends plugin
35 {
36   /* Definitions */
37   var $plHeadline= "UNIX";
38   var $plDescription= "Edit users POSIX settings";
40   /* Plugin specific values */
41   var $homeDirectory= "";
42   var $loginShell= "/bin/bash";
43   var $uidNumber= "";
44   var $gidNumber= "";
45   var $gecos= "";
46   var $shadowMin= "0";
47   var $shadowMax= "0";
48   var $shadowWarning= "0";
49   var $shadowLastChange= "0";
50   var $shadowInactive= "0";
51   var $shadowExpire= "0";
52   var $gosaDefaultPrinter= "";
53   var $accessTo= array();
54   var $trustModel= "";
56   var $glist=array();
57   var $status= "";
58   var $loginShellList= array();
59   var $groupMembership= array();
60   var $savedGroupMembership= array();
61   var $savedUidNumber= "";
62   var $savedGidNumber= "";
63   var $activate_shadowMin= "0";
64   var $activate_shadowMax= "0";
65   var $activate_shadowWarning= "0";
66   var $activate_shadowInactive= "0";
67   var $activate_shadowExpire= "0";
68   var $mustchangepassword= "0";
69   var $force_ids= 0;
70   var $group_dialog= FALSE;
71   var $show_ws_dialog= FALSE;
72   var $secondaryGroups= array();
73   var $primaryGroup= 0;
74   var $was_trust_account= FALSE;
75   var $memberGroup= array();
76   var $grouplist= array();
77   var $ui= array();
78   var $ssh= null;
80   var $GroupRegex= "*";
81   var $GroupUserRegex= "*";
82   var $SubSearch= false;
84   var $view_logged= false;
86   /* attribute list for save action */
87   var $CopyPasteVars  = 
88       array("grouplist","groupMembership","activate_shadowMin",
89       "activate_shadowMax","activate_shadowWarning","activate_shadowInactive","activate_shadowExpire",
90       "must_change_password","printerList","grouplist","savedGidNumber","savedUidNumber");
92   var $attributes     = array("homeDirectory", "loginShell", "uidNumber", "gidNumber", "gecos",
93       "shadowMin", "shadowMax", "shadowWarning", "shadowInactive", "shadowLastChange",
94       "shadowExpire", "gosaDefaultPrinter", "uid","accessTo","trustModel");
96   var $objectclasses= array("posixAccount", "shadowAccount");
98   var $uid= "";
99   var $multiple_support = TRUE;
100   var $groupMembership_some = array();
102   /* constructor, if 'dn' is set, the node loads the given
103      'dn' from LDAP */
104   function posixAccount (&$config, $dn= NULL)
105   {
106     global $class_mapping;
108     /* Configuration is fine, allways */
109     $this->config= $config;
111     /* Load bases attributes */
112     plugin::plugin($config, $dn);
114     /* Setting uid to default */
115     if(isset($this->attrs['uid'][0])){
116       $this->uid = $this->attrs['uid'][0];
117     }
119     $ldap= $this->config->get_ldap_link();
121     if ($dn !== NULL){
123       /* Correct is_account. shadowAccount is not required. */
124       if (isset($this->attrs['objectClass']) &&
125           in_array ('posixAccount', $this->attrs['objectClass'])){
127         $this->is_account= TRUE;
128       }
130       /* Is this account a trustAccount? */
131       if ($this->is_account && isset($this->attrs['trustModel'])){
132         $this->trustModel= $this->attrs['trustModel'][0];
133         $this->was_trust_account= TRUE;
134       } else {
135         $this->was_trust_account= FALSE;
136         $this->trustModel= "";
137       }
139       $this->accessTo = array(); 
140       if ($this->is_account && isset($this->attrs['accessTo'])){
141         for ($i= 0; $i<$this->attrs['accessTo']['count']; $i++){
142           $tmp= $this->attrs['accessTo'][$i];
143           $this->accessTo[$tmp]= $tmp;
144         }
145       }
146       $this->initially_was_account= $this->is_account;
148       /* Fill group */
149       $this->primaryGroup= $this->gidNumber;
151       /* Generate status text */
152       $current= date("U");
154       $current= floor($current / 60 /60 / 24);
156       if (($current >= $this->shadowExpire) && $this->shadowExpire){
157         $this->status= _("expired");
158         if (($current - $this->shadowExpire) < $this->shadowInactive){
159           $this->status.= ", "._("grace time active");
160         }
161       } elseif (($this->shadowLastChange + $this->shadowMin) >= $current){
162         $this->status= _("active").", "._("password not changeable");
163       } elseif (($this->shadowLastChange + $this->shadowMax) >= $current){
164         $this->status= _("active").", "._("password expired");
165       } else {
166         $this->status= _("active");
167       }
169       /* Get group membership */
170       $ldap->cd($this->config->current['BASE']);
171       $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->uid."))", array("cn", "description"));
173       while ($attrs= $ldap->fetch()){
174         if (!isset($attrs["description"][0])){
175           $entry= $attrs["cn"][0];
176         } else {
177           $entry= $attrs["cn"][0]." [".$attrs["description"][0]."]";
178         }
179         $this->groupMembership[$ldap->getDN()]= $entry;
180       }
181       asort($this->groupMembership);
182       reset($this->groupMembership);
183       $this->savedGroupMembership= $this->groupMembership;
184       $this->savedUidNumber= $this->uidNumber;
185       $this->savedGidNumber= $this->gidNumber;
187       // Instanciate SSH object if available
188       if (isset($class_mapping["sshPublicKey"])){
189         $this->ssh= new sshPublicKey($this->config, $this->dn);
190       }
191     }
193     /* Adjust shadow checkboxes */
194     foreach (array("shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
195           "shadowExpire") as $val){
197       if ($this->$val != 0){
198         $oval= "activate_".$val;
199         $this->$oval= "1";
200       }
201     }
203     /* Convert to seconds */
204     $this->shadowExpire= $this->convertToSeconds($this->shadowExpire);
206     /* Generate shell list from CONFIG_DIR./shells */
207     if (file_exists(CONFIG_DIR.'/shells')){
208       $shells = file (CONFIG_DIR.'/shells');
209       foreach ($shells as $line){
210         if (!preg_match ("/^#/", $line)){
211           $this->loginShellList[]= trim($line);
212         }
213       }
214     } else {
215       if ($this->loginShell == ""){
216         $this->loginShellList[]= _("unconfigured");
217       }
218     }
220     /* Insert possibly missing loginShell */
221     if ($this->loginShell != "" && !in_array($this->loginShell, $this->loginShellList)){
222       $this->loginShellList[]= $this->loginShell;
223     }
225     /* Generate group list */
226     $this->ui = get_userinfo(); 
227     $this->secondaryGroups[]= "- "._("automatic")." -";
228     $ldap->cd($this->config->current['BASE']);
229     $ldap->search("(objectClass=posixGroup)", array("cn", "gidNumber"));
230     while($attrs = $ldap->fetch()){
231       $this->secondaryGroups[$attrs['gidNumber'][0]]= $attrs['cn'][0];
232     }
233     asort ($this->secondaryGroups);
235     /* Get global filter config */
236     if (!session::is_set("sysfilter")){
237       $ui= get_userinfo();
238       $base= get_base_from_people($ui->dn);
239       $sysfilter= array( "depselect"       => $base,
240           "regex"           => "*");
241       session::set("sysfilter", $sysfilter);
242     }
243     $this->ui = get_userinfo();
244   }
247   /* execute generates the html output for this node */
248   function execute($isCopyPaste = false)
249   {
250     /* Call parent execute */
251     plugin::execute();
252     $display= "";
254     /* Log view */
255     if($this->is_account && !$this->view_logged){
256       $this->view_logged = TRUE;
257       new log("view","users/".get_class($this),$this->dn);
258     }
260     /* Department has changed? */
261     if(isset($_POST['depselect'])){
262       session::set('CurrentMainBase',validate($_POST['depselect']));
263     }
265     if($this->multiple_support_active){
266       $this->is_account = TRUE;
267     }
269     if(!$isCopyPaste && ! $this->multiple_support_active){
271       /* Do we need to flip is_account state? */
272       if(isset($_POST['modify_state'])){
273         if($this->is_account && $this->acl_is_removeable()){
274           $this->is_account= FALSE;
275         }elseif(!$this->is_account && $this->acl_is_createable()){
276           $this->is_account= TRUE;
277         }
278       }
280       /* Do we represent a valid posixAccount? */
281       if (!$this->is_account && $this->parent === NULL ){
282         $display= "<img alt=\"\" src=\"images/small-error.png\" align=\"middle\">&nbsp;<b>".
283           msgPool::noValidExtension(_("POSIX"))."</b>";
284         $display.= back_to_main();
285         return ($display);
286       }
289       /* Show tab dialog headers */
290       if ($this->parent !== NULL){
291         if ($this->is_account){
292           if (isset($this->parent->by_object['sambaAccount'])){
293             $obj= $this->parent->by_object['sambaAccount'];
294           }
295           if (isset($obj) && $obj->is_account == TRUE &&
296               ((isset($this->parent->by_object['sambaAccount']))&&($this->parent->by_object['sambaAccount']->is_account))
297               ||(isset($this->parent->by_object['environment'] ))&&($this->parent->by_object['environment'] ->is_account)){
299             /* Samba3 dependency on posix accounts are enabled
300                in the moment, because I need to rely on unique
301                uidNumbers. There'll be a better solution later
302                on. */
303             $display= $this->show_disable_header(msgPool::removeFeaturesButton(_("POSIX")), msgPool::featuresEnabled(_("POSIX"), array(_("Samba"), _("Environment"))), TRUE);
304           } else {
305             $display= $this->show_disable_header(msgPool::removeFeaturesButton(_("POSIX")), msgPool::featuresEnabled(_("POSIX")));
306           }
307         } else {
308           $display= $this->show_enable_header(msgPool::addFeaturesButton(_("POSIX")), msgPool::featuresDisabled(_("POSIX")));
309           return($display);
310         }
311       }
312     }
314     /* Trigger group edit? */
315     if (isset($_POST['edit_groupmembership'])){
316       $this->group_dialog= TRUE;
317       $this->dialog= TRUE;
318     }
320     /* Cancel group edit? */
321     if (isset($_POST['add_groups_cancel']) ||
322         isset($_POST['add_groups_finish'])){
323       $this->group_dialog= FALSE;
324       $this->dialog= FALSE;
325     }
327     /* Add selected groups */
328     if (isset($_POST['add_groups_finish']) && isset($_POST['groups']) &&
329         count($_POST['groups'])){
331       $this->addGroup ($_POST['groups']);
332     }
334     /* Delete selected groups */
335     if (isset($_POST['delete_groupmembership']) && 
336         isset($_POST['group_list']) && count($_POST['group_list'])){
338       $this->delGroup ($_POST['group_list']);
339     }
341     /* Add user workstation? */
342     if (isset($_POST["add_ws"])){
343       $this->show_ws_dialog= TRUE;
344       $this->dialog= TRUE;
345     }
347     /* Add user workstation? */
348     if (isset($_POST["add_ws_finish"]) && isset($_POST['wslist'])){
349       foreach($_POST['wslist'] as $ws){
350         $this->accessTo[$ws]= $ws;
351       }
352       ksort($this->accessTo);
353       $this->is_modified= TRUE;
354     }
356     /* Remove user workstations? */
357     if (isset($_POST["delete_ws"]) && isset($_POST['workstation_list'])){
358       foreach($_POST['workstation_list'] as $name){
359         unset ($this->accessTo[$name]);
360       }
361       $this->is_modified= TRUE;
362     }
364     /* Add user workstation finished? */
365     if (isset($_POST["add_ws_finish"]) || isset($_POST["add_ws_cancel"])){
366       $this->show_ws_dialog= FALSE;
367       $this->dialog= FALSE;
368     }
370     /* Templates now! */
371     $smarty= get_smarty();
373     /* Show ws dialog */
374     if ($this->show_ws_dialog){
375       /* Save data */
376       $sysfilter= session::get("sysfilter");
377       foreach( array("depselect", "regex") as $type){
378         if (isset($_POST[$type])){
379           $sysfilter[$type]= $_POST[$type];
380         }
381       }
382       if (isset($_GET['search'])){
383         $s= mb_substr($_GET['search'], 0, 1, "UTF8")."*";
384         if ($s == "**"){
385           $s= "*";
386         }
387         $sysfilter['regex']= $s;
388       }
389       session::set("sysfilter", $sysfilter);
391       /* Get workstation list */
392       $exclude= "";
393       foreach($this->accessTo as $ws){
394         $exclude.= "(cn=$ws)";
395       }
396       if ($exclude != ""){
397         $exclude= "(!(|$exclude))";
398       }
399       $regex= $sysfilter['regex'];
401       $acls = array();
402       if(class_available("servgeneric")) $acls[] = "server";
403       if(class_available("workgeneric")) $acls[] = "worstation";
404       if(class_available("termgeneric")) $acls[] = "terminal";
406       $filter= "(&(|(objectClass=goServer)(objectClass=gotoWorkstation)(objectClass=gotoTerminal))$exclude(cn=*)(cn=$regex))";
408       $deps_a = array(get_ou("serverRDN"),
409                       get_ou("terminalRDN"),
410                       get_ou("workstationRDN")); 
412       $res= get_sub_list($filter, $acls, $deps_a, get_ou("systemRDN").$sysfilter['depselect'], array("cn"), GL_SUBSEARCH | GL_SIZELIMIT);
413       $wslist= array();
414       foreach ($res as $attrs){
415         $wslist[]= preg_replace('/\$/', '', $attrs['cn'][0]);
416       }
417       asort($wslist);
418       $smarty->assign("search_image", get_template_path('images/lists/search.png'));
419       $smarty->assign("launchimage", get_template_path('images/lists/action.png'));
420       $smarty->assign("tree_image", get_template_path('images/lists/search-subtree.png'));
421       $smarty->assign("deplist", $this->config->idepartments);
422       $smarty->assign("alphabet", generate_alphabet());
423       foreach( array("depselect", "regex") as $type){
424         $smarty->assign("$type", $sysfilter[$type]);
425       }
426       $smarty->assign("hint", print_sizelimit_warning());
427       $smarty->assign("wslist", $wslist);
428       $smarty->assign("apply", apply_filter());
429       $display= $smarty->fetch (get_template_path('trust_machines.tpl', TRUE, dirname(__FILE__)));
430       return ($display);
431     }
433     /* Manage group add dialog */
434     if ($this->group_dialog){
436       /* Get global filter config */
437       $this->reload();
439       /* remove already assigned groups */
440       $glist= array();
441       foreach ($this->grouplist as $key => $value){
442         if (!isset($this->groupMembership[$key]) && obj_is_writable($key,"groups/group","memberUid")){
443           $glist[$key]= $value;
444         }
445       }
447       if($this->SubSearch){
448         $smarty->assign("SubSearchCHK"," checked ");
449       }else{
450         $smarty->assign("SubSearchCHK","");
451       }
453       $smarty->assign("regex",$this->GroupRegex);
454       $smarty->assign("guser",$this->GroupUserRegex);
455       $smarty->assign("groups", $glist);
456       $smarty->assign("search_image", get_template_path('images/lists/search.png'));
457       $smarty->assign("launchimage", get_template_path('images/lists/action.png'));
458       $smarty->assign("tree_image", get_template_path('images/lists/search-subtree.png'));
459       $smarty->assign("deplist", $this->config->idepartments);
460       $smarty->assign("alphabet", generate_alphabet());
461       $smarty->assign("depselect", session::get('CurrentMainBase'));
462       $smarty->assign("hint", print_sizelimit_warning());
463       $smarty->assign("apply", apply_filter());
465       $display.= $smarty->fetch (get_template_path('posix_groups.tpl', TRUE, dirname(__FILE__)));
466       return ($display);
467     }
469     // Handle ssh dialog?
470     if ($this->ssh && preg_match('/[rw]/', $this->getacl("sshPublicKey"))) {
471        if ($result= $this->ssh->execute()) {
472          $this->dialog= true;
473          return $result;
474        }
475        $this->dialog= false;
476     }
479     /* Show main page */
480     $smarty= get_smarty();
482     /* In 'MyAccount' mode, we must remove write acls if we are not in editing mode. */ 
483     $SkipWrite = (!isset($this->parent) || !$this->parent) && !session::is_set('edit');
485     $smarty->assign("sshPublicKeyACL", $this->getacl("sshPublicKey"));
487     /* Depending on pwmode, currently hardcoded because there are no other methods */
488     if ( 1 == 1 ){
489       $smarty->assign("pwmode", dirname(__FILE__)."/posix_shadow");
491       $shadowMinACL     =  $this->getacl("shadowMin",$SkipWrite);
492       $smarty->assign("shadowmins", sprintf(_("Password can't be changed up to %s days after last change"), 
493                                               "<input name=\"shadowMin\" size=3 maxlength=4 value=\"".$this->shadowMin."\">"));
495       $shadowMaxACL     =  $this->getacl("shadowMax",$SkipWrite);
496       $smarty->assign("shadowmaxs", sprintf(_("Password must be changed after %s days"), 
497                                               "<input name=\"shadowMax\" size=3 maxlength=4 value=\"".$this->shadowMax."\">"));
499       $shadowInactiveACL=  $this->getacl("shadowInactive",$SkipWrite);
500       $smarty->assign("shadowinactives", sprintf(_("Disable account after %s days of inactivity after password expiry"), 
501                                               "<input name=\"shadowInactive\" size=3 maxlength=4 value=\"".$this->shadowInactive."\">"));
503       $shadowWarningACL =  $this->getacl("shadowWarning",$SkipWrite);
504       $smarty->assign("shadowwarnings", sprintf(_("Warn user %s days before password expiry"), 
505                                               "<input name=\"shadowWarning\" size=3 maxlength=4 value=\"".$this->shadowWarning."\">"));
507       foreach( array("activate_shadowMin", "activate_shadowMax",
508                      "activate_shadowExpire", "activate_shadowInactive","activate_shadowWarning") as $val){
509         if ($this->$val == 1){
510           $smarty->assign("$val", "checked");
511         } else {
512           $smarty->assign("$val", "");
513         }
514         $smarty->assign("$val"."ACL", $this->getacl($val,$SkipWrite));
515       }
517       $smarty->assign("mustchangepasswordACL", $this->getacl("mustchangepassword",$SkipWrite));
518     }
520     /* Fill calendar */
521     /* If this $this->shadowExpire is empty 
522         use current date as base for calculating selectbox values.
523        (This attribute is empty if this is a new user )*/ 
524     if(empty($this->shadowExpire)){
525       $date= getdate(time());
526     }else{
527       $date= getdate($this->shadowExpire);
528     }
529  
530     $days= array();
531     for($d= 1; $d<32; $d++){
532       $days[$d]= $d;
533     }
534     $years= array();
535     for($y= $date['year']-10; $y<$date['year']+10; $y++){
536       $years[]= $y;
537     }
538     $months= msgPool::months();
539     $smarty->assign("day", $date["mday"]);
540     $smarty->assign("days", $days);
541     $smarty->assign("months", $months);
542     $smarty->assign("month", $date["mon"]-1);
543     $smarty->assign("years", $years);
544     $smarty->assign("year", $date["year"]);
546     /* Fill arrays */
547     $smarty->assign("shells", $this->loginShellList);
548     $smarty->assign("secondaryGroups", $this->secondaryGroups);
549     $smarty->assign("primaryGroup", $this->primaryGroup);
550     if(!$this->multiple_support_active){
551       if (!count($this->groupMembership)){
552         $smarty->assign("groupMembership", array("&nbsp;"));
553       } else {
554         $smarty->assign("groupMembership", $this->groupMembership);
555       }
556     }else{
557       $smarty->assign("groupMembership", $this->groupMembership);
558       $smarty->assign("groupMembership_some", $this->groupMembership_some);
559     }
560     if (count($this->groupMembership) > 16){
561       $smarty->assign("groups", "too_many_for_nfs");
562     } else {
563       $smarty->assign("groups", "");
564     }
566     /* Avoid "Undefined index: forceMode" */
567     $smarty->assign("forceMode", "");
569     /* Checkboxes */
570     if ($this->force_ids == 1){
571       $smarty->assign("force_ids", "checked");
572       if (session::get('js')){
573         $smarty->assign("forceMode", "");
574       }
575     } else {
576       if (session::get('js')){
577         $smarty->assign("forceMode", "disabled");
578       }
579       $smarty->assign("force_ids", "");
580     }
582     /* Create onClick="" action string for the "Force UID/GID" option 
583      */
584     $onClickIDS ="";
585     if(preg_match("/w/",$this->getacl("uidNumber",$SkipWrite))){
586       $onClickIDS .= "changeState('uidNumber');";
587     }
588     if(preg_match("/w/",$this->getacl("gidNumber",$SkipWrite))){
589       $onClickIDS .= "changeState('gidNumber');";
590     }
591     $smarty->assign("onClickIDS", $onClickIDS);
592     $smarty->assign("force_idsACL", $this->getacl("uidNumber",$SkipWrite).$this->getacl("gidNumber",$SkipWrite));
594     foreach(array("primaryGroup","trustmode","activate_shadowWarning","activate_shadowInactive","activate_shadowMin","activate_shadowMax","activate_shadowExpire","mustchangepassword") as $val){
595       if(in_array($val,$this->multi_boxes)){
596         $smarty->assign("use_".$val,TRUE);
597       }else{
598         $smarty->assign("use_".$val,FALSE);
599       }
600     }
603     /* Load attributes and acl's */
604     foreach($this->attributes as $val){
605       if(in_array($val,$this->multi_boxes)){
606         $smarty->assign("use_".$val,TRUE);
607       }else{
608         $smarty->assign("use_".$val,FALSE);
609       }
611       if((session::get("js"))&&(($val=="uidNumber")||($val=="gidNumber")))
612       {
613         $smarty->assign("$val"."ACL",$this->getacl($val,$SkipWrite));
614         $smarty->assign("$val", $this->$val);
615         continue;
616       }
617       $smarty->assign("$val", $this->$val);
618       $smarty->assign("$val"."ACL", $this->getacl($val,$SkipWrite));
619     }
620     if($SkipWrite){
621       $smarty->assign("groupMembershipACL","r");
622     }else{
623       $smarty->assign("groupMembershipACL","rw");
624     }
625     $smarty->assign("status", $this->status);
627     /* Work on trust modes */
628     $smarty->assign("trusthide", " disabled ");
629     $smarty->assign("trustmodeACL",  $this->getacl("trustModel",$SkipWrite));
630     if ($this->trustModel == "fullaccess"){
631       $trustmode= 1;
632       // pervent double disable tag in html code, this will disturb our clean w3c html
633       $smarty->assign("trustmode",  $this->getacl("trustModel",$SkipWrite));
635     } elseif ($this->trustModel == "byhost"){
636       $trustmode= 2;
637       $smarty->assign("trusthide", "");
638     } else {
639       // pervent double disable tag in html code, this will disturb our clean w3c html
640       $smarty->assign("trustmode",  $this->getacl("trustModel",$SkipWrite));
641       $trustmode= 0;
642     }
643     $smarty->assign("trustmode", $trustmode);
644     $smarty->assign("trustmodes", array( 0 => _("disabled"), 1 => _("full access"),
645           2 => _("allow access to these hosts")));
649     if((count($this->accessTo))==0)
650       $smarty->assign("emptyArrAccess",true);
651     else
652       $smarty->assign("emptyArrAccess",false);
654       if($this->mustchangepassword){
655         $smarty->assign("mustchangepassword", " checked ");
656       } else {
657         $smarty->assign("mustchangepassword", "");
658       }
660     $smarty->assign("workstations", $this->accessTo);
662     // Add SSH button if available
663     if ($this->ssh) {
664       $smarty->assign("sshPublicKey", 1);
665     }
667     $smarty->assign("apply", apply_filter());
668     $smarty->assign("multiple_support" , $this->multiple_support_active);
669     $display.= $smarty->fetch (get_template_path('generic.tpl', TRUE, dirname(__FILE__)));
670     return($display);
671   }
674   /* remove object from parent */
675   function remove_from_parent()
676   {
677     /* Cancel if there's nothing to do here */
678     if ((!$this->initially_was_account) || (!$this->acl_is_removeable())){
679       return;
680     }
683     /* Remove and write to LDAP */
684     plugin::remove_from_parent();
686     /* Zero out array */
687     $this->attrs['gosaHostACL']= array();
689     /* Keep uid, because we need it for authentification! */
690     unset($this->attrs['uid']);
691     unset($this->attrs['trustModel']);
693     @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
694     /* include global link_info */
695      $this->attributes, "Save");
696     $ldap= $this->config->get_ldap_link();
697     $ldap->cd($this->dn);
698     $this->cleanup();
699     $ldap->modify ($this->attrs); 
701     new log("remove","users/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
703     if (!$ldap->success()){
704       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
705     }
707     /* Delete group only if cn is uid and there are no other
708        members inside */
709     $ldap->cd ($this->config->current['BASE']);
710     $ldap->search ("(&(objectClass=posixGroup)(gidNumber=".$this->gidNumber."))", array("cn", "memberUid"));
711     if ($ldap->count() != 0){
712       $attrs= $ldap->fetch();
713       if ($attrs['cn'][0] == $this->uid &&
714           !isset($this->attrs['memberUid'])){
716         $ldap->rmDir($ldap->getDN());
717       }
718     }
720     /* Optionally execute a command after we're done */
721     $this->handle_post_events("remove",array("uid" => $this->uid));
722   }
725   function save_object()
726   {
727     if (isset($_POST['posixTab'])){
728       /* Save values to object */
729       plugin::save_object();
732       /* Save force GID checkbox */
733       if($this->acl_is_writeable("gidNumber") || $this->acl_is_writeable("uidNumber")){
734         if (isset ($_POST['force_ids'])){
735           $data= 1;
736         } else {
737           $data= 0;
738         }
739         if ($this->force_ids != $data){
740           $this->is_modified= TRUE;
741         }
742         $this->force_ids= $data;
743       }
745       /*Save primary group settings */
746       if($this->acl_is_writeable("primaryGroup") && isset($_POST['primaryGroup'])){
747         $data= $_POST['primaryGroup'];
748         if ($this->primaryGroup != $data){
749           $this->is_modified= TRUE;
750         }
751         $this->primaryGroup= $_POST['primaryGroup'];
752       }
754       /* Get seelcted shadow checkboxes */
755       foreach(array("shadowMin","shadowMax","shadowExpire","shadowInactive","shadowWarning") as $var) {
756         if($this->acl_is_writeable($var)){
757           $activate_var = "activate_".$var;
758           if(isset($_POST['activate_'.$var])){
759             $this->$activate_var  = true;
760             $this->$var      = $_POST[$var];
761           }else{
762             $this->$activate_var  = false;
763             $this->$var      = 0;
764           }
765         }
766       }
768       /* Force change password ? */
769       if(isset($_POST['mustchangepassword'])){
770         $this->mustchangepassword = TRUE;
771       }else{
772         $this->mustchangepassword = FALSE;
773       }
775       /* Trust mode - special handling */
776       if($this->acl_is_writeable("trustModel")){
777         if (isset($_POST['trustmode'])){
778           $saved= $this->trustModel;
779           if ($_POST['trustmode'] == "1"){
780             $this->trustModel= "fullaccess";
781           } elseif ($_POST['trustmode'] == "2"){
782             $this->trustModel= "byhost";
783           } else {
784             $this->trustModel= "";
785           }
786           if ($this->trustModel != $saved){
787             $this->is_modified= TRUE;
788           }
789         }
790       }
791     }
793     /* Get regex from alphabet */
794     if(isset($_GET['search'])){
795       $this->GroupRegex = $_GET['search']."*";
796     }
798     /* Check checkboxes and regexes */
799     if(isset($_POST["PosixGroupDialogPosted"])){
801       if(isset($_POST['SubSearch']) && ($_POST['SubSearch'])){
802         $this->SubSearch = true;
803       }else{
804         $this->SubSearch = false;
805       }
806       if(isset($_POST['guser'])){
807         $this->GroupUserRegex = $_POST['guser'];
808       }
809       if(isset($_POST['regex'])){
810         $this->GroupRegex = $_POST['regex'];
811       }
812     }
813     $this->GroupRegex = preg_replace("/\*\**/","*",$this->GroupRegex);
814     $this->GroupUserRegex = preg_replace("/\*\**/","*",$this->GroupUserRegex);
815   }
818   /* Save data to LDAP, depending on is_account we save or delete */
819   function save()
820   {
822     /* Adapt shadow values */
823     if (!$this->activate_shadowExpire){
824       $this->shadowExpire= "0";
825     } else {
826       /* Transform seconds to days here */
827       $this->shadowExpire= (int)($this->shadowExpire / (60 * 60 * 24)) ;
828     }
829     if (!$this->activate_shadowMax){
830       $this->shadowMax= "0";
831     }
832     if ($this->mustchangepassword){
833       $this->shadowLastChange= (int)(date("U") / 86400) - $this->shadowMax - 1;
834     } else {
835       $this->shadowLastChange= (int)(date("U") / 86400);
836     }
837     if (!$this->activate_shadowWarning){
838       $this->shadowWarning= "0";
839     }
841     /* Check what to do with ID's 
842         Nothing forced, so we may have to generate our own IDs, if not done already.
843      */
844     if ($this->force_ids == 0){
846       /* Handle uidNumber. 
847        * - use existing number if possible
848        * - if not, try to create a new uniqe one.
849        * */
850       if ($this->savedUidNumber != ""){
851         $this->uidNumber= $this->savedUidNumber;
852       } else {
854         /* Calculate new id's. We need to place a lock before calling get_next_id
855            to get real unique values. 
856          */
857         $wait= 10;
858         while (get_lock("uidnumber") != ""){
859           sleep (1);
861           /* Oups - timed out */
862           if ($wait-- == 0){
863             msg_dialog::display(_("Warning"), _("Timeout while waiting for lock. Ignoring lock!"), WARNING_DIALOG);
864             break;
865           }
866         }
867         add_lock ("uidnumber", "gosa");
868         $this->uidNumber= $this->get_next_id("uidNumber", $this->dn);
869       }
870     }
873     /* Handle gidNumber 
874      * - If we do not have a primary group selected (automatic), we will check if there 
875      *    is already a group  with the same name and use this as primary.
876      * - .. if we couldn't find a group with the same name, we will create a new one, 
877      *    using the users uid as cn and a generated uniqe gidNumber. 
878      * */
879     if ($this->primaryGroup == 0 || $this->force_ids){
881       /* Search for existing group */
882       $ldap = $this->config->get_ldap_link();
883       $ldap->cd($this->config->current['BASE']);
885       /* Are we forced to use a special gidNumber? */ 
886       if($this->force_ids){
887         $ldap->search("(&(objectClass=posixGroup)(gidNumber=".$this->gidNumber."))", array("cn","gidNumber"));
888       }else{
889         $ldap->search("(&(objectClass=posixGroup)(gidNumber=*)(cn=".$this->uid."))", array("cn","gidNumber"));
890       }
892       /* No primary group found, create a new one */
893       if ($ldap->count() == 0){
895         $groupcn = $this->uid;
896         $groupdn= preg_replace ('/^'.$this->config->get_cfg_value("accountPrimaryAttribute").'=[^,]+,'.get_people_ou().'/i',
897             'cn='.$groupcn.','.get_groups_ou(), $this->dn);
899         /* Request a new and uniqe gidNumber, if required */
900         if(!$this->force_ids){
901           $this->gidNumber= $this->get_next_id("gidNumber", $this->dn);
902         }else{
904           /* If forced gidNumber could not be found, then check if the given group name already exists 
905               we do not want to modify the gidNumber of an existing group.
906            */
907           $cnt= 0; 
908           while($ldap->dn_exists($groupdn)){
909             $cnt ++;
910             $groupcn = $this->uid."_".$cnt;
911             $groupdn= preg_replace ('/^'.$this->config->get_cfg_value("accountPrimaryAttribute").'=[^,]+,'.get_people_ou().'/i',
912             'cn='.$groupcn.','.get_groups_ou(), $this->dn);
913           }
914         }
916         /* Create new primary group and enforce the new gidNumber */
917         $g= new group($this->config, $groupdn);
918         $g->cn= $groupcn;
919         $g->force_gid= 1;
920         $g->gidNumber= $this->gidNumber;
921         $g->description= _("Group of user")." ".$this->givenName." ".$this->sn;
922         $g->save ();
924         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
925             sprintf("Primary group '%s' created, using gidNumber '%s'.",$groupcn,$this->gidNumber),"");
926       }else{
927         $attrs = $ldap->fetch();
928         $this->gidNumber = $attrs['gidNumber'][0];
929         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
930             "Found and used: <i>".$attrs['dn']."</i>",
931             sprintf("Primary group '%s' exists, gidNumber is '%s'.",$this->uid,$this->gidNumber));
932       }
933     }else{
935       /* Primary group was selected by user
936        */
937       $this->gidNumber = $this->primaryGroup;
938       @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
939           sprintf("Primary group '%s' for user '%s' manually selected.",$this->gidNumber,$this->uid),"");
940     }
942     if ($this->activate_shadowMin != "1" ) {
943       $this->shadowMin = "";
944     }
946     if (($this->activate_shadowMax != "1") && ($this->mustchangepassword != "1")) {
947       $this->shadowMax = "";
948     }
950     if ($this->activate_shadowWarning != "1" ) {
951       $this->shadowWarning = "";
952     }
954     if ($this->activate_shadowInactive != "1" ) {
955       $this->shadowInactive = "";
956     }
958     if ($this->activate_shadowExpire != "1" ) {
959       $this->shadowExpire = "";
960     }
962     /* Fill gecos */
963     if (isset($this->parent) && $this->parent !== NULL){
964       $this->gecos= rewrite($this->parent->by_object['user']->cn);
965       if (!preg_match('/^[a-z0-9 -]+$/i', $this->gecos)){
966         $this->gecos= "";
967       }
968     }
970     foreach(array("shadowMin","shadowMax","shadowWarning","shadowInactive","shadowExpire") as $attr){
971       $this->$attr = (int) $this->$attr;
972     }
973     /* Call parents save to prepare $this->attrs */
974     plugin::save();
976     /* Trust accounts */
977     $objectclasses= array();
978     foreach ($this->attrs['objectClass'] as $key => $class){
979       if (preg_match('/trustAccount/i', $class)){
980         continue;
981       }
982       $objectclasses[]= $this->attrs['objectClass'][$key];
983     }
984     $this->attrs['objectClass']= $objectclasses;
985     if ($this->trustModel != ""){
986       $this->attrs['objectClass'][]= "trustAccount";
987       $this->attrs['trustModel']= $this->trustModel;
988       $this->attrs['accessTo']= array();
989       if ($this->trustModel == "byhost"){
990         foreach ($this->accessTo as $host){
991           $this->attrs['accessTo'][]= $host;
992         }
993       }
994     } else {
995       if ($this->was_trust_account){
996         $this->attrs['accessTo']= array();
997         $this->attrs['trustModel']= array();
998       }
999     }
1001     if(empty($this->attrs['gosaDefaultPrinter'])){
1002       $thid->attrs['gosaDefaultPrinter']=array();
1003     }
1006     /* include global link_info */
1007     $this->cleanup();
1008  
1009     /* This is just a test, we have had duplicated ids 
1010         in the past when copy & paste was used. 
1011        Normaly this should not happen.
1012      */ 
1013     if(isset($this->attrs['uidNumber']) && !$this->force_ids){
1014       $used = $this->get_used_uid_numbers();
1015       if(isset($used[$this->attrs['uidNumber']]) && $used[$this->attrs['uidNumber']] != $this->dn){
1016         msg_dialog::display(_("Warning"),_("A duplicated UID number was written for this user. If this was not intended please verify all used uidNumbers!"), WARNING_DIALOG);
1017       }
1018     }
1020     $ldap= $this->config->get_ldap_link();
1021     $ldap->cd($this->dn);
1022     unset($this->attrs['uid']);
1023     $ldap->modify ($this->attrs); 
1025     /* Log last action */ 
1026     if($this->initially_was_account){
1027       new log("modify","users/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
1028     }else{
1029       new log("create","users/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error());
1030     }
1032     if (!$ldap->success()){
1033       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
1034     }
1036     /* Remove lock needed for unique id generation */
1037     del_lock ("uidnumber");
1039     // Save ssh stuff if needed
1040     if ($this->ssh) {
1041       $this->ssh->setDN($this->dn);
1042       $this->ssh->save();
1043     }
1045     /* Take care about groupMembership values: add to groups */
1046     foreach ($this->groupMembership as $key => $value){
1047       if (!isset($this->savedGroupMembership[$key])){
1048         $g= new grouptabs($this->config,$this->config->data['TABS']['GROUPTABS'], $key,"groups");
1049         $g->set_acl_base($key);
1050         $g->by_object['group']->addUser($this->uid);
1051         $g->save();
1052       }
1053     }
1055     /* Remove groups not listed in groupMembership */
1056     foreach ($this->savedGroupMembership as $key => $value){
1057       if (!isset($this->groupMembership[$key])){
1058         $g= new grouptabs($this->config,$this->config->data['TABS']['GROUPTABS'], $key,"groups");
1059         $g->set_acl_base($key);
1060         $g->by_object['group']->removeUser ($this->uid);
1061         $g->save();
1062       }
1063     }
1065     /* Optionally execute a command after we're done */
1066     if ($this->initially_was_account == $this->is_account){
1067       if ($this->is_modified){
1068         $this->handle_post_events("modify",array("uid" => $this->uid));
1069       }
1070     } else {
1071       $this->handle_post_events("add" ,array("uid"=> $this->uid));
1072     }
1073   }
1076   /* Check formular input */
1077   function check()
1078   {
1079     /* Include global link_info */
1080     $ldap= $this->config->get_ldap_link();
1082     /* Append groups as memberGroup: to check hook 
1083      */
1084     $tmp_attributes  = $this->attributes;    
1085     $this->attributes[] = "memberGroup";
1086     $this->memberGroup = array();
1087     foreach($this->groupMembership as $dn => $name){
1088       $this->memberGroup[] = $name;
1089     }
1091     /* Call common method to give check the hook */
1092     $message= plugin::check();
1093     $this->attributes = $tmp_attributes;
1095     /* must: homeDirectory */
1096     if ($this->homeDirectory == ""){
1097       $message[]= msgPool::required(_("Home directory"));
1098     }
1099     if (!tests::is_path($this->homeDirectory)){
1100       $message[]= msgPool::invalid(_("Home directory"), "", "", "/home/yourname" );
1101     }
1103     /* Check ID's if they are forced by user */
1104     if ($this->force_ids == "1"){
1106       /* Valid uid/gid? */
1107       if (!tests::is_id($this->uidNumber)){
1108         $message[]= msgPool::invalid(_("UID"), $this->uidNumber, "/[0-9]/");
1109       } else {
1110         if ($this->uidNumber < $this->config->get_cfg_value("minId")){
1111           $message[]= msgPool::toosmall(_("UID"), $this->config->get_cfg_value("minId"));
1112         }
1113       }
1114       if (!tests::is_id($this->gidNumber)){
1115         $message[]= msgPool::invalid(_("GID"), $this->gidNumber, "/[0-9]/");
1116       } else {
1117         if ($this->gidNumber < $this->config->get_cfg_value("minId")){
1118           $message[]= msgPool::toosmall(_("GID"), $this->config->get_cfg_value("minId"));
1119         }
1120       }
1121     }
1123     /* Check shadow settings, well I like spaghetties... */
1124     if ($this->activate_shadowMin){
1125       if (!tests::is_id($this->shadowMin)){
1126         $message[]= msgPool::invalid(_("shadowMin"), $this->shadowMin, "/[0-9]/");
1127       }
1128     }
1129     if ($this->activate_shadowMax){
1130       if (!tests::is_id($this->shadowMax)){
1131         $message[]= msgPool::invalid(_("shadowMax"), $this->shadowMax, "/[0-9]/");
1132       }
1133     }
1134     if ($this->activate_shadowWarning){
1135       if (!tests::is_id($this->shadowWarning)){
1136         $message[]= msgPool::invalid(_("shadowWarning"), $this->shadowWarning, "/[0-9]/");
1137       }
1138       if (!$this->activate_shadowMax){
1139         $message[]= msgPool::depends("shadowWarning", "shadowMax");
1140       }
1141       if ($this->shadowWarning > $this->shadowMax){
1142         $message[]= msgPool::toobig("shadowWarning", "shadowMax");
1143       }
1144       if ($this->activate_shadowMin && $this->shadowWarning < $this->shadowMin){
1145         $message[]= msgPool::toosmall("shadowWarning", "shadowMin");
1146       }
1147     }
1148     if ($this->activate_shadowInactive){
1149       if (!tests::is_id($this->shadowInactive)){
1150         $message[]= msgPool::invalid(_("shadowInactive"), $this->shadowInactive, "/[0-9]/");
1151       }
1152       if (!$this->activate_shadowMax){
1153         $message[]= msgPool::depends("shadowInactive", "shadowMax");
1154       }
1155     }
1156     if ($this->activate_shadowMin && $this->activate_shadowMax){
1157       if ($this->shadowMin > $this->shadowMax){
1158         $message[]= msgPool::toobig("shadowMin", "shadowMax");
1159       }
1160     }
1162     return ($message);
1163   }
1166   function multiple_check()
1167   {
1168     $message = plugin::multiple_check();
1169     if ($this->homeDirectory == "" && in_array("homeDirectory",$this->multi_boxes)){
1170       $message[]= msgPool::required(_("Home directory"));
1171     }
1172     if (!tests::is_path($this->homeDirectory) && in_array("homeDirectory",$this->multi_boxes)){
1173       $message[]= msgPool::invalid(_("Home directory"), "", "", "/home/yourname" );
1174     }
1176     /* Check shadow settings, well I like spaghetties... */
1177     if ($this->activate_shadowMin && in_array("activate_shadowMin",$this->multi_boxes)){
1178       if (!tests::is_id($this->shadowMin)){
1179         $message[]= msgPool::invalid(_("shadowMin"), $this->shadowMin, "/[0-9]/");
1180       }
1181     }
1182     if ($this->activate_shadowMax && in_array("activate_shadowMax",$this->multi_boxes)){
1183       if (!tests::is_id($this->shadowMax)){
1184         $message[]= msgPool::invalid(_("shadowMax"), $this->shadowMax, "/[0-9]/");
1185       }
1186     }
1187     if ($this->activate_shadowWarning && in_array("activate_shadowWarning",$this->multi_boxes)){
1188       if (!tests::is_id($this->shadowWarning)){
1189         $message[]= msgPool::invalid(_("shadowWarning"), $this->shadowWarning, "/[0-9]/");
1190       }
1191       if (!$this->activate_shadowMax && in_array("activate_shadowMax",$this->multi_boxes)){
1192         $message[]= msgPool::depends("shadowWarning", "shadowMax");
1193       }
1194       if ($this->shadowWarning > $this->shadowMax && in_array("activate_shadowWarning",$this->multi_boxes)){
1195         $message[]= msgPool::toobig("shadowWarning", "shadowMax");
1196       }
1197       if ($this->activate_shadowMin && $this->shadowWarning < $this->shadowMin && in_array("activate_shadowMin",$this->multi_boxes)){
1198         $message[]= msgPool::tosmall("shadowWarning", "shadowMin");
1199       }
1200     }
1201     if ($this->activate_shadowInactive && in_array("activate_shadowInactive",$this->multi_boxes)){
1202       if (!tests::is_id($this->shadowInactive)){
1203         $message[]= msgPool::invalid(_("shadowInactive"), $this->shadowInactive, "/[0-9]/");
1204       }
1205       if (!$this->activate_shadowMax && in_array("activate_shadowMax",$this->multi_boxes)){
1206         $message[]= msgPool::depends("shadowInactive", "shadowMax");
1207       }
1208     }
1209     if ($this->activate_shadowMin && $this->activate_shadowMax && in_array("activate_shadowMin",$this->multi_boxes)){
1210       if ($this->shadowMin > $this->shadowMax){
1211         $message[]= msgPool::toobig("shadowMin", "shadowMax");
1212       }
1213     }
1215     return($message);
1216   }
1219   function addGroup ($groups)
1220   {
1221     /* include global link_info */
1222     $ldap= $this->config->get_ldap_link();
1224     /* Walk through groups and add the descriptive entry if not exists */
1225     foreach ($groups as $value){
1227       if (!array_key_exists($value, $this->groupMembership)){
1228         $ldap->cat($value, array('cn', 'description', 'dn'));
1229         $attrs= $ldap->fetch();
1230         error_reporting (0);
1231         if (!isset($attrs['description'][0])){
1232           $entry= $attrs["cn"][0];
1233         } else {
1234           $dsc= preg_replace ('/^Group of user/', _("Group of user"), $attrs["description"][0]);
1235           $entry= $attrs["cn"][0]." [$dsc]";
1236         }
1237         error_reporting (E_ALL | E_STRICT);
1239         if(obj_is_writable($attrs['dn'],"groups/group","memberUid")){
1240           $this->groupMembership[$attrs['dn']]= $entry;
1241           if($this->multiple_support_active && isset($this->groupMembership_some[$attrs['dn']])){
1242             unset($this->groupMembership_some[$attrs['dn']]);
1243           }
1244         }
1245       }
1246     }
1248     /* Sort groups */
1249     asort ($this->groupMembership);
1250     reset ($this->groupMembership);
1251   }
1254   /* Del posix user from some groups */
1255   function delGroup ($groups)
1256   {
1257     $dest= array();
1258     foreach($groups as $dn_to_del){
1259       if(isset($this->groupMembership[$dn_to_del]) && obj_is_writable($dn_to_del,"groups/group","memberUid")){
1260         unset($this->groupMembership[$dn_to_del]);
1261       }
1262       if($this->multiple_support_active){
1263         if(isset($this->groupMembership_some[$dn_to_del]) && obj_is_writable($dn_to_del,"groups/group","memberUid")){
1264           unset($this->groupMembership_some[$dn_to_del]);
1265         }
1266       }
1267     }
1268   }
1271   /* Adapt from template, using 'dn' */
1272   function adapt_from_template($dn, $skip= array())
1273   {
1274     /* Include global link_info */
1275     $ldap= $this->config->get_ldap_link();
1277     plugin::adapt_from_template($dn, $skip);
1278     $template= $this->attrs['uid'][0];
1280     /* Adapt group membership */
1281     $ldap->cd($this->config->current['BASE']);
1282     $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->attrs["uid"][0]."))", array("description", "cn"));
1284     while ($this->attrs= $ldap->fetch()){
1285       if (!isset($this->attrs["description"][0])){
1286         $entry= $this->attrs["cn"][0];
1287       } else {
1288         $entry= $this->attrs["cn"][0]." [".$this->attrs["description"][0]."]";
1289       }
1290       $this->groupMembership[$ldap->getDN()]= $entry;
1291     }
1293     /* Fix primary group settings */
1294     $ldap->cd($this->config->current['BASE']);
1295     $ldap->search("(&(objectClass=posixGroup)(cn=$template)(gidNumber=".$this->gidNumber."))", array("cn"));
1296     if ($ldap->count() != 1){
1297       $this->primaryGroup= $this->gidNumber;
1298     }
1300     $ldap->cd($this->config->current['BASE']);
1301     $ldap->search("(&(objectClass=gosaUserTemplate)(uid=".$template.")(accessTo=*))", array("cn","accessTo"));
1302     while($attr = $ldap->fetch()){
1303       $tmp = $attr['accessTo'];
1304       unset ($tmp['count']);
1305       $this->accessTo = $tmp;   
1306     }
1308     /* Adjust shadow checkboxes */
1309     foreach (array("shadowMin", "shadowMax", "shadowWarning", "shadowInactive") as $val){
1310       if ($this->$val != 0){
1311         $oval= "activate_".$val;
1312         $this->$oval= "1";
1313       }
1314     }
1316     /* FIXME: NEED review of this section */
1317     /* Need to check shadowExpire separately */
1319     /* 
1320      * If shadowExpire is not enabled in the template, it's a UNIX timestamp - so don't convert it to seconds.
1321      * The check is a hack - if difference between timestamp generated above and here is max 1 day.
1322      */
1323     if(abs($this->shadowExpire - time())>86400) {
1324       $this->shadowExpire= $this->convertToSeconds($this->shadowExpire);
1325     }
1326     
1327     /* Only enable checkbox, if shadowExpire is in the future */
1328     if($this->shadowExpire > time()) {
1329       $this->activate_shadowExpire= "1";
1330     }
1331   }
1333   function convertToSeconds($val)
1334   {
1335     if ($val != 0){
1336       $val*= 60 * 60 * 24;
1337     } else {
1338       $date= getdate();
1339       $val= floor($date[0] / (60*60*24)) * 60 * 60 * 24;
1340     }
1341     return($val);
1342   }
1345   function get_used_uid_numbers()
1346   {
1347     $ids= array();
1348     $ldap= $this->config->get_ldap_link();
1350     $ldap->cd ($this->config->current['BASE']);
1351     $ldap->search ("(&(objectClass=posixAccount)(uidNumber=*))", array("uidNumber"));
1353     /* Get list of ids */
1354     while ($attrs= $ldap->fetch()){
1355       $ids[$attrs['uidNumber'][0]] = $attrs['dn'];
1356     }
1357     return($ids);
1358   }
1360   
1361   function get_next_id($attrib, $dn)
1362   {
1363     $ids= array();
1364     $ldap= $this->config->get_ldap_link();
1366     $ldap->cd ($this->config->current['BASE']);
1367     if (preg_match('/gidNumber/i', $attrib)){
1368       $oc= "posixGroup";
1369     } else {
1370       $oc= "posixAccount";
1371     }
1372     $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib"));
1374     /* Get list of ids */
1375     while ($attrs= $ldap->fetch()){
1376       $ids[]= (int)$attrs["$attrib"][0];
1377     }
1379     /* Add the nobody id */
1380     $ids[]= 65534;
1382     /* get the ranges */
1383     $tmp = array('0'=> 1000); 
1384     if (preg_match('/posixAccount/', $oc) && $this->config->get_cfg_value("uidNumberBase") != ""){
1385       $tmp= split('-',$this->config->get_cfg_value("uidNumberBase"));
1386     } elseif($this->config->get_cfg_value("gidNumberBase") != ""){
1387       $tmp= split('-',$this->config->get_cfg_value("gidNumberBase"));
1388     }
1390     /* Set hwm to max if not set - for backward compatibility */
1391     $lwm= $tmp[0];
1392     if (isset($tmp[1])){
1393       $hwm= $tmp[1];
1394     } else {
1395       $hwm= pow(2,32);
1396     }
1398     /* Find out next free id near to UID_BASE */
1399     if ($this->config->get_cfg_value("baseIdHook") == ""){
1400       $base= $lwm;
1401     } else {
1402       /* Call base hook */
1403       $base= get_base_from_hook($dn, $attrib);
1404     }
1405     for ($id= $base; $id++; $id < pow(2,32)){
1406       if (!in_array($id, $ids)){
1407         return ($id);
1408       }
1409     }
1411     /* Should not happen */
1412     if ($id == $hwm){
1413       msg_dialog::display(_("Error"), _("Cannot allocate a free ID!"), ERROR_DIALOG);
1414       exit;
1415     }
1417   }
1419   function reload()
1420   {
1421     /* Set base for all searches */
1422     $base      = session::get('CurrentMainBase');
1423     $base     = $base;
1424     $ldap     = $this->config->get_ldap_link();    
1425     $attrs    =  array("cn", "description", "gidNumber");
1426     $Flags    = GL_SIZELIMIT;
1428     /* Get groups */
1429     if ($this->GroupUserRegex == '*'){
1430       $filter = "(&(objectClass=posixGroup)(cn=".$this->GroupRegex."))";
1431     } else {
1432       $filter= "(&(objectClass=posixGroup)(cn=".$this->GroupRegex.")(memberUid=".$this->GroupUserRegex."))";
1433     }
1434     if($this->SubSearch){
1435       $Flags |= GL_SUBSEARCH;
1436     }else{
1437       $base = get_groups_ou().$base;
1438     }
1440     $res= get_list($filter, "groups", $base,$attrs, $Flags);
1441   
1442     /* check sizelimit */
1443     if (preg_match("/size limit/i", $ldap->get_error())){
1444       session::set('limit_exceeded',TRUE);
1445     }
1447     /* Create a list of users */
1448     $this->grouplist = array();
1449     foreach ($res as $value){
1450       $this->grouplist[$value['gidNumber'][0]]= $value;
1451     }
1453     $tmp=array();
1454     foreach($this->grouplist as $tkey => $val ){
1455       $tmp[strtolower($val['cn'][0]).$val['cn'][0]]=$val;
1456     }
1458     /* Sort index */
1459     ksort($tmp);
1461     /* Recreate index array[dn]=cn[description]*/
1462     $this->grouplist=array();
1463     foreach($tmp as $val){
1464       if(isset($val['description'])){
1465         $this->grouplist[$val['dn']]=$val['cn'][0]."&nbsp;[".$val['description'][0]."]";
1466       }else{
1467         $this->grouplist[$val['dn']]=$val['cn'][0];
1468       }
1469     }
1471     reset ($this->grouplist);
1472   }
1475   /* Get posts from copy & paste dialog */ 
1476   function saveCopyDialog()
1477   {
1478     if(isset($_POST['homeDirectory'])){
1479       $this->homeDirectory = $_POST['homeDirectory'];
1480       if (isset ($_POST['force_ids'])){
1481         $data= 1;
1482         $this->gidNumber = $_POST['gidNumber'];
1483         $this->uidNumber = $_POST['uidNumber'];
1484       } else {
1485         $data= 0;
1486       }
1487       if ($this->force_ids != $data){
1488         $this->is_modified= TRUE;
1489       }
1490       $this->force_ids= $data;
1491       $data= $_POST['primaryGroup'];
1492       if ($this->primaryGroup != $data){
1493         $this->is_modified= TRUE;
1494       }
1495       $this->primaryGroup= $_POST['primaryGroup'];
1496     }
1497   }
1498  
1500   /* Create the posix dialog part for copy & paste */
1501   function getCopyDialog()
1502   {
1503     /* Skip dialog creation if this is not a valid account*/
1504     if(!$this->is_account) return("");
1505     if ($this->force_ids == 1){
1506       $force_ids = "checked";
1507       if (session::get('js')){
1508         $forceMode = "";
1509       }
1510     } else {
1511       if (session::get('js')){
1512         if($this->acl != "#none#")
1513           $forceMode ="disabled";
1514       }
1515       $force_ids = "";
1516     }
1518     $sta = "";
1520     /* Open group add dialog */
1521     if(isset($_POST['edit_groupmembership'])){
1522       $this->group_dialog = TRUE;
1523       $sta = "SubDialog";
1524     }
1526     /* If the group-add dialog is closed, call execute 
1527        to ensure that the membership is updatd */
1528     if(isset($_POST['add_groups_finish']) || isset($_POST['add_groups_cancel'])){
1529       $this->execute();
1530       $this->group_dialog =FALSE;
1531     }
1533     if($this->group_dialog){
1534       $str = $this->execute(true);
1535       $ret = array();
1536       $ret['string'] = $str;
1537       $ret['status'] = $sta;
1538       return($ret);
1539     }
1541     /* If a group member should be deleted, simply call execute */
1542     if(isset($_POST['delete_groupmembership'])){
1543       $this->execute();
1544     }
1546     /* Assigned informations to smarty */
1547     $smarty = get_smarty();
1548     $smarty->assign("homeDirectory",$this->homeDirectory);
1549     $smarty->assign("secondaryGroups",$this->secondaryGroups);
1550     $smarty->assign("primaryGroup",$this->primaryGroup);
1551  
1552     $smarty->assign("uidNumber",$this->uidNumber);
1553     $smarty->assign("gidNumber",$this->gidNumber);
1554     $smarty->assign("forceMode",$forceMode);
1555     $smarty->assign("force_ids",$force_ids);
1556     if (!count($this->groupMembership)){
1557       $smarty->assign("groupMembership", array("&nbsp;"));
1558     } else {
1559       $smarty->assign("groupMembership", $this->groupMembership);
1560     }
1562     /* Display wars message if there are more than 16 group members */
1563     if (count($this->groupMembership) > 16){
1564       $smarty->assign("groups", "too_many_for_nfs");
1565     } else {
1566       $smarty->assign("groups", "");
1567     }
1568     $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE,dirname(__FILE__)));
1570     $ret = array();
1571     $ret['string'] = $str;
1572     $ret['status'] = $sta;
1573     return($ret);
1574   }
1577   function PrepareForCopyPaste($source)
1578   {
1579     plugin::PrepareForCopyPaste($source);
1581     /* Avoid using the same gid/uid number as source user 
1582         empty numbers to enforce new ones. */
1583 #    $this->savedUidNumber = $this->get_next_id("uidNumber", $this->dn);
1584     $this->savedUidNumber = "";
1585 #    $this->savedGidNumber = $this->get_next_id("gidNumber", $this->dn);
1586     $this->savedGidNumber = "";
1588     /* Fill group */
1589     if(isset($source['gidNumber'][0])){
1590       $this->primaryGroup= $source['gidNumber'][0];
1591     }
1593   }
1596   function multiple_execute()
1597   {
1598     return($this->execute());
1599   }
1602   static function plInfo()
1603   {
1604     return (array(
1605           "plDescription"     => _("POSIX account"),
1606           "plSelfModify"      => TRUE,
1607           "plDepends"         => array("user"),
1608           "plPriority"        => 2,
1609           "plSection"         => array("personal" => _("My account")),
1610           "plCategory"        => array("users"),
1611           "plOptions"         => array(),
1613           "plProvidedAcls"  => array(
1615             "homeDirectory"       =>  _("Home directory"), 
1616             "loginShell"          =>  _("Shell"),
1617             "uidNumber"           =>  _("User ID"),
1618             "gidNumber"           =>  _("Group ID"),
1620             "mustchangepassword"=>  _("Force password change on login"),
1621             "shadowMin"           =>  _("Shadow min"),
1622             "shadowMax"           =>  _("Shadow max"),
1623             "shadowWarning"       =>  _("Shadow warning"),
1624             "shadowInactive"      =>  _("Shadow inactive"),
1625             "shadowExpire"        =>  _("Shadow expire"),
1626             "trustModel"          =>  _("System trust model")))
1627             );
1628   }
1631   /* Return selected values for multiple edit */
1632   function get_multi_edit_values()
1633   {
1634     $ret = plugin::get_multi_edit_values();
1635     $ret['groupMembership']     = $this->groupMembership;
1636     $ret['groupMembership_some']= $this->groupMembership_some;
1638     if(in_array("primaryGroup",$this->multi_boxes)){
1639       $ret['primaryGroup'] = $this->primaryGroup;
1640     }
1641     if(in_array("trustmode",$this->multi_boxes)){
1642       $ret['trustModel'] = $this->trustModel;
1643       $ret['accessTo'] = $this->accessTo;
1644     }
1645     foreach(array("shadowWarning","shadowInactive","shadowMin","shadowMax", "shadowExpire") as $entry){
1646       $active = "activate_".$entry;
1647       if(in_array($active,$this->multi_boxes)){
1648         $ret[$entry] = $this->$entry;
1649         $ret[$active] = $this->$active;
1650       }
1651     }
1652     if(in_array("mustchangepassword",$this->multi_boxes)){
1653       $ret['mustchangepassword'] = $this->mustchangepassword;
1654     }
1655     return($ret);
1656   }
1659   /* Save posts for multiple edit 
1660    */
1661   function multiple_save_object()
1662   {
1663     if(isset($_POST['posix_mulitple_edit'])){
1664  
1665       /* Backup expire value */ 
1666       $expire_tmp = $this->shadowExpire;
1667   
1668       /* Update all values */
1669       plugin::multiple_save_object();
1671       /* Get selected checkboxes */
1672       foreach(array("primaryGroup","trustmode","mustchangepassword","activate_shadowWarning","activate_shadowInactive","activate_shadowMin", "activate_shadowMax","activate_shadowExpire") as $val){
1673         if(isset($_POST["use_".$val])){
1674           $this->multi_boxes[] = $val;
1675         }
1676       }
1678       /* Update special values, checkboxes for posixShadow */
1679       foreach(array("shadowMin","shadowMax","shadowExpire","shadowInactive","shadowWarning") as $var) {
1680         if($this->acl_is_writeable($var)){
1681           $activate_var = "activate_".$var;
1682           if(in_array($activate_var, $this->multi_boxes)){
1683             if(isset($_POST['activate_'.$var])){
1684               $this->$activate_var  = true;
1685               $this->$var      = $_POST[$var];
1686             }else{
1687               $this->$activate_var  = false;
1688               $this->$var      = 0;
1689             }
1690           }
1691         }
1692       }
1694       /* Restore shadow value, if the shadow attribute isn't used */
1695       if(!in_array("activate_shadowExpire",$this->multi_boxes)){
1696         $this->shadowExpire = $expire_tmp;
1697       }
1699       /* Force change password ? */
1700       if(isset($_POST['mustchangepassword'])){
1701         $this->mustchangepassword = TRUE;
1702       }else{
1703         $this->mustchangepassword = FALSE;
1704       }
1706       /* Trust mode - special handling */
1707       if($this->acl_is_writeable("trustModel")){
1708         if (isset($_POST['trustmode'])){
1709           $saved= $this->trustModel;
1710           if ($_POST['trustmode'] == "1"){
1711             $this->trustModel= "fullaccess";
1712           } elseif ($_POST['trustmode'] == "2"){
1713             $this->trustModel= "byhost";
1714           } else {
1715             $this->trustModel= "";
1716           }
1717           if ($this->trustModel != $saved){
1718             $this->is_modified= TRUE;
1719           }
1720         }
1721       }
1723       /* Save primary group settings */
1724       if($this->acl_is_writeable("primaryGroup") && isset($_POST['primaryGroup'])){
1725         $data= $_POST['primaryGroup'];
1726         if ($this->primaryGroup != $data){
1727           $this->is_modified= TRUE;
1728         }
1729         $this->primaryGroup= $_POST['primaryGroup'];
1730       }
1731     }
1732   }
1734   
1735   /* Initialize plugin with given atribute arrays 
1736    */
1737   function init_multiple_support($attrs,$all)
1738   {
1739     plugin::init_multiple_support($attrs,$all);
1741     /* Some dummy values */
1742     $groups_some = array();
1743     $groups_all  = array();
1744     $groups_uid  = array();
1745     $uids        = array();
1746     $first       = TRUE;
1748     /* Get all groups used by currently edited users */
1749     $uid_filter="";  
1750     for($i =0; $i < $this->multi_attrs_all['uid']['count'] ; $i ++){
1751       $uid = $this->multi_attrs_all['uid'][$i];
1752       $uids[] = $uid;
1753       $uid_filter.= "(memberUid=".$uid.")"; 
1754     }
1755     $uid_filter = "(&(objectClass=posixGroup)(|".$uid_filter."))";
1756     $ldap = $this->config->get_ldap_link();
1757     $ldap->cd($this->config->current['BASE']);
1758     $ldap->search($uid_filter,array("dn","cn","memberUid"));
1759     while($group = $ldap->fetch()){
1760       $groups_some[$group['dn']] = $group['cn'][0];
1761       for($i = 0 ; $i < $group['memberUid']['count'] ; $i++){
1762         $groups_uid[$group['dn']][] = $group['memberUid'][$i];
1763       }
1764     }
1766     /* Create an array, containing all used groups */
1767     $groups_all = $groups_some;
1768     foreach($groups_all as $id => $group){
1769       foreach($uids as $uid){
1770         if(!in_array($uid,$groups_uid[$id])){
1771           unset($groups_all[$id]);
1772           break;
1773         }
1774       }
1775     }
1777     /* Assign group array */
1778     $this->groupMembership = $groups_all;
1780     /* Create an array of all grouops used by all users */
1781     foreach( $groups_all as $dn => $cn){
1782       if(isset($groups_some[$dn])){
1783         unset($groups_some[$dn]);
1784       }
1785     }
1786     $this->groupMembership_some = $groups_some;
1787     $this->primaryGroup = $this->gidNumber;
1789     /* Is this account a trustAccount? */
1790     if (isset($this->multi_attrs['trustModel'])){
1791       $this->trustModel= $this->multi_attrs['trustModel'][0];
1792       $this->was_trust_account= TRUE;
1793       $this->multi_boxes[] = "trustmode";
1794     } else {
1795       $this->was_trust_account= FALSE;
1796       $this->trustModel= "";
1797     }
1799     /* Create access informations */
1800     $this->accessTo = array();
1801     if (isset($this->multi_attrs['accessTo'])){
1802       for ($i= 0; $i<$this->multi_attrs['accessTo']['count']; $i++){
1803         $tmp= $this->multi_attrs['accessTo'][$i];
1804         $this->accessTo[$tmp]= $tmp;
1805       }
1806     }
1808     /* Adjust shadow checkboxes */
1809     foreach (array("shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
1810           "shadowExpire") as $val){
1811       if ($this->$val != 0){
1812         $oval= "activate_".$val;
1813         $this->$oval= "1";
1814       }
1815     }
1817     /* Convert to seconds */
1818     if(isset($this->multi_attrs['shadowExpire'])){
1819       $this->shadowExpire = $this->convertToSeconds($this->multi_attrs['shadowExpire'][0]);
1820     }else{
1821       $this->activate_shadowExpire = FALSE;
1822     }
1823   }
1826   function set_multi_edit_values($attrs)
1827   {
1828     $groups = array();
1830     /* Update groupMembership, keep optinal group */
1831     foreach($attrs['groupMembership_some'] as $dn => $cn){
1832       if(isset($this->groupMembership[$dn])){
1833         $groups[$dn] = $cn;
1834       }
1835     }
1836     /* Update groupMembership, add forced groups */
1837     foreach($attrs['groupMembership'] as $dn => $cn){
1838       $groups[$dn] = $cn;
1839     }
1840     plugin::set_multi_edit_values($attrs);
1841     $this->groupMembership = $groups;
1842   }
1845 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1846 ?>