X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=include%2Fclass_ldap.inc;h=0e1e909b5282c3e4e6ae12e96847863947321076;hb=1fbbb90f97a78530289dfb14614053794327c2b7;hp=a098b15f5747afd0266c922ed42173805ea34285;hpb=1f56f14cf6e1b6cac9f04e167201814a4795bcb6;p=gosa.git diff --git a/include/class_ldap.inc b/include/class_ldap.inc index a098b15f5..0e1e909b5 100644 --- a/include/class_ldap.inc +++ b/include/class_ldap.inc @@ -30,16 +30,24 @@ 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=$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(); } @@ -51,15 +59,19 @@ class LDAP{ Currently used codes: , => CO \2C => CO + \22 => TO + \" => TO + \+ => PL ( => OB ) => CB / => SL */ function convert($dn) { if (SPECIALS_OVERRIDE == TRUE){ - return (preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"), - array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"), - $dn)); + $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//", "/\\\\22/", '/\\\\"/', "/\\\\3D/", "/\\\\2B/", '/\\\\+/'), + array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL", "\001TO", "\001TO", "\001GL", "\001PL", "\001PL"), + $dn); + return (preg_replace('/,\s+/', ',', $tmp)); } else { return ($dn); } @@ -73,8 +85,8 @@ class LDAP{ function fix($dn) { if (SPECIALS_OVERRIDE == TRUE){ - return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"), - array("\,", "(", ")", "/"), + return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/", "/\001TO/", "/\001PL/", "/\001GL/"), + array("\,", "(", ")", "/", '\"', "\+", "="), $dn)); } else { return ($dn); @@ -82,6 +94,14 @@ class LDAP{ } + /* Function to fix problematic characters in DN's that are used for search + requests. I.e. member=.... */ + function prepare4filter($dn) + { + return normalizeLdap(preg_replace('/\\\\/', '\\\\\\', @LDAP::fix($dn))); + } + + function connect() { $this->hascon=false; @@ -171,12 +191,25 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); + + $start = microtime(); + $this->clearResult(); $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)) ; + } + } + + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')"); + return($this->sr); }else{ $this->error = "Could not connect to LDAP server"; @@ -193,10 +226,24 @@ class LDAP{ $basedn = $this->basedn; 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)) ; + } + } + + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')"); + return($this->sr); }else{ $this->error = "Could not connect to LDAP server"; @@ -208,12 +255,14 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); + $start = microtime(); $this->clearResult(); $filter = "(objectclass=*)"; $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs); $this->error = @ldap_error($this->cid); $this->resetResult(); $this->hasres=true; + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')"); return($this->sr); }else{ $this->error = "Could not connect to LDAP server"; @@ -236,6 +285,7 @@ class LDAP{ function fetch() { + $att= array(); if($this->hascon){ if($this->hasres){ if ($this->start == 0) @@ -248,7 +298,7 @@ class LDAP{ if ($this->re) { $att= @ldap_get_attributes($this->cid, $this->re); - $att['dn']= $this->convert(@ldap_get_dn($this->cid, $this->re)); + $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re))); } $this->error = @ldap_error($this->cid); if (!isset($att)){ @@ -292,7 +342,7 @@ class LDAP{ $rv = @ldap_get_dn($this->cid, $this->re); $this->error = @ldap_error($this->cid); - return($this->convert($rv)); + return(trim($this->convert($rv))); } }else{ $this->error = "Perform a Fetch with no Search"; @@ -357,8 +407,10 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); + $start= microtime(); $r = @ldap_delete($this->cid, $this->fix($deletedn)); $this->error = @ldap_error($this->cid); + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')"); return($r ? $r : 0); }else{ $this->error = "Could not connect to LDAP server"; @@ -407,21 +459,21 @@ class LDAP{ /* Copy given attributes and sub-dns with attributes to destination dn */ - function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = true,$depth=0) + function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0) { error_reporting(E_ALL); if($is_first){ - echo "

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

"; + echo "

".sprintf(_("Creating copy of %s"),"".@LDAP::fix($sourcedn)."")."

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

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

"; + echo "

"._("Processing")." ".@LDAP::fix($destinationdn)."

"; }else{ $tmp = split(",",$sourcedn); echo " "._("Object").": "; - $deststr = $destinationdn; + $deststr = @LDAP::fix($destinationdn); if(strlen($deststr) > 96){ $deststr = substr($deststr,0,96)."..."; } @@ -520,6 +572,23 @@ class LDAP{ }else{ print_red(_("Unknown FAIstate %s"),$type); } + }elseif(in_array("gosaApplication",$attr['objectClass'])){ + if(!in_array("FAIobject",$attr['objectClass'])){ + $attr['objectClass'][] = "FAIobject"; + } + $attr['FAIstate'] = $type; + } + + /* Replace FAIdebianRelease with new release name */ + if(in_array("FAIpackageList" , $attr['objectClass'])){ + $attr['FAIdebianRelease'] = $destinationName; + if($type=="branch"){ + $attr['FAIstate'] ="branch"; + }elseif($type=="freeze"){ + $attr['FAIstate'] ="freeze"; + }else{ + print_red(_("Unknown FAIstate %s"),$type); + } } /* Add entry */ @@ -531,7 +600,7 @@ class LDAP{ } if($this->error != "Success"){ - /* Some error occured */ + /* Some error occurred */ print "---------------------------------------------"; print $this->get_error()."
"; print $sourcedn."
"; @@ -542,6 +611,8 @@ class LDAP{ } } + echo "" ; + $this->ls ("(objectClass=*)",$sourcedn); while ($this->fetch()){ $deldn= $this->getDN(); @@ -556,7 +627,7 @@ class LDAP{ $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,false,$depth); + $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth); } } } @@ -574,8 +645,10 @@ class LDAP{ } if($this->hascon){ if ($this->reconnect) $this->connect(); + $start= microtime(); $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs); $this->error = @ldap_error($this->cid); + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')"); return($r ? $r : 0); }else{ $this->error = "Could not connect to LDAP server"; @@ -587,8 +660,10 @@ class LDAP{ { if($this->hascon){ if ($this->reconnect) $this->connect(); + $start= microtime(); $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs); $this->error = @ldap_error($this->cid); + $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')"); return($r ? $r : 0); }else{ $this->error = "Could not connect to LDAP server"; @@ -596,7 +671,151 @@ class LDAP{ } } + function create_missing_trees($target) + { + global $config; + + $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 ); + + if ($target == $this->basedn){ + $l= array("dummy"); + } else { + $l= array_reverse(gosa_ldap_explode_dn($real_path)); + } + unset($l['count']); + $cdn= $this->basedn; + $tag= ""; + + /* Load schema if available... */ + $classes= $this->get_objectclasses(); + + foreach ($l as $part){ + if ($part != "dummy"){ + $cdn= "$part,$cdn"; + } + + /* Ignore referrals */ + $found= false; + foreach($this->referrals as $ref){ + $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']); + if ($base == $cdn){ + $found= true; + break; + } + } + if ($found){ + continue; + } + + $this->cat ($cdn); + $attrs= $this->fetch(); + + /* Create missing entry? */ + 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(); + + /* Automatic or traditional? */ + if(count($classes)){ + + /* Get name of first matching objectClass */ + $ocname= ""; + foreach($classes as $class){ + if (isset($class['MUST']) && $class['MUST'] == "$type"){ + + /* Look for first classes that is structural... */ + if (isset($class['STRUCTURAL'])){ + $ocname= $class['NAME']; + break; + } + + /* Look for classes that are auxiliary... */ + if (isset($class['AUXILIARY'])){ + $ocname= $class['NAME']; + } + } + } + + /* Bail out, if we've nothing to do... */ + if ($ocname == ""){ + print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type)); + echo $_SESSION['errors']; + exit; + } + + /* Assemble_entry */ + if ($tag != ""){ + $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag"); + $na["gosaUnitTag"]= $tag; + } else { + $na['objectClass']= array($ocname); + } + if (isset($classes[$ocname]['AUXILIARY'])){ + $na['objectClass'][]= $classes[$ocname]['SUP']; + } + if ($type == "dc"){ + /* This is bad actually, but - tell me a better way? */ + $na['objectClass'][]= 'locality'; + } + $na[$type]= $param; + if (is_array($classes[$ocname]['MUST'])){ + foreach($classes[$ocname]['MUST'] as $attr){ + $na[$attr]= "filled"; + } + } + + } else { + + /* Use alternative add... */ + switch ($type){ + case 'ou': + if ($tag != ""){ + $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag"); + $na["gosaUnitTag"]= $tag; + } else { + $na["objectClass"]= "organizationalUnit"; + } + $na["ou"]= $param; + break; + case 'dc': + if ($tag != ""){ + $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag"); + $na["gosaUnitTag"]= $tag; + } else { + $na["objectClass"]= array("dcObject", "top", "locality"); + } + $na["dc"]= $param; + break; + default: + print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type)); + echo $_SESSION['errors']; + exit; + } + + } + $this->cd($cdn); + $this->add($na); + show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn)); + if (!preg_match('/success/i', $this->error)){ + return FALSE; + } + } + } + + return TRUE; + } + + + function create_missing_trees_old($target) { /* Ignore create_missing trees if the base equals target */ if ($target == $this->basedn){ @@ -604,9 +823,16 @@ class LDAP{ } $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 ); - $l= array_reverse(ldap_explode_dn($real_path,0)); + $tmp = ldap_explode_dn($real_path,0); + if(!$tmp){ + 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))); + return; + } + + $l= array_reverse($tmp); unset($l['count']); $cdn= $this->basedn; + $tag= ""; foreach ($l as $part){ $cdn= "$part,$cdn"; @@ -628,18 +854,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: @@ -710,7 +953,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->basedn, $this->hostname).")"; + } else { + $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")"; + } return $error; } } @@ -898,7 +1146,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec $ndn = split("#", $lineone[0]); $line = $ndn[1]; - $dnn = split (":",$line); + $dnn = split (":",$line,2); $current_line = $ndn[0]; $dn = $dnn[0]; $value = $dnn[1]; @@ -967,7 +1215,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec } /* Split the line into attribute and value */ - $attr = split(":", $row); + $attr = split(":", $row,2); $attr[0]= trim($attr[0]); /* attribute */ $attr[1]= trim($attr[1]); /* value */ @@ -1039,6 +1287,178 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec } } + + function get_objectclasses_old() + { + $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])){ + $this->error = @ldap_error($this->cid); + gosa_log($this->get_error()); + 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; + } + + + function get_objectclasses() + { + global $config; + $objectclasses = array(); + + if(isset($config) && preg_match("/config/i",get_class($config))){ + if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){ + return($objectclasses); + } + } + +# Get base to look for schema + $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry")); + if(!$sr){ + $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry")); + } + + $attr = @ldap_get_entries($this->cid,$sr); + if (!isset($attr[0]['subschemasubentry'][0])){ + return array(); + } + + /* Get list of objectclasses and fill array */ + $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){ + if (preg_match('/^[0-9]+$/', $val)){ + continue; + } + $name= "OID"; + $pattern= split(' ', $val); + $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val); + $objectclasses[$ocname]= array(); + + foreach($pattern as $chunk){ + switch($chunk){ + + case '(': + $value= ""; + break; + + case ')': if ($name != ""){ + $objectclasses[$ocname][$name]= $this->value2container($value); + } + $name= ""; + $value= ""; + break; + + case 'NAME': + case 'DESC': + case 'SUP': + case 'STRUCTURAL': + case 'ABSTRACT': + case 'AUXILIARY': + case 'MUST': + case 'MAY': + if ($name != ""){ + $objectclasses[$ocname][$name]= $this->value2container($value); + } + $name= $chunk; + $value= ""; + break; + + default: $value.= $chunk." "; + } + } + + } + + return $objectclasses; + } + + function value2container($value) + { + /* Set emtpy values to "true" only */ + if (preg_match('/^\s*$/', $value)){ + return true; + } + + /* Remove ' and " if needed */ + $value= preg_replace('/^[\'"]/', '', $value); + $value= preg_replace('/[\'"] *$/', '', $value); + + /* Convert to array if $ is inside... */ + if (preg_match('/\$/', $value)){ + $container= preg_split('/\s*\$\s*/', $value); + } else { + $container= chop($value); + } + + return ($container); + } + + function log($string) + { + if (isset($_SESSION['config'])){ + $cfg= $_SESSION['config']; + if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){ + syslog (LOG_INFO, $string); + } + } + } + + /* added by Guido Serra aka Zeph */ + function getCn($dn){ + $simple= split(",", $dn); + + foreach($simple as $piece) { + $partial= split("=", $piece); + + if($partial[0] == "cn"){ + return $partial[1]; + } + } + + } + + function get_naming_contexts($server, $admin= "", $password= "") + { + /* Build LDAP connection */ + $ds= ldap_connect ($server); + if (!$ds) { + die ("Can't bind to LDAP. No check possible!"); + } + ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); + $r= ldap_bind ($ds, $admin, $password); + + /* Get base to look for naming contexts */ + $sr = @ldap_read ($ds, "", "objectClass=*", array("+")); + $attr= @ldap_get_entries($ds,$sr); + + return ($attr[0]['namingcontexts']); + } }