LookupAccountSid() 在 Server 2016 上抛出 System.AccessViolationException

LookupAccountSid() throws System.AccessViolationException on Server 2016

我在托管 C# 代码中使用 LookupAccountSid 的 pinvoke 实现多年。

German Windows Server 2016 上,它在解析 S-1-5-11(经过身份验证的用户)时开始抛出 System.AccessViolationException,其中德语名称为:“NT-Authorität\Authentifizierte Benutzer”。

我测试了 3 种不同的实现 来排除 pinvoke 错误。他们都在同一个电话上抛出。

  1. From the github vanara project and my discussion with the author
  2. 我目前找不到源的第二个 SO 实现。

它们都抛出相同的异常,所以这可能是 api 中的一个普遍问题。可能是因为名称中的元音变音 Ä?

SO

的类似问题

听起来很相似,但这不是我面临的问题。

我在早期项目中的经验

我在 Windodws 7 / Server 2008 环境中使用 (2.) 年前的实现没有任何问题,但不幸的是我目前没有这样的系统来验证我最近的代码。

报告的类似问题

我在 french system

上找到了关于类似行为的帖子

我目前的解决方法是

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

但是 sid.Translate(..) 在传递外国委托人时会抛出异常,我不知道它在其他情况下的可靠性如何。

问题

我使用 Vanara libraries 和@RbMm 的评论编写了以下内容,以使用 LsaLookupSids.

模仿 LookupAccountSid 功能
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;
}

对于那些不熟悉 vanara 库以及如何将 SecurityIdentifier 转换为 PSID 指针的人,这里是 的包装器。要使用该库,只需获取 nuget 包 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: 
        return LookupAccountSid2(lpSystemName, lpSid, out samAccountName, out domainName, out useFlags);
    }
}