--- ldapauth.module	2006-12-20 20:21:16.045848819 -0500
+++ ldapauth-5.0rc1.module	2006-12-20 20:21:35.979274133 -0500
@@ -1,5 +1,5 @@
 <?php
-// $Id: ldapauth.module,v 1.1.4.5 2006/07/29 18:22:57 pablobm Exp $
+// $Id: ldapauth.module,v 1.1.4.14 2006/12/09 16:18:48 pablobm Exp $
 
 include_once('ldap_integration/ldapauth.conf.php');
 include_once('ldap_integration/libdebug.php');
@@ -24,25 +24,27 @@
  *       1. Drupal hooks         *
  *********************************/
 
+/** 
+ * Implementation of hook_help().
+ */
 function ldapauth_help($section) {
   $output = '';
 
   switch ($section) {
-    case 'admin/modules#ldapauth':
-      $output = 'ldapauth';
-      break;
-    case 'admin/modules#description':
     case 'admin/help#ldapauth':
-      $output = t('Enables authentication via LDAP.');
-      break;
+		$output = '<p>' . t('Implements LDAP Authentication') . '</p>';
+		break;
     case 'user/help#ldapauth':
       $output = t('<p>If you are registered in %org\'s LDAP directory, you\'ll probably be able to login this site by using your LDAP login and password</p>', array('%org' => variable_get('ldap_org_name', LDAP_DEFAULT_ORG)));
       break;
   }
-
   return $output;
 }
 
+/** 
+ * Implementation of hook_info 
+ */
+
 function ldapauth_info($field = 0) {
   $info['name'] = variable_get('ldap_org_name', LDAP_DEFAULT_ORG);
   $info['protocol'] = 'LDAP';
@@ -55,16 +57,67 @@
   }
 }
 
-function ldapauth_settings() {
-  $form['ldap-note'] = array(
-    '#value' => t('<p style="margin: 1em;"><strong style="color: red;">PLEASE NOTE</strong>: advanced configuration for this module can be set by editing the module\'s config file, located at <em style="font-style: normal; padding: 1px 3px; border: 1px solid #8888CC; background-color: #DDDDFF">modules/ldap_integration/ldapauth.conf.php</em> in your Drupal install.</p>')
-  );
+/**
+ * Implementation of hook_menu() 
+**/
 
-  $form['server-settings'] = ldapauth_settings_server();
-  $form['login-procedure'] = ldapauth_settings_login_procedure();
-  $form['advanced'] = ldapauth_settings_advanced();
+function ldapauth_menu($may_cache) {
+	$items = array();
+	if ($may_cache) {
+		$items[] = array(	'path' => 'admin/settings/ldapauth', 
+								'title' => t('LDAP Integration'),
+    							'description' => t('Configure LDAP Settings'),
+								'callback' => 'drupal_get_form',
+								'callback arguments' => 'ldapauth_admin',
+								'type' => MENU_NORMAL_ITEM,
+								'access' => user_access('administer site configuration')
+							);
+	}
 
-  return $form;
+	return $items;
+}
+
+function ldapauth_admin() {
+  $form['server-settings'] = array( '#type' => 'fieldset', '#title' => t('Server settings'), '#collapsible' => TRUE, '#collapsed' => TRUE);
+
+  $form['server-settings']['ldap_org_name'] = array( '#type' => 'textfield', '#title' => t('Organisation name'), '#default_value' => variable_get('ldap_org_name', LDAP_DEFAULT_ORG), '#size' => 50, '#maxlength' => 255, '#description' => t('<p>Name of the organisation the LDAP directory belongs to.</>'),);
+
+  $form['server-settings']['ldap_server'] = array( '#type' => 'textfield', '#title' => t('LDAP server'), '#default_value' => variable_get('ldap_server', 'localhost'), '#size' => 50, '#maxlength' => 255, '#description' => t('<p>The domain name or IP address of your LDAP Server.</p>'),); 
+  
+  $form['server-settings']['ldap_port'] = array( '#type' => 'textfield', '#title' => t('LDAP port'), '#default_value' => variable_get('ldap_port', 389), '#size' => 50, '#maxlength' => 255, '#description' => t('<p>The TCP/IP port on the above server which accepts LDAP connections. Must be an integer.</p>'),);
+
+  $form['server-settings']['ldap_use_TLS'] = array( '#type' => 'checkbox', '#title' => t('Use TLS encryption'), '#return_value' => 1, '#default_value' => variable_get('ldap_use_TLS', 0), '#description' => t('<p>Secure the connection between the Drupal and the LDAP servers using TLS.</p>'),); 
+
+  $form['server-settings']['ldap_store_encrypted_pass'] = array( '#type' => 'checkbox', '#title' => t('Store passwords in encrypted form'), '#return_value' => 1, '#default_value' => variable_get('ldap_store_encrypted_pass', 0), '#description' => t('<p>Secure the password in LDAP by storing it MD5 encrypted (use with care, as some LDAP directories may do this automatically, what would cause logins problems).</p>'),);
+
+  $form['login-procedure'] = array( '#type' => 'fieldset', '#title' => 'Login procedure', '#collapsible' => TRUE, '#collapsed' => FALSE);
+
+  $form['login-procedure']['ldap_forget_passwords'] = array( '#type' => 'checkbox', '#title' => t('Do not store users\' passwords during sessions'), '#return_value' => true, '#default_value' => variable_get('ldap_forget_passwords', false), '#description' => t('<p>If you are going to use the <strong>ldapdata</strong> module and allow users to modify their LDAP entries, this module will need to store the user password during the session, so that it can have write access to the LDAP directory.</p><p>Physically, these passwords are stored in the Drupal\'s session table in clear text. If the database is well protected, this should not be a problem, but some admins may feel uneasy about this.</p><p>If you are not going to use the <strong>ldapdata</strong> module, or you are, but only for read-only access, you can safely check this box and get extra security for your system.</p>'),);
+
+  $options_login_process = array( LDAP_FIRST_DRUPAL => t('Drupal\'s own database. If it fails, will look on the LDAP directory'), LDAP_FIRST_LDAP => t('LDAP directory only'));
+
+  $form['login-procedure']['ldap_login_process'] = array( '#type' => 'radios', '#title' => t('When logging in, Drupal will look up for the user on'), '#default_value' => variable_get('ldap_login_process', LDAP_FIRST_DRUPAL), '#options' => $options_login_process, '#description' => NULL, '#required' => true,);
+
+  $form['login-procedure']['ldap_base_dn'] = array( '#type' => 'textarea', '#title' => t('Base DNs'), '#default_value' => variable_get('ldap_base_dn', LDAP_DEFAULT_BASE_DN), '#cols' => 50, '#rows' => 6, '#description' => t('<p>Base DNs for users. Enter one per line in case you need several of them.</p>'));
+
+  $form['login-procedure']['ldap_user_attribute'] = array( '#type' => 'textfield', '#title' => t('UserName attribute'), '#default_value' => variable_get('ldap_user_attribute', LDAP_DEFAULT_USER_ATTRIBUTE), '#size' => 50, '#maxlength' => 255, '#description' => t('<p>The attribute that holds the users\' login name. (eg. <em style="font-style: normal; padding: 1px 3px; border: 1px solid #8888CC; background-color: #DDDDFF">cn</em> for eDir or <em style="font-style: normal; padding: 1px 3px; border: 1px solid #8888CC; background-color: #DDDDFF">sAMAccountName</em> for Active Directory).</p>'),);
+
+  $form['advanced'] = array( '#type' => 'fieldset', '#title' => 'Advanced configuration', '#collapsible' => TRUE, '#collapsed' => TRUE);
+
+  $form['advanced']['ldap-note'] = array( '#value' => '<p>The process of authentication starts by establishing an anonymous connection to the LDAP directory and looking up for the user on it. Once this user is found, LDAP authentication is performed on them.</p><p>However, some LDAP configurations (specially common in <strong>Active Directory</strong> setups) restrict anonymous searches.</p><p>If your LDAP setup does not allow anonymous searches, or these are restricted in such a way that login names for users cannot be retrieved as a result of them, then you have to specify here a DN//password pair that will be used for these searches.</p><p>For security reasons, this pair should belong to an LDAP account with stripped down permissions.</p>');
+
+  $form['advanced']['ldap_search_as_dn'] = array( '#type' => 'textfield', '#title' => t('DN for non-anonymous search'), '#default_value' => variable_get('ldap_search_as_dn', ''), '#size' => 50, '#maxlength' => 255,);
+
+  if (variable_get('ldap_search_as_pass_clear', false) || ! variable_get('ldap_search_as_pass', false)) {
+    variable_set('ldap_search_as_pass', '');
+    $form['advanced']['ldap_search_as_pass'] = array( '#type' => 'password', '#title' => t('Password for non-anonymous search'), '#default_value' => variable_get('ldap_search_as_pass', ''), '#size' => 50, '#maxlength' => 255,);
+    variable_set('ldap_search_as_pass_clear', false);
+  }
+  else {
+    $form['advanced']['ldap_search_as_pass_clear'] = array( '#type' => 'checkbox', '#title' => t('Clear current password'), '#default_value' => false,);
+  }
+
+  return system_settings_form($form);
 }
 
 function ldapauth_auth($name, $pass, $server) {
@@ -80,7 +133,9 @@
 
   $dn = _ldapauth_login2dn($login_name);
 
-  if ($dn) {
+  // Not allowing empty passwords because they cause problems
+  // on some setups. See http://drupal.org/node/87831
+  if ($dn && $pass) {
     $ok = $ldap->connect($dn, $pass);
   }
 
@@ -92,7 +147,7 @@
 }
 
 function ldapauth_exit() {
-  // We delete the login info here, instead of just not storing it as
+  // We delete the login info here, instead of just not storing it at
   // ldapauth_auth(), so at least ldapgroups can use it at login time
   if (variable_get('ldap_forget_passwords', false) && isset($_SESSION['ldap_login'])) {
     unset($_SESSION['ldap_login']);
@@ -102,7 +157,7 @@
 function ldapauth_user($op, &$edit, &$user, $category = NULL) {
   // This is to convert from old ldap_integration to new ldapauth
   if ($op == 'login' && $user->ldap_authentified) {
-    db_query("UPDATE {authmap} SET module = 'ldapauth' WHERE uid = '$user->uid'");
+    db_query("UPDATE {authmap} SET module = 'ldapauth' WHERE uid = '%d'", $user->uid);
   }
 }
 
@@ -231,13 +286,24 @@
     '#maxlength' => 255,
   );
 
-  $form['ldap_search_as_pass'] = array(
-    '#type' => 'password',
-    '#title' => t('Password for non-anonymous search'),
-    '#default_value' => variable_get('ldap_search_as_password', ''),
-    '#size' => 50,
-    '#maxlength' => 255,
-  );
+  if (variable_get('ldap_search_as_pass_clear', false) || ! variable_get('ldap_search_as_pass', false)) {
+    variable_set('ldap_search_as_pass', '');
+    $form['ldap_search_as_pass'] = array(
+      '#type' => 'password',
+      '#title' => t('Password for non-anonymous search'),
+      '#default_value' => variable_get('ldap_search_as_pass', ''),
+      '#size' => 50,
+      '#maxlength' => 255,
+    );
+    variable_set('ldap_search_as_pass_clear', false);
+  }
+  else {
+    $form['ldap_search_as_pass_clear'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Clear current password'),
+      '#default_value' => false,
+    );
+  }
 
   return $form;
 }
@@ -290,7 +356,40 @@
       continue;
     }
 
-    $ret = $result[0];
+    $match = $result[0];
+
+    // These lines serve to fix the attribute name in case a
+    // naughty server (i.e.: MS Active Directory) is messing the
+    // characters' case.
+    // This was contributed by Dan "Gribnif" Wilga, and described
+    // here: http://drupal.org/node/87833
+    if ( ! isset($match[$name_attr][0]) ) {
+      $name_attr = strtolower($name_attr);
+      if ( ! isset($match[$name_attr][0]) ) {
+        continue;
+      }
+    }
+
+    // Finally, we must filter out results with spaces added before
+    // or after, which are considered OK by LDAP but are no good for us
+    // We allow lettercase independence, as requested by Marc Galera
+    // on http://drupal.org/node/97728
+    //
+    // Some setups have multiple $name_attr per entry, as pointed out by
+    // Clarence "sparr" Risher on http://drupal.org/node/102008, so we
+    // loop through all possible options.
+    $ok = false;
+    foreach ($match[$name_attr] as $value) {
+      if (strtolower($value) == strtolower($name)) {
+        $ok = true;
+        break;
+      }
+    }
+    if ( ! $ok) {
+      continue;
+    }
+
+    $ret = $match;
   }
 
   return $ret;
@@ -305,9 +404,6 @@
   if (isset($form['#validate']['user_login_validate'])) {
     $form['#validate'] = array('ldapauth_login_validate' => array());
   }
-  else if (isset($form['#submit']['user_pass_submit'])) {
-    $form['#submit'] = array('ldapauth_pass_submit' => array());
-  }
 }
 
 function ldapauth_login_validate($form_id, $form_values) {
@@ -346,15 +442,17 @@
 
   if ( ! _ldapauth_is_ldap_login_only($name)) {
     // Authenticate locally only if not initially authenticated by LDAP, or if configured to do so
+	 msg_r("local authentication");
     $user = user_authenticate($name, $pass);
   }
 
   // If not successful, try LDAP authentication directly
   if (!$user->uid) {
+	 msg_r("ldap authentication");
     $user = _ldapauth_ldap_login($name, $pass);
   }
 
-  if ($user->uid) {
+  if ($user->uid && $user->ldap_dn) {
     $_SESSION['ldap_login']['dn'] = $user->ldap_dn;
     $_SESSION['ldap_login']['pass'] = $pass;
   }
@@ -363,6 +461,7 @@
 }
 
 function _ldapauth_is_ldap_login_only($name) {
+  //return variable_get('ldap_login_process', LDAP_FIRST_LDAP) ;
   return variable_get('ldap_login_process', LDAP_FIRST_LDAP) && db_num_rows(db_query("SELECT name FROM {users} WHERE data LIKE '%%ldap\_authentified%%' AND name='%s'", $name));
 }
 
@@ -385,9 +484,10 @@
   }
 
   if (ldapauth_auth($name, $pass, $server)) {
+
     $account = user_load(array('name' => $login_string));
     $tmp_user->name = $login_string;
-    if ( ! $account->uid) { // Register this new user.
+    if ( ! isset($account->uid)) { // Register this new user.
       // Changes to this user_save():
       //   1. 'pass' => in "LDAP then Drupal" mode, actual password
       //                is written. In "LDAP only" mode, a random
@@ -411,7 +511,7 @@
       $dn = _ldapauth_login2dn($login_string);
 
       $user = user_save('', array('name' => $login_string, 'pass' => $pass, 'mail' => $mail, 'init' => $init, 'status' => 1, 'authname_ldapauth' => $login_string, 'roles' => array(DRUPAL_AUTHENTICATED_RID), 'ldap_authentified' => TRUE, 'ldap_dn' => $dn));
-      watchdog('user', t('New external user: %user using module %module.', array('%user' => theme('placeholder', $login_string), '%module' => theme('placeholder', $module))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
+      watchdog('user', t('New external user: %user using module %module.', array('%user' => theme('placeholder', $login_string), '%module' => theme('placeholder', 'ldapauth'))), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
     }
     else if ( ! $account->ldap_authentified) {
       drupal_set_message(t('Another user already exists in this system with the same login name. You should contact the system\'s administrator in order to solve this conflict.'), 'error');
@@ -426,14 +526,4 @@
   return $user;
 }
 
-function ldapauth_pass_submit($form_id, $form_values) {
-  $user = $form_values['account'];
-  if ($user->ldap_authentified) {
-    drupal_set_message('Lost passwords recovery is not yet implemented for LDAP users. Please contact the administrator if you need a password change.');
-  }
-  else {
-    user_pass_submit($form_id, $form_values);
-  }
-}
-
-?>
\ No newline at end of file
+?>
