# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: contributions/modules/login_security/login_security.admin.inc
--- contributions/modules/login_security/login_security.admin.inc Base (1.1.2.1)
+++ contributions/modules/login_security/login_security.admin.inc Locally Modified (Based On 1.1.2.1)
@@ -72,6 +72,16 @@
     '#description' => t('Enter the number of login failures a host is allowed. After that number is reached, the host will be blocked, no matter the username attempting to log in. The host blocking protection will not dissapear automatically and should be removed manually from the !access administration interface.', array('!access' => l(t('access rules'), 'admin/user/rules'))),
     '#field_suffix' => '<kbd>'. t('Failed attempts') .'</kbd>'
   );
+  $form['login_security_activity_threshold'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Maximum number of login failures before detecting an ongoing attack'),
+    '#default_value' => variable_get('login_security_activity_threshold', LOGIN_SECURITY_ACTIVITY_THRESHOLD),
+    '#element_validate' => array('_login_security_valid_integer'),
+    '#size' => 3,
+    '#maxlength' => 3,
+    '#description' => t('Enter the number of login failures before creating a warning log entry about this suspicious activity. If the number of invalid login events currently being tracked reach this number, and ongoing attack is detected.'),
+    '#field_suffix' => '<kbd>'. t('Failed attempts') .'</kbd>'
+  );
 
   $form['login_messages'] = array(
     '#type' => 'fieldset',
@@ -106,6 +116,11 @@
     '#title' => t('Send email message to the admin (uid 1) when a user is blocked by this module.'),
     '#default_value' => variable_get('login_security_user_blocked_email', LOGIN_SECURITY_USER_BLOCKED_EMAIL),
   );
+  $form['login_messages']['login_security_login_activity_email'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Send email message to the admin (uid 1) when an ongoing attack is detected.'),
+    '#default_value' => variable_get('login_security_login_activity_email', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL),
+  );
 
 
   $form['login_security']['Notifications'] = array(
@@ -114,7 +129,7 @@
     '#weight' => 3,
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
-    '#description' => t("You may edit the notifications used by the Login Security module. Allowed placeholders for all the notifications include the following: <ul><li>%date                  :  The (formatted) date and time of the event.</li><li>%ip                    :  The IP address tracked for this event.</li><li>%username              :  The username entered in the login form (sanitized).</li><li>%email                 :  If the user exists, this will be the email address.</li><li>%uid                   :  If the user exists, this will be the user uid.</li><li>%site                  :  The name of the site as configured in the administration.</li><li>%uri                   :  The base url of this Drupal site.</li><li>%edit_uri              :  Direct link to the user (based on the name entered) edit page.</li><li>%hard_block_attempts   :  Configured maximum attempts before hard blocking the IP address.</li><li>%soft_block_attempts   :  Configured maximum attempts before soft blocking the IP address.</li><li>%user_block_attempts   :  Configured maximum login attempts before blocking the user.</li><li>%user_ip_current_count :  The total attempts for this user name tracked from this IP address.</li><li>%ip_current_count      :  The total login attempts tracked from from this IP address.</li><li>%user_current_count    :  The total login attempts tracked for this user name .</li><li>%tracking_time         :  The tracking time value: in hours.</li></ul>"),
+    '#description' => t("You may edit the notifications used by the Login Security module. Allowed placeholders for all the notifications include the following: <ul><li>%date                  :  The (formatted) date and time of the event.</li><li>%ip                    :  The IP address tracked for this event.</li><li>%username              :  The username entered in the login form (sanitized).</li><li>%email                 :  If the user exists, this will be the email address.</li><li>%uid                   :  If the user exists, this will be the user uid.</li><li>%site                  :  The name of the site as configured in the administration.</li><li>%uri                   :  The base url of this Drupal site.</li><li>%edit_uri              :  Direct link to the user (based on the name entered) edit page.</li><li>%hard_block_attempts   :  Configured maximum attempts before hard blocking the IP address.</li><li>%soft_block_attempts   :  Configured maximum attempts before soft blocking the IP address.</li><li>%user_block_attempts   :  Configured maximum login attempts before blocking the user.</li><li>%user_ip_current_count :  The total attempts for this user name tracked from this IP address.</li><li>%ip_current_count      :  The total login attempts tracked from from this IP address.</li><li>%user_current_count    :  The total login attempts tracked for this user name .</li><li>%tracking_time         :  The tracking time value: in hours.</li><li>%tracking_current_count:  Total tracked events</li><li>%activity_threshold    :  Value of attempts to detect ongoing attack.</li></ul>"),
   );
   $form['login_security']['Notifications']['login_security_notice_attempts_message'] = array(
     '#type' => 'textarea',
@@ -145,25 +160,42 @@
     '#description' => t('Enter the message to be shown when a user gets blocked due to enough failed login attempts.'),
   );
 
-  $form['login_security']['Notifications']['email'] = array(
+  $form['login_security']['Notifications']['user_block_email'] = array(
     '#type' => 'fieldset',
     '#title' => t('Email to be sent to the administrator user (uid 1) for blocked accounts.'),
     '#weight' => 3,
-    '#description' => t('Configure the subject and body fo the email message.'),
+    '#description' => t('Configure the subject and body of the email message.'),
   );
-
-  $form['login_security']['Notifications']['email']['login_security_user_blocked_email_subject'] = array(
+  $form['login_security']['Notifications']['user_block_email']['login_security_user_blocked_email_subject'] = array(
     '#type' => 'textfield',
     '#title' => t('Email subject'),
     '#default_value' => variable_get('login_security_user_blocked_email_subject', LOGIN_SECURITY_USER_BLOCKED_EMAIL_SUBJECT),
   );
-  $form['login_security']['Notifications']['email']['login_security_user_blocked_email_body'] = array(
+  $form['login_security']['Notifications']['user_block_email']['login_security_user_blocked_email_body'] = array(
     '#type' => 'textarea',
     '#title' => t('Email body'),
     '#default_value' => variable_get('login_security_user_blocked_email_body', LOGIN_SECURITY_USER_BLOCKED_EMAIL_BODY),
     '#description' => t('Enter the message to be sent to the administrator informing a user has been blocked.'),
   );
 
+  $form['login_security']['Notifications']['login_activity_email'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Email to be sent to the administrator user (uid 1) for ongoing attack detections.'),
+    '#weight' => 3,
+    '#description' => t('Configure the subject and body of the email message.'),
+  );
+  $form['login_security']['Notifications']['login_activity_email']['login_security_login_activity_email_subject'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Email subject'),
+    '#default_value' => variable_get('login_security_login_activity_email_subject', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_SUBJECT),
+  );
+  $form['login_security']['Notifications']['login_activity_email']['login_security_login_activity_email_body'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Email body'),
+    '#default_value' => variable_get('login_security_login_activity_email_body', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_BODY),
+    '#description' => t('Enter the message to be sent to the administrator informing about supicious activity.'),
+  );
+  
   return system_settings_form($form);
 }
 
Index: contributions/modules/login_security/login_security.module
--- contributions/modules/login_security/login_security.module Base (1.12.2.14)
+++ contributions/modules/login_security/login_security.module Locally Modified (Based On 1.12.2.14)
@@ -18,6 +18,7 @@
 define('LOGIN_SECURITY_HOST_WRONG_COUNT_HARD', 0);
 define('LOGIN_SECURITY_DISABLE_CORE_LOGIN_ERROR', 0);
 define('LOGIN_SECURITY_NOTICE_ATTEMPTS_AVAILABLE', 0);
+define('LOGIN_SECURITY_ACTIVITY_THRESHOLD', 0);
 define('LOGIN_SECURITY_NOTICE_ATTEMPTS_MESSAGE', "You have used %user_current_count out of %user_block_attempts login attempts. After all %user_block_attempts have been used, you will be unable to login.");
 define('LOGIN_SECURITY_HOST_SOFT_BANNED', "This host is not allowed to log in to %site. Please contact your site administrator.");
 define('LOGIN_SECURITY_HOST_HARD_BANNED', "The IP address <em>%ip</em> is banned at %site, and will not be able to access any of its content from now on. Please contact the site administrator.");
@@ -25,6 +26,10 @@
 define('LOGIN_SECURITY_USER_BLOCKED_EMAIL', FALSE);
 define('LOGIN_SECURITY_USER_BLOCKED_EMAIL_SUBJECT', "Security action: The user %username has been blocked.");
 define('LOGIN_SECURITY_USER_BLOCKED_EMAIL_BODY', "The user %username (%edit_uri) has been blocked at %site due to the amount of failed login attempts. Please check the logs for more information.");
+define('LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL', FALSE);
+define('LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_SUBJECT', "Security information: Unexpected login activity has been detected at %site.");
+define('LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_BODY', "The configured threshold of %activity_threshold logins has been reached with a tota of %tracking_current_count invalid login attempts. You should review your log information about login attempts at %site.");
+define('LOGIN_SECURITY_THRESHOLD_NOTIFIED', FALSE);
 
 /**
  * Implementation of hook_cron().
@@ -100,7 +105,7 @@
 }
 
 /**
- * Temprarily deny validation to users with excess invalid login attempts.
+ * Temporarily deny validation to users with excess invalid login attempts.
  *
  * @url http://drupal.org/node/493164
  */
@@ -136,7 +141,35 @@
   // Populate variables to be used in any module message or login operation
   $variables = _login_security_get_variables_by_name($name);
 
-  // Start with login Delay
+  // First, check if administrator should be notified of unexpected login activity..
+  // Only process if configured threshold > 1
+  // see: http://drupal.org/node/583092
+  if ($variables['%activity_threshold'])  {
+    //check if threshold has been reached
+    if ($variables['%tracking_current_count'] > $variables['%activity_threshold'] ) {
+      // Check if admin has been already alerted
+      if (!variable_get('login_security_threshold_notified', LOGIN_SECURITY_THRESHOLD_NOTIFIED)) {
+        //Mark alert status as notified and send the email
+        watchdog('login_security', 'Ongoing attack detected: Suspicious activity detected in login form submissions. Too many invalid login attempts threshold reached: currently %tracking_current_count events are tracked, and threshold is configured for %activity_threshold attempts.', $variables, WATCHDOG_WARNING);
+        variable_set('login_security_threshold_notified', TRUE);
+        //Submit email only if required..
+        if( variable_get('login_security_login_activity_email', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL) ){
+          $from = variable_get('site_mail', ini_get('sendmail_from'));
+          $admin_mail =  db_result(db_query("SELECT mail FROM {users} WHERE uid = 1"));
+          $subject = login_security_t(variable_get('login_security_login_activity_email_subject', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_SUBJECT), $variables);
+          $body = login_security_t(variable_get('login_security_login_activity_email_mody', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_BODY), $variables);
+          $mail = drupal_mail('login_security', 'login_activity_notify', $admin_mail, language_default(), $variables, $from, TRUE);
+        }
+      }
+    }
+    elseif ($variables['%tracking_current_count'] < ($variables['%activity_threshold'] / 3) ) {
+      //Reset alert if currently tracked events is < threshold / 3
+      watchdog('login_security', 'Suspicious activity in login form submissions is no longer detected: currently %tracking_current_count events are being tracked, and threshold is configured for %activity_threshold maximum allowed attempts).', $variables, WATCHDOG_NOTICE);
+      variable_set('login_security_threshold_notified', FALSE);
+    }
+  }
+
+  // then, start with login Delay
   if ($delay = variable_get('login_security_delay_base_time', LOGIN_SECURITY_BASE_TIME)) {
     $secs = (variable_get('login_security_delay_increase', LOGIN_SECURITY_DELAY_INCREASE) == 1) ? intval($variables['%user_ip_current_count']-1) * intval($delay) : intval($delay);
     //Included 0 just in case of 'max_execution_time' being lower than 3
@@ -310,6 +343,8 @@
     '%ip_current_count' => db_result(db_query("SELECT COUNT(id) FROM {login_security_track} WHERE host = '%s'", $ipaddress)),
     '%user_current_count' => db_result(db_query("SELECT COUNT(id) FROM {login_security_track} WHERE name = '%s'", $name)),
     '%tracking_time' => variable_get('login_security_track_time', LOGIN_SECURITY_TRACK_TIME),
+    '%tracking_current_count' => db_result(db_query("SELECT COUNT(id) FROM {login_security_track}")),
+    '%activity_threshold' => variable_get('login_security_activity_threshold', LOGIN_SECURITY_ACTIVITY_THRESHOLD),
   );
   return $variables;
 }
@@ -320,6 +355,10 @@
       $message['subject'] = login_security_t(variable_get('login_security_user_blocked_email_subject', LOGIN_SECURITY_USER_BLOCKED_EMAIL_SUBJECT), $variables);
       $message['body'] = login_security_t(variable_get('login_security_user_blocked_email_mody', LOGIN_SECURITY_USER_BLOCKED_EMAIL_BODY), $variables);
       break;
+    case 'login_activity_notify':
+      $message['subject'] = login_security_t(variable_get('login_security_login_activity_email_subject', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_SUBJECT), $variables);
+      $message['body'] = login_security_t(variable_get('login_security_login_activity_email_mody', LOGIN_SECURITY_LOGIN_ACTIVITY_EMAIL_BODY), $variables);
+      break;
   }
 }
 
Index: contributions/modules/login_security/login_security.test
--- contributions/modules/login_security/login_security.test Base (1.1.2.9)
+++ contributions/modules/login_security/login_security.test Locally Modified (Based On 1.1.2.9)
@@ -44,6 +44,11 @@
     $this->assertField('login_security_user_blocked_email_body', t('User blocked email body field exists'));
     $this->assertField('login_security_last_login_timestamp', t('Last login timestamp field exists.'));
     $this->assertField('login_security_last_access_timestamp', t('Last access timestamp field exists.'));
+    $this->assertField('login_security_login_activity_email', t('Send email for unexpected login activity field exists.'));
+    $this->assertField('login_security_login_activity_email_subject', t('Login activity email subject field exists.'));
+    $this->assertField('login_security_login_activity_email_body', t('Login activity email body field exists.'));
+    $this->assertField('login_security_activity_threshold', t('Invalid login threshold field exists.'));
+    
\ No newline at end of file
   }
 }
 
Index: contributions/modules/login_security/README.txt
--- contributions/modules/login_security/README.txt Base (1.4.4.3)
+++ contributions/modules/login_security/README.txt Locally Modified (Based On 1.4.4.3)
@@ -12,6 +12,12 @@
 
 These are the features included:
 
+Ongoing attack detection
+------------------------
+System will detect if a password guessing or bruteforce attack is being performed
+against the Drupal login form. Using a threshold value, you instruct the module
+to alert (using a watchdog message, and optionally send an email) the admin user
+when the number of invalid login attempts reaches the threshold value.
 
 Soft Protections
 ----------------
@@ -128,6 +134,11 @@
    included in the access list as a deny rule. To remove the IP from this ban,
    you will have to go to:  Administer -> User Management -> Access Rules.
 
+ - Maximum number of login failures to detect ongoing attack: This value is the
+   threshold used to detect a password guess attack. The limit means that during
+   the "track time" period, this number of invalid logins indicates a password
+   guessing attack.
+
 Notifications
 
  The module also provides some notifications for the users to understand what is
@@ -147,9 +158,14 @@
    will be shown at all, so user will not be aware of unsuccessful login
    attempt, or blocked account messages.
 
- - Send email message to the admin: An email could also be sent to the 
-   administrator (uid 1), each time an account is blocked.
+ - Send email message to the admin about blocked accounts: An email could also
+   be sent to the administrator (uid 1), each time an account is blocked.
 
+ - Send email message to the admin about login suspicious activity: An email
+   could also be sent to the administrator (uid 1), whenever suspicious activity
+   in detected in the login form submissions. When a determined value (threshold)
+   of invalid login attemps is reached, the email is sent.
+
 Notifications are configurable in the Login Security settings section, where
 the strings could be personalized using the following placeholders:
 
@@ -168,6 +184,8 @@
     %ip_current_count      :  The total login attempts by this IP address
     %user_current_count    :  The total login attempts for this name 
     %tracking_time         :  The tracking time: in hours
+    %tracking_current_count:  Total tracked events
+    %activity_threshold    :  Value of attempts to detect ongoing attack.
 
 
 Understanding protections
@@ -204,7 +222,24 @@
    Note: The tracking entries in the database for any host <-> username pair are
         being deleted on: 'login', 'update' and 'delete' user operations.
 
+ 6.- For the onoing attack detection, all the tracked events are taken in count.
+   The system detects an ongoing attack and notices the admin about that. It will
+   remain in attack mode (no more notices will be sent) untill the attack is no
+   longer detected. This will happen when the total number of tracked events is
+   below 'maximum allowed to detect ongoing attack' / 3. Since then, once the
+   threshold value is reached again, a new notification will be set in the log
+   or sent by email.
 
+   E.g Say you put 1 hour of track time and a maximum number of login failures
+   to detect ongoing attack of 20. This means that if during the last hour there
+   are more than 20 invalid login attemps an attack is detected. A log entry is
+   created to notice the detected attack, and system switches to 'attack' status,
+   where no more notices about the attack will be logged or sent. After sometime
+   the attack stops. And once the number of invalid login attemps for this last
+   hour is below 1/3 of this maximum: invalid attemps are below 6 (20 / 3 for
+   the example) a normal status is recovered. If a new attack is detected, the
+   module will alert again about it.
+
 Most used configuration
 -----------------------
 The most common configuration options will look like this:
