I'm using an ActiveDirectory server to query the groups that a user belongs to. I would like to get all the groups that a user belongs to, but using the Network Management funcions of the Network API.
I realized that already exist a function called NetUserGetGroups, but unfortunately, this function does not include the groups that a member indirect belongs to.
For example, if I have the following structure:
MyGroup1
|_ MyGroup2
|_ MyUser
MyGroup2
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;
}
This code returns:
MyGroup1 <-- this is what I need, loading the indirect groups!
MyGroup2
(and others)
The problem is that I'm using .NET2, and I cannot get access to the System.DirectoryServices. I only have access to the NetworkAPI.
Someone knows how could I implement the user.GetAuthorizationGroups()
call, using the NetworkAPI?
The solution is using the AuthzAPI. The following code loads the user groups for a given user SID. The results are the same that the user.GetAuthorizationGroups()
call retrieves:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With