From: Andrew Bartlett Date: Mon, 11 Dec 2023 07:56:16 +0000 (+1300) Subject: samba-tool: Make samba-tool user getpassword support a ';previous=1' option X-Git-Tag: talloc-2.4.2~243 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=113d2aab30fc84e5434d5475982ae579d8433b70;p=thirdparty%2Fsamba.git samba-tool: Make samba-tool user getpassword support a ';previous=1' option Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall --- diff --git a/python/samba/netcmd/user/readpasswords/common.py b/python/samba/netcmd/user/readpasswords/common.py index 267c8242b8e..6d44881823d 100644 --- a/python/samba/netcmd/user/readpasswords/common.py +++ b/python/samba/netcmd/user/readpasswords/common.py @@ -371,6 +371,8 @@ class GetPasswordCommand(Command): managed_password) calculated["Primary:CLEARTEXT"] = \ unpacked_managed_password.passwords.current + calculated["OLDCLEARTEXT"] = \ + unpacked_managed_password.passwords.previous account_name = str(obj["sAMAccountName"][0]) if "userPrincipalName" in obj: @@ -397,6 +399,17 @@ class GetPasswordCommand(Command): return binascii.a2b_hex(p.data) return None + def get_cleartext(attr_opts): + param = get_option(attr_opts, "previous") + if param: + if param != "1": + raise CommandError( + f"Invalid attribute parameter ;previous={param}, " + "only supported value is previous=1") + return calculated.get("OLDCLEARTEXT") + else: + return get_package("Primary:CLEARTEXT") + def get_kerberos_ctr(): primary_krb5 = get_package("Primary:Kerberos-Newer-Keys") if primary_krb5 is None: @@ -596,7 +609,7 @@ class GetPasswordCommand(Command): 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") + b = get_cleartext(attr_opts) if b is not None: u8 = get_utf8(a, b, username or account_name) if u8 is not None: @@ -664,6 +677,14 @@ class GetPasswordCommand(Command): except ValueError: return 0 + def get_unicode_pwd_hash(pwd): + # We can't read unicodePwd directly, but we can regenerate + # it from msDS-ManagedPassword + tmp = credentials.Credentials() + tmp.set_anonymous() + tmp.set_utf16_password(pwd) + return tmp.get_nt_hash() + # We use sort here in order to have a predictable processing order for a in sorted(virtual_attributes.keys()): vattr = None @@ -679,7 +700,7 @@ class GetPasswordCommand(Command): attr_opts = vattr["opts"] if a == "virtualClearTextUTF8": - b = get_package("Primary:CLEARTEXT") + b = get_cleartext(attr_opts) if b is None: continue u8 = get_utf8(a, b, username or account_name) @@ -687,11 +708,11 @@ class GetPasswordCommand(Command): continue v = u8 elif a == "virtualClearTextUTF16": - v = get_package("Primary:CLEARTEXT") + v = get_cleartext(attr_opts) if v is None: continue elif a == "virtualSSHA": - b = get_package("Primary:CLEARTEXT") + b = get_cleartext(attr_opts) if b is None: continue u8 = get_utf8(a, b, username or account_name) @@ -728,13 +749,13 @@ class GetPasswordCommand(Command): v = kerberos_salt if v is None: continue - elif a == "unicodePwd" and "Primary:CLEARTEXT" in calculated and unicodePwd is None: - # We can't read unicodePwd directly, but we can regenerate - # it from msDS-ManagedPassword - tmp = credentials.Credentials() - tmp.set_anonymous() - tmp.set_utf16_password(calculated["Primary:CLEARTEXT"]) - v = tmp.get_nt_hash() + elif a == "unicodePwd" and unicodePwd is None: + if "Primary:CLEARTEXT" in calculated and not get_option(attr_opts, "previous"): + v = get_unicode_pwd_hash(calculated["Primary:CLEARTEXT"]) + elif "OLDCLEARTEXT" in calculated and get_option(attr_opts, "previous"): + v = get_unicode_pwd_hash(calculated["OLDCLEARTEXT"]) + else: + continue elif a.startswith("virtualWDigest"): primary_wdigest = get_package("Primary:WDigest") if primary_wdigest is None: