summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2017-05-22 09:49:17 +1200
committerAndrew Bartlett <abartlet@samba.org>2017-05-25 02:25:12 +0200
commit64199090940cad9f3b4c3f5781426e61418dde9b (patch)
tree59c2b4c5151486a979136b8fa49c1b9483e8f5e9 /python
parent83fbd80b3f11f94dc00950c270daf9288148a658 (diff)
downloadsamba-64199090940cad9f3b4c3f5781426e61418dde9b.tar.gz
tests password_hash: Add ldap based tests for WDigest
Add tests of the WDigest values using ldap. This allows the tests to be run against Windows, to validate the calculated values. Tests validated against Windows Server 2012 R2 Signed-off-by: Gary Lockyer <gary@catalyst.net.nz> Reviewed-by: Garming Sam <garming@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'python')
-rw-r--r--python/samba/tests/password_hash.py67
-rw-r--r--python/samba/tests/password_hash_ldap.py132
2 files changed, 171 insertions, 28 deletions
diff --git a/python/samba/tests/password_hash.py b/python/samba/tests/password_hash.py
index 39744ffacce..611983e87ad 100644
--- a/python/samba/tests/password_hash.py
+++ b/python/samba/tests/password_hash.py
@@ -66,23 +66,34 @@ def calc_digest(user, realm, password):
class PassWordHashTests(TestCase):
def setUp(self):
+ self.lp = samba.tests.env_loadparm()
super(PassWordHashTests, self).setUp()
# Add a user to ldb, this will exercise the password_hash code
# and calculate the appropriate supplemental credentials
- def add_user(self, options=None, clear_text=False):
- self.lp = samba.tests.env_loadparm()
+ def add_user(self, options=None, clear_text=False, ldb=None):
# set any needed options
if options is not None:
for (option, value) in options:
self.lp.set(option, value)
- self.creds = Credentials()
- self.session = system_session()
- self.ldb = SamDB(
- session_info=self.session,
- credentials=self.creds,
- lp=self.lp)
+ if ldb is None:
+ self.creds = Credentials()
+ self.session = system_session()
+ self.creds.guess(self.lp)
+ self.session = system_session()
+ self.ldb = SamDB(session_info=self.session,
+ credentials=self.creds,
+ lp=self.lp)
+ else:
+ self.ldb = ldb
+
+ res = self.ldb.search(base=self.ldb.get_config_basedn(),
+ expression="ncName=%s" % self.ldb.get_default_basedn(),
+ attrs=["nETBIOSName"])
+ self.netbios_domain = res[0]["nETBIOSName"][0]
+ self.dns_domain = self.ldb.domain_dns_name()
+
# Gets back the basedn
base_dn = self.ldb.domain_dn()
@@ -164,59 +175,59 @@ class PassWordHashTests(TestCase):
# Using the n-1 pattern in the array indexes to make it easier
# to check the tests against the spec and the samba-tool user tests.
self.check_digest(USER_NAME,
- self.lp.get("workgroup"),
+ self.netbios_domain,
USER_PASS,
digests.hashes[1-1].hash)
self.check_digest(USER_NAME.lower(),
- self.lp.get("workgroup").lower(),
+ self.netbios_domain.lower(),
USER_PASS,
digests.hashes[2-1].hash)
self.check_digest(USER_NAME.upper(),
- self.lp.get("workgroup").upper(),
+ self.netbios_domain.upper(),
USER_PASS,
digests.hashes[3-1].hash)
self.check_digest(USER_NAME,
- self.lp.get("workgroup").upper(),
+ self.netbios_domain.upper(),
USER_PASS,
digests.hashes[4-1].hash)
self.check_digest(USER_NAME,
- self.lp.get("workgroup").lower(),
+ self.netbios_domain.lower(),
USER_PASS,
digests.hashes[5-1].hash)
self.check_digest(USER_NAME.upper(),
- self.lp.get("workgroup").lower(),
+ self.netbios_domain.lower(),
USER_PASS,
digests.hashes[6-1].hash)
self.check_digest(USER_NAME.lower(),
- self.lp.get("workgroup").upper(),
+ self.netbios_domain.upper(),
USER_PASS,
digests.hashes[7-1].hash)
self.check_digest(USER_NAME,
- self.lp.get("realm").lower(),
+ self.dns_domain,
USER_PASS,
digests.hashes[8-1].hash)
self.check_digest(USER_NAME.lower(),
- self.lp.get("realm").lower(),
+ self.dns_domain.lower(),
USER_PASS,
digests.hashes[9-1].hash)
self.check_digest(USER_NAME.upper(),
- self.lp.get("realm"),
+ self.dns_domain.upper(),
USER_PASS,
digests.hashes[10-1].hash)
self.check_digest(USER_NAME,
- self.lp.get("realm"),
+ self.dns_domain.upper(),
USER_PASS,
digests.hashes[11-1].hash)
self.check_digest(USER_NAME,
- self.lp.get("realm").lower(),
+ self.dns_domain.lower(),
USER_PASS,
digests.hashes[12-1].hash)
self.check_digest(USER_NAME.upper(),
- self.lp.get("realm").lower(),
+ self.dns_domain.lower(),
USER_PASS,
digests.hashes[13-1].hash)
self.check_digest(USER_NAME.lower(),
- self.lp.get("realm"),
+ self.dns_domain.upper(),
USER_PASS,
digests.hashes[14-1].hash)
self.check_digest(UPN,
@@ -232,19 +243,19 @@ class PassWordHashTests(TestCase):
USER_PASS,
digests.hashes[17-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup"), USER_NAME)
+ name = "%s\\%s" % (self.netbios_domain, USER_NAME)
self.check_digest(name,
"",
USER_PASS,
digests.hashes[18-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup").lower(), USER_NAME.lower())
+ name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower())
self.check_digest(name,
"",
USER_PASS,
digests.hashes[19-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup").upper(), USER_NAME.upper())
+ name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper())
self.check_digest(name,
"",
USER_PASS,
@@ -273,19 +284,19 @@ class PassWordHashTests(TestCase):
"Digest",
USER_PASS,
digests.hashes[26-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup"), USER_NAME)
+ name = "%s\\%s" % (self.netbios_domain, USER_NAME)
self.check_digest(name,
"Digest",
USER_PASS,
digests.hashes[27-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup").lower(), USER_NAME.lower())
+ name = "%s\\%s" % (self.netbios_domain.lower(), USER_NAME.lower())
self.check_digest(name,
"Digest",
USER_PASS,
digests.hashes[28-1].hash)
- name = "%s\\%s" % (self.lp.get("workgroup").upper(), USER_NAME.upper())
+ name = "%s\\%s" % (self.netbios_domain.upper(), USER_NAME.upper())
self.check_digest(name,
"Digest",
USER_PASS,
diff --git a/python/samba/tests/password_hash_ldap.py b/python/samba/tests/password_hash_ldap.py
new file mode 100644
index 00000000000..c2c0f781628
--- /dev/null
+++ b/python/samba/tests/password_hash_ldap.py
@@ -0,0 +1,132 @@
+# Tests for Tests for source4/dsdb/samdb/ldb_modules/password_hash.c
+#
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+#
+# 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Tests for source4/dsdb/samdb/ldb_modules/password_hash.c
+
+These tests are designed to also run against Windows to confirm the values
+returned from Windows.
+
+To run against Windows:
+Set the following environment variables:
+ PASSWORD=Administrator password
+ USERNAME=Administrator
+ SMB_CONF_PATH=/dev/null
+ PYTHONPATH=bin/python
+ SERVER=Windows server IP
+
+ /usr/bin/python source4/scripting/bin/subunitrun
+ samba.tests.password_hash_ldap.PassWordHashLDAPTests
+ -U"Administrator%adminpassword"
+"""
+
+from samba.tests.password_hash import (
+ PassWordHashTests,
+ get_package,
+ USER_NAME,
+ USER_PASS
+)
+from samba.samdb import SamDB
+from samba.ndr import ndr_unpack
+from samba.dcerpc import drsblobs, drsuapi, misc
+from samba import drs_utils, net
+from samba.credentials import Credentials
+import binascii
+import os
+
+def attid_equal(a1, a2):
+ return (a1 & 0xffffffff) == (a2 & 0xffffffff)
+
+class PassWordHashLDAPTests(PassWordHashTests):
+
+ def setUp(self):
+ super(PassWordHashLDAPTests, self).setUp()
+
+ # Get the supplemental credentials for the user under test
+ def get_supplemental_creds_drs(self):
+ binding_str = "ncacn_ip_tcp:%s[seal]" % os.environ["SERVER"]
+ dn = "cn=" + USER_NAME + ",cn=users," + self.base_dn
+ drs = drsuapi.drsuapi(binding_str, self.get_loadparm(), self.creds)
+ (drs_handle, supported_extensions) = drs_utils.drs_DsBind(drs)
+
+ req8 = drsuapi.DsGetNCChangesRequest8()
+
+ null_guid = misc.GUID()
+ req8.destination_dsa_guid = null_guid
+ req8.source_dsa_invocation_id = null_guid
+ req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
+ req8.naming_context.dn = unicode(dn)
+
+ req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
+ req8.highwatermark.tmp_highest_usn = 0
+ req8.highwatermark.reserved_usn = 0
+ req8.highwatermark.highest_usn = 0
+ req8.uptodateness_vector = None
+ req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
+ drsuapi.DRSUAPI_DRS_PER_SYNC |
+ drsuapi.DRSUAPI_DRS_GET_ANC |
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED |
+ drsuapi.DRSUAPI_DRS_WRIT_REP)
+ req8.max_object_count = 402
+ req8.max_ndr_size = 402116
+ req8.extended_op = drsuapi.DRSUAPI_EXOP_REPL_OBJ
+ req8.fsmo_info = 0
+ req8.partial_attribute_set = None
+ req8.partial_attribute_set_ex = None
+ req8.mapping_ctr.num_mappings = 0
+ req8.mapping_ctr.mappings = None
+ (level, ctr) = drs.DsGetNCChanges(drs_handle, 8, req8)
+
+ obj_item = ctr.first_object
+ obj = obj_item.object
+
+ sc_blob = None
+
+ for i in range(0, obj.attribute_ctr.num_attributes):
+ attr = obj.attribute_ctr.attributes[i]
+ if attid_equal(attr.attid,
+ drsuapi.DRSUAPI_ATTID_supplementalCredentials):
+ net_ctx = net.Net(self.creds)
+ net_ctx.replicate_decrypt(drs, attr, 0)
+ sc_blob = attr.value_ctr.values[0].blob
+
+
+ sc = ndr_unpack(drsblobs.supplementalCredentialsBlob, sc_blob)
+ return sc
+
+ def test_wDigest_supplementalCredentials(self):
+ self.creds = Credentials()
+ self.creds.set_username(os.environ["USERNAME"])
+ self.creds.set_password(os.environ["PASSWORD"])
+ self.creds.guess(self.lp)
+ ldb = SamDB("ldap://" + os.environ["SERVER"],
+ credentials=self.creds,
+ lp=self.lp)
+
+ self.add_user(ldb=ldb)
+
+ sc = self.get_supplemental_creds_drs()
+
+ (pos, package) = get_package(sc, "Primary:WDigest")
+ self.assertEquals("Primary:WDigest", package.name)
+
+ # Check that the WDigest values are correct.
+ #
+ digests = ndr_unpack(drsblobs.package_PrimaryWDigestBlob,
+ binascii.a2b_hex(package.data))
+ self.check_wdigests(digests)