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 \22 => TO
63 \" => TO
64 \+ => PL
65 ( => OB
66 ) => CB
67 / => SL */
68 function convert($dn)
69 {
70 if (SPECIALS_OVERRIDE == TRUE){
71 $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//", "/\\\\22/", '/\\\\"/', "/\\\\3D/", "/\\\\2B/", '/\\\\+/'),
72 array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL", "\001TO", "\001TO", "\001GL", "\001PL", "\001PL"),
73 $dn);
74 return (preg_replace('/,\s+/', ',', $tmp));
75 } else {
76 return ($dn);
77 }
78 }
81 /* Function to fix all problematic characters inside a DN by replacing \001XX
82 codes to their original values. See "convert" for mor information.
83 ',' characters are always expanded to \, (not \2C), since all tested LDAP
84 servers seem to take it the correct way. */
85 function fix($dn)
86 {
87 if (SPECIALS_OVERRIDE == TRUE){
88 return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/", "/\001TO/", "/\001PL/", "/\001GL/"),
89 array("\,", "(", ")", "/", '\"', "\+", "="),
90 $dn));
91 } else {
92 return ($dn);
93 }
94 }
97 function connect()
98 {
99 $this->hascon=false;
100 $this->reconnect=false;
101 if ($this->cid= @ldap_connect($this->hostname)) {
102 @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
103 if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
104 @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
105 @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
106 }
107 if (function_exists("ldap_start_tls") && $this->tls){
108 @ldap_start_tls($this->cid);
109 }
111 $this->error = "No Error";
112 if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
113 $this->error = "Success";
114 $this->hascon=true;
115 } else {
116 if ($this->reconnect){
117 if ($this->error != "Success"){
118 $this->error = "Could not rebind to " . $this->binddn;
119 }
120 } else {
121 $this->error = "Could not bind to " . $this->binddn;
122 }
123 }
124 } else {
125 $this->error = "Could not connect to LDAP server";
126 }
127 }
129 function rebind($ldap, $referral)
130 {
131 $credentials= $this->get_credentials($referral);
132 if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
133 $this->error = "Success";
134 $this->hascon=true;
135 $this->reconnect= true;
136 return (0);
137 } else {
138 $this->error = "Could not bind to " . $credentials['ADMIN'];
139 return NULL;
140 }
141 }
143 function reconnect()
144 {
145 if ($this->reconnect){
146 @ldap_unbind($this->cid);
147 $this->cid = NULL;
148 }
149 }
151 function unbind()
152 {
153 @ldap_unbind($this->cid);
154 $this->cid = NULL;
155 }
157 function disconnect()
158 {
159 if($this->hascon){
160 @ldap_close($this->cid);
161 $this->hascon=false;
162 }
163 }
165 function cd($dir)
166 {
167 if ($dir == "..")
168 $this->basedn = $this->getParentDir();
169 else
170 $this->basedn = $this->convert($dir);
171 }
173 function getParentDir($basedn = "")
174 {
175 if ($basedn=="")
176 $basedn = $this->basedn;
177 else
178 $basedn = $this->convert($this->basedn);
179 return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
180 }
182 function search($filter, $attrs= array())
183 {
184 if($this->hascon){
185 if ($this->reconnect) $this->connect();
187 $start = microtime();
189 $this->clearResult();
190 $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
191 $this->error = @ldap_error($this->cid);
192 $this->resetResult();
193 $this->hasres=true;
195 /* Check if query took longer as specified in max_ldap_query_time */
196 if($this->max_ldap_query_time){
197 $diff = get_MicroTimeDiff($start,microtime());
198 if($diff > $this->max_ldap_query_time){
199 print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
200 }
201 }
203 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
205 return($this->sr);
206 }else{
207 $this->error = "Could not connect to LDAP server";
208 return("");
209 }
210 }
212 function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
213 {
214 if($this->hascon){
215 if ($this->reconnect) $this->connect();
216 $this->clearResult();
217 if ($basedn == "")
218 $basedn = $this->basedn;
219 else
220 $basedn= $this->convert($basedn);
222 $start = microtime();
224 $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
225 $this->error = @ldap_error($this->cid);
226 $this->resetResult();
227 $this->hasres=true;
229 /* Check if query took longer as specified in max_ldap_query_time */
230 if($this->max_ldap_query_time){
231 $diff = get_MicroTimeDiff($start,microtime());
232 if($diff > $this->max_ldap_query_time){
233 print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
234 }
235 }
237 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
239 return($this->sr);
240 }else{
241 $this->error = "Could not connect to LDAP server";
242 return("");
243 }
244 }
246 function cat($dn,$attrs= array("*"))
247 {
248 if($this->hascon){
249 if ($this->reconnect) $this->connect();
250 $start = microtime();
251 $this->clearResult();
252 $filter = "(objectclass=*)";
253 $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
254 $this->error = @ldap_error($this->cid);
255 $this->resetResult();
256 $this->hasres=true;
257 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
258 return($this->sr);
259 }else{
260 $this->error = "Could not connect to LDAP server";
261 return("");
262 }
263 }
265 function set_size_limit($size)
266 {
267 /* Ignore zero settings */
268 if ($size == 0){
269 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
270 }
271 if($this->hascon){
272 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
273 } else {
274 $this->error = "Could not connect to LDAP server";
275 }
276 }
278 function fetch()
279 {
280 $att= array();
281 if($this->hascon){
282 if($this->hasres){
283 if ($this->start == 0)
284 {
285 $this->start = 1;
286 $this->re= @ldap_first_entry($this->cid, $this->sr);
287 } else {
288 $this->re= @ldap_next_entry($this->cid, $this->re);
289 }
290 if ($this->re)
291 {
292 $att= @ldap_get_attributes($this->cid, $this->re);
293 $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
294 }
295 $this->error = @ldap_error($this->cid);
296 if (!isset($att)){
297 $att= array();
298 }
299 return($att);
300 }else{
301 $this->error = "Perform a Fetch with no Search";
302 return("");
303 }
304 }else{
305 $this->error = "Could not connect to LDAP server";
306 return("");
307 }
308 }
310 function resetResult()
311 {
312 $this->start = 0;
313 }
315 function clearResult()
316 {
317 if($this->hasres){
318 $this->hasres = false;
319 @ldap_free_result($this->sr);
320 }
321 }
323 function getDN()
324 {
325 if($this->hascon){
326 if($this->hasres){
328 if(!$this->re)
329 {
330 $this->error = "Perform a Fetch with no valid Result";
331 }
332 else
333 {
334 $rv = @ldap_get_dn($this->cid, $this->re);
336 $this->error = @ldap_error($this->cid);
337 return(trim($this->convert($rv)));
338 }
339 }else{
340 $this->error = "Perform a Fetch with no Search";
341 return("");
342 }
343 }else{
344 $this->error = "Could not connect to LDAP server";
345 return("");
346 }
347 }
349 function count()
350 {
351 if($this->hascon){
352 if($this->hasres){
353 $rv = @ldap_count_entries($this->cid, $this->sr);
354 $this->error = @ldap_error($this->cid);
355 return($rv);
356 }else{
357 $this->error = "Perform a Fetch with no Search";
358 return("");
359 }
360 }else{
361 $this->error = "Could not connect to LDAP server";
362 return("");
363 }
364 }
366 function rm($attrs = "", $dn = "")
367 {
368 if($this->hascon){
369 if ($this->reconnect) $this->connect();
370 if ($dn == "")
371 $dn = $this->basedn;
373 $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
374 $this->error = @ldap_error($this->cid);
375 return($r);
376 }else{
377 $this->error = "Could not connect to LDAP server";
378 return("");
379 }
380 }
382 function rename($attrs, $dn = "")
383 {
384 if($this->hascon){
385 if ($this->reconnect) $this->connect();
386 if ($dn == "")
387 $dn = $this->basedn;
389 $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
390 $this->error = @ldap_error($this->cid);
391 return($r);
392 }else{
393 $this->error = "Could not connect to LDAP server";
394 return("");
395 }
396 }
398 function rmdir($deletedn)
399 {
400 if($this->hascon){
401 if ($this->reconnect) $this->connect();
402 $start= microtime();
403 $r = @ldap_delete($this->cid, $this->fix($deletedn));
404 $this->error = @ldap_error($this->cid);
405 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
406 return($r ? $r : 0);
407 }else{
408 $this->error = "Could not connect to LDAP server";
409 return("");
410 }
411 }
413 /**
414 * Function rmdir_recursive
415 *
416 * Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
417 * Parameters: The dn to delete
418 * GiveBack: True on sucessfull , 0 in error, and "" when we don't get a ldap conection
419 *
420 */
422 function rmdir_recursive($deletedn)
423 {
424 if($this->hascon){
425 if ($this->reconnect) $this->connect();
426 $delarray= array();
428 /* Get sorted list of dn's to delete */
429 $this->ls ("(objectClass=*)",$deletedn);
430 while ($this->fetch()){
431 $deldn= $this->getDN();
432 $delarray[$deldn]= strlen($deldn);
433 }
434 arsort ($delarray);
435 reset ($delarray);
437 /* Really Delete ALL dn's in subtree */
438 foreach ($delarray as $key => $value){
439 $this->rmdir_recursive($key);
440 }
442 /* Finally Delete own Node */
443 $r = @ldap_delete($this->cid, $this->fix($deletedn));
444 $this->error = @ldap_error($this->cid);
445 return($r ? $r : 0);
446 }else{
447 $this->error = "Could not connect to LDAP server";
448 return("");
449 }
450 }
452 /* Copy given attributes and sub-dns with attributes to destination dn
453 */
454 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
455 {
456 error_reporting(E_ALL);
458 if($is_first){
459 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
460 }else{
461 if(preg_match("/^ou=/",$sourcedn)){
462 echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
463 }else{
464 $tmp = split(",",$sourcedn);
466 echo " <b>"._("Object").":</b> ";
468 $deststr = @LDAP::fix($destinationdn);
469 if(strlen($deststr) > 96){
470 $deststr = substr($deststr,0,96)."...";
471 }
473 echo $deststr."<br>";
474 }
475 }
477 flush();
479 if($this->hascon){
480 if ($this->reconnect) $this->connect();
482 /* Save base dn */
483 $basedn= $this->basedn;
484 $delarray= array();
486 /* Check if destination entry already exists */
487 $this->cat($destinationdn);
489 if($this->count()){
490 return;
491 }else{
493 $this->clearResult();
495 /* Get source entry */
496 $this->cd($basedn);
497 $this->cat($sourcedn);
498 $attr = $this->fetch();
500 /* Error while fetching object / attribute abort*/
501 if((!$attr) || (count($attr)) ==0) {
502 echo _("Error while fetching source dn - aborted!");
503 return;
504 }
506 /* check if this is a department */
507 if(in_array("organizationalUnit",$attr['objectClass'])){
508 $attr['dn'] = $this->convert($destinationdn);
509 $this->cd($basedn);
510 $this->create_missing_trees($destinationdn);
511 $this->cd($destinationdn);
513 /* If is first entry, append FAIbranch to department entry */
514 if($is_first){
515 $this->cat($destinationdn);
516 $attr= $this->fetch();
518 /* Filter unneeded informations */
519 foreach($attr as $key => $value){
520 if(is_numeric($key)) unset($attr[$key]);
521 if(isset($attr[$key]['count'])){
522 if(is_array($attr[$key])){
523 unset($attr[$key]['count']);
524 }
525 }
526 }
528 unset($attr['count']);
529 unset($attr['dn']);
531 /* Add marking attribute */
532 $attr['objectClass'][] = "FAIbranch";
534 /* Add this entry */
535 $this->modify($attr);
536 }
537 }else{
539 /* If this is no department */
540 foreach($attr as $key => $value){
541 if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
542 $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
543 $ei= ldap_first_entry($this->cid, $sr);
544 if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
545 $attr[$key] = $tmp;
546 }
547 }
549 if(is_numeric($key)) unset($attr[$key]);
550 if(isset($attr[$key]['count'])){
551 if(is_array($attr[$key])){
552 unset($attr[$key]['count']);
553 }
554 }
555 }
556 unset($attr['count']);
557 unset($attr['dn']);
559 if(!in_array("gosaApplication" , $attr['objectClass'])){
560 if($type=="branch"){
561 $attr['FAIstate'] ="branch";
562 }elseif($type=="freeze"){
563 $attr['FAIstate'] ="freeze";
564 }else{
565 print_red(_("Unknown FAIstate %s"),$type);
566 }
567 }elseif(in_array("gosaApplication",$attr['objectClass'])){
568 if(!in_array("FAIobject",$attr['objectClass'])){
569 $attr['objectClass'][] = "FAIobject";
570 }
571 $attr['FAIstate'] = $type;
572 }
574 /* Replace FAIdebianRelease with new release name */
575 if(in_array("FAIpackageList" , $attr['objectClass'])){
576 $attr['FAIdebianRelease'] = $destinationName;
577 if($type=="branch"){
578 $attr['FAIstate'] ="branch";
579 }elseif($type=="freeze"){
580 $attr['FAIstate'] ="freeze";
581 }else{
582 print_red(_("Unknown FAIstate %s"),$type);
583 }
584 }
586 /* Add entry */
587 $this->cd($destinationdn);
588 $this->cat($destinationdn);
589 $a = $this->fetch();
590 if(!count($a)){
591 $this->add($attr);
592 }
594 if($this->error != "Success"){
595 /* Some error occurred */
596 print "---------------------------------------------";
597 print $this->get_error()."<br>";
598 print $sourcedn."<br>";
599 print $destinationdn."<br>";
600 print_a( $attr);
601 exit();
602 }
603 }
604 }
606 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
608 $this->ls ("(objectClass=*)",$sourcedn);
609 while ($this->fetch()){
610 $deldn= $this->getDN();
611 $delarray[$deldn]= strlen($deldn);
612 }
613 asort ($delarray);
614 reset ($delarray);
616 $depth ++;
617 foreach($delarray as $dn => $bla){
618 if($dn != $destinationdn){
619 $this->cd($basedn);
620 $item = $this->fetch($this->cat($dn));
621 if(!in_array("FAIbranch",$item['objectClass'])){
622 $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
623 }
624 }
625 }
626 }
627 if($is_first){
628 echo "<p class='seperator'> </p>";
629 }
631 }
633 function modify($attrs)
634 {
635 if(count($attrs) == 0){
636 return (0);
637 }
638 if($this->hascon){
639 if ($this->reconnect) $this->connect();
640 $start= microtime();
641 $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
642 $this->error = @ldap_error($this->cid);
643 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
644 return($r ? $r : 0);
645 }else{
646 $this->error = "Could not connect to LDAP server";
647 return("");
648 }
649 }
651 function add($attrs)
652 {
653 if($this->hascon){
654 if ($this->reconnect) $this->connect();
655 $start= microtime();
656 $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
657 $this->error = @ldap_error($this->cid);
658 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
659 return($r ? $r : 0);
660 }else{
661 $this->error = "Could not connect to LDAP server";
662 return("");
663 }
664 }
667 function create_missing_trees($target)
668 {
669 global $config;
671 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
673 if ($target == $this->basedn){
674 $l= array("dummy");
675 } else {
676 $l= array_reverse(gosa_ldap_explode_dn($real_path));
677 }
678 unset($l['count']);
679 $cdn= $this->basedn;
680 $tag= "";
682 /* Load schema if available... */
683 $classes= $this->get_objectclasses();
685 foreach ($l as $part){
686 if ($part != "dummy"){
687 $cdn= "$part,$cdn";
688 }
690 /* Ignore referrals */
691 $found= false;
692 foreach($this->referrals as $ref){
693 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
694 if ($base == $cdn){
695 $found= true;
696 break;
697 }
698 }
699 if ($found){
700 continue;
701 }
703 $this->cat ($cdn);
704 $attrs= $this->fetch();
706 /* Create missing entry? */
707 if (count ($attrs)){
708 /* Catch the tag - if present */
709 if (isset($attrs['gosaUnitTag'][0])){
710 $tag= $attrs['gosaUnitTag'][0];
711 }
713 } else {
714 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
715 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
717 $na= array();
719 /* Automatic or traditional? */
720 if(count($classes)){
722 /* Get name of first matching objectClass */
723 $ocname= "";
724 foreach($classes as $class){
725 if (isset($class['MUST']) && $class['MUST'] == "$type"){
727 /* Look for first classes that is structural... */
728 if (isset($class['STRUCTURAL'])){
729 $ocname= $class['NAME'];
730 break;
731 }
733 /* Look for classes that are auxiliary... */
734 if (isset($class['AUXILIARY'])){
735 $ocname= $class['NAME'];
736 }
737 }
738 }
740 /* Bail out, if we've nothing to do... */
741 if ($ocname == ""){
742 print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
743 echo $_SESSION['errors'];
744 exit;
745 }
747 /* Assemble_entry */
748 if ($tag != ""){
749 $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
750 } else {
751 $na['objectClass']= array($ocname);
752 }
753 if (isset($classes[$ocname]['AUXILIARY'])){
754 $na['objectClass'][]= $classes[$ocname]['SUP'];
755 }
756 if ($type == "dc"){
757 /* This is bad actually, but - tell me a better way? */
758 $na['objectClass'][]= 'locality';
759 }
760 $na[$type]= $param;
761 if (is_array($classes[$ocname]['MUST'])){
762 foreach($classes[$ocname]['MUST'] as $attr){
763 $na[$attr]= "filled";
764 }
765 }
767 } else {
769 /* Use alternative add... */
770 switch ($type){
771 case 'ou':
772 if ($tag != ""){
773 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
774 $na["gosaUnitTag"]= $tag;
775 } else {
776 $na["objectClass"]= "organizationalUnit";
777 }
778 $na["ou"]= $param;
779 break;
780 case 'dc':
781 if ($tag != ""){
782 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
783 $na["gosaUnitTag"]= $tag;
784 } else {
785 $na["objectClass"]= array("dcObject", "top", "locality");
786 }
787 $na["dc"]= $param;
788 break;
789 default:
790 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
791 echo $_SESSION['errors'];
792 exit;
793 }
795 }
796 $this->cd($cdn);
797 $this->add($na);
798 show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
799 if (!preg_match('/success/i', $this->error)){
800 return FALSE;
801 }
802 }
803 }
805 return TRUE;
806 }
809 function create_missing_trees_old($target)
810 {
811 /* Ignore create_missing trees if the base equals target */
812 if ($target == $this->basedn){
813 return;
814 }
816 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
817 $tmp = ldap_explode_dn($real_path,0);
818 if(!$tmp){
819 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)));
820 return;
821 }
823 $l= array_reverse($tmp);
824 unset($l['count']);
825 $cdn= $this->basedn;
826 $tag= "";
828 foreach ($l as $part){
829 $cdn= "$part,$cdn";
831 /* Ignore referrals */
832 $found= false;
833 foreach($this->referrals as $ref){
834 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
835 if ($base == $cdn){
836 $found= true;
837 break;
838 }
839 }
840 if ($found){
841 continue;
842 }
844 $this->cat ($cdn);
845 $attrs= $this->fetch();
847 /* Create missing entry? */
848 if (count ($attrs)){
850 /* Catch the tag - if present */
851 if (isset($attrs['gosaUnitTag'][0])){
852 $tag= $attrs['gosaUnitTag'][0];
853 }
855 } else {
856 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
857 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
859 $na= array();
860 switch ($type){
861 case 'ou':
862 if ($tag != ""){
863 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
864 $na["gosaUnitTag"]= $tag;
865 } else {
866 $na["objectClass"]= "organizationalUnit";
867 }
868 $na["ou"]= $param;
869 break;
870 case 'dc':
871 if ($tag != ""){
872 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
873 $na["gosaUnitTag"]= $tag;
874 } else {
875 $na["objectClass"]= array("dcObject", "top", "locality");
876 }
877 $na["dc"]= $param;
878 break;
879 default:
880 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
881 echo $_SESSION['errors'];
882 exit;
883 }
884 $this->cd($cdn);
885 $this->add($na);
886 }
887 }
888 }
890 function recursive_remove()
891 {
892 $delarray= array();
894 /* Get sorted list of dn's to delete */
895 $this->search ("(objectClass=*)");
896 while ($this->fetch()){
897 $deldn= $this->getDN();
898 $delarray[$deldn]= strlen($deldn);
899 }
900 arsort ($delarray);
901 reset ($delarray);
903 /* Delete all dn's in subtree */
904 foreach ($delarray as $key => $value){
905 $this->rmdir($key);
906 }
907 }
909 function get_attribute($dn, $name,$r_array=0)
910 {
911 $data= "";
912 if ($this->reconnect) $this->connect();
913 $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
915 /* fill data from LDAP */
916 if ($sr) {
917 $ei= @ldap_first_entry($this->cid, $sr);
918 if ($ei) {
919 if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
920 $data= $info[0];
921 }
923 }
924 }
925 if($r_array==0)
926 return ($data);
927 else
928 return ($info);
931 }
935 function get_additional_error()
936 {
937 $error= "";
938 @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
939 return ($error);
940 }
942 function get_error()
943 {
944 if ($this->error == 'Success'){
945 return $this->error;
946 } else {
947 $adderror= $this->get_additional_error();
948 if ($adderror != ""){
949 $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
950 } else {
951 $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
952 }
953 return $error;
954 }
955 }
957 function get_credentials($url, $referrals= NULL)
958 {
959 $ret= array();
960 $url= preg_replace('!\?\?.*$!', '', $url);
961 $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
963 if ($referrals == NULL){
964 $referrals= $this->referrals;
965 }
967 if (isset($referrals[$server])){
968 return ($referrals[$server]);
969 } else {
970 $ret['ADMIN']= $this->fix($this->binddn);
971 $ret['PASSWORD']= $this->bindpw;
972 }
974 return ($ret);
975 }
978 function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
979 {
980 $display= "";
982 if ($recursive){
983 $this->cd($dn);
984 $this->search("$filter", array('dn'));
985 while ($attrs= $this->fetch()){
986 $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
987 $display.= "\n";
988 }
989 } else {
990 $display.= $this->gen_one_entry($dn);
991 }
993 return ($display);
994 }
996 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
997 {
998 $display= "";
1000 $this->cd($dn);
1001 $this->search("$filter");
1003 $i=0;
1004 while ($attrs= $this->fetch()){
1005 $j=0;
1007 foreach ($attributes as $at){
1008 $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1009 $j++;
1010 }
1012 $i++;
1013 }
1015 return ($display);
1016 }
1019 function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1020 {
1021 $ret = "";
1022 $data = "";
1023 if($this->reconnect){
1024 $this->connect();
1025 }
1027 /* Searching Ldap Tree */
1028 $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1030 /* Get the first entry */
1031 $entry= @ldap_first_entry($this->cid, $sr);
1033 /* Get all attributes related to that Objekt */
1034 $atts = array();
1036 /* Assemble dn */
1037 $atts[0]['name'] = "dn";
1038 $atts[0]['value'] = array('count' => 1, 0 => $dn);
1040 /* Reset index */
1041 $i = 1 ;
1042 $identifier = array();
1043 $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1044 while ($attribute) {
1045 $i++;
1046 $atts[$i]['name'] = $attribute;
1047 $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1049 /* Next one */
1050 $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1051 }
1053 foreach($atts as $at)
1054 {
1055 for ($i= 0; $i<$at['value']['count']; $i++){
1057 /* Check if we must encode the data */
1058 if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1059 $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1060 } else {
1061 $ret .= $at['name'].": ".$at['value'][$i]."\n";
1062 }
1063 }
1064 }
1066 return($ret);
1067 }
1070 function dn_exists($dn)
1071 {
1072 return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1073 }
1077 function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1078 {
1079 if($this->reconnect) $this->connect();
1081 /* First we have to splitt the string ito detect empty lines
1082 An empty line indicates an new Entry */
1083 $entries = split("\n",$str_attr);
1085 $data = "";
1086 $cnt = 0;
1087 $current_line = 0;
1089 /* Every single line ... */
1090 foreach($entries as $entry) {
1091 $current_line ++;
1093 /* Removing Spaces to ..
1094 .. test if a new entry begins */
1095 $tmp = str_replace(" ","",$data );
1097 /* .. prevent empty lines in an entry */
1098 $tmp2 = str_replace(" ","",$entry);
1100 /* If the Block ends (Empty Line) */
1101 if((empty($entry))&&(!empty($tmp))) {
1102 /* Add collected lines as a complete block */
1103 $all[$cnt] = $data;
1104 $cnt ++;
1105 $data ="";
1106 } else {
1108 /* Append lines ... */
1109 if(!empty($tmp2)) {
1110 /* check if we need base64_decode for this line */
1111 if(ereg("::",$tmp2))
1112 {
1113 $encoded = split("::",$entry);
1114 $attr = $encoded[0];
1115 $value = base64_decode($encoded[1]);
1116 /* Add linenumber */
1117 $data .= $current_line."#".$attr.":".$value."\n";
1118 }
1119 else
1120 {
1121 /* Add Linenumber */
1122 $data .= $current_line."#".$entry."\n";
1123 }
1124 }
1125 }
1126 }
1128 /* The Data we collected is not in the array all[];
1129 For example the Data is stored like this..
1131 all[0] = "1#dn : .... \n
1132 2#ObjectType: person \n ...."
1134 Now we check every insertblock and try to insert */
1135 foreach ( $all as $single) {
1136 $lineone = split("\n",$single);
1137 $ndn = split("#", $lineone[0]);
1138 $line = $ndn[1];
1140 $dnn = split (":",$line,2);
1141 $current_line = $ndn[0];
1142 $dn = $dnn[0];
1143 $value = $dnn[1];
1145 /* Every block must begin with a dn */
1146 if($dn != "dn") {
1147 $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1148 return -2;
1149 }
1151 /* Should we use Modify instead of Add */
1152 $usemodify= false;
1154 /* Delete before insert */
1155 $usermdir= false;
1157 /* The dn address already exists! */
1158 if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1160 $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1161 return ALREADY_EXISTING_ENTRY;
1163 } elseif(($this->dn_exists($value))&&($cleanup)){
1165 /* Delete first, then add */
1166 $usermdir = true;
1168 } elseif(($this->dn_exists($value))&&($overwrite)) {
1170 /* Modify instead of Add */
1171 $usemodify = true;
1172 }
1174 /* If we can't Import, return with a file error */
1175 if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1176 $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1177 $current_line);
1178 return UNKNOWN_TOKEN_IN_LDIF_FILE; }
1179 }
1181 return (INSERT_OK);
1182 }
1185 /* Imports a single entry */
1186 function import_single_entry($str_attr,$modify,$delete)
1187 {
1188 if($this->reconnect) $this->connect();
1190 $ret = false;
1191 $rows= split("\n",$str_attr);
1192 $data= false;
1194 foreach($rows as $row) {
1196 /* Check if we use Linenumbers (when import_complete_ldif is called we use
1197 Linenumbers) Linenumbers are use like this 123#attribute : value */
1198 if(!empty($row)) {
1199 if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1201 /* We are using line numbers
1202 Because there is a # before a : */
1203 $tmp1= split("#",$row);
1204 $current_line= $tmp1[0];
1205 $row= $tmp1[1];
1206 }
1208 /* Split the line into attribute and value */
1209 $attr = split(":", $row,2);
1210 $attr[0]= trim($attr[0]); /* attribute */
1211 $attr[1]= trim($attr[1]); /* value */
1213 /* Check for attributes that are used more than once */
1214 if(!isset($data[$attr[0]])) {
1215 $data[$attr[0]]=$attr[1];
1216 } else {
1217 $tmp = $data[$attr[0]];
1219 if(!is_array($tmp)) {
1220 $new[0]=$tmp;
1221 $new[1]=$attr[1];
1222 $datas[$attr[0]]['count']=1;
1223 $data[$attr[0]]=$new;
1224 } else {
1225 $cnt = $datas[$attr[0]]['count'];
1226 $cnt ++;
1227 $data[$attr[0]][$cnt]=$attr[1];
1228 $datas[$attr[0]]['count'] = $cnt;
1229 }
1230 }
1231 }
1232 }
1234 /* If dn is an index of data, we should try to insert the data */
1235 if(isset($data['dn'])) {
1236 /* Creating Entry */
1237 $this->cd($data['dn']);
1239 /* Delete existing entry */
1240 if($delete){
1241 $this->rmdir($data['dn']);
1242 }
1244 /* Create missing trees */
1245 $this->create_missing_trees($data['dn']);
1246 unset($data['dn']);
1248 /* If entry exists use modify */
1249 if(!$modify){
1250 $ret = $this->add($data);
1251 } else {
1252 $ret = $this->modify($data);
1253 }
1254 }
1256 return($ret);
1257 }
1260 function importcsv($str)
1261 {
1262 $lines = split("\n",$str);
1263 foreach($lines as $line)
1264 {
1265 /* continue if theres a comment */
1266 if(substr(trim($line),0,1)=="#"){
1267 continue;
1268 }
1270 $line= str_replace ("\t\t","\t",$line);
1271 $line= str_replace ("\t" ,"," ,$line);
1272 echo $line;
1274 $cells = split(",",$line ) ;
1275 $linet= str_replace ("\t\t",",",$line);
1276 $cells = split("\t",$line);
1277 $count = count($cells);
1278 }
1280 }
1282 function get_objectclasses_old()
1283 {
1284 $objectclasses = array();
1286 # Get base to look for schema
1287 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1288 $attr = @ldap_get_entries($this->cid,$sr);
1290 if (!isset($attr[0]['subschemasubentry'][0])){
1291 $this->error = @ldap_error($this->cid);
1292 gosa_log($this->get_error());
1293 return array();
1294 }
1296 # Get list of objectclasses
1297 $nb= $attr[0]['subschemasubentry'][0];
1298 $objectclasses= array();
1299 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1300 $attrs= ldap_get_entries($this->cid,$sr);
1301 if (!isset($attrs[0])){
1302 return array();
1303 }
1304 foreach ($attrs[0]['objectclasses'] as $val){
1305 $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1306 if ($name != $val){
1307 $objectclasses[$name]= $val;
1308 }
1309 }
1311 return $objectclasses;
1312 }
1315 function get_objectclasses()
1316 {
1317 global $config;
1318 $objectclasses = array();
1320 if(isset($config) && preg_match("/config/i",get_class($config))){
1321 if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
1322 return($objectclasses);
1323 }
1324 }
1326 # Get base to look for schema
1327 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1328 if(!$sr){
1329 $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1330 }
1332 $attr = @ldap_get_entries($this->cid,$sr);
1333 if (!isset($attr[0]['subschemasubentry'][0])){
1334 return array();
1335 }
1337 /* Get list of objectclasses and fill array */
1338 $nb= $attr[0]['subschemasubentry'][0];
1339 $objectclasses= array();
1340 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1341 $attrs= ldap_get_entries($this->cid,$sr);
1342 if (!isset($attrs[0])){
1343 return array();
1344 }
1345 foreach ($attrs[0]['objectclasses'] as $val){
1346 if (preg_match('/^[0-9]+$/', $val)){
1347 continue;
1348 }
1349 $name= "OID";
1350 $pattern= split(' ', $val);
1351 $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1352 $objectclasses[$ocname]= array();
1354 foreach($pattern as $chunk){
1355 switch($chunk){
1357 case '(':
1358 $value= "";
1359 break;
1361 case ')': if ($name != ""){
1362 $objectclasses[$ocname][$name]= $this->value2container($value);
1363 }
1364 $name= "";
1365 $value= "";
1366 break;
1368 case 'NAME':
1369 case 'DESC':
1370 case 'SUP':
1371 case 'STRUCTURAL':
1372 case 'ABSTRACT':
1373 case 'AUXILIARY':
1374 case 'MUST':
1375 case 'MAY':
1376 if ($name != ""){
1377 $objectclasses[$ocname][$name]= $this->value2container($value);
1378 }
1379 $name= $chunk;
1380 $value= "";
1381 break;
1383 default: $value.= $chunk." ";
1384 }
1385 }
1387 }
1389 return $objectclasses;
1390 }
1392 function value2container($value)
1393 {
1394 /* Set emtpy values to "true" only */
1395 if (preg_match('/^\s*$/', $value)){
1396 return true;
1397 }
1399 /* Remove ' and " if needed */
1400 $value= preg_replace('/^[\'"]/', '', $value);
1401 $value= preg_replace('/[\'"] *$/', '', $value);
1403 /* Convert to array if $ is inside... */
1404 if (preg_match('/\$/', $value)){
1405 $container= preg_split('/\s*\$\s*/', $value);
1406 } else {
1407 $container= chop($value);
1408 }
1410 return ($container);
1411 }
1413 function log($string)
1414 {
1415 if (isset($_SESSION['config'])){
1416 $cfg= $_SESSION['config'];
1417 if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1418 syslog (LOG_INFO, $string);
1419 }
1420 }
1421 }
1423 /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1424 function getCn($dn){
1425 $simple= split(",", $dn);
1427 foreach($simple as $piece) {
1428 $partial= split("=", $piece);
1430 if($partial[0] == "cn"){
1431 return $partial[1];
1432 }
1433 }
1435 }
1437 function get_naming_contexts($server, $admin= "", $password= "")
1438 {
1439 /* Build LDAP connection */
1440 $ds= ldap_connect ($server);
1441 if (!$ds) {
1442 die ("Can't bind to LDAP. No check possible!");
1443 }
1444 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1445 $r= ldap_bind ($ds, $admin, $password);
1447 /* Get base to look for naming contexts */
1448 $sr = @ldap_read ($ds, "", "objectClass=*", array("+"));
1449 $attr= @ldap_get_entries($ds,$sr);
1451 return ($attr[0]['namingcontexts']);
1452 }
1454 }
1456 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1457 ?>