2 * Copyright (c) 2000-2002 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>
79 #include <sys/mount.h>
80 #include <mach/message.h>
81 #include <mach/host_security.h>
83 #include <kern/host.h>
86 * setprivexec: (dis)allow this process to hold
87 * task, thread, or execption ports of processes about to exec.
89 struct setprivexec_args
{
93 setprivexec(p
, uap
, retval
)
95 register struct setprivexec_args
*uap
;
98 *retval
= p
->p_debugger
;
99 p
->p_debugger
= (uap
->flag
!= 0);
104 getpid(p
, uap
, retval
)
112 retval
[1] = p
->p_pptr
->p_pid
;
118 getppid(p
, uap
, retval
)
124 *retval
= p
->p_pptr
->p_pid
;
128 /* Get process group ID; note that POSIX getpgrp takes no parameter */
129 getpgrp(p
, uap
, retval
)
135 *retval
= p
->p_pgrp
->pg_id
;
139 /* Get an arbitary pid's process group id */
140 struct getpgid_args
{
145 getpgid(p
, uap
, retval
)
147 struct getpgid_args
*uap
;
156 if ((pt
= pfind(uap
->pid
)) == 0)
159 *retval
= pt
->p_pgrp
->pg_id
;
164 * Get an arbitary pid's session id.
171 getsid(p
, uap
, retval
)
173 struct getsid_args
*uap
;
182 if ((pt
= pfind(uap
->pid
)) == 0)
185 *retval
= pt
->p_session
->s_sid
;
190 getuid(p
, uap
, retval
)
196 *retval
= p
->p_cred
->p_ruid
;
198 retval
[1] = p
->p_ucred
->cr_uid
;
204 geteuid(p
, uap
, retval
)
210 *retval
= p
->p_ucred
->cr_uid
;
215 getgid(p
, uap
, retval
)
221 *retval
= p
->p_cred
->p_rgid
;
223 retval
[1] = p
->p_ucred
->cr_groups
[0];
229 * Get effective group ID. The "egid" is groups[0], and could be obtained
230 * via getgroups. This syscall exists because it is somewhat painful to do
231 * correctly in a library function.
234 getegid(p
, uap
, retval
)
240 *retval
= p
->p_ucred
->cr_groups
[0];
244 struct getgroups_args
{
248 getgroups(p
, uap
, retval
)
250 register struct getgroups_args
*uap
;
253 register struct pcred
*pc
= p
->p_cred
;
257 if ((ngrp
= uap
->gidsetsize
) == 0) {
258 *retval
= pc
->pc_ucred
->cr_ngroups
;
261 if (ngrp
< pc
->pc_ucred
->cr_ngroups
)
264 ngrp
= pc
->pc_ucred
->cr_ngroups
;
265 if (error
= copyout((caddr_t
)pc
->pc_ucred
->cr_groups
,
266 (caddr_t
)uap
->gidset
, ngrp
* sizeof(gid_t
))) {
276 setsid(p
, uap
, retval
)
277 register struct proc
*p
;
282 if (p
->p_pgid
== p
->p_pid
|| pgfind(p
->p_pid
)) {
285 (void)enterpgrp(p
, p
->p_pid
, 1);
292 * set process group (setpgid/old setpgrp)
294 * caller does setpgid(targpid, targpgid)
296 * pid must be caller or child of caller (ESRCH)
298 * pid must be in same session (EPERM)
299 * pid can't have done an exec (EACCES)
301 * there must exist some pid in same session having pgid (EPERM)
302 * pid must not be session leader (EPERM)
304 struct setpgid_args
{
309 setpgid(curp
, uap
, retval
)
311 register struct setpgid_args
*uap
;
314 register struct proc
*targp
; /* target process */
315 register struct pgrp
*pgrp
; /* target pgrp */
317 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
318 if ((targp
= pfind(uap
->pid
)) == 0 || !inferior(targp
))
320 if (targp
->p_session
!= curp
->p_session
)
322 if (targp
->p_flag
& P_EXEC
)
326 if (SESS_LEADER(targp
))
329 uap
->pgid
= targp
->p_pid
;
330 else if (uap
->pgid
!= targp
->p_pid
)
331 if ((pgrp
= pgfind(uap
->pgid
)) == 0 ||
332 pgrp
->pg_session
!= curp
->p_session
)
334 return (enterpgrp(targp
, uap
->pgid
, 0));
337 struct issetugid_args
{
340 issetugid(p
, uap
, retval
)
342 struct issetugid_args
*uap
;
346 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
347 * we use P_SUGID because we consider changing the owners as
348 * "tainting" as well.
349 * This is significant for procs that start as root and "become"
350 * a user without an exec - programs cannot know *everything*
351 * that libc *might* have put in their data segment.
354 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
362 setuid(p
, uap
, retval
)
364 struct setuid_args
*uap
;
367 register struct pcred
*pc
= p
->p_cred
;
372 if (uid
!= pc
->p_ruid
&&
373 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
376 * Everything's okay, do it.
377 * Transfer proc count to new user.
378 * Copy credentials so other references do not see our changes.
381 /* prepare app access profile files */
382 prepare_profile_database(uap
->uid
);
384 (void)chgproccnt(pc
->p_ruid
, -1);
385 (void)chgproccnt(uid
, 1);
386 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
387 pc
->pc_ucred
->cr_uid
= uid
;
391 set_security_token(p
);
392 p
->p_flag
|= P_SUGID
;
396 struct seteuid_args
{
400 seteuid(p
, uap
, retval
)
402 struct seteuid_args
*uap
;
405 register struct pcred
*pc
= p
->p_cred
;
410 if (euid
!= pc
->p_ruid
&& euid
!= pc
->p_svuid
&&
411 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
414 * Everything's okay, do it. Copy credentials so other references do
415 * not see our changes.
418 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
419 pc
->pc_ucred
->cr_uid
= euid
;
421 set_security_token(p
);
422 p
->p_flag
|= P_SUGID
;
430 setgid(p
, uap
, retval
)
432 struct setgid_args
*uap
;
435 register struct pcred
*pc
= p
->p_cred
;
440 if (gid
!= pc
->p_rgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
443 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
444 pc
->pc_ucred
->cr_groups
[0] = gid
;
446 pc
->p_svgid
= gid
; /* ??? */
448 set_security_token(p
);
449 p
->p_flag
|= P_SUGID
;
453 struct setegid_args
{
457 setegid(p
, uap
, retval
)
459 struct setegid_args
*uap
;
462 register struct pcred
*pc
= p
->p_cred
;
467 if (egid
!= pc
->p_rgid
&& egid
!= pc
->p_svgid
&&
468 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
471 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
472 pc
->pc_ucred
->cr_groups
[0] = egid
;
474 set_security_token(p
);
475 p
->p_flag
|= P_SUGID
;
479 struct setgroups_args
{
485 setgroups(p
, uap
, retval
)
487 struct setgroups_args
*uap
;
490 register struct pcred
*pc
= p
->p_cred
;
491 struct ucred
*new, *old
;
495 if (error
= suser(pc
->pc_ucred
, &p
->p_acflag
))
497 ngrp
= uap
->gidsetsize
;
498 if (ngrp
< 1 || ngrp
> NGROUPS
)
501 error
= copyin((caddr_t
)uap
->gidset
,
502 (caddr_t
)new->cr_groups
, ngrp
* sizeof(gid_t
));
507 new->cr_ngroups
= ngrp
;
510 new->cr_uid
= old
->cr_uid
;
513 set_security_token(p
);
514 p
->p_flag
|= P_SUGID
;
521 struct osetreuid_args
{
526 osetreuid(p
, uap
, retval
)
527 register struct proc
*p
;
528 struct osetreuid_args
*uap
;
531 struct seteuid_args seuidargs
;
532 struct setuid_args suidargs
;
535 * There are five cases, and we attempt to emulate them in
536 * the following fashion:
537 * -1, -1: return 0. This is correct emulation.
538 * -1, N: call seteuid(N). This is correct emulation.
539 * N, -1: if we called setuid(N), our euid would be changed
540 * to N as well. the theory is that we don't want to
541 * revoke root access yet, so we call seteuid(N)
542 * instead. This is incorrect emulation, but often
543 * suffices enough for binary compatibility.
544 * N, N: call setuid(N). This is correct emulation.
545 * N, M: call setuid(N). This is close to correct emulation.
547 if (uap
->ruid
== (uid_t
)-1) {
548 if (uap
->euid
== (uid_t
)-1)
549 return (0); /* -1, -1 */
550 seuidargs
.euid
= uap
->euid
; /* -1, N */
551 return (seteuid(p
, &seuidargs
, retval
));
553 if (uap
->euid
== (uid_t
)-1) {
554 seuidargs
.euid
= uap
->ruid
; /* N, -1 */
555 return (seteuid(p
, &seuidargs
, retval
));
557 suidargs
.uid
= uap
->ruid
; /* N, N and N, M */
558 return (setuid(p
, &suidargs
, retval
));
561 struct osetregid_args
{
566 osetregid(p
, uap
, retval
)
567 register struct proc
*p
;
568 struct osetregid_args
*uap
;
571 struct setegid_args segidargs
;
572 struct setgid_args sgidargs
;
575 * There are five cases, described above in osetreuid()
577 if (uap
->rgid
== (gid_t
)-1) {
578 if (uap
->egid
== (gid_t
)-1)
579 return (0); /* -1, -1 */
580 segidargs
.egid
= uap
->egid
; /* -1, N */
581 return (setegid(p
, &segidargs
, retval
));
583 if (uap
->egid
== (gid_t
)-1) {
584 segidargs
.egid
= uap
->rgid
; /* N, -1 */
585 return (setegid(p
, &segidargs
, retval
));
587 sgidargs
.gid
= uap
->rgid
; /* N, N and N, M */
588 return (setgid(p
, &sgidargs
, retval
));
590 #endif /* COMPAT_43 */
593 * Check if gid is a member of the group set.
595 groupmember(gid
, cred
)
597 register struct ucred
*cred
;
602 egp
= &(cred
->cr_groups
[cred
->cr_ngroups
]);
603 for (gp
= cred
->cr_groups
; gp
< egp
; gp
++)
610 * Test whether the specified credentials imply "super-user"
611 * privilege; if so, and we have accounting info, set the flag
612 * indicating use of super-powers.
613 * Returns 0 or error.
620 if (cred
== NOCRED
|| cred
== FSCRED
)
623 if (cred
->cr_uid
== 0) {
634 struct proc
*p
= current_proc();
639 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0);
645 struct proc
*p
= current_proc();
650 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0 ||
651 p
->p_cred
->p_ruid
== 0 || p
->p_cred
->p_svuid
== 0);
655 * Allocate a zeroed cred structure.
660 register struct ucred
*cr
;
662 MALLOC_ZONE(cr
, struct ucred
*, sizeof(*cr
), M_CRED
, M_WAITOK
);
663 bzero((caddr_t
)cr
, sizeof(*cr
));
669 * Free a cred structure.
670 * Throws away space when ref count gets to 0.
677 if (cr
== NOCRED
|| cr
== FSCRED
)
680 if (--cr
->cr_ref
== 0)
681 FREE_ZONE((caddr_t
)cr
, sizeof *cr
, M_CRED
);
685 * Copy cred structure to a new one and free the old one.
694 if (cr
== NOCRED
|| cr
== FSCRED
)
707 * Dup cred struct to a new held one.
716 if (cr
== NOCRED
|| cr
== FSCRED
)
726 * Get login name, if available.
728 struct getlogin_args
{
733 getlogin(p
, uap
, retval
)
735 struct getlogin_args
*uap
;
739 if (uap
->namelen
> sizeof (p
->p_pgrp
->pg_session
->s_login
))
740 uap
->namelen
= sizeof (p
->p_pgrp
->pg_session
->s_login
);
741 return (copyout((caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
742 (caddr_t
)uap
->namebuf
, uap
->namelen
));
748 struct setlogin_args
{
752 setlogin(p
, uap
, retval
)
754 struct setlogin_args
*uap
;
760 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
763 error
= copyinstr((caddr_t
) uap
->namebuf
,
764 (caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
765 sizeof (p
->p_pgrp
->pg_session
->s_login
) - 1, (size_t *)&dummy
);
766 if (error
== ENAMETOOLONG
)
772 /* Set the secrity token of the task with current euid and eguid */
774 set_security_token(struct proc
* p
)
776 security_token_t sec_token
;
778 sec_token
.val
[0] = p
->p_ucred
->cr_uid
;
779 sec_token
.val
[1] = p
->p_ucred
->cr_gid
;
780 return host_security_set_task_token(host_security_self(),