summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2017-05-09 11:20:15 +1200
committerAndrew Bartlett <abartlet@samba.org>2017-05-25 02:25:12 +0200
commitd4bc91a964725c0a0fb8f8c3aa48fcb13f4a998e (patch)
treefea58766c1bfce4761713118ddd06a095ae4bc78 /python
parentd51253609de61b8c7c75d0de8febe9c2c0afdae7 (diff)
downloadsamba-d4bc91a964725c0a0fb8f8c3aa48fcb13f4a998e.tar.gz
samba-tool user: add rounds option to virtualCryptSHAxxx
Allow the number of rounds to be specified when calculating the virtualCryptSHA256 and virtualCryptSHA512 attributes. i.e. --attributes="virtualCryptSHA256;rounds=3000" will calculate the hash using 3,000 rounds. 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/netcmd/user.py85
1 files changed, 78 insertions, 7 deletions
diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py
index ae1c0aa5967..15595881e0c 100644
--- a/python/samba/netcmd/user.py
+++ b/python/samba/netcmd/user.py
@@ -103,7 +103,7 @@ def get_random_bytes(num):
raise ImportError(random_reason)
return get_random_bytes_fn(num)
-def get_crypt_value(alg, utf8pw):
+def get_crypt_value(alg, utf8pw, rounds=0):
algs = {
"5": {"length": 43},
"6": {"length": 86},
@@ -116,8 +116,13 @@ def get_crypt_value(alg, utf8pw):
# we can ignore the possible == at the end
# of the base64 string
# we just need to replace '+' by '.'
- b64salt = base64.b64encode(salt)
- crypt_salt = "$%s$%s$" % (alg, b64salt[0:16].replace('+', '.'))
+ b64salt = base64.b64encode(salt)[0:16].replace('+', '.')
+ crypt_salt = ""
+ if rounds != 0:
+ crypt_salt = "$%s$rounds=%s$%s$" % (alg, rounds, b64salt)
+ else:
+ crypt_salt = "$%s$%s$" % (alg, b64salt)
+
crypt_value = crypt.crypt(utf8pw, crypt_salt)
if crypt_value is None:
raise NotImplementedError("crypt.crypt(%s) returned None" % (crypt_salt))
@@ -127,6 +132,24 @@ def get_crypt_value(alg, utf8pw):
crypt_salt, len(crypt_value), expected_len))
return crypt_value
+# Extract the rounds value from the options of a virtualCrypt attribute
+# i.e. options = "rounds=20;other=ignored;" will return 20
+# if the rounds option is not found or the value is not a number, 0 is returned
+# which indicates that the default number of rounds should be used.
+def get_rounds(options):
+ if not options:
+ return 0
+
+ opts = options.split(';')
+ for o in opts:
+ if o.lower().startswith("rounds="):
+ (key, _, val) = o.partition('=')
+ try:
+ return int(val)
+ except ValueError:
+ return 0
+ return 0
+
try:
random_reason = check_random()
if random_reason is not None:
@@ -882,9 +905,19 @@ class GetPasswordCommand(Command):
def get_account_attributes(self, samdb, username, basedn, filter, scope,
attrs, decrypt):
- require_supplementalCredentials = False
- search_attrs = attrs[:]
+ raw_attrs = attrs[:]
+ search_attrs = []
+ attr_opts = {}
+ for a in raw_attrs:
+ (attr, _, opts) = a.partition(';')
+ if opts:
+ attr_opts[attr] = opts
+ else:
+ attr_opts[attr] = None
+ search_attrs.append(attr)
lower_attrs = [x.lower() for x in search_attrs]
+
+ require_supplementalCredentials = False
for a in virtual_attributes.keys():
if a.lower() in lower_attrs:
require_supplementalCredentials = True
@@ -1124,6 +1157,22 @@ class GetPasswordCommand(Command):
except IndexError:
return None
+ def get_userPassword_hash(blob, scheme, prefix):
+ up = ndr_unpack(drsblobs.package_PrimaryUserPasswordBlob, blob)
+
+ # Check that the NT hash has not been changed without updating
+ # the user password hashes.
+ if unicodePwd != bytearray(up.current_nt_hash.hash):
+ return 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
+
+ return None
+
# We use sort here in order to have a predictable processing order
for a in sorted(virtual_attributes.keys()):
if not a.lower() in lower_attrs:
@@ -1161,7 +1210,8 @@ class GetPasswordCommand(Command):
u8 = get_utf8(a, b, username or account_name)
if u8 is None:
continue
- sv = get_crypt_value("5", u8)
+ rounds = get_rounds(attr_opts[a])
+ sv = get_crypt_value("5", u8, rounds)
v = "{CRYPT}" + sv
elif a == "virtualCryptSHA512":
b = get_package("Primary:CLEARTEXT")
@@ -1170,7 +1220,8 @@ class GetPasswordCommand(Command):
u8 = get_utf8(a, b, username or account_name)
if u8 is None:
continue
- sv = get_crypt_value("6", u8)
+ rounds = get_rounds(attr_opts[a])
+ sv = get_crypt_value("6", u8, rounds)
v = "{CRYPT}" + sv
elif a == "virtualSambaGPG":
# Samba adds 'Primary:SambaGPG' at the end.
@@ -1257,10 +1308,20 @@ for which virtual attributes are supported in your environment):
virtualCryptSHA256: As virtualClearTextUTF8, but a salted SHA256
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
with a $5$... salt, see crypt(3) on modern systems.
+ The number of rounds used to calculate the hash can
+ also be specified. By appending ";rounds=x" to the
+ attribute name i.e. virtualCryptSHA256;rounds=10000
+ will calculate a SHA256 hash with 10,000 rounds.
+ non numeric values for rounds are silently ignored
virtualCryptSHA512: As virtualClearTextUTF8, but a salted SHA512
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
with a $6$... salt, see crypt(3) on modern systems.
+ The number of rounds used to calculate the hash can
+ also be specified. By appending ";rounds=x" to the
+ attribute name i.e. virtualCryptSHA512;rounds=10000
+ will calculate a SHA512 hash with 10,000 rounds.
+ non numeric values for rounds are silently ignored
virtualWDigestNN: The individual hash values stored in
'Primary:WDigest' where NN is the hash number in
@@ -1398,10 +1459,20 @@ for supported virtual attributes in your environment):
virtualCryptSHA256: As virtualClearTextUTF8, but a salted SHA256
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
with a $5$... salt, see crypt(3) on modern systems.
+ The number of rounds used to calculate the hash can
+ also be specified. By appending ";rounds=x" to the
+ attribute name i.e. virtualCryptSHA256;rounds=10000
+ will calculate a SHA256 hash with 10,000 rounds.
+ non numeric values for rounds are silently ignored
virtualCryptSHA512: As virtualClearTextUTF8, but a salted SHA512
checksum, useful for OpenLDAP's '{CRYPT}' algorithm,
with a $6$... salt, see crypt(3) on modern systems.
+ The number of rounds used to calculate the hash can
+ also be specified. By appending ";rounds=x" to the
+ attribute name i.e. virtualCryptSHA512;rounds=10000
+ will calculate a SHA512 hash with 10,000 rounds.
+ non numeric values for rounds are silently ignored
virtualWDigestNN: The individual hash values stored in
'Primary:WDigest' where NN is the hash number in