diff --git a/lam/HISTORY b/lam/HISTORY
index cb7e0a96..ad7bde84 100644
--- a/lam/HISTORY
+++ b/lam/HISTORY
@@ -2,6 +2,7 @@ June 2017
- Support multiple configurations for same account type
- PHP 7.1 compatibility
- Samba 3: added account expiration date to PDF fields
+ - Windows: Support unlocking of users with too many failed login attempts
15.03.2017 5.7
diff --git a/lam/lib/modules/windowsUser.inc b/lam/lib/modules/windowsUser.inc
index 12ebbcd9..f9dde396 100644
--- a/lam/lib/modules/windowsUser.inc
+++ b/lam/lib/modules/windowsUser.inc
@@ -1,5 +1,6 @@
-1)) {
+ return false;
+ }
+ $lockoutDurationSeconds = substr($lockoutDuration, 0, -7);
+ $lockoutTime = self::getFileTime($myAttrs['lockouttime'][0]);
+ $unlockTime = clone $lockoutTime;
+ $unlockTime->add(new DateInterval('PT' . abs($lockoutDurationSeconds) . 'S'));
+ $now = new DateTime();
+ if ($unlockTime > $now) {
+ $unlockTime->setTimezone(getTimeZone());
+ return $unlockTime;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the domain lockout duration for this DN.
+ *
+ * @param string $dn user DN
+ */
+ private static function getDomainLockoutDuration($dn) {
+ $lowerDn = strtolower($dn);
+ $domainRoot = substr($lowerDn, strpos($lowerDn, 'dc='));
+ if (isset(windowsUser::$lockoutDurationCache[$domainRoot])) {
+ return windowsUser::$lockoutDurationCache[$domainRoot];
+ }
+ $policyDN = 'cn=builtin,' . $domainRoot;
+ $policyAttrs = ldapGetDN($policyDN, array('lockoutduration'));
+ if (!empty($policyAttrs['lockoutduration'][0])) {
+ windowsUser::$lockoutDurationCache[$domainRoot] = $policyAttrs['lockoutduration'][0];
+ }
+ else {
+ windowsUser::$lockoutDurationCache[$domainRoot] = null;
+ }
+ return windowsUser::$lockoutDurationCache[$domainRoot];
+ }
+
+ /**
+ * Unlocks the user password. This resets 'lockoutTime' to 0.
+ */
+ public function unlockPassword() {
+ if (!empty($this->attributes['lockoutTime'][0])) {
+ $this->attributes['lockoutTime'][0] = '0';
+ }
+ }
+
/**
* Sets if the account is currently deactivated.
*
diff --git a/lam/lib/types/user.inc b/lam/lib/types/user.inc
index 2061e9c8..cf7bfa44 100644
--- a/lam/lib/types/user.inc
+++ b/lam/lib/types/user.inc
@@ -3,7 +3,7 @@
$Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
- Copyright (C) 2005 - 2016 Roland Gruber
+ Copyright (C) 2005 - 2017 Roland Gruber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -259,10 +259,22 @@ class user extends baseType {
$ppolicyLocked = true;
}
$windowsLocked = false;
- if ($windowsAvailable && windowsUser::isDeactivated($container->getAccountModule('windowsUser')->getAttributes())) {
- $windowsLocked = true;
+ $windowsPasswordLockedTime = null;
+ $windowsPasswordLocked = false;
+ if ($windowsAvailable){
+ $attrs = $container->getAccountModule('windowsUser')->getAttributes();
+ $attrs['dn'] = $container->dn_orig;
+ if (windowsUser::isDeactivated($attrs)) {
+ $windowsLocked = true;
+ }
+ $windowsPasswordLockedTime = windowsUser::getPasswordLocked($attrs, $this->getType());
+ if ($windowsPasswordLockedTime != null) {
+ $windowsPasswordLocked = true;
+ }
}
- $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked;
+ $partiallyLocked = $unixLocked || $sambaLocked
+ || $ppolicyLocked || $windowsLocked || $windowsPasswordLocked
+ || $is389dsDeactivated || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
@@ -309,6 +321,9 @@ class user extends baseType {
}
$statusTable .= '
' . _('Windows') . ' | |
';
}
+ if ($windowsAvailable && $windowsPasswordLocked) {
+ $statusTable .= '' . _('Locked till') . ' | ' . $windowsPasswordLockedTime->format('Y-m-d H:i:s') . ' |
';
+ }
// 389ds locked
if ($is389dsLocked) {
$statusTable .= '' . _('Locked') . ' | |
';
@@ -325,7 +340,7 @@ class user extends baseType {
$tipContent .= '
';
$tipContent .= _('Please click to lock/unlock this account.');
}
- $dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated);
+ $dialogDiv = $this->buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable, $windowsLocked, $windowsPasswordLockedTime, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated);
$onClick = '';
if ($isEditable) {
$onClick = 'onclick="showConfirmationDialog(\'' . _('Change account status') . '\', \'' . _('Ok') . '\', \'' . _('Cancel') . '\', \'lam_accountStatusDialog\', \'inputForm\', \'lam_accountStatusResult\');"';
@@ -344,18 +359,20 @@ class user extends baseType {
* @param boolean $ppolicyLocked PPolicy part is locked
* @param boolean $windowsAvailable Windows part is active
* @param boolean $windowsLocked Windows part is locked
+ * @param DateTime $windowsPasswordLockedTime lock time for Windows or null
* @param boolean $is389dsAvailable 389ds is available
* @param boolean $is389dsLocked account is locked
* @param boolean $is389dsDeactivated account is deactivated
*/
private function buildAccountStatusDialogDiv($unixAvailable, $unixLocked, $sambaAvailable, $sambaLocked, $ppolicyAvailable, $ppolicyLocked, $windowsAvailable,
- $windowsLocked, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated) {
- $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsLocked || $is389dsDeactivated;
+ $windowsLocked, $windowsPasswordLockedTime, $is389dsAvailable, $is389dsLocked, $is389dsDeactivated) {
+ $windowsPasswordLocked = ($windowsPasswordLockedTime != null);
+ $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $windowsPasswordLocked || $is389dsLocked || $is389dsDeactivated;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsLocked || $is389dsDeactivated)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
&& (!$ppolicyAvailable || $ppolicyLocked)
- && (!$windowsAvailable || $windowsLocked);
+ && (!$windowsAvailable || $windowsLocked || $windowsPasswordLocked);
$container = new htmlTable();
@@ -454,6 +471,10 @@ class user extends baseType {
$unlockContent->addElement(new htmlImage('../../graphics/samba.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindows', true, _('Windows'), null, false), true);
}
+ if ($windowsAvailable && $windowsPasswordLocked) {
+ $unlockContent->addElement(new htmlImage('../../graphics/samba.png'));
+ $unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlockWindowsPassword', true, _('Locked till') . ' ' . $windowsPasswordLockedTime->format('Y-m-d H:i:s'), null, false), true);
+ }
if ($is389dsLocked) {
$unlockContent->addElement(new htmlImage('../../graphics/security.png'));
$unlockContent->addElement(new htmlTableExtendedInputCheckbox('lam_accountStatusUnlock389ds', true, _('Unlock'), null, false), true);
@@ -540,6 +561,10 @@ class user extends baseType {
if (isset($_POST['lam_accountStatusUnlockWindows']) && ($_POST['lam_accountStatusUnlockWindows'] == 'on')) {
$container->getAccountModule('windowsUser')->setIsDeactivated(false);
}
+ // Windows password
+ if (isset($_POST['lam_accountStatusUnlockWindowsPassword']) && ($_POST['lam_accountStatusUnlockWindowsPassword'] == 'on')) {
+ $container->getAccountModule('windowsUser')->unlockPassword();
+ }
// 389ds unlocking
if (isset($_POST['lam_accountStatusUnlock389ds']) && ($_POST['lam_accountStatusUnlock389ds'] == 'on')) {
$container->getAccountModule('locking389ds')->unlock(false);
@@ -869,6 +894,7 @@ class lamUserList extends lamList {
$attrs[] = 'sambaAcctFlags';
$attrs[] = 'userPassword';
$attrs[] = 'userAccountControl';
+ $attrs[] = 'lockoutTime';
$attrs[] = 'nsAccountLock';
$attrs[] = 'accountUnlockTime';
$attrs[] = 'objectClass';
@@ -890,12 +916,13 @@ class lamUserList extends lamList {
$sambaLocked = self::isSambaLocked($this->entries[$i]);
$ppolicyLocked = self::isPPolicyLocked($this->entries[$i]);
$windowsLocked = self::isWindowsLocked($this->entries[$i]);
+ $windowsPasswordLocked = ($this->getWindowsPasswordLockedTime($this->entries[$i]) != null);
$is389dsLocked = self::is389dsLocked($this->entries[$i]);
$is389dsDeactivated = self::is389dsDeactivated($this->entries[$i]);
$hasLocked = ($unixAvailable && $unixLocked)
|| ($sambaAvailable && $sambaLocked)
|| ($ppolicyAvailable && $ppolicyLocked)
- || ($windowsAvailable && $windowsLocked)
+ || ($windowsAvailable && ($windowsLocked || $windowsPasswordLocked))
|| $is389dsDeactivated
|| $is389dsLocked;
$hasUnlocked = ($unixAvailable && !$unixLocked)
@@ -937,9 +964,13 @@ class lamUserList extends lamList {
$sambaLocked = self::isSambaLocked($attrs);
$ppolicyLocked = self::isPPolicyLocked($attrs);
$windowsLocked = self::isWindowsLocked($attrs);
+ $windowsPasswordLockedTime = $this->getWindowsPasswordLockedTime($attrs);
+ $windowsPasswordLocked = ($windowsPasswordLockedTime != null);
$is389dsDeactivated = self::is389dsDeactivated($attrs);
$is389dsLocked = self::is389dsLocked($attrs);
- $partiallyLocked = $unixLocked || $sambaLocked || $ppolicyLocked || $windowsLocked || $is389dsDeactivated || $is389dsLocked;
+ $partiallyLocked = $unixLocked || $sambaLocked
+ || $ppolicyLocked || $windowsLocked || $windowsPasswordLocked
+ || $is389dsDeactivated || $is389dsLocked;
$fullyLocked = ($unixAvailable || $sambaAvailable || $ppolicyAvailable || $windowsAvailable || $is389dsDeactivated || $is389dsLocked)
&& (!$unixAvailable || $unixLocked)
&& (!$sambaAvailable || $sambaLocked)
@@ -987,6 +1018,9 @@ class lamUserList extends lamList {
}
$tipContent .= '' . _('Windows') . ' | |
';
}
+ if ($windowsAvailable && $windowsPasswordLocked) {
+ $tipContent .= '' . _('Locked till') . ' | ' . $windowsPasswordLockedTime->format('Y-m-d H:i:s') . ' |
';
+ }
// 389 locked
if ($is389dsLocked) {
$tipContent .= '' . _('Locked') . ' | |
';
@@ -1083,6 +1117,16 @@ class lamUserList extends lamList {
return windowsUser::isDeactivated($attrs);
}
+ /**
+ * Returns if the Windows password is locked.
+ *
+ * @param array $attrs LDAP attributes
+ * @return DateTime Windows password lock time or null
+ */
+ public function getWindowsPasswordLockedTime(&$attrs) {
+ return windowsUser::getPasswordLocked($attrs, $this->type);
+ }
+
/**
* Returns if the 389ds is activated.
*