1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-22 22:04:08 +03:00

samba-tool add support for userPassword

Changes to virtualCryptSHA256 and virtualCryptSHA512 attributes.
The values are now calculated as follows:
  1) If a value exists in 'Primary:userPassword' with
     the specified number of rounds it is returned.
  2) If 'Primary:CLEARTEXT, or 'Primary:SambaGPG' with
     '--decrypt-samba-gpg'. Calculate a hash with the specified number of rounds
  3) Return the first {CRYPT} value in 'Primary:userPassword' with a
     matching algorithm

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Gary Lockyer 2017-05-15 12:19:22 +12:00 committed by Andrew Bartlett
parent 8a5308bea0
commit b14bb68417
2 changed files with 88 additions and 30 deletions

View File

@ -1157,21 +1157,62 @@ class GetPasswordCommand(Command):
except IndexError:
return None
def get_userPassword_hash(blob, scheme, prefix):
# get the value for a virtualCrypt attribute.
# look for an exact match on algorithm and rounds in supplemental creds
# if not found calculate using Primary:CLEARTEXT
# if no Primary:CLEARTEXT return the first supplementalCredential
# that matches the algorithm.
def get_virtual_crypt_value(a, algorithm, rounds, username, account_name):
sv = None
fb = None
b = get_package("Primary:userPassword")
if b is not None:
(sv, fb) = get_userPassword_hash(b, algorithm, rounds)
if sv is None:
# No exact match on algorithm and number of rounds
# try and calculate one from the Primary:CLEARTEXT
b = get_package("Primary:CLEARTEXT")
if b is not None:
u8 = get_utf8(a, b, username or account_name)
if u8 is not None:
sv = get_crypt_value(str(algorithm), u8, rounds)
if sv is None:
# Unable to calculate a hash with the specified
# number of rounds, fall back to the first hash using
# the specified algorithm
sv = fb
if sv is None:
return None
return "{CRYPT}" + sv
def get_userPassword_hash(blob, algorithm, rounds):
up = ndr_unpack(drsblobs.package_PrimaryUserPasswordBlob, blob)
SCHEME = "{CRYPT}"
# Check that the NT hash has not been changed without updating
# the user password hashes.
# the user password hashes. This indicates that password has been
# changed without updating the supplemental credentials.
if unicodePwd != bytearray(up.current_nt_hash.hash):
return None
scheme_prefix = "$%d$" % algorithm
prefix = scheme_prefix
if rounds > 0:
prefix = "$%d$rounds=%d" % (algorithm, rounds)
scheme_match = None
# Return the first hash that matches scheme
for h in up.hashes:
if h.scheme == scheme and h.value.startswith(prefix):
return h.value
if (scheme_match is None and
h.scheme == SCHEME and
h.value.startswith(scheme_prefix)):
scheme_match = h.value
if h.scheme == SCHEME and h.value.startswith(prefix):
return (h.value, scheme_match)
return None
# No match on the number of rounds, return the value of the
# first matching scheme
return (None, scheme_match)
# We use sort here in order to have a predictable processing order
for a in sorted(virtual_attributes.keys()):
@ -1204,25 +1245,17 @@ class GetPasswordCommand(Command):
bv = h.digest() + salt
v = "{SSHA}" + base64.b64encode(bv)
elif a == "virtualCryptSHA256":
b = get_package("Primary:CLEARTEXT")
if b is None:
continue
u8 = get_utf8(a, b, username or account_name)
if u8 is None:
continue
rounds = get_rounds(attr_opts[a])
sv = get_crypt_value("5", u8, rounds)
v = "{CRYPT}" + sv
x = get_virtual_crypt_value(a, 5, rounds, username, account_name)
if x is None:
continue
v = x
elif a == "virtualCryptSHA512":
b = get_package("Primary:CLEARTEXT")
if b is None:
continue
u8 = get_utf8(a, b, username or account_name)
if u8 is None:
continue
rounds = get_rounds(attr_opts[a])
sv = get_crypt_value("6", u8, rounds)
v = "{CRYPT}" + sv
x = get_virtual_crypt_value(a, 6, rounds, username, account_name)
if x is None:
continue
v = x
elif a == "virtualSambaGPG":
# Samba adds 'Primary:SambaGPG' at the end.
# When Windows sets the password it keeps
@ -1313,6 +1346,15 @@ for which virtual attributes are supported in your environment):
attribute name i.e. virtualCryptSHA256;rounds=10000
will calculate a SHA256 hash with 10,000 rounds.
non numeric values for rounds are silently ignored
The value is calculated as follows:
1) If a value exists in 'Primary:userPassword' with
the specified number of rounds it is returned.
2) If 'Primary:CLEARTEXT, or 'Primary:SambaGPG' with
'--decrypt-samba-gpg'. Calculate a hash with
the specified number of rounds
3) Return the first CryptSHA256 value in
'Primary:userPassword'
virtualCryptSHA512: As virtualClearTextUTF8, but a salted SHA512
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
@ -1322,6 +1364,14 @@ for which virtual attributes are supported in your environment):
attribute name i.e. virtualCryptSHA512;rounds=10000
will calculate a SHA512 hash with 10,000 rounds.
non numeric values for rounds are silently ignored
The value is calculated as follows:
1) If a value exists in 'Primary:userPassword' with
the specified number of rounds it is returned.
2) If 'Primary:CLEARTEXT, or 'Primary:SambaGPG' with
'--decrypt-samba-gpg'. Calculate a hash with
the specified number of rounds
3) Return the first CryptSHA512 value in
'Primary:userPassword'
virtualWDigestNN: The individual hash values stored in
'Primary:WDigest' where NN is the hash number in
@ -1464,6 +1514,14 @@ for supported virtual attributes in your environment):
attribute name i.e. virtualCryptSHA256;rounds=10000
will calculate a SHA256 hash with 10,000 rounds.
non numeric values for rounds are silently ignored
The value is calculated as follows:
1) If a value exists in 'Primary:userPassword' with
the specified number of rounds it is returned.
2) If 'Primary:CLEARTEXT, or 'Primary:SambaGPG' with
'--decrypt-samba-gpg'. Calculate a hash with
the specified number of rounds
3) Return the first CryptSHA256 value in
'Primary:userPassword'
virtualCryptSHA512: As virtualClearTextUTF8, but a salted SHA512
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
@ -1473,6 +1531,14 @@ for supported virtual attributes in your environment):
attribute name i.e. virtualCryptSHA512;rounds=10000
will calculate a SHA512 hash with 10,000 rounds.
non numeric values for rounds are silently ignored
The value is calculated as follows:
1) If a value exists in 'Primary:userPassword' with
the specified number of rounds it is returned.
2) If 'Primary:CLEARTEXT, or 'Primary:SambaGPG' with
'--decrypt-samba-gpg'. Calculate a hash with
the specified number of rounds
3) Return the first CryptSHA512 value in
'Primary:userPassword'
virtualWDigestNN: The individual hash values stored in
'Primary:WDigest' where NN is the hash number in

View File

@ -330,11 +330,3 @@
# We currently don't send referrals for LDAP modify of non-replicated attrs
^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.*
^samba4.ldap.rodc_rwdc.python.*.__main__.RodcRwdcTests.test_change_password_reveal_on_demand_kerberos
# Tests for samba-tool user command extracting CRYPT hashes from supplememtal
# credetials, will fail until code implemented
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_no_gpg_both_hashes_rounds_stored_hashes_with_rounds_no_match\(ad_dc:local\)
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_no_gpg_both_hashes_rounds_stored_hashes\(ad_dc:local\)
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_no_gpg_both_hashes_no_rounds_stored_hashes\(ad_dc:local\)
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_no_gpg_both_hashes_rounds_stored_hashes_with_rounds\(ad_dc:local\)
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_gpg_both_hashes_rounds_stored_hashes_with_rounds\(ad_dc:local\)
^samba.tests.samba_tool.user_virtualCryptSHA.samba.tests.samba_tool.user_virtualCryptSHA.UserCmdCryptShaTestCase.test_gpg_both_hashes_no_rounds_stored_hashes\(ad_dc:local\)