From a67779a590591981c85b56dacd792c80a4679fa6 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 1 Apr 2019 16:32:27 +1300 Subject: [PATCH 1/4] tests: Add test for setting min/maxPwdAge Currently setting maxPwdAge doesn't work at all. While we're adding a test, we might as well assert that minPwdAge can't be greater than maxPwdAge as well. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13873 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett (cherry picked from commit d247a600845fdc6bf232496e8db56cd1d95a3022) --- python/samba/tests/samba_tool/passwordsettings.py | 38 +++++++++++++++++++++++ selftest/knownfail.d/passwordsettings | 1 + 2 files changed, 39 insertions(+) create mode 100644 selftest/knownfail.d/passwordsettings diff --git a/python/samba/tests/samba_tool/passwordsettings.py b/python/samba/tests/samba_tool/passwordsettings.py index e29c76c..43264b6 100644 --- a/python/samba/tests/samba_tool/passwordsettings.py +++ b/python/samba/tests/samba_tool/passwordsettings.py @@ -444,3 +444,41 @@ class PwdSettingsCmdTestCase(SambaToolCmdTest): self.assertCmdSuccess(result, out, err) self.assertEquals(err, "", "Shouldn't be any error messages") self.assertIn("Minimum password length: %u" % new_len, out) + + def test_domain_passwordsettings_pwdage(self): + """Checks the 'set' command for the domain password age (non-PSO)""" + + # check we can set the domain max password age + max_pwd_age = self.ldb.get_maxPwdAge() + self.addCleanup(self.ldb.set_maxPwdAge, max_pwd_age) + max_pwd_args = "--max-pwd-age=270" + (result, out, err) = self.runsublevelcmd("domain", ("passwordsettings", + "set"), max_pwd_args, + "-H", self.server, + self.user_auth) + self.assertCmdSuccess(result, out, err) + self.assertEquals(err, "", "Shouldn't be any error messages") + self.assertIn("successful", out) + self.assertNotEquals(max_pwd_age, self.ldb.get_maxPwdAge()) + + # check we can't set the domain min password age to more than the max + min_pwd_age = self.ldb.get_minPwdAge() + self.addCleanup(self.ldb.set_minPwdAge, min_pwd_age) + min_pwd_args = "--min-pwd-age=271" + (result, out, err) = self.runsublevelcmd("domain", ("passwordsettings", + "set"), min_pwd_args, + "-H", self.server, + self.user_auth) + self.assertCmdFail(result, "minPwdAge > maxPwdAge should be rejected") + self.assertIn("Maximum password age", err) + + # check we can set the domain min password age to less than the max + min_pwd_args = "--min-pwd-age=269" + (result, out, err) = self.runsublevelcmd("domain", ("passwordsettings", + "set"), min_pwd_args, + "-H", self.server, + self.user_auth) + self.assertCmdSuccess(result, out, err) + self.assertEquals(err, "", "Shouldn't be any error messages") + self.assertIn("successful", out) + self.assertNotEquals(min_pwd_age, self.ldb.get_minPwdAge()) diff --git a/selftest/knownfail.d/passwordsettings b/selftest/knownfail.d/passwordsettings new file mode 100644 index 0000000..8e94cef --- /dev/null +++ b/selftest/knownfail.d/passwordsettings @@ -0,0 +1 @@ +samba.tests.samba_tool.passwordsettings.samba.tests.samba_tool.passwordsettings.PwdSettingsCmdTestCase.test_domain_passwordsettings_pwdage\(ad_dc_default:local\) -- 2.7.4 From 340b6ada7ccb77c0989dc0125c1d0ddb95d576a7 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 1 Apr 2019 16:42:32 +1300 Subject: [PATCH 2/4] netcmd: Use python constant for -0x8000000000000000 BUG: https://bugzilla.samba.org/show_bug.cgi?id=13873 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett (cherry picked from commit b43f997f2397771b159c49526a36bd2b3467b0ef) --- python/samba/netcmd/domain.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py index b7aedc1..d7889e6 100644 --- a/python/samba/netcmd/domain.py +++ b/python/samba/netcmd/domain.py @@ -1254,6 +1254,10 @@ class cmd_domain_level(Command): raise CommandError("invalid argument: '%s' (choose from 'show', 'raise')" % subcommand) +# In MS AD, setting a timeout to '(never)' corresponds to this value +NEVER_TIMESTAMP = int(-0x8000000000000000) + + class cmd_domain_passwordsettings_show(Command): """Display current password settings for the domain.""" @@ -1289,13 +1293,13 @@ class cmd_domain_passwordsettings_show(Command): cur_min_pwd_len = int(res[0]["minPwdLength"][0]) # ticks -> days cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) - if int(res[0]["maxPwdAge"][0]) == -0x8000000000000000: + if int(res[0]["maxPwdAge"][0]) == NEVER_TIMESTAMP: cur_max_pwd_age = 0 else: cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) cur_account_lockout_threshold = int(res[0]["lockoutThreshold"][0]) # ticks -> mins - if int(res[0]["lockoutDuration"][0]) == -0x8000000000000000: + if int(res[0]["lockoutDuration"][0]) == NEVER_TIMESTAMP: cur_account_lockout_duration = 0 else: cur_account_lockout_duration = abs(int(res[0]["lockoutDuration"][0])) / (1e7 * 60) @@ -1454,7 +1458,7 @@ class cmd_domain_passwordsettings_set(Command): # days -> ticks if max_pwd_age == 0: - max_pwd_age_ticks = -0x8000000000000000 + max_pwd_age_ticks = NEVER_TIMESTAMP else: max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7)) @@ -1473,7 +1477,7 @@ class cmd_domain_passwordsettings_set(Command): # minutes -> ticks if account_lockout_duration == 0: - account_lockout_duration_ticks = -0x8000000000000000 + account_lockout_duration_ticks = NEVER_TIMESTAMP else: account_lockout_duration_ticks = -int(account_lockout_duration * (60 * 1e7)) @@ -1502,7 +1506,7 @@ class cmd_domain_passwordsettings_set(Command): # minutes -> ticks if reset_account_lockout_after == 0: - reset_account_lockout_after_ticks = -0x8000000000000000 + reset_account_lockout_after_ticks = NEVER_TIMESTAMP else: reset_account_lockout_after_ticks = -int(reset_account_lockout_after * (60 * 1e7)) -- 2.7.4 From 579e2b589f264f5b3b6eff61bf5ec74207dbf6e9 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Tue, 2 Apr 2019 11:10:41 +1300 Subject: [PATCH 3/4] netcmd: Add some timestamp conversion helper functions BUG: https://bugzilla.samba.org/show_bug.cgi?id=13873 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett (cherry picked from commit 940306a24a8d14fbb8c76c5a60b3d5f2773873a0) --- python/samba/netcmd/domain.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py index d7889e6..de7d141 100644 --- a/python/samba/netcmd/domain.py +++ b/python/samba/netcmd/domain.py @@ -1258,6 +1258,22 @@ class cmd_domain_level(Command): NEVER_TIMESTAMP = int(-0x8000000000000000) +def timestamp_to_mins(timestamp_str): + """Converts a timestamp in -100 nanosecond units to minutes""" + # treat a timestamp of 'never' the same as zero (this should work OK for + # most settings, and it displays better than trying to convert + # -0x8000000000000000 to minutes) + if int(timestamp_str) == NEVER_TIMESTAMP: + return 0 + else: + return abs(int(timestamp_str)) / (1e7 * 60) + + +def timestamp_to_days(timestamp_str): + """Converts a timestamp in -100 nanosecond units to days""" + return timestamp_to_mins(timestamp_str) / (60 * 24) + + class cmd_domain_passwordsettings_show(Command): """Display current password settings for the domain.""" @@ -1292,18 +1308,14 @@ class cmd_domain_passwordsettings_show(Command): pwd_hist_len = int(res[0]["pwdHistoryLength"][0]) cur_min_pwd_len = int(res[0]["minPwdLength"][0]) # ticks -> days - cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24)) - if int(res[0]["maxPwdAge"][0]) == NEVER_TIMESTAMP: - cur_max_pwd_age = 0 - else: - cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24)) + cur_min_pwd_age = timestamp_to_days(res[0]["minPwdAge"][0]) + cur_max_pwd_age = timestamp_to_days(res[0]["maxPwdAge"][0]) + cur_account_lockout_threshold = int(res[0]["lockoutThreshold"][0]) + # ticks -> mins - if int(res[0]["lockoutDuration"][0]) == NEVER_TIMESTAMP: - cur_account_lockout_duration = 0 - else: - cur_account_lockout_duration = abs(int(res[0]["lockoutDuration"][0])) / (1e7 * 60) - cur_reset_account_lockout_after = abs(int(res[0]["lockOutObservationWindow"][0])) / (1e7 * 60) + cur_account_lockout_duration = timestamp_to_mins(res[0]["lockoutDuration"][0]) + cur_reset_account_lockout_after = timestamp_to_mins(res[0]["lockOutObservationWindow"][0]) except Exception as e: raise CommandError("Could not retrieve password properties!", e) -- 2.7.4 From f338f1af90c2e1cb852911e7c4a95511c83d0167 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Wed, 3 Apr 2019 09:10:55 +1300 Subject: [PATCH 4/4] netcmd: Fix passwordsettings --max-pwd-age command The min_pwd_age and max_pwd_age parameters are both optional and default to None. However, if we just set the max-pwd-age, then the check 'min_pwd_age >= max_pwd_age' will throw a Python exception because it's trying to compare an int to NoneType (min_pwd_age). This works on Python 2 but is a problem on Python 3. We could just add a check that min_pwd_age is not None, but that defeats the point of having the check if you're only setting either the min or max age indepedently. This patch gets the current min/max password age from the DB (in ticks). If either setting is changed, the ticks will be updated. Then at the end we check the min is still less than the max (to do this, we convert the ticks back to days in the interests of readability). BUG: https://bugzilla.samba.org/show_bug.cgi?id=13873 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Fri Apr 5 08:03:08 UTC 2019 on sn-devel-144 (cherry picked from commit 7a410ccb5f6f2958d56fa6f16d8780c69a3830dd) --- python/samba/netcmd/domain.py | 14 ++++++++++++-- selftest/knownfail.d/passwordsettings | 1 - 2 files changed, 12 insertions(+), 3 deletions(-) delete mode 100644 selftest/knownfail.d/passwordsettings diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py index de7d141..8ebaefa 100644 --- a/python/samba/netcmd/domain.py +++ b/python/samba/netcmd/domain.py @@ -1397,6 +1397,10 @@ class cmd_domain_passwordsettings_set(Command): m.dn = ldb.Dn(samdb, domain_dn) pwd_props = int(samdb.get_pwdProperties()) + # get the current password age settings + max_pwd_age_ticks = samdb.get_maxPwdAge() + min_pwd_age_ticks = samdb.get_minPwdAge() + if complexity is not None: if complexity == "on" or complexity == "default": pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX @@ -1526,8 +1530,14 @@ class cmd_domain_passwordsettings_set(Command): ldb.FLAG_MOD_REPLACE, "lockOutObservationWindow") msgs.append("Duration to reset account lockout after changed!") - if max_pwd_age and max_pwd_age > 0 and min_pwd_age >= max_pwd_age: - raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age)) + if max_pwd_age or min_pwd_age: + # If we're setting either min or max password, make sure the max is + # still greater overall. As either setting could be None, we use the + # ticks here (which are always set) and work backwards. + max_pwd_age = timestamp_to_days(max_pwd_age_ticks) + min_pwd_age = timestamp_to_days(min_pwd_age_ticks) + if max_pwd_age != 0 and min_pwd_age >= max_pwd_age: + raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age)) if len(m) == 0: raise CommandError("You must specify at least one option to set. Try --help") diff --git a/selftest/knownfail.d/passwordsettings b/selftest/knownfail.d/passwordsettings deleted file mode 100644 index 8e94cef..0000000 --- a/selftest/knownfail.d/passwordsettings +++ /dev/null @@ -1 +0,0 @@ -samba.tests.samba_tool.passwordsettings.samba.tests.samba_tool.passwordsettings.PwdSettingsCmdTestCase.test_domain_passwordsettings_pwdage\(ad_dc_default:local\) -- 2.7.4