private void TranslateSids(string target, IntPtr[] pSids) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: processing {0} SIDs", pSids.Length); // if there are no SIDs to translate return if (pSids.Length == 0) { return; } // Build the list of SIDs to resolve int sidCount = pSids.Length; // Translate the SIDs in bulk SafeLsaPolicyHandle policyHandle = null; SafeLsaMemoryHandle domainsHandle = null; SafeLsaMemoryHandle namesHandle = null; try { // // Get the policy handle // Interop.OBJECT_ATTRIBUTES oa = default; uint err = Interop.Advapi32.LsaOpenPolicy( target, ref oa, (int)Interop.Advapi32.PolicyRights.POLICY_LOOKUP_NAMES, out policyHandle); if (err != 0) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: couldn't get policy handle, err={0}", err); throw new PrincipalOperationException(SR.Format( SR.AuthZErrorEnumeratingGroups, Interop.Advapi32.LsaNtStatusToWinError(err))); } Debug.Assert(!policyHandle.IsInvalid); // // Translate the SIDs // err = Interop.Advapi32.LsaLookupSids( policyHandle, sidCount, pSids, out domainsHandle, out namesHandle); // Ignore error STATUS_SOME_NOT_MAPPED and STATUS_NONE_MAPPED if (err != Interop.StatusOptions.STATUS_SUCCESS && err != Interop.StatusOptions.STATUS_SOME_NOT_MAPPED && err != Interop.StatusOptions.STATUS_NONE_MAPPED) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: LsaLookupSids failed, err={0}", err); throw new PrincipalOperationException(SR.Format( SR.AuthZErrorEnumeratingGroups, Interop.Advapi32.LsaNtStatusToWinError(err))); } // // Get the group names in managed form // namesHandle.Initialize((uint)sidCount, (uint)Marshal.SizeOf <Interop.LSA_TRANSLATED_NAME>()); Interop.LSA_TRANSLATED_NAME[] names = new Interop.LSA_TRANSLATED_NAME[sidCount]; namesHandle.ReadArray(0, names, 0, names.Length); // // Get the domain names in managed form // domainsHandle.InitializeReferencedDomainsList(); Interop.LSA_REFERENCED_DOMAIN_LIST domainList = domainsHandle.Read <Interop.LSA_REFERENCED_DOMAIN_LIST>(0); // Extract LSA_REFERENCED_DOMAIN_LIST.Entries int domainCount = domainList.Entries; // Extract LSA_REFERENCED_DOMAIN_LIST.Domains, by iterating over the array and marshalling // each native LSA_TRUST_INFORMATION into a managed LSA_TRUST_INFORMATION. Interop.LSA_TRUST_INFORMATION[] domains = new Interop.LSA_TRUST_INFORMATION[domainCount]; IntPtr pCurrentDomain = domainList.Domains; for (int i = 0; i < domainCount; i++) { domains[i] = (Interop.LSA_TRUST_INFORMATION)Marshal.PtrToStructure(pCurrentDomain, typeof(Interop.LSA_TRUST_INFORMATION)); pCurrentDomain = new IntPtr(pCurrentDomain.ToInt64() + Marshal.SizeOf(typeof(Interop.LSA_TRUST_INFORMATION))); } GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: got {0} groups in {1} domains", sidCount, domainCount); // // Build the list of entries // Debug.Assert(names.Length == sidCount); for (int i = 0; i < names.Length; i++) { Interop.LSA_TRANSLATED_NAME name = names[i]; // Build an entry. Note that LSA_UNICODE_STRING.length is in bytes, // while PtrToStringUni expects a length in characters. SidListEntry entry = new SidListEntry(); Debug.Assert(name.Name.Length % 2 == 0); entry.name = Marshal.PtrToStringUni(name.Name.Buffer, name.Name.Length / 2); // Get the domain associated with this name Debug.Assert(name.DomainIndex < domains.Length); if (name.DomainIndex >= 0) { Interop.LSA_TRUST_INFORMATION domain = domains[name.DomainIndex]; Debug.Assert(domain.Name.Length % 2 == 0); entry.sidIssuerName = Marshal.PtrToStringUni(domain.Name.Buffer, domain.Name.Length / 2); } entry.pSid = pSids[i]; _entries.Add(entry); } // Sort the list so they are oriented by the issuer name. // this.entries.Sort( new SidListComparer()); } finally { if (domainsHandle != null) { domainsHandle.Dispose(); } if (namesHandle != null) { namesHandle.Dispose(); } if (policyHandle != null) { policyHandle.Dispose(); } } }
private static IdentityReferenceCollection TranslateToNTAccounts(IdentityReferenceCollection sourceSids, out bool someFailed) { if (sourceSids == null) { throw new ArgumentNullException("sourceSids"); } if (sourceSids.Count == 0) { throw new ArgumentException(SR.Arg_EmptyCollection, "sourceSids"); } Contract.EndContractBlock(); IntPtr[] SidArrayPtr = new IntPtr[sourceSids.Count]; GCHandle[] HandleArray = new GCHandle[sourceSids.Count]; SafeLsaPolicyHandle LsaHandle = SafeLsaPolicyHandle.InvalidHandle; SafeLsaMemoryHandle ReferencedDomainsPtr = SafeLsaMemoryHandle.InvalidHandle; SafeLsaMemoryHandle NamesPtr = SafeLsaMemoryHandle.InvalidHandle; try { // // Pin all elements in the array of SIDs // int currentSid = 0; foreach (IdentityReference id in sourceSids) { SecurityIdentifier sid = id as SecurityIdentifier; if (sid == null) { throw new ArgumentException(SR.Argument_ImproperType, "sourceSids"); } HandleArray[currentSid] = GCHandle.Alloc(sid.BinaryForm, GCHandleType.Pinned); SidArrayPtr[currentSid] = HandleArray[currentSid].AddrOfPinnedObject(); currentSid++; } // // Open LSA policy (for lookup requires it) // LsaHandle = Win32.LsaOpenPolicy(null, PolicyRights.POLICY_LOOKUP_NAMES); // // Perform the actual lookup // someFailed = false; uint ReturnCode; ReturnCode = Interop.mincore.LsaLookupSids(LsaHandle, sourceSids.Count, SidArrayPtr, ref ReferencedDomainsPtr, ref NamesPtr); // // Make a decision regarding whether it makes sense to proceed // based on the return code and the value of the forceSuccess argument // if (ReturnCode == Interop.StatusOptions.STATUS_NO_MEMORY || ReturnCode == Interop.StatusOptions.STATUS_INSUFFICIENT_RESOURCES) { throw new OutOfMemoryException(); } else if (ReturnCode == Interop.StatusOptions.STATUS_ACCESS_DENIED) { throw new UnauthorizedAccessException(); } else if (ReturnCode == Interop.StatusOptions.STATUS_NONE_MAPPED || ReturnCode == Interop.StatusOptions.STATUS_SOME_NOT_MAPPED) { someFailed = true; } else if (ReturnCode != 0) { int win32ErrorCode = Interop.mincore.RtlNtStatusToDosError(unchecked ((int)ReturnCode)); Debug.Assert(false, string.Format(CultureInfo.InvariantCulture, "Interop.LsaLookupSids returned {0}", win32ErrorCode)); throw new Win32Exception(win32ErrorCode); } NamesPtr.Initialize((uint)sourceSids.Count, (uint)Marshal.SizeOf <Interop.LSA_TRANSLATED_NAME>()); Win32.InitializeReferencedDomainsPointer(ReferencedDomainsPtr); // // Interpret the results and generate NTAccount objects // IdentityReferenceCollection Result = new IdentityReferenceCollection(sourceSids.Count); if (ReturnCode == 0 || ReturnCode == Interop.StatusOptions.STATUS_SOME_NOT_MAPPED) { // // Interpret the results and generate NT Account objects // Interop.LSA_REFERENCED_DOMAIN_LIST rdl = ReferencedDomainsPtr.Read <Interop.LSA_REFERENCED_DOMAIN_LIST>(0); string[] ReferencedDomains = new string[rdl.Entries]; for (int i = 0; i < rdl.Entries; i++) { Interop.LSA_TRUST_INFORMATION ti = (Interop.LSA_TRUST_INFORMATION)Marshal.PtrToStructure <Interop.LSA_TRUST_INFORMATION>(new IntPtr((long)rdl.Domains + i * Marshal.SizeOf <Interop.LSA_TRUST_INFORMATION>())); ReferencedDomains[i] = Marshal.PtrToStringUni(ti.Name.Buffer, ti.Name.Length / sizeof(char)); } Interop.LSA_TRANSLATED_NAME[] translatedNames = new Interop.LSA_TRANSLATED_NAME[sourceSids.Count]; NamesPtr.ReadArray(0, translatedNames, 0, translatedNames.Length); for (int i = 0; i < sourceSids.Count; i++) { Interop.LSA_TRANSLATED_NAME Ltn = translatedNames[i]; switch ((SidNameUse)Ltn.Use) { case SidNameUse.User: case SidNameUse.Group: case SidNameUse.Alias: case SidNameUse.Computer: case SidNameUse.WellKnownGroup: string account = Marshal.PtrToStringUni(Ltn.Name.Buffer, Ltn.Name.Length / sizeof(char));; string domain = ReferencedDomains[Ltn.DomainIndex]; Result.Add(new NTAccount(domain, account)); break; default: someFailed = true; Result.Add(sourceSids[i]); break; } } } else { for (int i = 0; i < sourceSids.Count; i++) { Result.Add(sourceSids[i]); } } return(Result); } finally { for (int i = 0; i < sourceSids.Count; i++) { if (HandleArray[i].IsAllocated) { HandleArray[i].Free(); } } LsaHandle.Dispose(); ReferencedDomainsPtr.Dispose(); NamesPtr.Dispose(); } }