-1

I use pinvoke implementations of LookupAccountSid in managed C# code for several years.

On a German Windows Server 2016 it starts throwing an System.AccessViolationException when resolving S-1-5-11 (Authenticated users) where the German name is: "NT-Authorität\Authentifizierte Benutzer".

I tested 3 different impementations to rule out an pinvoke error. They all throw at the same call.

  1. From the github vanara project and my discussion with the author
  2. First SO implementation
  3. Second SO implementation where I can't find the source at the moment.

They all throw the same exception so it may be a general problem in the api. Probably because of the umlaut Ä in the name?

Similar question at SO

This question sounds similar but this is not the problem I face.

My expirience in earlier projects

I used the implementation from (2.) years ago in a Windodws 7 / Server 2008 environment without any problems, but unfortunatelly I currently have no such systems to verify my recent code.

Similar reported issue

I found this thread regarding a similar behaviour on a french system

My current workaround is

ntAccountName = realSid.Translate(typeof(NTAccount)).ToString();
AdvApi32.LookupAccountName(systemName, ntAccountName, out foundSid, out domainName, out sidNameUse)

But sid.Translate(..) throws when passing a foreign principal an I don't know how reliable it is in other cases.

Questions

  • Is there any known issue with this api and how to solve it?
  • Is there any other workaround? (The LsaLookupSids can't be uses because the do not return the SID_NAME_USE flags)
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52
  • `LsaLookupSids[2]` of course can be and must be used. it return `SID_NAME_USE` flags - and note - this api anyway always internally called when you call `LookupAccountSid` but much more better call it direct – RbMm Dec 08 '20 at 11:10
  • 1
    but it inside [`LSA_TRANSLATED_NAME`](https://learn.microsoft.com/en-us/windows/win32/api/lsalookup/ns-lsalookup-lsa_translated_name) and can believe me - direct call to this api - much more better compare call to `LookupAccountSid`.. the `LsaLookupSids` always called internally and allocate memory by self. what sense ask you allocate additional memory by self, copy data from one buffer to another. i already not say about case when need lookup more than 1 sid or more than once – RbMm Dec 08 '20 at 11:21
  • 1
    need understand that `LookupAccountSid` only very bad designed shell over `LsaLookupSids[2]` – RbMm Dec 08 '20 at 11:23
  • @RbMm Thanks, I will test it! – marsh-wiggle Dec 08 '20 at 11:24
  • 1
    `LsaLookupSids` much more easy to use, because it allocated memory for you and you not need allocate unknown size buffers yourself. call twice (for get required buffer size is costly in case this rpc api). also if you need lookup multiple sids - you can do this by single call with Lsa version. if need do several query - you can open *PolicyHandle* only once but not every time. but main in your case - much more easy and fast memory managment – RbMm Dec 08 '20 at 11:30

2 Answers2

1

I wrote the following, using the Vanara libraries and @RbMm's comments, to mimic the LookupAccountSid functionality using LsaLookupSids.

private static NTStatus LookupAccountSid2([Optional] string lpSystemName, PSID lpSid, out string lpName,
   out string lpReferencedDomainName, out SID_NAME_USE peUse)
{
   lpName = lpReferencedDomainName = null;
   peUse = default;
   using var pol = LsaOpenPolicy(LsaPolicyRights.POLICY_LOOKUP_NAMES, lpSystemName);
   var ret = LsaLookupSids2(pol, LsaLookupSidsFlags.LSA_LOOKUP_RETURN_LOCAL_NAMES, 1, new[] { lpSid }, out var refDom, out var names);
   if (ret.Failed) return ret;
   using (refDom)
   using (names)
   {
      lpReferencedDomainName = refDom.ToStructure<LSA_REFERENCED_DOMAIN_LIST>().DomainList.First().Name;
      var name = names.ToArray<LSA_TRANSLATED_NAME>(1)[0];
      lpName = name.Name;
      peUse = name.Use;
   }
   return ret;
}
dahall
  • 318
  • 3
  • 6
0

For those who are not familiar with the vanara library and how to convert a SecurityIdentifier to a PSID pointer here is a wrapper for the accepted answer. To use the library just get the nuget package Vanara.AdvApi32

using Vanara.PInvoke;

public static bool LookupAccountSid2(string lpSystemName, SecurityIdentifier sid, out string samAccountName,
       out string domainName, out AdvApi32.SID_NAME_USE useFlags)
{
    using (AdvApi32.SafePSID safePSID = new AdvApi32.SafePSID(sid))
    {
        PSID lpSid = new PSID(safePSID);

        /// call the actual implementation from: https://stackoverflow.com/a/65202841/1574221
        return LookupAccountSid2(lpSystemName, lpSid, out samAccountName, out domainName, out useFlags);
    }
}
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52
  • 1
    There is a constructor for `SafePSID` that takes a `SecurityIdentiifer` so you can do: `new SafePSID(sid)` in your example rather than converting to a string. – dahall Dec 09 '20 at 14:31