summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJames Peach <jpeach@samba.org>2007-06-08 22:25:55 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:23:12 -0500
commit74c74f8dccc01c99c8098dcb0dcae5cfaa81566d (patch)
treeeb21fabc1c544a5c1ed90dac9ce4042f61f1835b /source3
parent0a1f5d71e4ad551f178613fff8bd288ad0cad057 (diff)
downloadsamba-74c74f8dccc01c99c8098dcb0dcae5cfaa81566d.tar.gz
samba-74c74f8dccc01c99c8098dcb0dcae5cfaa81566d.tar.bz2
samba-74c74f8dccc01c99c8098dcb0dcae5cfaa81566d.zip
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)
Diffstat (limited to 'source3')
-rw-r--r--source3/lib/system.c126
-rw-r--r--source3/lib/system_smbd.c2
-rw-r--r--source3/smbd/sec_ctx.c2
3 files changed, 103 insertions, 27 deletions
diff --git a/source3/lib/system.c b/source3/lib/system.c
index d7321501ad..2cc7ef6ca4 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -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
}
/**************************************************************************
diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c
index 509b2bbcb1..0d62360ca6 100644
--- a/source3/lib/system_smbd.c
+++ b/source3/lib/system_smbd.c
@@ -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");
diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c
index fd79fbb7fe..19dac0d27f 100644
--- a/source3/smbd/sec_ctx.c
+++ b/source3/smbd/sec_ctx.c
@@ -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 */