/** * updates an existing group in sync backend * * @param Tinebase_Model_Group $_group * * @return Tinebase_Model_Group */ public function updateGroupInSyncBackend(Tinebase_Model_Group $_group) { if ($this->isDisabledBackend() || $this->isReadOnlyBackend()) { return $_group; } $metaData = $this->_getMetaData($_group->getId()); $dn = $metaData['dn']; $ldapData = array('cn' => $_group->name, 'description' => $_group->description, 'objectclass' => $metaData['objectclass']); foreach ($this->_plugins as $plugin) { $plugin->inspectUpdateGroup($_group, $ldapData); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' $dn: ' . $dn); } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' $ldapData: ' . print_r($ldapData, true)); } $this->getLdap()->update($dn, $ldapData); if (isset($metaData['cn']) && $metaData['cn'] != $ldapData['cn']) { $newDn = "cn={$ldapData['cn']},{$this->_options['groupsDn']}"; $this->_ldap->rename($dn, $newDn); } $group = $this->getGroupByIdFromSyncBackend($_group); return $group; }
/** * resolve UUID(for example entryUUID) to uidnumber * * @param string $_uuid * @return string */ public function resolveUUIdToUIdNumber($_uuid) { if ($this->_userUUIDAttribute == 'uidnumber') { return $_uuid; } $filter = Zend_Ldap_Filter::equals($this->_userUUIDAttribute, $this->_encodeAccountId($_uuid)); $groupId = $this->_ldap->search($filter, $this->_options['userDn'], $this->_userSearchScope, array('uidnumber'))->getFirst(); return $groupId['uidnumber'][0]; }
/** * fetch one contact of a user identified by his user_id * * @param int $_userId * @return Addressbook_Model_Contact * @throws Addressbook_Exception_NotFound if contact not found */ public function getByUserId($_userId) { $userId = Tinebase_Model_User::convertUserIdToInt($_userId); $contactData = $this->_ldap->fetch($this->_baseDn, "uidnumber={$userId}", $this->_getSupportedLdapAttributes()); if (!$contactData) { throw new Addressbook_Exception_NotFound("Contact with user id {$_userId} not found."); } $contact = $this->_ldap2Contacts(array($contactData))->offsetGet(0); $contact->jpegphoto = $this->_ldap->fetchBinaryAttribute($this->_baseDn, "uidnumber={$userId}", 'jpegphoto'); return $contact; }
/** * returns ldap metadata of given group * * @param int $_groupId * @return array * * @todo remove obsolete code */ protected function _getGroupMetaData($_groupId) { $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId); $filter = Zend_Ldap_Filter::equals($this->_options['groupUUIDAttribute'], Zend_Ldap::filterEscape($groupId)); $result = $this->_ldap->search($filter, $this->_options['groupsDn'], Zend_Ldap::SEARCH_SCOPE_SUB, array('objectclass', 'sambasid'))->getFirst(); return $result; /* } catch (Tinebase_Exception_NotFound $e) { throw new Exception("group with id $groupId not found"); } */ }
/** * fetch domain config with domain sid and name * * @throws Tinebase_Exception_Backend_Ldap * @throws Zend_Ldap_Exception * @return array * * TODO cache this longer? */ public function getDomainConfiguration() { if ($this->_domainConfig === null) { $this->_domainConfig = $this->getLdap()->search('objectClass=domain', $this->getLdap()->getFirstNamingContext(), Zend_Ldap::SEARCH_SCOPE_BASE)->getFirst(); $this->_domainConfig['domainSidBinary'] = $this->_domainConfig['objectsid'][0]; $this->_domainConfig['domainSidPlain'] = Tinebase_Ldap::decodeSid($this->_domainConfig['objectsid'][0]); $domainNameParts = array(); $keys = null; // not really needed Zend_Ldap_Dn::explodeDn($this->_domainConfig['distinguishedname'][0], $keys, $domanNameParts); $this->_domainConfig['domainName'] = implode('.', $domainNameParts); } return $this->_domainConfig; }
/** * get groupmemberships of user from sync backend * * @param Tinebase_Model_User|string $_userId * @return array list of group ids */ public function getGroupMembershipsFromSyncBackend($_userId) { $metaData = $this->_getUserMetaData($_userId); $filter = Zend_Ldap_Filter::andFilter(Zend_Ldap_Filter::string($this->_groupBaseFilter), Zend_Ldap_Filter::orFilter(Zend_Ldap_Filter::equals('memberuid', Zend_Ldap::filterEscape($metaData['uid'][0])), Zend_Ldap_Filter::equals('member', Zend_Ldap::filterEscape($metaData['dn'])))); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ldap search filter: ' . $filter); } $groups = $this->_ldap->search($filter, $this->_options['groupsDn'], $this->_groupSearchScope, array('cn', 'description', $this->_groupUUIDAttribute)); $memberships = array(); foreach ($groups as $group) { $memberships[] = $group[$this->_groupUUIDAttribute][0]; } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' group memberships: ' . print_r($memberships, TRUE)); } return $memberships; }
/** * generates a gidnumber * * @todo add a persistent registry which id has been generated lastly to * reduce amount of groupid to be transfered * * @return int */ protected function _generateGidNumber() { $allGidNumbers = array(); foreach ($this->_ldap->fetchAll($this->_options['groupsDn'], 'objectclass=posixgroup', array('gidnumber')) as $groupData) { $allGidNumbers[] = $groupData['gidnumber'][0]; } sort($allGidNumbers); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Existing gidnumbers " . print_r($allGidNumbers, true)); } $numGroups = count($allGidNumbers); if ($numGroups == 0 || $allGidNumbers[$numGroups - 1] < $this->_options['minGroupId']) { $gidNumber = $this->_options['minGroupId']; } elseif ($allGidNumbers[$numGroups - 1] < $this->_options['maxGroupId']) { $gidNumber = ++$allGidNumbers[$numGroups - 1]; } else { throw new Tinebase_Exception_NotImplemented('Max Group Id is reached'); } return $gidNumber; }
/** * generates a uidnumber * * @todo add a persistent registry which id has been generated lastly to * reduce amount of userid to be transfered * * @return int */ protected function _generateUidNumber() { $allUidNumbers = array(); foreach ($this->_backend->fetchAll($this->_options['userDn'], 'objectclass=posixAccount', array('uidnumber')) as $userData) { $allUidNumbers[] = $userData['uidnumber'][0]; } sort($allUidNumbers); if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " Existing uidnumbers " . print_r($allUidNumbers, true)); } $numUsers = count($allUidNumbers); if ($numUsers == 0 || $allUidNumbers[$numUsers - 1] < $this->_options['minUserId']) { $uidNumber = $this->_options['minUserId']; } elseif ($allUidNumbers[$numUsers - 1] < $this->_options['maxUserId']) { $uidNumber = ++$allUidNumbers[$numUsers - 1]; } else { throw new Tinebase_Exception_NotImplemented('Max User Id is reached'); } return $uidNumber; }
/** * (non-PHPdoc) */ protected function _saveOrUpdateSpecialResultToLdap() { foreach ($this->_ldapRawData as $dn) { if (isset($dn['simplemail_readonly'])) { continue; } // check for any values of worth to be saved (compared to minimal entry) $skeleton = array_change_key_case($this->_simpleMailConfig['skeleton']); $skeleton['dn'] = true; $skeleton = array_merge($skeleton, Zend_Ldap_Dn::fromString($this->_simpleMailConfig['storage_rdn'])->getRdn()); try { if (count(array_diff_key($dn, $skeleton)) > 1) { $this->_ldap->save(Zend_Ldap_Dn::fromString($dn['dn']), $dn); } else { $this->_ldap->delete(Zend_Ldap_Dn::fromString($dn['dn']), false); } } catch (Zend_Ldap_Exception $ldapException) { if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' simpleMail - cannot modify ldap entry (' . $dn['dn'] . '): ' . $ldapException->getMessage()); } } } }
/** * (non-PHPdoc) */ protected function _saveOrUpdateSpecialResultToLdap() { foreach ($this->_ldapRawData as $dn) { if (isset($dn['simplemail_readonly'])) { continue; } $keepEntryThreshold = 0; foreach ($this->_propertyMapping as $property => $ldapName) { if (substr($ldapName, -8) == ':boolean') { $ldapName = substr($ldapName, 0, -8); } if (!isset($dn[$ldapName])) { $dn[$ldapName] = null; $keepEntryThreshold++; } elseif ($dn[$ldapName] === null) { $keepEntryThreshold++; } } // check for any values of worth to be saved (compared to minimal entry) $dn = array_change_key_case($dn); $skeleton = array_change_key_case($this->_simpleMailConfig['skeleton']); $skeleton = array_merge($skeleton, Zend_Ldap_Dn::fromString($this->_simpleMailConfig['storage_rdn'])->getRdn()); $skeleton['dn'] = true; // Zend_Ldap_Dn always carries the DN try { if (count(array_diff_key($dn, $skeleton)) > $keepEntryThreshold) { $this->_ldap->save(Zend_Ldap_Dn::fromString($dn['dn']), $dn); } else { $this->_ldap->delete(Zend_Ldap_Dn::fromString($dn['dn']), false); } } catch (Zend_Ldap_Exception $ldapException) { if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) { Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' simpleMail - cannot modify ldap entry (' . $dn['dn'] . '): ' . $ldapException->getMessage()); } } } }
/** * returns ldap metadata of given group * * @param string $_groupId * @return array * @throws Tinebase_Exception_NotFound * * @todo remove obsolete code */ protected function _getMetaData($_groupId) { $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId); $filter = Zend_Ldap_Filter::equals($this->_groupUUIDAttribute, $this->_encodeGroupId($groupId)); $result = $this->getLdap()->search($filter, $this->_options['groupsDn'], $this->_groupSearchScope, array('objectclass', 'objectsid')); if (count($result) !== 1) { throw new Tinebase_Exception_NotFound("Group with id {$_groupId} not found."); } $group = $result->getFirst(); return array('dn' => $group['dn'], 'objectclass' => $group['objectclass'], 'objectsid' => Tinebase_Ldap::decodeSid($group['objectsid'][0])); }
/** * get config for type IMAP/SMTP * * @param string $_configType * @return array */ public static function getConfig($_configType) { if (!isset(self::$_configs[$_configType])) { self::$_configs[$_configType] = Tinebase_Config::getInstance()->get($_configType, new Tinebase_Config_Struct())->toArray(); /* * If LDAP-Url is given (instead of comma separated domains) add secondary domains from LDAP * e.g. ldap://localhost/ou=domains,ou=mailConfig,dc=example,dc=com?dc?sub?objectclass=mailDomain */ if ($_configType == Tinebase_Config::SMTP && array_key_exists('secondarydomains', self::$_configs[Tinebase_Config::SMTP]) && preg_match("~^ldaps?://~i", self::$_configs[Tinebase_Config::SMTP]['secondarydomains'])) { $ldap_url = parse_url(self::$_configs[Tinebase_Config::SMTP]['secondarydomains']); $ldap_url['path'] = substr($ldap_url['path'], 1); $query = explode('?', $ldap_url['query']); count($query) > 0 ? $ldap_url['attributes'] = explode(',', $query[0]) : ($ldap_url['attributes'] = array()); $ldap_url['scope'] = Zend_Ldap::SEARCH_SCOPE_BASE; if (count($query) > 1) { switch ($query[1]) { case 'subtree': case 'sub': $ldap_url['scope'] = Zend_Ldap::SEARCH_SCOPE_SUB; break; case 'one': $ldap_url['scope'] = Zend_Ldap::SEARCH_SCOPE_ONE; break; } } count($query) > 2 ? $ldap_url['filter'] = $query[2] : ($ldap_url['filter'] = 'objectClass=*'); // By now your options are limited to configured server $ldap = new Tinebase_Ldap(Tinebase_User::getBackendConfiguration()); $ldap->connect()->bind(); $secondarydomains = $ldap->searchEntries($ldap_url['filter'], $ldap_url['path'], $ldap_url['scope'], $ldap_url['attributes']); self::$_configs[Tinebase_Config::SMTP]['secondarydomains'] = ''; foreach ($secondarydomains as $dn) { foreach ($ldap_url['attributes'] as $attr) { if (array_key_exists($attr, $dn)) { foreach ($dn[$attr] as $domain) { self::$_configs[Tinebase_Config::SMTP]['secondarydomains'] != '' ? $domain = ',' . $domain : $domain; self::$_configs[Tinebase_Config::SMTP]['secondarydomains'] .= $domain; } } } } if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Secondarydomains: ' . print_r(self::$_configs[Tinebase_Config::SMTP]['secondarydomains'], true)); } } } return self::$_configs[$_configType]; }
/** * @see 0011844: decodeSid fails for some encoded SIDs * * TODO write a test for a decoded sid, like this: ^A^E^@^@^@^@^@^E^U^@^@^@^A.z<F4>^W<B0>Ot^^<DC>^O^V<DE>-^@^@ * * we could dump the encoded sid like this: * $str = pack('c*', $data); * for ($i=0; $i < strlen($str); ++$i) { * echo '\x' . ord($str[$i]); * } */ public function testDecodeAlreadyDecodedSid() { $sid = "S-1-5-21-2127521184-1604012920-1887927527"; $decodedSid = Tinebase_Ldap::decodeSid($sid); $this->assertEquals($decodedSid, $sid); }
/** * convert plain text id to binary id * * @param string $accountId * @return string */ protected function _encodeAccountId($accountId) { switch ($this->_userUUIDAttribute) { case 'objectguid': return Tinebase_Ldap::encodeGuid($accountId); break; default: return $accountId; break; } }
/** * read ldap / get users and groups from tine an create mapping * * @return array */ protected function _getGroupMapping() { $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Fetching user mapping ...'); $filter = Zend_Ldap_Filter::andFilter(Zend_Ldap_Filter::string($this->_groupBaseFilter)); $mapping = array(); $groupNameMapping = $this->_config->groupNameMapping ? $this->_config->groupNameMapping->toArray() : array(); $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group name mapping: ' . print_r($groupNameMapping, TRUE)); $ldapGroups = $this->_ldap->search($filter, $this->_config->ldap->baseDn, $this->_groupSearchScope, array('*', '+')); foreach ($ldapGroups as $group) { $groupname = isset($groupNameMapping[$group['cn'][0]]) ? $groupNameMapping[$group['cn'][0]] : $group['cn'][0]; $ldapUuid = $this->_uuidProperty === 'objectguid' ? Tinebase_Ldap::decodeGuid($group['objectguid'][0]) : $group[$this->_uuidProperty][0]; try { $tineGroup = $this->_tineGroupBackend->getGroupByName($groupname); $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' . $group['cn'][0] . '): ' . $tineGroup->getId() . ' -> ' . $ldapUuid); $mapping[$tineGroup->getId()] = $ldapUuid; } catch (Tinebase_Exception_Record_NotDefined $tenf) { // @todo should be: Tinebase_Exception_NotFound $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' . $group['cn'][0] . '): ' . $tenf->getMessage()); } } $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Found ' . count($mapping) . ' groups for the mapping.'); $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($mapping, TRUE)); return $mapping; }