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