/** * Executes an LDAP search * @param string $filter the LDAP filter for the search * @param array $base an array containing the LDAP subtree(s) that shall be searched * @param string|string[] $attr optional, array, one or more attributes that shall be * @param int $limit * @param int $offset * @param bool $skipHandling * @return array with the search result */ private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { if ($limit <= 0) { //otherwise search will fail $limit = null; } $search = $this->executeSearch($filter, $base, $attr, $limit, $offset); if ($search === false) { return array(); } list($sr, $pagedSearchOK) = $search; $cr = $this->connection->getConnectionResource(); if ($skipHandling) { //i.e. result do not need to be fetched, we just need the cookie //thus pass 1 or any other value as $iFoundItems because it is not //used $this->processPagedSearchStatus($sr, $filter, $base, 1, $limit, $offset, $pagedSearchOK, $skipHandling); return array(); } // Do the server-side sorting foreach (array_reverse($attr) as $sortAttr) { foreach ($sr as $searchResource) { $this->ldap->sort($cr, $searchResource, $sortAttr); } } $findings = array(); foreach ($sr as $res) { $findings = array_merge($findings, $this->ldap->getEntries($cr, $res)); } $this->processPagedSearchStatus($sr, $filter, $base, $findings['count'], $limit, $offset, $pagedSearchOK, $skipHandling); // if we're here, probably no connection resource is returned. // to make ownCloud behave nicely, we simply give back an empty array. if (is_null($findings)) { return array(); } if (!is_null($attr)) { $selection = array(); $multiArray = false; if (count($attr) > 1) { $multiArray = true; $i = 0; } foreach ($findings as $item) { if (!is_array($item)) { continue; } $item = \OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8'); if ($multiArray) { foreach ($attr as $key) { $key = mb_strtolower($key, 'UTF-8'); if (isset($item[$key])) { if ($key !== 'dn') { $selection[$i][$key] = $this->resemblesDN($key) ? $this->sanitizeDN($item[$key][0]) : $item[$key][0]; } else { $selection[$i][$key] = $this->sanitizeDN($item[$key]); } } } $i++; } else { //tribute to case insensitivity $key = mb_strtolower($attr[0], 'UTF-8'); if (isset($item[$key])) { if ($this->resemblesDN($key)) { $selection[] = $this->sanitizeDN($item[$key]); } else { $selection[] = $item[$key]; } } } } $findings = $selection; } //we slice the findings, when //a) paged search unsuccessful, though attempted //b) no paged search, but limit set if (!$this->getPagedSearchResultState() && $pagedSearchOK || !$pagedSearchOK && !is_null($limit)) { $findings = array_slice($findings, intval($offset), $limit); } return $findings; }
/** * @brief appends a list of values fr * @param $result resource, the return value from ldap_get_attributes * @param $attribute string, the attribute values to look for * @param &$known array, new values will be appended here * @return int, state on of the class constants LRESULT_PROCESSED_OK, * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP */ private function getAttributeValuesFromEntry($result, $attribute, &$known) { if (!is_array($result) || !isset($result['count']) || !$result['count'] > 0) { return self::LRESULT_PROCESSED_INVALID; } //strtolower on all keys for proper comparison $result = \OCP\Util::mb_array_change_key_case($result); $attribute = strtolower($attribute); if (isset($result[$attribute])) { foreach ($result[$attribute] as $key => $val) { if ($key === 'count') { continue; } if (!in_array($val, $known)) { $known[] = $val; } } return self::LRESULT_PROCESSED_OK; } else { return self::LRESULT_PROCESSED_SKIP; } }
/** * Executes an LDAP search * @param string $filter the LDAP filter for the search * @param array $base an array containing the LDAP subtree(s) that shall be searched * @param string|string[] $attr optional, array, one or more attributes that shall be * @param int $limit * @param int $offset * @param bool $skipHandling * @return array with the search result */ private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { if ($limit <= 0) { //otherwise search will fail $limit = null; } /* ++ Fixing RHDS searches with pages with zero results ++ * As we can have pages with zero results and/or pages with less * than $limit results but with a still valid server 'cookie', * loops through until we get $continue equals true and * $findings['count'] < $limit */ $findings = array(); $savedoffset = $offset; do { $continue = false; $search = $this->executeSearch($filter, $base, $attr, $limit, $offset); if ($search === false) { return array(); } list($sr, $pagedSearchOK) = $search; $cr = $this->connection->getConnectionResource(); if ($skipHandling) { //i.e. result do not need to be fetched, we just need the cookie //thus pass 1 or any other value as $iFoundItems because it is not //used $this->processPagedSearchStatus($sr, $filter, $base, 1, $limit, $offset, $pagedSearchOK, $skipHandling); return array(); } // Do the server-side sorting foreach (array_reverse($attr) as $sortAttr) { foreach ($sr as $searchResource) { $this->ldap->sort($cr, $searchResource, $sortAttr); } } foreach ($sr as $res) { $findings = array_merge($findings, $this->ldap->getEntries($cr, $res)); } $continue = $this->processPagedSearchStatus($sr, $filter, $base, $findings['count'], $limit, $offset, $pagedSearchOK, $skipHandling); $offset += $limit; } while ($continue && $pagedSearchOK && $findings['count'] < $limit); // reseting offset $offset = $savedoffset; // if we're here, probably no connection resource is returned. // to make ownCloud behave nicely, we simply give back an empty array. if (is_null($findings)) { return array(); } if (!is_null($attr)) { $selection = array(); $i = 0; foreach ($findings as $item) { if (!is_array($item)) { continue; } $item = \OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8'); foreach ($attr as $key) { $key = mb_strtolower($key, 'UTF-8'); if (isset($item[$key])) { if (is_array($item[$key]) && isset($item[$key]['count'])) { unset($item[$key]['count']); } if ($key !== 'dn') { $selection[$i][$key] = $this->resemblesDN($key) ? $this->sanitizeDN($item[$key]) : $item[$key]; } else { $selection[$i][$key] = [$this->sanitizeDN($item[$key])]; } } } $i++; } $findings = $selection; } //we slice the findings, when //a) paged search unsuccessful, though attempted //b) no paged search, but limit set if (!$this->getPagedSearchResultState() && $pagedSearchOK || !$pagedSearchOK && !is_null($limit)) { $findings = array_slice($findings, intval($offset), $limit); } return $findings; }
/** * @brief executes an LDAP search * @param $filter the LDAP filter for the search * @param $base an array containing the LDAP subtree(s) that shall be searched * @param $attr optional, array, one or more attributes that shall be * retrieved. Results will according to the order in the array. * @returns array with the search result * * Executes an LDAP search */ private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { if (!is_null($attr) && !is_array($attr)) { $attr = array(mb_strtolower($attr, 'UTF-8')); } // See if we have a resource, in case not cancel with message $link_resource = $this->connection->getConnectionResource(); if (!$this->ldap->isResource($link_resource)) { // Seems like we didn't find any resource. // Return an empty array just like before. \OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG); return array(); } //check wether paged search should be attempted $pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset); $linkResources = array_pad(array(), count($base), $link_resource); $sr = $this->ldap->search($linkResources, $base, $filter, $attr); $error = $this->ldap->errno($link_resource); if (!is_array($sr) || $error !== 0) { \OCP\Util::writeLog('user_ldap', 'Error when searching: ' . $this->ldap->error($link_resource) . ' code ' . $this->ldap->errno($link_resource), \OCP\Util::ERROR); \OCP\Util::writeLog('user_ldap', 'Attempt for Paging? ' . print_r($pagedSearchOK, true), \OCP\Util::ERROR); return array(); } // Do the server-side sorting foreach (array_reverse($attr) as $sortAttr) { foreach ($sr as $searchResource) { $this->ldap->sort($link_resource, $searchResource, $sortAttr); } } $findings = array(); foreach ($sr as $key => $res) { $findings = array_merge($findings, $this->ldap->getEntries($link_resource, $res)); } if ($pagedSearchOK) { \OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO); foreach ($sr as $key => $res) { $cookie = null; if ($this->ldap->controlPagedResultResponse($link_resource, $res, $cookie)) { \OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO); $this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie); } } //browsing through prior pages to get the cookie for the new one if ($skipHandling) { return; } // if count is bigger, then the server does not support // paged search. Instead, he did a normal search. We set a // flag here, so the callee knows how to deal with it. if ($findings['count'] <= $limit) { $this->pagedSearchedSuccessful = true; } } else { if (!is_null($limit)) { \OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO); } } // if we're here, probably no connection resource is returned. // to make ownCloud behave nicely, we simply give back an empty array. if (is_null($findings)) { return array(); } if (!is_null($attr)) { $selection = array(); $multiarray = false; if (count($attr) > 1) { $multiarray = true; $i = 0; } foreach ($findings as $item) { if (!is_array($item)) { continue; } $item = \OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8'); if ($multiarray) { foreach ($attr as $key) { $key = mb_strtolower($key, 'UTF-8'); if (isset($item[$key])) { if ($key !== 'dn') { $selection[$i][$key] = $this->resemblesDN($key) ? $this->sanitizeDN($item[$key][0]) : $item[$key][0]; } else { $selection[$i][$key] = $this->sanitizeDN($item[$key]); } } } $i++; } else { //tribute to case insensitivity $key = mb_strtolower($attr[0], 'UTF-8'); if (isset($item[$key])) { if ($this->resemblesDN($key)) { $selection[] = $this->sanitizeDN($item[$key]); } else { $selection[] = $item[$key]; } } } } $findings = $selection; } //we slice the findings, when //a) paged search insuccessful, though attempted //b) no paged search, but limit set if (!$this->pagedSearchedSuccessful && $pagedSearchOK || !$pagedSearchOK && !is_null($limit)) { $findings = array_slice($findings, intval($offset), $limit); } return $findings; }
/** * @brief executes an LDAP search * @param $filter the LDAP filter for the search * @param $base the LDAP subtree that shall be searched * @param $attr optional, when a certain attribute shall be filtered out * @returns array with the search result * * Executes an LDAP search */ private function search($filter, $base, $attr = null) { if (!is_null($attr) && !is_array($attr)) { $attr = array(mb_strtolower($attr, 'UTF-8')); } // See if we have a resource $link_resource = $this->connection->getConnectionResource(); if (is_resource($link_resource)) { $sr = ldap_search($link_resource, $base, $filter, $attr); $findings = ldap_get_entries($link_resource, $sr); // if we're here, probably no connection resource is returned. // to make ownCloud behave nicely, we simply give back an empty array. if (is_null($findings)) { return array(); } } else { // Seems like we didn't find any resource. // Return an empty array just like before. \OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG); return array(); } if (!is_null($attr)) { $selection = array(); $multiarray = false; if (count($attr) > 1) { $multiarray = true; $i = 0; } foreach ($findings as $item) { if (!is_array($item)) { continue; } $item = \OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8'); if ($multiarray) { foreach ($attr as $key) { $key = mb_strtolower($key, 'UTF-8'); if (isset($item[$key])) { if ($key != 'dn') { $selection[$i][$key] = $this->resemblesDN($key) ? $this->sanitizeDN($item[$key][0]) : $item[$key][0]; } else { $selection[$i][$key] = $this->sanitizeDN($item[$key]); } } } $i++; } else { //tribute to case insensitivity $key = mb_strtolower($attr[0], 'UTF-8'); if (isset($item[$key])) { if ($this->resemblesDN($key)) { $selection[] = $this->sanitizeDN($item[$key]); } else { $selection[] = $item[$key]; } } } } return $selection; } return $findings; }