diff --git a/library/Icinga/Protocol/Ldap/Connection.php b/library/Icinga/Protocol/Ldap/Connection.php index 54cc05f53f..6419fbb6fe 100644 --- a/library/Icinga/Protocol/Ldap/Connection.php +++ b/library/Icinga/Protocol/Ldap/Connection.php @@ -63,6 +63,7 @@ class Connection protected $bind_pw; protected $root_dn; protected $count; + protected $ldap_extension = array( '1.3.6.1.4.1.1466.20037' => 'STARTTLS', // '1.3.6.1.4.1.4203.1.11.1' => '11.1', // PASSWORD_MODIFY @@ -109,6 +110,8 @@ class Connection protected $supports_v3 = false; protected $supports_tls = false; + protected $capabilities; + /** * Constructor * @@ -365,6 +368,7 @@ protected function prepareNewConnection() $ds = ldap_connect($this->hostname, $this->port); $cap = $this->discoverCapabilities($ds); + $this->capabilities = $cap; if ($use_tls) { if ($cap->starttls) { @@ -399,7 +403,6 @@ protected function prepareNewConnection() // TODO: remove this -> FORCING v3 for now ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); - Logger::warning('No LDAPv3 support detected'); } @@ -429,6 +432,116 @@ protected function prepareTlsEnvironment() } } + protected function hasCapabilityStarTSL($cap) + { + $cap = $this->getExtensionCapabilities($cap); + return isset($cap['1.3.6.1.4.1.1466.20037']); + } + + protected function hasCapabilityLdapV3($cap) + { + if ((is_string($cap->supportedLDAPVersion) + && (int) $cap->supportedLDAPVersion === 3) + || (is_array($cap->supportedLDAPVersion) + && in_array(3, $cap->supportedLDAPVersion) + )) { + return true; + } + return false; + } + + protected function getExtensionCapabilities($cap) + { + $extensions = array(); + if (isset($cap->supportedExtension)) { + foreach ($cap->supportedExtension as $oid) { + if (array_key_exists($oid, $this->ldap_extension)) { + if ($this->ldap_extension[$oid] === 'STARTTLS') { + $extensions['1.3.6.1.4.1.1466.20037'] = $this->ldap_extension['1.3.6.1.4.1.1466.20037']; + } + } + } + } + return $extensions; + } + + protected function getMsCapabilities($cap) + { + $ms = array(); + foreach ($this->ms_capability as $name) { + $ms[$this->convName($name)] = false; + } + + if (isset($cap->supportedCapabilities)) { + foreach ($cap->supportedCapabilities as $oid) { + if (array_key_exists($oid, $this->ms_capability)) { + $ms[$this->convName($this->ms_capability[$oid])] = true; + } + } + } + return (object)$ms; + } + + private function convName($name) + { + $parts = explode('_', $name); + foreach ($parts as $i => $part) { + $parts[$i] = ucfirst(strtolower($part)); + } + return implode('', $parts); + } + + /** + * Get the capabilities of this ldap server + * + * @return stdClass An object, providing the flags 'ldapv3' and 'starttls' to indicate LdapV3 and StartTLS + * support and an additional property 'msCapabilities', containing all supported active directory capabilities. + */ + public function getCapabilities() + { + return $this->capabilities; + } + + /** + * Get the default naming context of this ldap connection + * + * @return String|null the default naming context, or null when no contexts are available + */ + public function getDefaultNamingContext() + { + $cap = $this->capabilities; + if (isset($cap->defaultNamingContext)) { + return $cap->defaultNamingContext; + } + $namingContexts = $this->namingContexts($cap); + return empty($namingContexts) ? null : $namingContexts[0]; + } + + /** + * Fetch the namingContexts for this Ldap-Connection + * + * @return array the available naming contexts + */ + public function namingContexts() + { + $cap = $this->capabilities; + if (!isset($cap->namingContexts)) { + return array(); + } + if (!is_array($cap->namingContexts)) { + return array($cap->namingContexts); + } + return $cap->namingContexts; + } + + /** + * Discover the capabilities of the given ldap-server + * + * @param $ds The link identifier of the current ldap connection + * + * @return bool|object The capabilities or false if the server has none + * @throws Exception When the capability query fails + */ protected function discoverCapabilities($ds) { $query = $this->select()->from( @@ -471,69 +584,49 @@ protected function discoverCapabilities($ds) $cap = (object) array( 'ldapv3' => false, 'starttls' => false, + 'msCapabilities' => array() ); if ($entry === false) { // TODO: Is it OK to have no capabilities? - return $cap; + return false; } $ldapAttributes = ldap_get_attributes($ds, $entry); - $result = $this->cleanupAttributes( - $ldapAttributes - ); + $result = $this->cleanupAttributes($ldapAttributes); + $cap->ldapv3 = $this->hasCapabilityLdapV3($result); + $cap->starttls = $this->hasCapabilityStarTSL($result); + $cap->msCapabilities = $this->getMsCapabilities($result); + $cap->namingContexts = $result->namingContexts; /* if (isset($result->dnsHostName)) { ldap_set_option($ds, LDAP_OPT_HOST_NAME, $result->dnsHostName); } */ - if ((is_string($result->supportedLDAPVersion) - && (int) $result->supportedLDAPVersion === 3) - || (is_array($result->supportedLDAPVersion) - && in_array(3, $result->supportedLDAPVersion) - )) { - $cap->ldapv3 = true; - } - - if (isset($result->supportedCapabilities)) { - foreach ($result->supportedCapabilities as $oid) { - if (array_key_exists($oid, $this->ms_capability)) { - // echo $this->ms_capability[$oid] . "\n"; - } - } - } - if (isset($result->supportedExtension)) { - foreach ($result->supportedExtension as $oid) { - if (array_key_exists($oid, $this->ldap_extension)) { - if ($this->ldap_extension[$oid] === 'STARTTLS') { - $cap->starttls = true; - } - } - } - } return $cap; } - public function connect() + public function connect($anonymous = false) { if ($this->ds !== null) { return; } $this->ds = $this->prepareNewConnection(); - $r = @ldap_bind($this->ds, $this->bind_dn, $this->bind_pw); - - if (! $r) { - throw new \Exception( - sprintf( - 'LDAP connection to %s:%s (%s / %s) failed: %s', - $this->hostname, - $this->port, - $this->bind_dn, - '***' /* $this->bind_pw */, - ldap_error($this->ds) - ) - ); + if (!$anonymous) { + $r = @ldap_bind($this->ds, $this->bind_dn, $this->bind_pw); + if (! $r) { + throw new \Exception( + sprintf( + 'LDAP connection to %s:%s (%s / %s) failed: %s', + $this->hostname, + $this->port, + $this->bind_dn, + '***' /* $this->bind_pw */, + ldap_error($this->ds) + ) + ); + } } }