b01dd99e9346e7a66dabd1de5e8d844bc17529ab
1 <?php
2 /*****************************************************************************
3 newldap.inc - version 1.0
4 Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
5 Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
7 Based in code of ldap.inc of
8 Copyright (C) 1998 Eric Kilfoil <eric@ipass.net>
9 *****************************************************************************/
11 define("ALREADY_EXISTING_ENTRY",-10001);
12 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
13 define("NO_FILE_UPLOADED",10003);
14 define("INSERT_OK",10000);
15 define("SPECIALS_OVERRIDE", TRUE);
17 class LDAP{
19 var $hascon =false;
20 var $hasres =false;
21 var $reconnect=false;
22 var $tls = false;
23 var $basedn ="";
24 var $cid;
25 var $error = ""; // Any error messages to be returned can be put here
26 var $start = 0; // 0 if we are fetching the first entry, otherwise 1
27 var $objectClasses = array(); // Information read from slapd.oc.conf
28 var $binddn = "";
29 var $bindpw = "";
30 var $hostname = "";
31 var $follow_referral = FALSE;
32 var $referrals= array();
33 var $max_ldap_query_time = 0; // 0, empty or negative values will disable this check
35 function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
36 {
37 global $config;
38 $this->follow_referral= $follow_referral;
39 $this->tls=$tls;
40 $this->binddn=$this->convert($binddn);
42 $this->bindpw=$bindpw;
43 $this->hostname=$hostname;
45 /* Check if MAX_LDAP_QUERY_TIME is defined */
46 if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){
47 $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME'];
48 $this->max_ldap_query_time = (float)($str);
49 }
51 $this->connect();
52 }
55 /* Function to replace all problematic characters inside a DN by \001XX, where
56 \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely
57 that this character is inside a DN.
59 Currently used codes:
60 , => CO
61 \2C => CO
62 ( => OB
63 ) => CB
64 / => SL */
65 function convert($dn)
66 {
67 if (SPECIALS_OVERRIDE == TRUE){
68 $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
69 array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
70 $dn);
71 return (preg_replace('/,\s+/', ',', $tmp));
72 } else {
73 return ($dn);
74 }
75 }
78 /* Function to fix all problematic characters inside a DN by replacing \001XX
79 codes to their original values. See "convert" for mor information.
80 ',' characters are always expanded to \, (not \2C), since all tested LDAP
81 servers seem to take it the correct way. */
82 function fix($dn)
83 {
84 if (SPECIALS_OVERRIDE == TRUE){
85 return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
86 array("\,", "(", ")", "/"),
87 $dn));
88 } else {
89 return ($dn);
90 }
91 }
94 function connect()
95 {
96 $this->hascon=false;
97 $this->reconnect=false;
98 if ($this->cid= @ldap_connect($this->hostname)) {
99 @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
100 if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
101 @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
102 @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
103 }
104 if (function_exists("ldap_start_tls") && $this->tls){
105 @ldap_start_tls($this->cid);
106 }
108 $this->error = "No Error";
109 if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
110 $this->error = "Success";
111 $this->hascon=true;
112 } else {
113 if ($this->reconnect){
114 if ($this->error != "Success"){
115 $this->error = "Could not rebind to " . $this->binddn;
116 }
117 } else {
118 $this->error = "Could not bind to " . $this->binddn;
119 }
120 }
121 } else {
122 $this->error = "Could not connect to LDAP server";
123 }
124 }
126 function rebind($ldap, $referral)
127 {
128 $credentials= $this->get_credentials($referral);
129 if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
130 $this->error = "Success";
131 $this->hascon=true;
132 $this->reconnect= true;
133 return (0);
134 } else {
135 $this->error = "Could not bind to " . $credentials['ADMIN'];
136 return NULL;
137 }
138 }
140 function reconnect()
141 {
142 if ($this->reconnect){
143 @ldap_unbind($this->cid);
144 $this->cid = NULL;
145 }
146 }
148 function unbind()
149 {
150 @ldap_unbind($this->cid);
151 $this->cid = NULL;
152 }
154 function disconnect()
155 {
156 if($this->hascon){
157 @ldap_close($this->cid);
158 $this->hascon=false;
159 }
160 }
162 function cd($dir)
163 {
164 if ($dir == "..")
165 $this->basedn = $this->getParentDir();
166 else
167 $this->basedn = $this->convert($dir);
168 }
170 function getParentDir($basedn = "")
171 {
172 if ($basedn=="")
173 $basedn = $this->basedn;
174 else
175 $basedn = $this->convert($this->basedn);
176 return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
177 }
179 function search($filter, $attrs= array())
180 {
181 if($this->hascon){
182 if ($this->reconnect) $this->connect();
184 $start = microtime();
186 $this->clearResult();
187 $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
188 $this->error = @ldap_error($this->cid);
189 $this->resetResult();
190 $this->hasres=true;
192 /* Check if query took longer as specified in max_ldap_query_time */
193 if($this->max_ldap_query_time){
194 $diff = get_MicroTimeDiff($start,microtime());
195 if($diff > $this->max_ldap_query_time){
196 print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
197 }
198 }
200 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
202 return($this->sr);
203 }else{
204 $this->error = "Could not connect to LDAP server";
205 return("");
206 }
207 }
209 function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
210 {
211 if($this->hascon){
212 if ($this->reconnect) $this->connect();
213 $this->clearResult();
214 if ($basedn == "")
215 $basedn = $this->basedn;
216 else
217 $basedn= $this->convert($basedn);
219 $start = microtime();
221 $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
222 $this->error = @ldap_error($this->cid);
223 $this->resetResult();
224 $this->hasres=true;
226 /* Check if query took longer as specified in max_ldap_query_time */
227 if($this->max_ldap_query_time){
228 $diff = get_MicroTimeDiff($start,microtime());
229 if($diff > $this->max_ldap_query_time){
230 print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
231 }
232 }
234 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
236 return($this->sr);
237 }else{
238 $this->error = "Could not connect to LDAP server";
239 return("");
240 }
241 }
243 function cat($dn,$attrs= array("*"))
244 {
245 if($this->hascon){
246 if ($this->reconnect) $this->connect();
247 $start = microtime();
248 $this->clearResult();
249 $filter = "(objectclass=*)";
250 $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
251 $this->error = @ldap_error($this->cid);
252 $this->resetResult();
253 $this->hasres=true;
254 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
255 return($this->sr);
256 }else{
257 $this->error = "Could not connect to LDAP server";
258 return("");
259 }
260 }
262 function set_size_limit($size)
263 {
264 /* Ignore zero settings */
265 if ($size == 0){
266 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
267 }
268 if($this->hascon){
269 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
270 } else {
271 $this->error = "Could not connect to LDAP server";
272 }
273 }
275 function fetch()
276 {
277 $att= array();
278 if($this->hascon){
279 if($this->hasres){
280 if ($this->start == 0)
281 {
282 $this->start = 1;
283 $this->re= @ldap_first_entry($this->cid, $this->sr);
284 } else {
285 $this->re= @ldap_next_entry($this->cid, $this->re);
286 }
287 if ($this->re)
288 {
289 $att= @ldap_get_attributes($this->cid, $this->re);
290 $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
291 }
292 $this->error = @ldap_error($this->cid);
293 if (!isset($att)){
294 $att= array();
295 }
296 return($att);
297 }else{
298 $this->error = "Perform a Fetch with no Search";
299 return("");
300 }
301 }else{
302 $this->error = "Could not connect to LDAP server";
303 return("");
304 }
305 }
307 function resetResult()
308 {
309 $this->start = 0;
310 }
312 function clearResult()
313 {
314 if($this->hasres){
315 $this->hasres = false;
316 @ldap_free_result($this->sr);
317 }
318 }
320 function getDN()
321 {
322 if($this->hascon){
323 if($this->hasres){
325 if(!$this->re)
326 {
327 $this->error = "Perform a Fetch with no valid Result";
328 }
329 else
330 {
331 $rv = @ldap_get_dn($this->cid, $this->re);
333 $this->error = @ldap_error($this->cid);
334 return(trim($this->convert($rv)));
335 }
336 }else{
337 $this->error = "Perform a Fetch with no Search";
338 return("");
339 }
340 }else{
341 $this->error = "Could not connect to LDAP server";
342 return("");
343 }
344 }
346 function count()
347 {
348 if($this->hascon){
349 if($this->hasres){
350 $rv = @ldap_count_entries($this->cid, $this->sr);
351 $this->error = @ldap_error($this->cid);
352 return($rv);
353 }else{
354 $this->error = "Perform a Fetch with no Search";
355 return("");
356 }
357 }else{
358 $this->error = "Could not connect to LDAP server";
359 return("");
360 }
361 }
363 function rm($attrs = "", $dn = "")
364 {
365 if($this->hascon){
366 if ($this->reconnect) $this->connect();
367 if ($dn == "")
368 $dn = $this->basedn;
370 $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
371 $this->error = @ldap_error($this->cid);
372 return($r);
373 }else{
374 $this->error = "Could not connect to LDAP server";
375 return("");
376 }
377 }
379 function rename($attrs, $dn = "")
380 {
381 if($this->hascon){
382 if ($this->reconnect) $this->connect();
383 if ($dn == "")
384 $dn = $this->basedn;
386 $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
387 $this->error = @ldap_error($this->cid);
388 return($r);
389 }else{
390 $this->error = "Could not connect to LDAP server";
391 return("");
392 }
393 }
395 function rmdir($deletedn)
396 {
397 if($this->hascon){
398 if ($this->reconnect) $this->connect();
399 $start= microtime();
400 $r = @ldap_delete($this->cid, $this->fix($deletedn));
401 $this->error = @ldap_error($this->cid);
402 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
403 return($r ? $r : 0);
404 }else{
405 $this->error = "Could not connect to LDAP server";
406 return("");
407 }
408 }
410 /**
411 * Function rmdir_recursive
412 *
413 * Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
414 * Parameters: The dn to delete
415 * GiveBack: True on sucessfull , 0 in error, and "" when we don't get a ldap conection
416 *
417 */
419 function rmdir_recursive($deletedn)
420 {
421 if($this->hascon){
422 if ($this->reconnect) $this->connect();
423 $delarray= array();
425 /* Get sorted list of dn's to delete */
426 $this->ls ("(objectClass=*)",$deletedn);
427 while ($this->fetch()){
428 $deldn= $this->getDN();
429 $delarray[$deldn]= strlen($deldn);
430 }
431 arsort ($delarray);
432 reset ($delarray);
434 /* Really Delete ALL dn's in subtree */
435 foreach ($delarray as $key => $value){
436 $this->rmdir_recursive($key);
437 }
439 /* Finally Delete own Node */
440 $r = @ldap_delete($this->cid, $this->fix($deletedn));
441 $this->error = @ldap_error($this->cid);
442 return($r ? $r : 0);
443 }else{
444 $this->error = "Could not connect to LDAP server";
445 return("");
446 }
447 }
449 /* Copy given attributes and sub-dns with attributes to destination dn
450 */
451 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
452 {
453 error_reporting(E_ALL);
455 if($is_first){
456 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
457 }else{
458 if(preg_match("/^ou=/",$sourcedn)){
459 echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
460 }else{
461 $tmp = split(",",$sourcedn);
463 echo " <b>"._("Object").":</b> ";
465 $deststr = @LDAP::fix($destinationdn);
466 if(strlen($deststr) > 96){
467 $deststr = substr($deststr,0,96)."...";
468 }
470 echo $deststr."<br>";
471 }
472 }
474 flush();
476 if($this->hascon){
477 if ($this->reconnect) $this->connect();
479 /* Save base dn */
480 $basedn= $this->basedn;
481 $delarray= array();
483 /* Check if destination entry already exists */
484 $this->cat($destinationdn);
486 if($this->count()){
487 return;
488 }else{
490 $this->clearResult();
492 /* Get source entry */
493 $this->cd($basedn);
494 $this->cat($sourcedn);
495 $attr = $this->fetch();
497 /* Error while fetching object / attribute abort*/
498 if((!$attr) || (count($attr)) ==0) {
499 echo _("Error while fetching source dn - aborted!");
500 return;
501 }
503 /* check if this is a department */
504 if(in_array("organizationalUnit",$attr['objectClass'])){
505 $attr['dn'] = $this->convert($destinationdn);
506 $this->cd($basedn);
507 $this->create_missing_trees($destinationdn);
508 $this->cd($destinationdn);
510 /* If is first entry, append FAIbranch to department entry */
511 if($is_first){
512 $this->cat($destinationdn);
513 $attr= $this->fetch();
515 /* Filter unneeded informations */
516 foreach($attr as $key => $value){
517 if(is_numeric($key)) unset($attr[$key]);
518 if(isset($attr[$key]['count'])){
519 if(is_array($attr[$key])){
520 unset($attr[$key]['count']);
521 }
522 }
523 }
525 unset($attr['count']);
526 unset($attr['dn']);
528 /* Add marking attribute */
529 $attr['objectClass'][] = "FAIbranch";
531 /* Add this entry */
532 $this->modify($attr);
533 }
534 }else{
536 /* If this is no department */
537 foreach($attr as $key => $value){
538 if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
539 $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
540 $ei= ldap_first_entry($this->cid, $sr);
541 if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
542 $attr[$key] = $tmp;
543 }
544 }
546 if(is_numeric($key)) unset($attr[$key]);
547 if(isset($attr[$key]['count'])){
548 if(is_array($attr[$key])){
549 unset($attr[$key]['count']);
550 }
551 }
552 }
553 unset($attr['count']);
554 unset($attr['dn']);
556 if(!in_array("gosaApplication" , $attr['objectClass'])){
557 if($type=="branch"){
558 $attr['FAIstate'] ="branch";
559 }elseif($type=="freeze"){
560 $attr['FAIstate'] ="freeze";
561 }else{
562 print_red(_("Unknown FAIstate %s"),$type);
563 }
564 }elseif(in_array("gosaApplication",$attr['objectClass'])){
565 if(!in_array("FAIobject",$attr['objectClass'])){
566 $attr['objectClass'][] = "FAIobject";
567 }
568 $attr['FAIstate'] = $type;
569 }
571 /* Replace FAIdebianRelease with new release name */
572 if(in_array("FAIpackageList" , $attr['objectClass'])){
573 $attr['FAIdebianRelease'] = $destinationName;
574 if($type=="branch"){
575 $attr['FAIstate'] ="branch";
576 }elseif($type=="freeze"){
577 $attr['FAIstate'] ="freeze";
578 }else{
579 print_red(_("Unknown FAIstate %s"),$type);
580 }
581 }
583 /* Add entry */
584 $this->cd($destinationdn);
585 $this->cat($destinationdn);
586 $a = $this->fetch();
587 if(!count($a)){
588 $this->add($attr);
589 }
591 if($this->error != "Success"){
592 /* Some error occured */
593 print "---------------------------------------------";
594 print $this->get_error()."<br>";
595 print $sourcedn."<br>";
596 print $destinationdn."<br>";
597 print_a( $attr);
598 exit();
599 }
600 }
601 }
603 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
605 $this->ls ("(objectClass=*)",$sourcedn);
606 while ($this->fetch()){
607 $deldn= $this->getDN();
608 $delarray[$deldn]= strlen($deldn);
609 }
610 asort ($delarray);
611 reset ($delarray);
613 $depth ++;
614 foreach($delarray as $dn => $bla){
615 if($dn != $destinationdn){
616 $this->cd($basedn);
617 $item = $this->fetch($this->cat($dn));
618 if(!in_array("FAIbranch",$item['objectClass'])){
619 $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
620 }
621 }
622 }
623 }
624 if($is_first){
625 echo "<p class='seperator'> </p>";
626 }
628 }
630 function modify($attrs)
631 {
632 if(count($attrs) == 0){
633 return (0);
634 }
635 if($this->hascon){
636 if ($this->reconnect) $this->connect();
637 $start= microtime();
638 $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
639 $this->error = @ldap_error($this->cid);
640 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
641 return($r ? $r : 0);
642 }else{
643 $this->error = "Could not connect to LDAP server";
644 return("");
645 }
646 }
648 function add($attrs)
649 {
650 if($this->hascon){
651 if ($this->reconnect) $this->connect();
652 $start= microtime();
653 $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
654 $this->error = @ldap_error($this->cid);
655 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
656 return($r ? $r : 0);
657 }else{
658 $this->error = "Could not connect to LDAP server";
659 return("");
660 }
661 }
664 function create_missing_trees($target)
665 {
666 global $config;
668 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
670 if ($target == $this->basedn){
671 $l= array("dummy");
672 } else {
673 $l= array_reverse(gosa_ldap_explode_dn($real_path));
674 }
675 unset($l['count']);
676 $cdn= $this->basedn;
677 $tag= "";
679 /* Load schema if available... */
680 $classes= $this->get_objectclasses();
682 foreach ($l as $part){
683 if ($part != "dummy"){
684 $cdn= "$part,$cdn";
685 }
687 /* Ignore referrals */
688 $found= false;
689 foreach($this->referrals as $ref){
690 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
691 if ($base == $cdn){
692 $found= true;
693 break;
694 }
695 }
696 if ($found){
697 continue;
698 }
700 $this->cat ($cdn);
701 $attrs= $this->fetch();
703 /* Create missing entry? */
704 if (count ($attrs)){
705 /* Catch the tag - if present */
706 if (isset($attrs['gosaUnitTag'][0])){
707 $tag= $attrs['gosaUnitTag'][0];
708 }
710 } else {
711 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
712 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
714 $na= array();
716 /* Automatic or traditional? */
717 if(count($classes)){
719 /* Get name of first matching objectClass */
720 $ocname= "";
721 foreach($classes as $class){
722 if (isset($class['MUST']) && $class['MUST'] == "$type"){
724 /* Look for first classes that is structural... */
725 if (isset($class['STRUCTURAL'])){
726 $ocname= $class['NAME'];
727 break;
728 }
730 /* Look for classes that are auxiliary... */
731 if (isset($class['AUXILIARY'])){
732 $ocname= $class['NAME'];
733 }
734 }
735 }
737 /* Bail out, if we've nothing to do... */
738 if ($ocname == ""){
739 print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
740 echo $_SESSION['errors'];
741 exit;
742 }
744 /* Assemble_entry */
745 if ($tag != ""){
746 $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
747 } else {
748 $na['objectClass']= array($ocname);
749 }
750 if (isset($classes[$ocname]['AUXILIARY'])){
751 $na['objectClass'][]= $classes[$ocname]['SUP'];
752 }
753 if ($type == "dc"){
754 /* This is bad actually, but - tell me a better way? */
755 $na['objectClass'][]= 'locality';
756 }
757 $na[$type]= $param;
758 if (is_array($classes[$ocname]['MUST'])){
759 foreach($classes[$ocname]['MUST'] as $attr){
760 $na[$attr]= "filled";
761 }
762 }
764 } else {
766 /* Use alternative add... */
767 switch ($type){
768 case 'ou':
769 if ($tag != ""){
770 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
771 $na["gosaUnitTag"]= $tag;
772 } else {
773 $na["objectClass"]= "organizationalUnit";
774 }
775 $na["ou"]= $param;
776 break;
777 case 'dc':
778 if ($tag != ""){
779 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
780 $na["gosaUnitTag"]= $tag;
781 } else {
782 $na["objectClass"]= array("dcObject", "top", "locality");
783 }
784 $na["dc"]= $param;
785 break;
786 default:
787 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
788 echo $_SESSION['errors'];
789 exit;
790 }
792 }
793 $this->cd($cdn);
794 $this->add($na);
795 show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
796 if (!preg_match('/success/i', $this->error)){
797 return FALSE;
798 }
799 }
800 }
802 return TRUE;
803 }
806 function create_missing_trees_old($target)
807 {
808 /* Ignore create_missing trees if the base equals target */
809 if ($target == $this->basedn){
810 return;
811 }
813 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
814 $tmp = ldap_explode_dn($real_path,0);
815 if(!$tmp){
816 print_red(sprintf(_("The referral url '%s' is missing the ldap base. It should look like this 'ldap://server:port/base'."),$this->fix($this->basedn)));
817 return;
818 }
820 $l= array_reverse($tmp);
821 unset($l['count']);
822 $cdn= $this->basedn;
823 $tag= "";
825 foreach ($l as $part){
826 $cdn= "$part,$cdn";
828 /* Ignore referrals */
829 $found= false;
830 foreach($this->referrals as $ref){
831 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
832 if ($base == $cdn){
833 $found= true;
834 break;
835 }
836 }
837 if ($found){
838 continue;
839 }
841 $this->cat ($cdn);
842 $attrs= $this->fetch();
844 /* Create missing entry? */
845 if (count ($attrs)){
847 /* Catch the tag - if present */
848 if (isset($attrs['gosaUnitTag'][0])){
849 $tag= $attrs['gosaUnitTag'][0];
850 }
852 } else {
853 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
854 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
856 $na= array();
857 switch ($type){
858 case 'ou':
859 if ($tag != ""){
860 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
861 $na["gosaUnitTag"]= $tag;
862 } else {
863 $na["objectClass"]= "organizationalUnit";
864 }
865 $na["ou"]= $param;
866 break;
867 case 'dc':
868 if ($tag != ""){
869 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
870 $na["gosaUnitTag"]= $tag;
871 } else {
872 $na["objectClass"]= array("dcObject", "top", "locality");
873 }
874 $na["dc"]= $param;
875 break;
876 default:
877 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
878 echo $_SESSION['errors'];
879 exit;
880 }
881 $this->cd($cdn);
882 $this->add($na);
883 }
884 }
885 }
887 function recursive_remove()
888 {
889 $delarray= array();
891 /* Get sorted list of dn's to delete */
892 $this->search ("(objectClass=*)");
893 while ($this->fetch()){
894 $deldn= $this->getDN();
895 $delarray[$deldn]= strlen($deldn);
896 }
897 arsort ($delarray);
898 reset ($delarray);
900 /* Delete all dn's in subtree */
901 foreach ($delarray as $key => $value){
902 $this->rmdir($key);
903 }
904 }
906 function get_attribute($dn, $name,$r_array=0)
907 {
908 $data= "";
909 if ($this->reconnect) $this->connect();
910 $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
912 /* fill data from LDAP */
913 if ($sr) {
914 $ei= @ldap_first_entry($this->cid, $sr);
915 if ($ei) {
916 if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
917 $data= $info[0];
918 }
920 }
921 }
922 if($r_array==0)
923 return ($data);
924 else
925 return ($info);
928 }
932 function get_additional_error()
933 {
934 $error= "";
935 @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
936 return ($error);
937 }
939 function get_error()
940 {
941 if ($this->error == 'Success'){
942 return $this->error;
943 } else {
944 $adderror= $this->get_additional_error();
945 if ($adderror != ""){
946 $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
947 } else {
948 $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
949 }
950 return $error;
951 }
952 }
954 function get_credentials($url, $referrals= NULL)
955 {
956 $ret= array();
957 $url= preg_replace('!\?\?.*$!', '', $url);
958 $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
960 if ($referrals == NULL){
961 $referrals= $this->referrals;
962 }
964 if (isset($referrals[$server])){
965 return ($referrals[$server]);
966 } else {
967 $ret['ADMIN']= $this->fix($this->binddn);
968 $ret['PASSWORD']= $this->bindpw;
969 }
971 return ($ret);
972 }
975 function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
976 {
977 $display= "";
979 if ($recursive){
980 $this->cd($dn);
981 $this->search("$filter", array('dn'));
982 while ($attrs= $this->fetch()){
983 $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
984 $display.= "\n";
985 }
986 } else {
987 $display.= $this->gen_one_entry($dn);
988 }
990 return ($display);
991 }
993 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
994 {
995 $display= "";
997 $this->cd($dn);
998 $this->search("$filter");
1000 $i=0;
1001 while ($attrs= $this->fetch()){
1002 $j=0;
1004 foreach ($attributes as $at){
1005 $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1006 $j++;
1007 }
1009 $i++;
1010 }
1012 return ($display);
1013 }
1016 function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1017 {
1018 $ret = "";
1019 $data = "";
1020 if($this->reconnect){
1021 $this->connect();
1022 }
1024 /* Searching Ldap Tree */
1025 $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1027 /* Get the first entry */
1028 $entry= @ldap_first_entry($this->cid, $sr);
1030 /* Get all attributes related to that Objekt */
1031 $atts = array();
1033 /* Assemble dn */
1034 $atts[0]['name'] = "dn";
1035 $atts[0]['value'] = array('count' => 1, 0 => $dn);
1037 /* Reset index */
1038 $i = 1 ;
1039 $identifier = array();
1040 $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1041 while ($attribute) {
1042 $i++;
1043 $atts[$i]['name'] = $attribute;
1044 $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1046 /* Next one */
1047 $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1048 }
1050 foreach($atts as $at)
1051 {
1052 for ($i= 0; $i<$at['value']['count']; $i++){
1054 /* Check if we must encode the data */
1055 if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1056 $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1057 } else {
1058 $ret .= $at['name'].": ".$at['value'][$i]."\n";
1059 }
1060 }
1061 }
1063 return($ret);
1064 }
1067 function dn_exists($dn)
1068 {
1069 return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1070 }
1074 function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1075 {
1076 if($this->reconnect) $this->connect();
1078 /* First we have to splitt the string ito detect empty lines
1079 An empty line indicates an new Entry */
1080 $entries = split("\n",$str_attr);
1082 $data = "";
1083 $cnt = 0;
1084 $current_line = 0;
1086 /* Every single line ... */
1087 foreach($entries as $entry) {
1088 $current_line ++;
1090 /* Removing Spaces to ..
1091 .. test if a new entry begins */
1092 $tmp = str_replace(" ","",$data );
1094 /* .. prevent empty lines in an entry */
1095 $tmp2 = str_replace(" ","",$entry);
1097 /* If the Block ends (Empty Line) */
1098 if((empty($entry))&&(!empty($tmp))) {
1099 /* Add collected lines as a complete block */
1100 $all[$cnt] = $data;
1101 $cnt ++;
1102 $data ="";
1103 } else {
1105 /* Append lines ... */
1106 if(!empty($tmp2)) {
1107 /* check if we need base64_decode for this line */
1108 if(ereg("::",$tmp2))
1109 {
1110 $encoded = split("::",$entry);
1111 $attr = $encoded[0];
1112 $value = base64_decode($encoded[1]);
1113 /* Add linenumber */
1114 $data .= $current_line."#".$attr.":".$value."\n";
1115 }
1116 else
1117 {
1118 /* Add Linenumber */
1119 $data .= $current_line."#".$entry."\n";
1120 }
1121 }
1122 }
1123 }
1125 /* The Data we collected is not in the array all[];
1126 For example the Data is stored like this..
1128 all[0] = "1#dn : .... \n
1129 2#ObjectType: person \n ...."
1131 Now we check every insertblock and try to insert */
1132 foreach ( $all as $single) {
1133 $lineone = split("\n",$single);
1134 $ndn = split("#", $lineone[0]);
1135 $line = $ndn[1];
1137 $dnn = split (":",$line,2);
1138 $current_line = $ndn[0];
1139 $dn = $dnn[0];
1140 $value = $dnn[1];
1142 /* Every block must begin with a dn */
1143 if($dn != "dn") {
1144 $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1145 return -2;
1146 }
1148 /* Should we use Modify instead of Add */
1149 $usemodify= false;
1151 /* Delete before insert */
1152 $usermdir= false;
1154 /* The dn address already exists! */
1155 if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1157 $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1158 return ALREADY_EXISTING_ENTRY;
1160 } elseif(($this->dn_exists($value))&&($cleanup)){
1162 /* Delete first, then add */
1163 $usermdir = true;
1165 } elseif(($this->dn_exists($value))&&($overwrite)) {
1167 /* Modify instead of Add */
1168 $usemodify = true;
1169 }
1171 /* If we can't Import, return with a file error */
1172 if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1173 $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1174 $current_line);
1175 return UNKNOWN_TOKEN_IN_LDIF_FILE; }
1176 }
1178 return (INSERT_OK);
1179 }
1182 /* Imports a single entry */
1183 function import_single_entry($str_attr,$modify,$delete)
1184 {
1185 if($this->reconnect) $this->connect();
1187 $ret = false;
1188 $rows= split("\n",$str_attr);
1189 $data= false;
1191 foreach($rows as $row) {
1193 /* Check if we use Linenumbers (when import_complete_ldif is called we use
1194 Linenumbers) Linenumbers are use like this 123#attribute : value */
1195 if(!empty($row)) {
1196 if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1198 /* We are using line numbers
1199 Because there is a # before a : */
1200 $tmp1= split("#",$row);
1201 $current_line= $tmp1[0];
1202 $row= $tmp1[1];
1203 }
1205 /* Split the line into attribute and value */
1206 $attr = split(":", $row,2);
1207 $attr[0]= trim($attr[0]); /* attribute */
1208 $attr[1]= trim($attr[1]); /* value */
1210 /* Check for attributes that are used more than once */
1211 if(!isset($data[$attr[0]])) {
1212 $data[$attr[0]]=$attr[1];
1213 } else {
1214 $tmp = $data[$attr[0]];
1216 if(!is_array($tmp)) {
1217 $new[0]=$tmp;
1218 $new[1]=$attr[1];
1219 $datas[$attr[0]]['count']=1;
1220 $data[$attr[0]]=$new;
1221 } else {
1222 $cnt = $datas[$attr[0]]['count'];
1223 $cnt ++;
1224 $data[$attr[0]][$cnt]=$attr[1];
1225 $datas[$attr[0]]['count'] = $cnt;
1226 }
1227 }
1228 }
1229 }
1231 /* If dn is an index of data, we should try to insert the data */
1232 if(isset($data['dn'])) {
1233 /* Creating Entry */
1234 $this->cd($data['dn']);
1236 /* Delete existing entry */
1237 if($delete){
1238 $this->rmdir($data['dn']);
1239 }
1241 /* Create missing trees */
1242 $this->create_missing_trees($data['dn']);
1243 unset($data['dn']);
1245 /* If entry exists use modify */
1246 if(!$modify){
1247 $ret = $this->add($data);
1248 } else {
1249 $ret = $this->modify($data);
1250 }
1251 }
1253 return($ret);
1254 }
1257 function importcsv($str)
1258 {
1259 $lines = split("\n",$str);
1260 foreach($lines as $line)
1261 {
1262 /* continue if theres a comment */
1263 if(substr(trim($line),0,1)=="#"){
1264 continue;
1265 }
1267 $line= str_replace ("\t\t","\t",$line);
1268 $line= str_replace ("\t" ,"," ,$line);
1269 echo $line;
1271 $cells = split(",",$line ) ;
1272 $linet= str_replace ("\t\t",",",$line);
1273 $cells = split("\t",$line);
1274 $count = count($cells);
1275 }
1277 }
1279 function get_objectclasses_old()
1280 {
1281 $objectclasses = array();
1283 # Get base to look for schema
1284 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1285 $attr = @ldap_get_entries($this->cid,$sr);
1287 if (!isset($attr[0]['subschemasubentry'][0])){
1288 $this->error = @ldap_error($this->cid);
1289 gosa_log($this->get_error());
1290 return array();
1291 }
1293 # Get list of objectclasses
1294 $nb= $attr[0]['subschemasubentry'][0];
1295 $objectclasses= array();
1296 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1297 $attrs= ldap_get_entries($this->cid,$sr);
1298 if (!isset($attrs[0])){
1299 return array();
1300 }
1301 foreach ($attrs[0]['objectclasses'] as $val){
1302 $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1303 if ($name != $val){
1304 $objectclasses[$name]= $val;
1305 }
1306 }
1308 return $objectclasses;
1309 }
1312 function get_objectclasses()
1313 {
1314 $objectclasses = array();
1316 if(!isset($this->config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$this->config->data['MAIN']['SCHEMA_CHECK'])){
1317 return($objectclasses);
1318 }
1320 # Get base to look for schema
1321 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1322 if(!$sr){
1323 $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1324 }
1326 $attr = @ldap_get_entries($this->cid,$sr);
1327 if (!isset($attr[0]['subschemasubentry'][0])){
1328 return array();
1329 }
1331 /* Get list of objectclasses and fill array */
1332 $nb= $attr[0]['subschemasubentry'][0];
1333 $objectclasses= array();
1334 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1335 $attrs= ldap_get_entries($this->cid,$sr);
1336 if (!isset($attrs[0])){
1337 return array();
1338 }
1339 foreach ($attrs[0]['objectclasses'] as $val){
1340 if (preg_match('/^[0-9]+$/', $val)){
1341 continue;
1342 }
1343 $name= "OID";
1344 $pattern= split(' ', $val);
1345 $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1346 $objectclasses[$ocname]= array();
1348 foreach($pattern as $chunk){
1349 switch($chunk){
1351 case '(':
1352 $value= "";
1353 break;
1355 case ')': if ($name != ""){
1356 $objectclasses[$ocname][$name]= $this->value2container($value);
1357 }
1358 $name= "";
1359 $value= "";
1360 break;
1362 case 'NAME':
1363 case 'DESC':
1364 case 'SUP':
1365 case 'STRUCTURAL':
1366 case 'ABSTRACT':
1367 case 'AUXILIARY':
1368 case 'MUST':
1369 case 'MAY':
1370 if ($name != ""){
1371 $objectclasses[$ocname][$name]= $this->value2container($value);
1372 }
1373 $name= $chunk;
1374 $value= "";
1375 break;
1377 default: $value.= $chunk." ";
1378 }
1379 }
1381 }
1383 return $objectclasses;
1384 }
1386 function value2container($value)
1387 {
1388 /* Set emtpy values to "true" only */
1389 if (preg_match('/^\s*$/', $value)){
1390 return true;
1391 }
1393 /* Remove ' and " if needed */
1394 $value= preg_replace('/^[\'"]/', '', $value);
1395 $value= preg_replace('/[\'"] *$/', '', $value);
1397 /* Convert to array if $ is inside... */
1398 if (preg_match('/\$/', $value)){
1399 $container= preg_split('/\s*\$\s*/', $value);
1400 } else {
1401 $container= chop($value);
1402 }
1404 return ($container);
1405 }
1407 function log($string)
1408 {
1409 if (isset($_SESSION['config'])){
1410 $cfg= $_SESSION['config'];
1411 if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1412 syslog (LOG_INFO, $string);
1413 }
1414 }
1415 }
1417 /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1418 function getCn($dn){
1419 $simple= split(",", $dn);
1421 foreach($simple as $piece) {
1422 $partial= split("=", $piece);
1424 if($partial[0] == "cn"){
1425 return $partial[1];
1426 }
1427 }
1429 }
1431 function get_naming_contexts($server, $admin= "", $password= "")
1432 {
1433 /* Build LDAP connection */
1434 $ds= ldap_connect ($server);
1435 if (!$ds) {
1436 die ("Can't bind to LDAP. No check possible!");
1437 }
1438 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1439 $r= ldap_bind ($ds, $admin, $password);
1441 /* Get base to look for naming contexts */
1442 $sr = @ldap_read ($ds, "", "objectClass=*", array("+"));
1443 $attr= @ldap_get_entries($ds,$sr);
1445 return ($attr[0]['namingcontexts']);
1446 }
1448 }
1450 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1451 ?>