]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-792.17.14.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_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_rele(cred);
255 return (0);
256 }
257 if (ngrp < cred->cr_ngroups) {
258 kauth_cred_rele(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_rele(cred);
266 return (error);
267 }
268 kauth_cred_rele(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 we get back
398 * the same credential we passed in.
399 */
400 my_new_cred = kauth_cred_setuid(my_cred, uid);
401 if (my_cred != my_new_cred) {
402 proc_lock(p);
403 /* need to protect for a race where another thread also changed
404 * the credential after we took our reference. If p_ucred has
405 * changed then we should restart this again with the new cred.
406 */
407 if (p->p_ucred != my_cred) {
408 proc_unlock(p);
409 kauth_cred_rele(my_cred);
410 kauth_cred_rele(my_new_cred);
411 /* try again */
412 continue;
413 }
414 p->p_ucred = my_new_cred;
415 p->p_flag |= P_SUGID;
416 proc_unlock(p);
417 }
418 /* drop our extra reference */
419 kauth_cred_rele(my_cred);
420 break;
421 }
422
423 set_security_token(p);
424 return (0);
425 }
426
427 /* ARGSUSED */
428 int
429 seteuid(struct proc *p, struct seteuid_args *uap, __unused register_t *retval)
430 {
431 register uid_t euid;
432 int error;
433 kauth_cred_t my_cred, my_new_cred;
434
435 euid = uap->euid;
436 AUDIT_ARG(uid, 0, euid, 0, 0);
437 if (euid != p->p_ucred->cr_ruid && euid != p->p_ucred->cr_svuid &&
438 (error = suser(p->p_ucred, &p->p_acflag)))
439 return (error);
440 /*
441 * Everything's okay, do it. Copy credentials so other references do
442 * not see our changes. get current credential and take a reference
443 * while we muck with it
444 */
445 for (;;) {
446 my_cred = kauth_cred_proc_ref(p);
447
448 /*
449 * set the credential with new info. If there is no change we get back
450 * the same credential we passed in.
451 */
452 my_new_cred = kauth_cred_seteuid(p->p_ucred, euid);
453
454 if (my_cred != my_new_cred) {
455 proc_lock(p);
456 /* need to protect for a race where another thread also changed
457 * the credential after we took our reference. If p_ucred has
458 * changed then we should restart this again with the new cred.
459 */
460 if (p->p_ucred != my_cred) {
461 proc_unlock(p);
462 kauth_cred_rele(my_cred);
463 kauth_cred_rele(my_new_cred);
464 /* try again */
465 continue;
466 }
467 p->p_ucred = my_new_cred;
468 p->p_flag |= P_SUGID;
469 proc_unlock(p);
470 }
471 /* drop our extra reference */
472 kauth_cred_rele(my_cred);
473 break;
474 }
475
476 set_security_token(p);
477 return (0);
478 }
479
480 /* ARGSUSED */
481 int
482 setgid(struct proc *p, struct setgid_args *uap, __unused register_t *retval)
483 {
484 register gid_t gid;
485 int error;
486 kauth_cred_t my_cred, my_new_cred;
487
488 gid = uap->gid;
489 AUDIT_ARG(gid, gid, 0, 0, 0);
490 if (gid != p->p_ucred->cr_rgid && (error = suser(p->p_ucred, &p->p_acflag)))
491 return (error);
492
493 /* get current credential and take a reference while we muck with it */
494 for (;;) {
495 my_cred = kauth_cred_proc_ref(p);
496
497 /*
498 * set the credential with new info. If there is no change we get back
499 * the same credential we passed in.
500 */
501 my_new_cred = kauth_cred_setgid(p->p_ucred, gid);
502 if (my_cred != my_new_cred) {
503 proc_lock(p);
504 /* need to protect for a race where another thread also changed
505 * the credential after we took our reference. If p_ucred has
506 * changed then we should restart this again with the new cred.
507 */
508 if (p->p_ucred != my_cred) {
509 proc_unlock(p);
510 kauth_cred_rele(my_cred);
511 kauth_cred_rele(my_new_cred);
512 /* try again */
513 continue;
514 }
515 p->p_ucred = my_new_cred;
516 p->p_flag |= P_SUGID;
517 proc_unlock(p);
518 }
519 /* drop our extra reference */
520 kauth_cred_rele(my_cred);
521 break;
522 }
523
524 set_security_token(p);
525 return (0);
526 }
527
528 /* ARGSUSED */
529 int
530 setegid(struct proc *p, struct setegid_args *uap, __unused register_t *retval)
531 {
532 register gid_t egid;
533 int error;
534 kauth_cred_t my_cred, my_new_cred;
535
536 egid = uap->egid;
537 AUDIT_ARG(gid, 0, egid, 0, 0);
538 if (egid != p->p_ucred->cr_rgid && egid != p->p_ucred->cr_svgid &&
539 (error = suser(p->p_ucred, &p->p_acflag)))
540 return (error);
541
542 /* get current credential and take a reference while we muck with it */
543 for (;;) {
544 my_cred = kauth_cred_proc_ref(p);
545
546 /*
547 * set the credential with new info. If there is no change we get back
548 * the same credential we passed in.
549 */
550 my_new_cred = kauth_cred_setegid(p->p_ucred, egid);
551 if (my_cred != my_new_cred) {
552 proc_lock(p);
553 /* need to protect for a race where another thread also changed
554 * the credential after we took our reference. If p_ucred has
555 * changed then we should restart this again with the new cred.
556 */
557 if (p->p_ucred != my_cred) {
558 proc_unlock(p);
559 kauth_cred_rele(my_cred);
560 kauth_cred_rele(my_new_cred);
561 /* try again */
562 continue;
563 }
564 p->p_ucred = my_new_cred;
565 p->p_flag |= P_SUGID;
566 proc_unlock(p);
567 }
568 /* drop our extra reference */
569 kauth_cred_rele(my_cred);
570 break;
571 }
572
573 set_security_token(p);
574 return (0);
575 }
576
577 /*
578 * Set the per-thread override identity. The first parameter can be the
579 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
580 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
581 * means "revert to the per process credential"; otherwise, if permitted,
582 * it changes the effective, real, and saved UIDs and GIDs for the current
583 * thread to the requested UID and single GID, and clears all other GIDs.
584 */
585 int
586 settid(struct proc *p, struct settid_args *uap, __unused register_t *retval)
587 {
588 kauth_cred_t uc;
589 struct uthread *uthread = get_bsdthread_info(current_thread());
590 register uid_t uid;
591 register gid_t gid;
592
593 uid = uap->uid;
594 gid = uap->gid;
595 AUDIT_ARG(uid, uid, gid, gid, 0);
596
597 if (suser(p->p_ucred, &p->p_acflag) != 0) {
598 return (EPERM);
599 }
600
601 if (uid == KAUTH_UID_NONE) {
602
603 /* must already be assuming another identity in order to revert back */
604 if ((uthread->uu_flag & UT_SETUID) == 0)
605 return (EPERM);
606
607 /* revert to delayed binding of process credential */
608 uc = kauth_cred_proc_ref(p);
609 kauth_cred_rele(uthread->uu_ucred);
610 uthread->uu_ucred = uc;
611 uthread->uu_flag &= ~UT_SETUID;
612 } else {
613 kauth_cred_t my_cred, my_new_cred;
614
615 /* cannot already be assuming another identity */
616 if ((uthread->uu_flag & UT_SETUID) != 0) {
617 return (EPERM);
618 }
619
620 /*
621 * get a new credential instance from the old if this one changes else
622 * kauth_cred_setuidgid returns the same credential. we take an extra
623 * reference on the current credential while we muck wit it here.
624 */
625 kauth_cred_ref(uthread->uu_ucred);
626 my_cred = uthread->uu_ucred;
627 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
628 if (my_cred != my_new_cred)
629 uthread->uu_ucred = my_new_cred;
630 uthread->uu_flag |= UT_SETUID;
631
632 /* drop our extra reference */
633 kauth_cred_rele(my_cred);
634 }
635 /*
636 * XXX should potentially set per thread security token (there is
637 * XXX none).
638 * XXX it is unclear whether P_SUGID should be st at this point;
639 * XXX in theory, it is being deprecated.
640 */
641 return (0);
642 }
643
644 /*
645 * Set the per-thread override identity. Use this system call for a thread to
646 * assume the identity of another process or to revert back to normal identity
647 * of the current process.
648 * When the "assume" argument is non zero the current thread will assume the
649 * identity of the process represented by the pid argument.
650 * When the assume argument is zero we revert back to our normal identity.
651 */
652 int
653 settid_with_pid(struct proc *p, struct settid_with_pid_args *uap, __unused register_t *retval)
654 {
655 proc_t target_proc;
656 struct uthread *uthread = get_bsdthread_info(current_thread());
657 kauth_cred_t my_cred, my_target_cred, my_new_cred;
658
659 AUDIT_ARG(pid, uap->pid);
660 AUDIT_ARG(value, uap->assume);
661
662 if (suser(p->p_ucred, &p->p_acflag) != 0) {
663 return (EPERM);
664 }
665
666 /*
667 * XXX should potentially set per thread security token (there is
668 * XXX none).
669 * XXX it is unclear whether P_SUGID should be st at this point;
670 * XXX in theory, it is being deprecated.
671 */
672
673 /*
674 * assume argument tells us to assume the identity of the process with the
675 * id passed in the pid argument.
676 */
677 if (uap->assume != 0) {
678 /* can't do this if we have already assumed an identity */
679 if ((uthread->uu_flag & UT_SETUID) != 0)
680 return (EPERM);
681
682 target_proc = pfind(uap->pid);
683 /* can't assume the identity of the kernel process */
684 if (target_proc == NULL || target_proc == kernproc) {
685 return (ESRCH);
686 }
687
688 /*
689 * take a reference on the credential used in our target process then use
690 * it as the identity for our current thread.
691 */
692 kauth_cred_ref(uthread->uu_ucred);
693 my_cred = uthread->uu_ucred;
694 my_target_cred = kauth_cred_proc_ref(target_proc);
695 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
696 if (my_cred != my_new_cred)
697 uthread->uu_ucred = my_new_cred;
698
699 uthread->uu_flag |= UT_SETUID;
700
701 /* drop our extra references */
702 kauth_cred_rele(my_cred);
703 kauth_cred_rele(my_target_cred);
704
705 return (0);
706 }
707
708 /* we are reverting back to normal mode of operation where delayed binding
709 * of the process credential sets the credential in the thread (uu_ucred)
710 */
711 if ((uthread->uu_flag & UT_SETUID) == 0)
712 return (EPERM);
713
714 /* revert to delayed binding of process credential */
715 my_new_cred = kauth_cred_proc_ref(p);
716 kauth_cred_rele(uthread->uu_ucred);
717 uthread->uu_ucred = my_new_cred;
718 uthread->uu_flag &= ~UT_SETUID;
719
720 return (0);
721 }
722
723 /* ARGSUSED */
724 static int
725 setgroups1(struct proc *p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused register_t *retval)
726 {
727 register u_int ngrp;
728 gid_t newgroups[NGROUPS] = { 0 };
729 int error;
730 kauth_cred_t my_cred, my_new_cred;
731 struct uthread *uthread = get_bsdthread_info(current_thread());
732
733 if ((error = suser(p->p_ucred, &p->p_acflag)))
734 return (error);
735 ngrp = gidsetsize;
736 if (ngrp > NGROUPS)
737 return (EINVAL);
738
739 if ( ngrp < 1 ) {
740 ngrp = 1;
741 }
742 else {
743 error = copyin(gidset,
744 (caddr_t)newgroups, ngrp * sizeof(gid_t));
745 if (error) {
746 return (error);
747 }
748 }
749
750 if ((uthread->uu_flag & UT_SETUID) != 0) {
751 /*
752 * If this thread is under an assumed identity, set the
753 * supplementary grouplist on the thread credential instead
754 * of the process one. If we were the only reference holder,
755 * the credential is updated in place, otherwise, our reference
756 * is dropped and we get back a different cred with a reference
757 * already held on it. Because this is per-thread, we don't
758 * need the referencing/locking/retry required for per-process.
759 *
760 * Hack: this opts into memberd to avoid needing to use a per
761 * thread credential initgroups() instead of setgroups() in
762 * AFP server to address <rdar://4561060>
763 */
764 my_cred = uthread->uu_ucred;
765 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, my_cred->cr_gmuid);
766 } else {
767
768 /*
769 * get current credential and take a reference while we muck
770 * with it
771 */
772 for (;;) {
773 my_cred = kauth_cred_proc_ref(p);
774
775 /*
776 * set the credential with new info. If there is no
777 * change we get back the same credential we passed in.
778 */
779 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
780 if (my_cred != my_new_cred) {
781 proc_lock(p);
782 /*
783 * need to protect for a race where another
784 * thread also changed the credential after we
785 * took our reference. If p_ucred has
786 * changed then we should restart this again
787 * with the new cred.
788 */
789 if (p->p_ucred != my_cred) {
790 proc_unlock(p);
791 kauth_cred_rele(my_cred);
792 kauth_cred_rele(my_new_cred);
793 /* try again */
794 continue;
795 }
796 p->p_ucred = my_new_cred;
797 p->p_flag |= P_SUGID;
798 proc_unlock(p);
799 }
800 /* drop our extra reference */
801 kauth_cred_rele(my_cred);
802 break;
803 }
804
805 AUDIT_ARG(groupset, p->p_ucred->cr_groups, ngrp);
806 set_security_token(p);
807 }
808
809 return (0);
810 }
811
812 int
813 initgroups(struct proc *p, struct initgroups_args *uap, __unused register_t *retval)
814 {
815 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
816 }
817
818 int
819 setgroups(struct proc *p, struct setgroups_args *uap, __unused register_t *retval)
820 {
821 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
822 }
823
824 /*
825 * Set the per-thread/per-process supplementary groups list.
826 */
827 #warning XXX implement
828 int
829 setsgroups(__unused struct proc *p, __unused struct setsgroups_args *uap, __unused register_t *retval)
830 {
831 return(ENOTSUP);
832 }
833
834 /*
835 * Set the per-thread/per-process whiteout groups list.
836 */
837 #warning XXX implement
838 int
839 setwgroups(__unused struct proc *p, __unused struct setwgroups_args *uap, __unused register_t *retval)
840 {
841 return(ENOTSUP);
842 }
843
844 /*
845 * Check if gid is a member of the group set.
846 *
847 * XXX This interface is going away
848 */
849 int
850 groupmember(gid_t gid, kauth_cred_t cred)
851 {
852 int is_member;
853
854 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
855 return (1);
856 return (0);
857 }
858
859 /*
860 * Test whether the specified credentials imply "super-user"
861 * privilege; if so, and we have accounting info, set the flag
862 * indicating use of super-powers.
863 * Returns 0 or error.
864 *
865 * XXX This interface is going away
866 */
867 int
868 suser(kauth_cred_t cred, u_short *acflag)
869 {
870 #if DIAGNOSTIC
871 if (cred == NOCRED || cred == FSCRED)
872 panic("suser");
873 #endif
874 if (kauth_cred_getuid(cred) == 0) {
875 if (acflag)
876 *acflag |= ASU;
877 return (0);
878 }
879 return (EPERM);
880 }
881
882 int
883 is_suser(void)
884 {
885 struct proc *p = current_proc();
886
887 if (!p)
888 return (0);
889
890 return (suser(p->p_ucred, &p->p_acflag) == 0);
891 }
892
893 int
894 is_suser1(void)
895 {
896 struct proc *p = current_proc();
897
898 if (!p)
899 return (0);
900
901 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
902 p->p_ucred->cr_ruid == 0 || p->p_ucred->cr_svuid == 0);
903 }
904
905 /*
906 * Get login name, if available.
907 */
908 /* ARGSUSED */
909 int
910 getlogin(struct proc *p, struct getlogin_args *uap, __unused register_t *retval)
911 {
912
913 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
914 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
915 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
916 uap->namebuf, uap->namelen));
917 }
918
919 /*
920 * Set login name.
921 */
922 /* ARGSUSED */
923 int
924 setlogin(struct proc *p, struct setlogin_args *uap, __unused register_t *retval)
925 {
926 int error;
927 int dummy=0;
928
929 if ((error = suser(p->p_ucred, &p->p_acflag)))
930 return (error);
931
932 error = copyinstr(uap->namebuf,
933 (caddr_t) p->p_pgrp->pg_session->s_login,
934 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
935 if (!error)
936 AUDIT_ARG(text, p->p_pgrp->pg_session->s_login);
937 else if (error == ENAMETOOLONG)
938 error = EINVAL;
939 return (error);
940 }
941
942
943 /* Set the secrity token of the task with current euid and eguid */
944 /*
945 * XXX This needs to change to give the task a reference and/or an opaque
946 * XXX identifier.
947 */
948 int
949 set_security_token(struct proc * p)
950 {
951 security_token_t sec_token;
952 audit_token_t audit_token;
953
954 /*
955 * Don't allow a vfork child to override the parent's token settings
956 * (since they share a task). Instead, the child will just have to
957 * suffer along using the parent's token until the exec(). It's all
958 * undefined behavior anyway, right?
959 */
960 if (p->task == current_task()) {
961 uthread_t uthread;
962 uthread = (uthread_t)get_bsdthread_info(current_thread());
963 if (uthread->uu_flag & UT_VFORK)
964 return (1);
965 }
966
967 /* XXX mach_init doesn't have a p_ucred when it calls this function */
968 if (p->p_ucred != NOCRED && p->p_ucred != FSCRED) {
969 sec_token.val[0] = kauth_cred_getuid(p->p_ucred);
970 sec_token.val[1] = p->p_ucred->cr_gid;
971 } else {
972 sec_token.val[0] = 0;
973 sec_token.val[1] = 0;
974 }
975
976 /*
977 * The current layout of the Mach audit token explicitly
978 * adds these fields. But nobody should rely on such
979 * a literal representation. Instead, the BSM library
980 * provides a function to convert an audit token into
981 * a BSM subject. Use of that mechanism will isolate
982 * the user of the trailer from future representation
983 * changes.
984 */
985 audit_token.val[0] = p->p_ucred->cr_au.ai_auid;
986 audit_token.val[1] = p->p_ucred->cr_uid;
987 audit_token.val[2] = p->p_ucred->cr_gid;
988 audit_token.val[3] = p->p_ucred->cr_ruid;
989 audit_token.val[4] = p->p_ucred->cr_rgid;
990 audit_token.val[5] = p->p_pid;
991 audit_token.val[6] = p->p_ucred->cr_au.ai_asid;
992 audit_token.val[7] = p->p_ucred->cr_au.ai_termid.port;
993
994 return (host_security_set_task_token(host_security_self(),
995 p->task,
996 sec_token,
997 audit_token,
998 (sec_token.val[0]) ?
999 HOST_PRIV_NULL :
1000 host_priv_self()) != KERN_SUCCESS);
1001 }
1002
1003
1004 /*
1005 * Fill in a struct xucred based on a kauth_cred_t.
1006 */
1007 __private_extern__
1008 void
1009 cru2x(kauth_cred_t cr, struct xucred *xcr)
1010 {
1011
1012 bzero(xcr, sizeof(*xcr));
1013 xcr->cr_version = XUCRED_VERSION;
1014 xcr->cr_uid = kauth_cred_getuid(cr);
1015 xcr->cr_ngroups = cr->cr_ngroups;
1016 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
1017 }