1/*
2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 *
28 *
29 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
30 *
31 *
32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
33 *	The Regents of the University of California.  All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 *    notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 *    must display the following acknowledgement:
50 *	This product includes software developed by the University of
51 *	California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 *    may be used to endorse or promote products derived from this software
54 *    without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
69 *
70 *
71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
72 * support for mandatory and extensible security protections.  This notice
73 * is included in support of clause 2.2 (b) of the Apple Public License,
74 * Version 2.0.
75 *
76 *
77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
78 * support for mandatory and extensible security protections.  This notice
79 * is included in support of clause 2.2 (b) of the Apple Public License,
80 * Version 2.0.
81 *
82 */
83
84/*
85 * System calls related to processes and protection
86 */
87
88#include <sys/param.h>
89#include <sys/acct.h>
90#include <sys/systm.h>
91#include <sys/ucred.h>
92#include <sys/proc_internal.h>
93#include <sys/user.h>
94#include <sys/kauth.h>
95#include <sys/timeb.h>
96#include <sys/times.h>
97#include <sys/malloc.h>
98
99#include <security/audit/audit.h>
100
101#if CONFIG_LCTX
102#include <sys/lctx.h>
103#endif
104
105#if CONFIG_MACF
106#include <security/mac_framework.h>
107#if CONFIG_MACF_MACH
108#include <secuity/mac_mach_internal.h>
109#endif
110#endif
111
112#include <sys/mount_internal.h>
113#include <sys/sysproto.h>
114#include <mach/message.h>
115#include <mach/host_security.h>
116
117#include <kern/host.h>
118#include <kern/task.h>		/* for current_task() */
119#include <kern/assert.h>
120
121
122/*
123 * Credential debugging; we can track entry into a function that might
124 * change a credential, and we can track actual credential changes that
125 * result.
126 *
127 * Note:	Does *NOT* currently include per-thread credential changes
128 *
129 *		We don't use kauth_cred_print() in current debugging, but it
130 *		can be used if needed when debugging is active.
131 */
132#if DEBUG_CRED
133#define	DEBUG_CRED_ENTER		printf
134#define	DEBUG_CRED_CHANGE		printf
135extern void kauth_cred_print(kauth_cred_t cred);
136#else	/* !DEBUG_CRED */
137#define	DEBUG_CRED_ENTER(fmt, ...)	do {} while (0)
138#define	DEBUG_CRED_CHANGE(fmt, ...)	do {} while (0)
139#endif	/* !DEBUG_CRED */
140
141
142
143/*
144 * setprivexec
145 *
146 * Description:	(dis)allow this process to hold task, thread, or execption
147 *		ports of processes about to exec.
148 *
149 * Parameters:	uap->flag			New value for flag
150 *
151 * Returns:	int				Previous value of flag
152 *
153 * XXX:		Belongs in kern_proc.c
154 */
155int
156setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
157{
158	AUDIT_ARG(value32, uap->flag);
159	*retval = p->p_debugger;
160	p->p_debugger = (uap->flag != 0);
161	return(0);
162}
163
164
165/*
166 * getpid
167 *
168 * Description:	get the process ID
169 *
170 * Parameters:	(void)
171 *
172 * Returns:	pid_t				Current process ID
173 *
174 * XXX:		Belongs in kern_proc.c
175 */
176int
177getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
178{
179
180	*retval = p->p_pid;
181	return (0);
182}
183
184
185/*
186 * getppid
187 *
188 * Description: get the parent process ID
189 *
190 * Parameters:	(void)
191 *
192 * Returns:	pid_t				Parent process ID
193 *
194 * XXX:		Belongs in kern_proc.c
195 */
196int
197getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
198{
199
200	*retval = p->p_ppid;
201	return (0);
202}
203
204
205/*
206 * getpgrp
207 *
208 * Description:	get the process group ID of the calling process
209 *
210 * Parameters:	(void)
211 *
212 * Returns:	pid_t				Process group ID
213 *
214 * XXX:		Belongs in kern_proc.c
215 */
216int
217getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
218{
219
220	*retval = p->p_pgrpid;
221	return (0);
222}
223
224
225/*
226 * getpgid
227 *
228 * Description: Get an arbitary pid's process group id
229 *
230 * Parameters:	uap->pid			The target pid
231 *
232 * Returns:	0				Success
233 *		ESRCH				No such process
234 *
235 * Notes:	We are permitted to return EPERM in the case that the target
236 *		process is not in the same session as the calling process,
237 *		which could be a security consideration
238 *
239 * XXX:		Belongs in kern_proc.c
240 */
241int
242getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
243{
244	proc_t pt;
245	int refheld = 0;
246
247	pt = p;
248	if (uap->pid == 0)
249		goto found;
250
251	if ((pt = proc_find(uap->pid)) == 0)
252		return (ESRCH);
253	refheld = 1;
254found:
255	*retval = pt->p_pgrpid;
256	if (refheld != 0)
257		proc_rele(pt);
258	return (0);
259}
260
261
262/*
263 * getsid
264 *
265 * Description:	Get an arbitary pid's session leaders process group ID
266 *
267 * Parameters:	uap->pid			The target pid
268 *
269 * Returns:	0				Success
270 *		ESRCH				No such process
271 *
272 * Notes:	We are permitted to return EPERM in the case that the target
273 *		process is not in the same session as the calling process,
274 *		which could be a security consideration
275 *
276 * XXX:		Belongs in kern_proc.c
277 */
278int
279getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
280{
281	proc_t pt;
282	int refheld = 0;
283	struct session * sessp;
284
285	pt = p;
286	if (uap->pid == 0)
287		goto found;
288
289	if ((pt = proc_find(uap->pid)) == 0)
290		return (ESRCH);
291	refheld = 1;
292found:
293	sessp = proc_session(pt);
294	*retval = sessp->s_sid;
295	session_rele(sessp);
296
297	if (refheld != 0)
298		proc_rele(pt);
299	return (0);
300}
301
302
303/*
304 * getuid
305 *
306 * Description:	get real user ID for caller
307 *
308 * Parameters:	(void)
309 *
310 * Returns:	uid_t				The real uid of the caller
311 */
312int
313getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
314{
315
316 	*retval = kauth_getruid();
317	return (0);
318}
319
320
321/*
322 * geteuid
323 *
324 * Description:	get effective user ID for caller
325 *
326 * Parameters:	(void)
327 *
328 * Returns:	uid_t				The effective uid of the caller
329 */
330int
331geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
332{
333
334 	*retval = kauth_getuid();
335	return (0);
336}
337
338
339/*
340 * gettid
341 *
342 * Description:	Return the per-thread override identity.
343 *
344 * Parameters:	uap->uidp			Address of uid_t to get uid
345 *		uap->gidp			Address of gid_t to get gid
346 *
347 * Returns:	0				Success
348 *		ESRCH				No per thread identity active
349 */
350int
351gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
352{
353	struct uthread *uthread = get_bsdthread_info(current_thread());
354	int	error;
355
356	/*
357	 * If this thread is not running with an override identity, we can't
358	 * return one to the caller, so return an error instead.
359	 */
360	if (!(uthread->uu_flag & UT_SETUID))
361		return (ESRCH);
362
363	if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred))))
364		return (error);
365	if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred))))
366		return (error);
367
368	*retval = 0;
369	return (0);
370}
371
372
373/*
374 * getgid
375 *
376 * Description:	get the real group ID for the calling process
377 *
378 * Parameters:	(void)
379 *
380 * Returns:	gid_t				The real gid of the caller
381 */
382int
383getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
384{
385
386	*retval = kauth_getrgid();
387	return (0);
388}
389
390
391/*
392 * getegid
393 *
394 * Description:	get the effective group ID for the calling process
395 *
396 * Parameters:	(void)
397 *
398 * Returns:	gid_t				The effective gid of the caller
399 *
400 * Notes:	As an implementation detail, the effective gid is stored as
401 *		the first element of the supplementary group list.
402 *
403 *		This could be implemented in Libc instead because of the above
404 *		detail.
405 */
406int
407getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
408{
409
410	*retval = kauth_getgid();
411	return (0);
412}
413
414
415/*
416 * getgroups
417 *
418 * Description:	get the list of supplementary groups for the calling process
419 *
420 * Parameters:	uap->gidsetsize			# of gid_t's in user buffer
421 *		uap->gidset			Pointer to user buffer
422 *
423 * Returns:	0				Success
424 *		EINVAL				User buffer too small
425 *	copyout:EFAULT				User buffer invalid
426 *
427 * Retval:	-1				Error
428 *		!0				# of groups
429 *
430 * Notes:	The caller may specify a 0 value for gidsetsize, and we will
431 *		then return how large a buffer is required (in gid_t's) to
432 *		contain the answer at the time of the call.  Otherwise, we
433 *		return the number of gid_t's catually copied to user space.
434 *
435 *		When called with a 0 gidsetsize from a multithreaded program,
436 *		there is no guarantee that another thread may not change the
437 *		number of supplementary groups, and therefore a subsequent
438 *		call could still fail, unless the maximum possible buffer
439 *		size is supplied by the user.
440 *
441 *		As an implementation detail, the effective gid is stored as
442 *		the first element of the supplementary group list, and will
443 *		be returned by this call.
444 */
445int
446getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
447{
448	int ngrp;
449	int error;
450	kauth_cred_t cred;
451	posix_cred_t pcred;
452
453	/* grab reference while we muck around with the credential */
454	cred = kauth_cred_get_with_ref();
455	pcred = posix_cred_get(cred);
456
457	if ((ngrp = uap->gidsetsize) == 0) {
458		*retval = pcred->cr_ngroups;
459		kauth_cred_unref(&cred);
460		return (0);
461	}
462	if (ngrp < pcred->cr_ngroups) {
463		kauth_cred_unref(&cred);
464		return (EINVAL);
465	}
466	ngrp = pcred->cr_ngroups;
467	if ((error = copyout((caddr_t)pcred->cr_groups,
468	    				uap->gidset,
469	    				ngrp * sizeof(gid_t)))) {
470		kauth_cred_unref(&cred);
471		return (error);
472	}
473	kauth_cred_unref(&cred);
474	*retval = ngrp;
475	return (0);
476}
477
478
479/*
480 * Return the per-thread/per-process supplementary groups list.
481 *
482 * XXX implement getsgroups
483 *
484 */
485
486int
487getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
488{
489	return(ENOTSUP);
490}
491
492/*
493 * Return the per-thread/per-process whiteout groups list.
494 *
495 * XXX implement getwgroups
496 *
497 */
498
499int
500getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
501{
502	return(ENOTSUP);
503}
504
505
506/*
507 * setsid
508 *
509 * Description:	Create a new session and set the process group ID to the
510 *		session ID
511 *
512 * Parameters:	(void)
513 *
514 * Returns:	0				Success
515 *		EPERM				Permission denied
516 *
517 * Notes:	If the calling process is not the process group leader; there
518 *		is no existing process group with its ID, and we are not
519 *		currently in vfork, then this function will create a new
520 *		session, a new process group, and put the caller in the
521 *		process group (as the sole member) and make it the session
522 *		leader (as the sole process in the session).
523 *
524 *		The existing controlling tty (if any) will be dissociated
525 *		from the process, and the next non-O_NOCTTY open of a tty
526 *		will establish a new controlling tty.
527 *
528 * XXX:		Belongs in kern_proc.c
529 */
530int
531setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
532{
533	struct pgrp * pg = PGRP_NULL;
534
535	if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
536		if (pg != PGRP_NULL)
537			pg_rele(pg);
538		return (EPERM);
539	} else {
540		/* enter pgrp works with its own pgrp refcount */
541		(void)enterpgrp(p, p->p_pid, 1);
542		*retval = p->p_pid;
543		return (0);
544	}
545}
546
547
548/*
549 * setpgid
550 *
551 * Description: set process group ID for job control
552 *
553 * Parameters:	uap->pid			Process to change
554 *		uap->pgid			Process group to join or create
555 *
556 * Returns:	0			Success
557 *		ESRCH			pid is not the caller or a child of
558 *					the caller
559 *	enterpgrp:ESRCH			No such process
560 *		EACCES			Permission denied due to exec
561 *		EINVAL			Invalid argument
562 *		EPERM			The target process is not in the same
563 *					session as the calling process
564 *		EPERM			The target process is a session leader
565 *		EPERM			pid and pgid are not the same, and
566 *					there is no process in the calling
567 *					process whose process group ID matches
568 *					pgid
569 *
570 * Notes:	This function will cause the target process to either join
571 *		an existing process process group, or create a new process
572 *		group in the session of the calling process.  It cannot be
573 *		used to change the process group ID of a process which is
574 *		already a session leader.
575 *
576 *		If the target pid is 0, the pid of the calling process is
577 *		substituted as the new target; if pgid is 0, the target pid
578 *		is used as the target process group ID.
579 *
580 * Legacy:	This system call entry point is also used to implement the
581 *		legacy library routine setpgrp(), which under POSIX
582 *
583 * XXX:		Belongs in kern_proc.c
584 */
585int
586setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval)
587{
588	proc_t targp = PROC_NULL;	/* target process */
589	struct pgrp *pg = PGRP_NULL;	/* target pgrp */
590	int error = 0;
591	int refheld = 0;
592	int samesess = 0;
593	struct session * curp_sessp = SESSION_NULL;
594	struct session * targp_sessp = SESSION_NULL;
595
596	curp_sessp = proc_session(curp);
597
598	if (uap->pid != 0 && uap->pid != curp->p_pid) {
599		if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
600			if (targp != PROC_NULL)
601				refheld = 1;
602			error = ESRCH;
603			goto out;
604		}
605		refheld = 1;
606		targp_sessp = proc_session(targp);
607		if (targp_sessp != curp_sessp) {
608			error = EPERM;
609			goto out;
610		}
611		if (targp->p_flag & P_EXEC) {
612			error = EACCES;
613			goto out;
614		}
615	} else {
616		targp = curp;
617		targp_sessp = proc_session(targp);
618	}
619
620	if (SESS_LEADER(targp, targp_sessp)) {
621		error = EPERM;
622		goto out;
623	}
624	if (targp_sessp != SESSION_NULL) {
625		session_rele(targp_sessp);
626		targp_sessp = SESSION_NULL;
627	}
628
629	if (uap->pgid < 0) {
630		error = EINVAL;
631		goto out;
632	}
633	if (uap->pgid == 0)
634		uap->pgid = targp->p_pid;
635	else if (uap->pgid != targp->p_pid) {
636		if ((pg = pgfind(uap->pgid)) == 0){
637			error = EPERM;
638			goto out;
639		}
640		samesess = (pg->pg_session != curp_sessp);
641		pg_rele(pg);
642		if (samesess != 0) {
643			error = EPERM;
644			goto out;
645		}
646	}
647	error = enterpgrp(targp, uap->pgid, 0);
648out:
649	if (targp_sessp != SESSION_NULL)
650		session_rele(targp_sessp);
651	if (curp_sessp != SESSION_NULL)
652		session_rele(curp_sessp);
653	if (refheld != 0)
654		proc_rele(targp);
655	return(error);
656}
657
658
659/*
660 * issetugid
661 *
662 * Description:	Is current process tainted by uid or gid changes system call
663 *
664 * Parameters:	(void)
665 *
666 * Returns:	0				Not tainted
667 *		1				Tainted
668 *
669 * Notes:	A process is considered tainted if it was created as a retult
670 *		of an execve call from an imnage that had either the SUID or
671 *		SGID bit set on the executable, or if it has changed any of its
672 *		real, effective, or saved user or group IDs since beginning
673 *		execution.
674 */
675int
676issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
677{
678	/*
679	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
680	 * we use P_SUGID because we consider changing the owners as
681	 * "tainting" as well.
682	 * This is significant for procs that start as root and "become"
683	 * a user without an exec - programs cannot know *everything*
684	 * that libc *might* have put in their data segment.
685	 */
686
687	*retval = (p->p_flag & P_SUGID) ? 1 : 0;
688	return (0);
689}
690
691
692/*
693 * setuid
694 *
695 * Description:	Set user ID system call
696 *
697 * Parameters:	uap->uid			uid to set
698 *
699 * Returns:	0				Success
700 *	suser:EPERM				Permission denied
701 *
702 * Notes:	If called by a privileged process, this function will set the
703 *		real, effective, and saved uid to the requested value.
704 *
705 *		If called from an unprivileged process, but uid is equal to the
706 *		real or saved uid, then the effective uid will be set to the
707 *		requested value, but the real and saved uid will not change.
708 *
709 *		If the credential is changed as a result of this call, then we
710 *		flag the process as having set privilege since the last exec.
711 */
712int
713setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
714{
715	uid_t uid;
716	uid_t svuid = KAUTH_UID_NONE;
717	uid_t ruid = KAUTH_UID_NONE;
718	uid_t gmuid = KAUTH_UID_NONE;
719	int error;
720	kauth_cred_t my_cred, my_new_cred;
721	posix_cred_t my_pcred;
722
723
724	uid = uap->uid;
725
726	my_cred = kauth_cred_proc_ref(p);
727	my_pcred = posix_cred_get(my_cred);
728
729	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);
730	AUDIT_ARG(uid, uid);
731
732	if (uid != my_pcred->cr_ruid &&		/* allow setuid(getuid()) */
733	    uid != my_pcred->cr_svuid &&	/* allow setuid(saved uid) */
734	    (error = suser(my_cred, &p->p_acflag))) {
735		kauth_cred_unref(&my_cred);
736		return (error);
737	}
738	/*
739	 * Everything's okay, do it.
740	 */
741
742	/*
743	 * If we are priviledged, then set the saved and real UID too;
744	 * otherwise, just set the effective UID
745	 */
746	if (suser(my_cred, &p->p_acflag) == 0) {
747		svuid = uid;
748		ruid = uid;
749		/*
750		 * Transfer proc count to new user.
751		 * chgproccnt uses list lock for protection
752		 */
753		(void)chgproccnt(uid, 1);
754		(void)chgproccnt(my_pcred->cr_ruid, -1);
755	}
756
757	/* get current credential and take a reference while we muck with it */
758	for (;;) {
759		/*
760		 * Only set the gmuid if the current cred has not opt'ed out;
761		 * this normally only happens when calling setgroups() instead
762		 * of initgroups() to set an explicit group list, or one of the
763		 * other group manipulation functions is invoked and results in
764		 * a dislocation (i.e. the credential group membership changes
765		 * to something other than the default list for the user, as
766		 * in entering a group or leaving an exclusion group).
767		 */
768		if (!(my_pcred->cr_flags & CRF_NOMEMBERD))
769			gmuid = uid;
770
771  		/*
772		 * Set the credential with new info.  If there is no change,
773		 * we get back the same credential we passed in; if there is
774		 * a change, we drop the reference on the credential we
775		 * passed in.  The subsequent compare is safe, because it is
776		 * a pointer compare rather than a contents compare.
777  		 */
778		my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
779		if (my_cred != my_new_cred) {
780
781			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);
782
783			proc_lock(p);
784			/*
785			 * We need to protect for a race where another thread
786			 * also changed the credential after we took our
787			 * reference.  If p_ucred has changed then we should
788			 * restart this again with the new cred.
789			 */
790			if (p->p_ucred != my_cred) {
791				proc_unlock(p);
792				kauth_cred_unref(&my_new_cred);
793				my_cred = kauth_cred_proc_ref(p);
794				/* try again */
795				continue;
796			}
797			p->p_ucred = my_new_cred;
798			/* update cred on proc */
799			PROC_UPDATE_CREDS_ONPROC(p);
800
801			OSBitOrAtomic(P_SUGID, &p->p_flag);
802			proc_unlock(p);
803		}
804		break;
805	}
806	/* Drop old proc reference or our extra reference */
807	kauth_cred_unref(&my_cred);
808
809	set_security_token(p);
810	return (0);
811}
812
813
814/*
815 * seteuid
816 *
817 * Description:	Set effective user ID system call
818 *
819 * Parameters:	uap->euid			effective uid to set
820 *
821 * Returns:	0				Success
822 *	suser:EPERM				Permission denied
823 *
824 * Notes:	If called by a privileged process, or called from an
825 *		unprivileged process but euid is equal to the real or saved
826 *		uid, then the effective uid will be set to the requested
827 *		value, but the real and saved uid will not change.
828 *
829 *		If the credential is changed as a result of this call, then we
830 *		flag the process as having set privilege since the last exec.
831 */
832int
833seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
834{
835	uid_t euid;
836	int error;
837	kauth_cred_t my_cred, my_new_cred;
838	posix_cred_t my_pcred;
839
840	DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
841
842	euid = uap->euid;
843	AUDIT_ARG(euid, euid);
844
845	my_cred = kauth_cred_proc_ref(p);
846	my_pcred = posix_cred_get(my_cred);
847
848	if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
849	    (error = suser(my_cred, &p->p_acflag))) {
850		kauth_cred_unref(&my_cred);
851		return (error);
852	}
853
854	/*
855	 * Everything's okay, do it.  Copy credentials so other references do
856	 * not see our changes.  get current credential and take a reference
857	 * while we muck with it
858	 */
859	for (;;) {
860  		/*
861		 * Set the credential with new info.  If there is no change,
862		 * we get back the same credential we passed in; if there is
863		 * a change, we drop the reference on the credential we
864		 * passed in.  The subsequent compare is safe, because it is
865		 * a pointer compare rather than a contents compare.
866  		 */
867		my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
868
869		if (my_cred != my_new_cred) {
870
871			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);
872
873			proc_lock(p);
874			/*
875			 * We need to protect for a race where another thread
876			 * also changed the credential after we took our
877			 * reference.  If p_ucred has changed then we
878			 * should restart this again with the new cred.
879			 */
880			if (p->p_ucred != my_cred) {
881				proc_unlock(p);
882				kauth_cred_unref(&my_new_cred);
883				my_cred = kauth_cred_proc_ref(p);
884				/* try again */
885				continue;
886			}
887			p->p_ucred = my_new_cred;
888			/* update cred on proc */
889			PROC_UPDATE_CREDS_ONPROC(p);
890			OSBitOrAtomic(P_SUGID, &p->p_flag);
891			proc_unlock(p);
892		}
893		break;
894	}
895	/* drop old proc reference or our extra reference */
896	kauth_cred_unref(&my_cred);
897
898	set_security_token(p);
899	return (0);
900}
901
902
903/*
904 * setreuid
905 *
906 * Description:	Set real and effective user ID system call
907 *
908 * Parameters:	uap->ruid			real uid to set
909 *		uap->euid			effective uid to set
910 *
911 * Returns:	0				Success
912 *	suser:EPERM				Permission denied
913 *
914 * Notes:	A value of -1 is a special case indicating that the uid for
915 *		which that value is specified not be changed.  If both values
916 *		are specified as -1, no action is taken.
917 *
918 *		If called by a privileged process, the real and effective uid
919 *		will be set to the new value(s) specified.
920 *
921 *		If called from an unprivileged process, the real uid may be
922 *		set to the current value of the real uid, or to the current
923 *		value of the saved uid.  The effective uid may be set to the
924 *		current value of any of the effective, real, or saved uid.
925 *
926 *		If the newly requested real uid or effective uid does not
927 *		match the saved uid, then set the saved uid to the new
928 *		effective uid (potentially unrecoverably dropping saved
929 *		privilege).
930 *
931 *		If the credential is changed as a result of this call, then we
932 *		flag the process as having set privilege since the last exec.
933 */
934int
935setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
936{
937	uid_t ruid, euid;
938	int error;
939	kauth_cred_t my_cred, my_new_cred;
940	posix_cred_t my_pcred;
941
942	DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
943
944	ruid = uap->ruid;
945	euid = uap->euid;
946	if (ruid == (uid_t)-1)
947		ruid = KAUTH_UID_NONE;
948	if (euid == (uid_t)-1)
949		euid = KAUTH_UID_NONE;
950	AUDIT_ARG(euid, euid);
951	AUDIT_ARG(ruid, ruid);
952
953	my_cred = kauth_cred_proc_ref(p);
954	my_pcred = posix_cred_get(my_cred);
955
956	if (((ruid != KAUTH_UID_NONE &&		/* allow no change of ruid */
957	      ruid != my_pcred->cr_ruid &&	/* allow ruid = ruid */
958	      ruid != my_pcred->cr_uid &&	/* allow ruid = euid */
959	      ruid != my_pcred->cr_svuid) ||	/* allow ruid = svuid */
960	     (euid != KAUTH_UID_NONE &&		/* allow no change of euid */
961	      euid != my_pcred->cr_uid &&	/* allow euid = euid */
962	      euid != my_pcred->cr_ruid &&	/* allow euid = ruid */
963	      euid != my_pcred->cr_svuid)) &&	/* allow euid = svui */
964	    (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
965		kauth_cred_unref(&my_cred);
966		return (error);
967	}
968
969	/*
970	 * Everything's okay, do it.  Copy credentials so other references do
971	 * not see our changes.  get current credential and take a reference
972	 * while we muck with it
973	 */
974	for (;;) {
975		uid_t new_euid;
976		uid_t new_ruid;
977		uid_t svuid = KAUTH_UID_NONE;
978
979		new_euid = my_pcred->cr_uid;
980		new_ruid = my_pcred->cr_ruid;
981
982  		/*
983		 * Set the credential with new info.  If there is no change,
984		 * we get back the same credential we passed in; if there is
985		 * a change, we drop the reference on the credential we
986		 * passed in.  The subsequent compare is safe, because it is
987		 * a pointer compare rather than a contents compare.
988  		 */
989		if (euid == KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
990			/* changing the effective UID */
991			new_euid = euid;
992			OSBitOrAtomic(P_SUGID, &p->p_flag);
993		}
994		if (ruid != KAUTH_UID_NONE && my_pcred->cr_ruid != ruid) {
995			/* changing the real UID; must do user accounting */
996		 	/* chgproccnt uses list lock for protection */
997			(void)chgproccnt(ruid, 1);
998			(void)chgproccnt(my_pcred->cr_ruid, -1);
999			new_ruid = ruid;
1000			OSBitOrAtomic(P_SUGID, &p->p_flag);
1001		}
1002		/*
1003		 * If the newly requested real uid or effective uid does
1004		 * not match the saved uid, then set the saved uid to the
1005		 * new effective uid.  We are protected from escalation
1006		 * by the prechecking.
1007		 */
1008		if (my_pcred->cr_svuid != uap->ruid &&
1009		    my_pcred->cr_svuid != uap->euid) {
1010		    	svuid = new_euid;
1011			OSBitOrAtomic(P_SUGID, &p->p_flag);
1012		}
1013
1014		my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
1015
1016		if (my_cred != my_new_cred) {
1017
1018			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);
1019
1020			proc_lock(p);
1021			/*
1022			 * We need to protect for a race where another thread
1023			 * also changed the credential after we took our
1024			 * reference.  If p_ucred has changed then we should
1025			 * restart this again with the new cred.
1026			 */
1027			if (p->p_ucred != my_cred) {
1028				proc_unlock(p);
1029				kauth_cred_unref(&my_new_cred);
1030				my_cred = kauth_cred_proc_ref(p);
1031				/* try again */
1032				continue;
1033			}
1034			p->p_ucred = my_new_cred;
1035			/* update cred on proc */
1036			PROC_UPDATE_CREDS_ONPROC(p);
1037			OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1038			proc_unlock(p);
1039		}
1040		break;
1041	}
1042	/* drop old proc reference or our extra reference */
1043	kauth_cred_unref(&my_cred);
1044
1045	set_security_token(p);
1046	return (0);
1047}
1048
1049
1050/*
1051 * setgid
1052 *
1053 * Description:	Set group ID system call
1054 *
1055 * Parameters:	uap->gid			gid to set
1056 *
1057 * Returns:	0				Success
1058 *	suser:EPERM				Permission denied
1059 *
1060 * Notes:	If called by a privileged process, this function will set the
1061 *		real, effective, and saved gid to the requested value.
1062 *
1063 *		If called from an unprivileged process, but gid is equal to the
1064 *		real or saved gid, then the effective gid will be set to the
1065 *		requested value, but the real and saved gid will not change.
1066 *
1067 *		If the credential is changed as a result of this call, then we
1068 *		flag the process as having set privilege since the last exec.
1069 *
1070 *		As an implementation detail, the effective gid is stored as
1071 *		the first element of the supplementary group list, and
1072 *		therefore the effective group list may be reordered to keep
1073 *		the supplementary group list unchanged.
1074 */
1075int
1076setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
1077{
1078	gid_t gid;
1079	gid_t rgid = KAUTH_GID_NONE;
1080	gid_t svgid = KAUTH_GID_NONE;
1081	int error;
1082	kauth_cred_t my_cred, my_new_cred;
1083	posix_cred_t my_pcred;
1084
1085	DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
1086
1087	gid = uap->gid;
1088	AUDIT_ARG(gid, gid);
1089
1090	my_cred = kauth_cred_proc_ref(p);
1091	my_pcred = posix_cred_get(my_cred);
1092
1093	if (gid != my_pcred->cr_rgid &&		/* allow setgid(getgid()) */
1094	    gid != my_pcred->cr_svgid &&	/* allow setgid(saved gid) */
1095	    (error = suser(my_cred, &p->p_acflag))) {
1096		kauth_cred_unref(&my_cred);
1097		return (error);
1098	}
1099
1100	/*
1101	 * If we are priviledged, then set the saved and real GID too;
1102	 * otherwise, just set the effective GID
1103	 */
1104	if (suser(my_cred,  &p->p_acflag) == 0) {
1105		svgid = gid;
1106		rgid = gid;
1107	}
1108
1109	/* get current credential and take a reference while we muck with it */
1110	for (;;) {
1111
1112  		/*
1113		 * Set the credential with new info.  If there is no change,
1114		 * we get back the same credential we passed in; if there is
1115		 * a change, we drop the reference on the credential we
1116		 * passed in.  The subsequent compare is safe, because it is
1117		 * a pointer compare rather than a contents compare.
1118  		 */
1119		my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
1120		if (my_cred != my_new_cred) {
1121
1122			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);
1123
1124			proc_lock(p);
1125			/*
1126			 * We need to protect for a race where another thread
1127			 * also changed the credential after we took our
1128			 * reference.  If p_ucred has changed then we
1129			 * should restart this again with the new cred.
1130			 */
1131			if (p->p_ucred != my_cred) {
1132				proc_unlock(p);
1133				kauth_cred_unref(&my_new_cred);
1134				/* try again */
1135				my_cred = kauth_cred_proc_ref(p);
1136				continue;
1137			}
1138			p->p_ucred = my_new_cred;
1139			/* update cred on proc */
1140			PROC_UPDATE_CREDS_ONPROC(p);
1141			OSBitOrAtomic(P_SUGID, &p->p_flag);
1142			proc_unlock(p);
1143		}
1144		break;
1145	}
1146	/* Drop old proc reference or our extra reference */
1147	kauth_cred_unref(&my_cred);
1148
1149	set_security_token(p);
1150	return (0);
1151}
1152
1153
1154/*
1155 * setegid
1156 *
1157 * Description:	Set effective group ID system call
1158 *
1159 * Parameters:	uap->egid			effective gid to set
1160 *
1161 * Returns:	0				Success
1162 *	suser:EPERM
1163 *
1164 * Notes:	If called by a privileged process, or called from an
1165 *		unprivileged process but egid is equal to the real or saved
1166 *		gid, then the effective gid will be set to the requested
1167 *		value, but the real and saved gid will not change.
1168 *
1169 *		If the credential is changed as a result of this call, then we
1170 *		flag the process as having set privilege since the last exec.
1171 *
1172 *		As an implementation detail, the effective gid is stored as
1173 *		the first element of the supplementary group list, and
1174 *		therefore the effective group list may be reordered to keep
1175 *		the supplementary group list unchanged.
1176 */
1177int
1178setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1179{
1180	gid_t egid;
1181	int error;
1182	kauth_cred_t my_cred, my_new_cred;
1183	posix_cred_t my_pcred;
1184
1185	DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
1186
1187	egid = uap->egid;
1188	AUDIT_ARG(egid, egid);
1189
1190	my_cred = kauth_cred_proc_ref(p);
1191	my_pcred = posix_cred_get(my_cred);
1192
1193	if (egid != my_pcred->cr_rgid &&
1194	    egid != my_pcred->cr_svgid &&
1195	    (error = suser(my_cred, &p->p_acflag))) {
1196		kauth_cred_unref(&my_cred);
1197		return (error);
1198	}
1199
1200	/* get current credential and take a reference while we muck with it */
1201	for (;;) {
1202  		/*
1203		 * Set the credential with new info.  If there is no change,
1204		 * we get back the same credential we passed in; if there is
1205		 * a change, we drop the reference on the credential we
1206		 * passed in.  The subsequent compare is safe, because it is
1207		 * a pointer compare rather than a contents compare.
1208  		 */
1209		my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
1210		if (my_cred != my_new_cred) {
1211
1212			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);
1213
1214			proc_lock(p);
1215			/*
1216			 * We need to protect for a race where another thread
1217			 * also changed the credential after we took our
1218			 * reference.  If p_ucred has changed then we
1219			 * should restart this again with the new cred.
1220			 */
1221			if (p->p_ucred != my_cred) {
1222				proc_unlock(p);
1223				kauth_cred_unref(&my_new_cred);
1224				/* try again */
1225				my_cred = kauth_cred_proc_ref(p);
1226				continue;
1227			}
1228			p->p_ucred = my_new_cred;
1229			/* update cred on proc */
1230			PROC_UPDATE_CREDS_ONPROC(p);
1231			OSBitOrAtomic(P_SUGID, &p->p_flag);
1232			proc_unlock(p);
1233		}
1234		break;
1235	}
1236
1237	/* Drop old proc reference or our extra reference */
1238	kauth_cred_unref(&my_cred);
1239
1240	set_security_token(p);
1241	return (0);
1242}
1243
1244/*
1245 * setregid
1246 *
1247 * Description:	Set real and effective group ID system call
1248 *
1249 * Parameters:	uap->rgid			real gid to set
1250 *		uap->egid			effective gid to set
1251 *
1252 * Returns:	0				Success
1253 *	suser:EPERM				Permission denied
1254 *
1255 * Notes:	A value of -1 is a special case indicating that the gid for
1256 *		which that value is specified not be changed.  If both values
1257 *		are specified as -1, no action is taken.
1258 *
1259 *		If called by a privileged process, the real and effective gid
1260 *		will be set to the new value(s) specified.
1261 *
1262 *		If called from an unprivileged process, the real gid may be
1263 *		set to the current value of the real gid, or to the current
1264 *		value of the saved gid.  The effective gid may be set to the
1265 *		current value of any of the effective, real, or saved gid.
1266 *
1267 *		If the new real and effective gid will not be equal, or the
1268 *		new real or effective gid is not the same as the saved gid,
1269 *		then the saved gid will be updated to reflect the new
1270 *		effective gid (potentially unrecoverably dropping saved
1271 *		privilege).
1272 *
1273 *		If the credential is changed as a result of this call, then we
1274 *		flag the process as having set privilege since the last exec.
1275 *
1276 *		As an implementation detail, the effective gid is stored as
1277 *		the first element of the supplementary group list, and
1278 *		therefore the effective group list may be reordered to keep
1279 *		the supplementary group list unchanged.
1280 */
1281int
1282setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1283{
1284	gid_t rgid, egid;
1285	int error;
1286	kauth_cred_t my_cred, my_new_cred;
1287	posix_cred_t my_pcred;
1288
1289	DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
1290
1291	rgid = uap->rgid;
1292	egid = uap->egid;
1293
1294	if (rgid == (uid_t)-1)
1295		rgid = KAUTH_GID_NONE;
1296	if (egid == (uid_t)-1)
1297		egid = KAUTH_GID_NONE;
1298	AUDIT_ARG(egid, egid);
1299	AUDIT_ARG(rgid, rgid);
1300
1301	my_cred = kauth_cred_proc_ref(p);
1302	my_pcred = posix_cred_get(my_cred);
1303
1304	if (((rgid != KAUTH_UID_NONE &&		/* allow no change of rgid */
1305	      rgid != my_pcred->cr_rgid &&	/* allow rgid = rgid */
1306	      rgid != my_pcred->cr_gid &&	/* allow rgid = egid */
1307	      rgid != my_pcred->cr_svgid) ||	/* allow rgid = svgid */
1308	     (egid != KAUTH_UID_NONE &&		/* allow no change of egid */
1309	      egid != my_pcred->cr_groups[0] &&	/* allow no change of egid */
1310	      egid != my_pcred->cr_gid &&	/* allow egid = egid */
1311	      egid != my_pcred->cr_rgid &&	/* allow egid = rgid */
1312	      egid != my_pcred->cr_svgid)) &&	/* allow egid = svgid */
1313	    (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1314		kauth_cred_unref(&my_cred);
1315		return (error);
1316	}
1317
1318	/* get current credential and take a reference while we muck with it */
1319	for (;;) {
1320		uid_t new_egid = my_pcred->cr_gid;
1321		uid_t new_rgid = my_pcred->cr_rgid;
1322		uid_t svgid = KAUTH_UID_NONE;
1323
1324
1325  		/*
1326		 * Set the credential with new info.  If there is no change,
1327		 * we get back the same credential we passed in; if there is
1328		 * a change, we drop the reference on the credential we
1329		 * passed in.  The subsequent compare is safe, because it is
1330		 * a pointer compare rather than a contents compare.
1331  		 */
1332		if (egid == KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
1333			/* changing the effective GID */
1334			new_egid = egid;
1335			OSBitOrAtomic(P_SUGID, &p->p_flag);
1336		}
1337		if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) {
1338			/* changing the real GID */
1339			new_rgid = rgid;
1340			OSBitOrAtomic(P_SUGID, &p->p_flag);
1341		}
1342		/*
1343		 * If the newly requested real gid or effective gid does
1344		 * not match the saved gid, then set the saved gid to the
1345		 * new effective gid.  We are protected from escalation
1346		 * by the prechecking.
1347		 */
1348		if (my_pcred->cr_svgid != uap->rgid &&
1349		    my_pcred->cr_svgid != uap->egid) {
1350		    	svgid = new_egid;
1351			OSBitOrAtomic(P_SUGID, &p->p_flag);
1352		}
1353
1354		my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
1355		if (my_cred != my_new_cred) {
1356
1357			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);
1358
1359			proc_lock(p);
1360			/* need to protect for a race where another thread
1361			 * also changed the credential after we took our
1362			 * reference.  If p_ucred has changed then we
1363			 * should restart this again with the new cred.
1364			 */
1365			if (p->p_ucred != my_cred) {
1366				proc_unlock(p);
1367				kauth_cred_unref(&my_new_cred);
1368				/* try again */
1369				my_cred = kauth_cred_proc_ref(p);
1370				continue;
1371			}
1372			p->p_ucred = my_new_cred;
1373			/* update cred on proc */
1374			PROC_UPDATE_CREDS_ONPROC(p);
1375			OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1376			proc_unlock(p);
1377		}
1378		break;
1379	}
1380	/* Drop old proc reference or our extra reference */
1381	kauth_cred_unref(&my_cred);
1382
1383	set_security_token(p);
1384	return (0);
1385}
1386
1387
1388/*
1389 * Set the per-thread override identity.  The first parameter can be the
1390 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
1391 * can be any UID.  If it is KAUTH_UID_NONE, then as a special case, this
1392 * means "revert to the per process credential"; otherwise, if permitted,
1393 * it changes the effective, real, and saved UIDs and GIDs for the current
1394 * thread to the requested UID and single GID, and clears all other GIDs.
1395 */
1396int
1397settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1398{
1399	kauth_cred_t uc;
1400	struct uthread *uthread = get_bsdthread_info(current_thread());
1401	uid_t uid;
1402	gid_t gid;
1403
1404	uid = uap->uid;
1405	gid = uap->gid;
1406	AUDIT_ARG(uid, uid);
1407	AUDIT_ARG(gid, gid);
1408
1409	if (proc_suser(p) != 0)
1410		return (EPERM);
1411
1412	if (uid == KAUTH_UID_NONE) {
1413
1414		/* must already be assuming another identity in order to revert back */
1415		if ((uthread->uu_flag & UT_SETUID) == 0)
1416			return (EPERM);
1417
1418		/* revert to delayed binding of process credential */
1419		uc = kauth_cred_proc_ref(p);
1420		kauth_cred_unref(&uthread->uu_ucred);
1421		uthread->uu_ucred = uc;
1422		uthread->uu_flag &= ~UT_SETUID;
1423	} else {
1424		kauth_cred_t my_cred, my_new_cred;
1425
1426		/* cannot already be assuming another identity */
1427		if ((uthread->uu_flag & UT_SETUID) != 0) {
1428			return (EPERM);
1429		}
1430
1431		/*
1432		 * Get a new credential instance from the old if this one
1433		 * changes; otherwise kauth_cred_setuidgid() returns the
1434		 * same credential.  We take an extra reference on the
1435		 * current credential while we muck with it, so we can do
1436		 * the post-compare for changes by pointer.
1437		 */
1438		kauth_cred_ref(uthread->uu_ucred);
1439		my_cred = uthread->uu_ucred;
1440		my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
1441		if (my_cred != my_new_cred)
1442			uthread->uu_ucred = my_new_cred;
1443		uthread->uu_flag |= UT_SETUID;
1444
1445		/* Drop old uthread reference or our extra reference */
1446		kauth_cred_unref(&my_cred);
1447	}
1448	/*
1449	 * XXX should potentially set per thread security token (there is
1450	 * XXX none).
1451	 * XXX it is unclear whether P_SUGID should be st at this point;
1452	 * XXX in theory, it is being deprecated.
1453	 */
1454	return (0);
1455}
1456
1457
1458/*
1459 * Set the per-thread override identity.  Use this system call for a thread to
1460 * assume the identity of another process or to revert back to normal identity
1461 * of the current process.
1462 *
1463 * When the "assume" argument is non zero the current thread will assume the
1464 * identity of the process represented by the pid argument.
1465 *
1466 * When the assume argument is zero we revert back to our normal identity.
1467 */
1468int
1469settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1470{
1471	proc_t target_proc;
1472	struct uthread *uthread = get_bsdthread_info(current_thread());
1473	kauth_cred_t my_cred, my_target_cred, my_new_cred;
1474	posix_cred_t my_target_pcred;
1475
1476	AUDIT_ARG(pid, uap->pid);
1477	AUDIT_ARG(value32, uap->assume);
1478
1479	if (proc_suser(p) != 0) {
1480		return (EPERM);
1481	}
1482
1483	/*
1484	 * XXX should potentially set per thread security token (there is
1485	 * XXX none).
1486	 * XXX it is unclear whether P_SUGID should be st at this point;
1487	 * XXX in theory, it is being deprecated.
1488	 */
1489
1490	/*
1491	 * assume argument tells us to assume the identity of the process with the
1492	 * id passed in the pid argument.
1493	 */
1494	if (uap->assume != 0) {
1495		/* can't do this if we have already assumed an identity */
1496		if ((uthread->uu_flag & UT_SETUID) != 0)
1497			return (EPERM);
1498
1499		target_proc = proc_find(uap->pid);
1500		/* can't assume the identity of the kernel process */
1501		if (target_proc == NULL || target_proc == kernproc) {
1502			if (target_proc!= NULL)
1503				proc_rele(target_proc);
1504			return (ESRCH);
1505		}
1506
1507		/*
1508		 * Take a reference on the credential used in our target
1509		 * process then use it as the identity for our current
1510		 * thread.  We take an extra reference on the current
1511		 * credential while we muck with it, so we can do the
1512		 * post-compare for changes by pointer.
1513		 *
1514		 * The post-compare is needed for the case that our process
1515		 * credential has been changed to be identical to our thread
1516		 * credential following our assumption of a per-thread one,
1517		 * since the credential cache will maintain a unique instance.
1518		 */
1519		kauth_cred_ref(uthread->uu_ucred);
1520		my_cred = uthread->uu_ucred;
1521		my_target_cred = kauth_cred_proc_ref(target_proc);
1522		my_target_pcred = posix_cred_get(my_target_cred);
1523		my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
1524		if (my_cred != my_new_cred)
1525			uthread->uu_ucred = my_new_cred;
1526
1527		uthread->uu_flag |= UT_SETUID;
1528
1529		/* Drop old uthread reference or our extra reference */
1530		proc_rele(target_proc);
1531		kauth_cred_unref(&my_cred);
1532		kauth_cred_unref(&my_target_cred);
1533
1534		return (0);
1535	}
1536
1537	/*
1538	 * Otherwise, we are reverting back to normal mode of operation where
1539	 * delayed binding of the process credential sets the credential in
1540	 * the thread (uu_ucred)
1541	 */
1542	if ((uthread->uu_flag & UT_SETUID) == 0)
1543		return (EPERM);
1544
1545	/* revert to delayed binding of process credential */
1546	my_new_cred = kauth_cred_proc_ref(p);
1547	kauth_cred_unref(&uthread->uu_ucred);
1548	uthread->uu_ucred = my_new_cred;
1549	uthread->uu_flag &= ~UT_SETUID;
1550
1551	return (0);
1552}
1553
1554
1555/*
1556 * setgroups1
1557 *
1558 * Description: Internal implementation for both the setgroups and initgroups
1559 *		system calls
1560 *
1561 * Parameters:	gidsetsize			Number of groups in set
1562 *		gidset				Pointer to group list
1563 *		gmuid				Base gid (initgroups only!)
1564 *
1565 * Returns:	0				Success
1566 *	suser:EPERM				Permision denied
1567 *		EINVAL				Invalid gidsetsize value
1568 *	copyin:EFAULT				Bad gidset or gidsetsize is
1569 *						too large
1570 *
1571 * Notes:	When called from a thread running under an assumed per-thread
1572 *		identity, this function will operate against the per-thread
1573 *		credential, rather than against the process credential.  In
1574 *		this specific case, the process credential is verified to
1575 *		still be privileged at the time of the call, rather than the
1576 *		per-thread credential for this operation to be permitted.
1577 *
1578 *		This effectively means that setgroups/initigroups calls in
1579 *		a thread running a per-thread credential should occur *after*
1580 *		the settid call that created it, not before (unlike setuid,
1581 *		which must be called after, since it will result in privilege
1582 *		being dropped).
1583 *
1584 *		When called normally (i.e. no per-thread assumed identity),
1585 *		the per process credential is updated per POSIX.
1586 *
1587 *		If the credential is changed as a result of this call, then we
1588 *		flag the process as having set privilege since the last exec.
1589 */
1590static int
1591setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1592{
1593	u_int ngrp;
1594	gid_t	newgroups[NGROUPS] = { 0 };
1595	int 	error;
1596	kauth_cred_t my_cred, my_new_cred;
1597	struct uthread *uthread = get_bsdthread_info(current_thread());
1598
1599	DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), gidsetsize, gidset, gmuid);
1600
1601	ngrp = gidsetsize;
1602	if (ngrp > NGROUPS)
1603		return (EINVAL);
1604
1605	if ( ngrp < 1 ) {
1606		ngrp = 1;
1607	} else {
1608		error = copyin(gidset,
1609			(caddr_t)newgroups, ngrp * sizeof(gid_t));
1610		if (error) {
1611			return (error);
1612		}
1613	}
1614
1615	my_cred = kauth_cred_proc_ref(p);
1616	if ((error = suser(my_cred, &p->p_acflag))) {
1617		kauth_cred_unref(&my_cred);
1618		return (error);
1619	}
1620
1621	if ((uthread->uu_flag & UT_SETUID) != 0) {
1622#if DEBUG_CRED
1623		int my_cred_flags = uthread->uu_ucred->cr_flags;
1624#endif	/* DEBUG_CRED */
1625		kauth_cred_unref(&my_cred);
1626
1627		/*
1628		 * If this thread is under an assumed identity, set the
1629		 * supplementary grouplist on the thread credential instead
1630		 * of the process one.  If we were the only reference holder,
1631		 * the credential is updated in place, otherwise, our reference
1632		 * is dropped and we get back a different cred with a reference
1633		 * already held on it.  Because this is per-thread, we don't
1634		 * need the referencing/locking/retry required for per-process.
1635		 */
1636		my_cred = uthread->uu_ucred;
1637		uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1638#if DEBUG_CRED
1639		if (my_cred != uthread->uu_ucred) {
1640			DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred , uthread->uu_ucred ->cr_flags);
1641		}
1642#endif	/* DEBUG_CRED */
1643	} else {
1644
1645		/*
1646		 * get current credential and take a reference while we muck
1647		 * with it
1648		 */
1649		for (;;) {
1650			/*
1651			 * Set the credential with new info.  If there is no
1652			 * change, we get back the same credential we passed
1653			 * in; if there is a change, we drop the reference on
1654			 * the credential we passed in.  The subsequent
1655			 * compare is safe, because it is a pointer compare
1656			 * rather than a contents compare.
1657			 */
1658			my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1659			if (my_cred != my_new_cred) {
1660
1661				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);
1662
1663				proc_lock(p);
1664				/*
1665				 * We need to protect for a race where another
1666				 * thread also changed the credential after we
1667				 * took our reference.  If p_ucred has
1668				 * changed then we should restart this again
1669				 * with the new cred.
1670				 */
1671				if (p->p_ucred != my_cred) {
1672					proc_unlock(p);
1673					kauth_cred_unref(&my_new_cred);
1674					my_cred = kauth_cred_proc_ref(p);
1675					/* try again */
1676					continue;
1677				}
1678				p->p_ucred = my_new_cred;
1679				/* update cred on proc */
1680				PROC_UPDATE_CREDS_ONPROC(p);
1681				OSBitOrAtomic(P_SUGID, &p->p_flag);
1682				proc_unlock(p);
1683			}
1684			break;
1685		}
1686		/* Drop old proc reference or our extra reference */
1687		AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp);
1688		kauth_cred_unref(&my_cred);
1689
1690
1691		set_security_token(p);
1692	}
1693
1694	return (0);
1695}
1696
1697
1698/*
1699 * initgroups
1700 *
1701 * Description: Initialize the default supplementary groups list and set the
1702 *		gmuid for use by the external group resolver (if any)
1703 *
1704 * Parameters:	uap->gidsetsize			Number of groups in set
1705 *		uap->gidset			Pointer to group list
1706 *		uap->gmuid			Base gid
1707 *
1708 * Returns:	0				Success
1709 *	setgroups1:EPERM			Permision denied
1710 *	setgroups1:EINVAL			Invalid gidsetsize value
1711 *	setgroups1:EFAULT			Bad gidset or gidsetsize is
1712 *
1713 * Notes:	This function opts *IN* to memberd participation
1714 *
1715 *		The normal purpose of this function is for a privileged
1716 *		process to indicate supplementary groups and identity for
1717 *		participation in extended group membership resolution prior
1718 *		to dropping privilege by assuming a specific user identity.
1719 *
1720 *		It is the first half of the primary mechanism whereby user
1721 *		identity is established to the system by programs such as
1722 *		/usr/bin/login.  The second half is the drop of uid privilege
1723 *		for a specific uid corresponding to the user.
1724 *
1725 * See also:	setgroups1()
1726 */
1727int
1728initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1729{
1730	DEBUG_CRED_ENTER("initgroups\n");
1731
1732	return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
1733}
1734
1735
1736/*
1737 * setgroups
1738 *
1739 * Description: Initialize the default supplementary groups list
1740 *
1741 * Parameters:	gidsetsize			Number of groups in set
1742 *		gidset				Pointer to group list
1743 *
1744 * Returns:	0				Success
1745 *	setgroups1:EPERM			Permision denied
1746 *	setgroups1:EINVAL			Invalid gidsetsize value
1747 *	setgroups1:EFAULT			Bad gidset or gidsetsize is
1748 *
1749 * Notes:	This functions opts *OUT* of memberd participation.
1750 *
1751 *		This function exists for compatibility with POSIX.  Most user
1752 *		programs should use initgroups() instead to ensure correct
1753 *		participation in group membership resolution when utilizing
1754 *		a directory service for authentication.
1755 *
1756 *		It is identical to an initgroups() call with a gmuid argument
1757 *		of KAUTH_UID_NONE.
1758 *
1759 * See also:	setgroups1()
1760 */
1761int
1762setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1763{
1764	DEBUG_CRED_ENTER("setgroups\n");
1765
1766	return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1767}
1768
1769
1770/*
1771 * Set the per-thread/per-process supplementary groups list.
1772 *
1773 * XXX implement setsgroups
1774 *
1775 */
1776
1777int
1778setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1779{
1780	return(ENOTSUP);
1781}
1782
1783/*
1784 * Set the per-thread/per-process whiteout groups list.
1785 *
1786 * XXX implement setwgroups
1787 *
1788 */
1789
1790int
1791setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1792{
1793	return(ENOTSUP);
1794}
1795
1796
1797/*
1798 * Check if gid is a member of the group set.
1799 *
1800 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1801 * XXX instead.
1802 */
1803int
1804groupmember(gid_t gid, kauth_cred_t cred)
1805{
1806	int is_member;
1807
1808	if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
1809		return (1);
1810	return (0);
1811}
1812
1813
1814/*
1815 * Test whether the specified credentials imply "super-user"
1816 * privilege; if so, and we have accounting info, set the flag
1817 * indicating use of super-powers.
1818 * Returns 0 or error.
1819 *
1820 * XXX This interface is going away; use kauth_cred_issuser() directly
1821 * XXX instead.
1822 *
1823 * Note:	This interface exists to implement the "has used privilege"
1824 *		bit (ASU) in the p_acflags field of the process, which is
1825 *		only externalized via private sysctl and in process accounting
1826 *		records.  The flag is technically not required in either case.
1827 */
1828int
1829suser(kauth_cred_t cred, u_short *acflag)
1830{
1831#if DIAGNOSTIC
1832	if (!IS_VALID_CRED(cred))
1833		panic("suser");
1834#endif
1835	if (kauth_cred_getuid(cred) == 0) {
1836		if (acflag)
1837			*acflag |= ASU;
1838		return (0);
1839	}
1840	return (EPERM);
1841}
1842
1843
1844/*
1845 * getlogin
1846 *
1847 * Description:	Get login name, if available.
1848 *
1849 * Parameters:	uap->namebuf			User buffer for return
1850 *		uap->namelen			User buffer length
1851 *
1852 * Returns:	0				Success
1853 *	copyout:EFAULT
1854 *
1855 * Notes:	Intended to obtain a string containing the user name of the
1856 *		user associated with the controlling terminal for the calling
1857 *		process.
1858 *
1859 *		Not very useful on modern systems, due to inherent length
1860 *		limitations for the static array in the session structure
1861 *		which is used to store the login name.
1862 *
1863 *		Permitted to return NULL
1864 *
1865 * XXX:		Belongs in kern_proc.c
1866 */
1867int
1868getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1869{
1870	char buffer[MAXLOGNAME+1];
1871	struct session * sessp;
1872
1873	bzero(buffer, MAXLOGNAME+1);
1874
1875	sessp = proc_session(p);
1876
1877	if (uap->namelen > MAXLOGNAME)
1878		uap->namelen = MAXLOGNAME;
1879
1880	if(sessp != SESSION_NULL) {
1881		session_lock(sessp);
1882		bcopy( sessp->s_login, buffer, uap->namelen);
1883		session_unlock(sessp);
1884	}
1885	session_rele(sessp);
1886
1887	return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
1888}
1889
1890
1891/*
1892 * setlogin
1893 *
1894 * Description:	Set login name.
1895 *
1896 * Parameters:	uap->namebuf			User buffer containing name
1897 *
1898 * Returns:	0				Success
1899 *	suser:EPERM				Permission denied
1900 *	copyinstr:EFAULT			User buffer invalid
1901 *	copyinstr:EINVAL			Supplied name was too long
1902 *
1903 * Notes:	This is a utility system call to support getlogin().
1904 *
1905 * XXX:		Belongs in kern_proc.c
1906 */
1907int
1908setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1909{
1910	int error;
1911	size_t dummy=0;
1912	char buffer[MAXLOGNAME+1];
1913	struct session * sessp;
1914
1915	if ((error = proc_suser(p)))
1916		return (error);
1917
1918	bzero(&buffer[0], MAXLOGNAME+1);
1919
1920
1921	error = copyinstr(uap->namebuf,
1922	    (caddr_t) &buffer[0],
1923	    MAXLOGNAME - 1, (size_t *)&dummy);
1924
1925	sessp = proc_session(p);
1926
1927	if (sessp != SESSION_NULL) {
1928		session_lock(sessp);
1929		bcopy(buffer, sessp->s_login, MAXLOGNAME);
1930		session_unlock(sessp);
1931		session_rele(sessp);
1932	}
1933
1934
1935	if (!error) {
1936		AUDIT_ARG(text, buffer);
1937	 } else if (error == ENAMETOOLONG)
1938		error = EINVAL;
1939	return (error);
1940}
1941
1942
1943/* Set the secrity token of the task with current euid and eguid */
1944/*
1945 * XXX This needs to change to give the task a reference and/or an opaque
1946 * XXX identifier.
1947 */
1948int
1949set_security_token(proc_t p)
1950{
1951	security_token_t sec_token;
1952	audit_token_t    audit_token;
1953	kauth_cred_t my_cred;
1954	posix_cred_t my_pcred;
1955	host_priv_t host_priv;
1956
1957	/*
1958	 * Don't allow a vfork child to override the parent's token settings
1959	 * (since they share a task).  Instead, the child will just have to
1960	 * suffer along using the parent's token until the exec().  It's all
1961	 * undefined behavior anyway, right?
1962	 */
1963	if (p->task == current_task()) {
1964		uthread_t	 uthread;
1965		uthread = (uthread_t)get_bsdthread_info(current_thread());
1966		if (uthread->uu_flag & UT_VFORK)
1967			return (1);
1968	}
1969
1970	my_cred = kauth_cred_proc_ref(p);
1971	my_pcred = posix_cred_get(my_cred);
1972
1973	/* XXX mach_init doesn't have a p_ucred when it calls this function */
1974	if (IS_VALID_CRED(my_cred)) {
1975		sec_token.val[0] = kauth_cred_getuid(my_cred);
1976		sec_token.val[1] = kauth_cred_getgid(my_cred);
1977	} else {
1978		sec_token.val[0] = 0;
1979		sec_token.val[1] = 0;
1980	}
1981
1982	/*
1983	 * The current layout of the Mach audit token explicitly
1984	 * adds these fields.  But nobody should rely on such
1985	 * a literal representation.  Instead, the BSM library
1986	 * provides a function to convert an audit token into
1987	 * a BSM subject.  Use of that mechanism will isolate
1988	 * the user of the trailer from future representation
1989	 * changes.
1990	 */
1991	audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1992	audit_token.val[1] = my_pcred->cr_uid;
1993	audit_token.val[2] = my_pcred->cr_gid;
1994	audit_token.val[3] = my_pcred->cr_ruid;
1995	audit_token.val[4] = my_pcred->cr_rgid;
1996	audit_token.val[5] = p->p_pid;
1997	audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
1998	audit_token.val[7] = p->p_idversion;
1999
2000#if CONFIG_MACF_MACH
2001	mac_task_label_update_cred(my_cred, p->task);
2002#endif
2003
2004	host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
2005#if CONFIG_MACF
2006	if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
2007		host_priv = HOST_PRIV_NULL;
2008#endif
2009	kauth_cred_unref(&my_cred);
2010
2011	return (host_security_set_task_token(host_security_self(),
2012					   p->task,
2013					   sec_token,
2014					   audit_token,
2015					   host_priv) != KERN_SUCCESS);
2016}
2017
2018
2019/*
2020 * Fill in a struct xucred based on a kauth_cred_t.
2021 */
2022__private_extern__
2023void
2024cru2x(kauth_cred_t cr, struct xucred *xcr)
2025{
2026	posix_cred_t pcr = posix_cred_get(cr);
2027
2028	bzero(xcr, sizeof(*xcr));
2029	xcr->cr_version = XUCRED_VERSION;
2030	xcr->cr_uid = kauth_cred_getuid(cr);
2031	xcr->cr_ngroups = pcr->cr_ngroups;
2032	bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
2033}
2034
2035#if CONFIG_LCTX
2036
2037/*
2038 * Set Login Context ID
2039 */
2040/*
2041 * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
2042 *	    LCTX by its own locks.
2043 */
2044int
2045setlcid(proc_t p0, struct setlcid_args *uap, __unused int32_t *retval)
2046{
2047	proc_t p;
2048	struct lctx *l;
2049	int error = 0;
2050	int refheld = 0;
2051
2052	AUDIT_ARG(pid, uap->pid);
2053	AUDIT_ARG(value32, uap->lcid);
2054	if (uap->pid == LCID_PROC_SELF) {	/* Create/Join/Leave */
2055		p = p0;
2056	} else {				/* Adopt/Orphan */
2057		p = proc_find(uap->pid);
2058		if (p == NULL)
2059			return (ESRCH);
2060		refheld = 1;
2061	}
2062
2063#if CONFIG_MACF
2064	error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
2065	if (error)
2066		goto out;
2067#endif
2068
2069	switch (uap->lcid) {
2070	/* Leave/Orphan */
2071	case LCID_REMOVE:
2072
2073		/* Only root may Leave/Orphan. */
2074		if (!kauth_cred_issuser(kauth_cred_get())) {
2075			error = EPERM;
2076			goto out;
2077		}
2078
2079		/* Process not in login context. */
2080		if (p->p_lctx == NULL) {
2081			error = ENOATTR;
2082			goto out;
2083		}
2084
2085		l = NULL;
2086
2087		break;
2088
2089	/* Create */
2090	case LCID_CREATE:
2091
2092		/* Create only valid for self! */
2093		if (uap->pid != LCID_PROC_SELF) {
2094			error = EPERM;
2095			goto out;
2096		}
2097
2098		/* Already in a login context. */
2099		if (p->p_lctx != NULL) {
2100			error = EPERM;
2101			goto out;
2102		}
2103
2104		l = lccreate();
2105		if (l == NULL) {
2106			error = ENOMEM;
2107			goto out;
2108		}
2109
2110		LCTX_LOCK(l);
2111
2112		break;
2113
2114	/* Join/Adopt */
2115	default:
2116
2117		/* Only root may Join/Adopt. */
2118		if (!kauth_cred_issuser(kauth_cred_get())) {
2119			error = EPERM;
2120			goto out;
2121		}
2122
2123		l = lcfind(uap->lcid);
2124		if (l == NULL) {
2125			error = ENOATTR;
2126			goto out;
2127		}
2128
2129		break;
2130	}
2131
2132	ALLLCTX_LOCK;
2133	leavelctx(p);
2134	enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
2135	ALLLCTX_UNLOCK;
2136
2137out:
2138	if (refheld != 0)
2139		proc_rele(p);
2140	return (error);
2141}
2142
2143/*
2144 * Get Login Context ID
2145 */
2146/*
2147 * MPSAFE - membership of (visible) process in a login context
2148 *	    protected by the all-context lock.
2149 */
2150int
2151getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2152{
2153	proc_t p;
2154	int error = 0;
2155	int refheld = 0;
2156
2157	AUDIT_ARG(pid, uap->pid);
2158	if (uap->pid == LCID_PROC_SELF) {
2159		p = p0;
2160	} else {
2161		p = proc_find(uap->pid);
2162		if (p == NULL)
2163			return (ESRCH);
2164		refheld = 1;
2165	}
2166
2167#if CONFIG_MACF
2168	error = mac_proc_check_getlcid(p0, p, uap->pid);
2169	if (error)
2170		goto out;
2171#endif
2172	ALLLCTX_LOCK;
2173	if (p->p_lctx == NULL) {
2174		error = ENOATTR;
2175		ALLLCTX_UNLOCK;
2176		goto out;
2177	}
2178	*retval = p->p_lctx->lc_id;
2179	ALLLCTX_UNLOCK;
2180 out:
2181	if (refheld != 0)
2182		proc_rele(p);
2183
2184	return (error);
2185}
2186#else	/* LCTX */
2187int
2188setlcid(proc_t p0, struct setlcid_args *uap, int32_t *retval)
2189{
2190
2191	return (ENOSYS);
2192}
2193
2194int
2195getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2196{
2197
2198	return (ENOSYS);
2199}
2200#endif	/* !LCTX */
2201