2 * Copyright (c) 2000 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 <kern/host.h>
81 * setprivexec: (dis)allow this process to hold
82 * task, thread, or execption ports of processes about to exec.
84 struct setprivexec_args
{
88 setprivexec(p
, uap
, retval
)
90 register struct setprivexec_args
*uap
;
93 *retval
= p
->p_debugger
;
94 p
->p_debugger
= (uap
->flag
!= 0);
99 getpid(p
, uap
, retval
)
107 retval
[1] = p
->p_pptr
->p_pid
;
113 getppid(p
, uap
, retval
)
119 *retval
= p
->p_pptr
->p_pid
;
123 /* Get process group ID; note that POSIX getpgrp takes no parameter */
124 getpgrp(p
, uap
, retval
)
130 *retval
= p
->p_pgrp
->pg_id
;
135 getuid(p
, uap
, retval
)
141 *retval
= p
->p_cred
->p_ruid
;
143 retval
[1] = p
->p_ucred
->cr_uid
;
149 geteuid(p
, uap
, retval
)
155 *retval
= p
->p_ucred
->cr_uid
;
160 getgid(p
, uap
, retval
)
166 *retval
= p
->p_cred
->p_rgid
;
168 retval
[1] = p
->p_ucred
->cr_groups
[0];
174 * Get effective group ID. The "egid" is groups[0], and could be obtained
175 * via getgroups. This syscall exists because it is somewhat painful to do
176 * correctly in a library function.
179 getegid(p
, uap
, retval
)
185 *retval
= p
->p_ucred
->cr_groups
[0];
189 struct getgroups_args
{
193 getgroups(p
, uap
, retval
)
195 register struct getgroups_args
*uap
;
198 register struct pcred
*pc
= p
->p_cred
;
202 if ((ngrp
= uap
->gidsetsize
) == 0) {
203 *retval
= pc
->pc_ucred
->cr_ngroups
;
206 if (ngrp
< pc
->pc_ucred
->cr_ngroups
)
209 ngrp
= pc
->pc_ucred
->cr_ngroups
;
210 if (error
= copyout((caddr_t
)pc
->pc_ucred
->cr_groups
,
211 (caddr_t
)uap
->gidset
, ngrp
* sizeof(gid_t
))) {
221 setsid(p
, uap
, retval
)
222 register struct proc
*p
;
227 if (p
->p_pgid
== p
->p_pid
|| pgfind(p
->p_pid
)) {
230 (void)enterpgrp(p
, p
->p_pid
, 1);
237 * set process group (setpgid/old setpgrp)
239 * caller does setpgid(targpid, targpgid)
241 * pid must be caller or child of caller (ESRCH)
243 * pid must be in same session (EPERM)
244 * pid can't have done an exec (EACCES)
246 * there must exist some pid in same session having pgid (EPERM)
247 * pid must not be session leader (EPERM)
249 struct setpgid_args
{
254 setpgid(curp
, uap
, retval
)
256 register struct setpgid_args
*uap
;
259 register struct proc
*targp
; /* target process */
260 register struct pgrp
*pgrp
; /* target pgrp */
262 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
263 if ((targp
= pfind(uap
->pid
)) == 0 || !inferior(targp
))
265 if (targp
->p_session
!= curp
->p_session
)
267 if (targp
->p_flag
& P_EXEC
)
271 if (SESS_LEADER(targp
))
274 uap
->pgid
= targp
->p_pid
;
275 else if (uap
->pgid
!= targp
->p_pid
)
276 if ((pgrp
= pgfind(uap
->pgid
)) == 0 ||
277 pgrp
->pg_session
!= curp
->p_session
)
279 return (enterpgrp(targp
, uap
->pgid
, 0));
282 struct issetugid_args
{
285 issetugid(p
, uap
, retval
)
287 struct issetugid_args
*uap
;
291 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
292 * we use P_SUGID because we consider changing the owners as
293 * "tainting" as well.
294 * This is significant for procs that start as root and "become"
295 * a user without an exec - programs cannot know *everything*
296 * that libc *might* have put in their data segment.
299 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
307 setuid(p
, uap
, retval
)
309 struct setuid_args
*uap
;
312 register struct pcred
*pc
= p
->p_cred
;
317 if (uid
!= pc
->p_ruid
&&
318 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
321 * Everything's okay, do it.
322 * Transfer proc count to new user.
323 * Copy credentials so other references do not see our changes.
326 (void)chgproccnt(pc
->p_ruid
, -1);
327 (void)chgproccnt(uid
, 1);
328 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
329 pc
->pc_ucred
->cr_uid
= uid
;
333 set_security_token(p
);
334 p
->p_flag
|= P_SUGID
;
338 struct seteuid_args
{
342 seteuid(p
, uap
, retval
)
344 struct seteuid_args
*uap
;
347 register struct pcred
*pc
= p
->p_cred
;
352 if (euid
!= pc
->p_ruid
&& euid
!= pc
->p_svuid
&&
353 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
356 * Everything's okay, do it. Copy credentials so other references do
357 * not see our changes.
360 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
361 pc
->pc_ucred
->cr_uid
= euid
;
363 set_security_token(p
);
364 p
->p_flag
|= P_SUGID
;
372 setgid(p
, uap
, retval
)
374 struct setgid_args
*uap
;
377 register struct pcred
*pc
= p
->p_cred
;
382 if (gid
!= pc
->p_rgid
&& (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
385 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
386 pc
->pc_ucred
->cr_groups
[0] = gid
;
388 pc
->p_svgid
= gid
; /* ??? */
390 set_security_token(p
);
391 p
->p_flag
|= P_SUGID
;
395 struct setegid_args
{
399 setegid(p
, uap
, retval
)
401 struct setegid_args
*uap
;
404 register struct pcred
*pc
= p
->p_cred
;
409 if (egid
!= pc
->p_rgid
&& egid
!= pc
->p_svgid
&&
410 (error
= suser(pc
->pc_ucred
, &p
->p_acflag
)))
413 pc
->pc_ucred
= crcopy(pc
->pc_ucred
);
414 pc
->pc_ucred
->cr_groups
[0] = egid
;
416 set_security_token(p
);
417 p
->p_flag
|= P_SUGID
;
421 struct setgroups_args
{
427 setgroups(p
, uap
, retval
)
429 struct setgroups_args
*uap
;
432 register struct pcred
*pc
= p
->p_cred
;
433 struct ucred
*new, *old
;
437 if (error
= suser(pc
->pc_ucred
, &p
->p_acflag
))
439 ngrp
= uap
->gidsetsize
;
440 if (ngrp
< 1 || ngrp
> NGROUPS
)
443 error
= copyin((caddr_t
)uap
->gidset
,
444 (caddr_t
)new->cr_groups
, ngrp
* sizeof(gid_t
));
449 new->cr_ngroups
= ngrp
;
452 new->cr_uid
= old
->cr_uid
;
455 set_security_token(p
);
456 p
->p_flag
|= P_SUGID
;
463 struct osetreuid_args
{
468 osetreuid(p
, uap
, retval
)
469 register struct proc
*p
;
470 struct osetreuid_args
*uap
;
473 struct seteuid_args seuidargs
;
474 struct setuid_args suidargs
;
477 * There are five cases, and we attempt to emulate them in
478 * the following fashion:
479 * -1, -1: return 0. This is correct emulation.
480 * -1, N: call seteuid(N). This is correct emulation.
481 * N, -1: if we called setuid(N), our euid would be changed
482 * to N as well. the theory is that we don't want to
483 * revoke root access yet, so we call seteuid(N)
484 * instead. This is incorrect emulation, but often
485 * suffices enough for binary compatibility.
486 * N, N: call setuid(N). This is correct emulation.
487 * N, M: call setuid(N). This is close to correct emulation.
489 if (uap
->ruid
== (uid_t
)-1) {
490 if (uap
->euid
== (uid_t
)-1)
491 return (0); /* -1, -1 */
492 seuidargs
.euid
= uap
->euid
; /* -1, N */
493 return (seteuid(p
, &seuidargs
, retval
));
495 if (uap
->euid
== (uid_t
)-1) {
496 seuidargs
.euid
= uap
->ruid
; /* N, -1 */
497 return (seteuid(p
, &seuidargs
, retval
));
499 suidargs
.uid
= uap
->ruid
; /* N, N and N, M */
500 return (setuid(p
, &suidargs
, retval
));
503 struct osetregid_args
{
508 osetregid(p
, uap
, retval
)
509 register struct proc
*p
;
510 struct osetregid_args
*uap
;
513 struct setegid_args segidargs
;
514 struct setgid_args sgidargs
;
517 * There are five cases, described above in osetreuid()
519 if (uap
->rgid
== (gid_t
)-1) {
520 if (uap
->egid
== (gid_t
)-1)
521 return (0); /* -1, -1 */
522 segidargs
.egid
= uap
->egid
; /* -1, N */
523 return (setegid(p
, &segidargs
, retval
));
525 if (uap
->egid
== (gid_t
)-1) {
526 segidargs
.egid
= uap
->rgid
; /* N, -1 */
527 return (setegid(p
, &segidargs
, retval
));
529 sgidargs
.gid
= uap
->rgid
; /* N, N and N, M */
530 return (setgid(p
, &sgidargs
, retval
));
532 #endif /* COMPAT_43 */
535 * Check if gid is a member of the group set.
537 groupmember(gid
, cred
)
539 register struct ucred
*cred
;
544 egp
= &(cred
->cr_groups
[cred
->cr_ngroups
]);
545 for (gp
= cred
->cr_groups
; gp
< egp
; gp
++)
552 * Test whether the specified credentials imply "super-user"
553 * privilege; if so, and we have accounting info, set the flag
554 * indicating use of super-powers.
555 * Returns 0 or error.
562 if (cred
== NOCRED
|| cred
== FSCRED
)
565 if (cred
->cr_uid
== 0) {
576 struct proc
*p
= current_proc();
581 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0);
587 struct proc
*p
= current_proc();
592 return (suser(p
->p_ucred
, &p
->p_acflag
) == 0 ||
593 p
->p_cred
->p_ruid
== 0 || p
->p_cred
->p_svuid
== 0);
597 * Allocate a zeroed cred structure.
602 register struct ucred
*cr
;
604 MALLOC_ZONE(cr
, struct ucred
*, sizeof(*cr
), M_CRED
, M_WAITOK
);
605 bzero((caddr_t
)cr
, sizeof(*cr
));
611 * Free a cred structure.
612 * Throws away space when ref count gets to 0.
619 if (cr
== NOCRED
|| cr
== FSCRED
)
622 if (--cr
->cr_ref
== 0)
623 FREE_ZONE((caddr_t
)cr
, sizeof *cr
, M_CRED
);
627 * Copy cred structure to a new one and free the old one.
636 if (cr
== NOCRED
|| cr
== FSCRED
)
649 * Dup cred struct to a new held one.
658 if (cr
== NOCRED
|| cr
== FSCRED
)
668 * Get login name, if available.
670 struct getlogin_args
{
675 getlogin(p
, uap
, retval
)
677 struct getlogin_args
*uap
;
681 if (uap
->namelen
> sizeof (p
->p_pgrp
->pg_session
->s_login
))
682 uap
->namelen
= sizeof (p
->p_pgrp
->pg_session
->s_login
);
683 return (copyout((caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
684 (caddr_t
)uap
->namebuf
, uap
->namelen
));
690 struct setlogin_args
{
694 setlogin(p
, uap
, retval
)
696 struct setlogin_args
*uap
;
702 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
705 error
= copyinstr((caddr_t
) uap
->namebuf
,
706 (caddr_t
) p
->p_pgrp
->pg_session
->s_login
,
707 sizeof (p
->p_pgrp
->pg_session
->s_login
) - 1, (size_t *)&dummy
);
708 if (error
== ENAMETOOLONG
)
714 /* Set the secrity token of the task with current euid and eguid */
716 set_security_token(struct proc
* p
)
718 security_token_t sec_token
;
720 sec_token
.val
[0] = p
->p_ucred
->cr_uid
;
721 sec_token
.val
[1] = p
->p_ucred
->cr_gid
;
722 (void)host_security_set_task_token(host_security_self(),