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