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