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