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) {