pthread-setugid-np-credential-switching   [plain text]


Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -851,6 +851,8 @@ main() {
 	default_shared_modules="$default_shared_modules vfs_darwin_streams"
 	default_shared_modules="$default_shared_modules vfs_darwinacl"
 
+ 	AC_CHECK_FUNCS(pthread_setugid_np)
+
 	;;
     *hurd*)
         AC_MSG_CHECKING([for LFS support])
Index: samba/source/smbd/sec_ctx.c
===================================================================
--- samba/source/smbd/sec_ctx.c.orig
+++ samba/source/smbd/sec_ctx.c
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    uid/user handling
    Copyright (C) Tim Potter 2000
+   Copyright (C) 2008 Apple, Inc. All rights reserved.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,6 +21,10 @@
 
 #include "includes.h"
 
+#if HAVE_PTHREAD_SETUGID_NP
+#include <sys/kauth.h>
+#endif
+
 extern struct current_user current_user;
 
 struct sec_ctx {
@@ -33,6 +38,8 @@ struct sec_ctx {
 static struct sec_ctx sec_ctx_stack[MAX_SEC_CTX_DEPTH + 1];
 static int sec_ctx_stack_ndx;
 
+#if !defined (HAVE_PTHREAD_SETUGID_NP)
+
 /****************************************************************************
  Become the specified uid.
 ****************************************************************************/
@@ -125,6 +132,8 @@ static void gain_root(void)
 	}
 }
 
+#endif /* !defined (HAVE_PTHREAD_SETUGID_NP) */
+
 /****************************************************************************
  Get the list of current groups.
 ****************************************************************************/
@@ -139,6 +148,15 @@ static int get_current_groups(gid_t gid,
 	(*p_ngroups) = 0;
 	(*p_groups) = NULL;
 
+#if HAVE_PTHREAD_SETUGID_NP
+	/* Messing with the effective group ID doesn't work under a thread
+	 * credential. Once you have assumed a thread credential, then it's all
+	 * over until you unassume it.
+	 */
+
+	return 0;
+#endif
+
 	/* this looks a little strange, but is needed to cope with
 	   systems that put the current egid in the group list
 	   returned from getgroups() (tridge) */
@@ -231,6 +249,25 @@ BOOL push_sec_ctx(void)
  Set the current security context to a given user.
 ****************************************************************************/
 
+#if HAVE_PTHREAD_SETUGID_NP
+
+static BOOL running_with_thread_credential(void)
+{
+	uid_t uid;
+	gid_t gid;
+
+	/* Getting the assumed thread credential fails unless we have actually
+	 * assumed it.
+	 */
+	if (pthread_getugid_np(&uid, &gid) == -1 && errno == ESRCH) {
+		return False;
+	} else {
+		return True;
+	}
+}
+
+#endif /* HAVE_PTHREAD_SETUGID_NP */
+
 void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
 {
 	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
@@ -243,10 +280,12 @@ void set_sec_ctx(uid_t uid, gid_t gid, i
 	debug_nt_user_token(DBGC_CLASS, 5, token);
 	debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);
 
+#if !defined(HAVE_PTHREAD_SETUGID_NP)
 	gain_root();
 
 	become_gid(gid);
 	sys_setgroups(uid, ngroups, groups);
+#endif /* !defined(HAVE_PTHREAD_SETUGID_NP) */
 
 	ctx_p->ut.ngroups = ngroups;
 
@@ -276,8 +315,35 @@ void set_sec_ctx(uid_t uid, gid_t gid, i
 		ctx_p->token = NULL;
 	}
 
+#if !defined(HAVE_PTHREAD_SETUGID_NP)
+
 	become_uid(uid);
 
+#else /* !defined(HAVE_PTHREAD_SETUGID_NP) */
+
+	/* Pop the assumed thread credential. */
+	if (pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) == -1) {
+		if (running_with_thread_credential()) {
+			DEBUG(0, ("failed to pop thread credential: %s\n",
+				    strerror(errno)));
+			smb_panic("pthread_setugid_np failed to pop");
+		}
+	}
+
+	/* We should be root now ... push the previous credential. */
+	if (pthread_setugid_np(uid, gid) == -1) {
+		DEBUG(0, ("failed to push thread credential: %s\n",
+			    strerror(errno)));
+		DEBUG(0, ("failed to push thread credential (uid=%d, gid=%d): %s\n",
+			    (int)uid, (int)gid, strerror(errno)));
+		smb_panic("pthread_setugid_np failed to push");
+	}
+
+	/* Opt back into dynamic group membership */
+	sys_setgroups(uid, ngroups, groups);
+
+#endif /* !defined(HAVE_PTHREAD_SETUGID_NP) */
+
 	ctx_p->ut.uid = uid;
 	ctx_p->ut.gid = gid;
 
@@ -333,15 +399,42 @@ BOOL pop_sec_ctx(void)
 
 	sec_ctx_stack_ndx--;
 
+#if !defined (HAVE_PTHREAD_SETUGID_NP)
 	gain_root();
+#endif /* !defined (HAVE_PTHREAD_SETUGID_NP) */
 
 	prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
 
+#if !defined (HAVE_PTHREAD_SETUGID_NP)
 	become_gid(prev_ctx_p->ut.gid);
 	sys_setgroups(prev_ctx_p->ut.uid,
 		prev_ctx_p->ut.ngroups, prev_ctx_p->ut.groups);
 
 	become_uid(prev_ctx_p->ut.uid);
+#else /* !defined (HAVE_PTHREAD_SETUGID_NP) */
+
+	/* Pop the assumed thread credential. */
+	if (pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE) == -1) {
+		DEBUG(0, ("failed to pop thread credential: %s\n",
+			    strerror(errno)));
+		smb_panic("pthread_setugid_np failed to pop");
+	}
+
+	/* We should be root now ... push the previous credential. */
+	if (pthread_setugid_np(prev_ctx_p->ut.uid, prev_ctx_p->ut.gid) == -1) {
+		DEBUG(0, ("failed to push thread credential: %s\n",
+			    strerror(errno)));
+		DEBUG(0, ("failed to push thread credential (uid=%d, gid=%d): %s\n",
+			    (int)prev_ctx_p->ut.uid, (int)prev_ctx_p->ut.gid,
+			    strerror(errno)));
+		smb_panic("pthread_setugid_np failed to push");
+	}
+
+	/* Opt back into dynamic group membership. */
+	sys_setgroups(prev_ctx_p->ut.uid,
+		prev_ctx_p->ut.ngroups, prev_ctx_p->ut.groups);
+
+#endif /* !defined (HAVE_PTHREAD_SETUGID_NP) */
 
 	/* Update current_user stuff */
 
Index: samba/source/lib/messages.c
===================================================================
--- samba/source/lib/messages.c.orig
+++ samba/source/lib/messages.c
@@ -174,6 +174,7 @@ static NTSTATUS message_notify(struct pr
 	pid_t pid = procid.pid;
 	int ret;
 	uid_t euid = geteuid();
+	BOOL restore_credentials = False;
 
 	/*
 	 * Doing kill with a non-positive pid causes messages to be
@@ -184,17 +185,15 @@ static NTSTATUS message_notify(struct pr
 
 	if (euid != 0) {
 		/* If we're not root become so to send the message. */
-		save_re_uid();
-		set_effective_uid(0);
+		become_root();
+		restore_credentials = True;
 	}
 
 	ret = kill(pid, SIGUSR1);
 
-	if (euid != 0) {
+	if (restore_credentials) {
 		/* Go back to who we were. */
-		int saved_errno = errno;
-		restore_re_uid_fromroot();
-		errno = saved_errno;
+		unbecome_root();
 	}
 
 	if (ret == -1) {