e53fd53227766e6668931c7c6a56fb8229d08dd1
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: class_sudo.inc 9975 2008-03-25 14:09:30Z hickert $$
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 */
24 /*! \brief Sudo generic class. Allow setting User/Host/Command/Runas
25 for a sudo role object.
26 */
27 class sudo extends plugin
28 {
30 protected $cn= "";
31 protected $description= "";
33 protected $sudoUser = array("ALL");
34 protected $sudoCommand= array();
35 protected $sudoHost = array("ALL");
36 protected $sudoRunAs = array("ALL");
37 protected $accessTo = array();
38 protected $trustModel = "";
40 private $is_default = FALSE;
41 private $was_trust_account= FALSE;
43 public $objectclasses = array("top","sudoRole");
44 public $attributes = array("cn","description","sudoUser","sudoCommand","sudoHost","sudoRunAs","accessTo","trustModel");
46 public $ignore_account = TRUE;
48 public $orig_dn;
50 protected $trustSelect;
52 /*! \brief Returns to the base department for sudo roles.
53 This department is then used to store new roles.
54 @param Object GOsa configuration object.
55 @return String sudo store department
56 */
57 public static function get_sudoers_ou($config)
58 {
59 return(get_ou("sudoRDN").$config->current['BASE']);
60 }
62 /*! \brief Initializes this sudo class, with all required attributes.
63 @param Object $config GOsa configuration object.
64 @param String $db "new" or the sudo role dn.
65 @return .
66 */
67 function sudo(&$config, $dn= NULL)
68 {
69 plugin::plugin ($config, $dn);
71 if($this->initially_was_account){
72 foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
73 $this->$attr = array();
74 if(isset($this->attrs[$attr])){
75 $tmp = array();
76 for($i = 0 ; $i < $this->attrs[$attr]['count']; $i++){
77 $tmp[] = $this->attrs[$attr][$i];
78 }
79 $this->$attr = $tmp;
80 }
81 }
83 /* Is this account a trustAccount? */
84 if (isset($this->attrs['trustModel'])){
85 $this->trustModel= $this->attrs['trustModel'][0];
86 $this->was_trust_account= TRUE;
87 } else {
88 $this->was_trust_account= FALSE;
89 $this->trustModel= "";
90 }
92 $this->accessTo = array();
93 if (isset($this->attrs['accessTo'])){
94 for ($i= 0; $i<$this->attrs['accessTo']['count']; $i++){
95 $tmp= $this->attrs['accessTo'][$i];
96 $this->accessTo[$tmp]= $tmp;
97 }
98 }
100 }
102 if(preg_match("/^defaults$/i",$this->cn)){
103 $this->is_default = TRUE;
104 }
106 /* Get global filter config */
107 if (!session::is_set("sysfilter")){
108 $ui= get_userinfo();
109 $base= get_base_from_people($ui->dn);
110 $sysfilter= array( "depselect" => $base,
111 "regex" => "*");
112 session::set("sysfilter", $sysfilter);
113 }
115 $this->orig_dn = $this->dn;
116 }
119 /*! \brief Creates the sudo generic ui.
120 @return String The generated HTML content for this plugin.
121 */
122 function execute()
123 {
124 /* Call parent execute */
125 plugin::execute();
127 /*********************
128 Access control list / trust mode
129 *********************/
131 /* Add user workstation? */
132 if (isset($_POST["add_ws"])){
133 $this->trustSelect= new trustSelect($this->config,get_userinfo());
134 $this->dialog= TRUE;
135 }
137 // Add selected machines to trusted ones.
138 if (isset($_POST["add_ws_finish"]) && $this->trustSelect){
139 $trusts = $this->trustSelect->detectPostActions();
140 if(isset($trusts['targets'])){
142 $headpage = $this->trustSelect->getHeadpage();
143 foreach($trusts['targets'] as $id){
144 $attrs = $headpage->getEntry($id);
145 $this->accessTo[$attrs['cn'][0]]= $attrs['cn'][0];
146 }
147 ksort($this->accessTo);
148 $this->is_modified= TRUE;
149 }
150 $this->trustSelect= NULL;
151 $this->dialog= FALSE;
152 }
155 /* Remove user workstations? */
156 if (isset($_POST["delete_ws"]) && isset($_POST['workstation_list'])){
157 foreach($_POST['workstation_list'] as $name){
158 unset ($this->accessTo[$name]);
159 }
160 $this->is_modified= TRUE;
161 }
163 /* Add user workstation finished? */
164 if (isset($_POST["add_ws_finish"]) || isset($_POST["add_ws_cancel"])){
165 $this->trustSelect= NULL;
166 $this->dialog= FALSE;
167 }
169 /* Show ws dialog */
170 if ($this->trustSelect){
172 // Build up blocklist
173 session::set('filterBlacklist', array('cn' => array_values($this->accessTo)));
174 return($this->trustSelect->execute());
175 }
178 /*********************
179 Add users
180 *********************/
182 if(isset($_POST['list_sudoUser']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoUser")){
183 $this->dialog =new userGroupSelect($this->config,get_userinfo());
184 }
186 /* Add selected hosts to the sudoUser list */
187 if(isset($_POST['userGroupSelect_save']) && $this->dialog instanceof userGroupSelect){
188 if($this->acl_is_writeable("sudoUser")){
189 foreach($this->dialog->save() as $entry){
190 if(in_array_strict("posixGroup",$entry['objectClass'])){
191 $name = trim("%".$entry['cn'][0]);
192 }elseif(isset($entry['uid'][0])){
193 $name = trim($entry['uid'][0]);
194 }
195 if(!in_array_strict($name,$this->sudoUser) && !in_array_strict("!".$name,$this->sudoUser)){
196 $this->sudoUser[] = $name;
197 }
198 }
199 }
200 unset($this->dialog);
201 $this->dialog = NULL;
202 }
204 if(isset($_POST['userGroupSelect_cancel']) && $this->dialog instanceOf userGroupSelect){
205 unset($this->dialog);
206 $this->dialog = NULL;
207 }
209 if($this->dialog instanceOf userGroupSelect){
210 $used = array();
211 foreach($this->sudoUser as $name){
212 $str = preg_replace("/^!/","",$name);
213 if(preg_match("/^%/", $str)){
214 $used['cn'][] = preg_replace("/^%/","",$str);
215 }else{
216 $used['uid'][] = $str;
217 }
218 }
220 // Build up blocklist
221 session::set('filterBlacklist', $used);
222 return($this->dialog->execute());
223 }
227 /*********************
228 Add systems
229 *********************/
231 if(isset($_POST['list_sudoHost']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoHost")){
232 $this->dialog =new systemSelect($this->config,get_userinfo());
233 }
235 /* Add selected hosts to the sudoHost list */
236 if(isset($_POST['systemSelect_save']) && $this->dialog instanceof systemSelect){
237 if($this->acl_is_writeable("sudoHost")){
238 foreach($this->dialog->save() as $entry){
239 $cn = trim($entry['cn'][0]);
240 if(!in_array_strict($cn,$this->sudoHost) && !in_array_strict("!".$cn,$this->sudoHost)){
241 $this->sudoHost[] = $cn;
242 }
243 }
244 }
245 unset($this->dialog);
246 $this->dialog = NULL;
247 }
249 if(isset($_POST['systemSelect_cancel']) && $this->dialog instanceOf systemSelect){
250 unset($this->dialog);
251 $this->dialog = NULL;
252 }
254 if($this->dialog instanceOf systemSelect){
255 $used = array();
256 foreach($this->sudoHost as $name){
257 $used['cn'][] = preg_replace("/^!/","",$name);
258 }
260 // Build up blocklist
261 session::set('filterBlacklist', $used);
262 return($this->dialog->execute());
263 }
265 /*********************
266 Dialog handling / display / close
267 *********************/
269 if(is_object($this->dialog)){
270 return($this->dialog->execute());
271 }
274 /*********************
275 NEGATE values
276 *********************/
277 foreach($_POST as $name => $value){
278 if(preg_match("/^neg_/",$name)){
279 $attr = preg_replace("/^neg_([^_]*)_.*$/","\\1",$name);
280 $value= preg_replace("/^neg_[^_]*_([0-9]*)_.*$/","\\1",$name);
282 if($this->acl_is_writeable($attr)){
283 $attrs = $this->$attr;
284 if(isset( $attrs[$value])){
285 $v = $attrs[$value];
286 if(preg_match("/^!/",$v)){
287 $attrs[$value] = preg_replace("/^!/","",$v);
288 }else{
289 $attrs[$value] = "!".$v;
290 }
291 $this->$attr = $attrs;
292 }
293 }
294 break; // Do it once, image inputs will be posted twice
295 }
296 }
298 /*********************
299 Delete values
300 *********************/
301 foreach($_POST as $name => $value){
302 if(preg_match("/^del_/",$name)){
303 $attr = preg_replace("/^del_([^_]*)_.*$/","\\1",$name);
304 $value= preg_replace("/^del_[^_]*_([0-9]*)_.*$/","\\1",$name);
305 if($this->acl_is_writeable($attr)){
306 $attrs = $this->$attr;
307 if(isset( $attrs[$value])){
308 unset($attrs[$value]);
309 $this->$attr = $attrs;
310 }
311 }
312 break; // Do it once, image inputs will be posted twice
313 }
314 }
317 /*********************
318 ADD values
319 *********************/
321 /* User / Host / Runas */
322 foreach(array("sudoUser","sudoHost","sudoRunAs") as $attr){
323 if($this->acl_is_writeable($attr) &&
324 isset($_POST["add_".$attr]) &&
325 isset($_POST['new_'.$attr]) &&
326 !empty($_POST['new_'.$attr])){
328 $c = preg_quote(' *+-?_|!\'"()','/');
329 if(preg_match("/^[a-z0-9{$c}]*$/i",$_POST['new_'.$attr])){
330 $attrs = $this->$attr;
331 $attrs[] = trim($_POST['new_'.$attr]);
332 $this->$attr = $attrs;
333 }else{
334 msg_dialog::display(_("Error"),msgPool::invalid($attr,$_POST['new_'.$attr],"/[a-z0-9{$c}]/i"));
335 }
336 }
337 }
339 /* Command */
340 foreach(array("sudoCommand") as $attr){
341 if($this->acl_is_writeable($attr) && isset($_POST["add_".$attr]) && isset($_POST['new_'.$attr])){
342 $attrs = $this->$attr;
343 $attrs[] = trim($_POST['new_'.$attr]);
344 $this->$attr = $attrs;
345 }
346 }
349 /*********************
350 SMARTY assignments
351 *********************/
353 $smarty = get_smarty();
354 $smarty->assign("is_default",$this->is_default);
355 foreach($this->attributes as $attr){
356 if(is_string($this->$attr)){
357 $smarty->assign($attr,htmlentities($this->$attr));
358 }else{
359 $smarty->assign($attr,$this->$attr);
360 }
361 $smarty->assign($attr."ACL",$this->getacl($attr));
362 }
364 /* Work on trust modes */
365 $smarty->assign("trusthide", " disabled ");
366 if ($this->trustModel == "fullaccess"){
367 $trustmode= 1;
368 } elseif ($this->trustModel == "byhost"){
369 $trustmode= 2;
370 $smarty->assign("trusthide", "");
371 } else {
372 $trustmode= 0;
373 }
374 $smarty->assign("trustmode", $trustmode);
375 $smarty->assign("trustmodes", array(
376 0 => _("disabled"),
377 1 => _("full access"),
378 2 => _("allow access to these hosts")));
380 if((count($this->accessTo))==0){
381 $smarty->assign("emptyArrAccess",true);
382 }else{
383 $smarty->assign("emptyArrAccess",false);
384 }
385 $smarty->assign("workstations", $this->accessTo);
387 /* Create lists
388 */
389 $divlist_sudoUser = new divSelectBox("divlist_sudoUser");
390 $divlist_sudoUser->SetHeight("90");
391 $divlist_sudoHost = new divSelectBox("divlist_sudoHost");
392 $divlist_sudoHost->Setheight("90");
393 $divlist_sudoRunAs = new divSelectBox("divlist_sudoRunAs");
394 $divlist_sudoRunAs->Setheight("90");
395 $divlist_sudoCommand = new divSelectBox("divlist_sudoCommand");
396 $divlist_sudoCommand->Setheight("90");
398 /* Fill divlists
399 */
400 $neg_img= "<img src='plugins/sudo/images/negate.png' alt='!' class='center'>";
401 $option = "<input type='image' src='plugins/sudo/images/negate.png' name='neg_%ATTR%_%KEY%' class='center'>";
402 $option.= "<input type='image' src='images/lists/trash.png' name='del_%ATTR%_%KEY%' class='center'>";
403 foreach(array("sudoCommand","sudoHost","sudoRunAs") as $attr){
404 if($this->acl_is_readable($attr)){
405 foreach($this->$attr as $key => $entry){
406 $neg = "";
407 if(preg_match("/^!/",$entry)){
408 $neg = $neg_img;
409 }
410 $entry = preg_replace("/^!/","",$entry);
411 $list_name = "divlist_".$attr;
412 $$list_name->AddEntry(
413 array(
414 array("string" => $neg,"attach" => "style='width:18px;'"),
415 array("string" => $entry),
416 array("string" => preg_replace(array("/%KEY%/","/%ATTR%/"),array($key,$attr),$option),
417 "attach" => "style='width:40px; border-right: 0px;'")));
418 }
419 }
420 }
422 foreach(array("sudoUser") as $attr){
423 $img1 = "<img src='plugins/users/images/select_user.png' alt='"._("User")."' class='center'>";
424 $img2 = "<img src='plugins/groups/images/groups.png' alt='"._("Group")."' class='center'>";
425 if($this->acl_is_readable($attr)){
426 foreach($this->$attr as $key => $entry){
427 $neg = "";
428 if(preg_match("/^!/",$entry)){
429 $neg = $neg_img;
430 }
431 $entry = preg_replace("/^!/","",$entry);
433 $img = $img1;
434 if(preg_match("/^%/",$entry)){
435 $img = $img2;
436 }
437 $entry = preg_replace("/^%/","",$entry);
439 $list_name = "divlist_".$attr;
440 $$list_name->AddEntry(
441 array(
442 array("string" => $neg,"attach" => "style='width:18px;'"),
443 array("string" => $img,"attach" => "style='width:18px;'"),
444 array("string" => $entry),
445 array("string" => preg_replace(array("/%KEY%/","/%ATTR%/"),array($key,$attr),$option),
446 "attach" => "style='width:40px; border-right: 0px;'")));
447 }
448 }
449 }
454 /* Tell smarty about our divlists
455 */
456 $smarty->assign("divlist_sudoUser", $divlist_sudoUser->DrawList());
457 $smarty->assign("divlist_sudoHost", $divlist_sudoHost->DrawList());
458 $smarty->assign("divlist_sudoRunAs", $divlist_sudoRunAs->DrawList());
459 $smarty->assign("divlist_sudoCommand",$divlist_sudoCommand->DrawList());
460 return($smarty->fetch(get_template_path('generic.tpl', TRUE)));
461 }
464 /*! \brief Remove this sudo role from the ldap server
465 */
466 function remove_from_parent()
467 {
468 plugin::remove_from_parent();
470 $ldap = $this->config->get_ldap_link();
471 $ldap->cd($this->dn);
472 $ldap->rmdir($this->dn);
474 /* Send signal to the world that we've done */
475 $this->handle_post_events("remove");
476 }
479 /*! \brief Save all relevant HTML posts.
480 */
481 function save_object()
482 {
483 plugin::save_object();
485 if($this->is_default){
486 $this->cn = "defaults";
487 }
489 /* Trust mode - special handling */
490 if($this->acl_is_writeable("trustModel")){
491 if (isset($_POST['trustmode'])){
492 $saved= $this->trustModel;
493 if ($_POST['trustmode'] == "1"){
494 $this->trustModel= "fullaccess";
495 } elseif ($_POST['trustmode'] == "2"){
496 $this->trustModel= "byhost";
497 } else {
498 $this->trustModel= "";
499 }
500 if ($this->trustModel != $saved){
501 $this->is_modified= TRUE;
502 }
503 }
504 }
505 }
508 /*! \brief Save changes into the ldap database.
509 */
510 function save()
511 {
512 plugin::save();
513 /* Trust accounts */
514 $objectclasses= array();
515 foreach ($this->attrs['objectClass'] as $key => $class){
516 if (preg_match('/trustAccount/i', $class)){
517 continue;
518 }
519 $objectclasses[]= $this->attrs['objectClass'][$key];
520 }
522 $this->attrs['objectClass']= $objectclasses;
523 if ($this->trustModel != ""){
524 $this->attrs['objectClass'][]= "trustAccount";
525 $this->attrs['trustModel']= $this->trustModel;
526 $this->attrs['accessTo']= array();
527 if ($this->trustModel == "byhost"){
528 foreach ($this->accessTo as $host){
529 $this->attrs['accessTo'][]= $host;
530 }
531 }
532 } else {
533 if ($this->was_trust_account){
534 $this->attrs['accessTo']= array();
535 $this->attrs['trustModel']= array();
536 }
537 }
540 /* Ensure a correct array index
541 */
542 $this->attrs['sudoHost'] = array_values($this->attrs['sudoHost']);
543 $this->attrs['sudoRunAs'] = array_values($this->attrs['sudoRunAs']);
544 $this->attrs['sudoUser'] = array_values($this->attrs['sudoUser']);
545 $this->attrs['sudoCommand'] = array_values($this->attrs['sudoCommand']);
547 $this->cleanup();
549 $ldap = $this->config->get_ldap_link();
550 $ldap->cd($this->config->current['BASE']);
552 if($this->is_new){
553 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
554 $ldap->cd($this->dn);
555 $ldap->add($this->attrs);
557 /* Send signal to the world that we've done */
558 $this->handle_post_events("create");
559 }else{
560 $ldap->cd($this->dn);
561 $ldap->modify($this->attrs);;
563 /* Send signal to the world that we've done */
564 $this->handle_post_events("modify");
565 }
567 if (!$ldap->success()){
568 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
569 }
570 }
573 /*! \brief Check the given input.
574 @return Array All error messages in an array();
575 */
576 function check()
577 {
578 $message = plugin::check();
580 /* Is a name given? */
581 if($this->cn == ""){
582 $message[] = msgPool::required(_("Name"));
583 }
585 /* Check if name is reserved */
586 if(!$this->is_default && preg_match("/^defaults$/i",$this->cn)){
587 $message[] = msgPool::reserved(_("Name"));
588 }
590 /* Check name */
591 if(!preg_match("/^[0-9a-z\@]*$/i",$this->cn)){
592 $message[] = msgPool::invalid(_("Name"),$this->cn,"/[0-9a-z\@]/i");
593 }
595 /* Check if this entry will cause duplicated ldap entries */
596 $ldap = $this->config->get_ldap_link();
597 $ldap->cd($this->get_sudoers_ou($this->config));
598 $ldap->search("(&(objectClass=sudoRole)(cn=".$this->cn."))");
599 while($attrs = $ldap->fetch()){
600 if($attrs['dn'] != $this->dn){
601 $message[] = msgPool::duplicated(_("Name"));
602 }
603 }
605 /* Check if we are allowed to create or move this object
606 */
607 if($this->orig_dn == "new" && !$this->acl_is_createable($this->get_sudoers_ou($this->config))){
608 $message[] = msgPool::permCreate();
609 }
611 return ($message);
612 }
615 /*! \brief Force this entry to be handled and saved as 'default'
616 @param BOOL TRUE -force defaults FALSE -normal
617 */
618 public function set_default($state)
619 {
620 $this->is_default = TRUE;
621 $this->cn = "defaults";
622 }
625 /*! \brief Add ACL object
626 @return Returns the ACL object.
627 */
628 static function plInfo()
629 {
630 return (array(
631 "plShortName" => _("Sudo"),
632 "plDescription" => _("Sudo role"),
633 "plSelfModify" => FALSE,
634 "plDepends" => array(),
635 "plPriority" => 0,
636 "plSection" => array("administration"),
637 "plCategory" => array("sudo" => array("objectClass" => "sudoRole", "description" => _("Sudo role"))),
639 "plProvidedAcls" => array(
640 "cn" => _("Name"),
641 "description" => _("Description"),
642 "sudoUser" => _("Users"),
643 "sudoHost" => _("Host"),
644 "sudoCommand" => _("Command"),
645 "sudoRunAs" => _("Run as user"),
646 "trustModel" => _("Access control list"))
647 ));
648 }
651 /*! \brief This function will be called if an object gets copied.
652 This function adapts attributes from the source object.
653 @param Array The source object.
654 */
655 function PrepareForCopyPaste($source)
656 {
657 plugin::PrepareForCopyPaste($source);
658 foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
659 $this->$attr = array();
660 if(isset($source[$attr])){
661 $tmp = array();
662 for($i = 0 ; $i < $source[$attr]['count']; $i++){
663 $tmp[] = $source[$attr][$i];
664 }
665 $this->$attr = $tmp;
666 }
667 }
669 /* Is this account a trustAccount? */
670 if (isset($source['trustModel'])){
671 $this->trustModel= $source['trustModel'][0];
672 $this->was_trust_account= TRUE;
673 } else {
674 $this->was_trust_account= FALSE;
675 $this->trustModel= "";
676 }
678 $this->accessTo = array();
679 if (isset($source['accessTo'])){
680 for ($i= 0; $i<$source['accessTo']['count']; $i++){
681 $tmp= $source['accessTo'][$i];
682 $this->accessTo[$tmp]= $tmp;
683 }
684 }
685 }
688 /*! \brief Used for copy & paste.
689 Returns a HTML input mask, which allows to change the cn of this entry.
690 @param Array Array containing current status && a HTML template.
691 */
692 function getCopyDialog()
693 {
694 $vars = array("cn");
695 $smarty = get_smarty();
696 $smarty->assign("cn", htmlentities($this->cn));
697 $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE));
698 $ret = array();
699 $ret['string'] = $str;
700 $ret['status'] = "";
701 return($ret);
702 }
705 public function get_cn()
706 {
707 return($this->cn);
708 }
711 /*! \brief Used for copy & paste.
712 Some entries must be renamed to avaoid duplicate entries.
713 */
714 function saveCopyDialog()
715 {
716 if(isset($_POST['cn'])){
717 $this->cn = get_post('cn');
718 }
719 }
720 }
721 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
722 ?>