You are here

function password_policy_cron in Password Policy 6

Same name and namespace in other branches
  1. 8.3 password_policy.module \password_policy_cron()
  2. 5 password_policy.module \password_policy_cron()
  3. 7.2 password_policy.module \password_policy_cron()
  4. 7 password_policy.module \password_policy_cron()

Implements hook_cron().

File

./password_policy.module, line 517
The password policy module allows you to enforce a specific level of password complexity for the user passwords on the system.

Code

function password_policy_cron() {

  // Short circuit if no policies are active that use expiration.
  if (!db_result(db_query("SELECT COUNT(*) FROM {password_policy} WHERE enabled = 1 AND expiration > 0"))) {
    return;
  }

  // Get all users' last password change time. Don't touch blocked accounts
  $result = db_query("SELECT u.uid AS uid, u.created AS created_u, p.created AS created_p, e.pid AS pid, e.warning AS warning, e.unblocked AS unblocked FROM {users} u LEFT JOIN {password_policy_history} p ON u.uid = p.uid LEFT JOIN {password_policy_expiration} e ON u.uid = e.uid WHERE u.uid > 0 AND u.status = 1 ORDER BY p.created ASC");
  while ($row = db_fetch_object($result)) {
    if ($row->uid == 1 && !variable_get('password_policy_admin', 0)) {
      continue;
    }

    // Use account creation timestamp if there is no entry in password history
    // table.
    $accounts[$row->uid] = empty($row->created_p) ? $row->created_u : $row->created_p;

    // Last time a warning was mailed out (if was). We need it because we send
    // warnings only once a day, not on all cron runs.
    $warns[$row->uid] = $row->warning;

    // The user was last time unblocked (if was). We don't block this account
    // again for some period of time.
    $unblocks[$row->uid] = $row->unblocked;

    // The user was last time unblocked (if was). We don't block this account
    // again for some period of time.
    $pids[$row->uid] = $row->pid;
  }
  if ($accounts) {
    foreach ($accounts as $uid => $last_change) {

      /* Alternative: $result = db_query("SELECT p.* FROM {password_policy} p INNER JOIN {password_policy_role} r ON p.pid = r.pid INNER JOIN {users_roles} u ON r.rid = u.rid WHERE p.enabled = 1 AND u.uid = %d ORDER BY p.weight LIMIT 1", $uid); */
      $roles = array(
        DRUPAL_AUTHENTICATED_RID,
      );
      $result = db_query("SELECT rid FROM {users_roles} WHERE uid = %d ORDER BY rid", $uid);
      while ($row = db_fetch_object($result)) {
        $roles[] = $row->rid;
      }
      $policy = _password_policy_load_active_policy($roles);
      if ($policy) {
        $expiration = $policy['expiration'];
        $warnings = !empty($policy['warning']) ? explode(',', $policy['warning']) : array();
        if (!empty($expiration)) {

          // Calculate expiration time.
          $expiration_seconds = $expiration * 60 * 60 * 24;
          $policy_start = $policy['created'];
          if (variable_get('password_policy_begin', 0) == 1) {
            $policy_start -= $expiration_seconds;
          }
          rsort($warnings, SORT_NUMERIC);
          $time = time();

          // Check expiration and warning days for each account.
          if (!empty($warnings)) {
            foreach ($warnings as $warning) {

              // Loop through all configured warning send out days. If today is
              // the day we send out the warning.
              $warning_seconds = $warning * 60 * 60 * 24;

              // Warning start time.
              $start_period = max($policy_start, $last_change) + $expiration_seconds - $warning_seconds;

              // Warning end time. We create a one day window for cron to run.
              $end_period = $start_period + 60 * 60 * 24;
              if ($warns[$uid] && $warns[$uid] > $start_period && $warns[$uid] < $end_period) {

                // A warning was already mailed out
                continue;
              }
              if ($time > $start_period && $time < $end_period) {

                // A warning falls in the one day window, so we send out the
                // warning.
                $account = user_load(array(
                  'uid' => $uid,
                ));
                $message = drupal_mail('password_policy', 'warning', $account->mail, user_preferred_language($account), array(
                  'account' => $account,
                  'days_left' => $warning,
                ));
                if ($message['result']) {

                  // The mail was sent out successfully.
                  watchdog('password_policy', 'Password expiration warning mailed to %username at %email.', array(
                    '%username' => $account->name,
                    '%email' => $account->mail,
                  ));
                }
                if ($pids[$uid]) {
                  db_query("UPDATE {password_policy_expiration} SET warning = %d WHERE uid = %d", $time, $uid);
                }
                else {
                  db_query("INSERT INTO {password_policy_expiration} (uid, warning) VALUES (%d, %d)", $uid, $time);
                }
              }
            }
          }
          if ($time > max($policy_start, $last_change) + $expiration_seconds && $time > $unblocks[$uid] + 60 * 60 * 24 && variable_get('password_policy_block', 0) == 0) {

            // Block expired accounts. Unblocked accounts are not blocked for
            // 24h.  One time login lasts for a 24h.
            db_query("UPDATE {users} SET status = 0 WHERE uid = %d", $uid);
            if ($pids[$uid]) {
              db_query("UPDATE {password_policy_expiration} SET blocked = %d WHERE uid = %d", $time, $uid);
            }
            else {
              db_query("INSERT INTO {password_policy_expiration} (uid, blocked) VALUES (%d, %d)", $uid, $time);
            }
            $account = user_load(array(
              'uid' => $uid,
            ));
            watchdog('password_policy', 'Password for user %name has expired.', array(
              '%name' => $account->name,
            ), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
          }
        }
      }
    }
  }
}