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 *********************/
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 }
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 *********************/
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 }
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 *********************/
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 }
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);
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 }
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 }
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);
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);
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();
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 }
679 }
680 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
681 ?>