initgroups —
initialize supplementary groups as per
the group database
Standard C Library (libc, -lc)
#include
<unistd.h>
int
initgroups(const
char *name, gid_t
basegid);
The
initgroups()
function initializes the current process' supplementary groups as prescribed
by its arguments and the system's group database.
It first uses the
getgrouplist()
function to compute a list of groups containing the passed
basegid, which typically is the user's initial
numerical group ID from the password database, and the supplementary groups
in the group database for the user named name. It then
installs this list as the current process' supplementary groups using
setgroups().
The initgroups() function returns the
value 0 if successful; otherwise the value -1 is returned and
the global variable errno is set to indicate the
error.
The initgroups() function may fail and set
errno to any of the errors specified for the
setgroups(2) system call, or to:
- [
ENOMEM]
- The
initgroups() function was unable to allocate
temporary storage.
The initgroups() function appeared in
4.2BSD.
The initgroups() function changed
semantics in FreeBSD 15, following that of
setgroups(2) in the same release. Before that, it would also
set the effective group ID to basegid, and would not
include the latter in the supplementary groups except before
FreeBSD 8. Its current behavior in these respects is
known to be compatible with that of the following systems up to the
specified versions that are current at time of this writing:
- Linux (up to 6.6) with the GNU libc (up to 2.42)
- NetBSD 1.1 and greater (up to 10)
- OpenBSD (up to 7.7)
- Systems based on illumos (up to August 2025 sources)
As basegid is typically the user's initial
numerical group ID, to which the current process' effective group ID is
generally initialized, processes using functions to change their effective
group ID (via
setgid(2) or similar) or that are spawned from executables
with the set-group-ID mode bit set will not be able to relinquish the access
rights deriving from being a member of basegid, as
these functions do not change the supplementary groups.
This behavior is generally desirable in order to paper over the
difference of treatment between the effective group and supplementary ones
in this situation, as they are all in the end indiscriminately used in
traditional UNIX discretionary access checks. It blends well with the
practice of allocating each user its own private group, as processes
launched from a set-group-ID executable keep the same user and consistently
stay also in the same user's group. Finally, it was also chosen for
compatibility with other systems (see the
HISTORY section).
This convention of including basegid in the
supplementary groups is however only enforced by the
initgroups() function, and not by the
setgroups(2) system call, so applications expressly wanting
to include in the supplementary groups only those specified by the group
database can themselves call getgrouplist() and then
setgroups() on the result with the first element
skipped (see
getgrouplist(3)).