如何使用Network API获取用户组

时间:2014-03-13 13:48:54

标签: c# winapi active-directory directoryservices

我使用ActiveDirectory服务器查询用户所属的组。我想获取用户所属的所有群组,但使用网络API的Network Management funcions

我意识到已存在一个名为NetUserGetGroups的函数,但遗憾的是,此函数不包含成员间接所属的组。

实施例

例如,如果我有以下结构:

MyGroup1
   |_ MyGroup2
          |_ MyUser

使用 NetUserGetGroups 调用将返回:

MyGroup2

使用 System.DirectoryServices.AccountManagement ,将返回:

    public static List<string> GetUserGroupsAD(string dc, string userName)
    {
        var result = new List<string>();
        try
        {
            using (var context = new PrincipalContext(
                   ContextType.Domain, dc.Replace("\\", "")))
            {
                var user = UserPrincipal.FindByIdentity(context, userName);
                var groups = user.GetAuthorizationGroups();
                foreach (Principal p in groups2)
                    result.Add(p.Name);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("An error happened in GetUserGroups", ex);
        }

        return result;
    }

此代码返回:

MyGroup1 <-- this is what I need, loading the indirect groups!
MyGroup2
(and others)

问题是我使用.NET2 ,我无法访问System.DirectoryServices。我只能访问NetworkAPI。

我的问题

有人知道如何使用NetworkAPI实现user.GetAuthorizationGroups()调用?

1 个答案:

答案 0 :(得分:5)

解决方案是使用AuthzAPI。以下代码加载给定用户SID的用户组。结果与user.GetAuthorizationGroups()调用检索的结果相同:

    static List<string> GetSidGroupsFromSid(sbyte[] sid_bytes)
    {
        List<string> result = new List<string>();

        IntPtr clientContext = IntPtr.Zero;
        IntPtr resourceManager = IntPtr.Zero;
        IntPtr buffer = IntPtr.Zero;
        LUID unusedLuid = new LUID();
        bool success;
        try
        {
            success = AuthzInitializeResourceManager(
                (int)AuthzResourceManagerFlags.NO_AUDIT,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                string.Empty,
                out resourceManager);

            ThrowLastError(success);

            success = AuthzInitializeContextFromSid(
                (int)AuthzContextFlags.NONE,
                sid_bytes, resourceManager,
                IntPtr.Zero, unusedLuid,
                IntPtr.Zero,
                out clientContext);

            ThrowLastError(success);

            int pSizeRequired = 0;
            success = AuthzGetInformationFromContext(
                clientContext,
                (int)AuthContextInformation.AuthzContextInfoGroupsSids,
                0,
                out pSizeRequired,
                IntPtr.Zero);

            if (!success && pSizeRequired > 0 && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
            {
                buffer = Marshal.AllocHGlobal(pSizeRequired);
                success = AuthzGetInformationFromContext(clientContext, 2, pSizeRequired, out pSizeRequired, buffer);
                ThrowLastError(success);

                TOKEN_GROUPS groups = ((TOKEN_GROUPS)Marshal.PtrToStructure(buffer, typeof(TOKEN_GROUPS)));
                IntPtr ptr = new IntPtr(buffer.ToInt64() + (long)Marshal.SizeOf(typeof(TOKEN_GROUPS)) - (long)Marshal.SizeOf(typeof(IntPtr)));
                for (int index = 0; index < groups.groupCount; ++index)
                {
                    SID_AND_ATTR currentSid = (SID_AND_ATTR)Marshal.PtrToStructure(ptr, typeof(SID_AND_ATTR));
                    ptr = new IntPtr(ptr.ToInt64() + (long)Marshal.SizeOf(typeof(SID_AND_ATTR)));
                    string sidString = "";
                    NetWorkAPI.ConvertSidToStringSid(currentSid.pSid, ref sidString);
                    result.Add(sidString);
                }
            }
        }
        finally
        {
            if (clientContext != IntPtr.Zero)
            {
                success = AuthzFreeContext(clientContext);
                ThrowLastError(success);
            }
            if (resourceManager != IntPtr.Zero)
            {
                success = AuthzFreeResourceManager(resourceManager);
                ThrowLastError(success);
            }
            if (buffer != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        return result;
    }

    static void ThrowLastError(bool success)
    {
        if (success)
            return;

        int err = Marshal.GetLastWin32Error();
        Win32Exception win32Exception = new Win32Exception(err);
        throw new Exception("Authz error " + err + ": " + win32Exception.Message);
    }

    const int ERROR_INSUFFICIENT_BUFFER = 122;

    [Flags]
    enum AuthzResourceManagerFlags : int
    {
        NONE = 0,
        NO_AUDIT = 0x1,
        INITIALIZE_UNDER_IMPERSONATION = 0x2,
        VALID_INIT_FLAGS = (NO_AUDIT | INITIALIZE_UNDER_IMPERSONATION),
    };

    [Flags]
    enum AuthzContextFlags : int
    {
        NONE = 0,
        SKIP_TOKEN_GROUPS = 0x2,
        REQUIRE_S4U_LOGON = 0x4,
        COMPUTE_PRIVILEGES = 0x8
    };

    [StructLayout(LayoutKind.Sequential)]
    struct LUID
    {
        public uint LowPart;
        public int HighPart;
    };

    enum AuthContextInformation : int
    {
        AuthzContextInfoUserSid = 1,
        AuthzContextInfoGroupsSids = 2
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    sealed class TOKEN_GROUPS
    {
        public int groupCount;
        public IntPtr groups = IntPtr.Zero;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    sealed class SID_AND_ATTR
    {
        public IntPtr pSid = IntPtr.Zero;
        public int attrs;
    }

    [DllImport(
        "authz.dll",
        CharSet = CharSet.Unicode,
        CallingConvention = CallingConvention.StdCall,
        SetLastError = true)]
    static extern bool AuthzInitializeResourceManager(
        int flags,
        IntPtr pfnAccessCheck,
        IntPtr pfnComputeDynamicGroups,
        IntPtr pfnFreeDynamicGroups,
        string name,
        out IntPtr rm);

    [DllImport(
        "authz.dll",
        CharSet = CharSet.Unicode,
        CallingConvention = CallingConvention.StdCall,
        SetLastError = true)]
    static extern bool AuthzInitializeContextFromSid(
        int Flags,
        sbyte[] userSid,
        IntPtr AuthzResourceManager,
        IntPtr pExpirationTime,
        LUID Identitifier,
        IntPtr DynamicGroupArgs,
        out IntPtr pAuthzClientContext);

    [DllImport(
        "authz.dll",
        CharSet = CharSet.Unicode,
        CallingConvention = CallingConvention.StdCall,
        SetLastError = true)]
    static extern bool AuthzGetInformationFromContext(
        IntPtr hAuthzClientContext,
        int InfoClass,
        int BufferSize,
        out int pSizeRequired,
        IntPtr Buffer);

    [DllImport(
        "authz.dll",
        CharSet = CharSet.Unicode,
        CallingConvention = CallingConvention.StdCall)]
    static extern bool AuthzFreeContext(
        IntPtr AuthzClientContext);

    [DllImport(
        "authz.dll",
        CharSet = CharSet.Unicode,
        CallingConvention = CallingConvention.StdCall)]
    static extern bool AuthzFreeResourceManager(IntPtr rm);