summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/configure.in15
-rw-r--r--source3/smbd/sec_ctx.c49
2 files changed, 64 insertions, 0 deletions
diff --git a/source3/configure.in b/source3/configure.in
index be92a9144d..d69a40eb90 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -3100,6 +3100,21 @@ if test x"$samba_cv_USE_SETUIDX" = x"yes"; then
fi
fi
+AC_CACHE_CHECK([for the Darwin initgroups system call],
+ samba_cv_DARWIN_INITGROUPS,
+ AC_TRY_LINK([
+#include <sys/syscall.h>
+#include <unistd.h>
+ ],
+ [ syscall(SYS_initgroups, 16, NULL, NULL, 0); ],
+ samba_cv_DARWIN_INITGROUPS=yes,
+ samba_cv_DARWIN_INITGROUPS=no)
+)
+
+if test x"$samba_cv_DARWIN_INITGROUPS" = x"yes" ; then
+ AC_DEFINE(HAVE_DARWIN_INITGROUPS, 1,
+ [Whether to use the Darwin-specific initgroups system call])
+fi
AC_CACHE_CHECK([for working mmap],samba_cv_HAVE_MMAP,[
AC_TRY_RUN([#include "${srcdir-.}/tests/shared_mmap.c"],
diff --git a/source3/smbd/sec_ctx.c b/source3/smbd/sec_ctx.c
index 19dac0d27f..4d4e24407b 100644
--- a/source3/smbd/sec_ctx.c
+++ b/source3/smbd/sec_ctx.c
@@ -231,6 +231,10 @@ BOOL push_sec_ctx(void)
Change UNIX security context. Calls panic if not successful so no return value.
****************************************************************************/
+#ifndef HAVE_DARWIN_INITGROUPS
+
+/* Normal credential switch path. */
+
static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
{
/* Start context switch */
@@ -242,6 +246,51 @@ static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *grou
/* end context switch */
}
+#else /* 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
+*/
+
+#include <sys/syscall.h>
+
+static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
+{
+ int max = groups_max();
+
+ /* Start context switch */
+ gain_root();
+
+ become_gid(gid);
+
+
+ if (syscall(SYS_initgroups, (ngroups > max) ? max : ngroups,
+ groups, uid) == 1) {
+ DEBUG(0, ("WARNING: failed to set group list "
+ "(%d groups) for UID %ld: %s\n",
+ ngroups, uid, strerror(errno)));
+ }
+
+ become_uid(uid);
+ /* end context switch */
+}
+
+#endif /* HAVE_DARWIN_INITGROUPS */
+
/****************************************************************************
Set the current security context to a given user.
****************************************************************************/