代码之家  ›  专栏  ›  技术社区  ›  Andrew Cooper

如何检查ntaccount对象是否表示组或用户?

  •  4
  • Andrew Cooper  · 技术社区  · 15 年前

    使用返回的访问规则时

    GetAccessRules(True, True, GetType(System.Security.Principal.NTAccount))
    

    如何判断每个规则中引用的ntaccount对象是用户帐户还是组?

    更新:

    我能解决这个问题,如下所示。注意,此代码的目的是返回 True 如果 NTAccount 是一个群体, False 否则,或者在检查过程中发生错误。

    有更好的方法吗?

    Public Function IsGroup(ByVal account As NTAccount) as Boolean  
        Dim samAccountName as string = account.Value  
        Dim accountNameParts() As String = samAccountName.Split("\")  
        If accountNameParts.Count() = 2 Then  
            Dim principalContext As PrincipalContext  
            Try  
                principalContext = New PrincipalContext(ContextType.Domain, accountNameParts(0))  
            Catch  
                Try  
                    principalContext = New PrincipalContext(ContextType.Machine, accountNameParts(0))  
                Catch  
                    principalContext = Nothing  
                End Try  
            End Try  
            If Not principalContext Is Nothing Then  
                Dim principal As Principal  
                principal = principal.FindByIdentity(principalContext, _samAccountName)  
                If Not principal Is Nothing then   
                    return TypeOf principal Is GroupPrincipal  
                End If  
            End If  
        End If  
        Return False  
    End Function
    

    另一个更新:

    对于大多数服务器\帐户对象,上述解决方案都是可以的,但对于我们拥有的EMC Celerra NAS服务器上的本地组对象,则会失败。我正在尝试使用netusergetinfo/netlocalgroupgetinfo win api调用来查看这是否有效,但是我无法让它们正常工作。见 NetUserGetInfo/NetLocalGroupGetInfo returning error 1722 了解更多详细信息。

    2 回复  |  直到 12 年前
        1
  •  3
  •   Terry Tsay    12 年前

    我遇到了和你一样的问题。在到处做了一些研究之后,我终于找到了一个很好的解决方案:想法是使用winapi lookupaccountsid。 我已经对域和本地帐户进行了测试。 域\用户、NT权限\系统、计算机名\管理员都可以工作。 请注意,我不会在那里进行任何异常处理。你可以判断什么样的处理方式可以被你的场景接受。要获取异常,可以使用System.Runtime.InteropServices.Marshal.GetLastWin32Error()。

    public enum PrincipalType
    {
        User,
        Group
    }
    public bool TryGetPrincipalType(string domainQualifiedName, out PrincipalType type)
    {
            var name = new StringBuilder();
            var cchName = (uint) name.Capacity;
            var referencedDomainName = new StringBuilder();
            var cchReferencedDomainName = (uint) referencedDomainName.Capacity;
            SID_NAME_USE sidType;
    
            var account = new NTAccount(domainQualifiedName);
    
            var id = new SecurityIdentifier(account.Translate(typeof (SecurityIdentifier)).Value);
            var sidBuffer = new byte[id.BinaryLength];
            id.GetBinaryForm(sidBuffer, 0);
    
            if (LookupAccountSid(null, sidBuffer, name, ref cchName, referencedDomainName,
                                 ref cchReferencedDomainName, out sidType))
            {
                switch (sidType)
                {
                    case SID_NAME_USE.SidTypeGroup:
                    case SID_NAME_USE.SidTypeWellKnownGroup:
                    case SID_NAME_USE.SidTypeAlias:
                        type = PrincipalType.Group;
                        return true;
                    case SID_NAME_USE.SidTypeUser:
                        type = PrincipalType.User;
                        return true;
                }
            }
            type = default(PrincipalType);
            return false;
        }
    private enum SID_NAME_USE
    {
        SidTypeUser = 1,
        SidTypeGroup,
        SidTypeDomain,
        SidTypeAlias,
        SidTypeWellKnownGroup,
        SidTypeDeletedAccount,
        SidTypeInvalid,
        SidTypeUnknown,
        SidTypeComputer
    }
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool LookupAccountSid(
            string lpSystemName,
            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
            StringBuilder lpName,
            ref uint cchName,
            StringBuilder ReferencedDomainName,
            ref uint cchReferencedDomainName,
            out SID_NAME_USE peUse);
    
        2
  •  2
  •   Andrew Cooper    14 年前

    答案确实是使用Windows API( NetUserGetInfo NetLocalGroupGetInfo )

    Class NetApi
        Private Declare Unicode Function NetUserGetInfo Lib "Netapi32.dll" ( _
             ByVal ServerName As String, _
             ByVal UserName As String, _
             ByVal level As Integer, _
             ByRef BufPtr As IntPtr) As Integer
    
        Private Declare Unicode Function NetLocalGroupGetInfo Lib "Netapi32.dll" ( _
             ByVal ServerName As String, _
             ByVal GroupName As String, _
             ByVal level As Integer, _
             ByRef BufPtr As IntPtr) As Integer
    
        Declare Unicode Function NetApiBufferFree Lib "netapi32.dll" _
        (ByRef buffer As IntPtr) As Long
    
        Public Shared Function PrincipalIsGroup(ByVal MachineName As String, ByVal AccountName As String) As String
            If String.IsNullOrEmpty(MachineName) Then
                Throw New ArgumentException("MachineName is Required")
            End If
            If String.IsNullOrEmpty(AccountName) Then
                Throw New ArgumentException("AccountName is Required")
            End If
            Dim returnValue As String = "NotFound"
            Dim bufPtr As IntPtr
            Dim lngReturn As Integer = NetLocalGroupGetInfo("\\" & MachineName, AccountName, 0, bufPtr)
            Call NetApiBufferFree(bufPtr)
            bufPtr = IntPtr.Zero
            If lngReturn = 0 Then
                returnValue = "True"
            Else
                lngReturn = NetUserGetInfo("\\" & MachineName, AccountName, 0, bufPtr)
                Call NetApiBufferFree(bufPtr)
                bufPtr = IntPtr.Zero
                If lngReturn = 0 Then
                    returnValue = "False"
                End If
            End If
            Return returnValue
        End Function
    End Class