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