[SCM] Samba Shared Repository - branch master updated
Garming Sam
garming at samba.org
Fri May 11 07:07:02 UTC 2018
The branch, master has been updated
via 569937b tests: Add tests for samba-tool passwordsettings commands
via 7255e0c netcmd: Split 'domain passwordsettings' into a super-command
via 0da9dbb netcmd: Small tweak to retrieving pwdProperties
via 8a105af dsdb: Split out construct_generic_token_groups() so we can reuse it
via fcdb935 dsdb: Use attribute-name parameter for error message
via 823dec9 tests: Add a test case for msDS-PasswordReversibleEncryptionEnabled
via 17d8d47 tests: Add test for password-lockout via SAMR RPC
via f94f472 tests: Add PSO test case to existing password_lockout tests
via f5d67c1 tests: Add comments to help explain password_lockout tests
via 78ebfcf tests: Add tests for Password Settings Objects
via d0a9e19 tests: Split out setUp code into separate function for reuse
via 5974289 tests: Move repeated code into a helper function
from b07b4e4 loadparm: Remove unused realm_original
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 569937b8008ea8b64b4e3ead61ebc97c6c41f6b6
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu May 10 16:22:06 2018 +1200
tests: Add tests for samba-tool passwordsettings commands
I've added a test case for 'samba-tool domain passwordsettings set/show'
to prove I haven't broken it. It's behaviour shouldn't have changed, but
there was no test for it previously.
We'll extend these tests in the very near future, when we add samba-tool
support for managing PSOs.
The base samba_tool test's runsubcmd() only handled commands with
exactly one sub-command, i.e. it would handle the command 'samba-tool
domain passwordsettings' OK, but not 'samba-tool domain passwordsettings
set' (The command still seemed to run OK, but you wouldn't get the
output/err back correctly). A new runsublevelcmd() function now handles
a varying number of sub-commands.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
Autobuild-User(master): Garming Sam <garming at samba.org>
Autobuild-Date(master): Fri May 11 09:06:10 CEST 2018 on sn-devel-144
commit 7255e0ced33826d1e528c3e465105e7e194eb36e
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu May 3 12:12:04 2018 +1200
netcmd: Split 'domain passwordsettings' into a super-command
The show and set options are not really related to each other at all, so
it makes sense to split the code into 2 separate commands.
We also want to add separate sub-commands for PSOs in a subsequent
patch.
Because of the way the sub-command was implemented previously, it meant
that you could specify other command-line options before the 'set' or
'show' keyword, and the command would still be accepted. However, now
that it's a super-command 'set'/'show' needs to be specified before any
additional arguments, so we need to update the test code to reflect
this.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 0da9dbbf5a762f0953f1860b8b04810d33557094
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu May 3 11:48:21 2018 +1200
netcmd: Small tweak to retrieving pwdProperties
Currently the 'samba-tool domain passwordsettings' command shares a
'set' and 'show' option, but there is very little common code between
the two. The only variable that's shared is pwd_props, but there's a
separate API we can use to get this. This allows us to split the command
into a super-command in a subsequent patch.
Fixed up erroneous comments while I'm at it.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 8a105af76c3d432505e0a503cd32feb3808df59a
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu Apr 5 10:51:42 2018 +1200
dsdb: Split out construct_generic_token_groups() so we can reuse it
construct_generic_token_groups() currently works out the entire group
membership for a user, including the primaryGroupID. We want to do the
exact same thing for the msDS-ResultantPSO constructed attribute.
However, construct_generic_token_groups() currently adds the resulting
SIDs to the LDB search result, which we don't want to do for
msDS-ResultantPSO.
This patch splits the bulk of the group SID calculation work out into
a separate function that we can reuse for msDS-ResultantPSO. basically
this is just a straight move of the existing code. The only real change
is the TALLOC_CTX is renamed (tmp_ctx --> mem_ctx) and now passed into
the new function (so freeing it if an error conditions is hit is now
done in the caller).
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit fcdb935e3749cab5bc7dcbb83414032c683640ef
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu Apr 5 10:40:03 2018 +1200
dsdb: Use attribute-name parameter for error message
We'll reuse this code for working out the msDS-ResultantPSO, so
references to 'tokenGroups' in error messages would be misleading.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 823dec9d166b3fbe2caacdb699173601603c1101
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Mon May 7 17:33:51 2018 +1200
tests: Add a test case for msDS-PasswordReversibleEncryptionEnabled
Add a test for the 'msDS-PasswordReversibleEncryptionEnabled' attribute
on the PSO. The Effective-PasswordReversibleEncryptionEnabled is
based on the PSO setting (if one applies) or else the
DOMAIN_PASSWORD_STORE_CLEARTEXT bit for the domain's pwdProperties.
This indicates whether the user's cleartext password is to be stored
in the supplementalCredentials attribute (as 'Primary:CLEARTEXT').
The password_hash tests already text the cleartext behaviour, so I've
added an additional test case for PSOs. Note that supplementary-
credential information is not returned over LDAP (the password_hash
test uses a local LDB connection), so it made more sense to extend
the password_hash tests than to check this behaviour as part of the
PSO tests (i.e. rather than in password_settings.py).
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 17d8d475e5376a3c1a313c99cd988b0d1180c5e2
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Fri Apr 20 12:50:00 2018 +1200
tests: Add test for password-lockout via SAMR RPC
The existing password_lockout tests didn't check for changing the
password via the SAMR password_change RPC. This patch adds a test-case
for this, using the default domain lockout settings (which passes), and
then repeats the same test using a PSO (which fails).
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit f94f472830d684683f2769d83ad1205720a3029d
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Mon Mar 19 12:56:14 2018 +1300
tests: Add PSO test case to existing password_lockout tests
This checks that the lockout settings of the PSO take effect when one is
applied to a user. Import the password_settings code to create/apply a
PSO with the same lockout settings that the test cases normally use.
Then update the global settings so that the default lockout settings are
wildly different (i.e. so the test fails if the default lockout settings
get used instead of the PSO's).
As the password-lockout tests are quite slow, I've selected test cases
that should provide sufficient PSO coverage (rather than repeat every
single password-lockout test case in its entirety).
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit f5d67c10c02b9f5023cb58914cbb1af193846178
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Wed Apr 11 12:40:59 2018 +1200
tests: Add comments to help explain password_lockout tests
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 78ebfcfa862ba05d18305be07192837681c841cb
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Mon Mar 12 15:22:24 2018 +1300
tests: Add tests for Password Settings Objects
a.k.a Fine-Grained Password Policies
These tests currently all run and pass gainst Windows, but fail against
Samba. (Actually, the permissions test case passes against Samba,
presumably because it's enforced by the Schema permissions).
Two helper classes have been added:
- PasswordSettings: creates a PSO object and tracks its values.
- TestUser: creates a user and tracks its password history
This allows other existing tests (e.g. password_lockout, password_hash)
to easily be extended to also cover PSOs.
Most test cases use assert_PSO_applied(), which asserts:
- the correct msDS-ResultantPSO attribute is returned
- the PSO's min-password-length, complexity, and password-history
settings are correctly enforced (this has been temporarily been hobbled
until the basic constructed-attribute support is working).
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit d0a9e19114cfdaa9cd083e46d51f9e5de9e907e5
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Fri May 11 11:03:03 2018 +1200
tests: Split out setUp code into separate function for reuse
Any test that wants to change a password has to set the dSHeuristics
and minPwdAge first in order for the password change to work. The code
that does this is duplicated in several tests. This patch splits it out
into a static method so that the code can be reused rather than
duplicated.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
commit 597428943b1b77267243dc69ecea6fda8dfc3163
Author: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu Mar 15 12:44:30 2018 +1300
tests: Move repeated code into a helper function
Several tests hang all the objects they create off a unique OU.
Having a common OU makes cleanup easier, and having a unique OU (i.e.
adding some randomness) helps protect against one-off test failures
(Replication between testenvs is happening in the background.
Occasionally, when a test finishes on one testenv and moves onto the
next testenv, that testenv may have received the replicated test
objects from the first testenv, but has not received their deletion
yet).
Rather than copy-n-pasting this code yet again, split it out into a
helper function.
Reviewed-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
-----------------------------------------------------------------------
Summary of changes:
python/samba/netcmd/domain.py | 355 ++++-----
python/samba/tests/__init__.py | 13 +
python/samba/tests/auth_log_pass_change.py | 20 +-
python/samba/tests/password_hash.py | 40 +-
python/samba/tests/password_hash_gpgme.py | 67 +-
python/samba/tests/password_test.py | 60 ++
python/samba/tests/pso.py | 271 +++++++
python/samba/tests/samba_tool/base.py | 17 +
python/samba/tests/samba_tool/passwordsettings.py | 70 ++
selftest/knownfail.d/password_hash_gpgme | 2 +
selftest/knownfail.d/password_lockout | 6 +
selftest/knownfail.d/password_settings | 9 +
source4/dsdb/samdb/ldb_modules/operational.c | 104 +--
source4/dsdb/tests/python/acl.py | 16 +-
source4/dsdb/tests/python/password_lockout.py | 175 +++++
source4/dsdb/tests/python/password_lockout_base.py | 60 +-
source4/dsdb/tests/python/password_settings.py | 802 +++++++++++++++++++++
source4/dsdb/tests/python/passwords.py | 22 +-
source4/dsdb/tests/python/tombstone_reanimation.py | 16 +-
source4/selftest/tests.py | 6 +
source4/setup/tests/blackbox_setpassword.sh | 2 +-
source4/torture/drs/python/getncchanges.py | 9 +-
source4/torture/drs/python/link_conflicts.py | 9 +-
source4/torture/drs/python/repl_rodc.py | 10 +-
testprogs/blackbox/test_kinit_heimdal.sh | 4 +-
testprogs/blackbox/test_kinit_mit.sh | 4 +-
testprogs/blackbox/test_kpasswd_heimdal.sh | 4 +-
testprogs/blackbox/test_kpasswd_mit.sh | 4 +-
testprogs/blackbox/test_password_settings.sh | 10 +-
29 files changed, 1814 insertions(+), 373 deletions(-)
create mode 100644 python/samba/tests/password_test.py
create mode 100644 python/samba/tests/pso.py
create mode 100644 python/samba/tests/samba_tool/passwordsettings.py
create mode 100644 selftest/knownfail.d/password_hash_gpgme
create mode 100644 selftest/knownfail.d/password_lockout
create mode 100644 selftest/knownfail.d/password_settings
create mode 100644 source4/dsdb/tests/python/password_settings.py
Changeset truncated at 500 lines:
diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index da61711..cb2b1cc 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -1263,8 +1263,74 @@ class cmd_domain_level(Command):
else:
raise CommandError("invalid argument: '%s' (choose from 'show', 'raise')" % subcommand)
+class cmd_domain_passwordsettings_show(Command):
+ """Display current password settings for the domain."""
-class cmd_domain_passwordsettings(Command):
+ synopsis = "%prog [options]"
+
+ takes_optiongroups = {
+ "sambaopts": options.SambaOptions,
+ "versionopts": options.VersionOptions,
+ "credopts": options.CredentialsOptions,
+ }
+
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+ metavar="URL", dest="H"),
+ ]
+
+ def run(self, H=None, credopts=None, sambaopts=None, versionopts=None):
+ lp = sambaopts.get_loadparm()
+ creds = credopts.get_credentials(lp)
+
+ samdb = SamDB(url=H, session_info=system_session(),
+ credentials=creds, lp=lp)
+
+ domain_dn = samdb.domain_dn()
+ res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
+ attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
+ "minPwdAge", "maxPwdAge", "lockoutDuration", "lockoutThreshold",
+ "lockOutObservationWindow"])
+ assert(len(res) == 1)
+ try:
+ pwd_props = int(res[0]["pwdProperties"][0])
+ 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]) == -0x8000000000000000:
+ 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:
+ 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)
+ except Exception as e:
+ raise CommandError("Could not retrieve password properties!", e)
+
+ self.message("Password informations for domain '%s'" % domain_dn)
+ self.message("")
+ if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
+ self.message("Password complexity: on")
+ else:
+ self.message("Password complexity: off")
+ if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0:
+ self.message("Store plaintext passwords: on")
+ else:
+ self.message("Store plaintext passwords: off")
+ self.message("Password history length: %d" % pwd_hist_len)
+ self.message("Minimum password length: %d" % cur_min_pwd_len)
+ self.message("Minimum password age (days): %d" % cur_min_pwd_age)
+ self.message("Maximum password age (days): %d" % cur_max_pwd_age)
+ self.message("Account lockout duration (mins): %d" % cur_account_lockout_duration)
+ self.message("Account lockout threshold (attempts): %d" % cur_account_lockout_threshold)
+ self.message("Reset account lockout after (mins): %d" % cur_reset_account_lockout_after)
+
+class cmd_domain_passwordsettings_set(Command):
"""Set password settings.
Password complexity, password lockout policy, history length,
@@ -1274,7 +1340,7 @@ class cmd_domain_passwordsettings(Command):
Use against a Windows DC is possible, but group policy will override it.
"""
- synopsis = "%prog (show|set <options>) [options]"
+ synopsis = "%prog <options> [options]"
takes_optiongroups = {
"sambaopts": options.SambaOptions,
@@ -1306,9 +1372,7 @@ class cmd_domain_passwordsettings(Command):
help="After this time is elapsed, the recorded number of attempts restarts from zero (<integer> | default). Default is 30.", type=str),
]
- takes_args = ["subcommand"]
-
- def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None,
+ def run(self, H=None, min_pwd_age=None, max_pwd_age=None,
quiet=False, complexity=None, store_plaintext=None, history_length=None,
min_pwd_length=None, account_lockout_duration=None, account_lockout_threshold=None,
reset_account_lockout_after=None, credopts=None, sambaopts=None,
@@ -1320,194 +1384,155 @@ class cmd_domain_passwordsettings(Command):
credentials=creds, lp=lp)
domain_dn = samdb.domain_dn()
- res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
- attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
- "minPwdAge", "maxPwdAge", "lockoutDuration", "lockoutThreshold",
- "lockOutObservationWindow"])
- assert(len(res) == 1)
- try:
- pwd_props = int(res[0]["pwdProperties"][0])
- 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]) == -0x8000000000000000:
- cur_max_pwd_age = 0
+ msgs = []
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, domain_dn)
+ pwd_props = int(samdb.get_pwdProperties())
+
+ if complexity is not None:
+ if complexity == "on" or complexity == "default":
+ pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
+ msgs.append("Password complexity activated!")
+ elif complexity == "off":
+ pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
+ msgs.append("Password complexity deactivated!")
+
+ if store_plaintext is not None:
+ if store_plaintext == "on" or store_plaintext == "default":
+ pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
+ msgs.append("Plaintext password storage for changed passwords activated!")
+ elif store_plaintext == "off":
+ pwd_props = pwd_props & (~DOMAIN_PASSWORD_STORE_CLEARTEXT)
+ msgs.append("Plaintext password storage for changed passwords deactivated!")
+
+ if complexity is not None or store_plaintext is not None:
+ m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
+ ldb.FLAG_MOD_REPLACE, "pwdProperties")
+
+ if history_length is not None:
+ if history_length == "default":
+ pwd_hist_len = 24
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:
- 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)
- except Exception as e:
- raise CommandError("Could not retrieve password properties!", e)
+ pwd_hist_len = int(history_length)
- if subcommand == "show":
- self.message("Password informations for domain '%s'" % domain_dn)
- self.message("")
- if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
- self.message("Password complexity: on")
- else:
- self.message("Password complexity: off")
- if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0:
- self.message("Store plaintext passwords: on")
- else:
- self.message("Store plaintext passwords: off")
- self.message("Password history length: %d" % pwd_hist_len)
- self.message("Minimum password length: %d" % cur_min_pwd_len)
- self.message("Minimum password age (days): %d" % cur_min_pwd_age)
- self.message("Maximum password age (days): %d" % cur_max_pwd_age)
- self.message("Account lockout duration (mins): %d" % cur_account_lockout_duration)
- self.message("Account lockout threshold (attempts): %d" % cur_account_lockout_threshold)
- self.message("Reset account lockout after (mins): %d" % cur_reset_account_lockout_after)
- elif subcommand == "set":
- msgs = []
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
-
- if complexity is not None:
- if complexity == "on" or complexity == "default":
- pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
- msgs.append("Password complexity activated!")
- elif complexity == "off":
- pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
- msgs.append("Password complexity deactivated!")
-
- if store_plaintext is not None:
- if store_plaintext == "on" or store_plaintext == "default":
- pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
- msgs.append("Plaintext password storage for changed passwords activated!")
- elif store_plaintext == "off":
- pwd_props = pwd_props & (~DOMAIN_PASSWORD_STORE_CLEARTEXT)
- msgs.append("Plaintext password storage for changed passwords deactivated!")
-
- if complexity is not None or store_plaintext is not None:
- m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
- ldb.FLAG_MOD_REPLACE, "pwdProperties")
-
- if history_length is not None:
- if history_length == "default":
- pwd_hist_len = 24
- else:
- pwd_hist_len = int(history_length)
+ if pwd_hist_len < 0 or pwd_hist_len > 24:
+ raise CommandError("Password history length must be in the range of 0 to 24!")
- if pwd_hist_len < 0 or pwd_hist_len > 24:
- raise CommandError("Password history length must be in the range of 0 to 24!")
+ m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
+ ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
+ msgs.append("Password history length changed!")
- m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
- ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
- msgs.append("Password history length changed!")
+ if min_pwd_length is not None:
+ if min_pwd_length == "default":
+ min_pwd_len = 7
+ else:
+ min_pwd_len = int(min_pwd_length)
- if min_pwd_length is not None:
- if min_pwd_length == "default":
- min_pwd_len = 7
- else:
- min_pwd_len = int(min_pwd_length)
+ if min_pwd_len < 0 or min_pwd_len > 14:
+ raise CommandError("Minimum password length must be in the range of 0 to 14!")
- if min_pwd_len < 0 or min_pwd_len > 14:
- raise CommandError("Minimum password length must be in the range of 0 to 14!")
+ m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
+ ldb.FLAG_MOD_REPLACE, "minPwdLength")
+ msgs.append("Minimum password length changed!")
- m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
- ldb.FLAG_MOD_REPLACE, "minPwdLength")
- msgs.append("Minimum password length changed!")
+ if min_pwd_age is not None:
+ if min_pwd_age == "default":
+ min_pwd_age = 1
+ else:
+ min_pwd_age = int(min_pwd_age)
- if min_pwd_age is not None:
- if min_pwd_age == "default":
- min_pwd_age = 1
- else:
- min_pwd_age = int(min_pwd_age)
+ if min_pwd_age < 0 or min_pwd_age > 998:
+ raise CommandError("Minimum password age must be in the range of 0 to 998!")
- if min_pwd_age < 0 or min_pwd_age > 998:
- raise CommandError("Minimum password age must be in the range of 0 to 998!")
+ # days -> ticks
+ min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
- # days -> ticks
- min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
+ m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
+ ldb.FLAG_MOD_REPLACE, "minPwdAge")
+ msgs.append("Minimum password age changed!")
- m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "minPwdAge")
- msgs.append("Minimum password age changed!")
+ if max_pwd_age is not None:
+ if max_pwd_age == "default":
+ max_pwd_age = 43
+ else:
+ max_pwd_age = int(max_pwd_age)
- if max_pwd_age is not None:
- if max_pwd_age == "default":
- max_pwd_age = 43
- else:
- max_pwd_age = int(max_pwd_age)
+ if max_pwd_age < 0 or max_pwd_age > 999:
+ raise CommandError("Maximum password age must be in the range of 0 to 999!")
- if max_pwd_age < 0 or max_pwd_age > 999:
- raise CommandError("Maximum password age must be in the range of 0 to 999!")
+ # days -> ticks
+ if max_pwd_age == 0:
+ max_pwd_age_ticks = -0x8000000000000000
+ else:
+ max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
- # days -> ticks
- if max_pwd_age == 0:
- max_pwd_age_ticks = -0x8000000000000000
- else:
- max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
+ m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
+ ldb.FLAG_MOD_REPLACE, "maxPwdAge")
+ msgs.append("Maximum password age changed!")
- m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "maxPwdAge")
- msgs.append("Maximum password age changed!")
+ if account_lockout_duration is not None:
+ if account_lockout_duration == "default":
+ account_lockout_duration = 30
+ else:
+ account_lockout_duration = int(account_lockout_duration)
- if account_lockout_duration is not None:
- if account_lockout_duration == "default":
- account_lockout_duration = 30
- else:
- account_lockout_duration = int(account_lockout_duration)
+ if account_lockout_duration < 0 or account_lockout_duration > 99999:
+ raise CommandError("Maximum password age must be in the range of 0 to 99999!")
- if account_lockout_duration < 0 or account_lockout_duration > 99999:
- raise CommandError("Maximum password age must be in the range of 0 to 99999!")
+ # minutes -> ticks
+ if account_lockout_duration == 0:
+ account_lockout_duration_ticks = -0x8000000000000000
+ else:
+ account_lockout_duration_ticks = -int(account_lockout_duration * (60 * 1e7))
- # days -> ticks
- if account_lockout_duration == 0:
- account_lockout_duration_ticks = -0x8000000000000000
- else:
- account_lockout_duration_ticks = -int(account_lockout_duration * (60 * 1e7))
+ m["lockoutDuration"] = ldb.MessageElement(str(account_lockout_duration_ticks),
+ ldb.FLAG_MOD_REPLACE, "lockoutDuration")
+ msgs.append("Account lockout duration changed!")
- m["lockoutDuration"] = ldb.MessageElement(str(account_lockout_duration_ticks),
- ldb.FLAG_MOD_REPLACE, "lockoutDuration")
- msgs.append("Account lockout duration changed!")
+ if account_lockout_threshold is not None:
+ if account_lockout_threshold == "default":
+ account_lockout_threshold = 0
+ else:
+ account_lockout_threshold = int(account_lockout_threshold)
- if account_lockout_threshold is not None:
- if account_lockout_threshold == "default":
- account_lockout_threshold = 0
- else:
- account_lockout_threshold = int(account_lockout_threshold)
+ m["lockoutThreshold"] = ldb.MessageElement(str(account_lockout_threshold),
+ ldb.FLAG_MOD_REPLACE, "lockoutThreshold")
+ msgs.append("Account lockout threshold changed!")
- m["lockoutThreshold"] = ldb.MessageElement(str(account_lockout_threshold),
- ldb.FLAG_MOD_REPLACE, "lockoutThreshold")
- msgs.append("Account lockout threshold changed!")
+ if reset_account_lockout_after is not None:
+ if reset_account_lockout_after == "default":
+ reset_account_lockout_after = 30
+ else:
+ reset_account_lockout_after = int(reset_account_lockout_after)
- if reset_account_lockout_after is not None:
- if reset_account_lockout_after == "default":
- reset_account_lockout_after = 30
- else:
- reset_account_lockout_after = int(reset_account_lockout_after)
+ if reset_account_lockout_after < 0 or reset_account_lockout_after > 99999:
+ raise CommandError("Maximum password age must be in the range of 0 to 99999!")
- if reset_account_lockout_after < 0 or reset_account_lockout_after > 99999:
- raise CommandError("Maximum password age must be in the range of 0 to 99999!")
+ # minutes -> ticks
+ if reset_account_lockout_after == 0:
+ reset_account_lockout_after_ticks = -0x8000000000000000
+ else:
+ reset_account_lockout_after_ticks = -int(reset_account_lockout_after * (60 * 1e7))
- # days -> ticks
- if reset_account_lockout_after == 0:
- reset_account_lockout_after_ticks = -0x8000000000000000
- else:
- reset_account_lockout_after_ticks = -int(reset_account_lockout_after * (60 * 1e7))
+ m["lockOutObservationWindow"] = ldb.MessageElement(str(reset_account_lockout_after_ticks),
+ ldb.FLAG_MOD_REPLACE, "lockOutObservationWindow")
+ msgs.append("Duration to reset account lockout after changed!")
- m["lockOutObservationWindow"] = ldb.MessageElement(str(reset_account_lockout_after_ticks),
- ldb.FLAG_MOD_REPLACE, "lockOutObservationWindow")
- msgs.append("Duration to reset account lockout after changed!")
+ 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 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")
+ samdb.modify(m)
+ msgs.append("All changes applied successfully!")
+ self.message("\n".join(msgs))
- if len(m) == 0:
- raise CommandError("You must specify at least one option to set. Try --help")
- samdb.modify(m)
- msgs.append("All changes applied successfully!")
- self.message("\n".join(msgs))
- else:
- raise CommandError("Wrong argument '%s'!" % subcommand)
+class cmd_domain_passwordsettings(SuperCommand):
+ """Manage password policy settings."""
+ subcommands = {}
+ subcommands["show"] = cmd_domain_passwordsettings_show()
+ subcommands["set"] = cmd_domain_passwordsettings_set()
class cmd_domain_classicupgrade(Command):
"""Upgrade from Samba classic (NT4-like) database to Samba AD DC database.
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index bc8c185..61036b5 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -36,6 +36,7 @@ import re
import samba.auth
import samba.dcerpc.base
from samba.compat import PY3, text_type
+from random import randint
if not PY3:
# Py2 only
from samba.samdb import SamDB
@@ -475,3 +476,15 @@ def delete_force(samdb, dn, **kwargs):
except ldb.LdbError as error:
(num, errstr) = error.args
assert num == ldb.ERR_NO_SUCH_OBJECT, "ldb.delete() failed: %s" % errstr
+
+def create_test_ou(samdb, name):
+ """Creates a unique OU for the test"""
+
+ # Add some randomness to the test OU. Replication between the testenvs is
+ # constantly happening in the background. Deletion of the last test's
+ # objects can be slow to replicate out. So the OU created by a previous
+ # testenv may still exist at the point that tests start on another testenv.
+ rand = randint(1, 10000000)
+ dn = "OU=%s%d,%s" %(name, rand, samdb.get_default_basedn())
+ samdb.add({ "dn": dn, "objectclass": "organizationalUnit"})
+ return dn
diff --git a/python/samba/tests/auth_log_pass_change.py b/python/samba/tests/auth_log_pass_change.py
index 8890694..1bbb0ea 100644
--- a/python/samba/tests/auth_log_pass_change.py
+++ b/python/samba/tests/auth_log_pass_change.py
@@ -29,6 +29,7 @@ from samba.net import Net
import samba
from subprocess import call
from ldb import LdbError
+from samba.tests.password_test import PasswordCommon
USER_NAME = "authlogtestuser"
USER_PASS = samba.generate_random_password(32, 32)
@@ -53,26 +54,11 @@ class AuthLogPassChangeTests(samba.tests.auth_log_base.AuthLogTestBase):
base_dn = self.ldb.domain_dn()
print("base_dn %s" % base_dn)
- # Get the old "dSHeuristics" if it was set
- dsheuristics = self.ldb.get_dsheuristics()
+ # permit password changes during this test
+ PasswordCommon.allow_password_changes(self, self.ldb)
- # Set the "dSHeuristics" to activate the correct "userPassword"
- # behaviour
- self.ldb.set_dsheuristics("000000001")
-
- # Reset the "dSHeuristics" as they were before
- self.addCleanup(self.ldb.set_dsheuristics, dsheuristics)
-
- # Get the old "minPwdAge"
- minPwdAge = self.ldb.get_minPwdAge()
-
- # Set it temporarily to "0"
- self.ldb.set_minPwdAge("0")
self.base_dn = self.ldb.domain_dn()
- # Reset the "minPwdAge" as it was before
- self.addCleanup(self.ldb.set_minPwdAge, minPwdAge)
-
# (Re)adds the test user USER_NAME with password USER_PASS
delete_force(self.ldb, "cn=" + USER_NAME + ",cn=users," + self.base_dn)
self.ldb.add({
diff --git a/python/samba/tests/password_hash.py b/python/samba/tests/password_hash.py
index a3a74aa..4c4dbcf 100644
--- a/python/samba/tests/password_hash.py
+++ b/python/samba/tests/password_hash.py
@@ -29,6 +29,7 @@ from samba.dcerpc import drsblobs
from samba.dcerpc.samr import DOMAIN_PASSWORD_STORE_CLEARTEXT
from samba.dsdb import UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED
from samba.tests import delete_force
+from samba.tests.password_test import PasswordCommon
import ldb
import samba
import binascii
@@ -69,6 +70,17 @@ class PassWordHashTests(TestCase):
self.lp = samba.tests.env_loadparm()
super(PassWordHashTests, self).setUp()
--
Samba Shared Repository
More information about the samba-cvs
mailing list