1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r23393: Support BSD group semantics by making sure that the effective GID is always

passed as the first GID when calling setgroups(2).
(This used to be commit 6ebaf856c1d27f2fbfa0444a5c6c17c4331d2780)
This commit is contained in:
James Peach 2007-06-08 22:25:55 +00:00 committed by Gerald (Jerry) Carter
parent 0a1f5d71e4
commit 74c74f8dcc
3 changed files with 103 additions and 27 deletions

View File

@ -889,15 +889,13 @@ int groups_max(void)
}
/**************************************************************************
Wrapper for getgroups. Deals with broken (int) case.
Wrap setgroups and getgroups for systems that declare getgroups() as
returning an array of gid_t, but actuall return an array of int.
****************************************************************************/
int sys_getgroups(int setlen, gid_t *gidset)
#if defined(HAVE_BROKEN_GETGROUPS)
static int sys_broken_getgroups(int setlen, gid_t *gidset)
{
#if !defined(HAVE_BROKEN_GETGROUPS)
return getgroups(setlen, gidset);
#else
GID_T gid;
GID_T *group_list;
int i, ngroups;
@ -919,7 +917,7 @@ int sys_getgroups(int setlen, gid_t *gidset)
if (setlen == 0)
setlen = groups_max();
if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
DEBUG(0,("sys_getgroups: Malloc fail.\n"));
return -1;
}
@ -936,26 +934,10 @@ int sys_getgroups(int setlen, gid_t *gidset)
SAFE_FREE(group_list);
return ngroups;
#endif /* HAVE_BROKEN_GETGROUPS */
}
/**************************************************************************
Wrapper for setgroups. Deals with broken (int) case. Automatically used
if we have broken getgroups.
****************************************************************************/
int sys_setgroups(int setlen, gid_t *gidset)
static int sys_broken_setgroups(gid_t primary_gid, int setlen, gid_t *gidset)
{
#if !defined(HAVE_SETGROUPS)
errno = ENOSYS;
return -1;
#endif /* HAVE_SETGROUPS */
#if !defined(HAVE_BROKEN_GETGROUPS)
return setgroups(setlen, gidset);
#else
GID_T *group_list;
int i ;
@ -972,7 +954,7 @@ int sys_setgroups(int setlen, gid_t *gidset)
* GID_T array of size setlen.
*/
if((group_list = (GID_T *)malloc(setlen * sizeof(GID_T))) == NULL) {
if((group_list = SMB_MALLOC_ARRAY(GID_T, setlen)) == NULL) {
DEBUG(0,("sys_setgroups: Malloc fail.\n"));
return -1;
}
@ -989,7 +971,101 @@ int sys_setgroups(int setlen, gid_t *gidset)
SAFE_FREE(group_list);
return 0 ;
}
#endif /* HAVE_BROKEN_GETGROUPS */
/* This is a list of systems that require the first GID passed to setgroups(2)
* to be the effective GID. If your system is one of these, add it here.
*/
#if defined (FREEBSD) || defined (DARWINOS)
#define USE_BSD_SETGROUPS
#endif
#if defined(USE_BSD_SETGROUPS)
/* Depending on the particular BSD implementation, the first GID that is
* passed to setgroups(2) will either be ignored or will set the credential's
* effective GID. In either case, the right thing to do is to guarantee that
* gidset[0] is the effective GID.
*/
static int sys_bsd_setgroups(gid_t primary_gid, int setlen, const gid_t *gidset)
{
gid_t *new_gidset = NULL;
int max;
int ret;
/* setgroups(2) will fail with EINVAL if we pass too many groups. */
max = groups_max();
/* No group list, just make sure we are setting the efective GID. */
if (setlen == 0) {
return setgroups(1, &primary_gid);
}
/* If the primary gid is not the first array element, grow the array
* and insert it at the front.
*/
if (gidset[0] != primary_gid) {
gid_t *new_gidset;
new_gidset = SMB_MALLOC_ARRAY(gid_t, setlen + 1);
if (new_gidset == NULL) {
return -1;
}
memcpy(new_gidset + 1, gidset, ((setlen + 1) * sizeof(gid_t)));
new_gidset[0] = primary_gid;
setlen++;
}
#if defined(BROKEN_GETGROUPS)
ret = sys_broken_setgroups(max, new_gidset ? new_gidset : gidset);
#else
ret = setgroups(max, new_gidset ? new_gidset : gidset);
#endif
if (new_gidset) {
int errsav = errno;
SAFE_FREE(new_gidset);
errno = errsav;
}
return ret;
}
#endif /* USE_BSD_SETGROUPS */
/**************************************************************************
Wrapper for getgroups. Deals with broken (int) case.
****************************************************************************/
int sys_getgroups(int setlen, gid_t *gidset)
{
#if defined(HAVE_BROKEN_GETGROUPS)
return sys_broken_getgroups(setlen, gidset);
#else
return getgroups(setlen, gidset);
#endif
}
/**************************************************************************
Wrapper for setgroups. Deals with broken (int) case and BSD case.
****************************************************************************/
int sys_setgroups(gid_t UNUSED(primary_gid), int setlen, gid_t *gidset)
{
#if !defined(HAVE_SETGROUPS)
errno = ENOSYS;
return -1;
#endif /* HAVE_SETGROUPS */
#if defined(HAVE_BROKEN_GETGROUPS)
return sys_broken_setgroups(setlen, gidset);
#elif defined(USE_BSD_SETGROUPS)
return sys_bsd_setgroups(primary_gid, setlen, gidset);
#else
return setgroups(setlen, gidset);
#endif
}
/**************************************************************************

View File

@ -104,7 +104,7 @@ static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups,
restore_re_gid();
if (sys_setgroups(ngrp_saved, gids_saved) != 0) {
if (sys_setgroups(gid, ngrp_saved, gids_saved) != 0) {
/* yikes! */
DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
smb_panic("getgrouplist: failed to reset group list!\n");

View File

@ -236,7 +236,7 @@ static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *grou
/* Start context switch */
gain_root();
#ifdef HAVE_SETGROUPS
sys_setgroups(ngroups, groups);
sys_setgroups(gid, ngroups, groups);
#endif
become_id(uid, gid);
/* end context switch */