public void Save() { int count = 0; IntPtr records = (IntPtr)0; int currentCount = 0; IntPtr tmpPtr = (IntPtr)0; IntPtr forestInfo = (IntPtr)0; PolicySafeHandle handle = null; LSA_UNICODE_STRING trustedDomainName; IntPtr collisionInfo = (IntPtr)0; ArrayList ptrList = new ArrayList(); ArrayList sidList = new ArrayList(); bool impersonated = false; IntPtr target = (IntPtr)0; string serverName = null; IntPtr fileTime = (IntPtr)0; // first get the count of all the records int toplevelNamesCount = TopLevelNames.Count; int excludedNamesCount = ExcludedTopLevelNames.Count; int trustedDomainCount = TrustedDomainInformation.Count; int binaryDataCount = 0; checked { count += toplevelNamesCount; count += excludedNamesCount; count += trustedDomainCount; if (_binaryData.Count != 0) { binaryDataCount = _binaryData.Count; // for the ForestTrustRecordTypeLast record count++; count += binaryDataCount; } // allocate the memory for all the records records = Marshal.AllocHGlobal(count * IntPtr.Size); } try { try { IntPtr ptr = (IntPtr)0; fileTime = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FileTime))); UnsafeNativeMethods.GetSystemTimeAsFileTime(fileTime); // set the time FileTime currentTime = new FileTime(); Marshal.PtrToStructure(fileTime, currentTime); for (int i = 0; i < toplevelNamesCount; i++) { // now begin to construct top leve name record LSA_FOREST_TRUST_RECORD record = new LSA_FOREST_TRUST_RECORD(); record.Flags = (int)_topLevelNames[i].Status; record.ForestTrustType = LSA_FOREST_TRUST_RECORD_TYPE.ForestTrustTopLevelName; TopLevelName TLN = _topLevelNames[i]; record.Time = TLN.time; record.TopLevelName = new LSA_UNICODE_STRING(); ptr = Marshal.StringToHGlobalUni(TLN.Name); ptrList.Add(ptr); UnsafeNativeMethods.RtlInitUnicodeString(record.TopLevelName, ptr); tmpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_RECORD))); ptrList.Add(tmpPtr); Marshal.StructureToPtr(record, tmpPtr, false); Marshal.WriteIntPtr(records, IntPtr.Size * currentCount, tmpPtr); currentCount++; } for (int i = 0; i < excludedNamesCount; i++) { // now begin to construct excluded top leve name record LSA_FOREST_TRUST_RECORD record = new LSA_FOREST_TRUST_RECORD(); record.Flags = 0; record.ForestTrustType = LSA_FOREST_TRUST_RECORD_TYPE.ForestTrustTopLevelNameEx; if (_excludedNameTime.Contains(_excludedNames[i])) { record.Time = (LARGE_INTEGER)_excludedNameTime[i]; } else { record.Time = new LARGE_INTEGER(); record.Time.lowPart = currentTime.lower; record.Time.highPart = currentTime.higher; } record.TopLevelName = new LSA_UNICODE_STRING(); ptr = Marshal.StringToHGlobalUni(_excludedNames[i]); ptrList.Add(ptr); UnsafeNativeMethods.RtlInitUnicodeString(record.TopLevelName, ptr); tmpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_RECORD))); ptrList.Add(tmpPtr); Marshal.StructureToPtr(record, tmpPtr, false); Marshal.WriteIntPtr(records, IntPtr.Size * currentCount, tmpPtr); currentCount++; } for (int i = 0; i < trustedDomainCount; i++) { // now begin to construct domain info record LSA_FOREST_TRUST_RECORD record = new LSA_FOREST_TRUST_RECORD(); record.Flags = (int)_domainInfo[i].Status; record.ForestTrustType = LSA_FOREST_TRUST_RECORD_TYPE.ForestTrustDomainInfo; ForestTrustDomainInformation tmp = _domainInfo[i]; record.Time = tmp.time; IntPtr pSid = (IntPtr)0; IntPtr stringSid = (IntPtr)0; stringSid = Marshal.StringToHGlobalUni(tmp.DomainSid); ptrList.Add(stringSid); int result = UnsafeNativeMethods.ConvertStringSidToSidW(stringSid, ref pSid); if (result == 0) { throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); } record.DomainInfo = new LSA_FOREST_TRUST_DOMAIN_INFO(); record.DomainInfo.sid = pSid; sidList.Add(pSid); record.DomainInfo.DNSNameBuffer = Marshal.StringToHGlobalUni(tmp.DnsName); ptrList.Add(record.DomainInfo.DNSNameBuffer); record.DomainInfo.DNSNameLength = (short)(tmp.DnsName == null ? 0 : tmp.DnsName.Length * 2); // sizeof(WCHAR) record.DomainInfo.DNSNameMaximumLength = (short)(tmp.DnsName == null ? 0 : tmp.DnsName.Length * 2); record.DomainInfo.NetBIOSNameBuffer = Marshal.StringToHGlobalUni(tmp.NetBiosName); ptrList.Add(record.DomainInfo.NetBIOSNameBuffer); record.DomainInfo.NetBIOSNameLength = (short)(tmp.NetBiosName == null ? 0 : tmp.NetBiosName.Length * 2); record.DomainInfo.NetBIOSNameMaximumLength = (short)(tmp.NetBiosName == null ? 0 : tmp.NetBiosName.Length * 2); tmpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_RECORD))); ptrList.Add(tmpPtr); Marshal.StructureToPtr(record, tmpPtr, false); Marshal.WriteIntPtr(records, IntPtr.Size * currentCount, tmpPtr); currentCount++; } if (binaryDataCount > 0) { // now begin to construct ForestTrustRecordTypeLast LSA_FOREST_TRUST_RECORD lastRecord = new LSA_FOREST_TRUST_RECORD(); lastRecord.Flags = 0; lastRecord.ForestTrustType = LSA_FOREST_TRUST_RECORD_TYPE.ForestTrustRecordTypeLast; tmpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_RECORD))); ptrList.Add(tmpPtr); Marshal.StructureToPtr(lastRecord, tmpPtr, false); Marshal.WriteIntPtr(records, IntPtr.Size * currentCount, tmpPtr); currentCount++; for (int i = 0; i < binaryDataCount; i++) { // now begin to construct excluded top leve name record LSA_FOREST_TRUST_RECORD record = new LSA_FOREST_TRUST_RECORD(); record.Flags = 0; record.Time = (LARGE_INTEGER)_binaryDataTime[i]; record.Data.Length = ((byte[])_binaryData[i]).Length; if (record.Data.Length == 0) { record.Data.Buffer = (IntPtr)0; } else { record.Data.Buffer = Marshal.AllocHGlobal(record.Data.Length); ptrList.Add(record.Data.Buffer); Marshal.Copy((byte[])_binaryData[i], 0, record.Data.Buffer, record.Data.Length); } tmpPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_RECORD))); ptrList.Add(tmpPtr); Marshal.StructureToPtr(record, tmpPtr, false); Marshal.WriteIntPtr(records, IntPtr.Size * currentCount, tmpPtr); currentCount++; } } // finally construct the LSA_FOREST_TRUST_INFORMATION LSA_FOREST_TRUST_INFORMATION trustInformation = new LSA_FOREST_TRUST_INFORMATION(); trustInformation.RecordCount = count; trustInformation.Entries = records; forestInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LSA_FOREST_TRUST_INFORMATION))); Marshal.StructureToPtr(trustInformation, forestInfo, false); // get policy server name serverName = Utils.GetPolicyServerName(context, true, true, SourceName); // do impersonation first impersonated = Utils.Impersonate(context); // get the policy handle handle = new PolicySafeHandle(Utils.GetPolicyHandle(serverName)); // get the target name trustedDomainName = new LSA_UNICODE_STRING(); target = Marshal.StringToHGlobalUni(TargetName); UnsafeNativeMethods.RtlInitUnicodeString(trustedDomainName, target); // call the unmanaged function int error = UnsafeNativeMethods.LsaSetForestTrustInformation(handle, trustedDomainName, forestInfo, 1, out collisionInfo); if (error != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(UnsafeNativeMethods.LsaNtStatusToWinError(error), serverName); } // there is collision, throw proper exception so user can deal with it if (collisionInfo != (IntPtr)0) { throw ExceptionHelper.CreateForestTrustCollisionException(collisionInfo); } // commit the changes error = UnsafeNativeMethods.LsaSetForestTrustInformation(handle, trustedDomainName, forestInfo, 0, out collisionInfo); if (error != 0) { throw ExceptionHelper.GetExceptionFromErrorCode(error, serverName); } // now next time property is invoked, we need to go to the server retrieved = false; } finally { if (impersonated) { Utils.Revert(); } // release the memory for (int i = 0; i < ptrList.Count; i++) { Marshal.FreeHGlobal((IntPtr)ptrList[i]); } for (int i = 0; i < sidList.Count; i++) { UnsafeNativeMethods.LocalFree((IntPtr)sidList[i]); } if (records != (IntPtr)0) { Marshal.FreeHGlobal(records); } if (forestInfo != (IntPtr)0) { Marshal.FreeHGlobal(forestInfo); } if (collisionInfo != (IntPtr)0) { UnsafeNativeMethods.LsaFreeMemory(collisionInfo); } if (target != (IntPtr)0) { Marshal.FreeHGlobal(target); } if (fileTime != (IntPtr)0) { Marshal.FreeHGlobal(fileTime); } } } catch { throw; } }