2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
64 * System calls related to processes and protection
67 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/ucred.h>
72 #include <sys/timeb.h>
73 #include <sys/times.h>
74 #include <sys/malloc.h>
76 #include <sys/mount.h>
77 #include <mach/message.h>
78 #include <mach/host_security.h>
80 #include <kern/host.h>
83 * setprivexec: (dis)allow this process to hold
84 * task, thread, or execption ports of processes about to exec.
86 struct setprivexec_args
{
90 setprivexec(p
, uap
, retval
)
92 register struct setprivexec_args
*uap
;
95 *retval
= p
->p_debugger
;
96 p
->p_debugger
= (uap
->flag
!= 0);
101 getpid(p
, uap
, retval
)
109 retval
[1] = p
->p_pptr
->p_pid
;
115 getppid(p
, uap
, retval
)
121 *retval
= p
->p_pptr
->p_pid
;
125 /* Get process group ID; note that POSIX getpgrp takes no parameter */
126 getpgrp(p
, uap
, retval
)
132 *retval
= p
->p_pgrp
->pg_id
;
136 /* Get an arbitary pid's process group id */
137 struct getpgid_args
{
142 getpgid(p
, uap
, retval
)
144 struct getpgid_args
*uap
;
153 if ((pt
= pfind(uap
->pid
)) == 0)
156 *retval
= pt
->p_pgrp
->pg_id
;
161 * Get an arbitary pid's session id.
168 getsid(p
, uap
, retval
)
170 struct getsid_args
*uap
;
179 if ((pt
= pfind(uap
->pid
)) == 0)
182 *retval
= pt
->p_session
->s_sid
;
187 getuid(p
, uap
, retval
)
193 *retval
= p
->p_cred
->p_ruid
;
195 retval
[1] = p
->p_ucred
->cr_uid
;
201 geteuid(p
, uap
, retval
)
207 *retval
= p
->p_ucred
->cr_uid
;
212 getgid(p
, uap
, retval
)
218 *retval
= p
->p_cred
->p_rgid
;
220 retval
[1] = p
->p_ucred
->cr_groups
[0];
226 * Get effective group ID. The "egid" is groups[0], and could be obtained
227 * via getgroups. This syscall exists because it is somewhat painful to do
228 * correctly in a library function.
231 getegid(p
, uap
, retval
)
237 *retval
= p
->p_ucred
->cr_groups
[0];
241 struct getgroups_args
{
245 getgroups(p
, uap
, retval
)
247 register struct getgroups_args
*uap
;
250 register struct pcred
*pc
= p
->p_cred
;
254 if ((ngrp
= uap
->gidsetsize
) == 0) {
255 *retval
= pc
->pc_ucred
->cr_ngroups
;
258 if (ngrp
< pc
->pc_ucred
->cr_ngroups
)
261 ngrp
= pc
->pc_ucred
->cr_ngroups
;
262 if (error
= copyout((caddr_t
)pc
->pc_ucred
->cr_groups
,
263 (caddr_t
)uap
->gidset
, ngrp
* sizeof(gid_t
))) {
273 setsid(p
, uap
, retval
)
274 register struct proc
*p
;
279 if (p
->p_pgid
== p
->p_pid
|| pgfind(p
->p_pid
)) {
282 (void)enterpgrp(p
, p
->p_pid
, 1);
289 * set process group (setpgid/old setpgrp)
291 * caller does setpgid(targpid, targpgid)
293 * pid must be caller or child of caller (ESRCH)
295 * pid must be in same session (EPERM)
296 * pid can't have done an exec (EACCES)
298 * there must exist some pid in same session having pgid (EPERM)
299 * pid must not be session leader (EPERM)
301 struct setpgid_args
{
306 setpgid(curp
, uap
, retval
)
308 register struct setpgid_args
*uap
;
311 register struct proc
*targp
; /* target process */
312 register struct pgrp
*pgrp
; /* target pgrp */
314 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
315 if ((targp
= pfind(uap
->pid
)) == 0 || !inferior(targp
))
317 if (targp
->p_session
!= curp
->p_session
)
319 if (targp
->p_flag
& P_EXEC
)
323 if (SESS_LEADER(targp
))
326 uap
->pgid
= targp
->p_pid
;
327 else if (uap
->pgid
!= targp
->p_pid
)
328 if ((pgrp
= pgfind(uap
->pgid
)) == 0 ||
329 pgrp
->pg_session
!= curp
->p_session
)
331 return (enterpgrp(targp
, uap
->pgid
, 0));
334 struct issetugid_args
{
337 issetugid(p
, uap
, retval
)
339 struct issetugid_args
*uap
;
343 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
344 * we use P_SUGID because we consider changing the owners as
345 * "tainting" as well.
346 * This is significant for procs that start as root and "become"
347 * a user without an exec - programs cannot know *everything*
348 * that libc *might* have put in their data segment.
351 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
359 setuid(p
, uap
, retval
)
361 struct setuid_args
*uap
;
364 register struct pcred
*pc
= p
->p_cred
;
369 if (uid
!= pc
->p_ruid
&&
370 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
373 * Everything's okay, do it.
374 * Transfer proc count to new user.
375 * Copy credentials so other references do not see our changes.
378 /* prepare app access profile files */
379 prepare_profile_database(uap
->uid
);
381 (void)chgproccnt(pc
->p_ruid
, -1);
382 (void)chgproccnt(uid
, 1);
383 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
384 pc
->pc_ucred
->cr_uid
= uid
;
388 set_security_token(p
);
389 p
->p_flag
|= P_SUGID
;
393 struct seteuid_args
{
397 seteuid(p
, uap
, retval
)
399 struct seteuid_args
*uap
;
402 register struct pcred
*pc
= p
->p_cred
;
407 if (euid
!= pc
->p_ruid
&& euid
!= pc
->p_svuid
&&
408 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
411 * Everything's okay, do it. Copy credentials so other references do
412 * not see our changes.
415 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
416 pc
->pc_ucred
->cr_uid
= euid
;
418 set_security_token(p
);
419 p
->p_flag
|= P_SUGID
;
427 setgid(p
, uap
, retval
)
429 struct setgid_args
*uap
;
432 register struct pcred
*pc
= p
->p_cred
;
437 if (gid
!= pc
->p_rgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
440 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
441 pc
->pc_ucred
->cr_groups
[0] = gid
;
443 pc
->p_svgid
= gid
; /* ??? */
445 set_security_token(p
);
446 p
->p_flag
|= P_SUGID
;
450 struct setegid_args
{
454 setegid(p
, uap
, retval
)
456 struct setegid_args
*uap
;
459 register struct pcred
*pc
= p
->p_cred
;
464 if (egid
!= pc
->p_rgid
&& egid
!= pc
->p_svgid
&&
465 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
468 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
469 pc
->pc_ucred
->cr_groups
[0] = egid
;
471 set_security_token(p
);
472 p
->p_flag
|= P_SUGID
;
476 struct setgroups_args
{
482 setgroups(p
, uap
, retval
)
484 struct setgroups_args
*uap
;
487 register struct pcred
*pc
= p
->p_cred
;
488 struct ucred
*new, *old
;
492 if (error
= suser(pc
->pc_ucred
, &p
->p_acflag
))
494 ngrp
= uap
->gidsetsize
;
495 if (ngrp
< 1 || ngrp
> NGROUPS
)
498 error
= copyin((caddr_t
)uap
->gidset
,
499 (caddr_t
)new->cr_groups
, ngrp
* sizeof(gid_t
));
504 new->cr_ngroups
= ngrp
;
507 new->cr_uid
= old
->cr_uid
;
510 set_security_token(p
);
511 p
->p_flag
|= P_SUGID
;
518 struct osetreuid_args
{
523 osetreuid(p
, uap
, retval
)
524 register struct proc
*p
;
525 struct osetreuid_args
*uap
;
528 struct seteuid_args seuidargs
;
529 struct setuid_args suidargs
;
532 * There are five cases, and we attempt to emulate them in
533 * the following fashion:
534 * -1, -1: return 0. This is correct emulation.
535 * -1, N: call seteuid(N). This is correct emulation.
536 * N, -1: if we called setuid(N), our euid would be changed
537 * to N as well. the theory is that we don't want to
538 * revoke root access yet, so we call seteuid(N)
539 * instead. This is incorrect emulation, but often
540 * suffices enough for binary compatibility.
541 * N, N: call setuid(N). This is correct emulation.
542 * N, M: call setuid(N). This is close to correct emulation.
544 if (uap
->ruid
== (uid_t
)-1) {
545 if (uap
->euid
== (uid_t
)-1)
546 return (0); /* -1, -1 */
547 seuidargs
.euid
= uap
->euid
; /* -1, N */
548 return (seteuid(p
, &seuidargs
, retval
));
550 if (uap
->euid
== (uid_t
)-1) {
551 seuidargs
.euid
= uap
->ruid
; /* N, -1 */
552 return (seteuid(p
, &seuidargs
, retval
));
554 suidargs
.uid
= uap
->ruid
; /* N, N and N, M */
555 return (setuid(p
, &suidargs
, retval
));
558 struct osetregid_args
{
563 osetregid(p
, uap
, retval
)
564 register struct proc
*p
;
565 struct osetregid_args
*uap
;
568 struct setegid_args segidargs
;
569 struct setgid_args sgidargs
;
572 * There are five cases, described above in osetreuid()
574 if (uap
->rgid
== (gid_t
)-1) {
575 if (uap
->egid
== (gid_t
)-1)
576 return (0); /* -1, -1 */
577 segidargs
.egid
= uap
->egid
; /* -1, N */
578 return (setegid(p
, &segidargs
, retval
));
580 if (uap
->egid
== (gid_t
)-1) {
581 segidargs
.egid
= uap
->rgid
; /* N, -1 */
582 return (setegid(p
, &segidargs
, retval
));
584 sgidargs
.gid
= uap
->rgid
; /* N, N and N, M */
585 return (setgid(p
, &sgidargs
, retval
));
587 #endif /* COMPAT_43 */
590 * Check if gid is a member of the group set.
592 groupmember(gid
, cred
)
594 register struct ucred
*cred
;
599 egp
= &(cred
->cr_groups
[cred
->cr_ngroups
]);
600 for (gp
= cred
->cr_groups
; gp
< egp
; gp
++)
607 * Test whether the specified credentials imply "super-user"
608 * privilege; if so, and we have accounting info, set the flag
609 * indicating use of super-powers.
610 * Returns 0 or error.
617 if (cred
== NOCRED
|| cred
== FSCRED
)
620 if (cred
->cr_uid
== 0) {
631 struct proc
*p
= current_proc();
636 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0);
642 struct proc
*p
= current_proc();
647 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0 ||
648 p
->p_cred
->p_ruid
== 0 || p
->p_cred
->p_svuid
== 0);
652 * Allocate a zeroed cred structure.
657 register struct ucred
*cr
;
659 MALLOC_ZONE(cr
, struct ucred
*, sizeof(*cr
), M_CRED
, M_WAITOK
);
660 bzero((caddr_t
)cr
, sizeof(*cr
));
666 * Free a cred structure.
667 * Throws away space when ref count gets to 0.
674 if (cr
== NOCRED
|| cr
== FSCRED
)
677 if (--cr
->cr_ref
== 0)
678 FREE_ZONE((caddr_t
)cr
, sizeof *cr
, M_CRED
);
682 * Copy cred structure to a new one and free the old one.
691 if (cr
== NOCRED
|| cr
== FSCRED
)
704 * Dup cred struct to a new held one.
713 if (cr
== NOCRED
|| cr
== FSCRED
)
723 * Get login name, if available.
725 struct getlogin_args
{
730 getlogin(p
, uap
, retval
)
732 struct getlogin_args
*uap
;
736 if (uap
->namelen
> sizeof (p
->p_pgrp
->pg_session
->s_login
))
737 uap
->namelen
= sizeof (p
->p_pgrp
->pg_session
->s_login
);
738 return (copyout((caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
739 (caddr_t
)uap
->namebuf
, uap
->namelen
));
745 struct setlogin_args
{
749 setlogin(p
, uap
, retval
)
751 struct setlogin_args
*uap
;
757 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
760 error
= copyinstr((caddr_t
) uap
->namebuf
,
761 (caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
762 sizeof (p
->p_pgrp
->pg_session
->s_login
) - 1, (size_t *)&dummy
);
763 if (error
== ENAMETOOLONG
)
769 /* Set the secrity token of the task with current euid and eguid */
771 set_security_token(struct proc
* p
)
773 security_token_t sec_token
;
775 sec_token
.val
[0] = p
->p_ucred
->cr_uid
;
776 sec_token
.val
[1] = p
->p_ucred
->cr_gid
;
777 return host_security_set_task_token(host_security_self(),