/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
-/*
+ *
+ *
+ * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
+ *
+ *
* Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* SUCH DAMAGE.
*
* @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
- */
-/*
+ *
+ *
* NOTICE: This file was modified by McAfee Research in 2004 to introduce
* support for mandatory and extensible security protections. This notice
* is included in support of clause 2.2 (b) of the Apple Public License,
* Version 2.0.
- */
-/*
+ *
+ *
* NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
* support for mandatory and extensible security protections. This notice
* is included in support of clause 2.2 (b) of the Apple Public License,
* Version 2.0.
+ *
*/
/*
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/malloc.h>
+#include <sys/persona.h>
-#include <bsm/audit_kernel.h>
-
-#if CONFIG_LCTX
-#include <sys/lctx.h>
-#endif
+#include <security/audit/audit.h>
#if CONFIG_MACF
#include <security/mac_framework.h>
-#if CONFIG_MACF_MACH
-#include <secuity/mac_mach_internal.h>
-#endif
#endif
#include <sys/mount_internal.h>
#include <kern/assert.h>
-int groupmember(gid_t gid, kauth_cred_t cred);
-
/*
* Credential debugging; we can track entry into a function that might
* change a credential, and we can track actual credential changes that
#define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
#endif /* !DEBUG_CRED */
+#if DEVELOPMENT || DEBUG
+extern void task_importance_update_owner_info(task_t);
+#endif
/*
* XXX: Belongs in kern_proc.c
*/
int
-setprivexec(proc_t p, struct setprivexec_args *uap, register_t *retval)
+setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
{
- AUDIT_ARG(value, uap->flag);
+ AUDIT_ARG(value32, uap->flag);
*retval = p->p_debugger;
p->p_debugger = (uap->flag != 0);
return(0);
* XXX: Belongs in kern_proc.c
*/
int
-getpid(proc_t p, __unused struct getpid_args *uap, register_t *retval)
+getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
{
*retval = p->p_pid;
* XXX: Belongs in kern_proc.c
*/
int
-getppid(proc_t p, __unused struct getppid_args *uap, register_t *retval)
+getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
{
*retval = p->p_ppid;
* XXX: Belongs in kern_proc.c
*/
int
-getpgrp(proc_t p, __unused struct getpgrp_args *uap, register_t *retval)
+getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
{
*retval = p->p_pgrpid;
* XXX: Belongs in kern_proc.c
*/
int
-getpgid(proc_t p, struct getpgid_args *uap, register_t *retval)
+getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
{
proc_t pt;
int refheld = 0;
* XXX: Belongs in kern_proc.c
*/
int
-getsid(proc_t p, struct getsid_args *uap, register_t *retval)
+getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
{
proc_t pt;
int refheld = 0;
* Returns: uid_t The real uid of the caller
*/
int
-getuid(__unused proc_t p, __unused struct getuid_args *uap, register_t *retval)
+getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
{
*retval = kauth_getruid();
* Returns: uid_t The effective uid of the caller
*/
int
-geteuid(__unused proc_t p, __unused struct geteuid_args *uap, register_t *retval)
+geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
{
*retval = kauth_getuid();
* ESRCH No per thread identity active
*/
int
-gettid(__unused proc_t p, struct gettid_args *uap, register_t *retval)
+gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
{
struct uthread *uthread = get_bsdthread_info(current_thread());
int error;
if (!(uthread->uu_flag & UT_SETUID))
return (ESRCH);
- if ((error = suword(uap->uidp, uthread->uu_ucred->cr_ruid)))
+ if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred))))
return (error);
- if ((error = suword(uap->gidp, uthread->uu_ucred->cr_rgid)))
+ if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred))))
return (error);
*retval = 0;
* Returns: gid_t The real gid of the caller
*/
int
-getgid(__unused proc_t p, __unused struct getgid_args *uap, register_t *retval)
+getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
{
*retval = kauth_getrgid();
* detail.
*/
int
-getegid(__unused proc_t p, __unused struct getegid_args *uap, register_t *retval)
+getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
{
*retval = kauth_getgid();
* be returned by this call.
*/
int
-getgroups(__unused proc_t p, struct getgroups_args *uap, register_t *retval)
+getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
{
int ngrp;
int error;
kauth_cred_t cred;
+ posix_cred_t pcred;
/* grab reference while we muck around with the credential */
cred = kauth_cred_get_with_ref();
+ pcred = posix_cred_get(cred);
if ((ngrp = uap->gidsetsize) == 0) {
- *retval = cred->cr_ngroups;
+ *retval = pcred->cr_ngroups;
kauth_cred_unref(&cred);
return (0);
}
- if (ngrp < cred->cr_ngroups) {
+ if (ngrp < pcred->cr_ngroups) {
kauth_cred_unref(&cred);
return (EINVAL);
}
- ngrp = cred->cr_ngroups;
- if ((error = copyout((caddr_t)cred->cr_groups,
+ ngrp = pcred->cr_ngroups;
+ if ((error = copyout((caddr_t)pcred->cr_groups,
uap->gidset,
ngrp * sizeof(gid_t)))) {
kauth_cred_unref(&cred);
/*
* Return the per-thread/per-process supplementary groups list.
+ *
+ * XXX implement getsgroups
+ *
*/
-#warning XXX implement getsgroups
+
int
-getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused register_t *retval)
+getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
{
- /* XXX implement */
return(ENOTSUP);
}
/*
* Return the per-thread/per-process whiteout groups list.
+ *
+ * XXX implement getwgroups
+ *
*/
-#warning XXX implement getwgroups
+
int
-getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused register_t *retval)
+getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
{
- /* XXX implement */
return(ENOTSUP);
}
* XXX: Belongs in kern_proc.c
*/
int
-setsid(proc_t p, __unused struct setsid_args *uap, register_t *retval)
+setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
{
struct pgrp * pg = PGRP_NULL;
* XXX: Belongs in kern_proc.c
*/
int
-setpgid(proc_t curp, register struct setpgid_args *uap, __unused register_t *retval)
+setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
{
proc_t targp = PROC_NULL; /* target process */
struct pgrp *pg = PGRP_NULL; /* target pgrp */
* execution.
*/
int
-issetugid(proc_t p, __unused struct issetugid_args *uap, register_t *retval)
+proc_issetugid (proc_t p)
+{
+ return (p->p_flag & P_SUGID) ? 1 : 0;
+}
+
+int
+issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
{
/*
* Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
* that libc *might* have put in their data segment.
*/
- *retval = (p->p_flag & P_SUGID) ? 1 : 0;
+ *retval = proc_issetugid(p);
return (0);
}
* flag the process as having set privilege since the last exec.
*/
int
-setuid(proc_t p, struct setuid_args *uap, __unused register_t *retval)
+setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
{
uid_t uid;
uid_t svuid = KAUTH_UID_NONE;
uid_t gmuid = KAUTH_UID_NONE;
int error;
kauth_cred_t my_cred, my_new_cred;
-
+ posix_cred_t my_pcred;
uid = uap->uid;
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid);
- AUDIT_ARG(uid, uid, 0, 0, 0);
+ AUDIT_ARG(uid, uid);
- if (uid != my_cred->cr_ruid && /* allow setuid(getuid()) */
- uid != my_cred->cr_svuid && /* allow setuid(saved uid) */
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
- /*
- * Everything's okay, do it.
- */
+ for (;;) {
+ if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
+ uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
- /*
- * If we are priviledged, then set the saved and real UID too;
- * otherwise, just set the effective UID
- */
- if (suser(my_cred, &p->p_acflag) == 0) {
- svuid = uid;
- ruid = uid;
/*
- * Transfer proc count to new user.
- * chgproccnt uses list lock for protection
+ * If we are privileged, then set the saved and real UID too;
+ * otherwise, just set the effective UID
*/
- (void)chgproccnt(uid, 1);
- (void)chgproccnt(kauth_getruid(), -1);
- }
-
- /* get current credential and take a reference while we muck with it */
- for (;;) {
+ if (suser(my_cred, &p->p_acflag) == 0) {
+ svuid = uid;
+ ruid = uid;
+ } else {
+ svuid = KAUTH_UID_NONE;
+ ruid = KAUTH_UID_NONE;
+ }
/*
* Only set the gmuid if the current cred has not opt'ed out;
* this normally only happens when calling setgroups() instead
* to something other than the default list for the user, as
* in entering a group or leaving an exclusion group).
*/
- if (!(my_cred->cr_flags & CRF_NOMEMBERD))
+ if (!(my_pcred->cr_flags & CRF_NOMEMBERD))
gmuid = uid;
/*
my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
if (my_cred != my_new_cred) {
- DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+ DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
+
+ /*
+ * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
+ * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
+ * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
+ * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
+ * may be able to decrement the proc count of B before we can increment it. This results in a panic.
+ * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, 1);
+ }
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we should
* restart this again with the new cred.
+ *
+ * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
+ /*
+ * We didn't successfully switch to the new ruid, so decrement
+ * the procs/uid count that we incremented above.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, -1);
+ }
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
+ /*
+ * If we've updated the ruid, decrement the count of procs running
+ * under the previous ruid
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(my_pcred->cr_ruid, -1);
+ }
}
break;
}
* flag the process as having set privilege since the last exec.
*/
int
-seteuid(proc_t p, struct seteuid_args *uap, __unused register_t *retval)
+seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
{
uid_t euid;
int error;
kauth_cred_t my_cred, my_new_cred;
+ posix_cred_t my_pcred;
DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
euid = uap->euid;
- AUDIT_ARG(uid, 0, euid, 0, 0);
+ AUDIT_ARG(euid, euid);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
- if (euid != my_cred->cr_ruid && euid != my_cred->cr_svuid &&
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /*
- * Everything's okay, do it. Copy credentials so other references do
- * not see our changes. get current credential and take a reference
- * while we muck with it
- */
for (;;) {
+
+ if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
+
/*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
*/
- my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_cred->cr_gmuid);
+ my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
if (my_cred != my_new_cred) {
- DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+ DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
}
break;
}
* flag the process as having set privilege since the last exec.
*/
int
-setreuid(proc_t p, struct setreuid_args *uap, __unused register_t *retval)
+setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
{
uid_t ruid, euid;
int error;
kauth_cred_t my_cred, my_new_cred;
+ posix_cred_t my_pcred;
DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
ruid = KAUTH_UID_NONE;
if (euid == (uid_t)-1)
euid = KAUTH_UID_NONE;
- AUDIT_ARG(uid, euid, ruid, 0, 0);
+ AUDIT_ARG(euid, euid);
+ AUDIT_ARG(ruid, ruid);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
- if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
- ruid != my_cred->cr_ruid && /* allow ruid = ruid */
- ruid != my_cred->cr_uid && /* allow ruid = euid */
- ruid != my_cred->cr_svuid) || /* allow ruid = svuid */
- (euid != KAUTH_UID_NONE && /* allow no change of euid */
- euid != my_cred->cr_uid && /* allow euid = euid */
- euid != my_cred->cr_ruid && /* allow euid = ruid */
- euid != my_cred->cr_svuid)) && /* allow euid = svui */
- (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /*
- * Everything's okay, do it. Copy credentials so other references do
- * not see our changes. get current credential and take a reference
- * while we muck with it
- */
for (;;) {
+
+ if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
+ ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
+ ruid != my_pcred->cr_uid && /* allow ruid = euid */
+ ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
+ (euid != KAUTH_UID_NONE && /* allow no change of euid */
+ euid != my_pcred->cr_uid && /* allow euid = euid */
+ euid != my_pcred->cr_ruid && /* allow euid = ruid */
+ euid != my_pcred->cr_svuid)) && /* allow euid = svuid */
+ (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
+
uid_t new_euid;
- uid_t new_ruid;
uid_t svuid = KAUTH_UID_NONE;
- new_euid = my_cred->cr_uid;
- new_ruid = my_cred->cr_ruid;
-
+ new_euid = my_pcred->cr_uid;
/*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
*/
- if (euid == KAUTH_UID_NONE && my_cred->cr_uid != euid) {
+ if (euid != KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
/* changing the effective UID */
new_euid = euid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- }
- if (ruid != KAUTH_UID_NONE && my_cred->cr_ruid != ruid) {
- /* changing the real UID; must do user accounting */
- /* chgproccnt uses list lock for protection */
- (void)chgproccnt(ruid, 1);
- (void)chgproccnt(my_cred->cr_ruid, -1);
- new_ruid = ruid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
}
/*
* If the newly requested real uid or effective uid does
* new effective uid. We are protected from escalation
* by the prechecking.
*/
- if (my_cred->cr_svuid != uap->ruid &&
- my_cred->cr_svuid != uap->euid) {
+ if (my_pcred->cr_svuid != uap->ruid &&
+ my_pcred->cr_svuid != uap->euid) {
svuid = new_euid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
}
- my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_cred->cr_gmuid);
+ my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
if (my_cred != my_new_cred) {
- DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+ DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
+
+ /*
+ * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
+ * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
+ * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
+ * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
+ * may be able to decrement the proc count of B before we can increment it. This results in a panic.
+ * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, 1);
+ }
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we should
* restart this again with the new cred.
+ *
+ * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ /*
+ * We didn't successfully switch to the new ruid, so decrement
+ * the procs/uid count that we incremented above.
+ */
+ (void)chgproccnt(ruid, -1);
+ }
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
+
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag); /* XXX redundant? */
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
+
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ /*
+ * We switched to a new ruid, so decrement the count of procs running
+ * under the previous ruid
+ */
+ (void)chgproccnt(my_pcred->cr_ruid, -1);
+ }
}
break;
}
* the supplementary group list unchanged.
*/
int
-setgid(proc_t p, struct setgid_args *uap, __unused register_t *retval)
+setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
{
gid_t gid;
gid_t rgid = KAUTH_GID_NONE;
gid_t svgid = KAUTH_GID_NONE;
int error;
kauth_cred_t my_cred, my_new_cred;
+ posix_cred_t my_pcred;
DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
gid = uap->gid;
- AUDIT_ARG(gid, gid, 0, 0, 0);
+ AUDIT_ARG(gid, gid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
- if (gid != my_cred->cr_rgid && /* allow setgid(getgid()) */
- gid != my_cred->cr_svgid && /* allow setgid(saved gid) */
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
+ for (;;) {
+ if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
+ gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
- /*
- * If we are priviledged, then set the saved and real GID too;
- * otherwise, just set the effective GID
- */
- if (suser(my_cred, &p->p_acflag) == 0) {
- svgid = gid;
- rgid = gid;
- }
+ /*
+ * If we are privileged, then set the saved and real GID too;
+ * otherwise, just set the effective GID
+ */
+ if (suser(my_cred, &p->p_acflag) == 0) {
+ svgid = gid;
+ rgid = gid;
+ } else {
+ svgid = KAUTH_GID_NONE;
+ rgid = KAUTH_GID_NONE;
+ }
- /* get current credential and take a reference while we muck with it */
- for (;;) {
-
/*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
}
break;
}
* the supplementary group list unchanged.
*/
int
-setegid(proc_t p, struct setegid_args *uap, __unused register_t *retval)
+setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
{
gid_t egid;
int error;
kauth_cred_t my_cred, my_new_cred;
+ posix_cred_t my_pcred;
DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
egid = uap->egid;
- AUDIT_ARG(gid, 0, egid, 0, 0);
+ AUDIT_ARG(egid, egid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
- if (egid != my_cred->cr_rgid &&
- egid != my_cred->cr_svgid &&
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
- /* get current credential and take a reference while we muck with it */
for (;;) {
+ if (egid != my_pcred->cr_rgid &&
+ egid != my_pcred->cr_svgid &&
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
/*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
if (my_cred != my_new_cred) {
- DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+ DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
}
break;
}
* the supplementary group list unchanged.
*/
int
-setregid(proc_t p, struct setregid_args *uap, __unused register_t *retval)
+setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
{
gid_t rgid, egid;
int error;
kauth_cred_t my_cred, my_new_cred;
+ posix_cred_t my_pcred;
DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
rgid = KAUTH_GID_NONE;
if (egid == (uid_t)-1)
egid = KAUTH_GID_NONE;
- AUDIT_ARG(gid, egid, rgid, 0, 0);
+ AUDIT_ARG(egid, egid);
+ AUDIT_ARG(rgid, rgid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
- if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
- rgid != my_cred->cr_rgid && /* allow rgid = rgid */
- rgid != my_cred->cr_gid && /* allow rgid = egid */
- rgid != my_cred->cr_svgid) || /* allow rgid = svgid */
- (egid != KAUTH_UID_NONE && /* allow no change of egid */
- egid != my_cred->cr_groups[0] && /* allow no change of egid */
- egid != my_cred->cr_gid && /* allow egid = egid */
- egid != my_cred->cr_rgid && /* allow egid = rgid */
- egid != my_cred->cr_svgid)) && /* allow egid = svgid */
- (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /* get current credential and take a reference while we muck with it */
for (;;) {
- uid_t new_egid = my_cred->cr_gid;
- uid_t new_rgid = my_cred->cr_rgid;
+
+ if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
+ rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
+ rgid != my_pcred->cr_gid && /* allow rgid = egid */
+ rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
+ (egid != KAUTH_UID_NONE && /* allow no change of egid */
+ egid != my_pcred->cr_groups[0] && /* allow no change of egid */
+ egid != my_pcred->cr_gid && /* allow egid = egid */
+ egid != my_pcred->cr_rgid && /* allow egid = rgid */
+ egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
+ (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
+ kauth_cred_unref(&my_cred);
+ return (error);
+ }
+
+ uid_t new_egid = my_pcred->cr_gid;
+ uid_t new_rgid = my_pcred->cr_rgid;
uid_t svgid = KAUTH_UID_NONE;
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
*/
- if (egid == KAUTH_UID_NONE && my_cred->cr_groups[0] != egid) {
+ if (egid != KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
/* changing the effective GID */
new_egid = egid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
}
- if (rgid != KAUTH_UID_NONE && my_cred->cr_rgid != rgid) {
+ if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) {
/* changing the real GID */
new_rgid = rgid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
}
/*
* If the newly requested real gid or effective gid does
* new effective gid. We are protected from escalation
* by the prechecking.
*/
- if (my_cred->cr_svgid != uap->rgid &&
- my_cred->cr_svgid != uap->egid) {
+ if (my_pcred->cr_svgid != uap->rgid &&
+ my_pcred->cr_svgid != uap->egid) {
svgid = new_egid;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
}
my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
if (my_cred != my_new_cred) {
- DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
+ DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
- proc_lock(p);
+ proc_ucred_lock(p);
/* need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag); /* XXX redundant? */
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
+ proc_ucred_unlock(p);
}
break;
}
/*
* Set the per-thread override identity. The first parameter can be the
- * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
+ * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
* can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
* means "revert to the per process credential"; otherwise, if permitted,
* it changes the effective, real, and saved UIDs and GIDs for the current
* thread to the requested UID and single GID, and clears all other GIDs.
*/
int
-settid(proc_t p, struct settid_args *uap, __unused register_t *retval)
+settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
{
kauth_cred_t uc;
struct uthread *uthread = get_bsdthread_info(current_thread());
uid = uap->uid;
gid = uap->gid;
- AUDIT_ARG(uid, uid, gid, gid, 0);
+ AUDIT_ARG(uid, uid);
+ AUDIT_ARG(gid, gid);
if (proc_suser(p) != 0)
return (EPERM);
* When the assume argument is zero we revert back to our normal identity.
*/
int
-settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused register_t *retval)
+settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
{
proc_t target_proc;
struct uthread *uthread = get_bsdthread_info(current_thread());
kauth_cred_t my_cred, my_target_cred, my_new_cred;
+ posix_cred_t my_target_pcred;
AUDIT_ARG(pid, uap->pid);
- AUDIT_ARG(value, uap->assume);
+ AUDIT_ARG(value32, uap->assume);
if (proc_suser(p) != 0) {
return (EPERM);
kauth_cred_ref(uthread->uu_ucred);
my_cred = uthread->uu_ucred;
my_target_cred = kauth_cred_proc_ref(target_proc);
- my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
+ my_target_pcred = posix_cred_get(my_target_cred);
+ my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
if (my_cred != my_new_cred)
uthread->uu_ucred = my_new_cred;
* flag the process as having set privilege since the last exec.
*/
static int
-setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused register_t *retval)
+setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
{
u_int ngrp;
gid_t newgroups[NGROUPS] = { 0 };
DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another
* thread also changed the credential after we
* with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
/* try again */
continue;
}
p->p_ucred = my_new_cred;
- OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
- proc_unlock(p);
+ /* update cred on proc */
+ PROC_UPDATE_CREDS_ONPROC(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
}
break;
}
/* Drop old proc reference or our extra reference */
- AUDIT_ARG(groupset, my_cred->cr_groups, ngrp);
+ AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp);
kauth_cred_unref(&my_cred);
* See also: setgroups1()
*/
int
-initgroups(proc_t p, struct initgroups_args *uap, __unused register_t *retval)
+initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
{
DEBUG_CRED_ENTER("initgroups\n");
* See also: setgroups1()
*/
int
-setgroups(proc_t p, struct setgroups_args *uap, __unused register_t *retval)
+setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
{
DEBUG_CRED_ENTER("setgroups\n");
/*
* Set the per-thread/per-process supplementary groups list.
+ *
+ * XXX implement setsgroups
+ *
*/
-#warning XXX implement setsgroups
+
int
-setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused register_t *retval)
+setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
{
return(ENOTSUP);
}
/*
* Set the per-thread/per-process whiteout groups list.
+ *
+ * XXX implement setwgroups
+ *
*/
-#warning XXX implement setwgroups
+
int
-setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused register_t *retval)
+setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
{
return(ENOTSUP);
}
}
-/*
- * XXX This interface is going away; use kauth_cred_issuser() directly
- * XXX instead.
- */
-int
-is_suser(void)
-{
- proc_t p = current_proc();
-
- if (!p)
- return (0);
-
- return (proc_suser(p) == 0);
-}
-
-
-/*
- * XXX This interface is going away; use kauth_cred_issuser() directly
- * XXX instead.
- */
-int
-is_suser1(void)
-{
- proc_t p = current_proc();
- kauth_cred_t my_cred;
- int err;
-
- if (!p)
- return (0);
-
- my_cred = kauth_cred_proc_ref(p);
-
- err = (suser(my_cred, &p->p_acflag) == 0 ||
- my_cred->cr_ruid == 0 || my_cred->cr_svuid == 0);
- kauth_cred_unref(&my_cred);
- return(err);
-}
-
-
/*
* getlogin
*
* XXX: Belongs in kern_proc.c
*/
int
-getlogin(proc_t p, struct getlogin_args *uap, __unused register_t *retval)
+getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
{
char buffer[MAXLOGNAME+1];
struct session * sessp;
* XXX: Belongs in kern_proc.c
*/
int
-setlogin(proc_t p, struct setlogin_args *uap, __unused register_t *retval)
+setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
{
int error;
- int dummy=0;
+ size_t dummy=0;
char buffer[MAXLOGNAME+1];
struct session * sessp;
*/
int
set_security_token(proc_t p)
+{
+ return set_security_token_task_internal(p, p->task);
+}
+
+/*
+ * Set the secrity token of the task with current euid and eguid
+ * The function takes a proc and a task, where proc->task might point to a
+ * different task if called from exec.
+ */
+
+int
+set_security_token_task_internal(proc_t p, void *t)
{
security_token_t sec_token;
audit_token_t audit_token;
kauth_cred_t my_cred;
+ posix_cred_t my_pcred;
host_priv_t host_priv;
+ task_t task = t;
/*
* Don't allow a vfork child to override the parent's token settings
* suffer along using the parent's token until the exec(). It's all
* undefined behavior anyway, right?
*/
- if (p->task == current_task()) {
+ if (task == current_task()) {
uthread_t uthread;
uthread = (uthread_t)get_bsdthread_info(current_thread());
if (uthread->uu_flag & UT_VFORK)
}
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
+
/* XXX mach_init doesn't have a p_ucred when it calls this function */
if (IS_VALID_CRED(my_cred)) {
sec_token.val[0] = kauth_cred_getuid(my_cred);
- sec_token.val[1] = my_cred->cr_gid;
+ sec_token.val[1] = kauth_cred_getgid(my_cred);
} else {
sec_token.val[0] = 0;
sec_token.val[1] = 0;
* the user of the trailer from future representation
* changes.
*/
- audit_token.val[0] = my_cred->cr_au.ai_auid;
- audit_token.val[1] = my_cred->cr_uid;
- audit_token.val[2] = my_cred->cr_gid;
- audit_token.val[3] = my_cred->cr_ruid;
- audit_token.val[4] = my_cred->cr_rgid;
+ audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
+ audit_token.val[1] = my_pcred->cr_uid;
+ audit_token.val[2] = my_pcred->cr_gid;
+ audit_token.val[3] = my_pcred->cr_ruid;
+ audit_token.val[4] = my_pcred->cr_rgid;
audit_token.val[5] = p->p_pid;
- audit_token.val[6] = my_cred->cr_au.ai_asid;
+ audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
audit_token.val[7] = p->p_idversion;
-#if CONFIG_MACF_MACH
- mac_task_label_update_cred(my_cred, p->task);
-#endif
-
host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
#if CONFIG_MACF
if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
#endif
kauth_cred_unref(&my_cred);
+#if DEVELOPMENT || DEBUG
+ /*
+ * Update the pid an proc name for importance base if any
+ */
+ task_importance_update_owner_info(task);
+#endif
+
return (host_security_set_task_token(host_security_self(),
- p->task,
+ task,
sec_token,
audit_token,
host_priv) != KERN_SUCCESS);
}
+int get_audit_token_pid(audit_token_t *audit_token);
+
+int
+get_audit_token_pid(audit_token_t *audit_token)
+{
+ /* keep in-sync with set_security_token (above) */
+ if (audit_token)
+ return (int)audit_token->val[5];
+ return -1;
+}
+
+
/*
* Fill in a struct xucred based on a kauth_cred_t.
*/
void
cru2x(kauth_cred_t cr, struct xucred *xcr)
{
+ posix_cred_t pcr = posix_cred_get(cr);
bzero(xcr, sizeof(*xcr));
xcr->cr_version = XUCRED_VERSION;
xcr->cr_uid = kauth_cred_getuid(cr);
- xcr->cr_ngroups = cr->cr_ngroups;
- bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
-}
-
-#if CONFIG_LCTX
-
-/*
- * Set Login Context ID
- */
-/*
- * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
- * LCTX by its own locks.
- */
-int
-setlcid(proc_t p0, struct setlcid_args *uap, __unused register_t *retval)
-{
- proc_t p;
- struct lctx *l;
- int error = 0;
- int refheld = 0;
-
- AUDIT_ARG(pid, uap->pid);
- AUDIT_ARG(value, uap->lcid);
- if (uap->pid == LCID_PROC_SELF) { /* Create/Join/Leave */
- p = p0;
- } else { /* Adopt/Orphan */
- p = proc_find(uap->pid);
- if (p == NULL)
- return (ESRCH);
- refheld = 1;
- }
-
-#if CONFIG_MACF
- error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
- if (error)
- goto out;
-#endif
-
- switch (uap->lcid) {
- /* Leave/Orphan */
- case LCID_REMOVE:
-
- /* Only root may Leave/Orphan. */
- if (!is_suser1()) {
- error = EPERM;
- goto out;
- }
-
- /* Process not in login context. */
- if (p->p_lctx == NULL) {
- error = ENOATTR;
- goto out;
- }
-
- l = NULL;
-
- break;
-
- /* Create */
- case LCID_CREATE:
-
- /* Create only valid for self! */
- if (uap->pid != LCID_PROC_SELF) {
- error = EPERM;
- goto out;
- }
-
- /* Already in a login context. */
- if (p->p_lctx != NULL) {
- error = EPERM;
- goto out;
- }
-
- l = lccreate();
- if (l == NULL) {
- error = ENOMEM;
- goto out;
- }
-
- LCTX_LOCK(l);
-
- break;
-
- /* Join/Adopt */
- default:
-
- /* Only root may Join/Adopt. */
- if (!is_suser1()) {
- error = EPERM;
- goto out;
- }
-
- l = lcfind(uap->lcid);
- if (l == NULL) {
- error = ENOATTR;
- goto out;
- }
-
- break;
- }
-
- ALLLCTX_LOCK;
- leavelctx(p);
- enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
- ALLLCTX_UNLOCK;
-
-out:
- if (refheld != 0)
- proc_rele(p);
- return (error);
-}
-
-/*
- * Get Login Context ID
- */
-/*
- * MPSAFE - membership of (visible) process in a login context
- * protected by the all-context lock.
- */
-int
-getlcid(proc_t p0, struct getlcid_args *uap, register_t *retval)
-{
- proc_t p;
- int error = 0;
- int refheld = 0;
-
- AUDIT_ARG(pid, uap->pid);
- if (uap->pid == LCID_PROC_SELF) {
- p = p0;
- } else {
- p = proc_find(uap->pid);
- if (p == NULL)
- return (ESRCH);
- refheld = 1;
- }
-
-#if CONFIG_MACF
- error = mac_proc_check_getlcid(p0, p, uap->pid);
- if (error)
- goto out;
-#endif
- ALLLCTX_LOCK;
- if (p->p_lctx == NULL) {
- error = ENOATTR;
- ALLLCTX_UNLOCK;
- goto out;
- }
- *retval = p->p_lctx->lc_id;
- ALLLCTX_UNLOCK;
- out:
- if (refheld != 0)
- proc_rele(p);
-
- return (error);
-}
-#else /* LCTX */
-int
-setlcid(proc_t p0, struct setlcid_args *uap, register_t *retval)
-{
-
- return (ENOSYS);
-}
-
-int
-getlcid(proc_t p0, struct getlcid_args *uap, register_t *retval)
-{
-
- return (ENOSYS);
+ xcr->cr_ngroups = pcr->cr_ngroups;
+ bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
}
-#endif /* !LCTX */