'Reading the SECURITY_ENABLED flag of Group in Active Directory
I'm trying to read the SECURITY_ENABLED flag of a groups groupType property. The problem is that the value I retreive by using
DirectoryEntry entry...
entry.Properties["groupType"].Value;
is an int32
, whose range is -2,147,483,647 to 2,147,483,648 (or -0x7FFFFFFF to 0x80000000)
So anytime there is the GROUP_TYPE_SECURITY_ENABLED
and any other arbitraty flag set, the numeric value exceeds the the range of an int32 and an overflow happens.
Does anyone know how to avoid this overflow in order to read the correct value?
Solution 1:[1]
I think you need to use UInt32
as the type of your enumeration GroupType
as follows:
[Flags]
public enum GroupType : uint
{
BUILTIN_LOCAL_GROUP = 0x00000001,
ACCOUNT_GROUP = 0x00000002,
RESOURCE_GROUP = 0x00000004,
UNIVERSAL_GROUP = 0x00000008,
APP_BASIC_GROUP = 0x00000010,
APP_QUERY_GROUP = 0x00000020,
SECURITY_ENABLED = 0x80000000
}
Let me know if that solves your problem.
EDIT: OK, I wasn't sure if Entry
was an object you created, or part of the Active Directory API. Having said that, I quick created the following variables in a project I'm currently working on and compiled as follows:
// I only made it static so I could get my compiler to compile this in something I'm currently
// working on. It's not necessary for it to be static.
static int SECURITY_ENABLED = 0x80000000;
int newValue = SECURITY_ENABLED | 1;
I did not get any compile-time errors. In fact, re-looking at the value 0x80000000
, it's well with in the range of an Int32
.
Re-looking at your code above, on what line exactly, are you getting the error? I see this suspicios code:
if (groupTypes.Count == 1)
{
var firstFlag = (int) groupTypes[0];
// What is this checking, exactly?
// Is this where the error is occurring?
var longFlag = -(((long) flag) - firstFlag);
if ((longFlag == 0x80000000)) // Extra parentheses here...just a formatting thing
groupTypes.Add(GroupType.SECURITY_ENABLED);
}
Perhaps this code could be simplified?
public List<GroupType> GetGroupType()
{
var groupTypes = new List<GroupType>();
var flag = (GroupType) this.Entry.Properties["groupType"].Value;
if (flag & GroupType.ACCOUNT_GROUP > 0)
groupTypes.Add(GroupType.ACCOUNT_GROUP;
else if (flag & GroupType.APP_BASIC_GROUP > 0)
groupTypes.Add(GroupType.APP_BASIC_GROUP);
// ... Other else if ad nauseum ...
else if (flag & GroupType.SERUCITY_ENABLED > 0)
groupTypes.Add(GroupType.SECURITY_ENABLED);
return groupTypes;
}
If you really need an ArrayList()
for whatever reason, you could then just do return groupTypes.ToArray<int>();
HTH.
Solution 2:[2]
Referencing @fourpastmidnight's answer and these articles object-group-attribute-grouptype and msdn Group-Type attribute, I was able to find a solution that does not require casting to uint
or parsing through an if ... else if
statement.
Seeing the negative values from the first link and from @wodzu's comment on the return value of -2147483646, I tried inverting the SECURITY_ENALBED value to -0x80000000.
[System.Flags]
public enum GroupType
{
BUILTIN_LOCAL_GROUP = 0x00000001,
ACCOUNT_GROUP = 0x00000002,
RESOURCE_GROUP = 0x00000004,
UNIVERSAL_GROUP = 0x00000008,
APP_BASIC_GROUP = 0x00000010,
APP_QUERY_GROUP = 0x00000020,
SECURITY_ENABLED = -0x80000000
}
Now when getting the value and casting as GroupType
var groupType = (GroupType)this.Entry.Properties["groupType"].Value
You can then use .ToString() on the GroupType value which will return a comma separated string of each flag.
Or you can use the .HasFlag method to check if it is a Security Group
bool IsSecurityGroup = groupType.HasFlag(GroupType.SECURITY_ENABLED);
Solution 3:[3]
A little Python to decode groupType AD attribute value
prepare a dictionary with all the defined combination. (ref. Microsoft
gt_decode_dict = { "0x00000001": "SYSTEM CREATED", # Specifies a group that is created by the system. "0x00000002": "GLOBAL", # Specifies a group with global scope. "0x00000004": "LOCAL", # Specifies a group with domain local scope. "0x00000008": "UNIVERSAL", # Specifies a group with universal scope. "0x00000010": "APP_BASIC", # Specifies an APP_BASIC group for Windows Server Authorization Manager. "0x00000020": "APP_QUERY", # Specifies an APP_QUERY group for Windows Server Authorization Manager. "0x80000000": "SECURITY"} # Specifies a security group. If this flag is not set, then the group is a distribution group.
define a function to decode the groupType value
def decode_gt(_group_type): # # Decode groupType attribute. # global gt_decode_dict _delta = 0 _translatedGT = "" if _group_type > 0: _hex_gt = hex(_group_type) _gt_work = int(_hex_gt[2:]) _gt_work = str(_gt_work).rjust(8, "0") _gt_key = r'0x' + str(_gt_work) _translatedGT += "DISTRIBUTION - " else: _delta = 2147483648 - abs(_group_type) if (_delta % 2) > 0: _translatedGT = "SECURITY - SYSTEM CREATED - " _gt_key = r'0x' + str(_delta - 1).rjust(8, "0") else: _translatedGT = "SECURITY - " _gt_key = r'0x' + str(_delta).rjust(8, "0") if _gt_key in gt_decode_dict.keys(): _translatedGT += gt_decode_dict[_gt_key] else: notification(" Invalid groupType key: " + str(_gt_key) + ". Values dec: " + str(_group_type) + " delta:" + str(_delta) + ", for group " + _group_dn, 4) _translatedGT += " Error " return _translatedGT
call the function passing the groupType as an Integer
groupType = decode_gt(int(_groupType))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 |