2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
67 * System calls related to processes and protection
70 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/ucred.h>
75 #include <sys/timeb.h>
76 #include <sys/times.h>
77 #include <sys/malloc.h>
78 #include <sys/kern_audit.h>
80 #include <sys/mount.h>
81 #include <mach/message.h>
82 #include <mach/host_security.h>
84 #include <kern/host.h>
87 * setprivexec: (dis)allow this process to hold
88 * task, thread, or execption ports of processes about to exec.
90 struct setprivexec_args
{
94 setprivexec(p
, uap
, retval
)
96 register struct setprivexec_args
*uap
;
99 *retval
= p
->p_debugger
;
100 p
->p_debugger
= (uap
->flag
!= 0);
105 getpid(p
, uap
, retval
)
113 retval
[1] = p
->p_pptr
->p_pid
;
119 getppid(p
, uap
, retval
)
125 *retval
= p
->p_pptr
->p_pid
;
129 /* Get process group ID; note that POSIX getpgrp takes no parameter */
130 getpgrp(p
, uap
, retval
)
136 *retval
= p
->p_pgrp
->pg_id
;
140 /* Get an arbitary pid's process group id */
141 struct getpgid_args
{
146 getpgid(p
, uap
, retval
)
148 struct getpgid_args
*uap
;
157 if ((pt
= pfind(uap
->pid
)) == 0)
160 *retval
= pt
->p_pgrp
->pg_id
;
165 * Get an arbitary pid's session id.
172 getsid(p
, uap
, retval
)
174 struct getsid_args
*uap
;
183 if ((pt
= pfind(uap
->pid
)) == 0)
186 *retval
= pt
->p_session
->s_sid
;
191 getuid(p
, uap
, retval
)
197 *retval
= p
->p_cred
->p_ruid
;
199 retval
[1] = p
->p_ucred
->cr_uid
;
205 geteuid(p
, uap
, retval
)
211 *retval
= p
->p_ucred
->cr_uid
;
216 getgid(p
, uap
, retval
)
222 *retval
= p
->p_cred
->p_rgid
;
224 retval
[1] = p
->p_ucred
->cr_groups
[0];
230 * Get effective group ID. The "egid" is groups[0], and could be obtained
231 * via getgroups. This syscall exists because it is somewhat painful to do
232 * correctly in a library function.
235 getegid(p
, uap
, retval
)
241 *retval
= p
->p_ucred
->cr_groups
[0];
245 struct getgroups_args
{
249 getgroups(p
, uap
, retval
)
251 register struct getgroups_args
*uap
;
254 register struct pcred
*pc
= p
->p_cred
;
258 if ((ngrp
= uap
->gidsetsize
) == 0) {
259 *retval
= pc
->pc_ucred
->cr_ngroups
;
262 if (ngrp
< pc
->pc_ucred
->cr_ngroups
)
265 ngrp
= pc
->pc_ucred
->cr_ngroups
;
266 if (error
= copyout((caddr_t
)pc
->pc_ucred
->cr_groups
,
267 (caddr_t
)uap
->gidset
, ngrp
* sizeof(gid_t
))) {
277 setsid(p
, uap
, retval
)
278 register struct proc
*p
;
283 if (p
->p_pgid
== p
->p_pid
|| pgfind(p
->p_pid
) || p
->p_flag
& P_INVFORK
) {
286 (void)enterpgrp(p
, p
->p_pid
, 1);
293 * set process group (setpgid/old setpgrp)
295 * caller does setpgid(targpid, targpgid)
297 * pid must be caller or child of caller (ESRCH)
299 * pid must be in same session (EPERM)
300 * pid can't have done an exec (EACCES)
302 * there must exist some pid in same session having pgid (EPERM)
303 * pid must not be session leader (EPERM)
305 struct setpgid_args
{
310 setpgid(curp
, uap
, retval
)
312 register struct setpgid_args
*uap
;
315 register struct proc
*targp
; /* target process */
316 register struct pgrp
*pgrp
; /* target pgrp */
318 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
319 if ((targp
= pfind(uap
->pid
)) == 0 || !inferior(targp
))
321 if (targp
->p_session
!= curp
->p_session
)
323 if (targp
->p_flag
& P_EXEC
)
327 if (SESS_LEADER(targp
))
330 uap
->pgid
= targp
->p_pid
;
331 else if (uap
->pgid
!= targp
->p_pid
)
332 if ((pgrp
= pgfind(uap
->pgid
)) == 0 ||
333 pgrp
->pg_session
!= curp
->p_session
)
335 return (enterpgrp(targp
, uap
->pgid
, 0));
338 struct issetugid_args
{
341 issetugid(p
, uap
, retval
)
343 struct issetugid_args
*uap
;
347 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
348 * we use P_SUGID because we consider changing the owners as
349 * "tainting" as well.
350 * This is significant for procs that start as root and "become"
351 * a user without an exec - programs cannot know *everything*
352 * that libc *might* have put in their data segment.
355 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
363 setuid(p
, uap
, retval
)
365 struct setuid_args
*uap
;
368 register struct pcred
*pc
= p
->p_cred
;
373 AUDIT_ARG(uid
, uid
, 0, 0, 0);
374 if (uid
!= pc
->p_ruid
&&
375 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
378 * Everything's okay, do it.
379 * Transfer proc count to new user.
380 * Copy credentials so other references do not see our changes.
383 /* prepare app access profile files */
384 prepare_profile_database(uap
->uid
);
386 (void)chgproccnt(pc
->p_ruid
, -1);
387 (void)chgproccnt(uid
, 1);
388 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
389 pc
->pc_ucred
->cr_uid
= uid
;
393 set_security_token(p
);
394 p
->p_flag
|= P_SUGID
;
398 struct seteuid_args
{
402 seteuid(p
, uap
, retval
)
404 struct seteuid_args
*uap
;
407 register struct pcred
*pc
= p
->p_cred
;
412 AUDIT_ARG(uid
, 0, euid
, 0, 0);
413 if (euid
!= pc
->p_ruid
&& euid
!= pc
->p_svuid
&&
414 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
417 * Everything's okay, do it. Copy credentials so other references do
418 * not see our changes.
421 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
422 pc
->pc_ucred
->cr_uid
= euid
;
424 set_security_token(p
);
425 p
->p_flag
|= P_SUGID
;
433 setgid(p
, uap
, retval
)
435 struct setgid_args
*uap
;
438 register struct pcred
*pc
= p
->p_cred
;
443 AUDIT_ARG(gid
, gid
, 0, 0, 0);
444 if (gid
!= pc
->p_rgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
447 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
448 pc
->pc_ucred
->cr_groups
[0] = gid
;
450 pc
->p_svgid
= gid
; /* ??? */
452 set_security_token(p
);
453 p
->p_flag
|= P_SUGID
;
457 struct setegid_args
{
461 setegid(p
, uap
, retval
)
463 struct setegid_args
*uap
;
466 register struct pcred
*pc
= p
->p_cred
;
471 AUDIT_ARG(gid
, 0, egid
, 0, 0);
472 if (egid
!= pc
->p_rgid
&& egid
!= pc
->p_svgid
&&
473 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
476 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
477 pc
->pc_ucred
->cr_groups
[0] = egid
;
479 set_security_token(p
);
480 p
->p_flag
|= P_SUGID
;
484 struct setgroups_args
{
490 setgroups(p
, uap
, retval
)
492 struct setgroups_args
*uap
;
495 register struct pcred
*pc
= p
->p_cred
;
496 struct ucred
*new, *old
;
500 if (error
= suser(pc
->pc_ucred
, &p
->p_acflag
))
502 ngrp
= uap
->gidsetsize
;
511 error
= copyin((caddr_t
)uap
->gidset
,
512 (caddr_t
)new->cr_groups
, ngrp
* sizeof(gid_t
));
518 new->cr_ngroups
= ngrp
;
519 AUDIT_ARG(groupset
, new->cr_groups
, ngrp
);
522 new->cr_uid
= old
->cr_uid
;
525 set_security_token(p
);
526 p
->p_flag
|= P_SUGID
;
533 struct osetreuid_args
{
538 osetreuid(p
, uap
, retval
)
539 register struct proc
*p
;
540 struct osetreuid_args
*uap
;
543 struct seteuid_args seuidargs
;
544 struct setuid_args suidargs
;
547 * There are five cases, and we attempt to emulate them in
548 * the following fashion:
549 * -1, -1: return 0. This is correct emulation.
550 * -1, N: call seteuid(N). This is correct emulation.
551 * N, -1: if we called setuid(N), our euid would be changed
552 * to N as well. the theory is that we don't want to
553 * revoke root access yet, so we call seteuid(N)
554 * instead. This is incorrect emulation, but often
555 * suffices enough for binary compatibility.
556 * N, N: call setuid(N). This is correct emulation.
557 * N, M: call setuid(N). This is close to correct emulation.
559 if (uap
->ruid
== (uid_t
)-1) {
560 if (uap
->euid
== (uid_t
)-1)
561 return (0); /* -1, -1 */
562 seuidargs
.euid
= uap
->euid
; /* -1, N */
563 return (seteuid(p
, &seuidargs
, retval
));
565 if (uap
->euid
== (uid_t
)-1) {
566 seuidargs
.euid
= uap
->ruid
; /* N, -1 */
567 return (seteuid(p
, &seuidargs
, retval
));
569 suidargs
.uid
= uap
->ruid
; /* N, N and N, M */
570 return (setuid(p
, &suidargs
, retval
));
573 struct osetregid_args
{
578 osetregid(p
, uap
, retval
)
579 register struct proc
*p
;
580 struct osetregid_args
*uap
;
583 struct setegid_args segidargs
;
584 struct setgid_args sgidargs
;
587 * There are five cases, described above in osetreuid()
589 if (uap
->rgid
== (gid_t
)-1) {
590 if (uap
->egid
== (gid_t
)-1)
591 return (0); /* -1, -1 */
592 segidargs
.egid
= uap
->egid
; /* -1, N */
593 return (setegid(p
, &segidargs
, retval
));
595 if (uap
->egid
== (gid_t
)-1) {
596 segidargs
.egid
= uap
->rgid
; /* N, -1 */
597 return (setegid(p
, &segidargs
, retval
));
599 sgidargs
.gid
= uap
->rgid
; /* N, N and N, M */
600 return (setgid(p
, &sgidargs
, retval
));
602 #endif /* COMPAT_43 */
605 * Check if gid is a member of the group set.
607 groupmember(gid
, cred
)
609 register struct ucred
*cred
;
614 egp
= &(cred
->cr_groups
[cred
->cr_ngroups
]);
615 for (gp
= cred
->cr_groups
; gp
< egp
; gp
++)
622 * Test whether the specified credentials imply "super-user"
623 * privilege; if so, and we have accounting info, set the flag
624 * indicating use of super-powers.
625 * Returns 0 or error.
632 if (cred
== NOCRED
|| cred
== FSCRED
)
635 if (cred
->cr_uid
== 0) {
646 struct proc
*p
= current_proc();
651 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0);
657 struct proc
*p
= current_proc();
662 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0 ||
663 p
->p_cred
->p_ruid
== 0 || p
->p_cred
->p_svuid
== 0);
667 * Allocate a zeroed cred structure.
672 register struct ucred
*cr
;
674 MALLOC_ZONE(cr
, struct ucred
*, sizeof(*cr
), M_CRED
, M_WAITOK
);
675 bzero((caddr_t
)cr
, sizeof(*cr
));
681 * Free a cred structure.
682 * Throws away space when ref count gets to 0.
689 if (cr
== NOCRED
|| cr
== FSCRED
)
692 if (--cr
->cr_ref
== 0)
693 FREE_ZONE((caddr_t
)cr
, sizeof *cr
, M_CRED
);
697 * Copy cred structure to a new one and free the old one.
706 if (cr
== NOCRED
|| cr
== FSCRED
)
719 * Dup cred struct to a new held one.
728 if (cr
== NOCRED
|| cr
== FSCRED
)
738 * compare two cred structs
749 if (cr1
== NOCRED
|| cr1
== FSCRED
||
750 cr2
== NOCRED
|| cr2
== FSCRED
)
752 if (cr1
->cr_uid
!= cr2
->cr_uid
)
754 if (cr1
->cr_ngroups
!= cr2
->cr_ngroups
)
756 // XXX assumes groups will always be listed in some order
757 for (i
=0; i
< cr1
->cr_ngroups
; i
++)
758 if (cr1
->cr_groups
[i
] != cr2
->cr_groups
[i
])
764 * Get login name, if available.
766 struct getlogin_args
{
771 getlogin(p
, uap
, retval
)
773 struct getlogin_args
*uap
;
777 if (uap
->namelen
> sizeof (p
->p_pgrp
->pg_session
->s_login
))
778 uap
->namelen
= sizeof (p
->p_pgrp
->pg_session
->s_login
);
779 return (copyout((caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
780 (caddr_t
)uap
->namebuf
, uap
->namelen
));
786 struct setlogin_args
{
790 setlogin(p
, uap
, retval
)
792 struct setlogin_args
*uap
;
798 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
801 error
= copyinstr((caddr_t
) uap
->namebuf
,
802 (caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
803 sizeof (p
->p_pgrp
->pg_session
->s_login
) - 1, (size_t *)&dummy
);
804 if (error
== ENAMETOOLONG
)
810 /* Set the secrity token of the task with current euid and eguid */
812 set_security_token(struct proc
* p
)
814 security_token_t sec_token
;
815 audit_token_t audit_token
;
817 sec_token
.val
[0] = p
->p_ucred
->cr_uid
;
818 sec_token
.val
[1] = p
->p_ucred
->cr_gid
;
819 audit_token
.val
[0] = p
->p_au
->ai_auid
;
820 audit_token
.val
[1] = p
->p_au
->ai_asid
;
821 /* use au_tid for now, until au_tid_addr is put to use */
822 audit_token
.val
[2] = p
->p_au
->ai_termid
.port
;
823 audit_token
.val
[3] = p
->p_au
->ai_termid
.machine
;
824 audit_token
.val
[4] = 0;
825 audit_token
.val
[5] = 0;
826 audit_token
.val
[6] = 0;
827 audit_token
.val
[7] = 0;
828 return host_security_set_task_token(host_security_self(),
839 * Fill in a struct xucred based on a struct ucred.
843 cru2x(struct ucred
*cr
, struct xucred
*xcr
)
846 bzero(xcr
, sizeof(*xcr
));
847 xcr
->cr_version
= XUCRED_VERSION
;
848 xcr
->cr_uid
= cr
->cr_uid
;
849 xcr
->cr_ngroups
= cr
->cr_ngroups
;
850 bcopy(cr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));