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