r23398: Support membership of >16 groups on Darwin by making sure we opt in to the
[jerry/samba.git] / source / smbd / sec_ctx.c
index 19dac0d27fd166c0b4c979349b575a56aa24399a..4d4e24407bcd77a48af37b94d26121e3590a0947 100644 (file)
@@ -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.
 ****************************************************************************/