From: Andreas Schneider Date: Wed, 3 Apr 2024 09:16:19 +0000 (+0200) Subject: python: Implement CreateTrustedDomainFallback() X-Git-Tag: tdb-1.4.11~1259 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=859e7f8c5f1bc65361e3da9dee38db5307a4438f;p=thirdparty%2Fsamba.git python: Implement CreateTrustedDomainFallback() Signed-off-by: Andreas Schneider Reviewed-by: Andrew Bartlett --- diff --git a/python/samba/lsa_utils.py b/python/samba/lsa_utils.py index f2ac8931c2b..a56675d6b63 100644 --- a/python/samba/lsa_utils.py +++ b/python/samba/lsa_utils.py @@ -18,7 +18,12 @@ from samba.dcerpc import lsa, drsblobs, misc from samba.ndr import ndr_pack -from samba import NTSTATUSError, arcfour_encrypt, string_to_byte_array +from samba import ( + NTSTATUSError, + aead_aes_256_cbc_hmac_sha512, + arcfour_encrypt, + string_to_byte_array +) from samba.ntstatus import ( NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE ) @@ -109,3 +114,80 @@ def CreateTrustedDomainRelax( crypto.set_strict_mode() return lsaconn.CreateTrustedDomainEx2(policy, trust_info, auth_info, mask) + + +def CreateTrustedDomainFallback( + conn: lsa.lsarpc, + policy_handle: misc.policy_handle, + trust_info: lsa.TrustDomainInfoInfoEx, + access_mask: int, + srv_version: int, + srv_revision_info1: lsa.revision_info1, + in_blob: drsblobs.trustAuthInOutBlob, + out_blob: drsblobs.trustAuthInOutBlob +): + def generate_AuthInfoInternalAES( + session_key, + incoming=None, + outgoing=None + ): + trustpass = drsblobs.trustDomainPasswords() + + trustpass.outgoing = outgoing + trustpass.incoming = incoming + + trustpass_blob = ndr_pack(trustpass) + + lsa_aes256_enc_key = ( + "Microsoft LSAD encryption key AEAD-AES-256-CBC-HMAC-SHA512 16".encode() + + b'\x00' + ) + lsa_aes256_mac_key = ( + "Microsoft LSAD MAC key AEAD-AES-256-CBC-HMAC-SHA512 16".encode() + + b'\x00' + ) + + iv = token_bytes(16) + ciphertext, auth_data = aead_aes_256_cbc_hmac_sha512( + trustpass_blob, + session_key, + lsa_aes256_enc_key, + lsa_aes256_mac_key, + iv, + ) + + return ciphertext, iv, auth_data + + if (srv_version == 1 + and srv_revision_info1.revision == 1 + and (srv_revision_info1.supported_features + & lsa.LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER)): + + ciphertext, iv, auth_data = generate_AuthInfoInternalAES( + conn.session_key, in_blob, out_blob + ) + + auth_blob = lsa.DATA_BUF2() + auth_blob.size = len(ciphertext) + auth_blob.data = string_to_byte_array(ciphertext) + + auth_info = lsa.TrustDomainInfoAuthInfoInternalAES() + auth_info.cipher = auth_blob + auth_info.salt = string_to_byte_array(iv) + auth_info.auth_data = string_to_byte_array(auth_data) + + return conn.CreateTrustedDomainEx3( + policy_handle, + trust_info, + auth_info, + access_mask + ) + + return CreateTrustedDomainRelax( + conn, + policy_handle, + trust_info, + access_mask, + in_blob, + out_blob + ) diff --git a/python/samba/tests/dcerpc/lsa_utils.py b/python/samba/tests/dcerpc/lsa_utils.py index 648f8ace481..d6da5eb60bd 100644 --- a/python/samba/tests/dcerpc/lsa_utils.py +++ b/python/samba/tests/dcerpc/lsa_utils.py @@ -27,7 +27,11 @@ from samba.credentials import ( SMB_ENCRYPTION_REQUIRED, SMB_ENCRYPTION_OFF ) -from samba.lsa_utils import OpenPolicyFallback, CreateTrustedDomainRelax +from samba.lsa_utils import ( + OpenPolicyFallback, + CreateTrustedDomainRelax, + CreateTrustedDomainFallback, +) class CreateTrustedDomain(TestCase): @@ -144,8 +148,100 @@ class CreateTrustedDomain(TestCase): else: self.assertIsNone(trustdom_handle) + def _create_trust_fallback(self): + creds = self.get_user_creds() + + lp = self.get_loadparm() + + binding_string = ( + "ncacn_np:%s" % (samba.tests.env_get_var_value('SERVER')) + ) + lsa_conn = lsa.lsarpc(binding_string, lp, creds) + + in_version = 1 + in_revision_info1 = lsa.revision_info1() + in_revision_info1.revision = 1 + in_revision_info1.supported_features = ( + lsa.LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER + ) + + out_version, out_revision_info1, pol_handle = OpenPolicyFallback( + lsa_conn, + '', + in_version, + in_revision_info1, + access_mask=security.SEC_FLAG_MAXIMUM_ALLOWED + ) + self.assertIsNotNone(pol_handle) + + name = lsa.String() + name.string = "tests.samba.example.com" + try: + info = lsa_conn.QueryTrustedDomainInfoByName( + pol_handle, + name, + lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO + ) + + lsa_conn.DeleteTrustedDomain(pol_handle, info.info_ex.sid) + except RuntimeError: + pass + + info = lsa.TrustDomainInfoInfoEx() + info.domain_name.string = name.string + info.netbios_name.string = "createtrustrelax" + info.sid = security.dom_sid("S-1-5-21-538490383-3740119673-95748416") + info.trust_direction = ( + lsa.LSA_TRUST_DIRECTION_INBOUND + | lsa.LSA_TRUST_DIRECTION_OUTBOUND + ) + info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL + info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE + + password_blob = samba.string_to_byte_array( + "password".encode('utf-16-le') + ) + + clear_value = drsblobs.AuthInfoClear() + clear_value.size = len(password_blob) + clear_value.password = password_blob + + clear_authentication_information = drsblobs.AuthenticationInformation() + clear_authentication_information.LastUpdateTime = 0 + clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR + clear_authentication_information.AuthInfo = clear_value + + auth_info_array = drsblobs.AuthenticationInformationArray() + auth_info_array.count = 1 + auth_info_array.array = [clear_authentication_information] + + outgoing = drsblobs.trustAuthInOutBlob() + outgoing.count = 1 + outgoing.current = auth_info_array + + trustdom_handle = None + try: + trustdom_handle = CreateTrustedDomainFallback( + lsa_conn, + pol_handle, + info, + security.SEC_STD_DELETE, + out_version, + out_revision_info1, + outgoing, + outgoing + ) + except samba.NTSTATUSError as nt: + raise AssertionError(nt) + + self.assertIsNotNone(trustdom_handle) + lsa_conn.DeleteTrustedDomain(pol_handle, info.sid) + def test_create_trust_relax_encrypt(self): self._create_trust_relax(True) def test_create_trust_relax_no_enc(self): self._create_trust_relax(False) + + def test_create_trust_fallback(self): + self._create_trust_fallback()