diff --git a/lam/HISTORY b/lam/HISTORY index e72db953..aa8daf2b 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,4 +1,5 @@ December 2014 4.8 + - Active Directory: support paged result as workaround for size limit exceeded - FreeRadius: support dialupAccess and radiusProfileDn - Usability improvements - LAM Pro: diff --git a/lam/docs/manual-sources/howto.xml b/lam/docs/manual-sources/howto.xml index b4310dce..15aabfd6 100644 --- a/lam/docs/manual-sources/howto.xml +++ b/lam/docs/manual-sources/howto.xml @@ -1291,10 +1291,16 @@ Have fun! linkend="a_accessLevelPasswordReset">this page for details on the different access levels. + Advanced options + By default LAM will not follow LDAP referrals. This is ok for most installations. If you use LDAP referrals please activate the referral option in advanced settings. + Paged results should be activated only if you encounter any + problems regarding size limits on Active Directory. LAM will then + query LDAP to return results in chunks of 999 entries. + diff --git a/lam/docs/manual-sources/images/configProfiles4.png b/lam/docs/manual-sources/images/configProfiles4.png index a1adea61..9b0c8ceb 100644 Binary files a/lam/docs/manual-sources/images/configProfiles4.png and b/lam/docs/manual-sources/images/configProfiles4.png differ diff --git a/lam/docs/manual-sources/images/lamdaemonServers.png b/lam/docs/manual-sources/images/lamdaemonServers.png new file mode 100644 index 00000000..c0ace848 Binary files /dev/null and b/lam/docs/manual-sources/images/lamdaemonServers.png differ diff --git a/lam/help/help.inc b/lam/help/help.inc index 83cb7ab0..5f6f7810 100644 --- a/lam/help/help.inc +++ b/lam/help/help.inc @@ -181,6 +181,8 @@ $helpArray = array ( "Text" => _('Here you can overwrite the display name for this account type.')), "265" => array ("Headline" => _('Read-only'), "Text" => _('Sets this account type to read-only.')), + "266" => array ("Headline" => _("Paged results"), + "Text" => _("This is a workaround for Active Directory. Enable it if you get messages about size limit exceeded.")), // 300 - 399 // profile editor, file upload "301" => array ("Headline" => _("RDN identifier"), diff --git a/lam/lib/account.inc b/lam/lib/account.inc index 3d1df2a3..5b2430a6 100644 --- a/lam/lib/account.inc +++ b/lam/lib/account.inc @@ -668,19 +668,12 @@ function searchLDAPByAttribute($name, $value, $objectClass, $attributes, $scopes continue; // skip non-active account types } // search LDAP - $sr = @ldap_search($_SESSION['ldap']->server(), escapeDN($_SESSION['config']->get_Suffix($scopes[$s])), - $filter, $attributes, 0, $_SESSION['config']->get_searchLimit(), 0, LDAP_DEREF_NEVER); + $entries = searchLDAPPaged($_SESSION['ldap']->server(), escapeDN($_SESSION['config']->get_Suffix($scopes[$s])), + $filter, $attributes, 0, $_SESSION['config']->get_searchLimit()); if (ldap_errno($_SESSION['ldap']->server()) == 4) { logNewMessage(LOG_WARNING, 'LDAP size limit exeeded. Please increase the limit on your server.'); } - if ($sr) { - $entries = ldap_get_entries($_SESSION['ldap']->server(), $sr); - if ($entries) { - cleanLDAPResult($entries); - $return = array_merge($return, $entries); - } - @ldap_free_result($sr); - } + $return = array_merge($return, $entries); } return $return; } @@ -702,19 +695,12 @@ function searchLDAPByFilter($filter, $attributes, $scopes, $attrsOnly = false) { } for ($s = 0; $s < sizeof($scopes); $s++) { // search LDAP - $sr = @ldap_search($_SESSION['ldap']->server(), escapeDN($_SESSION['config']->get_Suffix($scopes[$s])), - $filter, $attributes, $readAttributesOnly, $_SESSION['config']->get_searchLimit(), 0, LDAP_DEREF_NEVER); + $entries = searchLDAPPaged($_SESSION['ldap']->server(), escapeDN($_SESSION['config']->get_Suffix($scopes[$s])), + $filter, $attributes, $readAttributesOnly, $_SESSION['config']->get_searchLimit()); if (ldap_errno($_SESSION['ldap']->server()) == 4) { logNewMessage(LOG_WARNING, 'LDAP size limit exeeded. Please increase the limit on your server.'); } - if ($sr) { - $entries = ldap_get_entries($_SESSION['ldap']->server(), $sr); - if ($entries) { - cleanLDAPResult($entries); - $return = array_merge($return, $entries); - } - @ldap_free_result($sr); - } + $return = array_merge($return, $entries); } return $return; } @@ -728,20 +714,56 @@ function searchLDAPByFilter($filter, $attributes, $scopes, $attrsOnly = false) { * @return array list of found entries */ function searchLDAP($suffix, $filter, $attributes) { - $return = array(); - $sr = @ldap_search($_SESSION['ldap']->server(), escapeDN($suffix), $filter, $attributes, - 0, $_SESSION['config']->get_searchLimit(), 0, LDAP_DEREF_NEVER); + $return = searchLDAPPaged($_SESSION['ldap']->server(), escapeDN($suffix), $filter, $attributes, + 0, $_SESSION['config']->get_searchLimit()); if (ldap_errno($_SESSION['ldap']->server()) == 4) { logNewMessage(LOG_WARNING, 'LDAP size limit exeeded. Please increase the limit on your server.'); } - if ($sr) { - $entries = ldap_get_entries($_SESSION['ldap']->server(), $sr); - if ($entries) { + return $return; +} + +/** + * Runs an LDAP search and uses paging if configured. + * + * @param handle $server LDAP connection handle + * @param String $dn DN + * @param String $filter filter + * @param array $attributes attribute list + * @param boolean $attrsOnly return only attribute names + * @param int $limit size limit + */ +function searchLDAPPaged($server, $dn, $filter, $attributes, $attrsOnly, $limit) { + if (empty($_SESSION['config']) || ($_SESSION['config']->getPagedResults() !== 'true')) { + $sr = @ldap_search($server, $dn, $filter, $attributes, $attrsOnly, $limit, 0, LDAP_DEREF_NEVER); + if ($sr) { + $entries = ldap_get_entries($server, $sr); + if (!$entries) { + return array(); + } cleanLDAPResult($entries); - @ldap_free_result($sr); return $entries; } + else { + return array(); + } } + $pageSize = 999; + $cookie = ''; + $return = array(); + do { + @ldap_control_paged_result($server, $pageSize, true, $cookie); + $sr = @ldap_search($server, $dn, $filter, $attributes, $attrsOnly, $limit, 0, LDAP_DEREF_NEVER); + if (!$sr) { + break; + } + $entries = ldap_get_entries($server, $sr); + if (!$entries) { + break; + } + $return = array_merge($return, $entries); + @ldap_control_paged_result_response($server, $sr, $cookie); + } while($cookie !== null && $cookie != ''); + cleanLDAPResult($return); return $return; } diff --git a/lam/lib/config.inc b/lam/lib/config.inc index 3e9570f6..5a798be6 100644 --- a/lam/lib/config.inc +++ b/lam/lib/config.inc @@ -362,6 +362,9 @@ class LAMConfig { /** automatically follow referrals */ private $followReferrals = 'false'; + /** use paged results */ + private $pagedResults = 'false'; + /** Array of string: users with admin rights */ private $Admins; @@ -456,7 +459,7 @@ class LAMConfig { private $lamProMailText = ''; /** List of all settings in config file */ - private $settings = array("ServerURL", "useTLS", "followReferrals", "Passwd", "Admins", "treesuffix", + private $settings = array("ServerURL", "useTLS", "followReferrals", 'pagedResults', "Passwd", "Admins", "treesuffix", "defaultLanguage", "scriptPath", "scriptServer", "scriptRights", "cachetimeout", "modules", "activeTypes", "types", "tools", "accessLevel", 'loginMethod', 'loginSearchSuffix', 'loginSearchFilter', 'searchLimit', 'lamProMailFrom', 'lamProMailReplyTo', 'lamProMailSubject', @@ -625,6 +628,7 @@ class LAMConfig { if (!in_array("ServerURL", $saved)) array_push($file_array, "\n\n# server address (e.g. ldap://localhost:389 or ldaps://localhost:636)\n" . "serverURL: " . $this->ServerURL . "\n"); if (!in_array("useTLS", $saved)) array_push($file_array, "\n\n# enable TLS encryption\n" . "useTLS: " . $this->useTLS . "\n"); if (!in_array("followReferrals", $saved)) array_push($file_array, "\n\n# follow referrals\n" . "followReferrals: " . $this->followReferrals . "\n"); + if (!in_array("pagedResults", $saved)) array_push($file_array, "\n\n# paged results\n" . "pagedResults: " . $this->pagedResults . "\n"); if (!in_array("Passwd", $saved)) array_push($file_array, "\n\n# password to change these preferences via webfrontend\n" . "passwd: " . $this->Passwd . "\n"); if (!in_array("Admins", $saved)) array_push($file_array, "\n\n# list of users who are allowed to use LDAP Account Manager\n" . "# names have to be seperated by semicolons\n" . @@ -777,6 +781,24 @@ class LAMConfig { $this->followReferrals = $followReferrals; } + /** + * Returns if paged results should be used. + * + * @return String true or false + */ + public function getPagedResults() { + return $this->pagedResults; + } + + /** + * Sets if paged results should be used. + * + * @param String $pagedResults true or false + */ + public function setPagedResults($pagedResults) { + $this->pagedResults = $pagedResults; + } + /** * Returns an array of string with all admin names * diff --git a/lam/lib/types/group.inc b/lam/lib/types/group.inc index f56f8689..b1041854 100644 --- a/lam/lib/types/group.inc +++ b/lam/lib/types/group.inc @@ -405,6 +405,9 @@ class lamGroupList extends lamList { $module_filter = get_ldap_filter($scope); // basic filter is provided by modules $attrs = array( "uid" ); for ($i = 0; $i < sizeof($this->entries); $i++) { + if (empty($this->entries[$i]['gidnumber'][0])) { + continue; + } $gid = $this->entries[$i]['gidnumber'][0]; $filter = "(&(&" . $module_filter . ")(gidNumber=" . $gid . "))"; $entries = searchLDAPByFilter($filter, $attrs, array($scope)); diff --git a/lam/templates/config/confmain.php b/lam/templates/config/confmain.php index b15d187c..40b151dd 100644 --- a/lam/templates/config/confmain.php +++ b/lam/templates/config/confmain.php @@ -270,7 +270,10 @@ if (isLAMProVersion()) { $advancedOptionsContent = new htmlTable(); // referrals $followReferrals = ($conf->getFollowReferrals() === 'true'); -$advancedOptionsContent->addElement(new htmlTableExtendedInputCheckbox('followReferrals',$followReferrals , _('Follow referrals'), '205'), true); +$advancedOptionsContent->addElement(new htmlTableExtendedInputCheckbox('followReferrals', $followReferrals , _('Follow referrals'), '205'), true); +// paged results +$pagedResults = ($conf->getPagedResults() === 'true'); +$advancedOptionsContent->addElement(new htmlTableExtendedInputCheckbox('pagedResults', $pagedResults , _('Paged results'), '266'), true); // build advanced options box $advancedOptions = new htmlAccordion('advancedOptions_server', array(_('Advanced options') => $advancedOptionsContent), false); @@ -509,6 +512,12 @@ function checkInput() { else { $conf->setFollowReferrals('false'); } + if (isset($_POST['pagedResults']) && ($_POST['pagedResults'] == 'on')) { + $conf->setPagedResults('true'); + } + else { + $conf->setPagedResults('false'); + } /* if (!$conf->set_cacheTimeout($_POST['cachetimeout'])) { $errors[] = array("ERROR", _("Cache timeout is invalid!")); }*/