Code

Updated sudo
[gosa.git] / gosa-plugins / sudo / admin / sudo / class_sudoGeneric.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: 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 {
29   /* Group attributes */
30   var $cn= "";
31   var $description= "";
33   var $sudoUser   = array("ALL");
34   var $sudoCommand= array();
35   var $sudoHost   = array("ALL");
36   var $sudoRunAs  = array("ALL");
38   var $accessTo         = array();
39   var $trustModel       = "";
40   var $show_ws_dialog   = FALSE;
41   var $was_trust_account= FALSE;
43   var $objectclasses = array("top","sudoRole");
44   var $attributes    = array("cn","description","sudoUser","sudoCommand","sudoHost","sudoRunAs","accessTo","trustModel");
46   var $is_account = TRUE;
47   var $is_default = FALSE;
48   var $dialog;
50   /*! \brief  Returns to the base department for sudo roles.
51               This department is then used to store new roles.
52       @param  Object  GOsa configuration object.
53       @return String sudo store department
54    */
55   public static function get_sudoers_ou($config)
56   {
57     /***
58       GET sudo base
59      ***/
60     $base ="";
61     if(empty($base)){
62       /* Default is ou=sudoers,BASE */
63       $base = "ou=sudoers,".$config->current['BASE'];
64     }else{
66       /* Append base to given sudoers ou if missing */
67       if(!preg_match("/".normalizePreg($config->current['BASE'])."$/i",$base)){
68         if(!preg_match("/,$/",$base)){
69           $base = $base.",".$config->current['BASE'];
70         }else{
71           $base = $base.$config->current['BASE'];
72         }
73       }
74     }
75     return($base);
76   }
78   /*! \brief  Initializes this sudo class, with all required attributes.
79       @param  Object $config  GOsa configuration object.
80       @param  String $db      "new" or the sudo role dn.
81       @return .
82    */
83   function sudo(&$config, $dn= NULL)
84   {
85     plugin::plugin ($config, $dn);
87     if($this->initially_was_account){
88       foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
89         $this->$attr = array();
90         if(isset($this->attrs[$attr])){
91           $tmp = array();
92           for($i = 0 ; $i < $this->attrs[$attr]['count']; $i++){
93             $tmp[] = $this->attrs[$attr][$i];
94           }
95           $this->$attr = $tmp;
96         }
97       }
99       /* Is this account a trustAccount? */
100       if ($this->is_account && isset($this->attrs['trustModel'])){
101         $this->trustModel= $this->attrs['trustModel'][0];
102         $this->was_trust_account= TRUE;
103       } else {
104         $this->was_trust_account= FALSE;
105         $this->trustModel= "";
106       }
108       $this->accessTo = array();
109       if ($this->is_account && isset($this->attrs['accessTo'])){
110         for ($i= 0; $i<$this->attrs['accessTo']['count']; $i++){
111           $tmp= $this->attrs['accessTo'][$i];
112           $this->accessTo[$tmp]= $tmp;
113         }
114       }
116     }
118     if(preg_match("/^default$/i",$this->cn)){
119       $this->is_default = TRUE;
120     }
122     /* Get global filter config */
123     if (!session::is_set("sysfilter")){
124       $ui= get_userinfo();
125       $base= get_base_from_people($ui->dn);
126       $sysfilter= array( "depselect"       => $base,
127           "regex"           => "*");
128       session::set("sysfilter", $sysfilter);
129     }
130   }
133   /*! \brief  Creates the sudo generic ui. 
134       @return String  The generated HTML content for this plugin. 
135    */
136   function execute()
137   {
138     /* Call parent execute */
139     plugin::execute();
141     /*********************
142        Access control list / trust mode 
143      *********************/ 
145     /* Add user workstation? */
146     if (isset($_POST["add_ws"])){
147       $this->show_ws_dialog= TRUE;
148       $this->dialog= TRUE;
149     }
151     /* Add user workstation? */
152     if (isset($_POST["add_ws_finish"]) && isset($_POST['wslist'])){
153       foreach($_POST['wslist'] as $ws){
154         $this->accessTo[$ws]= $ws;
155       }
156       ksort($this->accessTo);
157       $this->is_modified= TRUE;
158     }
160     /* Remove user workstations? */
161     if (isset($_POST["delete_ws"]) && isset($_POST['workstation_list'])){
162       foreach($_POST['workstation_list'] as $name){
163         unset ($this->accessTo[$name]);
164       }
165       $this->is_modified= TRUE;
166     }
168     /* Add user workstation finished? */
169     if (isset($_POST["add_ws_finish"]) || isset($_POST["add_ws_cancel"])){
170       $this->show_ws_dialog= FALSE;
171       $this->dialog= FALSE;
172     }
174     /* Show ws dialog */
175     if ($this->show_ws_dialog){
176       return($this->display_trust_add_dialog());
177     }
180     /*********************
181        Add users 
182      *********************/ 
183   
184     if(isset($_POST['list_sudoUser']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoUser")){
185       $used = array();
186       foreach($this->sudoUser as $name){
187         $used[] = preg_replace("/^!/","",$name);
188       }
189       $this->dialog =new target_list_users($this->config,$used);
190     }
191    
192     /* Add selected hosts  to the sudoUser list */ 
193     if(isset($_POST['SaveMultiSelectWindow']) && $this->dialog instanceof target_list_users){
194       if($this->acl_is_writeable("sudoUser")){
195         foreach($this->dialog->save() as $entry){
196           if(in_array("posixGroup",$entry['objectClass'])){
197             $name = trim("%".$entry['cn'][0]);
198           }else{
199             $name = trim($entry['uid'][0]);
200           }
201           if(!in_array($name,$this->sudoUser) && !in_array("!".$name,$this->sudoUser)){
202             $this->sudoUser[] = $name;
203           }
204         }   
205       }
206       unset($this->dialog);
207       $this->dialog = NULL;
208     }    
211     /*********************
212        Add systems 
213      *********************/ 
214   
215     if(isset($_POST['list_sudoHost']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoHost")){
216       $used = array();
217       foreach($this->sudoHost as $name){
218         $used[] = preg_replace("/^!/","",$name);
219       }
220       $this->dialog =new target_list_systems($this->config,$used);
221     }
222    
223     /* Add selected hosts  to the sudoHost list */ 
224     if(isset($_POST['SaveMultiSelectWindow']) && $this->dialog instanceof target_list_systems){
225       if($this->acl_is_writeable("sudoHost")){
226         foreach($this->dialog->save() as $entry){
227           $cn = trim($entry['cn'][0]);
228           if(!in_array($cn,$this->sudoHost) && !in_array("!".$cn,$this->sudoHost)){
229             $this->sudoHost[] = $cn;
230           }
231         }   
232       }   
233       unset($this->dialog);
234       $this->dialog = NULL;
235     }    
238     /*********************
239        Dialog handling / display / close  
240      *********************/ 
241   
242     if(isset($_POST['CloseMultiSelectWindow']) && is_object($this->dialog)){
243       unset($this->dialog);
244       $this->dialog = NULL;
245     }    
247     if(is_object($this->dialog)){
248       return($this->dialog->execute());
249     }
251  
252     /*********************
253        NEGATE values 
254      *********************/ 
255     foreach($_POST as $name => $value){
256       if(preg_match("/^neg_/",$name)){
257         $attr = preg_replace("/^neg_([^_]*)_.*$/","\\1",$name);
258         $value= preg_replace("/^neg_[^_]*_([0-9]*)_.*$/","\\1",$name);
259  
260         if($this->acl_is_writeable($attr)){
261           $attrs = $this->$attr;
262           if(isset( $attrs[$value])){
263             $v =  $attrs[$value];
264             if(preg_match("/^!/",$v)){
265               $attrs[$value] = preg_replace("/^!/","",$v);
266             }else{
267               $attrs[$value] = "!".$v;
268             }
269             $this->$attr = $attrs;  
270           }
271         }
272         break; // Do it once, image inputs will be posted twice
273       }
274     }
275   
276     /*********************
277        Delete values 
278      *********************/ 
279     foreach($_POST as $name => $value){
280       if(preg_match("/^del_/",$name)){
281         $attr = preg_replace("/^del_([^_]*)_.*$/","\\1",$name);
282         $value= preg_replace("/^del_[^_]*_([0-9]*)_.*$/","\\1",$name);
283         if($this->acl_is_writeable($attr)){
284           $attrs = $this->$attr;
285           if(isset( $attrs[$value])){
286             unset($attrs[$value]);
287             $this->$attr = $attrs;  
288           }
289         }
290         break; // Do it once, image inputs will be posted twice
291       }
292     }
295     /*********************
296        ADD values 
297      *********************/
299     /* User / Host / Runas */ 
300     foreach(array("sudoUser","sudoHost","sudoRunAs") as $attr){
301       if($this->acl_is_writeable($attr) && 
302           isset($_POST["add_".$attr]) && 
303           isset($_POST['new_'.$attr]) && 
304           !empty($_POST['new_'.$attr])){
305         if(preg_match("/^[a-z\.0-9]*$/i",$_POST['new_'.$attr])){
306           $attrs = $this->$attr;
307           $attrs[] =  trim($_POST['new_'.$attr]); 
308           $this->$attr = $attrs;
309         }else{
310           msg_dialog::display(_("Error"),msgPool::invalid($attr,$_POST['new_'.$attr],"/[a-z0-9]/"));
311         }
312       }
313     }
315     /* Command */
316     foreach(array("sudoCommand") as $attr){
317       if($this->acl_is_writeable($attr) && isset($_POST["add_".$attr]) && isset($_POST['new_'.$attr])){
318         $attrs = $this->$attr;
319         $attrs[] =  trim($_POST['new_'.$attr]); 
320         $this->$attr = $attrs;
321       }
322     }
324     
325     /*********************
326        SMARTY assignments 
327      *********************/
329     $smarty = get_smarty();
330     $smarty->assign("is_default",$this->is_default);
331     foreach($this->attributes as $attr){
332       $smarty->assign($attr,$this->$attr);
333       $smarty->assign($attr."ACL",$this->getacl($attr));
334     }
336     /* Work on trust modes */
337     $smarty->assign("trusthide", " disabled ");
338     if ($this->trustModel == "fullaccess"){
339       $trustmode= 1;
340     } elseif ($this->trustModel == "byhost"){
341       $trustmode= 2;
342       $smarty->assign("trusthide", "");
343     } else {
344       $trustmode= 0;
345     }
346     $smarty->assign("trustmode", $trustmode);
347     $smarty->assign("trustmodes", array( 
348           0 => _("disabled"), 
349           1 => _("full access"),
350           2 => _("allow access to these hosts")));
352     if((count($this->accessTo))==0){
353       $smarty->assign("emptyArrAccess",true);
354     }else{
355       $smarty->assign("emptyArrAccess",false);
356     }
357     $smarty->assign("workstations", $this->accessTo);
358     
359     /* Create lists 
360      */
361     $divlist_sudoUser = new divSelectBox("divlist_sudoUser");
362     $divlist_sudoUser->SetHeight("90");
363     $divlist_sudoHost = new divSelectBox("divlist_sudoHost");
364     $divlist_sudoHost->Setheight("90");
365     $divlist_sudoRunAs = new divSelectBox("divlist_sudoRunAs");
366     $divlist_sudoRunAs->Setheight("90");
367     $divlist_sudoCommand = new divSelectBox("divlist_sudoCommand");
368     $divlist_sudoCommand->Setheight("90");
370     /* Fill divlists
371      */
372     $neg_img= "<img src='images/negate.png' alt='!' class='center'>"; 
373     $option = "<input type='image' src='images/negate.png'     name='neg_%ATTR%_%KEY%' class='center'>"; 
374     $option.= "<input type='image' src='images/edittrash.png'  name='del_%ATTR%_%KEY%' class='center'>"; 
375     foreach(array("sudoCommand","sudoHost","sudoRunAs") as $attr){
376       if($this->acl_is_readable($attr)){
377         foreach($this->$attr as $key => $entry){
378           $neg = "";
379           if(preg_match("/^!/",$entry)){
380             $neg = $neg_img;
381           }
382           $entry = preg_replace("/^!/","",$entry);
383           $list_name = "divlist_".$attr;
384           $$list_name->AddEntry(
385               array(
386                 array("string" => $neg,"attach" => "style='width:18px;'"),
387                 array("string" => $entry),
388                 array("string" => preg_replace(array("/%KEY%/","/%ATTR%/"),array($key,$attr),$option),
389                   "attach" => "style='width:40px; border-right: 0px;'")));
390         }
391       }
392     }
394     foreach(array("sudoUser") as $attr){
395       $img1 = "<img src='images/select_user.png'   alt='"._("User")."' class='center'>";
396       $img2 = "<img src='images/select_groups.png' alt='"._("Group")."' class='center'>";
397       if($this->acl_is_readable($attr)){
398         foreach($this->$attr as $key => $entry){
399           $neg = "";
400           if(preg_match("/^!/",$entry)){
401             $neg = $neg_img;
402           }
403           $entry = preg_replace("/^!/","",$entry);
405           $img = $img1;
406           if(preg_match("/^%/",$entry)){
407             $img = $img2;
408           }
409           $entry = preg_replace("/^%/","",$entry);
410   
411           $list_name = "divlist_".$attr;
412           $$list_name->AddEntry(
413               array(
414                 array("string" => $neg,"attach" => "style='width:18px;'"),
415                 array("string" => $img,"attach" => "style='width:18px;'"),
416                 array("string" => $entry),
417                 array("string" => preg_replace(array("/%KEY%/","/%ATTR%/"),array($key,$attr),$option),
418                   "attach" => "style='width:40px; border-right: 0px;'")));
419         }
420       }
421     }
426     /* Tell smarty about our divlists 
427      */
428     $smarty->assign("divlist_sudoUser",   $divlist_sudoUser->DrawList());
429     $smarty->assign("divlist_sudoHost",   $divlist_sudoHost->DrawList());
430     $smarty->assign("divlist_sudoRunAs",  $divlist_sudoRunAs->DrawList());
431     $smarty->assign("divlist_sudoCommand",$divlist_sudoCommand->DrawList());
432     return($smarty->fetch(get_template_path('generic.tpl', TRUE)));
433   }
436   /*! \brief  Remove this sudo role from the ldap server 
437    */
438   function remove_from_parent()
439   {
440     plugin::remove_from_parent();
442     $ldap = $this->config->get_ldap_link();
443     $ldap->cd($this->dn);
444     $ldap->rmdir($this->dn);
446     /* Send signal to the world that we've done */
447     $this->handle_post_events("remove");
448   }
451   /*! \brief  Save all relevant HTML posts. 
452    */
453   function save_object()
454   {
455     plugin::save_object();
456     
457     if($this->is_default){
458       $this->cn = "default";
459     }  
461     if(is_object($this->dialog)){
462       $this->dialog->save_object();
463     }
465     /* Trust mode - special handling */
466     if($this->acl_is_writeable("trustModel")){
467       if (isset($_POST['trustmode'])){
468         $saved= $this->trustModel;
469         if ($_POST['trustmode'] == "1"){
470           $this->trustModel= "fullaccess";
471         } elseif ($_POST['trustmode'] == "2"){
472           $this->trustModel= "byhost";
473         } else {
474           $this->trustModel= "";
475         }
476         if ($this->trustModel != $saved){
477           $this->is_modified= TRUE;
478         }
479       }
480     }
481   }
484   /*! \brief  Save changes into the ldap database.
485    */
486   function save()
487   {
488     plugin::save();
489    /* Trust accounts */
490     $objectclasses= array();
491     foreach ($this->attrs['objectClass'] as $key => $class){
492       if (preg_match('/trustAccount/i', $class)){
493         continue;
494       }
495       $objectclasses[]= $this->attrs['objectClass'][$key];
496     }
498     $this->attrs['objectClass']= $objectclasses;
499     if ($this->trustModel != ""){
500       $this->attrs['objectClass'][]= "trustAccount";
501       $this->attrs['trustModel']= $this->trustModel;
502       $this->attrs['accessTo']= array();
503       if ($this->trustModel == "byhost"){
504         foreach ($this->accessTo as $host){
505           $this->attrs['accessTo'][]= $host;
506         }
507       }
508     } else {
509       if ($this->was_trust_account){
510         $this->attrs['accessTo']= array();
511         $this->attrs['trustModel']= array();
512       }
513     }
516     /* Ensure a correct array index 
517      */ 
518     $this->attrs['sudoHost']    = array_values($this->attrs['sudoHost']);
519     $this->attrs['sudoRunAs']   = array_values($this->attrs['sudoRunAs']);
520     $this->attrs['sudoUser']    = array_values($this->attrs['sudoUser']);
521     $this->attrs['sudoCommand'] = array_values($this->attrs['sudoCommand']);
523     $this->cleanup();
525     $ldap = $this->config->get_ldap_link();
526     $ldap->cd($this->config->current['BASE']);
527     if($this->is_new){
528       $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
529       $ldap->cd($this->dn);
530       $ldap->add($this->attrs);
532       /* Send signal to the world that we've done */
533       $this->handle_post_events("create");
534     }else{
535       $ldap->cd($this->dn);
536       $ldap->modify($this->attrs);;
538       /* Send signal to the world that we've done */
539       $this->handle_post_events("modify");
540     }
542     if (!$ldap->success()){
543       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
544     }
545   }
548   /*! \brief  Check the given input.
549       @return Array   All error messages in an array();
550    */
551   function check()
552   {
553     $message = plugin::check();
555     /* Is a name given? */
556     if(empty($this->cn)){
557       $message[] = msgPool::required(_("Name"));
558     }
560     /* Check if name is reserved */
561     if(!$this->is_default && preg_match("/^default$/i",$this->cn)){
562       $message[] = msgPool::reserved(_("Name"));
563     }
565     /* Check name */
566     if(!preg_match("/^[a-z]*$/i",$this->cn)){
567       $message[] = msgPool::invalid(_("Name"),$this->cn,"/[a-z]/i");
568     }
570     /* Check if this entry will cause duplicated ldap entries */
571     $ldap = $this->config->get_ldap_link();
572     $ldap->cd($this->get_sudoers_ou($this->config));
573     $ldap->search("(&(objectClass=sudoRole)(cn=".$this->cn."))");
574     while($attrs = $ldap->fetch()){
575       if($attrs['dn'] != $this->dn){
576         $message[] = msgPool::duplicated(_("Name"));
577       }
578     }
580     return ($message);
581   }
584   /*! \brief  Display the System Trust Add Workstation dialog 
585     @return String  HTML dialog to add a system to the trust list.
587    */
588   private function display_trust_add_dialog()
589   {
590     $smarty = get_smarty();
592     /* Save data */
593     $sysfilter= session::get("sysfilter");
594     foreach( array("depselect", "regex") as $type){
595       if (isset($_POST[$type])){
596         $sysfilter[$type]= $_POST[$type];
597       }
598     }
599     if (isset($_GET['search'])){
600       $s= mb_substr($_GET['search'], 0, 1, "UTF8")."*";
601       if ($s == "**"){
602         $s= "*";
603       }
604       $sysfilter['regex']= $s;
605     }
606     session::set("sysfilter", $sysfilter);
608     /* Get workstation list */
609     $exclude= "";
610     foreach($this->accessTo as $ws){
611       $exclude.= "(cn=$ws)";
612     }
613     if ($exclude != ""){
614       $exclude= "(!(|$exclude))";
615     }
616     $regex= $sysfilter['regex'];
617     $filter= "(&(|(objectClass=goServer)(objectClass=gotoWorkstation)(objectClass=gotoTerminal))$exclude(cn=*)(cn=$regex))";
619     $res = array();
620     $res= array_merge($res,get_sub_list($filter, array("terminal"), get_ou("terminalou"),
621         get_ou("systemsou").$sysfilter['depselect'],          array("cn"), GL_SUBSEARCH | GL_SIZELIMIT));
622     $res= array_merge($res,get_sub_list($filter, array("server"), get_ou("serverou"), 
623         get_ou("systemsou").$sysfilter['depselect'],          array("cn"), GL_SUBSEARCH | GL_SIZELIMIT));
624     $res= array_merge($res,get_sub_list($filter, array("workstation"), get_ou("workstationou"),
625         get_ou("systemsou").$sysfilter['depselect'],          array("cn"), GL_SUBSEARCH | GL_SIZELIMIT));
627     $wslist= array();
628     foreach ($res as $attrs){
629       $wslist[]= preg_replace('/\$/', '', $attrs['cn'][0]);
630     }
631     asort($wslist);
632     foreach( array("depselect","regex") as $type){
633       $smarty->assign("$type", $sysfilter[$type]);
634     }
635     $smarty->assign("search_image", get_template_path('images/search.png'));
636     $smarty->assign("launchimage",  get_template_path('images/small_filter.png'));
637     $smarty->assign("tree_image",   get_template_path('images/tree.png'));
638     $smarty->assign("deplist",      $this->config->idepartments);
639     $smarty->assign("alphabet",     generate_alphabet());
640     $smarty->assign("hint",         print_sizelimit_warning());
641     $smarty->assign("wslist",       $wslist);
642     $smarty->assign("apply",        apply_filter());
643     $display= $smarty->fetch (get_template_path('trust_machines.tpl', TRUE, dirname(__FILE__)));
644     return ($display);
645   }
648   public function set_default($state)
649   {
650     $this->is_default = TRUE;
651     $this->cn = "default";
652   }
655   /*! \brief  Add ACL object
656       @return Returns the ACL object.
657    */
658   static function plInfo()
659   {
660     return (array(  
661           "plShortName" => _("Sudo"),
662           "plDescription" => _("Sudo role"),
663           "plSelfModify"  => FALSE,
664           "plDepends"     => array(),
665           "plPriority"    => 0,
666           "plSection"     => array("admin"),
667           "plCategory"    => array("sudo" => array("objectClass" => "sudoRole", "description" => _("Sudo role"))),
669           "plProvidedAcls"    => array(
670             "cn"                => _("Name"),
671             "description"       => _("Description"),
672             "sudoUser"          => _("Users"),
673             "sudoHost"          => _("Host"),
674             "sudoCommand"       => _("Command"),
675             "sudoRunAs"         => _("Run as user"),
676             "trustModel"        => _("Access control list"))
677         ));
678   }
680 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
681 ?>