Question

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)

quickWatch

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.

groupTypeScreen

Does anyone know how to avoid this overflow in order to read the correct value?

Was it helpful?

Solution 2

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.

OTHER TIPS

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);

A little Python to decode groupType AD attribute value

  1. 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.
    
  2. 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
    
  3. call the function passing the groupType as an Integer

    groupType = decode_gt(int(_groupType))

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top