0e1e909b5282c3e4e6ae12e96847863947321076
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 to fix problematic characters in DN's that are used for search
98 requests. I.e. member=.... */
99 function prepare4filter($dn)
100 {
101 return normalizeLdap(preg_replace('/\\\\/', '\\\\\\', @LDAP::fix($dn)));
102 }
105 function connect()
106 {
107 $this->hascon=false;
108 $this->reconnect=false;
109 if ($this->cid= @ldap_connect($this->hostname)) {
110 @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
111 if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
112 @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
113 @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
114 }
115 if (function_exists("ldap_start_tls") && $this->tls){
116 @ldap_start_tls($this->cid);
117 }
119 $this->error = "No Error";
120 if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
121 $this->error = "Success";
122 $this->hascon=true;
123 } else {
124 if ($this->reconnect){
125 if ($this->error != "Success"){
126 $this->error = "Could not rebind to " . $this->binddn;
127 }
128 } else {
129 $this->error = "Could not bind to " . $this->binddn;
130 }
131 }
132 } else {
133 $this->error = "Could not connect to LDAP server";
134 }
135 }
137 function rebind($ldap, $referral)
138 {
139 $credentials= $this->get_credentials($referral);
140 if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
141 $this->error = "Success";
142 $this->hascon=true;
143 $this->reconnect= true;
144 return (0);
145 } else {
146 $this->error = "Could not bind to " . $credentials['ADMIN'];
147 return NULL;
148 }
149 }
151 function reconnect()
152 {
153 if ($this->reconnect){
154 @ldap_unbind($this->cid);
155 $this->cid = NULL;
156 }
157 }
159 function unbind()
160 {
161 @ldap_unbind($this->cid);
162 $this->cid = NULL;
163 }
165 function disconnect()
166 {
167 if($this->hascon){
168 @ldap_close($this->cid);
169 $this->hascon=false;
170 }
171 }
173 function cd($dir)
174 {
175 if ($dir == "..")
176 $this->basedn = $this->getParentDir();
177 else
178 $this->basedn = $this->convert($dir);
179 }
181 function getParentDir($basedn = "")
182 {
183 if ($basedn=="")
184 $basedn = $this->basedn;
185 else
186 $basedn = $this->convert($this->basedn);
187 return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
188 }
190 function search($filter, $attrs= array())
191 {
192 if($this->hascon){
193 if ($this->reconnect) $this->connect();
195 $start = microtime();
197 $this->clearResult();
198 $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
199 $this->error = @ldap_error($this->cid);
200 $this->resetResult();
201 $this->hasres=true;
203 /* Check if query took longer as specified in max_ldap_query_time */
204 if($this->max_ldap_query_time){
205 $diff = get_MicroTimeDiff($start,microtime());
206 if($diff > $this->max_ldap_query_time){
207 print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
208 }
209 }
211 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
213 return($this->sr);
214 }else{
215 $this->error = "Could not connect to LDAP server";
216 return("");
217 }
218 }
220 function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
221 {
222 if($this->hascon){
223 if ($this->reconnect) $this->connect();
224 $this->clearResult();
225 if ($basedn == "")
226 $basedn = $this->basedn;
227 else
228 $basedn= $this->convert($basedn);
230 $start = microtime();
232 $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
233 $this->error = @ldap_error($this->cid);
234 $this->resetResult();
235 $this->hasres=true;
237 /* Check if query took longer as specified in max_ldap_query_time */
238 if($this->max_ldap_query_time){
239 $diff = get_MicroTimeDiff($start,microtime());
240 if($diff > $this->max_ldap_query_time){
241 print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
242 }
243 }
245 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
247 return($this->sr);
248 }else{
249 $this->error = "Could not connect to LDAP server";
250 return("");
251 }
252 }
254 function cat($dn,$attrs= array("*"))
255 {
256 if($this->hascon){
257 if ($this->reconnect) $this->connect();
258 $start = microtime();
259 $this->clearResult();
260 $filter = "(objectclass=*)";
261 $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
262 $this->error = @ldap_error($this->cid);
263 $this->resetResult();
264 $this->hasres=true;
265 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
266 return($this->sr);
267 }else{
268 $this->error = "Could not connect to LDAP server";
269 return("");
270 }
271 }
273 function set_size_limit($size)
274 {
275 /* Ignore zero settings */
276 if ($size == 0){
277 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
278 }
279 if($this->hascon){
280 @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
281 } else {
282 $this->error = "Could not connect to LDAP server";
283 }
284 }
286 function fetch()
287 {
288 $att= array();
289 if($this->hascon){
290 if($this->hasres){
291 if ($this->start == 0)
292 {
293 $this->start = 1;
294 $this->re= @ldap_first_entry($this->cid, $this->sr);
295 } else {
296 $this->re= @ldap_next_entry($this->cid, $this->re);
297 }
298 if ($this->re)
299 {
300 $att= @ldap_get_attributes($this->cid, $this->re);
301 $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
302 }
303 $this->error = @ldap_error($this->cid);
304 if (!isset($att)){
305 $att= array();
306 }
307 return($att);
308 }else{
309 $this->error = "Perform a Fetch with no Search";
310 return("");
311 }
312 }else{
313 $this->error = "Could not connect to LDAP server";
314 return("");
315 }
316 }
318 function resetResult()
319 {
320 $this->start = 0;
321 }
323 function clearResult()
324 {
325 if($this->hasres){
326 $this->hasres = false;
327 @ldap_free_result($this->sr);
328 }
329 }
331 function getDN()
332 {
333 if($this->hascon){
334 if($this->hasres){
336 if(!$this->re)
337 {
338 $this->error = "Perform a Fetch with no valid Result";
339 }
340 else
341 {
342 $rv = @ldap_get_dn($this->cid, $this->re);
344 $this->error = @ldap_error($this->cid);
345 return(trim($this->convert($rv)));
346 }
347 }else{
348 $this->error = "Perform a Fetch with no Search";
349 return("");
350 }
351 }else{
352 $this->error = "Could not connect to LDAP server";
353 return("");
354 }
355 }
357 function count()
358 {
359 if($this->hascon){
360 if($this->hasres){
361 $rv = @ldap_count_entries($this->cid, $this->sr);
362 $this->error = @ldap_error($this->cid);
363 return($rv);
364 }else{
365 $this->error = "Perform a Fetch with no Search";
366 return("");
367 }
368 }else{
369 $this->error = "Could not connect to LDAP server";
370 return("");
371 }
372 }
374 function rm($attrs = "", $dn = "")
375 {
376 if($this->hascon){
377 if ($this->reconnect) $this->connect();
378 if ($dn == "")
379 $dn = $this->basedn;
381 $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
382 $this->error = @ldap_error($this->cid);
383 return($r);
384 }else{
385 $this->error = "Could not connect to LDAP server";
386 return("");
387 }
388 }
390 function rename($attrs, $dn = "")
391 {
392 if($this->hascon){
393 if ($this->reconnect) $this->connect();
394 if ($dn == "")
395 $dn = $this->basedn;
397 $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
398 $this->error = @ldap_error($this->cid);
399 return($r);
400 }else{
401 $this->error = "Could not connect to LDAP server";
402 return("");
403 }
404 }
406 function rmdir($deletedn)
407 {
408 if($this->hascon){
409 if ($this->reconnect) $this->connect();
410 $start= microtime();
411 $r = @ldap_delete($this->cid, $this->fix($deletedn));
412 $this->error = @ldap_error($this->cid);
413 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
414 return($r ? $r : 0);
415 }else{
416 $this->error = "Could not connect to LDAP server";
417 return("");
418 }
419 }
421 /**
422 * Function rmdir_recursive
423 *
424 * Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
425 * Parameters: The dn to delete
426 * GiveBack: True on sucessfull , 0 in error, and "" when we don't get a ldap conection
427 *
428 */
430 function rmdir_recursive($deletedn)
431 {
432 if($this->hascon){
433 if ($this->reconnect) $this->connect();
434 $delarray= array();
436 /* Get sorted list of dn's to delete */
437 $this->ls ("(objectClass=*)",$deletedn);
438 while ($this->fetch()){
439 $deldn= $this->getDN();
440 $delarray[$deldn]= strlen($deldn);
441 }
442 arsort ($delarray);
443 reset ($delarray);
445 /* Really Delete ALL dn's in subtree */
446 foreach ($delarray as $key => $value){
447 $this->rmdir_recursive($key);
448 }
450 /* Finally Delete own Node */
451 $r = @ldap_delete($this->cid, $this->fix($deletedn));
452 $this->error = @ldap_error($this->cid);
453 return($r ? $r : 0);
454 }else{
455 $this->error = "Could not connect to LDAP server";
456 return("");
457 }
458 }
460 /* Copy given attributes and sub-dns with attributes to destination dn
461 */
462 function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
463 {
464 error_reporting(E_ALL);
466 if($is_first){
467 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
468 }else{
469 if(preg_match("/^ou=/",$sourcedn)){
470 echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
471 }else{
472 $tmp = split(",",$sourcedn);
474 echo " <b>"._("Object").":</b> ";
476 $deststr = @LDAP::fix($destinationdn);
477 if(strlen($deststr) > 96){
478 $deststr = substr($deststr,0,96)."...";
479 }
481 echo $deststr."<br>";
482 }
483 }
485 flush();
487 if($this->hascon){
488 if ($this->reconnect) $this->connect();
490 /* Save base dn */
491 $basedn= $this->basedn;
492 $delarray= array();
494 /* Check if destination entry already exists */
495 $this->cat($destinationdn);
497 if($this->count()){
498 return;
499 }else{
501 $this->clearResult();
503 /* Get source entry */
504 $this->cd($basedn);
505 $this->cat($sourcedn);
506 $attr = $this->fetch();
508 /* Error while fetching object / attribute abort*/
509 if((!$attr) || (count($attr)) ==0) {
510 echo _("Error while fetching source dn - aborted!");
511 return;
512 }
514 /* check if this is a department */
515 if(in_array("organizationalUnit",$attr['objectClass'])){
516 $attr['dn'] = $this->convert($destinationdn);
517 $this->cd($basedn);
518 $this->create_missing_trees($destinationdn);
519 $this->cd($destinationdn);
521 /* If is first entry, append FAIbranch to department entry */
522 if($is_first){
523 $this->cat($destinationdn);
524 $attr= $this->fetch();
526 /* Filter unneeded informations */
527 foreach($attr as $key => $value){
528 if(is_numeric($key)) unset($attr[$key]);
529 if(isset($attr[$key]['count'])){
530 if(is_array($attr[$key])){
531 unset($attr[$key]['count']);
532 }
533 }
534 }
536 unset($attr['count']);
537 unset($attr['dn']);
539 /* Add marking attribute */
540 $attr['objectClass'][] = "FAIbranch";
542 /* Add this entry */
543 $this->modify($attr);
544 }
545 }else{
547 /* If this is no department */
548 foreach($attr as $key => $value){
549 if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
550 $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
551 $ei= ldap_first_entry($this->cid, $sr);
552 if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
553 $attr[$key] = $tmp;
554 }
555 }
557 if(is_numeric($key)) unset($attr[$key]);
558 if(isset($attr[$key]['count'])){
559 if(is_array($attr[$key])){
560 unset($attr[$key]['count']);
561 }
562 }
563 }
564 unset($attr['count']);
565 unset($attr['dn']);
567 if(!in_array("gosaApplication" , $attr['objectClass'])){
568 if($type=="branch"){
569 $attr['FAIstate'] ="branch";
570 }elseif($type=="freeze"){
571 $attr['FAIstate'] ="freeze";
572 }else{
573 print_red(_("Unknown FAIstate %s"),$type);
574 }
575 }elseif(in_array("gosaApplication",$attr['objectClass'])){
576 if(!in_array("FAIobject",$attr['objectClass'])){
577 $attr['objectClass'][] = "FAIobject";
578 }
579 $attr['FAIstate'] = $type;
580 }
582 /* Replace FAIdebianRelease with new release name */
583 if(in_array("FAIpackageList" , $attr['objectClass'])){
584 $attr['FAIdebianRelease'] = $destinationName;
585 if($type=="branch"){
586 $attr['FAIstate'] ="branch";
587 }elseif($type=="freeze"){
588 $attr['FAIstate'] ="freeze";
589 }else{
590 print_red(_("Unknown FAIstate %s"),$type);
591 }
592 }
594 /* Add entry */
595 $this->cd($destinationdn);
596 $this->cat($destinationdn);
597 $a = $this->fetch();
598 if(!count($a)){
599 $this->add($attr);
600 }
602 if($this->error != "Success"){
603 /* Some error occurred */
604 print "---------------------------------------------";
605 print $this->get_error()."<br>";
606 print $sourcedn."<br>";
607 print $destinationdn."<br>";
608 print_a( $attr);
609 exit();
610 }
611 }
612 }
614 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
616 $this->ls ("(objectClass=*)",$sourcedn);
617 while ($this->fetch()){
618 $deldn= $this->getDN();
619 $delarray[$deldn]= strlen($deldn);
620 }
621 asort ($delarray);
622 reset ($delarray);
624 $depth ++;
625 foreach($delarray as $dn => $bla){
626 if($dn != $destinationdn){
627 $this->cd($basedn);
628 $item = $this->fetch($this->cat($dn));
629 if(!in_array("FAIbranch",$item['objectClass'])){
630 $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
631 }
632 }
633 }
634 }
635 if($is_first){
636 echo "<p class='seperator'> </p>";
637 }
639 }
641 function modify($attrs)
642 {
643 if(count($attrs) == 0){
644 return (0);
645 }
646 if($this->hascon){
647 if ($this->reconnect) $this->connect();
648 $start= microtime();
649 $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
650 $this->error = @ldap_error($this->cid);
651 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
652 return($r ? $r : 0);
653 }else{
654 $this->error = "Could not connect to LDAP server";
655 return("");
656 }
657 }
659 function add($attrs)
660 {
661 if($this->hascon){
662 if ($this->reconnect) $this->connect();
663 $start= microtime();
664 $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
665 $this->error = @ldap_error($this->cid);
666 $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
667 return($r ? $r : 0);
668 }else{
669 $this->error = "Could not connect to LDAP server";
670 return("");
671 }
672 }
675 function create_missing_trees($target)
676 {
677 global $config;
679 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
681 if ($target == $this->basedn){
682 $l= array("dummy");
683 } else {
684 $l= array_reverse(gosa_ldap_explode_dn($real_path));
685 }
686 unset($l['count']);
687 $cdn= $this->basedn;
688 $tag= "";
690 /* Load schema if available... */
691 $classes= $this->get_objectclasses();
693 foreach ($l as $part){
694 if ($part != "dummy"){
695 $cdn= "$part,$cdn";
696 }
698 /* Ignore referrals */
699 $found= false;
700 foreach($this->referrals as $ref){
701 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
702 if ($base == $cdn){
703 $found= true;
704 break;
705 }
706 }
707 if ($found){
708 continue;
709 }
711 $this->cat ($cdn);
712 $attrs= $this->fetch();
714 /* Create missing entry? */
715 if (count ($attrs)){
716 /* Catch the tag - if present */
717 if (isset($attrs['gosaUnitTag'][0])){
718 $tag= $attrs['gosaUnitTag'][0];
719 }
721 } else {
722 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
723 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
725 $na= array();
727 /* Automatic or traditional? */
728 if(count($classes)){
730 /* Get name of first matching objectClass */
731 $ocname= "";
732 foreach($classes as $class){
733 if (isset($class['MUST']) && $class['MUST'] == "$type"){
735 /* Look for first classes that is structural... */
736 if (isset($class['STRUCTURAL'])){
737 $ocname= $class['NAME'];
738 break;
739 }
741 /* Look for classes that are auxiliary... */
742 if (isset($class['AUXILIARY'])){
743 $ocname= $class['NAME'];
744 }
745 }
746 }
748 /* Bail out, if we've nothing to do... */
749 if ($ocname == ""){
750 print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
751 echo $_SESSION['errors'];
752 exit;
753 }
755 /* Assemble_entry */
756 if ($tag != ""){
757 $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
758 $na["gosaUnitTag"]= $tag;
759 } else {
760 $na['objectClass']= array($ocname);
761 }
762 if (isset($classes[$ocname]['AUXILIARY'])){
763 $na['objectClass'][]= $classes[$ocname]['SUP'];
764 }
765 if ($type == "dc"){
766 /* This is bad actually, but - tell me a better way? */
767 $na['objectClass'][]= 'locality';
768 }
769 $na[$type]= $param;
770 if (is_array($classes[$ocname]['MUST'])){
771 foreach($classes[$ocname]['MUST'] as $attr){
772 $na[$attr]= "filled";
773 }
774 }
776 } else {
778 /* Use alternative add... */
779 switch ($type){
780 case 'ou':
781 if ($tag != ""){
782 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
783 $na["gosaUnitTag"]= $tag;
784 } else {
785 $na["objectClass"]= "organizationalUnit";
786 }
787 $na["ou"]= $param;
788 break;
789 case 'dc':
790 if ($tag != ""){
791 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
792 $na["gosaUnitTag"]= $tag;
793 } else {
794 $na["objectClass"]= array("dcObject", "top", "locality");
795 }
796 $na["dc"]= $param;
797 break;
798 default:
799 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
800 echo $_SESSION['errors'];
801 exit;
802 }
804 }
805 $this->cd($cdn);
806 $this->add($na);
807 show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
808 if (!preg_match('/success/i', $this->error)){
809 return FALSE;
810 }
811 }
812 }
814 return TRUE;
815 }
818 function create_missing_trees_old($target)
819 {
820 /* Ignore create_missing trees if the base equals target */
821 if ($target == $this->basedn){
822 return;
823 }
825 $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
826 $tmp = ldap_explode_dn($real_path,0);
827 if(!$tmp){
828 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)));
829 return;
830 }
832 $l= array_reverse($tmp);
833 unset($l['count']);
834 $cdn= $this->basedn;
835 $tag= "";
837 foreach ($l as $part){
838 $cdn= "$part,$cdn";
840 /* Ignore referrals */
841 $found= false;
842 foreach($this->referrals as $ref){
843 $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
844 if ($base == $cdn){
845 $found= true;
846 break;
847 }
848 }
849 if ($found){
850 continue;
851 }
853 $this->cat ($cdn);
854 $attrs= $this->fetch();
856 /* Create missing entry? */
857 if (count ($attrs)){
859 /* Catch the tag - if present */
860 if (isset($attrs['gosaUnitTag'][0])){
861 $tag= $attrs['gosaUnitTag'][0];
862 }
864 } else {
865 $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
866 $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
868 $na= array();
869 switch ($type){
870 case 'ou':
871 if ($tag != ""){
872 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
873 $na["gosaUnitTag"]= $tag;
874 } else {
875 $na["objectClass"]= "organizationalUnit";
876 }
877 $na["ou"]= $param;
878 break;
879 case 'dc':
880 if ($tag != ""){
881 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
882 $na["gosaUnitTag"]= $tag;
883 } else {
884 $na["objectClass"]= array("dcObject", "top", "locality");
885 }
886 $na["dc"]= $param;
887 break;
888 default:
889 print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
890 echo $_SESSION['errors'];
891 exit;
892 }
893 $this->cd($cdn);
894 $this->add($na);
895 }
896 }
897 }
899 function recursive_remove()
900 {
901 $delarray= array();
903 /* Get sorted list of dn's to delete */
904 $this->search ("(objectClass=*)");
905 while ($this->fetch()){
906 $deldn= $this->getDN();
907 $delarray[$deldn]= strlen($deldn);
908 }
909 arsort ($delarray);
910 reset ($delarray);
912 /* Delete all dn's in subtree */
913 foreach ($delarray as $key => $value){
914 $this->rmdir($key);
915 }
916 }
918 function get_attribute($dn, $name,$r_array=0)
919 {
920 $data= "";
921 if ($this->reconnect) $this->connect();
922 $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
924 /* fill data from LDAP */
925 if ($sr) {
926 $ei= @ldap_first_entry($this->cid, $sr);
927 if ($ei) {
928 if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
929 $data= $info[0];
930 }
932 }
933 }
934 if($r_array==0)
935 return ($data);
936 else
937 return ($info);
940 }
944 function get_additional_error()
945 {
946 $error= "";
947 @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
948 return ($error);
949 }
951 function get_error()
952 {
953 if ($this->error == 'Success'){
954 return $this->error;
955 } else {
956 $adderror= $this->get_additional_error();
957 if ($adderror != ""){
958 $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
959 } else {
960 $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
961 }
962 return $error;
963 }
964 }
966 function get_credentials($url, $referrals= NULL)
967 {
968 $ret= array();
969 $url= preg_replace('!\?\?.*$!', '', $url);
970 $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
972 if ($referrals == NULL){
973 $referrals= $this->referrals;
974 }
976 if (isset($referrals[$server])){
977 return ($referrals[$server]);
978 } else {
979 $ret['ADMIN']= $this->fix($this->binddn);
980 $ret['PASSWORD']= $this->bindpw;
981 }
983 return ($ret);
984 }
987 function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
988 {
989 $display= "";
991 if ($recursive){
992 $this->cd($dn);
993 $this->search("$filter", array('dn'));
994 while ($attrs= $this->fetch()){
995 $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
996 $display.= "\n";
997 }
998 } else {
999 $display.= $this->gen_one_entry($dn);
1000 }
1002 return ($display);
1003 }
1005 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
1006 {
1007 $display= "";
1009 $this->cd($dn);
1010 $this->search("$filter");
1012 $i=0;
1013 while ($attrs= $this->fetch()){
1014 $j=0;
1016 foreach ($attributes as $at){
1017 $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1018 $j++;
1019 }
1021 $i++;
1022 }
1024 return ($display);
1025 }
1028 function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1029 {
1030 $ret = "";
1031 $data = "";
1032 if($this->reconnect){
1033 $this->connect();
1034 }
1036 /* Searching Ldap Tree */
1037 $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1039 /* Get the first entry */
1040 $entry= @ldap_first_entry($this->cid, $sr);
1042 /* Get all attributes related to that Objekt */
1043 $atts = array();
1045 /* Assemble dn */
1046 $atts[0]['name'] = "dn";
1047 $atts[0]['value'] = array('count' => 1, 0 => $dn);
1049 /* Reset index */
1050 $i = 1 ;
1051 $identifier = array();
1052 $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1053 while ($attribute) {
1054 $i++;
1055 $atts[$i]['name'] = $attribute;
1056 $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1058 /* Next one */
1059 $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1060 }
1062 foreach($atts as $at)
1063 {
1064 for ($i= 0; $i<$at['value']['count']; $i++){
1066 /* Check if we must encode the data */
1067 if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1068 $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1069 } else {
1070 $ret .= $at['name'].": ".$at['value'][$i]."\n";
1071 }
1072 }
1073 }
1075 return($ret);
1076 }
1079 function dn_exists($dn)
1080 {
1081 return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1082 }
1086 function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1087 {
1088 if($this->reconnect) $this->connect();
1090 /* First we have to splitt the string ito detect empty lines
1091 An empty line indicates an new Entry */
1092 $entries = split("\n",$str_attr);
1094 $data = "";
1095 $cnt = 0;
1096 $current_line = 0;
1098 /* Every single line ... */
1099 foreach($entries as $entry) {
1100 $current_line ++;
1102 /* Removing Spaces to ..
1103 .. test if a new entry begins */
1104 $tmp = str_replace(" ","",$data );
1106 /* .. prevent empty lines in an entry */
1107 $tmp2 = str_replace(" ","",$entry);
1109 /* If the Block ends (Empty Line) */
1110 if((empty($entry))&&(!empty($tmp))) {
1111 /* Add collected lines as a complete block */
1112 $all[$cnt] = $data;
1113 $cnt ++;
1114 $data ="";
1115 } else {
1117 /* Append lines ... */
1118 if(!empty($tmp2)) {
1119 /* check if we need base64_decode for this line */
1120 if(ereg("::",$tmp2))
1121 {
1122 $encoded = split("::",$entry);
1123 $attr = $encoded[0];
1124 $value = base64_decode($encoded[1]);
1125 /* Add linenumber */
1126 $data .= $current_line."#".$attr.":".$value."\n";
1127 }
1128 else
1129 {
1130 /* Add Linenumber */
1131 $data .= $current_line."#".$entry."\n";
1132 }
1133 }
1134 }
1135 }
1137 /* The Data we collected is not in the array all[];
1138 For example the Data is stored like this..
1140 all[0] = "1#dn : .... \n
1141 2#ObjectType: person \n ...."
1143 Now we check every insertblock and try to insert */
1144 foreach ( $all as $single) {
1145 $lineone = split("\n",$single);
1146 $ndn = split("#", $lineone[0]);
1147 $line = $ndn[1];
1149 $dnn = split (":",$line,2);
1150 $current_line = $ndn[0];
1151 $dn = $dnn[0];
1152 $value = $dnn[1];
1154 /* Every block must begin with a dn */
1155 if($dn != "dn") {
1156 $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1157 return -2;
1158 }
1160 /* Should we use Modify instead of Add */
1161 $usemodify= false;
1163 /* Delete before insert */
1164 $usermdir= false;
1166 /* The dn address already exists! */
1167 if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1169 $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1170 return ALREADY_EXISTING_ENTRY;
1172 } elseif(($this->dn_exists($value))&&($cleanup)){
1174 /* Delete first, then add */
1175 $usermdir = true;
1177 } elseif(($this->dn_exists($value))&&($overwrite)) {
1179 /* Modify instead of Add */
1180 $usemodify = true;
1181 }
1183 /* If we can't Import, return with a file error */
1184 if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1185 $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1186 $current_line);
1187 return UNKNOWN_TOKEN_IN_LDIF_FILE; }
1188 }
1190 return (INSERT_OK);
1191 }
1194 /* Imports a single entry */
1195 function import_single_entry($str_attr,$modify,$delete)
1196 {
1197 if($this->reconnect) $this->connect();
1199 $ret = false;
1200 $rows= split("\n",$str_attr);
1201 $data= false;
1203 foreach($rows as $row) {
1205 /* Check if we use Linenumbers (when import_complete_ldif is called we use
1206 Linenumbers) Linenumbers are use like this 123#attribute : value */
1207 if(!empty($row)) {
1208 if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1210 /* We are using line numbers
1211 Because there is a # before a : */
1212 $tmp1= split("#",$row);
1213 $current_line= $tmp1[0];
1214 $row= $tmp1[1];
1215 }
1217 /* Split the line into attribute and value */
1218 $attr = split(":", $row,2);
1219 $attr[0]= trim($attr[0]); /* attribute */
1220 $attr[1]= trim($attr[1]); /* value */
1222 /* Check for attributes that are used more than once */
1223 if(!isset($data[$attr[0]])) {
1224 $data[$attr[0]]=$attr[1];
1225 } else {
1226 $tmp = $data[$attr[0]];
1228 if(!is_array($tmp)) {
1229 $new[0]=$tmp;
1230 $new[1]=$attr[1];
1231 $datas[$attr[0]]['count']=1;
1232 $data[$attr[0]]=$new;
1233 } else {
1234 $cnt = $datas[$attr[0]]['count'];
1235 $cnt ++;
1236 $data[$attr[0]][$cnt]=$attr[1];
1237 $datas[$attr[0]]['count'] = $cnt;
1238 }
1239 }
1240 }
1241 }
1243 /* If dn is an index of data, we should try to insert the data */
1244 if(isset($data['dn'])) {
1245 /* Creating Entry */
1246 $this->cd($data['dn']);
1248 /* Delete existing entry */
1249 if($delete){
1250 $this->rmdir($data['dn']);
1251 }
1253 /* Create missing trees */
1254 $this->create_missing_trees($data['dn']);
1255 unset($data['dn']);
1257 /* If entry exists use modify */
1258 if(!$modify){
1259 $ret = $this->add($data);
1260 } else {
1261 $ret = $this->modify($data);
1262 }
1263 }
1265 return($ret);
1266 }
1269 function importcsv($str)
1270 {
1271 $lines = split("\n",$str);
1272 foreach($lines as $line)
1273 {
1274 /* continue if theres a comment */
1275 if(substr(trim($line),0,1)=="#"){
1276 continue;
1277 }
1279 $line= str_replace ("\t\t","\t",$line);
1280 $line= str_replace ("\t" ,"," ,$line);
1281 echo $line;
1283 $cells = split(",",$line ) ;
1284 $linet= str_replace ("\t\t",",",$line);
1285 $cells = split("\t",$line);
1286 $count = count($cells);
1287 }
1289 }
1291 function get_objectclasses_old()
1292 {
1293 $objectclasses = array();
1295 # Get base to look for schema
1296 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1297 $attr = @ldap_get_entries($this->cid,$sr);
1299 if (!isset($attr[0]['subschemasubentry'][0])){
1300 $this->error = @ldap_error($this->cid);
1301 gosa_log($this->get_error());
1302 return array();
1303 }
1305 # Get list of objectclasses
1306 $nb= $attr[0]['subschemasubentry'][0];
1307 $objectclasses= array();
1308 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1309 $attrs= ldap_get_entries($this->cid,$sr);
1310 if (!isset($attrs[0])){
1311 return array();
1312 }
1313 foreach ($attrs[0]['objectclasses'] as $val){
1314 $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1315 if ($name != $val){
1316 $objectclasses[$name]= $val;
1317 }
1318 }
1320 return $objectclasses;
1321 }
1324 function get_objectclasses()
1325 {
1326 global $config;
1327 $objectclasses = array();
1329 if(isset($config) && preg_match("/config/i",get_class($config))){
1330 if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
1331 return($objectclasses);
1332 }
1333 }
1335 # Get base to look for schema
1336 $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1337 if(!$sr){
1338 $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1339 }
1341 $attr = @ldap_get_entries($this->cid,$sr);
1342 if (!isset($attr[0]['subschemasubentry'][0])){
1343 return array();
1344 }
1346 /* Get list of objectclasses and fill array */
1347 $nb= $attr[0]['subschemasubentry'][0];
1348 $objectclasses= array();
1349 $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1350 $attrs= ldap_get_entries($this->cid,$sr);
1351 if (!isset($attrs[0])){
1352 return array();
1353 }
1354 foreach ($attrs[0]['objectclasses'] as $val){
1355 if (preg_match('/^[0-9]+$/', $val)){
1356 continue;
1357 }
1358 $name= "OID";
1359 $pattern= split(' ', $val);
1360 $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1361 $objectclasses[$ocname]= array();
1363 foreach($pattern as $chunk){
1364 switch($chunk){
1366 case '(':
1367 $value= "";
1368 break;
1370 case ')': if ($name != ""){
1371 $objectclasses[$ocname][$name]= $this->value2container($value);
1372 }
1373 $name= "";
1374 $value= "";
1375 break;
1377 case 'NAME':
1378 case 'DESC':
1379 case 'SUP':
1380 case 'STRUCTURAL':
1381 case 'ABSTRACT':
1382 case 'AUXILIARY':
1383 case 'MUST':
1384 case 'MAY':
1385 if ($name != ""){
1386 $objectclasses[$ocname][$name]= $this->value2container($value);
1387 }
1388 $name= $chunk;
1389 $value= "";
1390 break;
1392 default: $value.= $chunk." ";
1393 }
1394 }
1396 }
1398 return $objectclasses;
1399 }
1401 function value2container($value)
1402 {
1403 /* Set emtpy values to "true" only */
1404 if (preg_match('/^\s*$/', $value)){
1405 return true;
1406 }
1408 /* Remove ' and " if needed */
1409 $value= preg_replace('/^[\'"]/', '', $value);
1410 $value= preg_replace('/[\'"] *$/', '', $value);
1412 /* Convert to array if $ is inside... */
1413 if (preg_match('/\$/', $value)){
1414 $container= preg_split('/\s*\$\s*/', $value);
1415 } else {
1416 $container= chop($value);
1417 }
1419 return ($container);
1420 }
1422 function log($string)
1423 {
1424 if (isset($_SESSION['config'])){
1425 $cfg= $_SESSION['config'];
1426 if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1427 syslog (LOG_INFO, $string);
1428 }
1429 }
1430 }
1432 /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1433 function getCn($dn){
1434 $simple= split(",", $dn);
1436 foreach($simple as $piece) {
1437 $partial= split("=", $piece);
1439 if($partial[0] == "cn"){
1440 return $partial[1];
1441 }
1442 }
1444 }
1446 function get_naming_contexts($server, $admin= "", $password= "")
1447 {
1448 /* Build LDAP connection */
1449 $ds= ldap_connect ($server);
1450 if (!$ds) {
1451 die ("Can't bind to LDAP. No check possible!");
1452 }
1453 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1454 $r= ldap_bind ($ds, $admin, $password);
1456 /* Get base to look for naming contexts */
1457 $sr = @ldap_read ($ds, "", "objectClass=*", array("+"));
1458 $attr= @ldap_get_entries($ds,$sr);
1460 return ($attr[0]['namingcontexts']);
1461 }
1463 }
1465 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1466 ?>