If you are checking once to see if an account is in a group, there is a simple and obvious approach (omitting some details):
grp = getgrnam(GRPNAME);
getgrouplist(pwent->pw_name, pwent->pw_gid, &groups, &ngroups);
for (i = 0; i < ngroups; i++) {
if (groups[i] == grp->gr_gid)
return 1;
}
There is just one problem with this: on many systems,
getgrouplist()
will re-scan and re-parse
/etc/group
every time you call it. If you call it only once or twice this usually doesn't matter. If you call it a lot, this matters a lot (especially if
/etc/group
is big).
In theory, the better check is simple. Instead of getting the login's group list and seeing if the group's GID is in there, you work the other way around: you get the group's membership (as part of getting the group entry itself) and then see if the login either has the group's GID as it's primary group or appears on the list of group members. This avoids (repeatedly) parsing all of
/etc/group
, especially if you cache the group entry for the group you care about.
However, these two checks are not equivalent and now you have to decide what you care about. The first version checks to see if a login has the group ID of a particular group. The second version checks to see if a login has the group name of a particular group. To see the difference, consider the following group entries:
wheel:x:10:jane cog:x:10:fred
Here is the question: is
fred
in group
wheel
? If we go by GID the answer is clearly yes;
fred
will have GID 10 as one of his supplemental groups when he logs in and be able to access files that are only accessible to GID 10. But if we go by group name, the answer is no;
fred
is in
cog
, not
wheel
, although they have the same GID. Which version the software you use cares about is something that you may have to investigate.
(If you are designing the software, you can decide to make it whichever is more convenient and useful to you.)
The corollary is that if you really do need the GID version and you want to be fast for a large number of checks, in theory you need to build some sort of full in-memory index of
/etc/group
. In practice, however, duplicate GIDs are extremely rare and usually not intended so you may be to be able to ignore them. If not, you can at least scan
/etc/group
once to see if the group you care about has duplicated GIDs.
(The fully general version is to scan
/etc/group
and accumulate all of the group entries for groups with the same GID as the group you care about. Then you check all of their group membership lists. This is going to require caching in order to make it fast for a large number of logins and groups.)