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