Netgroups define network-wide groups used for permission checking when fielding requests for remote mounts, remote logins, and remote shells. For remote mounts, the information in netgroup is used to classify machines; for remote logins and remote shells, it is used to classify users.
Netgroups have a name, and contain one or more of the following members:
- The name of another netgroup (supporting nested netgroups)
- A three-tuple of (username,hostname,domainname) (parentheses included)
The interface and behavior of netgroups in libc is a multi-step procedural interface as follows:
- The user calls
- This sets an internal, global iterator to the start of the list of members for the netgroup specified by netgroupname
- The user calls
getnetgrent()repeatedly until it returns failure
- This returns one set of username, hostname and domainname for each call, until there are no more associated with the netgroupname
- The user calls
- This cleans up after itself
Internally, libraries providing netgroups in libc must unroll the nested netgroups so that all results are returned by
getnetgrent() without additional explicit calls.
Netgroups in LDAP are entries containing the objectClass
nisNetgroup. This objectClass specifies two options:
A netgroup, specified as a literal string. So it would be
The name of another netgroup whose contents need to be rolled into this entry.
Complete example (taken from http://directory.fedoraproject.org/wiki/Howto:Netgroups):
dn: cn=LinuxTeam,ou=Netgroup,dc=example,dc=com objectClass: nisNetgroup objectClass: top cn: LinuxTeam nisNetgroupTriple: (,frank,example.com) nisNetgroupTriple: (,jill,example.com) memberNisNetgroup: QA memberNisNetgroup: Development memberNisNetgroup: Operations description: The Linux Team
Netgroups will be processed similarly to how we handle enumerations in SSSD.
- When a
setnetgrent()request arrives, we will first check the LDB cache and then we will go to the backends to update the cache.
- Once the cache is readied, we will then construct a result object that we can iterate through to return the result set.
- Once the result object is ready, we will reply to the
setgetgrent()request to notify the calling application that it can start calling
- The calling application will issue
getnetgrent()calls until there are no more members available.
- The calling application will call
- Incoming requests to the SSSD will behave similarly to the user and group enumeration code, except that the individual result objects for different netgroup names will be stored in a hash table keyed on the netgroup name.
- During processing, if a netgroup contains nested netgroups, we will need to issue a recursive internal
setnetgrent()request. This means we will need to have a nesting limit (and ideally, loop-detection)
- The response object must contain the complete unrolled results of all of its child netgroups, so that we do not need to maintain multiple iterators for reading through the children.
- The acknowledgement response to the initial
setnetgrent()request will need to happen only after all nested netgroups have been cached.
setnetgrent() processing, we will convert the results into a collection object (see libcollection). For each nested group, we will recurse into
setnetgrent() and create a new collection object that can be added to the parent collection. In this way, we will be able to unroll the groups easily.
getnetgrent() processing, we will construct the response from the stored collection object, rather than directly from the ldb_result object as we do with user and group enumerations.
struct tevent_req setnetgrent_send(char *netgroupname, hash_table_t *nesting) errno_t setnetgrent_recv(tevent_req *req, struct collection **entries)
Internally, the processing for
setnetgrent_send() is expected to recurse into nested netgroups and add the resulting
entries to its own list using the
col_add_collection_to_collection() interface with the
The biggest danger in nesting is the risk of loops in the memberships. To resolve this, I propose that we keep track of subrequests in a dhash table. This would behave as follows:
setnetgrent_send()we would first check whether the hash_count of the hash table is equal to the nesting limit. If it is, we will return completion immediately.
- Next we will check whether netgroupname already exists in the hash table. If it does, then we know we have looped and will simply return completion immediately.
- At this point, we will add the current netgroup name to the hash table (with a NULL associated value) and continue processing this request.
setnetgrent_recv()we will remove the requested netgroupname from the hash table and amend the result collection.
This will allow us to protect against both loops and excessive nesting all at once.
- Is it permissible for a single client to request multiple different netgroups concurrently?
My reading of the documentation for [set get end]netgrent leads me to believe that this is not permitted by libc.
- Maybe this is too low-level at this time, but is a cleanup task planned?
- Netgroups should be handled in the same way that users and groups are handled, so I will probably have to extend the existing cleanup task to also address the netgroups entries in the cache -sgallagh