Hybrid Private Groups for LDAP and AD domains¶
Problem statement¶
This change will augment the auto_private_groups
option which currently
is a boolean option with a third mode that would, for users whose uidNumber
has the same value as the gidNumber
attribute and no group exists in
LDAP that has the same value of gidNumber, to autogenerate a user-private
group.
Use cases¶
This change is mostly useful for backwards compatibility in environments
that used to manually create a corresponding group for every user’s
gidNumber
and need to retain the same primary groups, but for newly
added user, autogenerate the user private group from the gidNumber.
To keep backwards compatibility, if a group exists with the same
gidNumber
as set a user entry, this “real” group must not be shadowed
by the autogenerated group even if the autogenerated group comes from a
different domain than the user.
Please see the “How to test” section for a complete example.
Overview of the solution¶
Internally, a hybrid domain would work as a usual non-MPG domain. All
logic will be implemented in the NSS responder, to account for the
case where the primary group comes from a different domain than
the user, because in that case, SSSD must iterate over the domains,
which means calling into the cache_req
code.
Care must be taken in the getgrnam
and getgrgid
calls to not
return the autogenerated group if requested for a user whose gidNumber
is also represented in LDAP with a real group.
Implementation details¶
As said above, the logic will be contained in the NSS responder. If a request for a group arrives, either by ID or by name, the NSS responder first issues a request for a group. If that group is not resolvable and the domain is configured in this special mode, the SSSD retries the same search in the user ID space or name space.
If a result is found with this fallback search, the resulting object would be transformed from a user object to a group object so that the NSS protocol can create a reply.
As a last step, if a group is requested by name, the NSS responder must,
in case of returning the user group, verify that this user group is
not shadowed by an entry in another domain. This is important because
if the autogenerated group was returned even as an alias, the result
would have been stored in the memory cache and subsequent getgrgid()
requests would return this autogenerated group from the memory cache
until it expires, but then return the real group entry from the on-disk
cache. To avoid this confusing state, the NSS responder would also run
a by-GID search and only return the result if the by-GID search returns
nothing. For example, consider that there is a user hybrid_with_group
whose uid and gid are the same, but there exists a group real_group
with the same gid as the primary gid of the user entry. A getgrnam
request arrives for the hybrid_with_group
group, does not match a real
group entry, falls back to the user space. In order to avoid returning the
hybrid_with_group
group, the NSS responder would search the group space
again for hybrid_with_group
’s primary GID, find out that the group
real_group
exists and return ENOENT.
Configuration changes¶
Since we are adding a new option value to the existing
auto_private_groups
call, the option must internally be converted from
boolean to a string with three possible values. We would retain true
and false
for backwards compatibility but add a third option value
hybrid.
How To Test¶
Considering these partial LDIFs:
cn=posixuser,ou=Users,dc=example,dc=com
objectclass: posixUser
uidNumber: 1234
gidNumber: 5678
cn: posixuser
gecos: posix user
homeDirectory: /home/posixuser
loginShell: /bin/sh
cn=posixgroup,ou=Groups,dc=example,dc=com
objectclass: posixGroup
gidNumber: 5678
cn: real_group
cn=hybriduser,ou=Users,dc=example,dc=com
objectclass: posixUser
uidNumber: 2345
gidNumber: 2345
cn: hybriduser
gecos: hybrid user
homeDirectory: /home/hybriduser
loginShell: /bin/sh
cn=hybrid_with_group,ou=Users,dc=example,dc=com
objectclass: posixUser
uidNumber: 3456
gidNumber: 3456
cn: hybrid_with_group
gecos: hybrid with group
homeDirectory: /home/hybrid_with_group
loginShell: /bin/sh
cn=real_group,ou=Groups,dc=example,dc=com
objectclass: posixGroup
gidNumber: 3456
cn: real_group
The posixuser
behaves as usual:
$ getent passwd posixuser
posixuser:*:1234:5678:posix user:/home/posixuser:/bin/sh
$ getent group 5678
posixgroup:*:5678:
$ getent group posixuser
returns nothing
$ id posixuser
uid=1234(posixuser) gid=5678(posixgroup) groups=5678(posixgroup)
The hybriduser
’s primary group is autogenerated:
$ getent passwd hybriduser
hybriduser:*:2345:2345:posix user:/home/hybriduser:/bin/sh
$ getent group 2345
hybriduser:*:2345:
$ getent group hybriduser
hybriduser:*:2345:
$ id hybriduser
uid=2345(hybriduser) gid=2345(hybriduser) groups=2345(hybriduser)
The primary group of hybrid_with_group
is still the one stored in LDAP, not autogenerated:
$ getent passwd hybrid_with_group
hybrid_with_group:*:3456:3456:posix user:/home/hybrid_with_group:/bin/sh
$ getent group 3456
real_group:*:3456:
$ getent group hybrid_with_group
returns nothing
$ id hybrid_with_group
uid=3456(hybrid_with_group) gid=3456(real_group) groups=3456(hybrid_with_group)
Authors¶
- Jakub Hrozek <jhrozek@redhat.com>