From bdae11ff4ac5a486c942170b0fb378e4d95d2e74 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 20 May 2016 19:38:36 +0200 Subject: [PATCH] store sambaPasswordHistory --- lam/lib/account.inc | 8 +- lam/lib/modules/sambaSamAccount.inc | 74 ++++++++++++++++++- lam/tests/lib/modules/sambaSamAccountTest.php | 54 ++++++++++++++ 3 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 lam/tests/lib/modules/sambaSamAccountTest.php diff --git a/lam/lib/account.inc b/lam/lib/account.inc index fcfe40f4..511edc85 100644 --- a/lam/lib/account.inc +++ b/lam/lib/account.inc @@ -385,7 +385,9 @@ function search_domains($server = null, $suffix = null) { } $ret = array(); $attr = array("DN", "sambaDomainName", "sambaSID", "sambaNextRid", "sambaNextGroupRid", - "sambaNextUserRid", "sambaAlgorithmicRidBase", 'sambaMinPwdAge', 'sambaMaxPwdAge'); + "sambaNextUserRid", "sambaAlgorithmicRidBase", 'sambaMinPwdAge', 'sambaMaxPwdAge', + 'sambaPwdHistoryLength' + ); if ($server == null) { $server = $_SESSION['ldap']->server(); } @@ -402,6 +404,7 @@ function search_domains($server = null, $suffix = null) { if (isset($units[$i]['sambaalgorithmicridbase'][0])) $ret[$i]->RIDbase = $units[$i]['sambaalgorithmicridbase'][0]; if (isset($units[$i]['sambaminpwdage'][0])) $ret[$i]->minPwdAge = $units[$i]['sambaminpwdage'][0]; if (isset($units[$i]['sambamaxpwdage'][0])) $ret[$i]->maxPwdAge = $units[$i]['sambamaxpwdage'][0]; + if (isset($units[$i]['sambapwdhistorylength'][0])) $ret[$i]->pwdHistoryLength = $units[$i]['sambapwdhistorylength'][0]; } return $ret; } @@ -439,6 +442,9 @@ class samba3domain { /** seconds after the password must be changed */ public $maxPwdAge; + + /** password history length */ + public $pwdHistoryLength; } /** diff --git a/lam/lib/modules/sambaSamAccount.inc b/lam/lib/modules/sambaSamAccount.inc index fb62f323..d4dc3ce6 100644 --- a/lam/lib/modules/sambaSamAccount.inc +++ b/lam/lib/modules/sambaSamAccount.inc @@ -4,7 +4,7 @@ $Id$ This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) Copyright (C) 2003 - 2006 Tilo Lutz - 2005 - 2015 Roland Gruber + 2005 - 2016 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 @@ -157,7 +157,7 @@ class sambaSamAccount extends baseModule implements passwordService { 'sambaLogonTime', 'sambaLogoffTime', 'sambaKickoffTime', 'sambaAcctFlags', 'sambaPwdLastSet', 'displayName', 'sambaHomePath', 'sambaHomeDrive', 'sambaLogonScript', 'sambaProfilePath', 'sambaUserWorkstations', 'sambaPrimaryGroupSID', 'sambaDomainName', 'sambaLogonHours', 'sambaMungedDial', - 'sambaPwdCanChange', 'sambaPwdMustChange'); // sambaPwdCanChange/sambaPwdMustChange only for extension removal + 'sambaPasswordHistory', 'sambaPwdCanChange', 'sambaPwdMustChange'); // sambaPwdCanChange/sambaPwdMustChange only for extension removal // PHP extensions $return['extensions'] = array('hash', 'iconv'); // profile options @@ -2396,6 +2396,41 @@ class sambaSamAccount extends baseModule implements passwordService { if ($forcePasswordChange) { $this->attributes['sambaPwdLastSet'][0] = '0'; } + // password history entry + $sambaDomains = $this->getDomains(); + if (sizeof($sambaDomains) > 0) { + if (isset($this->attributes['sambaSID'][0]) && $this->attributes['sambaSID'][0] != '') { + $domainSID = substr($this->attributes['sambaSID'][0], 0, strrpos($this->attributes['sambaSID'][0], "-")); + } + $historyLength = 0; + for ($i = 0; $i < count($sambaDomains); $i++) { + if (!empty($domainSID)) { + if (($domainSID == $sambaDomains[$i]->SID) && !empty($sambaDomains[$i]->pwdHistoryLength)) { + $historyLength = $sambaDomains[$i]->pwdHistoryLength; + break; + } + } + elseif (isset($this->attributes['sambaDomainName'][0]) && ($this->attributes['sambaDomainName'][0]!='')) { + if (($this->attributes['sambaDomainName'][0] == $sambaDomains[$i]->name) && !empty($sambaDomains[$i]->pwdHistoryLength)) { + $historyLength = $sambaDomains[$i]->pwdHistoryLength; + break; + } + } + } + if (!empty($historyLength) && is_numeric($historyLength) && ($historyLength > 0)) { + if (!empty($this->orig['sambaPasswordHistory'][0])) { + $this->attributes['sambaPasswordHistory'] = $this->orig['sambaPasswordHistory']; + } + else { + $this->attributes['sambaPasswordHistory'] = array(); + } + while (sizeof($this->attributes['sambaPasswordHistory']) > ($historyLength - 1)) { + array_pop($this->attributes['sambaPasswordHistory']); + } + $this->attributes['sambaPasswordHistory'][] = sambaSamAccount::createHistoryEntry($password); + $this->attributes['sambaPasswordHistory'] = array_values($this->attributes['sambaPasswordHistory']); + } + } return array(); } @@ -2581,6 +2616,41 @@ class sambaSamAccount extends baseModule implements passwordService { $this->attributes['sambaAcctFlags'][0] = str_replace(']', ' ]', $this->attributes['sambaAcctFlags'][0]); } + /** + * Creates the value to store in sambaPasswordHistory attribute. + * + * @param String $password password + * @return String value for sambaPasswordHistory + */ + public static function createHistoryEntry($password) { + if (empty($password)) { + return null; + } + $salt = generateSalt(16); + $saltHex = bin2hex($salt); + $md4hash = ntPassword($password); + $md5hash = md5($salt . hex2bin($md4hash)); + return strtoupper($saltHex . $md5hash); + } + + /** + * Checks if the given password matches the history entry. + * + * @param String $password password + * @param String $historyEntry sambaPasswordHistory entry + * @return Boolean entry matches password + */ + public static function validateHistoryEntry($password, $historyEntry) { + if (empty($historyEntry) || (strlen($historyEntry) != 64)) { + return false; + } + $salt = hex2bin(substr($historyEntry, 0, 32)); + $hash = substr($historyEntry, 32, 32); + $md4hash = ntPassword($password); + $md5hash = md5($salt . hex2bin($md4hash)); + return strtolower($md5hash) == strtolower($hash); + } + } ?> diff --git a/lam/tests/lib/modules/sambaSamAccountTest.php b/lam/tests/lib/modules/sambaSamAccountTest.php new file mode 100644 index 00000000..2fb419c3 --- /dev/null +++ b/lam/tests/lib/modules/sambaSamAccountTest.php @@ -0,0 +1,54 @@ +assertFalse(sambaSamAccount::validateHistoryEntry("password", "")); + $this->assertFalse(sambaSamAccount::validateHistoryEntry("password", "123")); + $this->assertFalse(sambaSamAccount::validateHistoryEntry("password", "1234567890123456789012345678901234567890")); + $this->assertFalse(sambaSamAccount::validateHistoryEntry("password", "12345678901234567890123456789012")); + $this->assertTrue(sambaSamAccount::validateHistoryEntry("password", "8E36265C3B44B640CCB365040DE68E5A4BF09D61C23AB4A0CC9D1866E1C69191")); + } + + public function testCreateHistoryEntry() { + $this->assertEquals(sambaSamAccount::createHistoryEntry(""), null); + + $password = 'password123'; + $this->assertTrue(sambaSamAccount::validateHistoryEntry($password, sambaSamAccount::createHistoryEntry($password))); + } + +} + +?> \ No newline at end of file