Index: contrib/password_tab/password_policy_password_tab.pages.inc
===================================================================
--- contrib/password_tab/password_policy_password_tab.pages.inc
+++ contrib/password_tab/password_policy_password_tab.pages.inc	(working copy)
@@ -34,6 +34,11 @@
   if (empty($pass)) {
     form_set_error('pass', t('Your password cannot be empty.'));
   }
+
+  // If block $_SESSION flag is set, always reset to 2 in case of form validation issues.
+  if ($_SESSION['password_policy_blocked']) {
+    $_SESSION['password_policy_blocked'] = 2;
+  }
 }
 
 /**
@@ -49,5 +54,10 @@
     $redirect = parse_url(urldecode(strtr(PASSWORD_POLICY_PASSWORD_TAB_REDIRECT, array('%uid' => $user->uid))));
     $form_state['redirect'] = array($redirect['path'], isset($redirect['query']) ? $redirect['query'] : NULL, isset($redirect['fragment']) ? $redirect['fragment'] : NULL);
   }
+  
+  // Password changed, clear block $_SESSION flag.
+  if ($_SESSION['password_policy_blocked']) {
+    unset($_SESSION['password_policy_blocked']);
+  }
 }
 
Index: password_policy.module
===================================================================
--- password_policy.module
+++ password_policy.module	(working copy)
@@ -32,7 +32,7 @@
  * Implementation of hook_init().
  */
 function password_policy_init() {
-  global $_password_policy;
+  global $_password_policy, $user;
 
   // Save all available constrains in a global variable.
   $dir = drupal_get_path('module', 'password_policy') .'/constraints';
@@ -43,6 +43,17 @@
       $_password_policy[] = drupal_substr($file->name, 11);
     }
   }
+
+  // Account has been initially flagged to be blocked. If the submit handler 
+  // does not clear the block $_SESSION flag, the account will be blocked.  
+  if ($user->uid > 1 && $_SESSION['password_policy_blocked']) {
+    // Increment the counter. Normal progression is account flagged on login (1), 
+    // form display (2), validate (3), submit (would be 4 but is cleared).
+    $_SESSION['password_policy_blocked']++;
+    if (($_SESSION['password_policy_blocked'] == 3 && empty($_POST)) || $_SESSION['password_policy_blocked'] > 3) {
+      _password_policy_expire_account($user);
+    }
+  }
 }
 
 /**
@@ -247,24 +258,14 @@
           }
           $time = time();
           if ($time > max($policy_start, $last_change) + $expiration_seconds) {
-            // The account has expired.
-            db_query("UPDATE {users} SET status = '0' WHERE uid = %d", $account->uid);
-            $result = db_query("SELECT * FROM {password_policy_expiration} WHERE uid = %d", $account->uid);
-            if ($row = db_fetch_array($result)) {
-              db_query("UPDATE {password_policy_expiration} SET blocked = %d WHERE uid = %d", $time, $account->uid);
-            }
-            else {
-              db_query("INSERT INTO {password_policy_expiration} (uid, blocked) VALUES (%d, %d)", $account->uid, $time);
-            }
-            watchdog('password_policy', 'Password for user %name has expired.', array('%name' => $account->name), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
             if (PASSWORD_POLICY_BLOCK == 0) {
               // User is blocked imediately and cannot change his password after expiration.
-              include_once(drupal_get_path('module', 'user') .'/user.pages.inc');
-              user_logout();
+              _password_policy_expire_account($account);
             }
             else {
-              // User is transfered to a password change page. User is unblocked on password change.
-              // If the user don't change password now, he will not be able to login again, since he is still blocked.
+              // Redirect user to change password form and set initial block $_SESSION flag.
+              $_SESSION['password_policy_blocked'] = 1;
+              
               drupal_set_message(t('Your password has expired. You have to change it now or you won\'t be able to login again.'), 'error');
               $destination = drupal_get_destination();
               unset($_REQUEST['destination']);
@@ -325,6 +326,11 @@
       // Set a custom form validate and submit handlers.
       $form['#validate'][] = 'password_policy_password_validate';
       $form['#submit'][] = 'password_policy_password_submit';
+
+      // If block $_SESSION flag is set, always reset to 2 in case of form validation issues.
+      if ($_SESSION['password_policy_blocked']) {
+        $_SESSION['password_policy_blocked'] = 2;
+      }
       break;
   }
 }
@@ -475,10 +481,9 @@
   if ($account->uid && !empty($values['pass'])) {
     _password_policy_store_password($account->uid, $values['pass']);
 
-    // If user successfully changed his password we will unblock the account.
-    if ($user->uid == $account->uid) {
-      db_query("UPDATE {users} SET status = 1 WHERE uid = %d", $account->uid);
-      db_query("DELETE FROM {password_policy_expiration} WHERE uid = %d", $account->uid);
+    // Password changed, clear block $_SESSION flag.
+    if ($_SESSION['password_policy_blocked']) {
+      unset($_SESSION['password_policy_blocked']);
     }
   }
 }
@@ -785,3 +790,22 @@
     'setting');
 }
 
+/**
+ * Account has expired.
+ */
+function _password_policy_expire_account($account) {
+  if ($account->uid > 1) {
+    db_query("UPDATE {users} SET status = '0' WHERE uid = %d", $account->uid);
+    $result = db_query("SELECT * FROM {password_policy_expiration} WHERE uid = %d", $account->uid);
+    if ($row = db_fetch_array($result)) {
+      db_query("UPDATE {password_policy_expiration} SET blocked = %d WHERE uid = %d", time(), $account->uid);
+    }
+    else {
+      db_query("INSERT INTO {password_policy_expiration} (uid, blocked) VALUES (%d, %d)", $account->uid, time());
+    }
+    watchdog('password_policy', 'Password for user %name has expired.', array('%name' => $account->name), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $account->uid .'/edit'));
+    
+    include_once(drupal_get_path('module', 'user') .'/user.pages.inc');
+    user_logout();
+  }
+} 
