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