From 7b82372a2dcdcbc9be0359849430f5fa962da1a3 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sun, 7 May 2017 13:26:41 +0200 Subject: [PATCH] support Windows lockoutTime --- lam/HISTORY | 1 + lam/lib/modules/windowsUser.inc | 65 ++++++++++++++++++++++++++++++++- lam/lib/types/user.inc | 64 +++++++++++++++++++++++++++----- 3 files changed, 119 insertions(+), 11 deletions(-) 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 .= '
"hint" '; $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. *