internal void SyncReplicaHelper(IntPtr dsHandle, bool isADAM, string partition, string sourceServer, int option, LoadLibrarySafeHandle libHandle) { int structSize = Marshal.SizeOf(typeof(Guid)); IntPtr unmanagedGuid = (IntPtr)0; Guid guid = Guid.Empty; AdamInstance adamServer = null; DomainController dcServer = null; unmanagedGuid = Marshal.AllocHGlobal(structSize); try { if (sourceServer != null) { DirectoryContext newContext = Utils.GetNewDirectoryContext(sourceServer, DirectoryContextType.DirectoryServer, context); if (isADAM) { adamServer = AdamInstance.GetAdamInstance(newContext); guid = adamServer.NtdsaObjectGuid; } else { dcServer = DomainController.GetDomainController(newContext); guid = dcServer.NtdsaObjectGuid; } Marshal.StructureToPtr(guid, unmanagedGuid, false); } // call DsReplicaSyncW IntPtr functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaSyncW"); if (functionPtr == (IntPtr)0) { throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); } UnsafeNativeMethods.DsReplicaSyncW dsReplicaSyncW = (UnsafeNativeMethods.DsReplicaSyncW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaSyncW)); int result = dsReplicaSyncW(dsHandle, partition, unmanagedGuid, (int)option); // check the result if (result != 0) { if (!Partitions.Contains(partition)) { throw new ArgumentException(SR.ServerNotAReplica, nameof(partition)); } string serverDownName = null; // this is the error returned when the server that we want to sync from is down if (result == ExceptionHelper.RPC_S_SERVER_UNAVAILABLE) { serverDownName = sourceServer; } // this is the error returned when the server that we want to get synced is down else if (result == ExceptionHelper.RPC_S_CALL_FAILED) { serverDownName = Name; } throw ExceptionHelper.GetExceptionFromErrorCode(result, serverDownName); } } finally { if (unmanagedGuid != (IntPtr)0) { Marshal.FreeHGlobal(unmanagedGuid); } if (adamServer != null) { adamServer.Dispose(); } if (dcServer != null) { dcServer.Dispose(); } } }
internal static void UpdateTrustDirection(DirectoryContext context, string? sourceName, string? targetName, string password, bool isForest, TrustDirection newTrustDirection) { PolicySafeHandle? handle = null; IntPtr buffer = (IntPtr)0; LSA_UNICODE_STRING? trustedDomainName = null; IntPtr newBuffer = (IntPtr)0; bool impersonated = false; LSA_AUTH_INFORMATION? AuthData = null; IntPtr fileTime = (IntPtr)0; IntPtr unmanagedPassword = (IntPtr)0; IntPtr unmanagedAuthData = (IntPtr)0; TRUSTED_DOMAIN_AUTH_INFORMATION? AuthInfoEx = null; IntPtr target = (IntPtr)0; string? serverName = null; serverName = Utils.GetPolicyServerName(context, isForest, false, sourceName); impersonated = Utils.Impersonate(context); try { try { // get the policy handle first handle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(targetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); // get the trusted domain information int result = UnsafeNativeMethods.LsaQueryTrustedDomainInfoByName(handle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainFullInformation, ref buffer); if (result != 0) { int win32Error = UnsafeNativeMethods.LsaNtStatusToWinError(result); // 2 ERROR_FILE_NOT_FOUND <--> 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND if (win32Error == STATUS_OBJECT_NAME_NOT_FOUND) { if (isForest) throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ForestTrustDoesNotExist, sourceName, targetName), typeof(ForestTrustRelationshipInformation), null); else throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DomainTrustDoesNotExist, sourceName, targetName), typeof(TrustRelationshipInformation), null); } else throw ExceptionHelper.GetExceptionFromErrorCode(win32Error, serverName); } // get the managed structre representation TRUSTED_DOMAIN_FULL_INFORMATION domainInfo = new TRUSTED_DOMAIN_FULL_INFORMATION(); Marshal.PtrToStructure(buffer, domainInfo); // validate the trust attribute first ValidateTrustAttribute(domainInfo.Information!, isForest, sourceName, targetName); // change the attribute value properly AuthData = new LSA_AUTH_INFORMATION(); fileTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FileTime))); UnsafeNativeMethods.GetSystemTimeAsFileTime(fileTime); // set the time FileTime tmp = new FileTime(); Marshal.PtrToStructure(fileTime, tmp); AuthData.LastUpdateTime = new LARGE_INTEGER(); AuthData.LastUpdateTime.lowPart = tmp.lower; AuthData.LastUpdateTime.highPart = tmp.higher; AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR; unmanagedPassword = Marshal.StringToHGlobalUni(password); AuthData.AuthInfo = unmanagedPassword; AuthData.AuthInfoLength = password.Length * 2; unmanagedAuthData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_AUTH_INFORMATION))); Marshal.StructureToPtr(AuthData, unmanagedAuthData, false); AuthInfoEx = new TRUSTED_DOMAIN_AUTH_INFORMATION(); if ((newTrustDirection & TrustDirection.Inbound) != 0) { AuthInfoEx.IncomingAuthInfos = 1; AuthInfoEx.IncomingAuthenticationInformation = unmanagedAuthData; AuthInfoEx.IncomingPreviousAuthenticationInformation = (IntPtr)0; } else { AuthInfoEx.IncomingAuthInfos = 0; AuthInfoEx.IncomingAuthenticationInformation = (IntPtr)0; AuthInfoEx.IncomingPreviousAuthenticationInformation = (IntPtr)0; } if ((newTrustDirection & TrustDirection.Outbound) != 0) { AuthInfoEx.OutgoingAuthInfos = 1; AuthInfoEx.OutgoingAuthenticationInformation = unmanagedAuthData; AuthInfoEx.OutgoingPreviousAuthenticationInformation = (IntPtr)0; } else { AuthInfoEx.OutgoingAuthInfos = 0; AuthInfoEx.OutgoingAuthenticationInformation = (IntPtr)0; AuthInfoEx.OutgoingPreviousAuthenticationInformation = (IntPtr)0; } // reconstruct the unmanaged structure to set it back domainInfo.AuthInformation = AuthInfoEx; // reset the trust direction domainInfo.Information!.TrustDirection = (int)newTrustDirection; newBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TRUSTED_DOMAIN_FULL_INFORMATION))); Marshal.StructureToPtr(domainInfo, newBuffer, false); result = UnsafeNativeMethods.LsaSetTrustedDomainInfoByName(handle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainFullInformation, newBuffer); if (result != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(UnsafeNativeMethods.LsaNtStatusToWinError(result), serverName); } return; } finally { if (impersonated) Utils.Revert(); if (target != (IntPtr)0) Marshal.FreeHGlobal(target); if (buffer != (IntPtr)0) UnsafeNativeMethods.LsaFreeMemory(buffer); if (newBuffer != (IntPtr)0) Marshal.FreeHGlobal(newBuffer); if (fileTime != (IntPtr)0) Marshal.FreeHGlobal(fileTime); if (unmanagedPassword != (IntPtr)0) Marshal.FreeHGlobal(unmanagedPassword); if (unmanagedAuthData != (IntPtr)0) Marshal.FreeHGlobal(unmanagedAuthData); } } catch { throw; } }
internal IntPtr GetReplicationInfoHelper(IntPtr dsHandle, int type, int secondaryType, string partition, ref bool advanced, int context, LoadLibrarySafeHandle libHandle) { IntPtr info = (IntPtr)0; int result = 0; bool needToTryAgain = true; IntPtr functionPtr; // first try to use the DsReplicaGetInfo2W API which does not exist on win2k machine // call DsReplicaGetInfo2W functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfo2W"); if (functionPtr == (IntPtr)0) { // a win2k machine which does not have it. functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfoW"); if (functionPtr == (IntPtr)0) { throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); } UnsafeNativeMethods.DsReplicaGetInfoW dsReplicaGetInfoW = (UnsafeNativeMethods.DsReplicaGetInfoW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfoW)); result = dsReplicaGetInfoW(dsHandle, secondaryType, partition, (IntPtr)0, ref info); advanced = false; needToTryAgain = false; } else { UnsafeNativeMethods.DsReplicaGetInfo2W dsReplicaGetInfo2W = (UnsafeNativeMethods.DsReplicaGetInfo2W)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfo2W)); result = dsReplicaGetInfo2W(dsHandle, type, partition, (IntPtr)0, null, null, 0, context, ref info); } // check the result if (needToTryAgain && result == DS_REPL_NOTSUPPORTED) { // this is the case that client is xp/win2k3, dc is win2k functionPtr = UnsafeNativeMethods.GetProcAddress(libHandle, "DsReplicaGetInfoW"); if (functionPtr == (IntPtr)0) { throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); } UnsafeNativeMethods.DsReplicaGetInfoW dsReplicaGetInfoW = (UnsafeNativeMethods.DsReplicaGetInfoW)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(UnsafeNativeMethods.DsReplicaGetInfoW)); result = dsReplicaGetInfoW(dsHandle, secondaryType, partition, (IntPtr)0, ref info); advanced = false; } if (result != 0) { if (partition != null) { // this is the case of meta data if (type == (int)DS_REPL_INFO_TYPE.DS_REPL_INFO_METADATA_2_FOR_OBJ) { if (result == ExceptionHelper.ERROR_DS_DRA_BAD_DN || result == ExceptionHelper.ERROR_DS_NAME_UNPARSEABLE) { throw new ArgumentException(ExceptionHelper.GetErrorMessage(result, false), "objectPath"); } DirectoryEntry verifyEntry = DirectoryEntryManager.GetDirectoryEntry(this.context, partition); try { verifyEntry.RefreshCache(new string[] { "name" }); } catch (COMException e) { if (e.ErrorCode == unchecked ((int)0x80072020) | // dir_error on server side e.ErrorCode == unchecked ((int)0x80072030)) // object not exists { throw new ArgumentException(SR.DSNoObject, "objectPath"); } else if (e.ErrorCode == unchecked ((int)0x80005000) | // bad path name e.ErrorCode == unchecked ((int)0x80072032)) // ERROR_DS_INVALID_DN_SYNTAX { throw new ArgumentException(SR.DSInvalidPath, "objectPath"); } } } else { if (!Partitions.Contains(partition)) { throw new ArgumentException(SR.ServerNotAReplica, nameof(partition)); } } } throw ExceptionHelper.GetExceptionFromErrorCode(result, Name); } return(info); }
internal static bool GetTrustedDomainInfoStatus(DirectoryContext context, string? sourceName, string targetName, TRUST_ATTRIBUTE attribute, bool isForest) { PolicySafeHandle? handle = null; IntPtr buffer = (IntPtr)0; LSA_UNICODE_STRING? trustedDomainName = null; bool impersonated = false; IntPtr target = (IntPtr)0; string? serverName = null; // get policy server name serverName = Utils.GetPolicyServerName(context, isForest, false, sourceName); impersonated = Utils.Impersonate(context); try { try { // get the policy handle first handle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(targetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); int result = UnsafeNativeMethods.LsaQueryTrustedDomainInfoByName(handle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainInformationEx, ref buffer); if (result != 0) { int win32Error = UnsafeNativeMethods.LsaNtStatusToWinError(result); // 2 ERROR_FILE_NOT_FOUND <--> 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND if (win32Error == STATUS_OBJECT_NAME_NOT_FOUND) { if (isForest) throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ForestTrustDoesNotExist, sourceName, targetName), typeof(ForestTrustRelationshipInformation), null); else throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DomainTrustDoesNotExist, sourceName, targetName), typeof(TrustRelationshipInformation), null); } else throw ExceptionHelper.GetExceptionFromErrorCode(win32Error, serverName); } Debug.Assert(buffer != (IntPtr)0); TRUSTED_DOMAIN_INFORMATION_EX domainInfo = new TRUSTED_DOMAIN_INFORMATION_EX(); Marshal.PtrToStructure(buffer, domainInfo); // validate this is the trust that the user refers to ValidateTrustAttribute(domainInfo, isForest, sourceName, targetName); // get the attribute of the trust // selective authentication info if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_CROSS_ORGANIZATION) { if ((domainInfo.TrustAttributes & TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_CROSS_ORGANIZATION) == 0) return false; else return true; } // sid filtering behavior for forest trust else if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL) { if ((domainInfo.TrustAttributes & TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL) == 0) return true; else return false; } // sid filtering behavior for domain trust else if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) { if ((domainInfo.TrustAttributes & TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) == 0) return false; else return true; } else { // should not happen throw new ArgumentException(nameof(attribute)); } } finally { if (impersonated) Utils.Revert(); if (target != (IntPtr)0) Marshal.FreeHGlobal(target); if (buffer != (IntPtr)0) UnsafeNativeMethods.LsaFreeMemory(buffer); } } catch { throw; } }
internal static void CreateTrust(DirectoryContext sourceContext, string? sourceName, DirectoryContext targetContext, string? targetName, bool isForest, TrustDirection direction, string password) { LSA_AUTH_INFORMATION? AuthData = null; TRUSTED_DOMAIN_AUTH_INFORMATION? AuthInfoEx = null; TRUSTED_DOMAIN_INFORMATION_EX? tdi = null; IntPtr fileTime = (IntPtr)0; IntPtr unmanagedPassword = (IntPtr)0; IntPtr info = (IntPtr)0; IntPtr domainHandle = (IntPtr)0; PolicySafeHandle? policyHandle = null; IntPtr unmanagedAuthData = (IntPtr)0; bool impersonated = false; string? serverName = null; // get the domain info first info = GetTrustedDomainInfo(targetContext, targetName, isForest); try { try { POLICY_DNS_DOMAIN_INFO domainInfo = new POLICY_DNS_DOMAIN_INFO(); Marshal.PtrToStructure(info, domainInfo); AuthData = new LSA_AUTH_INFORMATION(); fileTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FileTime))); UnsafeNativeMethods.GetSystemTimeAsFileTime(fileTime); // set the time FileTime tmp = new FileTime(); Marshal.PtrToStructure(fileTime, tmp); AuthData.LastUpdateTime = new LARGE_INTEGER(); AuthData.LastUpdateTime.lowPart = tmp.lower; AuthData.LastUpdateTime.highPart = tmp.higher; AuthData.AuthType = TRUST_AUTH_TYPE_CLEAR; unmanagedPassword = Marshal.StringToHGlobalUni(password); AuthData.AuthInfo = unmanagedPassword; AuthData.AuthInfoLength = password.Length * 2; // sizeof(WCHAR) unmanagedAuthData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_AUTH_INFORMATION))); Marshal.StructureToPtr(AuthData, unmanagedAuthData, false); AuthInfoEx = new TRUSTED_DOMAIN_AUTH_INFORMATION(); if ((direction & TrustDirection.Inbound) != 0) { AuthInfoEx.IncomingAuthInfos = 1; AuthInfoEx.IncomingAuthenticationInformation = unmanagedAuthData; AuthInfoEx.IncomingPreviousAuthenticationInformation = (IntPtr)0; } if ((direction & TrustDirection.Outbound) != 0) { AuthInfoEx.OutgoingAuthInfos = 1; AuthInfoEx.OutgoingAuthenticationInformation = unmanagedAuthData; AuthInfoEx.OutgoingPreviousAuthenticationInformation = (IntPtr)0; } tdi = new TRUSTED_DOMAIN_INFORMATION_EX(); tdi.FlatName = domainInfo.Name; tdi.Name = domainInfo.DnsDomainName; tdi.Sid = domainInfo.Sid; tdi.TrustType = TRUST_TYPE_UPLEVEL; tdi.TrustDirection = (int)direction; if (isForest) { tdi.TrustAttributes = TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_FOREST_TRANSITIVE; } else { tdi.TrustAttributes = TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN; } // get server name serverName = Utils.GetPolicyServerName(sourceContext, isForest, false, sourceName); // do impersonation and get policy handle impersonated = Utils.Impersonate(sourceContext); policyHandle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); int result = UnsafeNativeMethods.LsaCreateTrustedDomainEx(policyHandle, tdi, AuthInfoEx, TRUSTED_SET_POSIX | TRUSTED_SET_AUTH, out domainHandle); if (result != 0) { result = UnsafeNativeMethods.LsaNtStatusToWinError(result); if (result == ERROR_ALREADY_EXISTS) { if (isForest) throw new ActiveDirectoryObjectExistsException(SR.Format(SR.AlreadyExistingForestTrust, sourceName, targetName)); else throw new ActiveDirectoryObjectExistsException(SR.Format(SR.AlreadyExistingDomainTrust, sourceName, targetName)); } else throw ExceptionHelper.GetExceptionFromErrorCode(result, serverName); } } finally { if (impersonated) Utils.Revert(); if (fileTime != (IntPtr)0) Marshal.FreeHGlobal(fileTime); if (domainHandle != (IntPtr)0) UnsafeNativeMethods.LsaClose(domainHandle); if (info != (IntPtr)0) UnsafeNativeMethods.LsaFreeMemory(info); if (unmanagedPassword != (IntPtr)0) Marshal.FreeHGlobal(unmanagedPassword); if (unmanagedAuthData != (IntPtr)0) Marshal.FreeHGlobal(unmanagedAuthData); } } catch { throw; } }
internal static void VerifyTrust(DirectoryContext context, string? sourceName, string? targetName, bool isForest, TrustDirection direction, bool forceSecureChannelReset, string? preferredTargetServer) { PolicySafeHandle? policyHandle = null; LSA_UNICODE_STRING? trustedDomainName = null; int win32Error = 0; IntPtr data = (IntPtr)0; IntPtr ptr = (IntPtr)0; IntPtr buffer1 = (IntPtr)0; IntPtr buffer2 = (IntPtr)0; bool impersonated = true; IntPtr target = (IntPtr)0; string? policyServerName = null; policyServerName = Utils.GetPolicyServerName(context, isForest, false, sourceName); impersonated = Utils.Impersonate(context); try { try { // get the policy handle policyHandle = new PolicySafeHandle(Utils.GetPolicyHandle(policyServerName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(targetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); // validate the trust existence ValidateTrust(policyHandle, trustedDomainName, sourceName, targetName, isForest, (int)direction, policyServerName); // need to verify direction if (preferredTargetServer == null) data = Marshal.StringToHGlobalUni(targetName); else // this is the case that we need to specifically go to a particular server. This is the way to tell netlogon to do that. data = Marshal.StringToHGlobalUni(targetName + "\\" + preferredTargetServer); ptr = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(ptr, data); if (!forceSecureChannelReset) { win32Error = UnsafeNativeMethods.I_NetLogonControl2(policyServerName, NETLOGON_CONTROL_TC_VERIFY, NETLOGON_QUERY_LEVEL, ptr, out buffer1); if (win32Error == 0) { NETLOGON_INFO_2 info = new NETLOGON_INFO_2(); Marshal.PtrToStructure(buffer1, info); if ((info.netlog2_flags & NETLOGON_VERIFY_STATUS_RETURNED) != 0) { int result = info.netlog2_pdc_connection_status; if (result == 0) { // verification succeeded return; } else { // don't really know which server is down, the source or the target throw ExceptionHelper.GetExceptionFromErrorCode(result); } } else { int result = info.netlog2_tc_connection_status; throw ExceptionHelper.GetExceptionFromErrorCode(result); } } else { if (win32Error == ERROR_INVALID_LEVEL) { // it is pre-win2k SP3 dc that does not support NETLOGON_CONTROL_TC_VERIFY throw new NotSupportedException(SR.TrustVerificationNotSupport); } else { throw ExceptionHelper.GetExceptionFromErrorCode(win32Error); } } } else { // then try secure channel reset win32Error = UnsafeNativeMethods.I_NetLogonControl2(policyServerName, NETLOGON_CONTROL_REDISCOVER, NETLOGON_QUERY_LEVEL, ptr, out buffer2); if (win32Error != 0) // don't really know which server is down, the source or the target throw ExceptionHelper.GetExceptionFromErrorCode(win32Error); } } finally { if (impersonated) Utils.Revert(); if (target != (IntPtr)0) Marshal.FreeHGlobal(target); if (ptr != (IntPtr)0) Marshal.FreeHGlobal(ptr); if (data != (IntPtr)0) Marshal.FreeHGlobal(data); if (buffer1 != (IntPtr)0) UnsafeNativeMethods.NetApiBufferFree(buffer1); if (buffer2 != (IntPtr)0) UnsafeNativeMethods.NetApiBufferFree(buffer2); } } catch { throw; } }
internal static void DeleteTrust(DirectoryContext sourceContext, string? sourceName, string? targetName, bool isForest) { PolicySafeHandle? policyHandle = null; LSA_UNICODE_STRING? trustedDomainName = null; int win32Error = 0; bool impersonated = false; IntPtr target = (IntPtr)0; string? serverName = null; IntPtr buffer = (IntPtr)0; serverName = Utils.GetPolicyServerName(sourceContext, isForest, false, sourceName); impersonated = Utils.Impersonate(sourceContext); try { try { // get the policy handle policyHandle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(targetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); // get trust information int result = UnsafeNativeMethods.LsaQueryTrustedDomainInfoByName(policyHandle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainInformationEx, ref buffer); if (result != 0) { win32Error = UnsafeNativeMethods.LsaNtStatusToWinError(result); // 2 ERROR_FILE_NOT_FOUND <--> 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND if (win32Error == STATUS_OBJECT_NAME_NOT_FOUND) { if (isForest) throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ForestTrustDoesNotExist, sourceName, targetName), typeof(ForestTrustRelationshipInformation), null); else throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DomainTrustDoesNotExist, sourceName, targetName), typeof(TrustRelationshipInformation), null); } else throw ExceptionHelper.GetExceptionFromErrorCode(win32Error, serverName); } Debug.Assert(buffer != (IntPtr)0); try { TRUSTED_DOMAIN_INFORMATION_EX domainInfo = new TRUSTED_DOMAIN_INFORMATION_EX(); Marshal.PtrToStructure(buffer, domainInfo); // validate this is the trust that the user refers to ValidateTrustAttribute(domainInfo, isForest, sourceName, targetName); // delete the trust result = UnsafeNativeMethods.LsaDeleteTrustedDomain(policyHandle, domainInfo.Sid); if (result != 0) { win32Error = UnsafeNativeMethods.LsaNtStatusToWinError(result); throw ExceptionHelper.GetExceptionFromErrorCode(win32Error, serverName); } } finally { if (buffer != (IntPtr)0) UnsafeNativeMethods.LsaFreeMemory(buffer); } } finally { if (impersonated) Utils.Revert(); if (target != (IntPtr)0) Marshal.FreeHGlobal(target); } } catch { throw; } }
internal static void SetTrustedDomainInfoStatus(DirectoryContext context, string? sourceName, string targetName, TRUST_ATTRIBUTE attribute, bool status, bool isForest) { PolicySafeHandle? handle = null; IntPtr buffer = (IntPtr)0; IntPtr newInfo = (IntPtr)0; LSA_UNICODE_STRING? trustedDomainName = null; bool impersonated = false; IntPtr target = (IntPtr)0; string? serverName = null; serverName = Utils.GetPolicyServerName(context, isForest, false, sourceName); impersonated = Utils.Impersonate(context); try { try { // get the policy handle first handle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(targetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); // get the trusted domain information int result = UnsafeNativeMethods.LsaQueryTrustedDomainInfoByName(handle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainInformationEx, ref buffer); if (result != 0) { int win32Error = UnsafeNativeMethods.LsaNtStatusToWinError(result); // 2 ERROR_FILE_NOT_FOUND <--> 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND if (win32Error == STATUS_OBJECT_NAME_NOT_FOUND) { if (isForest) throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.ForestTrustDoesNotExist, sourceName, targetName), typeof(ForestTrustRelationshipInformation), null); else throw new ActiveDirectoryObjectNotFoundException(SR.Format(SR.DomainTrustDoesNotExist, sourceName, targetName), typeof(TrustRelationshipInformation), null); } else throw ExceptionHelper.GetExceptionFromErrorCode(win32Error, serverName); } Debug.Assert(buffer != (IntPtr)0); // get the managed structre representation TRUSTED_DOMAIN_INFORMATION_EX domainInfo = new TRUSTED_DOMAIN_INFORMATION_EX(); Marshal.PtrToStructure(buffer, domainInfo); // validate this is the trust that the user refers to ValidateTrustAttribute(domainInfo, isForest, sourceName, targetName); // change the attribute value properly // selective authentication if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_CROSS_ORGANIZATION) { if (status) { // turns on selective authentication domainInfo.TrustAttributes |= TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_CROSS_ORGANIZATION; } else { // turns off selective authentication domainInfo.TrustAttributes &= ~(TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_CROSS_ORGANIZATION); } } // user wants to change sid filtering behavior for forest trust else if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL) { if (status) { // user wants sid filtering behavior domainInfo.TrustAttributes &= ~(TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL); } else { // users wants to turn off sid filtering behavior domainInfo.TrustAttributes |= TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL; } } // user wants to change sid filtering behavior for external trust else if (attribute == TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) { if (status) { // user wants sid filtering behavior domainInfo.TrustAttributes |= TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN; } else { // user wants to turn off sid filtering behavior domainInfo.TrustAttributes &= ~(TRUST_ATTRIBUTE.TRUST_ATTRIBUTE_QUARANTINED_DOMAIN); } } else { throw new ArgumentException(nameof(attribute)); } // reconstruct the unmanaged structure to set it back newInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TRUSTED_DOMAIN_INFORMATION_EX))); Marshal.StructureToPtr(domainInfo, newInfo, false); result = UnsafeNativeMethods.LsaSetTrustedDomainInfoByName(handle, trustedDomainName, TRUSTED_INFORMATION_CLASS.TrustedDomainInformationEx, newInfo); if (result != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(UnsafeNativeMethods.LsaNtStatusToWinError(result), serverName); } return; } finally { if (impersonated) Utils.Revert(); if (target != (IntPtr)0) Marshal.FreeHGlobal(target); if (buffer != (IntPtr)0) UnsafeNativeMethods.LsaFreeMemory(buffer); if (newInfo != (IntPtr)0) Marshal.FreeHGlobal(newInfo); } } catch { throw; } }