Code

Updated sudo plugin
[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 {
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");
38     private $is_default = FALSE;
40     public $objectclasses = array("top","sudoRole");
41     public $attributes    = array("cn","description","sudoUser","sudoCommand","sudoHost","sudoRunAs");
43     public $ignore_account = TRUE;
45     public $orig_dn;
47     /*! \brief  Returns to the base department for sudo roles.
48       This department is then used to store new roles.
49       @param  Object  GOsa configuration object.
50       @return String sudo store department
51      */
52     public static function get_sudoers_ou($config)
53     {
54         return(get_ou("sudo", "sudoRDN").$config->current['BASE']);
55     }
57     /*! \brief  Initializes this sudo class, with all required attributes.
58       @param  Object $config  GOsa configuration object.
59       @param  String $db      "new" or the sudo role dn.
60       @return .
61      */
62     function sudo(&$config, $dn= NULL)
63     {
64         plugin::plugin ($config, $dn);
66         $this->trustModeDialog = new trustModeDialog($this->config, $this->dn,NULL);
67         $this->trustModeDialog->setAcl('sudo/sudo');
69         if($this->initially_was_account){
70             foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
71                 $this->$attr = array();
72                 if(isset($this->attrs[$attr])){
73                     $tmp = array();
74                     for($i = 0 ; $i < $this->attrs[$attr]['count']; $i++){
75                         $tmp[] = $this->attrs[$attr][$i];
76                     }
77                     $this->$attr = $tmp;
78                 }
79             }
80         }
82         if(preg_match("/^defaults$/i",$this->cn)){
83             $this->is_default = TRUE;
84         }
86         /* Get global filter config */
87         if (!session::is_set("sysfilter")){
88             $ui= get_userinfo();
89             $base= get_base_from_people($ui->dn);
90             $sysfilter= array( "depselect"       => $base,
91                     "regex"           => "*");
92             session::set("sysfilter", $sysfilter);
93         }
95         $this->orig_dn = $this->dn;
97         // Build sortable lists 
98         foreach(array('sudoUser','sudoCommand','sudoHost','sudoRunAs') as $l){
99             $ll = $l."List";
100             $this->$ll = new sortableListing($this->$l);
101             $this->$ll->setDeleteable(false);
102             $this->$ll->setEditable(false);
103             $this->$ll->setWidth("100%");
104             $this->$ll->setHeight("100px");
105             $this->$ll->setAcl($this->getacl($l));
106             $this->$ll->setDefaultSortColumn(1);
107         }
108         $this->sudoUserList->setHeader(array("!",_("Type"),_("Member"),_("Option")));
109         $this->sudoUserList->setColspecs(array('24px','24px','*','46px'));
110         $this->sudoUserList->setDefaultSortColumn(2);
111         $this->sudoHostList->setHeader(array("!",_("System"),_("Option")));
112         $this->sudoHostList->setColspecs(array('24px','*','46px'));
113         $this->sudoCommandList->setHeader(array("!",_("Command"),_("Option")));
114         $this->sudoCommandList->setColspecs(array('24px','*','46px'));
115         $this->sudoRunAsList->setHeader(array("!",_("User"),_("Option")));
116         $this->sudoRunAsList->setColspecs(array('24px','*','46px'));
117     }
120     /*! \brief  Creates the sudo generic ui. 
121       @return String  The generated HTML content for this plugin. 
122      */
123     function execute()
124     {
125         /* Call parent execute */
126         plugin::execute();
128         // Handle trust mode dialog
129         $trustModeDialog = $this->trustModeDialog->execute();
130         if($this->trustModeDialog->trustSelect){
131             $this->dialog = TRUE;
132             return($trustModeDialog);
134         }
135         $this->dialog = FALSE;
137         /*********************
138           Add users 
139          *********************/ 
141         if(isset($_POST['list_sudoUser']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoUser")){
142             $this->dialog =new userGroupSelect($this->config,get_userinfo());
143         }
145         /* Add selected hosts  to the sudoUser list */ 
146         if(isset($_POST['userGroupSelect_save']) && $this->dialog instanceof userGroupSelect){
147             if($this->acl_is_writeable("sudoUser")){
148                 foreach($this->dialog->save() as $entry){
149                     if(in_array("posixGroup",$entry['objectClass'])){
150                         $name = trim("%".$entry['cn'][0]);
151                     }elseif(isset($entry['uid'][0])){
152                         $name = trim($entry['uid'][0]);
153                     }
154                     if(!in_array($name,$this->sudoUser) && !in_array("!".$name,$this->sudoUser)){
155                         $this->sudoUser[] = $name;
156                     }
157                 }   
158             }
159             unset($this->dialog);
160             $this->dialog = NULL;
161         }    
163         if(isset($_POST['userGroupSelect_cancel']) && $this->dialog instanceOf userGroupSelect){
164             unset($this->dialog);
165             $this->dialog = NULL;
166         }    
168         if($this->dialog instanceOf userGroupSelect){
169             $used = array();
170             foreach($this->sudoUser as $name){
171                 $str = preg_replace("/^!/","",$name);
172                 if(preg_match("/^%/", $str)){
173                     $used['cn'][] = preg_replace("/^%/","",$str);
174                 }else{
175                     $used['uid'][] = $str;
176                 }
177             }
179             // Build up blocklist
180             session::set('filterBlacklist', $used);
181             return($this->dialog->execute());
182         }
186         /*********************
187           Add systems 
188          *********************/ 
190         if(isset($_POST['list_sudoHost']) && !is_object($this->dialog) && $this->acl_is_writeable("sudoHost")){
191             $this->dialog =new systemSelect($this->config,get_userinfo());
192         }
194         /* Add selected hosts  to the sudoHost list */ 
195         if(isset($_POST['systemSelect_save']) && $this->dialog instanceof systemSelect){
196             if($this->acl_is_writeable("sudoHost")){
197                 foreach($this->dialog->save() as $entry){
198                     $cn = trim($entry['cn'][0]);
199                     if(!in_array($cn,$this->sudoHost) && !in_array("!".$cn,$this->sudoHost)){
200                         $this->sudoHost[] = $cn;
201                     }
202                 }   
203             }   
204             unset($this->dialog);
205             $this->dialog = NULL;
206         }    
208         if(isset($_POST['systemSelect_cancel']) && $this->dialog instanceOf systemSelect){
209             unset($this->dialog);
210             $this->dialog = NULL;
211         }    
213         if($this->dialog instanceOf systemSelect){
214             $used = array();
215             foreach($this->sudoHost as $name){
216                 $used['cn'][] = preg_replace("/^!/","",$name);
217             }
219             // Build up blocklist
220             session::set('filterBlacklist', $used);
221             return($this->dialog->execute());
222         }
224         /*********************
225           Dialog handling / display / close  
226          *********************/ 
228         if(is_object($this->dialog)){
229             return($this->dialog->execute());
230         }
233         /*********************
234           NEGATE values 
235          *********************/ 
236         foreach($_POST as $name => $value){
237             if(preg_match("/^neg_/",$name)){
238                 $attr = preg_replace("/^neg_([^_]*)_.*$/","\\1",$name);
239                 $value= preg_replace("/^neg_[^_]*_([0-9]*)$/","\\1",$name);
241                 if($this->acl_is_writeable($attr)){
242                     $attrs = $this->$attr;
243                     if(isset( $attrs[$value])){
244                         $v =  $attrs[$value];
245                         if(preg_match("/^!/",$v)){
246                             $attrs[$value] = preg_replace("/^!/","",$v);
247                         }else{
248                             $attrs[$value] = "!".$v;
249                         }
250                         $this->$attr = $attrs;  
251                     }
252                 }
253                 break; // Do it once, image inputs will be posted twice
254             }
255         }
257         /*********************
258           Delete values 
259          *********************/ 
260         foreach($_POST as $name => $value){
261             if(preg_match("/^delS_/",$name)){
262                 $attr = preg_replace("/^delS_([^_]*).*$/","\\1",$name);
263                 $value= preg_replace("/^delS_[^_]*_([0-9]*)$/","\\1",$name);
264                 if($this->acl_is_writeable($attr)){
265                     $attrs = $this->$attr;
266                     if(isset( $attrs[$value])){
267                         unset($attrs[$value]);
268                         $this->$attr = $attrs;  
269                     }
270                 }
271                 break; // Do it once, image inputs will be posted twice
272             }
273         }
276         /*********************
277           ADD values 
278          *********************/
280         /* User / Host / Runas */ 
281         foreach(array("sudoUser","sudoHost","sudoRunAs") as $attr){
282             if($this->acl_is_writeable($attr) && 
283                     isset($_POST["add_".$attr]) && 
284                     isset($_POST['new_'.$attr]) && 
285                     !empty($_POST['new_'.$attr])){
287                 $c = preg_quote('’ *+-?_|!\'"()','/');
288                 if(preg_match("/^[a-z0-9{$c}]*$/i",$_POST['new_'.$attr])){
289                     $attrs = $this->$attr;
290                     $attrs[] =  trim($_POST['new_'.$attr]); 
291                     $this->$attr = $attrs;
292                 }else{
293                     msg_dialog::display(_("Error"),msgPool::invalid($attr,$_POST['new_'.$attr],"/[a-z0-9{$c}]/i"));
294                 }
295             }
296         }
298         /* Command */
299         foreach(array("sudoCommand") as $attr){
300             if($this->acl_is_writeable($attr) && isset($_POST["add_".$attr]) && isset($_POST['new_'.$attr])){
301                 $attrs = $this->$attr;
302                 $attrs[] =  trim($_POST['new_'.$attr]); 
303                 $this->$attr = $attrs;
304             }
305         }
308         /*********************
309           SMARTY assignments 
310          *********************/
312         $smarty = get_smarty();
313         $smarty->assign("trustModeDialog" , $trustModeDialog);
314         $smarty->assign("is_default",$this->is_default);
315         foreach($this->attributes as $attr){
316             if(is_string($this->$attr)){
317                 $smarty->assign($attr,htmlentities($this->$attr));
318             }else{
319                 $smarty->assign($attr,$this->$attr);
320             }
321             $smarty->assign($attr."ACL",$this->getacl($attr));
322         }
324         /* Fill listings
325          */
326         $neg_img= image('plugins/sudo/images/negate.png','','!');
327         $option = image('plugins/sudo/images/negate.png','neg_%ATTR%_%KEY%');
328         $option.= image('images/lists/trash.png', 'delS_%ATTR%_%KEY%');
329         foreach(array('sudoUser','sudoCommand','sudoHost','sudoRunAs') as $l){
330             $l.="Data";
331             $$l = array();
332         }
334         foreach(array("sudoCommand","sudoHost","sudoRunAs") as $attr){
335             $tmp =array();
336             $list = $attr."List";
337             $data = $attr."Data";
338             foreach($this->$attr as $id => $entry){
339                 $neg = "";
340                 if(preg_match("/^!/",$entry)){
341                     $neg = $neg_img;
342                 }
343                 $entry = preg_replace("/^!/","",$entry);
345                 $action =preg_replace(array("/%KEY%/","/%ATTR%/"),array($id,$attr),$option);
346                 $tmp[$id] = array('data'=>array($neg,$entry,$action)) ;
347             }
348             $this->$list->setListData($this->$attr, $tmp);
349             $this->$list->update();
350             $smarty->assign("listing_{$attr}", $this->$list->render());
351         }
354         $img1 = image('plugins/users/images/select_user.png','',_("User"));
355         $img2 = image('plugins/groups/images/select_group.png','',_("Group"));
356         $sudoUserData  = array();
357         foreach($this->sudoUser as $id => $entry){
358             $neg = "";
359             if(preg_match("/^!/",$entry)){
360                 $neg = $neg_img;
361             }
362             $entry = preg_replace("/^!/","",$entry);
364             $img = $img1;
365             if(preg_match("/^%/",$entry)){
366                 $img = $img2;
367             }
368             $entry = preg_replace("/^%/","",$entry);
369             $action =preg_replace(array("/%KEY%/","/%ATTR%/"),array($id,'sudoUser'),$option);
370             $sudoUserData[$id] = array('data'=>array($neg,$img,$entry,$action)) ;
371         }
372         $this->sudoUserList->setListData($this->sudoUser,$sudoUserData);
373         $this->sudoUserList->update();
374         $smarty->assign("listing_sudoUser", $this->sudoUserList->render());
375         return($smarty->fetch(get_template_path('generic.tpl', TRUE)));
376     }
379     /*! \brief  Remove this sudo role from the ldap server 
380      */
381     function remove_from_parent()
382     {
383         plugin::remove_from_parent();
385         $ldap = $this->config->get_ldap_link();
386         $ldap->cd($this->dn);
387         $ldap->rmdir($this->dn);
389         /* Send signal to the world that we've done */
390         $this->handle_post_events("remove");
391     }
394     /*! \brief  Save all relevant HTML posts. 
395      */
396     function save_object()
397     {
398         plugin::save_object();
399         $this->trustModeDialog->save_object();
401         if($this->is_default){
402             $this->cn = "defaults";
403         }  
404     }
407     function set_acl_base($base)
408     {
409         plugin::set_acl_base($base); 
410         $this->trustModeDialog->set_acl_base($base);
411     }
414     /*! \brief  Save changes into the ldap database.
415      */
416     function save()
417     {
418         plugin::save();
420         /* Ensure a correct array index 
421          */ 
422         $this->attrs['sudoHost']    = array_values($this->attrs['sudoHost']);
423         $this->attrs['sudoRunAs']   = array_values($this->attrs['sudoRunAs']);
424         $this->attrs['sudoUser']    = array_values($this->attrs['sudoUser']);
425         $this->attrs['sudoCommand'] = array_values($this->attrs['sudoCommand']);
427         $this->cleanup();
429         $ldap = $this->config->get_ldap_link();
430         $ldap->cd($this->config->current['BASE']);
432         if($this->is_new){
433             $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
434             $ldap->cd($this->dn);
435             $ldap->add($this->attrs);
437             /* Send signal to the world that we've done */
438             $this->handle_post_events("create");
439         }else{
440             $ldap->cd($this->dn);
441             $ldap->modify($this->attrs);;
443             /* Send signal to the world that we've done */
444             $this->handle_post_events("modify");
445         }
446         $this->trustModeDialog->dn = $this->dn;
447         $this->trustModeDialog->save();
449         if (!$ldap->success()){
450             msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
451         }
452     }
455     /*! \brief  Check the given input.
456       @return Array   All error messages in an array();
457      */
458     function check()
459     {
460         $message = plugin::check();
462         /* Is a name given? */
463         if($this->cn == ""){
464             $message[] = msgPool::required(_("Name"));
465         }
467         /* Check if name is reserved */
468         if(!$this->is_default && preg_match("/^defaults$/i",$this->cn)){
469             $message[] = msgPool::reserved(_("Name"));
470         }
472         /* Check name */
473         if(!preg_match("/^[0-9a-z\@]*$/i",$this->cn)){
474             $message[] = msgPool::invalid(_("Name"),$this->cn,"/[0-9a-z\@]/i");
475         }
477         /* Check if this entry will cause duplicated ldap entries */
478         $ldap = $this->config->get_ldap_link();
479         $ldap->cd($this->get_sudoers_ou($this->config));
480         $ldap->search("(&(objectClass=sudoRole)(cn=".$this->cn."))");
481         while($attrs = $ldap->fetch()){
482             if($attrs['dn'] != $this->dn){
483                 $message[] = msgPool::duplicated(_("Name"));
484             }
485         }
487         /* Check if we are allowed to create or move this object
488          */
489         if($this->orig_dn == "new" && !$this->acl_is_createable($this->get_sudoers_ou($this->config))){
490             $message[] = msgPool::permCreate();
491         }
493         return ($message);
494     }
497     /*! \brief Force this entry to be handled and saved as 'default'
498       @param  BOOL  TRUE -force defaults   FALSE -normal
499      */
500     public function set_default($state)
501     {
502         $this->is_default = TRUE;
503         $this->cn = "defaults";
504     }
507     /*! \brief  Add ACL object
508       @return Returns the ACL object.
509      */
510     static function plInfo()
511     {
512         return (array(  
513                     "plShortName" => _("Sudo"),
514                     "plDescription" => _("Sudo role"),
515                     "plSelfModify"  => FALSE,
516                     "plDepends"     => array(),
517                     "plPriority"    => 0,
518                     "plSection"     => array("administration"),
519                     "plCategory"    => array("sudo" => array("objectClass" => "sudoRole", "description" => _("Sudo role"))),
520                 
521                     "plProperties" => 
522                     array(
523                         array(
524                             "name"          => "sudoRDN",
525                             "type"          => "rdn",
526                             "default"       => "ou=sudoers,",
527                             "description"   => "The 'sudoRDN' statement defines the location where new sudo-roles will be created. The default is 'ou=sudoers,'.",
528                             "check"         => "gosaProperty::isRdn",
529                             "migrate"       => "migrate_sudoRDN",
530                             "group"         => "plugin",
531                             "mandatory"     => FALSE)),
534                     "plProvidedAcls"    => array(
535                         "accessTo"          => _("System trust"),
536                         "cn"                => _("Name"),
537                         "description"       => _("Description"),
538                         "sudoUser"          => _("Users"),
539                         "sudoHost"          => _("Host"),
540                         "sudoCommand"       => _("Command"),
541                         "sudoRunAs"         => _("Run as user"),
542                         "trustModel"        => _("Access control list"))
543                     ));
544     }
547     /*! \brief  This function will be called if an object gets copied.
548       This function adapts attributes from the source object.
549       @param  Array The source object.
550      */
551     function PrepareForCopyPaste($source)
552     {
553         plugin::PrepareForCopyPaste($source);
554         
555         $this->trustModeDialog->PrepareForCopyPaste($source);
557         foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
558             $this->$attr = array();
559             if(isset($source[$attr])){
560                 $tmp = array();
561                 for($i = 0 ; $i < $source[$attr]['count']; $i++){
562                     $tmp[] = $source[$attr][$i];
563                 }
564                 $this->$attr = $tmp;
565             }
566         }
567     }
570     /*! \brief  Used for copy & paste.
571       Returns a HTML input mask, which allows to change the cn of this entry.
572       @param  Array   Array containing current status && a HTML template.              
573      */
574     function getCopyDialog()
575     {
576         $vars = array("cn");
577         $smarty = get_smarty();
578         $smarty->assign("cn", htmlentities($this->cn));
579         $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE));
580         $ret = array();
581         $ret['string'] = $str;
582         $ret['status'] = "";
583         return($ret);
584     }
587     public function get_cn()
588     {
589         return($this->cn);
590     }
593     /*! \brief  Used for copy & paste.
594       Some entries must be renamed to avaoid duplicate entries.
595      */
596     function saveCopyDialog()
597     {
598         if(isset($_POST['cn'])){
599             $this->cn = get_post('cn');
600         }
601     }
603 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
604 ?>