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