Problems detecting if a macOS user is a local or domain account
As a software engineer working in the field of security, I needed to know if a user was that of the local machine, or a user authenticated by Active Directory.
The way in which accounts (users and groups) are identified by macOS(or Unix variants) differs from those under Windows
Windows associates a user account with a Security Identifier (SID), along with a user’s credentials; name and password.
In contrast, macOS is all about the uid (user id) and gid (group id), as is well known to those also familiar with Linux.
If macOS is connected to Active Directory, AD provides a uid / gid for a user account / group account respectively, during logon of the user session.
Under AD management, identity mapping could be performed with a GUI extension known as Identity Management for Unix (IDMU), though this tool has recently been marked as deprecated. However, adding the required attributes is still possible, even if managing the mapping is not as simple as with IDMU.
Using the BSD membership functions, it is possible to query information about a current user and retrieve the user’s SID in macOS.
As expected, with a uid of a domain account we can obtain the correct SID to that stored in Active Directory.
However, it’s not as simple as just seeing if the SID is returned to know if this is a domain account, as using the same functions on a local account also returns a SID, though I’m not sure why; perhaps it’s for Open Directory, which I don’t think anyone uses these days, at least not in the corporate world!
macOS groups
Various groups are provided by default on macOS, many of which have been around since the very early days of BSD, such as the wheel group, which pretty much denotes who can use su and sudo.
The Administrator’s group is rather self-explanatory!
Initially I thought that the staff group represents the list of all users, but this turns out not to be the case. If an AD user is logged on to macOS, they are not members of the staff group. Interestingly macOS has an odd way of listing membership of this group, as a Standard User has the staff group as its PrimaryGroupID, but iterating through the list of staff users fails to display them. I now realise that the the staff group is the group of local users.
macOS user id
Local Session users (those that can log into the system) have a uid > 500. The first user created starts with 501, the next 502 and so on. A uid less than 501 is reserved for system users, such as those for daemons.
If an AD user has a manual mapping, applied between its SID and uid (or gid), it’s possible to set almost any number. If left to its own devices, the uid tends to be very large. As described here, Dynamic allocation of UIDs and GIDs from LDAP are in the range of 7000 — 4,000,000,000.
Local or Domain account via assumption
It’s not a great solution, but as far as I can tell, it appears that the only way to check if a user or group account is that of a domain is by a set of assumptions, which are as follows: -
- All local session users have a uid greater than 500 (session user is a user that can log in, so this does not include users for daemon services)
- All daemon service users have a uid less than 501
- All local session users are members of the staff group
- Domain users are not, by default, members of the staff group
Put more simply, in pseudo code: -
if(uid <= 500 || (uid > 500 && userIsMemberOfStaffGroup(uid))
{
user = local;
}
else
{
user = domain;
}
This is not foolproof!
Using assumptions is a poor method of classifying the user as being a local or domain account. If connected to a domain, the above assumptions appear to hold true.
However, in the case of a mobile (roaming) user, who may not be able to connect to the domain controller at the time of logging into their session, the SIDs of Domain Groups to which they belong cannot be retrieved and no SID is returned.
macOS does cache known SIDs, but the cache can be cleared, or if the AD controller is not available, it may be out of sync.
In conclusion, I’m hoping I’ve missed a glaring observation and someone can point out a simple method of classifying the user, but at present, there appears not to be a better solution.