1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2003 Cajus Pollmeier
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 /*! \brief The plugin base class
22 \author Cajus Pollmeier <pollmeier@gonicus.de>
23 \version 2.00
24 \date 24.07.2003
26 This is the base class for all plugins. It can be used standalone or
27 can be included by the tabs class. All management should be done
28 within this class. Extend your plugins from this class.
29 */
31 class plugin
32 {
33 /*!
34 \brief Reference to parent object
36 This variable is used when the plugin is included in tabs
37 and keeps reference to the tab class. Communication to other
38 tabs is possible by 'name'. So the 'fax' plugin can ask the
39 'userinfo' plugin for the fax number.
41 \sa tab
42 */
43 var $parent= NULL;
45 /*!
46 \brief Configuration container
48 Access to global configuration
49 */
50 var $config= NULL;
52 /*!
53 \brief Mark plugin as account
55 Defines whether this plugin is defined as an account or not.
56 This has consequences for the plugin to be saved from tab
57 mode. If it is set to 'FALSE' the tab will call the delete
58 function, else the save function. Should be set to 'TRUE' if
59 the construtor detects a valid LDAP object.
61 \sa plugin::plugin()
62 */
63 var $is_account= FALSE;
64 var $initially_was_account= FALSE;
66 /*!
67 \brief Mark plugin as template
69 Defines whether we are creating a template or a normal object.
70 Has conseqences on the way execute() shows the formular and how
71 save() puts the data to LDAP.
73 \sa plugin::save() plugin::execute()
74 */
75 var $is_template= FALSE;
76 var $ignore_account= FALSE;
77 var $is_modified= FALSE;
79 /*!
80 \brief Represent temporary LDAP data
82 This is only used internally.
83 */
84 var $attrs= array();
87 /*!
88 \brief Used standard values
90 dn
91 */
92 var $dn= "";
93 var $uid= "";
94 var $sn= "";
95 var $givenName= "";
96 var $acl= "*none*";
97 var $dialog= FALSE;
99 /* attribute list for save action */
100 var $attributes= array();
101 var $objectclasses= array();
102 var $new= TRUE;
104 /*! \brief plugin constructor
106 If 'dn' is set, the node loads the given 'dn' from LDAP
108 \param dn Distinguished name to initialize plugin from
109 \sa plugin()
110 */
111 function plugin ($config, $dn= NULL)
112 {
113 /* Configuration is fine, allways */
114 $this->config= $config;
115 $this->dn= $dn;
117 /* Handle new accounts, don't read information from LDAP */
118 if ($dn == "new"){
119 return;
120 }
122 /* Get LDAP descriptor */
123 $ldap= $this->config->get_ldap_link();
124 if ($dn != NULL){
126 /* Load data to 'attrs' and save 'dn' */
127 $ldap->cat ($dn);
128 $this->attrs= $ldap->fetch();
130 /* Copy needed attributes */
131 foreach ($this->attributes as $val){
132 if (isset($this->attrs["$val"][0])){
133 $this->$val= $this->attrs["$val"][0];
134 }
135 }
137 /* Set the template flag according to the existence of objectClass
138 gosaUserTemplate */
139 if (isset($this->attrs['objectClass'])){
140 if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
141 $this->is_template= TRUE;
142 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
143 "found", "Template check");
144 }
145 }
147 /* Is Account? */
148 error_reporting(0);
149 $found= TRUE;
150 foreach ($this->objectclasses as $obj){
151 if (preg_match('/top/i', $obj)){
152 continue;
153 }
154 if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
155 $found= FALSE;
156 break;
157 }
158 }
159 error_reporting(E_ALL);
160 if ($found){
161 $this->is_account= TRUE;
162 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
163 "found", "Object check");
164 }
165 }
167 /* Save initial account state */
168 $this->initially_was_account= $this->is_account;
169 }
171 /*! \brief execute plugin
173 Generates the html output for this node
174 */
175 function execute()
176 {
177 # This one is empty currently. Fabian - please fill in the docu code
178 }
180 /* remove object from parent */
181 function remove_from_parent()
182 {
183 /* include global link_info */
184 $ldap= $this->config->get_ldap_link();
186 /* Get current objectClasses in order to add the required ones */
187 $ldap->cat($this->dn);
188 $tmp= $ldap->fetch ();
189 if (isset($tmp['objectClass'])){
190 $oc= $tmp['objectClass'];
191 } else {
192 $oc= array("count" => 0);
193 }
195 /* Remove objectClasses from entry */
196 $ldap->cd($this->dn);
197 $this->attrs= array();
198 $this->attrs['objectClass']= array();
199 for ($i= 0; $i<$oc["count"]; $i++){
200 if (!in_array_ics($oc[$i], $this->objectclasses)){
201 $this->attrs['objectClass'][]= $oc[$i];
202 }
203 }
205 /* Unset attributes from entry */
206 foreach ($this->attributes as $val){
207 $this->attrs["$val"]= array();
208 }
210 /* Unset account info */
211 $this->is_account= FALSE;
213 /* Do not write in plugin base class, this must be done by
214 children, since there are normally additional attribs,
215 lists, etc. */
216 /*
217 $ldap->modify($this->attrs);
218 */
219 }
222 /* Save data to object */
223 function save_object()
224 {
225 /* Save values to object */
226 foreach ($this->attributes as $val){
227 if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
228 /* Check for modifications */
229 if (get_magic_quotes_gpc()) {
230 $data= stripcslashes($_POST["$val"]);
231 } else {
232 $data= $this->$val = $_POST["$val"];
233 }
234 if ($this->$val != $data){
235 $this->is_modified= TRUE;
236 }
238 /* Okay, how can I explain this fix ...
239 * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds.
240 * So IE posts these 'unselectable' option, with value = chr(194)
241 * chr(194) seems to be the in between the ...option> </option.. because there is no value=".." specified in these option fields
242 * This was added for W3c compliance, but now causes these ... ldap errors ...
243 * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
244 */
245 if(isset($data[0]) && $data[0] == chr(194)) {
246 $data = "";
247 }
248 $this->$val= $data;
249 }
250 }
251 }
254 /* Save data to LDAP, depending on is_account we save or delete */
255 function save()
256 {
257 /* include global link_info */
258 $ldap= $this->config->get_ldap_link();
260 /* Start with empty array */
261 $this->attrs= array();
263 /* Get current objectClasses in order to add the required ones */
264 $ldap->cat($this->dn);
266 $tmp= $ldap->fetch ();
268 if (isset($tmp['objectClass'])){
269 $oc= $tmp["objectClass"];
270 $this->new= FALSE;
271 } else {
272 $oc= array("count" => 0);
273 $this->new= TRUE;
274 }
276 /* Load (minimum) attributes, add missing ones */
277 $this->attrs['objectClass']= $this->objectclasses;
278 for ($i= 0; $i<$oc["count"]; $i++){
279 if (!in_array_ics($oc[$i], $this->objectclasses)){
280 $this->attrs['objectClass'][]= $oc[$i];
281 }
282 }
284 /* Copy standard attributes */
285 foreach ($this->attributes as $val){
286 if ($this->$val != ""){
287 $this->attrs["$val"]= $this->$val;
288 } elseif (!$this->new) {
289 $this->attrs["$val"]= array();
290 }
291 }
293 }
295 /* Check formular input */
296 function check()
297 {
298 $message= array();
299 return ($message);
300 }
302 /* Adapt from template, using 'dn' */
303 function adapt_from_template($dn)
304 {
305 /* Include global link_info */
306 $ldap= $this->config->get_ldap_link();
308 /* Load requested 'dn' to 'attrs' */
309 $ldap->cat ($dn);
310 $this->attrs= $ldap->fetch();
312 /* Walk through attributes */
313 foreach ($this->attributes as $val){
315 if (isset($this->attrs["$val"][0])){
317 /* If attribute is set, replace dynamic parts:
318 %sn, %givenName and %uid. Fill these in our local variables. */
319 $value= $this->attrs["$val"][0];
321 foreach (array("sn", "givenName", "uid") as $repl){
322 if (preg_match("/%$repl/i", $value)){
323 $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
324 }
325 }
326 $this->$val= $value;
327 }
328 }
330 /* Is Account? */
331 $found= TRUE;
332 foreach ($this->objectclasses as $obj){
333 if (preg_match('/top/i', $obj)){
334 continue;
335 }
336 if (!in_array_ics ($obj, $this->attrs['objectClass'])){
337 $found= FALSE;
338 break;
339 }
340 }
341 if ($found){
342 $this->is_account= TRUE;
343 }
344 }
346 /* Indicate whether a password change is needed or not */
347 function password_change_needed()
348 {
349 return FALSE;
350 }
352 /* Show header message for tab dialogs */
353 function show_header($button_text, $text, $disabled= FALSE)
354 {
355 if ($disabled == TRUE){
356 $state= "disabled";
357 } else {
358 $state= "";
359 }
360 $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
361 $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".
362 chkacl($this->acl, "all")." ".$state.
363 "><p class=\"seperator\"> </p></td></tr></table>";
365 return($display);
366 }
368 function postcreate()
369 {
370 /* Find postcreate entries for this class */
371 $command= search_config($this->config->data['MENU'], get_class($this), "POSTCREATE");
372 if ($command == "" && isset($this->config->data['TABS'])){
373 $command= search_config($this->config->data['TABS'], get_class($this), "POSTCREATE");
374 }
376 if ($command != ""){
377 /* Walk through attribute list */
378 foreach ($this->attributes as $attr){
379 if (!is_array($this->$attr)){
380 $command= preg_replace("/%$attr/", $this->$attr, $command);
381 }
382 }
383 $command= preg_replace("/%dn/", $this->dn, $command);
384 if (check_command($command)){
385 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
386 $command, "Execute");
388 exec($command);
389 } else {
390 $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
391 print_red ($message);
392 }
393 }
394 }
396 function postmodify()
397 {
398 /* Find postcreate entries for this class */
399 $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
400 if ($command == "" && isset($this->config->data['TABS'])){
401 $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
402 }
404 if ($command != ""){
405 /* Walk through attribute list */
406 foreach ($this->attributes as $attr){
407 if (!is_array($this->$attr)){
408 $command= preg_replace("/%$attr/", $this->$attr, $command);
409 }
410 }
411 $command= preg_replace("/%dn/", $this->dn, $command);
412 if (check_command($command)){
413 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
414 $command, "Execute");
416 exec($command);
417 } else {
418 $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
419 print_red ($message);
420 }
421 }
422 }
424 function postremove()
425 {
426 /* Find postremove entries for this class */
427 $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
428 if ($command == "" && isset($this->config->data['TABS'])){
429 $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
430 }
432 if ($command != ""){
433 /* Walk through attribute list */
434 foreach ($this->attributes as $attr){
435 if (!is_array($this->$attr)){
436 $command= preg_replace("/%$attr/", $this->$attr, $command);
437 }
438 }
439 $command= preg_replace("/%dn/", $this->dn, $command);
440 if (check_command($command)){
441 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
442 $command, "Execute");
444 exec($command);
445 } else {
446 $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
447 print_red ($message);
448 }
449 }
450 }
452 /* Create unique DN */
453 function create_unique_dn($attribute, $base)
454 {
455 $ldap= $this->config->get_ldap_link();
456 $base= preg_replace("/^,*/", "", $base);
458 /* Try to use plain entry first */
459 $dn= "$attribute=".$this->$attribute.",$base";
460 $ldap->cat ($dn);
461 if (!$ldap->fetch()){
462 return ($dn);
463 }
465 /* Look for additional attributes */
466 foreach ($this->attributes as $attr){
467 if ($attr == $attribute || $this->$attr == ""){
468 continue;
469 }
471 $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
472 $ldap->cat ($dn);
473 if (!$ldap->fetch()){
474 return ($dn);
475 }
476 }
478 /* None found */
479 return ("none");
480 }
482 function rebind($ldap, $referral)
483 {
484 $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
485 if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
486 $this->error = "Success";
487 $this->hascon=true;
488 $this->reconnect= true;
489 return (0);
490 } else {
491 $this->error = "Could not bind to " . $credentials['ADMIN'];
492 return NULL;
493 }
494 }
496 /* This is a workaround function. */
497 function copy($src_dn, $dst_dn)
498 {
499 /* Rename dn in possible object groups */
500 $ldap= $this->config->get_ldap_link();
501 $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.$src_dn.'))',
502 array('cn'));
503 while ($attrs= $ldap->fetch()){
504 $og= new ogroup($this->config, $ldap->getDN());
505 unset($og->member[$src_dn]);
506 $og->member[$dst_dn]= $dst_dn;
507 $og->save ();
508 }
510 $ldap->cat($dst_dn);
511 $attrs= $ldap->fetch();
512 if (count($attrs)){
513 trigger_error("Trying to overwrite $dst_dn, which already exists.",
514 E_USER_WARNING);
515 return (FALSE);
516 }
518 $ldap->cat($src_dn);
519 $attrs= array();
520 $attrs= $ldap->fetch();
521 if (!count($attrs)){
522 trigger_error("Trying to move $src_dn, which does not seem to exist.",
523 E_USER_WARNING);
524 return (FALSE);
525 }
527 /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
528 $ds= ldap_connect($this->config->current['SERVER']);
529 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
530 if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
531 ldap_set_rebind_proc($ds, array(&$this, "rebind"));
532 }
534 $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
535 error_reporting (0);
536 $sr=ldap_read($ds, $src_dn, "objectClass=*");
538 /* Fill data from LDAP */
539 $new= array();
540 if ($sr) {
541 $ei=ldap_first_entry($ds, $sr);
542 if ($ei) {
543 foreach($attrs as $attr => $val){
544 if ($info = ldap_get_values_len($ds, $ei, $attr)){
545 for ($i= 0; $i<$info['count']; $i++){
546 if ($info['count'] == 1){
547 $new[$attr]= $info[$i];
548 } else {
549 $new[$attr][]= $info[$i];
550 }
551 }
552 }
553 }
554 }
555 }
557 /* close conncetion */
558 error_reporting (E_ALL);
559 ldap_unbind($ds);
561 /* Adapt naming attribute */
562 $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
563 $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
564 $new[$dst_name]= $dst_val;
566 /* Save copy */
567 $ldap->connect();
568 $ldap->cd($this->config->current['BASE']);
569 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
570 $ldap->cd($dst_dn);
571 $ldap->add($new);
573 if ($ldap->error != "Success"){
574 trigger_error("Trying to save $dst_dn failed.",
575 E_USER_WARNING);
576 return(FALSE);
577 }
579 return (TRUE);
580 }
583 function move($src_dn, $dst_dn)
584 {
585 /* Copy source to destination */
586 if (!$this->copy($src_dn, $dst_dn)){
587 return (FALSE);
588 }
590 /* Delete source */
591 $ldap= $this->config->get_ldap_link();
592 $ldap->rmdir($src_dn);
593 if ($ldap->error != "Success"){
594 trigger_error("Trying to delete $src_dn failed.",
595 E_USER_WARNING);
596 return (FALSE);
597 }
599 return (TRUE);
600 }
603 /* Move/Rename complete trees */
604 function recursive_move($src_dn, $dst_dn)
605 {
606 /* Check if the destination entry exists */
607 $ldap= $this->config->get_ldap_link();
609 /* Check if destination exists - abort */
610 $ldap->cat($dst_dn);
611 if ($ldap->fetch()){
612 trigger_error("recursive_move $dst_dn already exists.",
613 E_USER_WARNING);
614 return (FALSE);
615 }
617 /* Perform a search for all objects to be moved */
618 $objects= array();
619 $ldap->cd($src_dn);
620 $ldap->search("(objectClass=*)", array("dn"));
621 while($attrs= $ldap->fetch()){
622 $dn= $attrs['dn'];
623 $objects[$dn]= strlen($dn);
624 }
626 /* Sort objects by indent level */
627 asort($objects);
628 reset($objects);
630 /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
631 foreach ($objects as $object => $len){
632 $src= $object;
633 $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
634 if (!$this->copy($src, $dst)){
635 return (FALSE);
636 }
637 }
639 /* Remove src_dn */
640 $ldap->cd($src_dn);
641 $ldap->recursive_remove();
642 return (TRUE);
643 }
646 function handle_post_events($mode)
647 {
648 switch ($mode){
649 case "add":
650 $this->postcreate();
651 break;
653 case "modify":
654 $this->postmodify();
655 break;
657 case "remove":
658 $this->postremove();
659 break;
660 }
661 }
664 }
666 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
667 ?>