]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_prot.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / kern / kern_prot.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
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.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 *
60 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
61 */
62
63/*
64 * System calls related to processes and protection
65 */
66
67#include <sys/param.h>
68#include <sys/acct.h>
69#include <sys/systm.h>
70#include <sys/ucred.h>
91447636
A
71#include <sys/proc_internal.h>
72#include <sys/user.h>
73#include <sys/kauth.h>
1c79356b
A
74#include <sys/timeb.h>
75#include <sys/times.h>
76#include <sys/malloc.h>
e5568f75
A
77
78#include <bsm/audit_kernel.h>
1c79356b 79
91447636
A
80#include <sys/mount_internal.h>
81#include <sys/sysproto.h>
1c79356b 82#include <mach/message.h>
9bccf70c
A
83#include <mach/host_security.h>
84
1c79356b
A
85#include <kern/host.h>
86
91447636
A
87int groupmember(gid_t gid, kauth_cred_t cred);
88int is_suser(void);
89int is_suser1(void);
90
91extern int prepare_profile_database(int user);
92
1c79356b
A
93/*
94 * setprivexec: (dis)allow this process to hold
95 * task, thread, or execption ports of processes about to exec.
96 */
1c79356b 97int
91447636 98setprivexec(struct proc *p, struct setprivexec_args *uap, register_t *retval)
1c79356b 99{
e5568f75 100 AUDIT_ARG(value, uap->flag);
1c79356b
A
101 *retval = p->p_debugger;
102 p->p_debugger = (uap->flag != 0);
103 return(0);
104}
105
106/* ARGSUSED */
91447636
A
107int
108getpid(struct proc *p, __unused struct getpid_args *uap, register_t *retval)
1c79356b
A
109{
110
111 *retval = p->p_pid;
1c79356b
A
112 return (0);
113}
114
115/* ARGSUSED */
91447636
A
116int
117getppid(struct proc *p, __unused struct getppid_args *uap, register_t *retval)
1c79356b
A
118{
119
120 *retval = p->p_pptr->p_pid;
121 return (0);
122}
123
124/* Get process group ID; note that POSIX getpgrp takes no parameter */
91447636
A
125int
126getpgrp(struct proc *p, __unused struct getpgrp_args *uap, register_t *retval)
1c79356b
A
127{
128
129 *retval = p->p_pgrp->pg_id;
130 return (0);
131}
132
9bccf70c 133/* Get an arbitary pid's process group id */
9bccf70c 134int
91447636 135getpgid(struct proc *p, struct getpgid_args *uap, register_t *retval)
9bccf70c
A
136{
137 struct proc *pt;
138
139 pt = p;
140 if (uap->pid == 0)
141 goto found;
142
143 if ((pt = pfind(uap->pid)) == 0)
144 return (ESRCH);
145found:
146 *retval = pt->p_pgrp->pg_id;
147 return (0);
148}
149
150/*
151 * Get an arbitary pid's session id.
152 */
9bccf70c
A
153
154int
91447636 155getsid(struct proc *p, struct getsid_args *uap, register_t *retval)
9bccf70c
A
156{
157 struct proc *pt;
158
159 pt = p;
160 if (uap->pid == 0)
161 goto found;
162
163 if ((pt = pfind(uap->pid)) == 0)
164 return (ESRCH);
165found:
166 *retval = pt->p_session->s_sid;
167 return (0);
168}
169
1c79356b 170/* ARGSUSED */
91447636
A
171int
172getuid(__unused struct proc *p, __unused struct getuid_args *uap, register_t *retval)
1c79356b
A
173{
174
91447636 175 *retval = kauth_getruid();
1c79356b
A
176 return (0);
177}
178
179/* ARGSUSED */
91447636
A
180int
181geteuid(__unused struct proc *p, __unused struct geteuid_args *uap, register_t *retval)
182{
183
184 *retval = kauth_getuid();
185 return (0);
186}
187
188/*
189 * Return the per-thread override identity.
190 */
191int
192gettid(__unused struct proc *p, struct gettid_args *uap, register_t *retval)
1c79356b 193{
91447636
A
194 struct uthread *uthread = get_bsdthread_info(current_thread());
195 int error;
1c79356b 196
91447636
A
197 /*
198 * If this thread is not running with an override identity, we can't
199 * return one to the caller, so return an error instead.
200 */
201 if (!(uthread->uu_flag & UT_SETUID))
202 return (ESRCH);
203
204 if ((error = suword(uap->uidp, uthread->uu_ucred->cr_ruid)))
205 return (error);
206 if ((error = suword(uap->gidp, uthread->uu_ucred->cr_rgid)))
207 return (error);
208
209 *retval = 0;
1c79356b
A
210 return (0);
211}
212
213/* ARGSUSED */
91447636
A
214int
215getgid(__unused struct proc *p, __unused struct getgid_args *uap, register_t *retval)
1c79356b
A
216{
217
91447636 218 *retval = kauth_getrgid();
1c79356b
A
219 return (0);
220}
221
222/*
223 * Get effective group ID. The "egid" is groups[0], and could be obtained
224 * via getgroups. This syscall exists because it is somewhat painful to do
225 * correctly in a library function.
226 */
227/* ARGSUSED */
91447636
A
228int
229getegid(struct proc *p, __unused struct getegid_args *uap, register_t *retval)
1c79356b
A
230{
231
91447636 232 *retval = kauth_getgid();
1c79356b
A
233 return (0);
234}
235
91447636
A
236int
237getgroups(__unused struct proc *p, struct getgroups_args *uap, register_t *retval)
1c79356b 238{
91447636 239 register int ngrp;
1c79356b 240 int error;
91447636
A
241 kauth_cred_t cred;
242
243 /* grab reference while we muck around with the credential */
244 cred = kauth_cred_get_with_ref();
1c79356b
A
245
246 if ((ngrp = uap->gidsetsize) == 0) {
91447636
A
247 *retval = cred->cr_ngroups;
248 kauth_cred_rele(cred);
1c79356b
A
249 return (0);
250 }
91447636
A
251 if (ngrp < cred->cr_ngroups) {
252 kauth_cred_rele(cred);
1c79356b 253 return (EINVAL);
91447636
A
254 }
255 ngrp = cred->cr_ngroups;
256 if ((error = copyout((caddr_t)cred->cr_groups,
257 uap->gidset,
258 ngrp * sizeof(gid_t)))) {
259 kauth_cred_rele(cred);
1c79356b
A
260 return (error);
261 }
91447636 262 kauth_cred_rele(cred);
1c79356b
A
263 *retval = ngrp;
264 return (0);
265}
266
91447636
A
267/*
268 * Return the per-thread/per-process supplementary groups list.
269 */
270#warning XXX implement
271int
272getsgroups(__unused struct proc *p, __unused struct getsgroups_args *uap, __unused register_t *retval)
273{
274 /* XXX implement */
275 return(ENOTSUP);
276}
277
278/*
279 * Return the per-thread/per-process whiteout groups list.
280 */
281#warning XXX implement
282int
283getwgroups(__unused struct proc *p, __unused struct getwgroups_args *uap, __unused register_t *retval)
284{
285 /* XXX implement */
286 return(ENOTSUP);
287}
288
1c79356b 289/* ARGSUSED */
91447636
A
290int
291setsid(struct proc *p, __unused struct setsid_args *uap, register_t *retval)
1c79356b
A
292{
293
55e303ae 294 if (p->p_pgid == p->p_pid || pgfind(p->p_pid) || p->p_flag & P_INVFORK) {
1c79356b
A
295 return (EPERM);
296 } else {
297 (void)enterpgrp(p, p->p_pid, 1);
298 *retval = p->p_pid;
299 return (0);
300 }
301}
302
303/*
304 * set process group (setpgid/old setpgrp)
305 *
306 * caller does setpgid(targpid, targpgid)
307 *
308 * pid must be caller or child of caller (ESRCH)
309 * if a child
310 * pid must be in same session (EPERM)
311 * pid can't have done an exec (EACCES)
91447636 312 * ig pgid is -ve return EINVAL (as per SUV spec)
1c79356b
A
313 * if pgid != pid
314 * there must exist some pid in same session having pgid (EPERM)
315 * pid must not be session leader (EPERM)
316 */
1c79356b 317/* ARGSUSED */
91447636
A
318int
319setpgid(struct proc *curp, register struct setpgid_args *uap, __unused register_t *retval)
1c79356b
A
320{
321 register struct proc *targp; /* target process */
322 register struct pgrp *pgrp; /* target pgrp */
323
324 if (uap->pid != 0 && uap->pid != curp->p_pid) {
325 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
326 return (ESRCH);
327 if (targp->p_session != curp->p_session)
328 return (EPERM);
329 if (targp->p_flag & P_EXEC)
330 return (EACCES);
331 } else
332 targp = curp;
333 if (SESS_LEADER(targp))
334 return (EPERM);
91447636
A
335 if (uap->pgid < 0)
336 return(EINVAL);
1c79356b
A
337 if (uap->pgid == 0)
338 uap->pgid = targp->p_pid;
339 else if (uap->pgid != targp->p_pid)
340 if ((pgrp = pgfind(uap->pgid)) == 0 ||
55e303ae 341 pgrp->pg_session != curp->p_session)
1c79356b
A
342 return (EPERM);
343 return (enterpgrp(targp, uap->pgid, 0));
344}
345
91447636
A
346int
347issetugid(struct proc *p, __unused struct issetugid_args *uap, register_t *retval)
0b4e3aa0
A
348{
349 /*
350 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
351 * we use P_SUGID because we consider changing the owners as
352 * "tainting" as well.
353 * This is significant for procs that start as root and "become"
354 * a user without an exec - programs cannot know *everything*
355 * that libc *might* have put in their data segment.
356 */
357
358 *retval = (p->p_flag & P_SUGID) ? 1 : 0;
359 return (0);
360}
361
1c79356b 362/* ARGSUSED */
91447636
A
363int
364setuid(struct proc *p, struct setuid_args *uap, __unused register_t *retval)
1c79356b 365{
1c79356b
A
366 register uid_t uid;
367 int error;
91447636 368 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
369
370 uid = uap->uid;
55e303ae 371 AUDIT_ARG(uid, uid, 0, 0, 0);
91447636
A
372 if (uid != p->p_ucred->cr_ruid &&
373 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
374 return (error);
375 /*
376 * Everything's okay, do it.
377 * Transfer proc count to new user.
378 * Copy credentials so other references do not see our changes.
379 */
9bccf70c
A
380
381 /* prepare app access profile files */
382 prepare_profile_database(uap->uid);
91447636 383 (void)chgproccnt(kauth_getruid(), -1);
1c79356b 384 (void)chgproccnt(uid, 1);
91447636
A
385
386 /* get current credential and take a reference while we muck with it */
387 for (;;) {
388 my_cred = kauth_cred_proc_ref(p);
389
390 /*
391 * set the credential with new info. If there is no change we get back
392 * the same credential we passed in.
393 */
394 my_new_cred = kauth_cred_setuid(my_cred, uid);
395 if (my_cred != my_new_cred) {
396 proc_lock(p);
397 /* need to protect for a race where another thread also changed
398 * the credential after we took our reference. If p_ucred has
399 * changed then we should restart this again with the new cred.
400 */
401 if (p->p_ucred != my_cred) {
402 proc_unlock(p);
403 kauth_cred_rele(my_cred);
404 kauth_cred_rele(my_new_cred);
405 /* try again */
406 continue;
407 }
408 p->p_ucred = my_new_cred;
409 p->p_flag |= P_SUGID;
410 proc_unlock(p);
411 }
412 /* drop our extra reference */
413 kauth_cred_rele(my_cred);
414 break;
415 }
416
1c79356b 417 set_security_token(p);
1c79356b
A
418 return (0);
419}
420
1c79356b 421/* ARGSUSED */
91447636
A
422int
423seteuid(struct proc *p, struct seteuid_args *uap, __unused register_t *retval)
1c79356b 424{
1c79356b
A
425 register uid_t euid;
426 int error;
91447636 427 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
428
429 euid = uap->euid;
55e303ae 430 AUDIT_ARG(uid, 0, euid, 0, 0);
91447636
A
431 if (euid != p->p_ucred->cr_ruid && euid != p->p_ucred->cr_svuid &&
432 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
433 return (error);
434 /*
435 * Everything's okay, do it. Copy credentials so other references do
91447636
A
436 * not see our changes. get current credential and take a reference
437 * while we muck with it
1c79356b 438 */
91447636
A
439 for (;;) {
440 my_cred = kauth_cred_proc_ref(p);
441
442 /*
443 * set the credential with new info. If there is no change we get back
444 * the same credential we passed in.
445 */
446 my_new_cred = kauth_cred_seteuid(p->p_ucred, euid);
447
448 if (my_cred != my_new_cred) {
449 proc_lock(p);
450 /* need to protect for a race where another thread also changed
451 * the credential after we took our reference. If p_ucred has
452 * changed then we should restart this again with the new cred.
453 */
454 if (p->p_ucred != my_cred) {
455 proc_unlock(p);
456 kauth_cred_rele(my_cred);
457 kauth_cred_rele(my_new_cred);
458 /* try again */
459 continue;
460 }
461 p->p_ucred = my_new_cred;
462 p->p_flag |= P_SUGID;
463 proc_unlock(p);
464 }
465 /* drop our extra reference */
466 kauth_cred_rele(my_cred);
467 break;
468 }
469
1c79356b 470 set_security_token(p);
1c79356b
A
471 return (0);
472}
473
1c79356b 474/* ARGSUSED */
91447636
A
475int
476setgid(struct proc *p, struct setgid_args *uap, __unused register_t *retval)
1c79356b 477{
1c79356b
A
478 register gid_t gid;
479 int error;
91447636 480 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
481
482 gid = uap->gid;
55e303ae 483 AUDIT_ARG(gid, gid, 0, 0, 0);
91447636 484 if (gid != p->p_ucred->cr_rgid && (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 485 return (error);
91447636
A
486
487 /* get current credential and take a reference while we muck with it */
488 for (;;) {
489 my_cred = kauth_cred_proc_ref(p);
490
491 /*
492 * set the credential with new info. If there is no change we get back
493 * the same credential we passed in.
494 */
495 my_new_cred = kauth_cred_setgid(p->p_ucred, gid);
496 if (my_cred != my_new_cred) {
497 proc_lock(p);
498 /* need to protect for a race where another thread also changed
499 * the credential after we took our reference. If p_ucred has
500 * changed then we should restart this again with the new cred.
501 */
502 if (p->p_ucred != my_cred) {
503 proc_unlock(p);
504 kauth_cred_rele(my_cred);
505 kauth_cred_rele(my_new_cred);
506 /* try again */
507 continue;
508 }
509 p->p_ucred = my_new_cred;
510 p->p_flag |= P_SUGID;
511 proc_unlock(p);
512 }
513 /* drop our extra reference */
514 kauth_cred_rele(my_cred);
515 break;
516 }
517
1c79356b 518 set_security_token(p);
1c79356b
A
519 return (0);
520}
521
1c79356b 522/* ARGSUSED */
91447636
A
523int
524setegid(struct proc *p, struct setegid_args *uap, __unused register_t *retval)
1c79356b 525{
1c79356b
A
526 register gid_t egid;
527 int error;
91447636 528 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
529
530 egid = uap->egid;
55e303ae 531 AUDIT_ARG(gid, 0, egid, 0, 0);
91447636
A
532 if (egid != p->p_ucred->cr_rgid && egid != p->p_ucred->cr_svgid &&
533 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 534 return (error);
91447636
A
535
536 /* get current credential and take a reference while we muck with it */
537 for (;;) {
538 my_cred = kauth_cred_proc_ref(p);
539
540 /*
541 * set the credential with new info. If there is no change we get back
542 * the same credential we passed in.
543 */
544 my_new_cred = kauth_cred_setegid(p->p_ucred, egid);
545 if (my_cred != my_new_cred) {
546 proc_lock(p);
547 /* need to protect for a race where another thread also changed
548 * the credential after we took our reference. If p_ucred has
549 * changed then we should restart this again with the new cred.
550 */
551 if (p->p_ucred != my_cred) {
552 proc_unlock(p);
553 kauth_cred_rele(my_cred);
554 kauth_cred_rele(my_new_cred);
555 /* try again */
556 continue;
557 }
558 p->p_ucred = my_new_cred;
559 p->p_flag |= P_SUGID;
560 proc_unlock(p);
561 }
562 /* drop our extra reference */
563 kauth_cred_rele(my_cred);
564 break;
565 }
566
1c79356b 567 set_security_token(p);
1c79356b
A
568 return (0);
569}
570
91447636
A
571/*
572 * Set the per-thread override identity. The first parameter can be the
573 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
574 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
575 * means "revert to the per process credential"; otherwise, if permitted,
576 * it changes the effective, real, and saved UIDs and GIDs for the current
577 * thread to the requested UID and single GID, and clears all other GIDs.
578 */
579int
580settid(struct proc *p, struct settid_args *uap, __unused register_t *retval)
581{
582 kauth_cred_t uc;
583 struct uthread *uthread = get_bsdthread_info(current_thread());
584 register uid_t uid;
585 register gid_t gid;
586
587 uid = uap->uid;
588 gid = uap->gid;
589 AUDIT_ARG(uid, uid, gid, gid, 0);
590
591 if (suser(p->p_ucred, &p->p_acflag) != 0) {
592 return (EPERM);
593 }
594
595 if (uid == KAUTH_UID_NONE) {
596
597 /* must already be assuming another identity in order to revert back */
598 if ((uthread->uu_flag & UT_SETUID) == 0)
599 return (EPERM);
600
601 /* revert to delayed binding of process credential */
602 uc = kauth_cred_proc_ref(p);
603 kauth_cred_rele(uthread->uu_ucred);
604 uthread->uu_ucred = uc;
605 uthread->uu_flag &= ~UT_SETUID;
606 } else {
607 kauth_cred_t my_cred, my_new_cred;
608
609 /* cannot already be assuming another identity */
610 if ((uthread->uu_flag & UT_SETUID) != 0) {
611 return (EPERM);
612 }
613
614 /*
615 * get a new credential instance from the old if this one changes else
616 * kauth_cred_setuidgid returns the same credential. we take an extra
617 * reference on the current credential while we muck wit it here.
618 */
619 kauth_cred_ref(uthread->uu_ucred);
620 my_cred = uthread->uu_ucred;
621 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
622 if (my_cred != my_new_cred)
623 uthread->uu_ucred = my_new_cred;
624 uthread->uu_flag |= UT_SETUID;
625
626 /* drop our extra reference */
627 kauth_cred_rele(my_cred);
628 }
629 /*
630 * XXX should potentially set per thread security token (there is
631 * XXX none).
632 * XXX it is unclear whether P_SUGID should be st at this point;
633 * XXX in theory, it is being deprecated.
634 */
635 return (0);
636}
637
638/*
639 * Set the per-thread override identity. Use this system call for a thread to
640 * assume the identity of another process or to revert back to normal identity
641 * of the current process.
642 * When the "assume" argument is non zero the current thread will assume the
643 * identity of the process represented by the pid argument.
644 * When the assume argument is zero we revert back to our normal identity.
645 */
646int
647settid_with_pid(struct proc *p, struct settid_with_pid_args *uap, __unused register_t *retval)
648{
649 proc_t target_proc;
650 struct uthread *uthread = get_bsdthread_info(current_thread());
651 kauth_cred_t my_cred, my_target_cred, my_new_cred;
652
653 AUDIT_ARG(pid, uap->pid);
654 AUDIT_ARG(value, uap->assume);
655
656 if (suser(p->p_ucred, &p->p_acflag) != 0) {
657 return (EPERM);
658 }
659
660 /*
661 * XXX should potentially set per thread security token (there is
662 * XXX none).
663 * XXX it is unclear whether P_SUGID should be st at this point;
664 * XXX in theory, it is being deprecated.
665 */
666
667 /*
668 * assume argument tells us to assume the identity of the process with the
669 * id passed in the pid argument.
670 */
671 if (uap->assume != 0) {
672 /* can't do this if we have already assumed an identity */
673 if ((uthread->uu_flag & UT_SETUID) != 0)
674 return (EPERM);
675
676 target_proc = pfind(uap->pid);
677 /* can't assume the identity of the kernel process */
678 if (target_proc == NULL || target_proc == kernproc) {
679 return (ESRCH);
680 }
681
682 /*
683 * take a reference on the credential used in our target process then use
684 * it as the identity for our current thread.
685 */
686 kauth_cred_ref(uthread->uu_ucred);
687 my_cred = uthread->uu_ucred;
688 my_target_cred = kauth_cred_proc_ref(target_proc);
689 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
690 if (my_cred != my_new_cred)
691 uthread->uu_ucred = my_new_cred;
692
693 uthread->uu_flag |= UT_SETUID;
694
695 /* drop our extra references */
696 kauth_cred_rele(my_cred);
697 kauth_cred_rele(my_target_cred);
698
699 return (0);
700 }
701
702 /* we are reverting back to normal mode of operation where delayed binding
703 * of the process credential sets the credential in the thread (uu_ucred)
704 */
705 if ((uthread->uu_flag & UT_SETUID) == 0)
706 return (EPERM);
707
708 /* revert to delayed binding of process credential */
709 my_new_cred = kauth_cred_proc_ref(p);
710 kauth_cred_rele(uthread->uu_ucred);
711 uthread->uu_ucred = my_new_cred;
712 uthread->uu_flag &= ~UT_SETUID;
713
714 return (0);
715}
1c79356b
A
716
717/* ARGSUSED */
91447636
A
718static int
719setgroups1(struct proc *p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused register_t *retval)
1c79356b 720{
1c79356b 721 register u_int ngrp;
91447636
A
722 gid_t newgroups[NGROUPS] = { 0 };
723 int error;
724 kauth_cred_t my_cred, my_new_cred;
1c79356b 725
91447636 726 if ((error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 727 return (error);
91447636 728 ngrp = gidsetsize;
55e303ae 729 if (ngrp > NGROUPS)
1c79356b 730 return (EINVAL);
91447636 731
55e303ae
A
732 if ( ngrp < 1 ) {
733 ngrp = 1;
734 }
735 else {
91447636
A
736 error = copyin(gidset,
737 (caddr_t)newgroups, ngrp * sizeof(gid_t));
55e303ae 738 if (error) {
55e303ae
A
739 return (error);
740 }
1c79356b 741 }
91447636
A
742
743 /* get current credential and take a reference while we muck with it */
744 for (;;) {
745 my_cred = kauth_cred_proc_ref(p);
746
747 /*
748 * set the credential with new info. If there is no change we get back
749 * the same credential we passed in.
750 */
751 my_new_cred = kauth_cred_setgroups(p->p_ucred, &newgroups[0], ngrp, gmuid);
752 if (my_cred != my_new_cred) {
753 proc_lock(p);
754 /* need to protect for a race where another thread also changed
755 * the credential after we took our reference. If p_ucred has
756 * changed then we should restart this again with the new cred.
757 */
758 if (p->p_ucred != my_cred) {
759 proc_unlock(p);
760 kauth_cred_rele(my_cred);
761 kauth_cred_rele(my_new_cred);
762 /* try again */
763 continue;
764 }
765 p->p_ucred = my_new_cred;
766 p->p_flag |= P_SUGID;
767 proc_unlock(p);
768 }
769 /* drop our extra reference */
770 kauth_cred_rele(my_cred);
771 break;
772 }
773
774 AUDIT_ARG(groupset, p->p_ucred->cr_groups, ngrp);
1c79356b 775 set_security_token(p);
91447636 776
1c79356b
A
777 return (0);
778}
779
91447636
A
780int
781initgroups(struct proc *p, struct initgroups_args *uap, __unused register_t *retval)
1c79356b 782{
91447636
A
783 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
784}
1c79356b 785
91447636
A
786int
787setgroups(struct proc *p, struct setgroups_args *uap, __unused register_t *retval)
788{
789 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1c79356b
A
790}
791
91447636
A
792/*
793 * Set the per-thread/per-process supplementary groups list.
794 */
795#warning XXX implement
796int
797setsgroups(__unused struct proc *p, __unused struct setsgroups_args *uap, __unused register_t *retval)
1c79356b 798{
91447636
A
799 return(ENOTSUP);
800}
1c79356b 801
91447636
A
802/*
803 * Set the per-thread/per-process whiteout groups list.
804 */
805#warning XXX implement
806int
807setwgroups(__unused struct proc *p, __unused struct setwgroups_args *uap, __unused register_t *retval)
808{
809 return(ENOTSUP);
1c79356b 810}
1c79356b
A
811
812/*
813 * Check if gid is a member of the group set.
91447636
A
814 *
815 * XXX This interface is going away
1c79356b 816 */
91447636
A
817int
818groupmember(gid_t gid, kauth_cred_t cred)
1c79356b 819{
91447636 820 int is_member;
1c79356b 821
91447636
A
822 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
823 return (1);
1c79356b
A
824 return (0);
825}
826
827/*
828 * Test whether the specified credentials imply "super-user"
829 * privilege; if so, and we have accounting info, set the flag
830 * indicating use of super-powers.
831 * Returns 0 or error.
91447636
A
832 *
833 * XXX This interface is going away
1c79356b 834 */
91447636
A
835int
836suser(kauth_cred_t cred, u_short *acflag)
1c79356b
A
837{
838#if DIAGNOSTIC
839 if (cred == NOCRED || cred == FSCRED)
840 panic("suser");
841#endif
91447636 842 if (kauth_cred_getuid(cred) == 0) {
1c79356b
A
843 if (acflag)
844 *acflag |= ASU;
845 return (0);
846 }
847 return (EPERM);
848}
849
850int
851is_suser(void)
852{
853 struct proc *p = current_proc();
854
855 if (!p)
856 return (0);
857
858 return (suser(p->p_ucred, &p->p_acflag) == 0);
859}
860
861int
862is_suser1(void)
863{
864 struct proc *p = current_proc();
865
866 if (!p)
867 return (0);
868
869 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
91447636 870 p->p_ucred->cr_ruid == 0 || p->p_ucred->cr_svuid == 0);
55e303ae
A
871}
872
1c79356b
A
873/*
874 * Get login name, if available.
875 */
1c79356b 876/* ARGSUSED */
91447636
A
877int
878getlogin(struct proc *p, struct getlogin_args *uap, __unused register_t *retval)
1c79356b
A
879{
880
881 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
882 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
883 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
91447636 884 uap->namebuf, uap->namelen));
1c79356b
A
885}
886
887/*
888 * Set login name.
889 */
1c79356b 890/* ARGSUSED */
91447636
A
891int
892setlogin(struct proc *p, struct setlogin_args *uap, __unused register_t *retval)
1c79356b
A
893{
894 int error;
895 int dummy=0;
896
91447636 897 if ((error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
898 return (error);
899
91447636 900 error = copyinstr(uap->namebuf,
1c79356b
A
901 (caddr_t) p->p_pgrp->pg_session->s_login,
902 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
91447636 903 if (!error)
e5568f75
A
904 AUDIT_ARG(text, p->p_pgrp->pg_session->s_login);
905 else if (error == ENAMETOOLONG)
1c79356b
A
906 error = EINVAL;
907 return (error);
908}
909
910
911/* Set the secrity token of the task with current euid and eguid */
91447636
A
912/*
913 * XXX This needs to change to give the task a reference and/or an opaque
914 * XXX identifier.
915 */
916int
1c79356b
A
917set_security_token(struct proc * p)
918{
919 security_token_t sec_token;
55e303ae 920 audit_token_t audit_token;
1c79356b 921
91447636
A
922 /*
923 * Don't allow a vfork child to override the parent's token settings
924 * (since they share a task). Instead, the child will just have to
925 * suffer along using the parent's token until the exec(). It's all
926 * undefined behavior anyway, right?
927 */
928 if (p->task == current_task()) {
929 uthread_t uthread;
930 uthread = (uthread_t)get_bsdthread_info(current_thread());
931 if (uthread->uu_flag & UT_VFORK)
932 return (1);
933 }
934
935 /* XXX mach_init doesn't have a p_ucred when it calls this function */
936 if (p->p_ucred != NOCRED && p->p_ucred != FSCRED) {
937 sec_token.val[0] = kauth_cred_getuid(p->p_ucred);
938 sec_token.val[1] = p->p_ucred->cr_gid;
939 } else {
940 sec_token.val[0] = 0;
941 sec_token.val[1] = 0;
942 }
e5568f75
A
943
944 /*
945 * The current layout of the Mach audit token explicitly
946 * adds these fields. But nobody should rely on such
947 * a literal representation. Instead, the BSM library
948 * provides a function to convert an audit token into
949 * a BSM subject. Use of that mechanism will isolate
950 * the user of the trailer from future representation
951 * changes.
952 */
91447636 953 audit_token.val[0] = p->p_ucred->cr_au.ai_auid;
e5568f75 954 audit_token.val[1] = p->p_ucred->cr_uid;
91447636
A
955 audit_token.val[2] = p->p_ucred->cr_gid;
956 audit_token.val[3] = p->p_ucred->cr_ruid;
957 audit_token.val[4] = p->p_ucred->cr_rgid;
e5568f75 958 audit_token.val[5] = p->p_pid;
91447636
A
959 audit_token.val[6] = p->p_ucred->cr_au.ai_asid;
960 audit_token.val[7] = p->p_ucred->cr_au.ai_termid.port;
e5568f75 961
91447636 962 return (host_security_set_task_token(host_security_self(),
1c79356b
A
963 p->task,
964 sec_token,
55e303ae 965 audit_token,
1c79356b 966 (sec_token.val[0]) ?
55e303ae 967 HOST_PRIV_NULL :
91447636 968 host_priv_self()) != KERN_SUCCESS);
1c79356b 969}
55e303ae
A
970
971
972/*
91447636 973 * Fill in a struct xucred based on a kauth_cred_t.
55e303ae
A
974 */
975__private_extern__
976void
91447636 977cru2x(kauth_cred_t cr, struct xucred *xcr)
55e303ae
A
978{
979
980 bzero(xcr, sizeof(*xcr));
981 xcr->cr_version = XUCRED_VERSION;
91447636 982 xcr->cr_uid = kauth_cred_getuid(cr);
55e303ae
A
983 xcr->cr_ngroups = cr->cr_ngroups;
984 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
985}