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