joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

Setting the primary group with LDAP

by @ 2:21 am on 12/13/2005. Filed under tech

A friend of mine and fellow MVP named Laura Hunter (www.shutuplaura.com) is working on the new edition of the Active Directory Cookbook and has been pinging me with various AdFind/AdMod questions and well anything else that happens to come up. I guess if you want to know what makes the horse tick you walk up and ask the horse, I am fine with that, I am a chatty horse at times. Actually I prefer it, if you are going to write about one of my tools, feel free to email me about it and I will usually spend time helping out as needed. That way I don’t have to see a set of switches documented incorrectly or described wrong or a command line example that isn’t quite right.

Anyway, she ran into an error when setting the primary group with ADMOD and I thought it was worth writing up for others as it isn’t really something that is well known.

Basically the problem was that setting the primaryGroupID attribute on a user was causing an “unwilling to perform” error to pop up. When you enable the extended error information with the -exterr option you get something like


Error 0x35 (53) - Unwilling To Perform
Extended Error: 00000529: SvcErr: DSID-031A0FC0, problem 5003 (WILL_NOT_PERFORM), data 0

The specifics of the DSID error are not usually useful to most people who don’t have source code access. If you have source access, it tell you the line of code that threw the error so you can chase into it. The part of the message that is useful to nearly anyone though is the first set of numbers… 00000529… If you throw this through ERR it will output various possible issues that could be causing the “unwilling to perform” generic message.

So ERR tells me the following:


[Tue 12/13/2005 2:05:17.79]
F:\DEV\cpp\ExchMbx>err 529
# for decimal 529 / hex 0x211 :
SE_AUDITID_UNKNOWN_USER_OR_PWD msaudite.h
# Logon Failure:%n
# %tReason:%t%tUnknown user name or bad password%n
# %tUser Name:%t%1%n
# %tDomain:%t%t%2%n
# %tLogon Type:%t%3%n
# %tLogon Process:%t%4%n
# %tAuthentication Package:%t%5%n
# %tWorkstation Name:%t%6%n
# %tCaller User Name:%t%7%n
# %tCaller Domain:%t%8%n
# %tCaller Logon ID:%t%9%n
# %tCaller Process ID:%t%10%n
# %tTransited Services:%t%11%n
# %tSource Network Address:%t%12%n
# %tSource Port:%t%13%n
SQL_529_severity_16 sql_err
# Explicit conversion from data type %ls to %ls is not
# allowed.
# for hex 0x529 / decimal 1321 :
ERROR_MEMBER_NOT_IN_GROUP winerror.h
# The specified user account is not a member of the specified
# group account.
# 3 matches found for "529"

If you look through them you see ERROR_MEMBER_NOT_IN_GROUP. This is promising since we are working with group membership. So the error it gives for being unwilling to perform is that the user isn’t in the group. True, we are trying to add the member to the group.

Well here is the core of the issue. You can’t add a user to a group by modifying the primaryGroupID attribute, you can only set it to values of groups that the user is already a member of… But why? If you are thinking out several steps you already know why, or at least a good logical reason that I think is the why though I never verified it with anyone because if it isn’t the reason why, it really should be….

You can configure any person you want to be able to modify a user object. As soon as someone has full control or owner rights or permission change rights on a user, they can do just about anything they want to to that user including changing the primary group. Now how bad would it be if someone takes a normal user and just writes in a value of say… I don’t know… 512 into the primaryGroupID. What would that do? Well it would add the normal user to Domain Admins. That would be a bit of a security hole. So when you change the primaryGroupID attribute, the first thing AD does is make sure that the user is in the group. If not, it rejects the change. Otherwise someone who has the ability to manipulate a user could also magically manipulate groups, very important groups.

So in order to change a person’s primary group with an LDAP tool (ADMOD or other), you must add the user to the group you want to set as primary, then afterward, change the primaryGroupID value, and then if you want, remove the user from the old primary group.

admod -b cn=domain admins,cn=users,dc=dom,dc=com member:+:cn=someuser,ou=someou,dc=dom,dc=com
admod -b cn=someuser,ou=someou,dc=dom,dc=com primaryGroupID::512
admod -b cn=domain users,cn=users,dc=dom,dc=com member:-:cn=someuser,ou=someou,dc=dom,dc=com

Those three commands would add a user to domain admins, set that as their primary group, and removes them from domain users. I don’t generally recommend removing users from domain users (or even setting a primary group of domain admins) but it is good example for illustration.

joe

Rating 3.50 out of 5

9 Responses to “Setting the primary group with LDAP”

  1. Kamlesh says:

    joe,

    I never actually found the use of PrimaryGroupID?
    if you look at MSDN description for this attribute, it says “This property is not used in the context of the Active Directory.”

    What I get when I search for it is that, it is useful only if AD user accounts and membership is used to manage Unix based systems, where they have a concept of Primary Group. And while working within Windows realm, it always looks at actual group memberships and primaryGroupID is ignored.

    Can you throw some light on this stuff?

    As always, appreciate your knowledge sharing.

    Cheers,
    Kamlesh

  2. joe says:

    That is the normal use of it, for UNIX based or Apple systems. However I have seen many ported applications that continue that mentality even though they now run on Windows. Just easier to do it that way or to maintain consistency across versions of the apps.

    PrimaryGroup is certainly not ignored though… Add yourself to domain admins and then make it your primary group. It will disappear from the normal membership list but I can assure you you are still a domain admin. This is something many people miss when auditing domain admin membership in fact.

  3. Dean Wells says:

    One key point worth a mention here is that the group represented by the RID of the (user-in-question’s) primaryGroupID property is not impacted by the Windows 2000 and non-2K3-native 5000 member limitation (recommendation) since the relationship is known only to the user (and not collectively to the group’s member property). This facility is exploited by Windows 2000 and Windows 2003 in order to permit a more scalable number of user’s default-membership within the “Domain Users” group.

  4. Kamlesh says:

    joe,

    I tested as you mentioned, it only disappeared from appearing in DSQUERY / adfind /adsiedit tool for listing member ship of domain admins.
    It did NOT go away, when I checked membership using ADUC or
    net group “domain admins” /domain

    I wonder, how ADUC picked it, while others who (dsquery,adsiedit) list the members as DN missed it.

    and luckily I use, “net group” command to record the membership history.[1]

    And importantly, It also didn’t allow me to change primarygroupid of account without making it member of “domain admins” OR remove userid from “domain admins” while keeping user’s primarygroup as “domain admins”, I tried this using, ADUC, admod , net group and adsiedit.msc

    So, I guess, only threat remaining in this case would be directly changing it in DB while logged in as SYSTEM on DC. As all other methods will use standard API’s where API would do some sanity check.
    (I guess directly editing DB should be hard enough, as DB itself keeps integrity checks)

    And for that purpose, I don’t give user right “act as part of operating system” to anyone including administrators. Again this can be circumvented but, one more hill for attacker to cross.

    Also, I have included a query in my daily routine to check users having primarygroupid =512 (finger crossed, I hope i never see anyone there)
    same for other groups like EA,BO,SO,PO

    I hope this measures are enough against someone using primarygroup ?

    [1] I know you have argued that things can be changed in DC and reverted back so fast that membership change never gets recorded.

    Cheers,
    Kamlesh

  5. joe says:

    Correct, it is still a member, however, as you notice, it disappears from the member attribute of the group and the memberof (backlink) attribute of the user. This is because, as Dean indicated, the membership of a primary group is maintained in a different attribute and is specifically designed to get around the limitation from Windows 2000 AD with group sizes. That is why the LDAP mechanisms don’t see it as a member because they specifically enumerate the member attribute.

    Careful with using NET GROUP, it depends on the legacy API which does not have visualization into same scope group nesting which can occur in native mode. Also NET GROUP doesn’t catch domain localgroup and builtin group memberships such as administrators, etc.

    BTW, just checking for users who have primary group 512 doesn’t necessarily catch everyone. Consider the case of someone in Global Group X as their primary and that group is nested in Domain Admins. NET GROUP (nor any mechanism using the legacy NBET API) will not show that relationship and the primary group ID will not be 512, it will be the RID of whatever the primary group actually is.

    joe

  6. Kamlesh says:

    joe,

    Why did ADUC picked it up, as it also shows the membership as DN, and I assume it looks at members attribute.

    I didn’t mention it specifically, but I assume WinNT provider would take care of group scope.

    Also, I checked my query list again, and found that, I have a query where it checks for primarygroupid 513 and lists username,primarygroupid

    Now, i have to find what group this primarygroupid is associated with, for that I can see, primarygrouptoken attribute on group.
    Sad part is it says, it is COMPUTED, so can’t use it in query to find the specific group.

    Kamlesh

  7. joe says:

    ADUC has special code to grab the primaryGroupID and resolve it to a DN. The info for the primary group is absolutely not in the member attribute. My memberof tool shows primary group membership as well and I can assure you it doesn’t get it from memberof or member.

    WinNT provider uses the NET API so has the same limitations as the NET API and will not see (or more accurately handle) anything that isn’t legal in NT4.

    513 is Domain Users. Not sure why you are checking that but ok…

    Correct, primarygrouptoken is computed and can’t be queried. You need to take the primarygroupid, prepend the SID of the domain, then do a SID lookup. Alternately, you can load up the RIDs of all groups into a table and do a lookup. The former is much faster unless you only have a couple of groups though.

    joe

  8. DaveC says:

    So I’ve seen this particular subject get a bunch of attention and I’m curious to know if the conclusion I’ve reached is pretty much the consensus [at this point in time at least!]:

    The ADUC GUI seems to be the most reliable way to retrieve ALL of the members of the group Domain Admins, including users with primaryGroupID=512 (to use that example), but the caveats are:

    1) You have to the chase the nestings on your own
    2) You can’t easily get the output OUT of the GUI nicely (like you can with command line tools). Sorry if it can be had easily and I just haven’t played with the GUI nearly enough!

    If I’ve summed this up correctly (and I know that may be a big IF), then I’d say that stinks beyond belief!

  9. joe says:

    The best is a script I have that I can’t share for various reasons as it does the stuff you mention. ;o)

    At some point I hope to make it into an executable and release, I basically just need to rewrite it without looking at it. 🙂

    The group story has always been a bad one with AD in terms of trying to easily resolve membership.

[joeware – never stop exploring… :) is proudly powered by WordPress.]