int EnumerateUserGroups()

in src/common/commonutils/UserUtils.c [446:576]


int EnumerateUserGroups(SimplifiedUser* user, SimplifiedGroup** groupList, unsigned int* size, char** reason, OsConfigLogHandle log)
{
    gid_t* groupIds = NULL;
    int numberOfGroups = MAX_GROUPS_USER_CAN_BE_IN;
    struct group* groupEntry = NULL;
    size_t groupNameLength = 0;
    int i = 0;
    int getGroupListResult = 0;
    int status = 0;

    if ((NULL == user) || (NULL == groupList) || (NULL == size))
    {
        OsConfigLogError(log, "EnumerateUserGroups: invalid arguments");
        return EINVAL;
    }
    else if (NULL == user->username)
    {
        OsConfigLogError(log, "EnumerateUserGroups: unable to enumerate groups for user without name");
        return ENOENT;
    }

    *groupList = NULL;
    *size = 0;

    if (NULL == (groupIds = malloc(numberOfGroups * sizeof(gid_t))))
    {
        OsConfigLogError(log, "EnumerateUserGroups: out of memory allocating list of %d group identifiers", numberOfGroups);
        numberOfGroups = 0;
        status = ENOMEM;
    }
    else if (-1 == (getGroupListResult = getgrouplist(user->username, user->groupId, groupIds, &numberOfGroups)))
    {
        OsConfigLogDebug(log, "EnumerateUserGroups: first call to getgrouplist for user %u (%u) returned %d and %d", user->userId, user->groupId, getGroupListResult, numberOfGroups);
        FREE_MEMORY(groupIds);

        if (0 < numberOfGroups)
        {
            if (NULL != (groupIds = malloc(numberOfGroups * sizeof(gid_t))))
            {
                getGroupListResult = getgrouplist(user->username, user->groupId, groupIds, &numberOfGroups);
                OsConfigLogDebug(log, "EnumerateUserGroups: second call to getgrouplist for user '%u' (%u) returned %d and %d", user->userId, user->groupId, getGroupListResult, numberOfGroups);
            }
            else
            {
                OsConfigLogError(log, "EnumerateUserGroups: out of memory allocating list of %d group identifiers", numberOfGroups);
                numberOfGroups = 0;
                status = ENOMEM;
            }
        }
        else
        {
            OsConfigLogInfo(log, "EnumerateUserGroups: first call to getgrouplist for user %u (%u) returned -1 and %d groups", user->userId, user->groupId, numberOfGroups);
            status = ENOENT;
        }
    }

    if ((0 == status) && (0 < numberOfGroups))
    {
        OsConfigLogDebug(log, "EnumerateUserGroups: user %u ('%s', gid: %u) is in %d group%s",
            user->userId, IsSystemAccount(user) ? user->username : g_redacted, user->groupId, numberOfGroups, (1 == numberOfGroups) ? "" : "s");

        if (NULL == (*groupList = malloc(sizeof(SimplifiedGroup) * numberOfGroups)))
        {
            OsConfigLogError(log, "EnumerateUserGroups: out of memory");
            status = ENOMEM;
        }
        else
        {
            *size = numberOfGroups;

            for (i = 0; i < numberOfGroups; i++)
            {
                if (NULL == (groupEntry = getgrgid(groupIds[i])))
                {
                    if (0 == errno)
                    {
                        OsConfigLogInfo(log, "EnumerateUserGroups: group %u does not exist (errno: %d)", (unsigned int)groupIds[i], errno);
                        *size -= 1;
                        continue;
                    }
                    else
                    {
                        OsConfigLogInfo(log, "EnumerateUserGroups: getgrgid(for gid: %u) failed (errno: %d)", (unsigned int)groupIds[i], errno);
                        status = errno ? errno : ENOENT;
                        break;
                    }
                }

                if (NULL != groupEntry)
                {
                    (*groupList)[i].groupId = groupEntry->gr_gid;
                    (*groupList)[i].groupName = NULL;
                    (*groupList)[i].hasUsers = true;

                    if (0 < (groupNameLength = (groupEntry->gr_name ? strlen(groupEntry->gr_name) : 0)))
                    {
                        if (NULL != ((*groupList)[i].groupName = malloc(groupNameLength + 1)))
                        {
                            memset((*groupList)[i].groupName, 0, groupNameLength + 1);
                            memcpy((*groupList)[i].groupName, groupEntry->gr_name, groupNameLength);

                            OsConfigLogDebug(log, "EnumerateUserGroups: user %u ('%s', gid: %u) is in group %u ('%s')",
                                user->userId, IsSystemAccount(user) ? user->username : g_redacted, user->groupId,
                                (*groupList)[i].groupId, IsSystemGroup(&(*groupList)[i]) ? (*groupList)[i].groupName : g_redacted);
                        }
                        else
                        {
                            OsConfigLogError(log, "EnumerateUserGroups: out of memory");
                            status = ENOMEM;
                            break;
                        }
                    }
                }
            }
        }
    }

    if (0 == *size)
    {
        FREE_MEMORY(*groupList);
    }

    if (status)
    {
        OsConfigCaptureReason(reason, "Failed to enumerate groups for users (%d). User database may be corrupt. Automatic remediation is not possible", status);
    }

    FREE_MEMORY(groupIds);

    return status;
}