GETGROUPLIST(3C) Standard C Library Functions GETGROUPLIST(3C)

getgrouplistcalculate group access list

#include <grp.h>

int
getgrouplist(const char *user, gid_t agroup, gid_t *groups, int *ngroups);

The () function queries the group database to obtain the list of groups that user belongs to. The agroup group is always added to the resulting group list. This value is typically the primary gid of the user from the database.

When calling (), the caller should set the maximum number of groups that groups can hold in *ngroups. The value of NGROUPS_MAX can be used to size groups to ensure it can hold any number of groups supported by the system.

Upon return, () stores the list of groups that user belongs to in groups and stores the number of groups user belongs to in *ngroups (this may be a smaller than the value passed in when calling getgrouplist()). If groups is too small to hold all of the groups user belongs to, getgrouplist() fails and sets *ngroups to a value large enough to hold the full result.

On success, getgrouplist() returns the number of groups user belongs to, fills in groups with the gids of the groups user belongs to, and also sets *ngroups to the number of groups user belongs to.

On failure, getgrouplist() returns -1 and errno is set.

The behavior of getgrouplist() is undefined if the total number of groups a user belongs to exceeds NGROUPS_MAX.

Note that on FreeBSD, getgrouplist() always returns -1 on failure or 0 on success. A caller must rely on the value set in *ngroups upon return to determine the number of entries in groups.

On Linux, both glibc and musl return the number of groups user belongs to on success and return -1 on failure.

None of these other implementations document any errno values on failure, however their implementations show that errno may be set on failure. Software using getgrouplist() should be aware of these differences when attempting to write portable software.

Print all the groups for a user.

#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <err.h>

void
printgroups(const char *user)
{
    struct passwd *pw;
    gid_t *groups;
    int ngroups, ret;

    if ((groups = calloc(NGROUPS_MAX, sizeof (gid_t))) == NULL)
        err(EXIT_FAILURE, "calloc");

    if ((pw = getpwnam(user)) == NULL)
        err(EXIT_FAILURE, "getpwnam");

    ngroups = NGROUPS_MAX;
    ret = getgrouplist(user, pw->pw_gid, groups, &ngroups);
    if (ret < 0)
        err(EXIT_FAILURE, "getgrouplist");

    for (int i = 0; i < ret; i++) {
        struct group *gr = getgrgid(groups[i]);

        (void) printf("%s ", gr->gr_name);
    }
    (void) fputc('\n', stdout);

    free(groups);
}

On failure, getgrouplist() returns -1, and will set errno to one of the following values:

Not enough memory to complete the request.
One of the parameters is invalid (for example, ngroups is NULL).
The supplied value of *ngroups is too small to hold the results. *ngroups is set (upon return) to a value large enough to hold the results, and a partial set of results is written to groups. The value written to *ngroups may be larger than the value returned by a successful call to getgrouplist().

groups(1), getgroups(2), getuid(2), getgrnam(3C), initgroups(3C), limits.h(3HEAD)

December 2, 2023 OmniOS