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"))),
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);
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 }
602 }
603 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
604 ?>