Thanks to a vigilant Exim user, a difference between BSD and SYSV
concerned with groups has come to light. Exim wants to remove all
supplementary groups that may be present when it is called, and so near
the start it has the code
setgroups(0,NULL);
which works fine on Solaris 2 (where I develop). This also works on
SunOS4. However, it does not work on FreeBSD, and we suspect this may be
true on other BSD-based systems. On FreeBSD, the group list is not a
supplementary group list (as it is on SYSV), but a complete group list,
with the first element being the current group. Thus, to flush out all
additional groups you need to obey
setgroups(1,¤t_group);
I have modified the forthcoming 1.62 (mainly bug-fix) release to attempt
setgroups(0,NULL) and if that fails, then do the other. This has the
desired effect on Solaris 2, SunOS, and FreeBSD. For general peace of
mind, it would be nice to know for sure that it works on other systems.
Attached is a test program that needs to be run as root. It prints out
the group list as obtained from getgroups, runs the same code as Exim to
remove supplementary groups, gets and prints the group list again, uses
setgid(8) to change the basic group, then gets and prints the group list
yet again. On BSD systems, the group list should never get shorter than
1, and the use of setgid() should change the first element of the list.
If people could try this out as root on various other OS, I'd be
grateful. Please post the results to save too many people doing it.
Philip
--
Philip Hazel University Computing Service,
ph10@??? New Museums Site, Cambridge CB2 3QG,
P.Hazel@??? England. Phone: +44 1223 334714
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
int main(void)
{
int group_count, i;
gid_t group_list[NGROUPS_MAX];
printf("count = %d\n", group_count = getgroups(NGROUPS_MAX, group_list));
for (i = 0; i < group_count; i++) printf("%d ", group_list[i]);
printf("\n");
if (setgroups(0, NULL) != 0)
{
printf("setgroups(0,NULL) failed: %s\n", strerror(errno));
if (setgroups(1, group_list) != 0)
{
printf("setgroups(1, group_list) failed: %s\n", strerror(errno));
return 1;
}
else printf("setgroups(1,grouplist) succeeded\n");
}
else printf("setgroups(0,NULL) succeeded\n");
printf("count = %d\n", group_count = getgroups(NGROUPS_MAX, group_list));
for (i = 0; i < group_count; i++) printf("%d ", group_list[i]);
printf("\n");
if (setgid(8) != 0)
{
printf("setgid(8) failed: %s\n", strerror(errno));
return 1;
}
printf("gid = %d\n", getgid());
printf("count = %d\n", group_count = getgroups(NGROUPS_MAX, group_list));
for (i = 0; i < group_count; i++) printf("%d ", group_list[i]);
printf("\n");
return 0;
}