| /* getugroups.c -- return a list of the groups a user is in | |
| Copyright (C) 1990-1991, 1998-2000, 2003-2026 Free Software Foundation, Inc. | |
| This file is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU Lesser General Public License as | |
| published by the Free Software Foundation; either version 2.1 of the | |
| License, or (at your option) any later version. | |
| This file is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU Lesser General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public License | |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| /* Written by David MacKenzie. */ | |
| #include <config.h> | |
| #include "getugroups.h" | |
| #include <errno.h> | |
| #include <limits.h> | |
| #include <stdio.h> /* grp.h on alpha OSF1 V2.0 uses "FILE *". */ | |
| #include <string.h> | |
| #include <unistd.h> | |
| #if !HAVE_GRP_H || defined __ANDROID__ | |
| /* Mingw lacks all things related to group management. The best we | |
| can do is fail with ENOSYS. | |
| Bionic declares e.g. getgrent() in <grp.h> but it isn't actually | |
| defined in the library. */ | |
| int | |
| getugroups (_GL_UNUSED int maxcount, | |
| _GL_UNUSED gid_t *grouplist, | |
| _GL_UNUSED char const *username, | |
| _GL_UNUSED gid_t gid) | |
| { | |
| errno = ENOSYS; | |
| return -1; | |
| } | |
| #else /* HAVE_GRP_H */ | |
| # include <grp.h> | |
| /* Like 'getgroups', but for user USERNAME instead of for the current | |
| process. Store at most MAXCOUNT group IDs in the GROUPLIST array. | |
| If GID is not -1, store it first (if possible). GID should be the | |
| group ID (pw_gid) obtained from getpwuid, in case USERNAME is not | |
| listed in /etc/groups. Upon failure, set errno and return -1. | |
| Otherwise, return the number of IDs we've written into GROUPLIST. */ | |
| int | |
| getugroups (int maxcount, gid_t *grouplist, char const *username, | |
| gid_t gid) | |
| { | |
| int count = 0; | |
| if (gid != (gid_t) -1) | |
| { | |
| if (maxcount != 0) | |
| grouplist[count] = gid; | |
| ++count; | |
| } | |
| setgrent (); | |
| while (1) | |
| { | |
| errno = 0; | |
| struct group *grp = getgrent (); | |
| if (grp == NULL) | |
| break; | |
| for (char **cp = grp->gr_mem; *cp; ++cp) | |
| { | |
| if (streq (username, *cp)) | |
| { | |
| /* See if this group number is already on the list. */ | |
| int n; | |
| for (n = 0; n < count; ++n) | |
| if (grouplist && grouplist[n] == grp->gr_gid) | |
| break; | |
| /* If it's a new group number, then try to add it to the list. */ | |
| if (n == count) | |
| { | |
| if (maxcount != 0) | |
| { | |
| if (count >= maxcount) | |
| goto done; | |
| grouplist[count] = grp->gr_gid; | |
| } | |
| if (count == INT_MAX) | |
| { | |
| errno = EOVERFLOW; | |
| goto done; | |
| } | |
| count++; | |
| } | |
| } | |
| } | |
| } | |
| if (errno != 0) | |
| count = -1; | |
| done: | |
| { | |
| int saved_errno = errno; | |
| endgrent (); | |
| errno = saved_errno; | |
| } | |
| return count; | |
| } | |
| #endif /* HAVE_GRP_H */ |