]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-792.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
726 if ((error = suser(p->p_ucred, &p->p_acflag)))
727 return (error);
728 ngrp = gidsetsize;
729 if (ngrp > NGROUPS)
730 return (EINVAL);
731
732 if ( ngrp < 1 ) {
733 ngrp = 1;
734 }
735 else {
736 error = copyin(gidset,
737 (caddr_t)newgroups, ngrp * sizeof(gid_t));
738 if (error) {
739 return (error);
740 }
741 }
742
743 /* get current credential and take a reference while we muck with it */
744 for (;;) {
745 my_cred = kauth_cred_proc_ref(p);
746
747 /*
748 * set the credential with new info. If there is no change we get back
749 * the same credential we passed in.
750 */
751 my_new_cred = kauth_cred_setgroups(p->p_ucred, &newgroups[0], ngrp, gmuid);
752 if (my_cred != my_new_cred) {
753 proc_lock(p);
754 /* need to protect for a race where another thread also changed
755 * the credential after we took our reference. If p_ucred has
756 * changed then we should restart this again with the new cred.
757 */
758 if (p->p_ucred != my_cred) {
759 proc_unlock(p);
760 kauth_cred_rele(my_cred);
761 kauth_cred_rele(my_new_cred);
762 /* try again */
763 continue;
764 }
765 p->p_ucred = my_new_cred;
766 p->p_flag |= P_SUGID;
767 proc_unlock(p);
768 }
769 /* drop our extra reference */
770 kauth_cred_rele(my_cred);
771 break;
772 }
773
774 AUDIT_ARG(groupset, p->p_ucred->cr_groups, ngrp);
775 set_security_token(p);
776
777 return (0);
778 }
779
780 int
781 initgroups(struct proc *p, struct initgroups_args *uap, __unused register_t *retval)
782 {
783 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
784 }
785
786 int
787 setgroups(struct proc *p, struct setgroups_args *uap, __unused register_t *retval)
788 {
789 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
790 }
791
792 /*
793 * Set the per-thread/per-process supplementary groups list.
794 */
795 #warning XXX implement
796 int
797 setsgroups(__unused struct proc *p, __unused struct setsgroups_args *uap, __unused register_t *retval)
798 {
799 return(ENOTSUP);
800 }
801
802 /*
803 * Set the per-thread/per-process whiteout groups list.
804 */
805 #warning XXX implement
806 int
807 setwgroups(__unused struct proc *p, __unused struct setwgroups_args *uap, __unused register_t *retval)
808 {
809 return(ENOTSUP);
810 }
811
812 /*
813 * Check if gid is a member of the group set.
814 *
815 * XXX This interface is going away
816 */
817 int
818 groupmember(gid_t gid, kauth_cred_t cred)
819 {
820 int is_member;
821
822 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
823 return (1);
824 return (0);
825 }
826
827 /*
828 * Test whether the specified credentials imply "super-user"
829 * privilege; if so, and we have accounting info, set the flag
830 * indicating use of super-powers.
831 * Returns 0 or error.
832 *
833 * XXX This interface is going away
834 */
835 int
836 suser(kauth_cred_t cred, u_short *acflag)
837 {
838 #if DIAGNOSTIC
839 if (cred == NOCRED || cred == FSCRED)
840 panic("suser");
841 #endif
842 if (kauth_cred_getuid(cred) == 0) {
843 if (acflag)
844 *acflag |= ASU;
845 return (0);
846 }
847 return (EPERM);
848 }
849
850 int
851 is_suser(void)
852 {
853 struct proc *p = current_proc();
854
855 if (!p)
856 return (0);
857
858 return (suser(p->p_ucred, &p->p_acflag) == 0);
859 }
860
861 int
862 is_suser1(void)
863 {
864 struct proc *p = current_proc();
865
866 if (!p)
867 return (0);
868
869 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
870 p->p_ucred->cr_ruid == 0 || p->p_ucred->cr_svuid == 0);
871 }
872
873 /*
874 * Get login name, if available.
875 */
876 /* ARGSUSED */
877 int
878 getlogin(struct proc *p, struct getlogin_args *uap, __unused register_t *retval)
879 {
880
881 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
882 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
883 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
884 uap->namebuf, uap->namelen));
885 }
886
887 /*
888 * Set login name.
889 */
890 /* ARGSUSED */
891 int
892 setlogin(struct proc *p, struct setlogin_args *uap, __unused register_t *retval)
893 {
894 int error;
895 int dummy=0;
896
897 if ((error = suser(p->p_ucred, &p->p_acflag)))
898 return (error);
899
900 error = copyinstr(uap->namebuf,
901 (caddr_t) p->p_pgrp->pg_session->s_login,
902 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
903 if (!error)
904 AUDIT_ARG(text, p->p_pgrp->pg_session->s_login);
905 else if (error == ENAMETOOLONG)
906 error = EINVAL;
907 return (error);
908 }
909
910
911 /* Set the secrity token of the task with current euid and eguid */
912 /*
913 * XXX This needs to change to give the task a reference and/or an opaque
914 * XXX identifier.
915 */
916 int
917 set_security_token(struct proc * p)
918 {
919 security_token_t sec_token;
920 audit_token_t audit_token;
921
922 /*
923 * Don't allow a vfork child to override the parent's token settings
924 * (since they share a task). Instead, the child will just have to
925 * suffer along using the parent's token until the exec(). It's all
926 * undefined behavior anyway, right?
927 */
928 if (p->task == current_task()) {
929 uthread_t uthread;
930 uthread = (uthread_t)get_bsdthread_info(current_thread());
931 if (uthread->uu_flag & UT_VFORK)
932 return (1);
933 }
934
935 /* XXX mach_init doesn't have a p_ucred when it calls this function */
936 if (p->p_ucred != NOCRED && p->p_ucred != FSCRED) {
937 sec_token.val[0] = kauth_cred_getuid(p->p_ucred);
938 sec_token.val[1] = p->p_ucred->cr_gid;
939 } else {
940 sec_token.val[0] = 0;
941 sec_token.val[1] = 0;
942 }
943
944 /*
945 * The current layout of the Mach audit token explicitly
946 * adds these fields. But nobody should rely on such
947 * a literal representation. Instead, the BSM library
948 * provides a function to convert an audit token into
949 * a BSM subject. Use of that mechanism will isolate
950 * the user of the trailer from future representation
951 * changes.
952 */
953 audit_token.val[0] = p->p_ucred->cr_au.ai_auid;
954 audit_token.val[1] = p->p_ucred->cr_uid;
955 audit_token.val[2] = p->p_ucred->cr_gid;
956 audit_token.val[3] = p->p_ucred->cr_ruid;
957 audit_token.val[4] = p->p_ucred->cr_rgid;
958 audit_token.val[5] = p->p_pid;
959 audit_token.val[6] = p->p_ucred->cr_au.ai_asid;
960 audit_token.val[7] = p->p_ucred->cr_au.ai_termid.port;
961
962 return (host_security_set_task_token(host_security_self(),
963 p->task,
964 sec_token,
965 audit_token,
966 (sec_token.val[0]) ?
967 HOST_PRIV_NULL :
968 host_priv_self()) != KERN_SUCCESS);
969 }
970
971
972 /*
973 * Fill in a struct xucred based on a kauth_cred_t.
974 */
975 __private_extern__
976 void
977 cru2x(kauth_cred_t cr, struct xucred *xcr)
978 {
979
980 bzero(xcr, sizeof(*xcr));
981 xcr->cr_version = XUCRED_VERSION;
982 xcr->cr_uid = kauth_cred_getuid(cr);
983 xcr->cr_ngroups = cr->cr_ngroups;
984 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
985 }