[PATCH 3/4] Support dynamic group membership on Darwin.

James Peach jpeach at samba.org
Fri Jun 8 03:37:12 GMT 2007


Using setgroups(2) in Darwin opts out of the dynamic group resolution
mechanism. Use the initgroups system call directly to make sure we  
opt in. Make sure the order of credential operations is correct.
---
source/smbd/sec_ctx.c |   51 +++++++++++++++++++++++++++++++++++++++++ 
+------
1 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/source/smbd/sec_ctx.c b/source/smbd/sec_ctx.c
index ca9a6f2..d7a229e 100644
--- a/source/smbd/sec_ctx.c
+++ b/source/smbd/sec_ctx.c
@@ -20,6 +20,10 @@
#include "includes.h"
+#if defined(HAVE_DARWIN_INITGROUPS)
+#include <sys/syscall.h>
+#endif
+
extern struct current_user current_user;
struct sec_ctx {
@@ -187,7 +191,7 @@ fail:
static BOOL apply_unix_token(const UNIX_USER_TOKEN *ut)
{
-	int max = groups_max();
+	int ngroups = 0;
#ifdef FREEBSD
	/* Most (all?) BSD systems expect that the first element in the groups
@@ -217,26 +221,59 @@ static BOOL apply_unix_token(const  
UNIX_USER_TOKEN *ut)
#endif /* FREEBSD */
-
	/* Always truncate the groups list at the system maximum. On most
	 * systems, setgroups(2) will fail with EINVAL otherwise.
	 */
-	if (sys_setgroups((ut->ngroups > max) ? max : ut->ngroups,
-			    ut->groups) == -1) {
+	ngroups = (ut->ngroups > groups_max()) ? groups_max() : ut->ngroups,
+
+	if (!become_gid(ut->gid)) {
+		return False;
+	}
+
+#if defined(HAVE_DARWIN_INITGROUPS)
+
+       /* The Darwin groups implementation is a little unusual. The  
list of
+        * groups in the kernel credential is not exhaustive, but  
more like
+        * a cache. The full group list is held in userspace and checked
+        * dynamically.
+	*
+        * This is an optional mechanism, and setgroups(2) opts out
+        * of it. That is, if you call setgroups, then the list of  
groups you
+        * set are the only groups that are ever checked. This is not  
what we
+        * want. We want to opt in to the dynamic resolution  
mechanism, so we
+        * need to specify the uid of the user whose group list  
(cache) we are
+        * setting.
+        *
+        * The Darwin rules are:
+        *  1. Thou shalt setegid, initgroups and seteuid IN THAT ORDER
+        *  2. Thou shalt not pass more that NGROUPS_MAX to initgroups
+        *  3. Thou shalt leave the first entry in the groups list  
well alone
+        */
+
+       if (syscall(SYS_initgroups, ngroups, ut->groups, ut->uid) ==  
1) {
+		DEBUG(0, ("WARNING: failed to set group list "
+			"(%d groups) for UID %ld: %s\n",
+			ngroups, (long)ut->uid, strerror(errno)));
+       }
+
+#else
+	if (sys_setgroups(ngroups, ut->groups) == -1) {
		if (errno != ENOSYS) {
			DEBUG(0, ("WARNING: failed to set group list "
				"(%d groups) for UID %ld: %s\n",
-				ut->ngroups, (long)ut->uid, strerror(errno)));
+				ngroups, (long)ut->uid, strerror(errno)));
		}
	}
-	/* If setgroups fails, it's bad, but it might not be the end of
+#endif /* defined(HAVE_DARWIN_INITGROUPS) */
+
+	/* XXX If setgroups fails, it's bad, but it might not be the end of
	 * the world. OTOH, we don't want to have a group list from
	 * some other credential since that could grant access we might
	 * not otherwise have.
	 */
-	if (!become_id(ut->uid, ut->gid)) {
+	if (!become_uid(ut->uid)) {
		return False;
	}
--
1.5.2.1


--
James Peach | jpeach at samba.org




More information about the samba-technical mailing list