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("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])){
286 if(preg_match("/^[a-z\.0-9]*$/i",$_POST['new_'.$attr])){
287 $attrs = $this->$attr;
288 $attrs[] = trim($_POST['new_'.$attr]);
289 $this->$attr = $attrs;
290 }else{
291 msg_dialog::display(_("Error"),msgPool::invalid($attr,$_POST['new_'.$attr],"/[a-z0-9]/"));
292 }
293 }
294 }
296 /* Command */
297 foreach(array("sudoCommand") as $attr){
298 if($this->acl_is_writeable($attr) && isset($_POST["add_".$attr]) && isset($_POST['new_'.$attr])){
299 $attrs = $this->$attr;
300 $attrs[] = trim($_POST['new_'.$attr]);
301 $this->$attr = $attrs;
302 }
303 }
306 /*********************
307 SMARTY assignments
308 *********************/
310 $smarty = get_smarty();
311 $smarty->assign("trustModeDialog" , $trustModeDialog);
312 $smarty->assign("is_default",$this->is_default);
313 foreach($this->attributes as $attr){
314 if(is_string($this->$attr)){
315 $smarty->assign($attr,htmlentities($this->$attr));
316 }else{
317 $smarty->assign($attr,$this->$attr);
318 }
319 $smarty->assign($attr."ACL",$this->getacl($attr));
320 }
322 /* Fill listings
323 */
324 $neg_img= image('plugins/sudo/images/negate.png','','!');
325 $option = image('plugins/sudo/images/negate.png','neg_%ATTR%_%KEY%');
326 $option.= image('images/lists/trash.png', 'delS_%ATTR%_%KEY%');
327 foreach(array('sudoUser','sudoCommand','sudoHost','sudoRunAs') as $l){
328 $l.="Data";
329 $$l = array();
330 }
332 foreach(array("sudoCommand","sudoHost","sudoRunAs") as $attr){
333 $tmp =array();
334 $list = $attr."List";
335 $data = $attr."Data";
336 foreach($this->$attr as $id => $entry){
337 $neg = "";
338 if(preg_match("/^!/",$entry)){
339 $neg = $neg_img;
340 }
341 $entry = preg_replace("/^!/","",$entry);
343 $action =preg_replace(array("/%KEY%/","/%ATTR%/"),array($id,$attr),$option);
344 $tmp[$id] = array('data'=>array($neg,$entry,$action)) ;
345 }
346 $this->$list->setListData($this->$attr, $tmp);
347 $this->$list->update();
348 $smarty->assign("listing_{$attr}", $this->$list->render());
349 }
352 $img1 = image('plugins/users/images/select_user.png','',_("User"));
353 $img2 = image('plugins/groups/images/select_group.png','',_("Group"));
354 $sudoUserData = array();
355 foreach($this->sudoUser as $id => $entry){
356 $neg = "";
357 if(preg_match("/^!/",$entry)){
358 $neg = $neg_img;
359 }
360 $entry = preg_replace("/^!/","",$entry);
362 $img = $img1;
363 if(preg_match("/^%/",$entry)){
364 $img = $img2;
365 }
366 $entry = preg_replace("/^%/","",$entry);
367 $action =preg_replace(array("/%KEY%/","/%ATTR%/"),array($id,'sudoUser'),$option);
368 $sudoUserData[$id] = array('data'=>array($neg,$img,$entry,$action)) ;
369 }
370 $this->sudoUserList->setListData($this->sudoUser,$sudoUserData);
371 $this->sudoUserList->update();
372 $smarty->assign("listing_sudoUser", $this->sudoUserList->render());
373 return($smarty->fetch(get_template_path('generic.tpl', TRUE)));
374 }
377 /*! \brief Remove this sudo role from the ldap server
378 */
379 function remove_from_parent()
380 {
381 plugin::remove_from_parent();
383 $ldap = $this->config->get_ldap_link();
384 $ldap->cd($this->dn);
385 $ldap->rmdir($this->dn);
387 /* Send signal to the world that we've done */
388 $this->handle_post_events("remove");
389 }
392 /*! \brief Save all relevant HTML posts.
393 */
394 function save_object()
395 {
396 plugin::save_object();
397 $this->trustModeDialog->save_object();
399 if($this->is_default){
400 $this->cn = "defaults";
401 }
402 }
405 function set_acl_base($base)
406 {
407 plugin::set_acl_base($base);
408 $this->trustModeDialog->set_acl_base($base);
409 }
412 /*! \brief Save changes into the ldap database.
413 */
414 function save()
415 {
416 plugin::save();
418 /* Ensure a correct array index
419 */
420 $this->attrs['sudoHost'] = array_values($this->attrs['sudoHost']);
421 $this->attrs['sudoRunAs'] = array_values($this->attrs['sudoRunAs']);
422 $this->attrs['sudoUser'] = array_values($this->attrs['sudoUser']);
423 $this->attrs['sudoCommand'] = array_values($this->attrs['sudoCommand']);
425 $this->cleanup();
427 $ldap = $this->config->get_ldap_link();
428 $ldap->cd($this->config->current['BASE']);
430 if($this->is_new){
431 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
432 $ldap->cd($this->dn);
433 $ldap->add($this->attrs);
435 /* Send signal to the world that we've done */
436 $this->handle_post_events("create");
437 }else{
438 $ldap->cd($this->dn);
439 $ldap->modify($this->attrs);;
441 /* Send signal to the world that we've done */
442 $this->handle_post_events("modify");
443 }
444 $this->trustModeDialog->dn = $this->dn;
445 $this->trustModeDialog->save();
447 if (!$ldap->success()){
448 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_DEL, get_class()));
449 }
450 }
453 /*! \brief Check the given input.
454 @return Array All error messages in an array();
455 */
456 function check()
457 {
458 $message = plugin::check();
460 /* Is a name given? */
461 if($this->cn == ""){
462 $message[] = msgPool::required(_("Name"));
463 }
465 /* Check if name is reserved */
466 if(!$this->is_default && preg_match("/^defaults$/i",$this->cn)){
467 $message[] = msgPool::reserved(_("Name"));
468 }
470 /* Check name */
471 if(!preg_match("/^[0-9a-z\@]*$/i",$this->cn)){
472 $message[] = msgPool::invalid(_("Name"),$this->cn,"/[0-9a-z\@]/i");
473 }
475 /* Check if this entry will cause duplicated ldap entries */
476 $ldap = $this->config->get_ldap_link();
477 $ldap->cd($this->get_sudoers_ou($this->config));
478 $ldap->search("(&(objectClass=sudoRole)(cn=".$this->cn."))");
479 while($attrs = $ldap->fetch()){
480 if($attrs['dn'] != $this->dn){
481 $message[] = msgPool::duplicated(_("Name"));
482 }
483 }
485 /* Check if we are allowed to create or move this object
486 */
487 if($this->orig_dn == "new" && !$this->acl_is_createable($this->get_sudoers_ou($this->config))){
488 $message[] = msgPool::permCreate();
489 }
491 return ($message);
492 }
495 /*! \brief Force this entry to be handled and saved as 'default'
496 @param BOOL TRUE -force defaults FALSE -normal
497 */
498 public function set_default($state)
499 {
500 $this->is_default = TRUE;
501 $this->cn = "defaults";
502 }
505 /*! \brief Add ACL object
506 @return Returns the ACL object.
507 */
508 static function plInfo()
509 {
510 return (array(
511 "plShortName" => _("Sudo"),
512 "plDescription" => _("Sudo role"),
513 "plSelfModify" => FALSE,
514 "plDepends" => array(),
515 "plPriority" => 0,
516 "plSection" => array("administration"),
517 "plCategory" => array("sudo" => array("objectClass" => "sudoRole", "description" => _("Sudo role"))),
519 "plProvidedAcls" => array(
520 "accessTo" => _("System trust"),
521 "cn" => _("Name"),
522 "description" => _("Description"),
523 "sudoUser" => _("Users"),
524 "sudoHost" => _("Host"),
525 "sudoCommand" => _("Command"),
526 "sudoRunAs" => _("Run as user"),
527 "trustModel" => _("Access control list"))
528 ));
529 }
532 /*! \brief This function will be called if an object gets copied.
533 This function adapts attributes from the source object.
534 @param Array The source object.
535 */
536 function PrepareForCopyPaste($source)
537 {
538 plugin::PrepareForCopyPaste($source);
540 $this->trustModeDialog->PrepareForCopyPaste($source);
542 foreach(array("sudoUser","sudoCommand","sudoHost","sudoRunAs") as $attr){
543 $this->$attr = array();
544 if(isset($source[$attr])){
545 $tmp = array();
546 for($i = 0 ; $i < $source[$attr]['count']; $i++){
547 $tmp[] = $source[$attr][$i];
548 }
549 $this->$attr = $tmp;
550 }
551 }
552 }
555 /*! \brief Used for copy & paste.
556 Returns a HTML input mask, which allows to change the cn of this entry.
557 @param Array Array containing current status && a HTML template.
558 */
559 function getCopyDialog()
560 {
561 $vars = array("cn");
562 $smarty = get_smarty();
563 $smarty->assign("cn", htmlentities($this->cn));
564 $str = $smarty->fetch(get_template_path("paste_generic.tpl",TRUE));
565 $ret = array();
566 $ret['string'] = $str;
567 $ret['status'] = "";
568 return($ret);
569 }
572 public function get_cn()
573 {
574 return($this->cn);
575 }
578 /*! \brief Used for copy & paste.
579 Some entries must be renamed to avaoid duplicate entries.
580 */
581 function saveCopyDialog()
582 {
583 if(isset($_POST['cn'])){
584 $this->cn = get_post('cn');
585 }
586 }
587 }
588 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
589 ?>