1 <?php
2 /*!
3 \brief posixAccount plugin
4 \author Cajus Pollmeier <pollmeier@gonicus.de>
5 \version 2.00
6 \date 24.07.2003
8 This class provides the functionality to read and write all attributes
9 relevant for posixAccounts and shadowAccounts from/to the LDAP. It
10 does syntax checking and displays the formulars required.
11 */
13 class posixAccount extends plugin
14 {
15 /* Definitions */
16 var $plHeadline= "UNIX";
17 var $plDescription= "This does something";
19 /* CLI vars */
20 var $cli_summary= "Manage users posix account";
21 var $cli_description= "Some longer text\nfor help";
22 var $cli_parameters= array("eins" => "Eins ist toll", "zwei" => "Zwei ist noch besser");
24 /* Plugin specific values */
25 var $homeDirectory= "";
26 var $loginShell= "/bin/bash";
27 var $uidNumber= "";
28 var $gidNumber= "";
29 var $gecos= "";
30 var $shadowMin= "0";
31 var $shadowMax= "0";
32 var $shadowWarning= "0";
33 var $shadowLastChange= "0";
34 var $shadowInactive= "0";
35 var $shadowExpire= "0";
36 var $gosaDefaultPrinter= "";
37 var $gosaDefaultLanguage= "";
38 var $accessTo= array();
39 var $trustModel= "";
41 var $glist=array();
42 var $status= "";
43 var $loginShellList= array();
44 var $groupMembership= array();
45 var $savedGroupMembership= array();
46 var $savedUidNumber= "";
47 var $savedGidNumber= "";
48 var $use_shadowMin= "0";
49 var $use_shadowMax= "0";
50 var $use_shadowWarning= "0";
51 var $use_shadowInactive= "0";
52 var $use_shadowExpire= "0";
53 var $mustchangepassword= "0";
54 var $force_ids= 0;
55 var $group_dialog= FALSE;
56 var $show_ws_dialog= FALSE;
57 var $secondaryGroups= array();
58 var $primaryGroup= 0;
59 var $was_trust_account= FALSE;
61 var $grouplist = array();
62 var $ui = array();
64 var $GroupRegex = "*";
65 var $GroupUserRegex = "*";
66 var $SubSearch = false;
68 /* attribute list for save action */
69 var $CopyPasteVars =
70 array("grouplist","groupMembership","use_shadowMin",
71 "use_shadowMax","use_shadowWarning","use_shadowInactive","use_shadowExpire",
72 "must_change_password","printerList","grouplist","savedGidNumber","savedUidNumber");
74 var $attributes = array("homeDirectory", "loginShell", "uidNumber", "gidNumber", "gecos",
75 "shadowMin", "shadowMax", "shadowWarning", "shadowInactive", "shadowLastChange",
76 "shadowExpire", "gosaDefaultPrinter", "gosaDefaultLanguage", "uid","accessTo","trustModel");
78 var $objectclasses= array("posixAccount", "shadowAccount");
80 var $uid= "";
82 /* constructor, if 'dn' is set, the node loads the given
83 'dn' from LDAP */
84 function posixAccount ($config, $dn= NULL)
85 {
86 /* Configuration is fine, allways */
87 $this->config= $config;
89 /* Load bases attributes */
90 plugin::plugin($config, $dn);
92 /* Setting uid to default */
93 if(isset($this->attrs['uid'][0])){
94 $this->uid = $this->attrs['uid'][0];
95 }
97 $ldap= $this->config->get_ldap_link();
99 if ($dn != NULL){
101 /* Correct is_account. shadowAccount is not required. */
102 if (isset($this->attrs['objectClass']) &&
103 in_array ('posixAccount', $this->attrs['objectClass'])){
105 $this->is_account= TRUE;
106 }
108 /* Is this account a trustAccount? */
109 if ($this->is_account && isset($this->attrs['trustModel'])){
110 $this->trustModel= $this->attrs['trustModel'][0];
111 $this->was_trust_account= TRUE;
112 } else {
113 $this->was_trust_account= FALSE;
114 $this->trustModel= "";
115 }
117 $this->accessTo = array();
118 if ($this->is_account && isset($this->attrs['accessTo'])){
119 for ($i= 0; $i<$this->attrs['accessTo']['count']; $i++){
120 $tmp= $this->attrs['accessTo'][$i];
121 $this->accessTo[$tmp]= $tmp;
122 }
123 }
124 $this->initially_was_account= $this->is_account;
126 /* Fill group */
127 $this->primaryGroup= $this->gidNumber;
129 /* Generate status text */
130 $current= date("U");
132 $current= floor($current / 60 /60 / 24);
134 if (($current >= $this->shadowExpire) && $this->shadowExpire){
135 $this->status= _("expired");
136 if (($current - $this->shadowExpire) < $this->shadowInactive){
137 $this->status.= ", "._("grace time active");
138 }
139 } elseif (($this->shadowLastChange + $this->shadowMin) >= $current){
140 $this->status= _("active, password not changable");
141 } elseif (($this->shadowLastChange + $this->shadowMax) >= $current){
142 $this->status= _("active, password expired");
143 } else {
144 $this->status= _("active");
145 }
147 /* Get group membership */
148 $ldap->cd($this->config->current['BASE']);
149 $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->uid."))", array("cn", "description"));
151 while ($this->attrs= $ldap->fetch()){
152 if (!isset($this->attrs["description"][0])){
153 $entry= $this->attrs["cn"][0];
154 } else {
155 $dsc= preg_replace ('/^Group of user/', _("Group of user"), $this->attrs["description"][0]);
156 $entry= $this->attrs["cn"][0]." [$dsc]";
157 }
158 $this->groupMembership[$ldap->getDN()]= $entry;
159 }
160 asort($this->groupMembership);
161 reset($this->groupMembership);
162 $this->savedGroupMembership= $this->groupMembership;
163 $this->savedUidNumber= $this->uidNumber;
164 $this->savedGidNumber= $this->gidNumber;
165 }
167 /* Adjust shadow checkboxes */
168 foreach (array("shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
169 "shadowExpire") as $val){
171 if ($this->$val != 0){
172 $oval= "use_".$val;
173 $this->$oval= "1";
174 }
175 }
177 /* Convert to seconds */
178 $this->shadowExpire= $this->convertToSeconds($this->shadowExpire);
180 /* Generate shell list from CONFIG_DIR./shells */
181 if (file_exists(CONFIG_DIR.'/shells')){
182 $shells = file (CONFIG_DIR.'/shells');
183 foreach ($shells as $line){
184 if (!preg_match ("/^#/", $line)){
185 $this->loginShellList[]= trim($line);
186 }
187 }
188 } else {
189 if ($this->loginShell == ""){
190 $this->loginShellList[]= _("unconfigured");
191 }
192 }
194 /* Insert possibly missing loginShell */
195 if ($this->loginShell != "" && !in_array($this->loginShell, $this->loginShellList)){
196 $this->loginShellList[]= $this->loginShell;
197 }
199 /* Generate group list */
200 $this->ui = get_userinfo();
201 $this->secondaryGroups[]= "- "._("automatic")." -";
202 $ldap->cd($this->config->current['BASE']);
203 $ldap->search("(objectClass=posixGroup)", array("cn", "gidNumber"));
204 while($attrs = $ldap->fetch()){
205 $this->secondaryGroups[$attrs['gidNumber'][0]]= $attrs['cn'][0];
206 }
207 asort ($this->secondaryGroups);
209 /* Get global filter config */
210 if (!is_global("sysfilter")){
211 $ui= get_userinfo();
212 $base= get_base_from_people($ui->dn);
213 $sysfilter= array( "depselect" => $base,
214 "regex" => "*");
215 register_global("sysfilter", $sysfilter);
216 }
217 $this->ui = get_userinfo();
218 }
221 /* execute generates the html output for this node */
222 function execute($isCopyPaste = false)
223 {
224 /* Call parent execute */
225 plugin::execute();
226 $display= "";
228 /* Department has changed? */
229 if(isset($_POST['depselect'])){
230 $_SESSION['CurrentMainBase']= validate($_POST['depselect']);
231 }
233 if(!$isCopyPaste){
235 /* Do we need to flip is_account state? */
236 if(isset($_POST['modify_state'])){
237 if($this->is_account && $this->acl_is_removeable()){
238 $this->is_account= FALSE;
239 }elseif(!$this->is_account && $this->acl_is_createable()){
240 $this->is_account= TRUE;
241 }
242 }
244 /* Do we represent a valid posixAccount? */
245 if (!$this->is_account && $this->parent == NULL ){
246 $display= "<img alt=\"\" src=\"images/stop.png\" align=\"middle\"> <b>".
247 _("This account has no unix extensions.")."</b>";
248 $display.= back_to_main();
249 return ($display);
250 }
253 /* Show tab dialog headers */
254 if ($this->parent != NULL){
255 if ($this->is_account){
256 if (isset($this->parent->by_object['sambaAccount'])){
257 $obj= $this->parent->by_object['sambaAccount'];
258 }
259 if (isset($obj) && $obj->is_account == TRUE &&
260 ((isset($this->parent->by_object['sambaAccount']))&&($this->parent->by_object['sambaAccount']->is_account))
261 ||(isset($this->parent->by_object['environment'] ))&&($this->parent->by_object['environment'] ->is_account)){
263 /* Samba3 dependency on posix accounts are enabled
264 in the moment, because I need to rely on unique
265 uidNumbers. There'll be a better solution later
266 on. */
267 $display= $this->show_disable_header(_("Remove posix account"),
268 _("This account has unix features enabled. To disable them, you'll need to remove the samba / environment account first."), TRUE);
269 } else {
270 $display= $this->show_disable_header(_("Remove posix account"),
271 _("This account has posix features enabled. You can disable them by clicking below."));
272 }
273 } else {
274 $display= $this->show_enable_header(_("Create posix account"),
275 _("This account has posix features disabled. You can enable them by clicking below."));
276 return($display);
277 }
278 }
279 }
280 /* Trigger group edit? */
281 if (isset($_POST['edit_groupmembership'])){
282 $this->group_dialog= TRUE;
283 $this->dialog= TRUE;
284 }
286 /* Cancel group edit? */
287 if (isset($_POST['add_groups_cancel']) ||
288 isset($_POST['add_groups_finish'])){
289 $this->group_dialog= FALSE;
290 $this->dialog= FALSE;
291 }
293 /* Add selected groups */
294 if (isset($_POST['add_groups_finish']) && isset($_POST['groups']) &&
295 count($_POST['groups'])){
297 $this->addGroup ($_POST['groups']);
298 }
300 /* Delete selected groups */
301 if (isset($_POST['delete_groupmembership']) &&
302 isset($_POST['group_list']) && count($_POST['group_list'])){
304 $this->delGroup ($_POST['group_list']);
305 }
307 /* Add user workstation? */
308 if (isset($_POST["add_ws"])){
309 $this->show_ws_dialog= TRUE;
310 $this->dialog= TRUE;
311 }
313 /* Add user workstation? */
314 if (isset($_POST["add_ws_finish"]) && isset($_POST['wslist'])){
315 foreach($_POST['wslist'] as $ws){
316 $this->accessTo[$ws]= $ws;
317 }
318 ksort($this->accessTo);
319 $this->is_modified= TRUE;
320 }
322 /* Remove user workstations? */
323 if (isset($_POST["delete_ws"]) && isset($_POST['workstation_list'])){
324 foreach($_POST['workstation_list'] as $name){
325 unset ($this->accessTo[$name]);
326 }
327 $this->is_modified= TRUE;
328 }
330 /* Add user workstation finished? */
331 if (isset($_POST["add_ws_finish"]) || isset($_POST["add_ws_cancel"])){
332 $this->show_ws_dialog= FALSE;
333 $this->dialog= FALSE;
334 }
336 /* Templates now! */
337 $smarty= get_smarty();
339 /* Show ws dialog */
340 if ($this->show_ws_dialog){
341 /* Save data */
342 $sysfilter= get_global("sysfilter");
343 foreach( array("depselect", "regex") as $type){
344 if (isset($_POST[$type])){
345 $sysfilter[$type]= $_POST[$type];
346 }
347 }
348 if (isset($_GET['search'])){
349 $s= mb_substr($_GET['search'], 0, 1, "UTF8")."*";
350 if ($s == "**"){
351 $s= "*";
352 }
353 $sysfilter['regex']= $s;
354 }
355 register_global("sysfilter", $sysfilter);
357 /* Get workstation list */
358 $exclude= "";
359 foreach($this->accessTo as $ws){
360 $exclude.= "(cn=$ws)";
361 }
362 if ($exclude != ""){
363 $exclude= "(!(|$exclude))";
364 }
365 $regex= $sysfilter['regex'];
366 $filter= "(&(|(objectClass=goServer)(objectClass=gotoWorkstation)(objectClass=gotoTerminal))$exclude(cn=*)(cn=$regex))";
367 $res= get_list($filter, "groups", $sysfilter['depselect'], array("cn"), GL_SUBSEARCH | GL_SIZELIMIT);
368 $wslist= array();
369 foreach ($res as $attrs){
370 $wslist[]= preg_replace('/\$/', '', $attrs['cn'][0]);
371 }
372 asort($wslist);
373 $smarty->assign("search_image", get_template_path('images/search.png'));
374 $smarty->assign("launchimage", get_template_path('images/small_filter.png'));
375 $smarty->assign("tree_image", get_template_path('images/tree.png'));
376 $smarty->assign("deplist", $this->config->idepartments);
377 $smarty->assign("alphabet", generate_alphabet());
378 foreach( array("depselect", "regex") as $type){
379 $smarty->assign("$type", $sysfilter[$type]);
380 }
381 $smarty->assign("hint", print_sizelimit_warning());
382 $smarty->assign("wslist", $wslist);
383 $smarty->assign("apply", apply_filter());
384 $display= $smarty->fetch (get_template_path('trust_machines.tpl', TRUE, dirname(__FILE__)));
385 return ($display);
386 }
388 /* Manage group add dialog */
389 if ($this->group_dialog){
391 /* Get global filter config */
392 $this->reload();
394 /* remove already assigned groups */
395 $glist= array();
396 foreach ($this->grouplist as $key => $value){
397 if (!isset($this->groupMembership[$key]) && obj_is_writable($key,"groups/group","memberUid")){
398 $glist[$key]= $value;
399 }
400 }
402 if($this->SubSearch){
403 $smarty->assign("SubSearchCHK"," checked ");
404 }else{
405 $smarty->assign("SubSearchCHK","");
406 }
408 $smarty->assign("regex",$this->GroupRegex);
409 $smarty->assign("guser",$this->GroupUserRegex);
410 $smarty->assign("groups", $glist);
411 $smarty->assign("search_image", get_template_path('images/search.png'));
412 $smarty->assign("launchimage", get_template_path('images/small_filter.png'));
413 $smarty->assign("tree_image", get_template_path('images/tree.png'));
414 $smarty->assign("deplist", $this->config->idepartments);
415 $smarty->assign("alphabet", generate_alphabet());
416 $smarty->assign("depselect",$_SESSION['CurrentMainBase']);
417 $smarty->assign("hint", print_sizelimit_warning());
419 $smarty->assign("apply", apply_filter());
420 $display.= $smarty->fetch (get_template_path('posix_groups.tpl', TRUE, dirname(__FILE__)));
421 return ($display);
422 }
424 /* Show main page */
425 $smarty= get_smarty();
427 /* In 'MyAccount' mode, we must remove write acls if we are not in editing mode. */
428 $SkipWrite = (!isset($this->parent) || !$this->parent) && !isset($_SESSION['edit']);
430 /* Depending on pwmode, currently hardcoded because there are no other methods */
431 if ( 1 == 1 ){
432 $smarty->assign("pwmode", dirname(__FILE__)."/posix_shadow");
434 $shadowMinACL = $this->getacl("shadowMin",$SkipWrite);
435 $smarty->assign("shadowmins", sprintf(_("Password can't be changed up to %s days after last change"),
436 "<input name=\"shadowMin\" size=3 maxlength=4 value=\"".$this->shadowMin."\">"));
438 $shadowMaxACL = $this->getacl("shadowMax",$SkipWrite);
439 $smarty->assign("shadowmaxs", sprintf(_("Password must be changed after %s days"),
440 "<input name=\"shadowMax\" size=3 maxlength=4 value=\"".$this->shadowMax."\">"));
442 $shadowInactiveACL= $this->getacl("shadowInactive",$SkipWrite);
443 $smarty->assign("shadowinactives", sprintf(_("Disable account after %s days of inactivity after password expiery"),
444 "<input name=\"shadowInactive\" size=3 maxlength=4 value=\"".$this->shadowInactive."\">"));
446 $shadowWarningACL = $this->getacl("shadowWarning",$SkipWrite);
447 $smarty->assign("shadowwarnings", sprintf(_("Warn user %s days before password expiery"),
448 "<input name=\"shadowWarning\" size=3 maxlength=4 value=\"".$this->shadowWarning."\">"));
450 foreach( array("use_shadowMin", "use_shadowMax",
451 "use_shadowExpire", "use_shadowInactive","use_shadowWarning") as $val){
452 if ($this->$val == 1){
453 $smarty->assign("$val", "checked");
454 } else {
455 $smarty->assign("$val", "");
456 }
457 $smarty->assign("$val"."ACL", $this->getacl($val,$SkipWrite));
458 }
460 if($this->mustchangepassword){
461 $smarty->assign("mustchangepassword", "checked");
462 } else {
463 $smarty->assign("mustchangepassword", "");
464 }
465 $smarty->assign("mustchangepasswordACL", $this->getacl("mustchangepassword",$SkipWrite));
466 }
468 /* Fill calendar */
469 /* If this $this->shadowExpire is empty
470 use current date as base for calculating selectbox values.
471 (This attribute is empty if this is a new user )*/
472 if(empty($this->shadowExpire)){
473 $date= getdate(time());
474 }else{
475 $date= getdate($this->shadowExpire);
476 }
478 $days= array();
479 for($d= 1; $d<32; $d++){
480 $days[$d]= $d;
481 }
482 $years= array();
483 for($y= $date['year']-10; $y<$date['year']+10; $y++){
484 $years[]= $y;
485 }
486 $months= array(_("January"), _("February"), _("March"), _("April"),
487 _("May"), _("June"), _("July"), _("August"), _("September"),
488 _("October"), _("November"), _("December"));
489 $smarty->assign("day", $date["mday"]);
490 $smarty->assign("days", $days);
491 $smarty->assign("months", $months);
492 $smarty->assign("month", $date["mon"]-1);
493 $smarty->assign("years", $years);
494 $smarty->assign("year", $date["year"]);
496 /* Fill arrays */
497 $smarty->assign("shells", $this->loginShellList);
498 $smarty->assign("secondaryGroups", $this->secondaryGroups);
499 $smarty->assign("primaryGroup", $this->primaryGroup);
500 if (!count($this->groupMembership)){
501 $smarty->assign("groupMembership", array(" "));
502 } else {
503 $smarty->assign("groupMembership", $this->groupMembership);
504 }
505 if (count($this->groupMembership) > 16){
506 $smarty->assign("groups", "too_many_for_nfs");
507 } else {
508 $smarty->assign("groups", "");
509 }
510 $smarty->assign("languages", $this->config->data['MAIN']['LANGUAGES']);
512 /* Avoid "Undefined index: forceMode" */
513 $smarty->assign("forceMode", "");
515 /* Checkboxes */
516 if ($this->force_ids == 1){
517 $smarty->assign("force_ids", "checked");
518 if ($_SESSION['js']){
519 $smarty->assign("forceMode", "");
520 }
521 } else {
522 if ($_SESSION['js']){
523 $smarty->assign("forceMode", "disabled");
524 }
525 $smarty->assign("force_ids", "");
526 }
530 $smarty->assign("force_idsACL", $this->getacl("uidNumber",$SkipWrite).$this->getacl("gidNumber",$SkipWrite));
532 /* Load attributes and acl's */
533 foreach($this->attributes as $val){
534 if(($_SESSION["js"])&&(($val=="uidNumber")||($val=="gidNumber")))
535 {
536 $smarty->assign("$val"."ACL",$this->getacl($val,$SkipWrite));
537 $smarty->assign("$val", $this->$val);
538 continue;
539 }
540 $smarty->assign("$val", $this->$val);
541 $smarty->assign("$val"."ACL", $this->getacl($val,$SkipWrite));
542 }
543 if($SkipWrite){
544 $smarty->assign("groupMembershipACL","r");
545 }else{
546 $smarty->assign("groupMembershipACL","rw");
547 }
548 $smarty->assign("status", $this->status);
550 /* Work on trust modes */
551 $smarty->assign("trusthide", " disabled ");
552 $smarty->assign("trustmodeACL", $this->getacl("trustModel",$SkipWrite));
553 if ($this->trustModel == "fullaccess"){
554 $trustmode= 1;
555 // pervent double disable tag in html code, this will disturb our clean w3c html
556 $smarty->assign("trustmode", $this->getacl("trustModel",$SkipWrite));
558 } elseif ($this->trustModel == "byhost"){
559 $trustmode= 2;
560 $smarty->assign("trusthide", "");
561 } else {
562 // pervent double disable tag in html code, this will disturb our clean w3c html
563 $smarty->assign("trustmode", $this->getacl("trustModel",$SkipWrite));
564 $trustmode= 0;
565 }
566 $smarty->assign("trustmode", $trustmode);
567 $smarty->assign("trustmodes", array( 0 => _("disabled"), 1 => _("full access"),
568 2 => _("allow access to these hosts")));
572 if((count($this->accessTo))==0)
573 $smarty->assign("emptyArrAccess",true);
574 else
575 $smarty->assign("emptyArrAccess",false);
579 $smarty->assign("workstations", $this->accessTo);
581 $smarty->assign("apply", apply_filter());
582 $display.= $smarty->fetch (get_template_path('generic.tpl', TRUE, dirname(__FILE__)));
583 return($display);
584 }
587 /* remove object from parent */
588 function remove_from_parent()
589 {
590 /* Cancel if there's nothing to do here */
591 if ((!$this->initially_was_account) || (!$this->acl_is_removeable())){
592 return;
593 }
595 /* include global link_info */
596 $ldap= $this->config->get_ldap_link();
598 /* Remove and write to LDAP */
599 plugin::remove_from_parent();
601 /* Zero out array */
602 $this->attrs['gosaHostACL']= array();
604 /* Keep uid, because we need it for authentification! */
605 unset($this->attrs['uid']);
606 unset($this->attrs['trustModel']);
608 @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__,
609 $this->attributes, "Save");
610 $ldap->cd($this->dn);
611 $this->cleanup();
612 $ldap->modify ($this->attrs);
614 show_ldap_error($ldap->get_error(), sprintf(_("Removing of user/posix account with dn '%s' failed."),$this->dn));
616 /* Delete group only if cn is uid and there are no other
617 members inside */
618 $ldap->cd ($this->config->current['BASE']);
619 $ldap->search ("(&(objectClass=posixGroup)(gidNumber=".$this->gidNumber."))", array("cn", "memberUid"));
620 if ($ldap->count() != 0){
621 $attrs= $ldap->fetch();
622 if ($attrs['cn'][0] == $this->uid &&
623 !isset($this->attrs['memberUid'])){
625 $ldap->rmDir($ldap->getDN());
626 }
627 }
629 /* Optionally execute a command after we're done */
630 $this->handle_post_events("remove",array("uid" => $this->uid));
631 }
634 function save_object()
635 {
636 if (isset($_POST['posixTab'])){
637 /* Save values to object */
638 plugin::save_object();
641 /* Save force GID checkbox */
642 if($this->acl_is_writeable("gidNumber") || $this->acl_is_writeable("uidNumber")){
643 if (isset ($_POST['force_ids'])){
644 $data= 1;
645 } else {
646 $data= 0;
647 }
648 if ($this->force_ids != $data){
649 $this->is_modified= TRUE;
650 }
651 $this->force_ids= $data;
652 }
654 /*Save primary group settings */
655 if($this->acl_is_writeable("primaryGroup") && isset($_POST['primaryGroup'])){
656 $data= $_POST['primaryGroup'];
657 if ($this->primaryGroup != $data){
658 $this->is_modified= TRUE;
659 }
660 $this->primaryGroup= $_POST['primaryGroup'];
661 }
663 foreach(array("shadowMin","shadowMax","shadowExpire","shadowInactive","shadowWarning","mustchangepassword") as $var) {
664 if($this->acl_is_writeable($var)){
665 $use_var = "use_".$var;
666 if(isset($_POST['use_'.$var])){
667 $this->$use_var = true;
668 $this->$var = $_POST[$var];
669 }else{
670 $this->$use_var = false;
671 $this->$var = 0;
672 }
673 }
674 }
676 /* Trust mode - special handling */
677 if($this->acl_is_writeable("trustModel")){
678 if (isset($_POST['trustmode'])){
679 $saved= $this->trustModel;
680 if ($_POST['trustmode'] == "1"){
681 $this->trustModel= "fullaccess";
682 } elseif ($_POST['trustmode'] == "2"){
683 $this->trustModel= "byhost";
684 } else {
685 $this->trustModel= "";
686 }
687 if ($this->trustModel != $saved){
688 $this->is_modified= TRUE;
689 }
690 }
691 }
692 }
694 /* Get regex from alphabet */
695 if(isset($_GET['search'])){
696 $this->GroupRegex = $_GET['search']."*";
697 }
699 /* Check checkboxes and regexes */
700 if(isset($_POST["PosixGroupDialogPosted"])){
702 if(isset($_POST['SubSearch']) && ($_POST['SubSearch'])){
703 $this->SubSearch = true;
704 }else{
705 $this->SubSearch = false;
706 }
707 if(isset($_POST['guser'])){
708 $this->GroupUserRegex = $_POST['guser'];
709 }
710 if(isset($_POST['regex'])){
711 $this->GroupRegex = $_POST['regex'];
712 }
713 }
714 $this->GroupRegex = preg_replace("/\*\**/","*",$this->GroupRegex);
715 $this->GroupUserRegex = preg_replace("/\*\**/","*",$this->GroupUserRegex);
716 }
719 /* Save data to LDAP, depending on is_account we save or delete */
720 function save()
721 {
723 /* include global link_info */
724 $ldap= $this->config->get_ldap_link();
726 /* Adapt shadow values */
727 if (!$this->use_shadowExpire){
728 $this->shadowExpire= "0";
729 } else {
730 /* Transform seconds to days here */
731 $this->shadowExpire= (int)($this->shadowExpire / (60 * 60 * 24)) ;
732 }
733 if (!$this->use_shadowMax){
734 $this->shadowMax= "0";
735 }
736 if ($this->mustchangepassword){
737 $this->shadowLastChange= (int)(date("U") / 86400) - $this->shadowMax - 1;
738 } else {
739 $this->shadowLastChange= (int)(date("U") / 86400);
740 }
741 if (!$this->use_shadowWarning){
742 $this->shadowWarning= "0";
743 }
745 /* Check what to do with ID's */
746 if ($this->force_ids == 0){
748 /* Use id's that are already set */
749 if ($this->savedUidNumber != ""){
750 $this->uidNumber= $this->savedUidNumber;
751 $this->gidNumber= $this->savedGidNumber;
752 } else {
754 /* Calculate new id's. We need to place a lock before calling get_next_id
755 to get real unique values. */
756 $wait= 10;
757 while (get_lock("uidnumber") != ""){
758 sleep (1);
760 /* Oups - timed out */
761 if ($wait-- == 0){
762 print_red (_("Failed: overriding lock"));
763 break;
764 }
765 }
767 add_lock ("uidnumber", "gosa");
768 $this->uidNumber= $this->get_next_id("uidNumber");
769 if ($this->savedGidNumber != ""){
770 $this->gidNumber= $this->savedGidNumber;
771 } else {
772 $this->gidNumber= $this->get_next_id("gidNumber");
773 }
774 }
776 if ($this->primaryGroup != 0){
777 $this->gidNumber= $this->primaryGroup;
778 }
779 }
781 if ($this->use_shadowMin != "1" ) {
782 $this->shadowMin = "";
783 }
785 if (($this->use_shadowMax != "1") && ($this->mustchangepassword != "1")) {
786 $this->shadowMax = "";
787 }
789 if ($this->use_shadowWarning != "1" ) {
790 $this->shadowWarning = "";
791 }
793 if ($this->use_shadowInactive != "1" ) {
794 $this->shadowInactive = "";
795 }
797 if ($this->use_shadowExpire != "1" ) {
798 $this->shadowExpire = "";
799 }
801 /* Fill gecos */
802 if (isset($this->parent) && $this->parent != NULL){
803 $this->gecos= rewrite($this->parent->by_object['user']->cn);
804 if (!preg_match('/^[a-z0-9 -]+$/i', $this->gecos)){
805 $this->gecos= "";
806 }
807 }
809 foreach(array("shadowMin","shadowMax","shadowWarning","shadowInactive","shadowExpire") as $attr){
810 $this->$attr = (int) $this->$attr;
811 }
812 /* Call parents save to prepare $this->attrs */
813 plugin::save();
815 /* Trust accounts */
816 $objectclasses= array();
817 foreach ($this->attrs['objectClass'] as $key => $class){
818 if (preg_match('/trustAccount/i', $class)){
819 continue;
820 }
821 $objectclasses[]= $this->attrs['objectClass'][$key];
822 }
823 $this->attrs['objectClass']= $objectclasses;
824 if ($this->trustModel != ""){
825 $this->attrs['objectClass'][]= "trustAccount";
826 $this->attrs['trustModel']= $this->trustModel;
827 $this->attrs['accessTo']= array();
828 if ($this->trustModel == "byhost"){
829 foreach ($this->accessTo as $host){
830 $this->attrs['accessTo'][]= $host;
831 }
832 }
833 } else {
834 if ($this->was_trust_account){
835 $this->attrs['accessTo']= array();
836 $this->attrs['trustModel']= array();
837 }
838 }
840 if(empty($this->attrs['gosaDefaultPrinter'])){
841 $thid->attrs['gosaDefaultPrinter']=array();
842 }
845 /* Save data to LDAP */
846 $ldap->cd($this->dn);
847 $this->cleanup();
848 unset($this->attrs['uid']);
849 $ldap->modify ($this->attrs);
851 show_ldap_error($ldap->get_error(), sprintf(_("Saving of user/posix account with dn '%s' failed."),$this->dn));
853 /* Remove lock needed for unique id generation */
854 del_lock ("uidnumber");
856 /* Posix accounts have group interrelationship,
857 take care about these here if this is a new user without forced gidNumber. */
858 if ($this->force_ids == 0 && $this->primaryGroup == 0 && !$this->initially_was_account){
859 $ldap->cd($this->config->current['BASE']);
860 $ldap->search("(&(objectClass=posixGroup)(gidNumber=".$this->gidNumber."))", array("cn"));
862 /* Create group if it doesn't exist */
863 if ($ldap->count() == 0){
864 $groupdn= preg_replace ('/^'.$this->config->current['DNMODE'].'=[^,]+,'.get_people_ou().'/i', 'cn='.$this->uid.','.get_groups_ou(), $this->dn);
866 $g= new group($this->config, $groupdn);
867 $g->cn= $this->uid;
868 $g->force_gid= 1;
869 $g->gidNumber= $this->gidNumber;
870 $g->description= "Group of user ".$this->givenName." ".$this->sn;
871 $g->save ();
872 }
873 }
875 /* Take care about groupMembership values: add to groups */
876 foreach ($this->groupMembership as $key => $value){
877 if (!isset($this->savedGroupMembership[$key])){
878 $g= new grouptabs($this->config,$this->config->data['TABS']['GROUPTABS'], $key,"groups");
879 $g->set_acl_base($key);
880 $g->by_object['group']->addUser($this->uid);
881 $g->save();
882 }
883 }
885 /* Remove from groups not listed in groupMembership */
886 foreach ($this->savedGroupMembership as $key => $value){
887 if (!isset($this->groupMembership[$key])){
888 $g= new grouptabs($this->config,$this->config->data['TABS']['GROUPTABS'], $key,"groups");
889 $g->set_acl_base($key);
890 $g->by_object['group']->removeUser ($this->uid);
891 $g->save();
892 }
893 }
895 /* Optionally execute a command after we're done */
896 if ($this->initially_was_account == $this->is_account){
897 if ($this->is_modified){
898 $this->handle_post_events("modify",array("uid" => $this->uid));
899 }
900 } else {
901 $this->handle_post_events("add" ,array("uid"=> $this->uid));
902 }
903 }
905 /* Check formular input */
906 function check()
907 {
908 /* Include global link_info */
909 $ldap= $this->config->get_ldap_link();
911 /* Call common method to give check the hook */
912 $message= plugin::check();
914 /* must: homeDirectory */
915 if ($this->homeDirectory == ""){
916 $message[]= _("The required field 'Home directory' is not set.");
917 }
918 if (!is_path($this->homeDirectory)){
919 $message[]= _("Please enter a valid path in 'Home directory' field.");
920 }
922 /* Check ID's if they are forced by user */
923 if ($this->force_ids == "1"){
925 /* Valid uid/gid? */
926 if (!is_id($this->uidNumber)){
927 $message[]= _("Value specified as 'UID' is not valid.");
928 } else {
929 if ($this->uidNumber < $this->config->current['MINID']){
930 $message[]= _("Value specified as 'UID' is too small.");
931 }
932 }
933 if (!is_id($this->gidNumber)){
934 $message[]= _("Value specified as 'GID' is not valid.");
935 } else {
936 if ($this->gidNumber < $this->config->current['MINID']){
937 $message[]= _("Value specified as 'GID' is too small.");
938 }
939 }
940 }
942 /* Check shadow settings, well I like spaghetties... */
943 if ($this->use_shadowMin){
944 if (!is_id($this->shadowMin)){
945 $message[]= _("Value specified as 'shadowMin' is not valid.");
946 }
947 }
948 if ($this->use_shadowMax){
949 if (!is_id($this->shadowMax)){
950 $message[]= _("Value specified as 'shadowMax' is not valid.");
951 }
952 }
953 if ($this->use_shadowWarning){
954 if (!is_id($this->shadowWarning)){
955 $message[]= _("Value specified as 'shadowWarning' is not valid.");
956 }
957 if (!$this->use_shadowMax){
958 $message[]= _("'shadowWarning' without 'shadowMax' makes no sense.");
959 }
960 if ($this->shadowWarning > $this->shadowMax){
961 $message[]= _("Value specified as 'shadowWarning' should be smaller than 'shadowMax'.");
962 }
963 if ($this->use_shadowMin && $this->shadowWarning < $this->shadowMin){
964 $message[]= _("Value specified as 'shadowWarning' should be greater than 'shadowMin'.");
965 }
966 }
967 if ($this->use_shadowInactive){
968 if (!is_id($this->shadowInactive)){
969 $message[]= _("Value specified as 'shadowInactive' is not valid.");
970 }
971 if (!$this->use_shadowMax){
972 $message[]= _("'shadowInactive' without 'shadowMax' makes no sense.");
973 }
974 }
975 if ($this->use_shadowMin && $this->use_shadowMax){
976 if ($this->shadowMin > $this->shadowMax){
977 $message[]= _("Value specified as 'shadowMin' should be smaller than 'shadowMax'.");
978 }
979 }
981 // if(empty($this->gosaDefaultPrinter)){
982 // $message[]= _("You need to specify a valid default printer.");
983 // }
985 return ($message);
986 }
988 function addGroup ($groups)
989 {
990 /* include global link_info */
991 $ldap= $this->config->get_ldap_link();
993 /* Walk through groups and add the descriptive entry if not exists */
994 foreach ($groups as $value){
995 if (!array_key_exists($value, $this->groupMembership)){
996 $ldap->cat($value, array('cn', 'description', 'dn'));
997 $attrs= $ldap->fetch();
998 error_reporting (0);
999 if (!isset($attrs['description'][0])){
1000 $entry= $attrs["cn"][0];
1001 } else {
1002 $dsc= preg_replace ('/^Group of user/', _("Group of user"), $attrs["description"][0]);
1003 $entry= $attrs["cn"][0]." [$dsc]";
1004 }
1005 error_reporting (E_ALL);
1007 if(obj_is_writable($attrs['dn'],"groups/group","memberUid")){
1008 $this->groupMembership[$attrs['dn']]= $entry;
1009 }
1010 }
1011 }
1013 /* Sort groups */
1014 asort ($this->groupMembership);
1015 reset ($this->groupMembership);
1016 }
1019 /* Del posix user from some groups */
1020 function delGroup ($groups)
1021 {
1022 $dest= array();
1024 foreach ($this->groupMembership as $key => $value){
1025 if ((!in_array($key, $groups)) || (obj_is_writable($attrs['dn'],"groups/group","memberUid"))){
1026 $dest[$key]= $value;
1027 }
1028 }
1029 $this->groupMembership= $dest;
1030 }
1032 /* Adapt from template, using 'dn' */
1033 function adapt_from_template($dn)
1034 {
1035 /* Include global link_info */
1036 $ldap= $this->config->get_ldap_link();
1038 plugin::adapt_from_template($dn);
1039 $template= $this->attrs['uid'][0];
1041 /* Adapt group membership */
1042 $ldap->cd($this->config->current['BASE']);
1043 $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->attrs["uid"][0]."))", array("description", "cn"));
1045 while ($this->attrs= $ldap->fetch()){
1046 if (!isset($this->attrs["description"][0])){
1047 $entry= $this->attrs["cn"][0];
1048 } else {
1049 $entry= $this->attrs["cn"][0]." [".$this->attrs["description"][0]."]";
1050 }
1051 $this->groupMembership[$ldap->getDN()]= $entry;
1052 }
1054 /* Fix primary group settings */
1055 $ldap->cd($this->config->current['BASE']);
1056 $ldap->search("(&(objectClass=posixGroup)(cn=$template)(gidNumber=".$this->gidNumber."))", array("cn"));
1057 if ($ldap->count() != 1){
1058 $this->primaryGroup= $this->gidNumber;
1059 }
1061 $ldap->cd($this->config->current['BASE']);
1062 $ldap->search("(&(objectClass=gosaUserTemplate)(uid=".$template.")(accessTo=*))", array("cn","accessTo"));
1063 while($attr = $ldap->fetch()){
1064 $tmp = $attr['accessTo'];
1065 unset ($tmp['count']);
1066 $this->accessTo = $tmp;
1067 }
1069 /* Adjust shadow checkboxes */
1070 foreach (array("shadowMin", "shadowMax", "shadowWarning", "shadowInactive") as $val){
1071 if ($this->$val != 0){
1072 $oval= "use_".$val;
1073 $this->$oval= "1";
1074 }
1075 }
1077 /* FIXME: NEED review of this section */
1078 /* Need to check shadowExpire separately */
1080 /*
1081 * If shadowExpire is not enabled in the template, it's a UNIX timestamp - so don't convert it to seconds.
1082 * The check is a hack - if difference between timestamp generated above and here is max 1 day.
1083 */
1084 if(abs($this->shadowExpire - time())>86400) {
1085 $this->shadowExpire= $this->convertToSeconds($this->shadowExpire);
1086 }
1088 /* Only enable checkbox, if shadowExpire is in the future */
1089 if($this->shadowExpire > time()) {
1090 $this->use_shadowExpire= "1";
1091 }
1092 }
1095 function convertToSeconds($val)
1096 {
1097 if ($val != 0){
1098 $val*= 60 * 60 * 24;
1099 } else {
1100 $date= getdate();
1101 $val= floor($date[0] / (60*60*24)) * 60 * 60 * 24;
1102 }
1103 return($val);
1104 }
1107 function get_next_id($attrib)
1108 {
1109 $ids= array();
1110 $ldap= $this->config->get_ldap_link();
1112 $ldap->cd ($this->config->current['BASE']);
1113 if (preg_match('/gidNumber/i', $attrib)){
1114 $oc= "posixGroup";
1115 } else {
1116 $oc= "posixAccount";
1117 }
1118 $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib"));
1120 /* Get list of ids */
1121 while ($attrs= $ldap->fetch()){
1122 $ids[]= (int)$attrs["$attrib"][0];
1123 }
1125 /* Add the nobody id */
1126 $ids[]= 65534;
1128 /* get the ranges */
1129 $tmp = array('0'=> 1000);
1130 if (preg_match('/posixAccount/', $oc) && isset($this->config->current['UIDBASE'])) {
1131 $tmp= split('-',$this->config->current['UIDBASE']);
1132 } elseif(isset($this->config->current['UIDBASE'])) {
1133 $tmp= split('-',$this->config->current['GIDBASE']);
1134 }
1136 /* Set hwm to max if not set - for backward compatibility */
1137 $lwm= $tmp[0];
1138 if (isset($tmp[1])){
1139 $hwm= $tmp[1];
1140 } else {
1141 $hwm= pow(2,32);
1142 }
1144 /* Find out next free id near to UID_BASE */
1145 for ($id=$lwm; $id++; $id<$hwm){
1146 if (!in_array($id, $ids)){
1147 return ($id);
1148 }
1149 }
1151 /* Should not happen */
1152 if ($id == $hwm){
1153 print_red(_("Too many users, can't allocate a free ID!"));
1154 exit;
1155 }
1157 }
1159 function reload()
1160 {
1161 /* Set base for all searches */
1162 $base = $_SESSION['CurrentMainBase'];
1163 $base = $base;
1164 $ldap = $this->config->get_ldap_link();
1165 $attrs = array("cn", "description", "gidNumber");
1166 $Flags = GL_SIZELIMIT;
1168 /* Get groups */
1169 if ($this->GroupUserRegex == '*'){
1170 $filter = "(&(objectClass=posixGroup)(cn=".$this->GroupRegex."))";
1171 } else {
1172 $filter= "(&(objectClass=posixGroup)(cn=".$this->GroupRegex.")(memberUid=".$this->GroupUserRegex."))";
1173 }
1174 if($this->SubSearch){
1175 $Flags |= GL_SUBSEARCH;
1176 }else{
1177 $base = get_groups_ou().$base;
1178 }
1180 $res= get_list($filter, "groups", $base,$attrs, $Flags);
1182 /* check sizelimit */
1183 if (preg_match("/size limit/i", $ldap->error)){
1184 $_SESSION['limit_exceeded']= TRUE;
1185 }
1187 /* Create a list of users */
1188 $this->grouplist = array();
1189 foreach ($res as $value){
1190 $this->grouplist[$value['gidNumber'][0]]= $value;
1191 }
1193 $tmp=array();
1194 foreach($this->grouplist as $tkey => $val ){
1195 $tmp[strtolower($val['cn'][0]).$val['cn'][0]]=$val;
1196 }
1198 /* Sort index */
1199 ksort($tmp);
1201 /* Recreate index array[dn]=cn[description]*/
1202 $this->grouplist=array();
1203 foreach($tmp as $val){
1204 if(isset($val['description'])){
1205 $this->grouplist[$val['dn']]=$val['cn'][0]." [".$val['description'][0]."]";
1206 }else{
1207 $this->grouplist[$val['dn']]=$val['cn'][0];
1208 }
1209 }
1211 reset ($this->grouplist);
1212 }
1215 /* Get posts from copy & paste dialog */
1216 function saveCopyDialog()
1217 {
1218 if(isset($_POST['homeDirectory'])){
1219 $this->homeDirectory = $_POST['homeDirectory'];
1220 if (isset ($_POST['force_ids'])){
1221 $data= 1;
1222 $this->gidNumber = $_POST['gidNumber'];
1223 $this->uidNumber = $_POST['uidNumber'];
1224 } else {
1225 $data= 0;
1226 }
1227 if ($this->force_ids != $data){
1228 $this->is_modified= TRUE;
1229 }
1230 $this->force_ids= $data;
1231 }
1232 }
1235 /* Create the posix dialog part for copy & paste */
1236 function getCopyDialog()
1237 {
1238 /* Skip dialog creation if this is not a valid account*/
1239 if(!$this->is_account) return("");
1240 if ($this->force_ids == 1){
1241 $force_ids = "checked";
1242 if ($_SESSION['js']){
1243 $forceMode = "";
1244 }
1245 } else {
1246 if ($_SESSION['js']){
1247 if($this->acl != "#none#")
1248 $forceMode ="disabled";
1249 }
1250 $force_ids = "";
1251 }
1253 $sta = "";
1255 /* Open group add dialog */
1256 if(isset($_POST['edit_groupmembership'])){
1257 $this->group_dialog = TRUE;
1258 $sta = "SubDialog";
1259 }
1261 /* If the group-add dialog is closed, call execute
1262 to ensure that the membership is updatd */
1263 if(isset($_POST['add_groups_finish']) || isset($_POST['add_groups_cancel'])){
1264 $this->execute();
1265 $this->group_dialog =FALSE;
1266 }
1268 if($this->group_dialog){
1269 $str = $this->execute(true);
1270 $ret = array();
1271 $ret['string'] = $str;
1272 $ret['status'] = $sta;
1273 return($ret);
1274 }
1276 /* If a group member should be deleted, simply call execute */
1277 if(isset($_POST['delete_groupmembership'])){
1278 $this->execute();
1279 }
1281 /* Assigned informations to smarty */
1282 $smarty = get_smarty();
1283 $smarty->assign("homeDirectory",$this->homeDirectory);
1284 $smarty->assign("uidNumber",$this->uidNumber);
1285 $smarty->assign("gidNumber",$this->gidNumber);
1286 $smarty->assign("forceMode",$forceMode);
1287 $smarty->assign("force_ids",$force_ids);
1288 if (!count($this->groupMembership)){
1289 $smarty->assign("groupMembership", array(" "));
1290 } else {
1291 $smarty->assign("groupMembership", $this->groupMembership);
1292 }
1294 /* Display wars message if there are more than 16 group members */
1295 if (count($this->groupMembership) > 16){
1296 $smarty->assign("groups", "too_many_for_nfs");
1297 } else {
1298 $smarty->assign("groups", "");
1299 }
1300 $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE,dirname(__FILE__)));
1302 $ret = array();
1303 $ret['string'] = $str;
1304 $ret['status'] = $sta;
1305 return($ret);
1306 }
1309 function PrepareForCopyPaste($source)
1310 {
1311 plugin::PrepareForCopyPaste($source);
1313 /* Avoid using the same gid/uid number as source user */
1314 $this->savedUidNumber = $this->get_next_id("gidNumber");
1315 $this->savedGidNumber = $this->get_next_id("uidNumber");
1316 }
1319 function plInfo()
1320 {
1321 return (array(
1322 "plDescription" => _("POSIX account"),
1323 "plSelfModify" => TRUE,
1324 "plDepends" => array("user"),
1325 "plPriority" => 2,
1326 "plSection" => array("personal" => _("My account")),
1327 "plCategory" => array("users"),
1328 "plOptions" => array(),
1330 "plProvidedAcls" => array(
1332 "homeDirectory" => _("Home directory"),
1333 "loginShell" => _("Shell"),
1334 "uidNumber" => _("User ID"),
1335 "gidNumber" => _("Group ID"),
1337 "mustchangepassword"=> _("Force password change on login"),
1338 "shadowMin" => _("Shadow min"),
1339 "shadowMax" => _("Shadow max"),
1340 "shadowWarning" => _("Shadow warning"),
1341 "shadowInactive" => _("Shadow inactive"),
1342 "shadowExpire" => _("Shadow expire"),
1343 "trustModel" => _("System trust model")))
1344 );
1345 }
1346 }
1348 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1349 ?>