X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=include%2Fclass_ldap.inc;h=a1f960aa3bc730f67939ee52a170f3530ec83e84;hb=3fad6ea3ba20f4cfef3cf7d62c5a0082159dd208;hp=73dc11253dff3eb92b7dedc352c03783942d4730;hpb=ece29fd20f606a5f17d9a95ba4d5d1da0743186e;p=gosa.git diff --git a/include/class_ldap.inc b/include/class_ldap.inc index 73dc11253..a1f960aa3 100644 --- a/include/class_ldap.inc +++ b/include/class_ldap.inc @@ -2,7 +2,7 @@ /***************************************************************************** newldap.inc - version 1.0 Copyright (C) 2003 Alejandro Escanero Blanco - Copyright (C) 2004 Cajus Pollmeier + Copyright (C) 2004-2006 Cajus Pollmeier Based in code of ldap.inc of Copyright (C) 1998 Eric Kilfoil @@ -11,11 +11,8 @@ define("ALREADY_EXISTING_ENTRY",-10001); define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002); define("NO_FILE_UPLOADED",10003); - - define("INSERT_OK",10000); - - +define("SPECIALS_OVERRIDE", TRUE); class LDAP{ @@ -33,17 +30,66 @@ class LDAP{ var $hostname = ""; var $follow_referral = FALSE; var $referrals= array(); + var $max_ldap_query_time = 0; // 0, empty or negative values will disable this check function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE) { + global $config; $this->follow_referral= $follow_referral; $this->tls=$tls; - $this->binddn=$binddn; + $this->binddn=$this->convert($binddn); + $this->bindpw=$bindpw; $this->hostname=$hostname; + + /* Check if MAX_LDAP_QUERY_TIME is defined */ + if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){ + $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME']; + $this->max_ldap_query_time = (float)($str); + } + $this->connect(); } + + /* Function to replace all problematic characters inside a DN by \001XX, where + \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely + that this character is inside a DN. + + Currently used codes: + , => CO + \2C => CO + ( => OB + ) => CB + / => SL */ + function convert($dn) + { + if (SPECIALS_OVERRIDE == TRUE){ + return (preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"), + array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"), + $dn)); + } else { + return ($dn); + } + } + + + /* Function to fix all problematic characters inside a DN by replacing \001XX + codes to their original values. See "convert" for mor information. + ',' characters are always expanded to \, (not \2C), since all tested LDAP + servers seem to take it the correct way. */ + function fix($dn) + { + if (SPECIALS_OVERRIDE == TRUE){ + return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"), + array("\,", "(", ")", "/"), + $dn)); + } else { + return ($dn); + } + } + + function connect() { $this->hascon=false; @@ -59,7 +105,7 @@ class LDAP{ } $this->error = "No Error"; - if ($bid = @ldap_bind($this->cid, $this->binddn, $this->bindpw)) { + if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) { $this->error = "Success"; $this->hascon=true; } else { @@ -79,7 +125,7 @@ class LDAP{ function rebind($ldap, $referral) { $credentials= $this->get_credentials($referral); - if (@ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) { + if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) { $this->error = "Success"; $this->hascon=true; $this->reconnect= true; @@ -117,26 +163,39 @@ class LDAP{ if ($dir == "..") $this->basedn = $this->getParentDir(); else - $this->basedn = $dir; + $this->basedn = $this->convert($dir); } function getParentDir($basedn = "") { if ($basedn=="") $basedn = $this->basedn; + else + $basedn = $this->convert($this->basedn); return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn)); } function search($filter, $attrs= array()) { - if($this->hascon){ if ($this->reconnect) $this->connect(); + + $start = microtime(); + $this->clearResult(); - $this->sr = @ldap_search($this->cid, $this->basedn, $filter, $attrs); + $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs); $this->error = @ldap_error($this->cid); $this->resetResult(); $this->hasres=true; + + /* Check if query took longer as specified in max_ldap_query_time */ + if($this->max_ldap_query_time){ + $diff = get_MicroTimeDiff($start,microtime()); + if($diff > $this->max_ldap_query_time){ + print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ; + } + } + return($this->sr); }else{ $this->error = "Could not connect to LDAP server"; @@ -144,17 +203,31 @@ class LDAP{ } } - function ls($filter = "(objectclass=*)", $basedn = "") + function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*")) { if($this->hascon){ if ($this->reconnect) $this->connect(); $this->clearResult(); if ($basedn == "") $basedn = $this->basedn; - $this->sr = @ldap_list($this->cid, $basedn, $filter); + else + $basedn= $this->convert($basedn); + + $start = microtime(); + + $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs); $this->error = @ldap_error($this->cid); $this->resetResult(); $this->hasres=true; + + /* Check if query took longer as specified in max_ldap_query_time */ + if($this->max_ldap_query_time){ + $diff = get_MicroTimeDiff($start,microtime()); + if($diff > $this->max_ldap_query_time){ + print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ; + } + } + return($this->sr); }else{ $this->error = "Could not connect to LDAP server"; @@ -162,13 +235,13 @@ class LDAP{ } } - function cat($dn) + function cat($dn,$attrs= array("*")) { if($this->hascon){ if ($this->reconnect) $this->connect(); $this->clearResult(); $filter = "(objectclass=*)"; - $this->sr = @ldap_read($this->cid, $dn, $filter); + $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs); $this->error = @ldap_error($this->cid); $this->resetResult(); $this->hasres=true; @@ -194,6 +267,7 @@ class LDAP{ function fetch() { + $att= array(); if($this->hascon){ if($this->hasres){ if ($this->start == 0) @@ -206,7 +280,7 @@ class LDAP{ if ($this->re) { $att= @ldap_get_attributes($this->cid, $this->re); - $att['dn']= @ldap_get_dn($this->cid, $this->re); + $att['dn']= $this->convert(@ldap_get_dn($this->cid, $this->re)); } $this->error = @ldap_error($this->cid); if (!isset($att)){ @@ -250,8 +324,7 @@ class LDAP{ $rv = @ldap_get_dn($this->cid, $this->re); $this->error = @ldap_error($this->cid); - $rv= preg_replace("/[ ]*,[ ]*/", ",", $rv); - return($rv); + return($this->convert($rv)); } }else{ $this->error = "Perform a Fetch with no Search"; @@ -287,7 +360,7 @@ class LDAP{ if ($dn == "") $dn = $this->basedn; - $r = @ldap_mod_del($this->cid, $dn, $attrs); + $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs); $this->error = @ldap_error($this->cid); return($r); }else{ @@ -303,7 +376,7 @@ class LDAP{ if ($dn == "") $dn = $this->basedn; - $r = @ldap_mod_replace($this->cid, $dn, $attrs); + $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs); $this->error = @ldap_error($this->cid); return($r); }else{ @@ -316,7 +389,7 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); - $r = @ldap_delete($this->cid, $deletedn); + $r = @ldap_delete($this->cid, $this->fix($deletedn)); $this->error = @ldap_error($this->cid); return($r ? $r : 0); }else{ @@ -355,7 +428,7 @@ class LDAP{ } /* Finally Delete own Node */ - $r = @ldap_delete($this->cid, $deletedn); + $r = @ldap_delete($this->cid, $this->fix($deletedn)); $this->error = @ldap_error($this->cid); return($r ? $r : 0); }else{ @@ -365,53 +438,81 @@ class LDAP{ } /* Copy given attributes and sub-dns with attributes to destination dn - */ - function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = false) + function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = true,$depth=0) { error_reporting(E_ALL); + + if($is_first){ + echo "

".sprintf(_("Creating copy of %s"),"".$sourcedn."")."

"; + }else{ + if(preg_match("/^ou=/",$sourcedn)){ + echo "

"._("Processing")." $destinationdn

"; + }else{ + $tmp = split(",",$sourcedn); + + echo " "._("Object").": "; + + $deststr = $destinationdn; + if(strlen($deststr) > 96){ + $deststr = substr($deststr,0,96)."..."; + } + + echo $deststr."
"; + } + } + + flush(); + if($this->hascon){ if ($this->reconnect) $this->connect(); /* Save base dn */ $basedn= $this->basedn; $delarray= array(); - + /* Check if destination entry already exists */ - if($this->count($this->fetch($this->cat($destinationdn)))){ + $this->cat($destinationdn); + + if($this->count()){ return; }else{ + + $this->clearResult(); - /* Get source entrie */ + /* Get source entry */ $this->cd($basedn); - $attr = $this->fetch($this->cat($sourcedn)); + $this->cat($sourcedn); + $attr = $this->fetch(); + /* Error while fetching object / attribute abort*/ + if((!$attr) || (count($attr)) ==0) { + echo _("Error while fetching source dn - aborted!"); + return; + } + /* check if this is a department */ if(in_array("organizationalUnit",$attr['objectClass'])){ - $attr['dn'] = $destinationdn; + $attr['dn'] = $this->convert($destinationdn); $this->cd($basedn); $this->create_missing_trees($destinationdn); $this->cd($destinationdn); /* If is first entry, append FAIbranch to department entry */ if($is_first){ - $attr= $this->fetch($this->cat($destinationdn)); + $this->cat($destinationdn); + $attr= $this->fetch(); /* Filter unneeded informations */ foreach($attr as $key => $value){ if(is_numeric($key)) unset($attr[$key]); - if(isset($attr[$key]['count'])){ - if(($attr[$key]['count']==1)&&($key!="objectClass")){ - $attr[$key] = $attr[$key][0]; - } - } - if(isset($attr[$key]['count'])){ if(is_array($attr[$key])){ unset($attr[$key]['count']); } } } + unset($attr['count']); unset($attr['dn']); @@ -421,16 +522,19 @@ class LDAP{ /* Add this entry */ $this->modify($attr); } - }else{ - /* If this is no department */ + + /* If this is no department */ foreach($attr as $key => $value){ - if(is_numeric($key)) unset($attr[$key]); - if(isset($attr[$key]['count'])){ - if(($attr[$key]['count']==1)&&($key!="objectClass")){ - $attr[$key] = $attr[$key][0]; + if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){ + $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key)); + $ei= ldap_first_entry($this->cid, $sr); + if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){ + $attr[$key] = $tmp; } } + + if(is_numeric($key)) unset($attr[$key]); if(isset($attr[$key]['count'])){ if(is_array($attr[$key])){ unset($attr[$key]['count']); @@ -439,18 +543,21 @@ class LDAP{ } unset($attr['count']); unset($attr['dn']); - - if($type=="branch"){ - $attr['FAIstate'] ="branch"; - }elseif($type=="freeze"){ - $attr['FAIstate'] ="freeze"; - }else{ - print_red(_("Unknown FAIstate %s"),$type); + + if(!in_array("gosaApplication" , $attr['objectClass'])){ + if($type=="branch"){ + $attr['FAIstate'] ="branch"; + }elseif($type=="freeze"){ + $attr['FAIstate'] ="freeze"; + }else{ + print_red(_("Unknown FAIstate %s"),$type); + } } - + /* Add entry */ $this->cd($destinationdn); - $a = $this->fetch($this->cat($destinationdn)); + $this->cat($destinationdn); + $a = $this->fetch(); if(!count($a)){ $this->add($attr); } @@ -475,23 +582,31 @@ class LDAP{ asort ($delarray); reset ($delarray); + $depth ++; foreach($delarray as $dn => $bla){ if($dn != $destinationdn){ $this->cd($basedn); $item = $this->fetch($this->cat($dn)); if(!in_array("FAIbranch",$item['objectClass'])){ - $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$type); + $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$type,false,$depth); } } } } + if($is_first){ + echo "

 

"; + } + } function modify($attrs) { + if(count($attrs) == 0){ + return (0); + } if($this->hascon){ if ($this->reconnect) $this->connect(); - $r = @ldap_modify($this->cid, $this->basedn, $attrs); + $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs); $this->error = @ldap_error($this->cid); return($r ? $r : 0); }else{ @@ -504,7 +619,7 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); - $r = @ldap_add($this->cid, $this->basedn, $attrs); + $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs); $this->error = @ldap_error($this->cid); return($r ? $r : 0); }else{ @@ -519,8 +634,13 @@ class LDAP{ if ($target == $this->basedn){ return; } - $l= array_reverse(explode(",", preg_replace("/,".$this->basedn."/", "", $target))); + + $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 ); + $l= array_reverse(ldap_explode_dn($real_path,0)); + unset($l['count']); $cdn= $this->basedn; + $tag= ""; + foreach ($l as $part){ $cdn= "$part,$cdn"; @@ -541,18 +661,35 @@ class LDAP{ $attrs= $this->fetch(); /* Create missing entry? */ - if (!count ($attrs)){ + if (count ($attrs)){ + + /* Catch the tag - if present */ + if (isset($attrs['gosaUnitTag'][0])){ + $tag= $attrs['gosaUnitTag'][0]; + } + + } else { $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn); $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn); $na= array(); switch ($type){ case 'ou': - $na["objectClass"]= "organizationalUnit"; + if ($tag != ""){ + $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag"); + $na["gosaUnitTag"]= $tag; + } else { + $na["objectClass"]= "organizationalUnit"; + } $na["ou"]= $param; break; case 'dc': - $na["objectClass"]= array("dcObject", "top", "locality"); + if ($tag != ""){ + $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag"); + $na["gosaUnitTag"]= $tag; + } else { + $na["objectClass"]= array("dcObject", "top", "locality"); + } $na["dc"]= $param; break; default: @@ -589,7 +726,7 @@ class LDAP{ { $data= ""; if ($this->reconnect) $this->connect(); - $sr= @ldap_read($this->cid, $dn, "objectClass=*", array("$name")); + $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name")); /* fill data from LDAP */ if ($sr) { @@ -623,7 +760,12 @@ class LDAP{ if ($this->error == 'Success'){ return $this->error; } else { - $error= $this->error." (".$this->get_additional_error().")"; + $adderror= $this->get_additional_error(); + if ($adderror != ""){ + $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->base, $this->hostname).")"; + } else { + $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")"; + } return $error; } } @@ -641,7 +783,7 @@ class LDAP{ if (isset($referrals[$server])){ return ($referrals[$server]); } else { - $ret['ADMIN']= $this->binddn; + $ret['ADMIN']= $this->fix($this->binddn); $ret['PASSWORD']= $this->bindpw; } @@ -699,7 +841,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec } /* Searching Ldap Tree */ - $sr= @ldap_read($this->cid, $dn, $filter, $name); + $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name); /* Get the first entry */ $entry= @ldap_first_entry($this->cid, $sr); @@ -743,7 +885,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec function dn_exists($dn) { - return @ldap_list($this->cid, $dn, "(objectClass=*)", array("objectClass")); + return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass")); } @@ -952,6 +1094,35 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec } } + + function get_objectclasses() + { + $objectclasses = array(); + + # Get base to look for schema + $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry")); + $attr = @ldap_get_entries($this->cid,$sr); + if (!isset($attr[0]['subschemasubentry'][0])){ + return array(); + } + + # Get list of objectclasses + $nb= $attr[0]['subschemasubentry'][0]; + $objectclasses= array(); + $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses")); + $attrs= ldap_get_entries($this->cid,$sr); + if (!isset($attrs[0])){ + return array(); + } + foreach ($attrs[0]['objectclasses'] as $val){ + $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val); + if ($name != $val){ + $objectclasses[$name]= $val; + } + } + + return $objectclasses; + } }