Search code examples
c#c++winapipinvokeaccess-violation

LookupAccountSid() throws System.AccessViolationException on Server 2016


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)

Solution

  • 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;
    }