serverType = strtolower($conf['auth']['serverType']); switch ($this->serverType) { case "ldap": $this->hosts = $conf['auth']['ldap_hosts']; $this->ssl = $conf['auth']['ldap_ssl']; $this->basedn = $conf['auth']['ldap_basedn']; $this->userIdentifier = $conf['auth']['ldap_user_identifier']; $this->userContainer = $conf['auth']['ldap_user_container']; $this->login = $conf['auth']['ldap_login']; $this->name = $conf['auth']['ldap_name']; $this->mailAttr = $conf['auth']['ldap_mailAttr']; $this->searchUser = $conf['auth']['ldap_searchUser']; $this->searchPassword = $conf['auth']['ldap_searchPassword']; break; case "ad": $this->hosts = $conf['auth']['ad_hosts']; $this->ssl = $conf['auth']['ad_ssl']; $this->basedn = $conf['auth']['ad_basedn']; $this->userIdentifier = $conf['auth']['ad_user_identifier']; $this->domain = $conf['auth']['ad_domain']; $this->login = $conf['auth']['ad_login']; $this->name = $conf['auth']['ad_name']; $this->mailAttr = $conf['auth']['ad_mailAttr']; $this->searchUser = $conf['auth']['ad_searchUser']; $this->searchPassword = $conf['auth']['ad_searchPassword']; break; default: CmnFns::do_error_box(translate('Unknown server type'), '', false); } } // Connection handling methods ------------------------------------------- /** * Makes a connection to the LDAP server. * Just creates a connection which is used in all later access. * If it can't connect and bind anonymously, it creates an error code of -1. * Returns true if connected, false if failed. * Takes an array of possible servers - if one doesn't work, it tries the next and so on. * @param none */ function connect() { foreach ($this->hosts as $host) { $ldap_url = ( $this->ssl ? "ldaps://".$host : $host ); $this->connection = ldap_connect($ldap_url); if ($this->connection) { ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3); switch ($this->serverType) { case "ad": // Active Directory needs: ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0); break; default: break; } $this->connected = true; return true; } else { CmnFns::write_log('LDAP connection failed', ''); } } $this->ldapErrorCode = -1; $this->ldapErrorText = "Unable to connect to any server"; $this->connected = false; return false; } /** * Disconnects from the LDAP server * @param none */ function disconnect() { if( $this->connected ) { if ( ! @ldap_close( $this->connection ) ) { $this->ldapErrorCode = ldap_errno( $this->connection); $this->ldapErrorText = ldap_error( $this->connection); return false; } else { $this->connected = false; return true; } } return true; } /** * Anonymously binds to the connection. After this is done, * queries and searches can be done - but read-only. */ function anonBind() { if ( ! $this->bind = ldap_bind($this->connection) ) { $this->ldapErrorCode = ldap_errno( $this->connection); $this->ldapErrorText = ldap_error( $this->connection); CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, ''); return false; } else { return true; } } /** * Binds to the directory with a specific username and password: * @param string $dn full LDAP dn or AD type 'user@domain' * @param string $password password * @return bool */ function authBind($username, $password) { if ( ! $this->bind = @ldap_bind($this->connection, $username, $password) ) { $this->ldapErrorCode = ldap_errno( $this->connection); $this->ldapErrorText = ldap_error( $this->connection); CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, ''); return false; } else { return true; } } // User methods ------------------------------------------- /** * Returns the full user DN to use, based on the ldap server type * @param string $userlogin * @return string */ function getUserDN($userlogin) { switch ($this->serverType) { case "ldap": if ( $this->userContainer != '' && $this->userIdentifier == $this->login ) { // If a user container is specified and the login attribute is the same // as the user identifier attribute, build the user dn $dn = "$this->userIdentifier=$userlogin," . "$this->userContainer," . $this->basedn; } else { // Search for user dn $searchFilter = $this->login . "=" . $userlogin; $dn = $this->searchUserDN($searchFilter); } break; case "ad": if ( strtolower($this->login) == 'samaccountname' ) { // If the user login attribute is 'samaccountname', build the user AD login $dn = $userlogin . "@" . $this->domain; } else { // Search for user dn $searchFilter = $this->login . "=" . $userlogin; $dn = $this->searchUserDN($searchFilter); } break; default: CmnFns::do_error_box(translate('Unknown server type'), '', false); } return $dn; } /** * Returns the correct search base, based on the ldap server type * @param none * @return string */ function getSearchBase() { switch ($this->serverType) { case "ldap": $searchBase = ( $this->userContainer != '' ? "$this->userContainer," . $this->basedn : $this->basedn ); break; case "ad": $searchBase = $this->basedn; break; default: CmnFns::do_error_box(translate('Unknown server type'), '', false); } return $searchBase; } /** * Returns the correct user username that matches the search filter (array with single username) * If several usernames are found, return the array of usernames. * @param string $searchFilter search filter in a standard LDAP query * @return array */ function searchUserDN($searchFilter) { switch ($this->serverType) { case "ldap": if ( $this->searchUser != '' ) { // If a search user is defined bind with this user $this->authBind($this->searchUser, $this->searchPassword); } else { // Otherwise bind anonymously $this->anonBind(); } break; case "ad": // if the directory is AD, then bind first with the search user $this->authBind($this->searchUser, $this->searchPassword); break; default: CmnFns::do_error_box(translate('Unknown server type'), '', false); } $sr = ldap_search( $this->connection, $this->getSearchBase(), $searchFilter, array('dn')); $entries = ldap_get_entries( $this->connection, $sr); if ( $entries["count"] < 1 ) { // If no results returned $this->ldapErrorCode = -1; $this->ldapErrorText = "No users found matching search criteria"; CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, ''); } else { // The search should give an unique dn // If several results are found get the first one $dn = $entries[0]['dn']; } return $dn; } /** * Queries LDAP for user information * @param string $dn * @return boolean indicating success or failure */ function loadUserData($dn) { $this->emailAddress = array(); // We are instered in getting just the user's first name and his/her mail attribute(s) $attributes = $this->mailAttr; array_push( $attributes, strtolower($this->name) ); switch ($this->serverType) { case "ldap": $result = ldap_search( $this->connection, $dn, "objectclass=*", $attributes ); break; case "ad": if ( strtolower($this->login) == 'samaccountname' ) { // dn is of the form 'user@domain' list($samaccountname, $domain) = explode("@", $dn); $result = ldap_search( $this->connection, $this->getSearchBase(), $this->login . "=" . $samaccountname, $attributes ); } else { // dn is standard LDAP dn $result = ldap_search( $this->connection, $dn, "objectclass=*", $attributes ); } break; } $entries = ldap_get_entries( $this->connection, $result ); if( $result and ( $entries["count"] > 0 ) ) { // The search should give a single entry // If several results are found get the first entry $this->firstName = $entries[0][strtolower($this->name)][0]; foreach ( $this->mailAttr as $value ) { // For single value or multiple value attribute for ($i=0; $i<$entries[0][strtolower($value)]["count"]; $i++) { # AD proxyAddresses attribute values have 'smtp:' string before the actual email address if(preg_match("/^smtp:/i", strtolower($entries[0][strtolower($value)][$i])) == 1) { array_push( $this->emailAddress, preg_replace("/^\w+:/", '', strtolower($entries[0][strtolower($value)][$i])) ); } else { array_push( $this->emailAddress, strtolower($entries[0][strtolower($value)][$i]) ); } } } } else { // If no results returned $this->ldapErrorCode = -1; $this->ldapErrorText = "No entry found matching search criteria"; CmnFns::write_log($this->ldapErrorCode . ': ' . $this->ldapErrorText, ''); return false; } return true; } // Helper methods ------------------------------------------- /** * Returns user information * @return array containing user information */ function getUserData() { $rval = array( 'logonName' => $this->logonName, 'firstName' => $this->firstName, 'emailAddress' => $this->emailAddress ); return $rval; } } ?>