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 $na["gosaUnitTag"]= $tag;
751 } else {
752 $na['objectClass']= array($ocname);
753 }
754 if (isset($classes[$ocname]['AUXILIARY'])){
755 $na['objectClass'][]= $classes[$ocname]['SUP'];
756 }
757 if ($type == "dc"){
758 /* This is bad actually, but - tell me a better way? */
759 $na['objectClass'][]= 'locality';
760 }
761 $na[$type]= $param;
762 if (is_array($classes[$ocname]['MUST'])){
763 foreach($classes[$ocname]['MUST'] as $attr){
764 $na[$attr]= "filled";
765 }
766 }
768 } else {
770 /* Use alternative add... */
771 switch ($type){
772 case 'ou':
773 if ($tag != ""){
774 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
775 $na["gosaUnitTag"]= $tag;
776 } else {
777 $na["objectClass"]= "organizationalUnit";
778 }
779 $na["ou"]= $param;
780 break;
781 case 'dc':
782 if ($tag != ""){
783 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
784 $na["gosaUnitTag"]= $tag;
785 } else {
786 $na["objectClass"]= array("dcObject", "top", "locality");
787 }
788 $na["dc"]= $param;
789 break;
790 default:
791 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
792 echo $_SESSION['errors'];
793 exit;
794 }
796 }
797 $this->cd($cdn);
798 $this->add($na);
799 show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
800 if (!preg_match('/success/i', $this->error)){
801 return FALSE;
802 }
803 }
804 }
806 return TRUE;
807 }
810 function create_missing_trees_old($target)
811 {
812 /* Ignore create_missing trees if the base equals target */
813 if ($target == $this->basedn){
814 return;
815 }
817 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
818 $tmp = ldap_explode_dn($real_path,0);
819 if(!$tmp){
820 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)));
821 return;
822 }
824 $l= array_reverse($tmp);
825 unset($l['count']);
826 $cdn= $this->basedn;
827 $tag= "";
829 foreach ($l as $part){
830 $cdn= "$part,$cdn";
832 /* Ignore referrals */
833 $found= false;
834 foreach($this->referrals as $ref){
835 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
836 if ($base == $cdn){
837 $found= true;
838 break;
839 }
840 }
841 if ($found){
842 continue;
843 }
845 $this->cat ($cdn);
846 $attrs= $this->fetch();
848 /* Create missing entry? */
849 if (count ($attrs)){
851 /* Catch the tag - if present */
852 if (isset($attrs['gosaUnitTag'][0])){
853 $tag= $attrs['gosaUnitTag'][0];
854 }
856 } else {
857 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
858 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
860 $na= array();
861 switch ($type){
862 case 'ou':
863 if ($tag != ""){
864 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
865 $na["gosaUnitTag"]= $tag;
866 } else {
867 $na["objectClass"]= "organizationalUnit";
868 }
869 $na["ou"]= $param;
870 break;
871 case 'dc':
872 if ($tag != ""){
873 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
874 $na["gosaUnitTag"]= $tag;
875 } else {
876 $na["objectClass"]= array("dcObject", "top", "locality");
877 }
878 $na["dc"]= $param;
879 break;
880 default:
881 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
882 echo $_SESSION['errors'];
883 exit;
884 }
885 $this->cd($cdn);
886 $this->add($na);
887 }
888 }
889 }
891 function recursive_remove()
892 {
893 $delarray= array();
895 /* Get sorted list of dn's to delete */
896 $this->search ("(objectClass=*)");
897 while ($this->fetch()){
898 $deldn= $this->getDN();
899 $delarray[$deldn]= strlen($deldn);
900 }
901 arsort ($delarray);
902 reset ($delarray);
904 /* Delete all dn's in subtree */
905 foreach ($delarray as $key => $value){
906 $this->rmdir($key);
907 }
908 }
910 function get_attribute($dn, $name,$r_array=0)
911 {
912 $data= "";
913 if ($this->reconnect) $this->connect();
914 $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
916 /* fill data from LDAP */
917 if ($sr) {
918 $ei= @ldap_first_entry($this->cid, $sr);
919 if ($ei) {
920 if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
921 $data= $info[0];
922 }
924 }
925 }
926 if($r_array==0)
927 return ($data);
928 else
929 return ($info);
932 }
936 function get_additional_error()
937 {
938 $error= "";
939 @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
940 return ($error);
941 }
943 function get_error()
944 {
945 if ($this->error == 'Success'){
946 return $this->error;
947 } else {
948 $adderror= $this->get_additional_error();
949 if ($adderror != ""){
950 $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
951 } else {
952 $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
953 }
954 return $error;
955 }
956 }
958 function get_credentials($url, $referrals= NULL)
959 {
960 $ret= array();
961 $url= preg_replace('!\?\?.*$!', '', $url);
962 $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
964 if ($referrals == NULL){
965 $referrals= $this->referrals;
966 }
968 if (isset($referrals[$server])){
969 return ($referrals[$server]);
970 } else {
971 $ret['ADMIN']= $this->fix($this->binddn);
972 $ret['PASSWORD']= $this->bindpw;
973 }
975 return ($ret);
976 }
979 function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
980 {
981 $display= "";
983 if ($recursive){
984 $this->cd($dn);
985 $this->search("$filter", array('dn'));
986 while ($attrs= $this->fetch()){
987 $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
988 $display.= "\n";
989 }
990 } else {
991 $display.= $this->gen_one_entry($dn);
992 }
994 return ($display);
995 }
997 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
998 {
999 $display= "";
1001 $this->cd($dn);
1002 $this->search("$filter");
1004 $i=0;
1005 while ($attrs= $this->fetch()){
1006 $j=0;
1008 foreach ($attributes as $at){
1009 $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1010 $j++;
1011 }
1013 $i++;
1014 }
1016 return ($display);
1017 }
1020 function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1021 {
1022 $ret = "";
1023 $data = "";
1024 if($this->reconnect){
1025 $this->connect();
1026 }
1028 /* Searching Ldap Tree */
1029 $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1031 /* Get the first entry */
1032 $entry= @ldap_first_entry($this->cid, $sr);
1034 /* Get all attributes related to that Objekt */
1035 $atts = array();
1037 /* Assemble dn */
1038 $atts[0]['name'] = "dn";
1039 $atts[0]['value'] = array('count' => 1, 0 => $dn);
1041 /* Reset index */
1042 $i = 1 ;
1043 $identifier = array();
1044 $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1045 while ($attribute) {
1046 $i++;
1047 $atts[$i]['name'] = $attribute;
1048 $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1050 /* Next one */
1051 $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1052 }
1054 foreach($atts as $at)
1055 {
1056 for ($i= 0; $i<$at['value']['count']; $i++){
1058 /* Check if we must encode the data */
1059 if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1060 $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1061 } else {
1062 $ret .= $at['name'].": ".$at['value'][$i]."\n";
1063 }
1064 }
1065 }
1067 return($ret);
1068 }
1071 function dn_exists($dn)
1072 {
1073 return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1074 }
1078 function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1079 {
1080 if($this->reconnect) $this->connect();
1082 /* First we have to splitt the string ito detect empty lines
1083 An empty line indicates an new Entry */
1084 $entries = split("\n",$str_attr);
1086 $data = "";
1087 $cnt = 0;
1088 $current_line = 0;
1090 /* Every single line ... */
1091 foreach($entries as $entry) {
1092 $current_line ++;
1094 /* Removing Spaces to ..
1095 .. test if a new entry begins */
1096 $tmp = str_replace(" ","",$data );
1098 /* .. prevent empty lines in an entry */
1099 $tmp2 = str_replace(" ","",$entry);
1101 /* If the Block ends (Empty Line) */
1102 if((empty($entry))&&(!empty($tmp))) {
1103 /* Add collected lines as a complete block */
1104 $all[$cnt] = $data;
1105 $cnt ++;
1106 $data ="";
1107 } else {
1109 /* Append lines ... */
1110 if(!empty($tmp2)) {
1111 /* check if we need base64_decode for this line */
1112 if(ereg("::",$tmp2))
1113 {
1114 $encoded = split("::",$entry);
1115 $attr = $encoded[0];
1116 $value = base64_decode($encoded[1]);
1117 /* Add linenumber */
1118 $data .= $current_line."#".$attr.":".$value."\n";
1119 }
1120 else
1121 {
1122 /* Add Linenumber */
1123 $data .= $current_line."#".$entry."\n";
1124 }
1125 }
1126 }
1127 }
1129 /* The Data we collected is not in the array all[];
1130 For example the Data is stored like this..
1132 all[0] = "1#dn : .... \n
1133 2#ObjectType: person \n ...."
1135 Now we check every insertblock and try to insert */
1136 foreach ( $all as $single) {
1137 $lineone = split("\n",$single);
1138 $ndn = split("#", $lineone[0]);
1139 $line = $ndn[1];
1141 $dnn = split (":",$line,2);
1142 $current_line = $ndn[0];
1143 $dn = $dnn[0];
1144 $value = $dnn[1];
1146 /* Every block must begin with a dn */
1147 if($dn != "dn") {
1148 $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1149 return -2;
1150 }
1152 /* Should we use Modify instead of Add */
1153 $usemodify= false;
1155 /* Delete before insert */
1156 $usermdir= false;
1158 /* The dn address already exists! */
1159 if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1161 $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1162 return ALREADY_EXISTING_ENTRY;
1164 } elseif(($this->dn_exists($value))&&($cleanup)){
1166 /* Delete first, then add */
1167 $usermdir = true;
1169 } elseif(($this->dn_exists($value))&&($overwrite)) {
1171 /* Modify instead of Add */
1172 $usemodify = true;
1173 }
1175 /* If we can't Import, return with a file error */
1176 if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1177 $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1178 $current_line);
1179 return UNKNOWN_TOKEN_IN_LDIF_FILE; }
1180 }
1182 return (INSERT_OK);
1183 }
1186 /* Imports a single entry */
1187 function import_single_entry($str_attr,$modify,$delete)
1188 {
1189 if($this->reconnect) $this->connect();
1191 $ret = false;
1192 $rows= split("\n",$str_attr);
1193 $data= false;
1195 foreach($rows as $row) {
1197 /* Check if we use Linenumbers (when import_complete_ldif is called we use
1198 Linenumbers) Linenumbers are use like this 123#attribute : value */
1199 if(!empty($row)) {
1200 if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1202 /* We are using line numbers
1203 Because there is a # before a : */
1204 $tmp1= split("#",$row);
1205 $current_line= $tmp1[0];
1206 $row= $tmp1[1];
1207 }
1209 /* Split the line into attribute and value */
1210 $attr = split(":", $row,2);
1211 $attr[0]= trim($attr[0]); /* attribute */
1212 $attr[1]= trim($attr[1]); /* value */
1214 /* Check for attributes that are used more than once */
1215 if(!isset($data[$attr[0]])) {
1216 $data[$attr[0]]=$attr[1];
1217 } else {
1218 $tmp = $data[$attr[0]];
1220 if(!is_array($tmp)) {
1221 $new[0]=$tmp;
1222 $new[1]=$attr[1];
1223 $datas[$attr[0]]['count']=1;
1224 $data[$attr[0]]=$new;
1225 } else {
1226 $cnt = $datas[$attr[0]]['count'];
1227 $cnt ++;
1228 $data[$attr[0]][$cnt]=$attr[1];
1229 $datas[$attr[0]]['count'] = $cnt;
1230 }
1231 }
1232 }
1233 }
1235 /* If dn is an index of data, we should try to insert the data */
1236 if(isset($data['dn'])) {
1237 /* Creating Entry */
1238 $this->cd($data['dn']);
1240 /* Delete existing entry */
1241 if($delete){
1242 $this->rmdir($data['dn']);
1243 }
1245 /* Create missing trees */
1246 $this->create_missing_trees($data['dn']);
1247 unset($data['dn']);
1249 /* If entry exists use modify */
1250 if(!$modify){
1251 $ret = $this->add($data);
1252 } else {
1253 $ret = $this->modify($data);
1254 }
1255 }
1257 return($ret);
1258 }
1261 function importcsv($str)
1262 {
1263 $lines = split("\n",$str);
1264 foreach($lines as $line)
1265 {
1266 /* continue if theres a comment */
1267 if(substr(trim($line),0,1)=="#"){
1268 continue;
1269 }
1271 $line= str_replace ("\t\t","\t",$line);
1272 $line= str_replace ("\t" ,"," ,$line);
1273 echo $line;
1275 $cells = split(",",$line ) ;
1276 $linet= str_replace ("\t\t",",",$line);
1277 $cells = split("\t",$line);
1278 $count = count($cells);
1279 }
1281 }
1283 function get_objectclasses_old()
1284 {
1285 $objectclasses = array();
1287 # Get base to look for schema
1288 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1289 $attr = @ldap_get_entries($this->cid,$sr);
1291 if (!isset($attr[0]['subschemasubentry'][0])){
1292 $this->error = @ldap_error($this->cid);
1293 gosa_log($this->get_error());
1294 return array();
1295 }
1297 # Get list of objectclasses
1298 $nb= $attr[0]['subschemasubentry'][0];
1299 $objectclasses= array();
1300 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1301 $attrs= ldap_get_entries($this->cid,$sr);
1302 if (!isset($attrs[0])){
1303 return array();
1304 }
1305 foreach ($attrs[0]['objectclasses'] as $val){
1306 $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1307 if ($name != $val){
1308 $objectclasses[$name]= $val;
1309 }
1310 }
1312 return $objectclasses;
1313 }
1316 function get_objectclasses()
1317 {
1318 global $config;
1319 $objectclasses = array();
1321 if(isset($config) && preg_match("/config/i",get_class($config))){
1322 if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
1323 return($objectclasses);
1324 }
1325 }
1327 # Get base to look for schema
1328 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1329 if(!$sr){
1330 $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1331 }
1333 $attr = @ldap_get_entries($this->cid,$sr);
1334 if (!isset($attr[0]['subschemasubentry'][0])){
1335 return array();
1336 }
1338 /* Get list of objectclasses and fill array */
1339 $nb= $attr[0]['subschemasubentry'][0];
1340 $objectclasses= array();
1341 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1342 $attrs= ldap_get_entries($this->cid,$sr);
1343 if (!isset($attrs[0])){
1344 return array();
1345 }
1346 foreach ($attrs[0]['objectclasses'] as $val){
1347 if (preg_match('/^[0-9]+$/', $val)){
1348 continue;
1349 }
1350 $name= "OID";
1351 $pattern= split(' ', $val);
1352 $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1353 $objectclasses[$ocname]= array();
1355 foreach($pattern as $chunk){
1356 switch($chunk){
1358 case '(':
1359 $value= "";
1360 break;
1362 case ')': if ($name != ""){
1363 $objectclasses[$ocname][$name]= $this->value2container($value);
1364 }
1365 $name= "";
1366 $value= "";
1367 break;
1369 case 'NAME':
1370 case 'DESC':
1371 case 'SUP':
1372 case 'STRUCTURAL':
1373 case 'ABSTRACT':
1374 case 'AUXILIARY':
1375 case 'MUST':
1376 case 'MAY':
1377 if ($name != ""){
1378 $objectclasses[$ocname][$name]= $this->value2container($value);
1379 }
1380 $name= $chunk;
1381 $value= "";
1382 break;
1384 default: $value.= $chunk." ";
1385 }
1386 }
1388 }
1390 return $objectclasses;
1391 }
1393 function value2container($value)
1394 {
1395 /* Set emtpy values to "true" only */
1396 if (preg_match('/^\s*$/', $value)){
1397 return true;
1398 }
1400 /* Remove ' and " if needed */
1401 $value= preg_replace('/^[\'"]/', '', $value);
1402 $value= preg_replace('/[\'"] *$/', '', $value);
1404 /* Convert to array if $ is inside... */
1405 if (preg_match('/\$/', $value)){
1406 $container= preg_split('/\s*\$\s*/', $value);
1407 } else {
1408 $container= chop($value);
1409 }
1411 return ($container);
1412 }
1414 function log($string)
1415 {
1416 if (isset($_SESSION['config'])){
1417 $cfg= $_SESSION['config'];
1418 if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1419 syslog (LOG_INFO, $string);
1420 }
1421 }
1422 }
1424 /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1425 function getCn($dn){
1426 $simple= split(",", $dn);
1428 foreach($simple as $piece) {
1429 $partial= split("=", $piece);
1431 if($partial[0] == "cn"){
1432 return $partial[1];
1433 }
1434 }
1436 }
1438 function get_naming_contexts($server, $admin= "", $password= "")
1439 {
1440 /* Build LDAP connection */
1441 $ds= ldap_connect ($server);
1442 if (!$ds) {
1443 die ("Can't bind to LDAP. No check possible!");
1444 }
1445 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1446 $r= ldap_bind ($ds, $admin, $password);
1448 /* Get base to look for naming contexts */
1449 $sr = @ldap_read ($ds, "", "objectClass=*", array("+"));
1450 $attr= @ldap_get_entries($ds,$sr);
1452 return ($attr[0]['namingcontexts']);
1453 }
1455 }
1457 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1458 ?>