| |
@@ -10,63 +10,66 @@
|
| |
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 who do have
|
| |
- the ``gidNumber`` attribute set return the original group, but for users who
|
| |
- have no ``gidNumber,`` autogenerate a user-private group.
|
| |
+ 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 set a ``gidNumber`` and need to retain the same primary
|
| |
- GID number, but for newly added user, autogenerate the user private group
|
| |
- from the ``uidNumber.`` Please see the "How to test" section for an example.
|
| |
+ 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, this hybrid domain would work as a MPG domain, so as if
|
| |
- ``auto_private_groups`` was set true. The difference would be when
|
| |
- returning the entries. In the hybrid model, if the user being returned
|
| |
- had an original GID, this original GID would be used. Otherwise, a primary
|
| |
- group generated from the UID would be returned.
|
| |
+ 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 who also has the originalGID set.
|
| |
+ 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, for the most part, the hybrid domain would work in a similar
|
| |
- manner as a domain that had ``auto_private_groups=true`` set in the config
|
| |
- file. This means, that the ``uidNumber`` and ``gidNumber`` attributes in
|
| |
- the sysdb cache are always set to the same value, but in case the original
|
| |
- entry in LDAP did have a gidNumber stored, that original value is also
|
| |
- stored in the cache using the ``origPrimaryGroupGidNumber`` attribute.
|
| |
- The purpose of this attribute is to be able to return the original
|
| |
- primary GID as a supplementary group so that any resources owned by this
|
| |
- ID are still accessible to the user.
|
| |
-
|
| |
- We will take advantage of this attribute when returning the user object
|
| |
- during ``getpwnam`` (keep in mind that ``struct passwd`` that the
|
| |
- ``getpwnam`` call returns also contains the primary GID number), initgroups
|
| |
- and also for a special case during the ``getgrgid`` and ``getgrnam`` calls.
|
| |
-
|
| |
- During the getpwnam call, the code will check whether the user being returned
|
| |
- has the ``origPrimaryGroupGidNumber`` or not. If it does, its value would
|
| |
- be returned as the GID number, otherwise the ``gidNumber`` attribute would
|
| |
- be used. A similar logic will be implemented in the initgroups call, with
|
| |
- the additional caveat that if the ``origPrimaryGroupGidNumber`` exists,
|
| |
- it wouldn't be returned as another secondary group.
|
| |
-
|
| |
- For group requests in a domain where the user private groups are completely
|
| |
- managed, SSSD would search the whole combined user and group space and
|
| |
- return group objects based on user objects in the cache. The hybrid domain
|
| |
- must behave a little differently here. When a request for a user-private
|
| |
- group comes, the ``getgr*`` call in a hybrid domain should first try
|
| |
- to search group objects only. If there is no match, then also the user
|
| |
- objects need to be searched, but only those user objects that have no
|
| |
- ``origPrimaryGroupGidNumber`` set can be returned as a private groups.
|
| |
- Reusing the example above, ``getgrnam("hybriduser")`` would return a group
|
| |
- object inferred from the user object, but ``getgrnam("posixuser")`` would
|
| |
- not return anything.
|
| |
+ 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
|
| |
---------------------
|
| |
@@ -78,9 +81,10 @@
|
| |
|
| |
How To Test
|
| |
-----------
|
| |
- Considering these two partial LDIFs::
|
| |
+ Considering these partial LDIFs::
|
| |
|
| |
- cn=posixuser,dc=example,dc=com
|
| |
+ cn=posixuser,ou=Users,dc=example,dc=com
|
| |
+ objectclass: posixUser
|
| |
uidNumber: 1234
|
| |
gidNumber: 5678
|
| |
cn: posixuser
|
| |
@@ -88,20 +92,66 @@
|
| |
homeDirectory: /home/posixuser
|
| |
loginShell: /bin/sh
|
| |
|
| |
- cn=hybriduser,dc=example,dc=com
|
| |
+ 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
|
| |
- # note: no gidNumber attribute
|
| |
gecos: hybrid user
|
| |
homeDirectory: /home/hybriduser
|
| |
loginShell: /bin/sh
|
| |
|
| |
- The getpwnam output for these two users would be::
|
| |
+ 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:hybrid user:/home/hybriduser:/bin/sh
|
| |
+ 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
|
| |
-------
|
| |
This change reworks the design page to reflect the current state of https://github.com/SSSD/sssd/pull/650