From 703d4c7fb9c463a3e5a7a7f372669fbf0c704ada Mon Sep 17 00:00:00 2001
From: Hannes Georg <hannes.georg@xing.com>
Date: Wed, 14 Mar 2012 14:36:03 +0100
Subject: [PATCH] added an option to bind an ldap-account before searching it

---
 wwwroot/inc/auth.php    |   17 ++++++++++++++---
 wwwroot/inc/install.php |    3 +++
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/wwwroot/inc/auth.php b/wwwroot/inc/auth.php
index 77e03a6..b17cce7 100644
--- a/wwwroot/inc/auth.php
+++ b/wwwroot/inc/auth.php
@@ -391,6 +391,10 @@ function queryLDAPServer ($username, $password)
 			throw new RackTablesError ('LDAP misconfiguration: LDAP TLS required but not successfully negotiated.', RackTablesError::MISCONFIGURED);
 	}
 
+	if (array_key_exists ('options', $LDAP_options) and is_array ($LDAP_options['options']))
+		foreach ($LDAP_options['options'] as $opt_code => $opt_value)
+			ldap_set_option ($connect, $opt_code, $opt_value);
+
 	// Decide on the username we will actually authenticate for.
 	if (isset ($LDAP_options['domain']) and strlen ($LDAP_options['domain']))
 		$auth_user_name = $username . "@" . $LDAP_options['domain'];
@@ -402,6 +406,16 @@ function queryLDAPServer ($username, $password)
 		strlen ($LDAP_options['search_attr'])
 	)
 	{
+		// If a search_bind_rdn is supplied, bind to that and use it to search.
+		// This is required unless a server offers anonymous searching.
+		// Using bind again on the connection works as expected.
+		// The password is optional as it might be optional on server, too.
+		if( isset( $LDAP_options['search_bind_rdn'] ) && strlen( $LDAP_options['search_bind_rdn'] ) ){
+			$search_bind = @ldap_bind( $connect, $LDAP_options['search_bind_rdn'], isset($LDAP_options['search_bind_password']) ? $LDAP_options['search_bind_password'] : null );
+			if( $search_bind === FALSE ){
+				throw new RackTablesError ('LDAP misconfiguration. You have specified a search_bin_rdn'.(isset($LDAP_options['search_bind_password']) ? ' and a search_bind_password' : ' without a search_bind_password').', but the server refused it with: '.ldap_error($connect), RackTablesError::MISCONFIGURED);
+			}
+		}
 		$results = @ldap_search ($connect, $LDAP_options['search_dn'], '(' . $LDAP_options['search_attr'] . "=${username})", array("dn"));
 		if ($results === FALSE)
 			return array ('result' => 'CAN');
@@ -416,9 +430,6 @@ function queryLDAPServer ($username, $password)
 	}
 	else
 		throw new RackTablesError ('LDAP misconfiguration. Cannon build username for authentication.', RackTablesError::MISCONFIGURED);
-	if (array_key_exists ('options', $LDAP_options) and is_array ($LDAP_options['options']))
-		foreach ($LDAP_options['options'] as $opt_code => $opt_value)
-			ldap_set_option ($connect, $opt_code, $opt_value);
 	$bind = @ldap_bind ($connect, $auth_user_name, $password);
 	if ($bind === FALSE)
 		switch (ldap_errno ($connect))
diff --git a/wwwroot/inc/install.php b/wwwroot/inc/install.php
index cfaf199..7ad76ae 100644
--- a/wwwroot/inc/install.php
+++ b/wwwroot/inc/install.php
@@ -260,6 +260,9 @@ function init_config ()
 #	'domain' => 'example.com',
 #	'search_attr' => '',
 #	'search_dn' => '',
+# // The following credentials will be used when searching for the user's dn:
+#	'search_bind_rdn' => null,
+#	'search_bind_password' => null,
 #	'displayname_attrs' => '',
 #	'options' => array (LDAP_OPT_PROTOCOL_VERSION => 3),
 #	'use_tls' => 2,         // 0 == don't attempt, 1 == attempt, 2 == require
-- 
1.7.5.4

