]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_prot.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / kern / kern_prot.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
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.
8f6c56a5 11 *
6601e61a
A
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
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
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.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
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>
91447636
A
71#include <sys/proc_internal.h>
72#include <sys/user.h>
73#include <sys/kauth.h>
1c79356b
A
74#include <sys/timeb.h>
75#include <sys/times.h>
76#include <sys/malloc.h>
e5568f75
A
77
78#include <bsm/audit_kernel.h>
1c79356b 79
91447636
A
80#include <sys/mount_internal.h>
81#include <sys/sysproto.h>
1c79356b 82#include <mach/message.h>
9bccf70c
A
83#include <mach/host_security.h>
84
1c79356b
A
85#include <kern/host.h>
86
91447636
A
87int groupmember(gid_t gid, kauth_cred_t cred);
88int is_suser(void);
89int is_suser1(void);
90
91extern int prepare_profile_database(int user);
92
1c79356b
A
93/*
94 * setprivexec: (dis)allow this process to hold
95 * task, thread, or execption ports of processes about to exec.
96 */
1c79356b 97int
91447636 98setprivexec(struct proc *p, struct setprivexec_args *uap, register_t *retval)
1c79356b 99{
e5568f75 100 AUDIT_ARG(value, uap->flag);
1c79356b
A
101 *retval = p->p_debugger;
102 p->p_debugger = (uap->flag != 0);
103 return(0);
104}
105
106/* ARGSUSED */
91447636
A
107int
108getpid(struct proc *p, __unused struct getpid_args *uap, register_t *retval)
1c79356b
A
109{
110
111 *retval = p->p_pid;
1c79356b
A
112 return (0);
113}
114
115/* ARGSUSED */
91447636
A
116int
117getppid(struct proc *p, __unused struct getppid_args *uap, register_t *retval)
1c79356b
A
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 */
91447636
A
125int
126getpgrp(struct proc *p, __unused struct getpgrp_args *uap, register_t *retval)
1c79356b
A
127{
128
129 *retval = p->p_pgrp->pg_id;
130 return (0);
131}
132
9bccf70c 133/* Get an arbitary pid's process group id */
9bccf70c 134int
91447636 135getpgid(struct proc *p, struct getpgid_args *uap, register_t *retval)
9bccf70c
A
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);
145found:
146 *retval = pt->p_pgrp->pg_id;
147 return (0);
148}
149
150/*
151 * Get an arbitary pid's session id.
152 */
9bccf70c
A
153
154int
91447636 155getsid(struct proc *p, struct getsid_args *uap, register_t *retval)
9bccf70c
A
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);
165found:
166 *retval = pt->p_session->s_sid;
167 return (0);
168}
169
1c79356b 170/* ARGSUSED */
91447636
A
171int
172getuid(__unused struct proc *p, __unused struct getuid_args *uap, register_t *retval)
1c79356b
A
173{
174
91447636 175 *retval = kauth_getruid();
1c79356b
A
176 return (0);
177}
178
179/* ARGSUSED */
91447636
A
180int
181geteuid(__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 */
191int
192gettid(__unused struct proc *p, struct gettid_args *uap, register_t *retval)
1c79356b 193{
91447636
A
194 struct uthread *uthread = get_bsdthread_info(current_thread());
195 int error;
1c79356b 196
91447636
A
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;
1c79356b
A
210 return (0);
211}
212
213/* ARGSUSED */
91447636
A
214int
215getgid(__unused struct proc *p, __unused struct getgid_args *uap, register_t *retval)
1c79356b
A
216{
217
91447636 218 *retval = kauth_getrgid();
1c79356b
A
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 */
91447636
A
228int
229getegid(struct proc *p, __unused struct getegid_args *uap, register_t *retval)
1c79356b
A
230{
231
91447636 232 *retval = kauth_getgid();
1c79356b
A
233 return (0);
234}
235
91447636
A
236int
237getgroups(__unused struct proc *p, struct getgroups_args *uap, register_t *retval)
1c79356b 238{
91447636 239 register int ngrp;
1c79356b 240 int error;
91447636
A
241 kauth_cred_t cred;
242
243 /* grab reference while we muck around with the credential */
244 cred = kauth_cred_get_with_ref();
1c79356b
A
245
246 if ((ngrp = uap->gidsetsize) == 0) {
91447636 247 *retval = cred->cr_ngroups;
0c530ab8 248 kauth_cred_unref(&cred);
1c79356b
A
249 return (0);
250 }
91447636 251 if (ngrp < cred->cr_ngroups) {
0c530ab8 252 kauth_cred_unref(&cred);
1c79356b 253 return (EINVAL);
91447636
A
254 }
255 ngrp = cred->cr_ngroups;
256 if ((error = copyout((caddr_t)cred->cr_groups,
257 uap->gidset,
258 ngrp * sizeof(gid_t)))) {
0c530ab8 259 kauth_cred_unref(&cred);
1c79356b
A
260 return (error);
261 }
0c530ab8 262 kauth_cred_unref(&cred);
1c79356b
A
263 *retval = ngrp;
264 return (0);
265}
266
91447636
A
267/*
268 * Return the per-thread/per-process supplementary groups list.
269 */
270#warning XXX implement
271int
272getsgroups(__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
282int
283getwgroups(__unused struct proc *p, __unused struct getwgroups_args *uap, __unused register_t *retval)
284{
285 /* XXX implement */
286 return(ENOTSUP);
287}
288
1c79356b 289/* ARGSUSED */
91447636
A
290int
291setsid(struct proc *p, __unused struct setsid_args *uap, register_t *retval)
1c79356b
A
292{
293
55e303ae 294 if (p->p_pgid == p->p_pid || pgfind(p->p_pid) || p->p_flag & P_INVFORK) {
1c79356b
A
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)
91447636 312 * ig pgid is -ve return EINVAL (as per SUV spec)
1c79356b
A
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 */
1c79356b 317/* ARGSUSED */
91447636
A
318int
319setpgid(struct proc *curp, register struct setpgid_args *uap, __unused register_t *retval)
1c79356b
A
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);
91447636
A
335 if (uap->pgid < 0)
336 return(EINVAL);
1c79356b
A
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 ||
55e303ae 341 pgrp->pg_session != curp->p_session)
1c79356b
A
342 return (EPERM);
343 return (enterpgrp(targp, uap->pgid, 0));
344}
345
91447636
A
346int
347issetugid(struct proc *p, __unused struct issetugid_args *uap, register_t *retval)
0b4e3aa0
A
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
1c79356b 362/* ARGSUSED */
91447636
A
363int
364setuid(struct proc *p, struct setuid_args *uap, __unused register_t *retval)
1c79356b 365{
1c79356b
A
366 register uid_t uid;
367 int error;
91447636 368 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
369
370 uid = uap->uid;
55e303ae 371 AUDIT_ARG(uid, uid, 0, 0, 0);
91447636
A
372 if (uid != p->p_ucred->cr_ruid &&
373 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
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 */
9bccf70c
A
380
381 /* prepare app access profile files */
382 prepare_profile_database(uap->uid);
91447636 383 (void)chgproccnt(kauth_getruid(), -1);
1c79356b 384 (void)chgproccnt(uid, 1);
91447636
A
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 /*
0c530ab8
A
391 * Set the credential with new info. If there is no change,
392 * we get back the same credential we passed in; if there is
393 * a change, we drop the reference on the credential we
394 * passed in. The subsequent compare is safe, because it is
395 * a pointer compare rather than a contents compare.
91447636
A
396 */
397 my_new_cred = kauth_cred_setuid(my_cred, uid);
398 if (my_cred != my_new_cred) {
399 proc_lock(p);
400 /* need to protect for a race where another thread also changed
401 * the credential after we took our reference. If p_ucred has
402 * changed then we should restart this again with the new cred.
403 */
404 if (p->p_ucred != my_cred) {
405 proc_unlock(p);
0c530ab8 406 kauth_cred_unref(&my_new_cred);
91447636
A
407 /* try again */
408 continue;
409 }
410 p->p_ucred = my_new_cred;
411 p->p_flag |= P_SUGID;
412 proc_unlock(p);
413 }
0c530ab8
A
414 /* drop old proc reference or our extra reference */
415 kauth_cred_unref(&my_cred);
91447636
A
416 break;
417 }
418
1c79356b 419 set_security_token(p);
1c79356b
A
420 return (0);
421}
422
1c79356b 423/* ARGSUSED */
91447636
A
424int
425seteuid(struct proc *p, struct seteuid_args *uap, __unused register_t *retval)
1c79356b 426{
1c79356b
A
427 register uid_t euid;
428 int error;
91447636 429 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
430
431 euid = uap->euid;
55e303ae 432 AUDIT_ARG(uid, 0, euid, 0, 0);
91447636
A
433 if (euid != p->p_ucred->cr_ruid && euid != p->p_ucred->cr_svuid &&
434 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
435 return (error);
436 /*
437 * Everything's okay, do it. Copy credentials so other references do
91447636
A
438 * not see our changes. get current credential and take a reference
439 * while we muck with it
1c79356b 440 */
91447636
A
441 for (;;) {
442 my_cred = kauth_cred_proc_ref(p);
443
444 /*
0c530ab8
A
445 * Set the credential with new info. If there is no change,
446 * we get back the same credential we passed in; if there is
447 * a change, we drop the reference on the credential we
448 * passed in. The subsequent compare is safe, because it is
449 * a pointer compare rather than a contents compare.
91447636 450 */
0c530ab8 451 my_new_cred = kauth_cred_seteuid(my_cred, euid);
91447636
A
452
453 if (my_cred != my_new_cred) {
454 proc_lock(p);
0c530ab8
A
455 /*
456 * We need to protect for a race where another thread
457 * also changed the credential after we took our
458 * reference. If p_ucred has changed then we should
459 * restart this again with the new cred.
91447636
A
460 */
461 if (p->p_ucred != my_cred) {
462 proc_unlock(p);
0c530ab8 463 kauth_cred_unref(&my_new_cred);
91447636
A
464 /* try again */
465 continue;
466 }
467 p->p_ucred = my_new_cred;
468 p->p_flag |= P_SUGID;
469 proc_unlock(p);
470 }
0c530ab8
A
471 /* drop old proc reference or our extra reference */
472 kauth_cred_unref(&my_cred);
91447636
A
473 break;
474 }
475
1c79356b 476 set_security_token(p);
1c79356b
A
477 return (0);
478}
479
1c79356b 480/* ARGSUSED */
91447636
A
481int
482setgid(struct proc *p, struct setgid_args *uap, __unused register_t *retval)
1c79356b 483{
1c79356b
A
484 register gid_t gid;
485 int error;
91447636 486 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
487
488 gid = uap->gid;
55e303ae 489 AUDIT_ARG(gid, gid, 0, 0, 0);
91447636 490 if (gid != p->p_ucred->cr_rgid && (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 491 return (error);
91447636
A
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 /*
0c530ab8
A
498 * Set the credential with new info. If there is no change,
499 * we get back the same credential we passed in; if there is
500 * a change, we drop the reference on the credential we
501 * passed in. The subsequent compare is safe, because it is
502 * a pointer compare rather than a contents compare.
91447636 503 */
0c530ab8 504 my_new_cred = kauth_cred_setgid(my_cred, gid);
91447636
A
505 if (my_cred != my_new_cred) {
506 proc_lock(p);
0c530ab8
A
507 /*
508 * We need to protect for a race where another thread
509 * also changed the credential after we took our
510 * reference. If p_ucred has changed then we should
511 * restart this again with the new cred.
91447636
A
512 */
513 if (p->p_ucred != my_cred) {
514 proc_unlock(p);
0c530ab8 515 kauth_cred_unref(&my_new_cred);
91447636
A
516 /* try again */
517 continue;
518 }
519 p->p_ucred = my_new_cred;
520 p->p_flag |= P_SUGID;
521 proc_unlock(p);
522 }
0c530ab8
A
523 /* drop old proc reference or our extra reference */
524 kauth_cred_unref(&my_cred);
91447636
A
525 break;
526 }
527
1c79356b 528 set_security_token(p);
1c79356b
A
529 return (0);
530}
531
1c79356b 532/* ARGSUSED */
91447636
A
533int
534setegid(struct proc *p, struct setegid_args *uap, __unused register_t *retval)
1c79356b 535{
1c79356b
A
536 register gid_t egid;
537 int error;
91447636 538 kauth_cred_t my_cred, my_new_cred;
1c79356b
A
539
540 egid = uap->egid;
55e303ae 541 AUDIT_ARG(gid, 0, egid, 0, 0);
91447636
A
542 if (egid != p->p_ucred->cr_rgid && egid != p->p_ucred->cr_svgid &&
543 (error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 544 return (error);
91447636
A
545
546 /* get current credential and take a reference while we muck with it */
547 for (;;) {
548 my_cred = kauth_cred_proc_ref(p);
549
550 /*
0c530ab8
A
551 * Set the credential with new info. If there is no change,
552 * we get back the same credential we passed in; if there is
553 * a change, we drop the reference on the credential we
554 * passed in. The subsequent compare is safe, because it is
555 * a pointer compare rather than a contents compare.
91447636 556 */
0c530ab8 557 my_new_cred = kauth_cred_setegid(my_cred, egid);
91447636
A
558 if (my_cred != my_new_cred) {
559 proc_lock(p);
560 /* need to protect for a race where another thread also changed
561 * the credential after we took our reference. If p_ucred has
562 * changed then we should restart this again with the new cred.
563 */
564 if (p->p_ucred != my_cred) {
565 proc_unlock(p);
0c530ab8 566 kauth_cred_unref(&my_new_cred);
91447636
A
567 /* try again */
568 continue;
569 }
570 p->p_ucred = my_new_cred;
571 p->p_flag |= P_SUGID;
572 proc_unlock(p);
573 }
0c530ab8
A
574 /* drop old proc reference or our extra reference */
575 kauth_cred_unref(&my_cred);
91447636
A
576 break;
577 }
578
1c79356b 579 set_security_token(p);
1c79356b
A
580 return (0);
581}
582
91447636
A
583/*
584 * Set the per-thread override identity. The first parameter can be the
585 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
586 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
587 * means "revert to the per process credential"; otherwise, if permitted,
588 * it changes the effective, real, and saved UIDs and GIDs for the current
589 * thread to the requested UID and single GID, and clears all other GIDs.
590 */
591int
592settid(struct proc *p, struct settid_args *uap, __unused register_t *retval)
593{
594 kauth_cred_t uc;
595 struct uthread *uthread = get_bsdthread_info(current_thread());
596 register uid_t uid;
597 register gid_t gid;
598
599 uid = uap->uid;
600 gid = uap->gid;
601 AUDIT_ARG(uid, uid, gid, gid, 0);
602
603 if (suser(p->p_ucred, &p->p_acflag) != 0) {
604 return (EPERM);
605 }
606
607 if (uid == KAUTH_UID_NONE) {
608
609 /* must already be assuming another identity in order to revert back */
610 if ((uthread->uu_flag & UT_SETUID) == 0)
611 return (EPERM);
612
613 /* revert to delayed binding of process credential */
614 uc = kauth_cred_proc_ref(p);
0c530ab8 615 kauth_cred_unref(&uthread->uu_ucred);
91447636
A
616 uthread->uu_ucred = uc;
617 uthread->uu_flag &= ~UT_SETUID;
618 } else {
619 kauth_cred_t my_cred, my_new_cred;
620
621 /* cannot already be assuming another identity */
622 if ((uthread->uu_flag & UT_SETUID) != 0) {
623 return (EPERM);
624 }
625
626 /*
627 * get a new credential instance from the old if this one changes else
628 * kauth_cred_setuidgid returns the same credential. we take an extra
629 * reference on the current credential while we muck wit it here.
630 */
631 kauth_cred_ref(uthread->uu_ucred);
632 my_cred = uthread->uu_ucred;
633 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
634 if (my_cred != my_new_cred)
635 uthread->uu_ucred = my_new_cred;
636 uthread->uu_flag |= UT_SETUID;
637
638 /* drop our extra reference */
0c530ab8 639 kauth_cred_unref(&my_cred);
91447636
A
640 }
641 /*
642 * XXX should potentially set per thread security token (there is
643 * XXX none).
644 * XXX it is unclear whether P_SUGID should be st at this point;
645 * XXX in theory, it is being deprecated.
646 */
647 return (0);
648}
649
650/*
651 * Set the per-thread override identity. Use this system call for a thread to
652 * assume the identity of another process or to revert back to normal identity
653 * of the current process.
654 * When the "assume" argument is non zero the current thread will assume the
655 * identity of the process represented by the pid argument.
656 * When the assume argument is zero we revert back to our normal identity.
657 */
658int
659settid_with_pid(struct proc *p, struct settid_with_pid_args *uap, __unused register_t *retval)
660{
661 proc_t target_proc;
662 struct uthread *uthread = get_bsdthread_info(current_thread());
663 kauth_cred_t my_cred, my_target_cred, my_new_cred;
664
665 AUDIT_ARG(pid, uap->pid);
666 AUDIT_ARG(value, uap->assume);
667
668 if (suser(p->p_ucred, &p->p_acflag) != 0) {
669 return (EPERM);
670 }
671
672 /*
673 * XXX should potentially set per thread security token (there is
674 * XXX none).
675 * XXX it is unclear whether P_SUGID should be st at this point;
676 * XXX in theory, it is being deprecated.
677 */
678
679 /*
680 * assume argument tells us to assume the identity of the process with the
681 * id passed in the pid argument.
682 */
683 if (uap->assume != 0) {
684 /* can't do this if we have already assumed an identity */
685 if ((uthread->uu_flag & UT_SETUID) != 0)
686 return (EPERM);
687
688 target_proc = pfind(uap->pid);
689 /* can't assume the identity of the kernel process */
690 if (target_proc == NULL || target_proc == kernproc) {
691 return (ESRCH);
692 }
693
694 /*
695 * take a reference on the credential used in our target process then use
696 * it as the identity for our current thread.
697 */
698 kauth_cred_ref(uthread->uu_ucred);
699 my_cred = uthread->uu_ucred;
700 my_target_cred = kauth_cred_proc_ref(target_proc);
701 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
702 if (my_cred != my_new_cred)
703 uthread->uu_ucred = my_new_cred;
704
705 uthread->uu_flag |= UT_SETUID;
706
707 /* drop our extra references */
0c530ab8
A
708 kauth_cred_unref(&my_cred);
709 kauth_cred_unref(&my_target_cred);
91447636
A
710
711 return (0);
712 }
713
714 /* we are reverting back to normal mode of operation where delayed binding
715 * of the process credential sets the credential in the thread (uu_ucred)
716 */
717 if ((uthread->uu_flag & UT_SETUID) == 0)
718 return (EPERM);
719
720 /* revert to delayed binding of process credential */
721 my_new_cred = kauth_cred_proc_ref(p);
0c530ab8 722 kauth_cred_unref(&uthread->uu_ucred);
91447636
A
723 uthread->uu_ucred = my_new_cred;
724 uthread->uu_flag &= ~UT_SETUID;
725
726 return (0);
727}
1c79356b
A
728
729/* ARGSUSED */
91447636
A
730static int
731setgroups1(struct proc *p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused register_t *retval)
1c79356b 732{
1c79356b 733 register u_int ngrp;
91447636
A
734 gid_t newgroups[NGROUPS] = { 0 };
735 int error;
736 kauth_cred_t my_cred, my_new_cred;
13fec989 737 struct uthread *uthread = get_bsdthread_info(current_thread());
1c79356b 738
91447636 739 if ((error = suser(p->p_ucred, &p->p_acflag)))
1c79356b 740 return (error);
91447636 741 ngrp = gidsetsize;
55e303ae 742 if (ngrp > NGROUPS)
1c79356b 743 return (EINVAL);
91447636 744
55e303ae
A
745 if ( ngrp < 1 ) {
746 ngrp = 1;
747 }
748 else {
91447636
A
749 error = copyin(gidset,
750 (caddr_t)newgroups, ngrp * sizeof(gid_t));
55e303ae 751 if (error) {
55e303ae
A
752 return (error);
753 }
1c79356b 754 }
91447636 755
13fec989
A
756 if ((uthread->uu_flag & UT_SETUID) != 0) {
757 /*
758 * If this thread is under an assumed identity, set the
759 * supplementary grouplist on the thread credential instead
760 * of the process one. If we were the only reference holder,
761 * the credential is updated in place, otherwise, our reference
762 * is dropped and we get back a different cred with a reference
763 * already held on it. Because this is per-thread, we don't
764 * need the referencing/locking/retry required for per-process.
765 *
766 * Hack: this opts into memberd to avoid needing to use a per
767 * thread credential initgroups() instead of setgroups() in
768 * AFP server to address <rdar://4561060>
769 */
770 my_cred = uthread->uu_ucred;
771 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, my_cred->cr_gmuid);
772 } else {
91447636 773
13fec989
A
774 /*
775 * get current credential and take a reference while we muck
776 * with it
91447636 777 */
13fec989
A
778 for (;;) {
779 my_cred = kauth_cred_proc_ref(p);
780
781 /*
0c530ab8
A
782 * Set the credential with new info. If there is no
783 * change, we get back the same credential we passed
784 * in; if there is a change, we drop the reference on
785 * the credential we passed in. The subsequent
786 * compare is safe, because it is a pointer compare
787 * rather than a contents compare.
91447636 788 */
13fec989
A
789 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
790 if (my_cred != my_new_cred) {
791 proc_lock(p);
792 /*
793 * need to protect for a race where another
794 * thread also changed the credential after we
795 * took our reference. If p_ucred has
796 * changed then we should restart this again
797 * with the new cred.
798 */
799 if (p->p_ucred != my_cred) {
800 proc_unlock(p);
0c530ab8 801 kauth_cred_unref(&my_new_cred);
13fec989
A
802 /* try again */
803 continue;
804 }
805 p->p_ucred = my_new_cred;
806 p->p_flag |= P_SUGID;
91447636 807 proc_unlock(p);
91447636 808 }
0c530ab8
A
809 /* drop old proc reference or our extra reference */
810 kauth_cred_unref(&my_cred);
13fec989 811 break;
91447636 812 }
91447636 813
13fec989
A
814 AUDIT_ARG(groupset, p->p_ucred->cr_groups, ngrp);
815 set_security_token(p);
816 }
91447636 817
1c79356b
A
818 return (0);
819}
820
91447636
A
821int
822initgroups(struct proc *p, struct initgroups_args *uap, __unused register_t *retval)
1c79356b 823{
91447636
A
824 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
825}
1c79356b 826
91447636
A
827int
828setgroups(struct proc *p, struct setgroups_args *uap, __unused register_t *retval)
829{
830 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1c79356b
A
831}
832
91447636
A
833/*
834 * Set the per-thread/per-process supplementary groups list.
835 */
836#warning XXX implement
837int
838setsgroups(__unused struct proc *p, __unused struct setsgroups_args *uap, __unused register_t *retval)
1c79356b 839{
91447636
A
840 return(ENOTSUP);
841}
1c79356b 842
91447636
A
843/*
844 * Set the per-thread/per-process whiteout groups list.
845 */
846#warning XXX implement
847int
848setwgroups(__unused struct proc *p, __unused struct setwgroups_args *uap, __unused register_t *retval)
849{
850 return(ENOTSUP);
1c79356b 851}
1c79356b
A
852
853/*
854 * Check if gid is a member of the group set.
91447636
A
855 *
856 * XXX This interface is going away
1c79356b 857 */
91447636
A
858int
859groupmember(gid_t gid, kauth_cred_t cred)
1c79356b 860{
91447636 861 int is_member;
1c79356b 862
91447636
A
863 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
864 return (1);
1c79356b
A
865 return (0);
866}
867
868/*
869 * Test whether the specified credentials imply "super-user"
870 * privilege; if so, and we have accounting info, set the flag
871 * indicating use of super-powers.
872 * Returns 0 or error.
91447636
A
873 *
874 * XXX This interface is going away
1c79356b 875 */
91447636
A
876int
877suser(kauth_cred_t cred, u_short *acflag)
1c79356b
A
878{
879#if DIAGNOSTIC
0c530ab8 880 if (!IS_VALID_CRED(cred))
1c79356b
A
881 panic("suser");
882#endif
91447636 883 if (kauth_cred_getuid(cred) == 0) {
1c79356b
A
884 if (acflag)
885 *acflag |= ASU;
886 return (0);
887 }
888 return (EPERM);
889}
890
891int
892is_suser(void)
893{
894 struct proc *p = current_proc();
895
896 if (!p)
897 return (0);
898
899 return (suser(p->p_ucred, &p->p_acflag) == 0);
900}
901
902int
903is_suser1(void)
904{
905 struct proc *p = current_proc();
906
907 if (!p)
908 return (0);
909
910 return (suser(p->p_ucred, &p->p_acflag) == 0 ||
91447636 911 p->p_ucred->cr_ruid == 0 || p->p_ucred->cr_svuid == 0);
55e303ae
A
912}
913
1c79356b
A
914/*
915 * Get login name, if available.
916 */
1c79356b 917/* ARGSUSED */
91447636
A
918int
919getlogin(struct proc *p, struct getlogin_args *uap, __unused register_t *retval)
1c79356b
A
920{
921
922 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
923 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
924 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
91447636 925 uap->namebuf, uap->namelen));
1c79356b
A
926}
927
928/*
929 * Set login name.
930 */
1c79356b 931/* ARGSUSED */
91447636
A
932int
933setlogin(struct proc *p, struct setlogin_args *uap, __unused register_t *retval)
1c79356b
A
934{
935 int error;
936 int dummy=0;
937
91447636 938 if ((error = suser(p->p_ucred, &p->p_acflag)))
1c79356b
A
939 return (error);
940
91447636 941 error = copyinstr(uap->namebuf,
1c79356b
A
942 (caddr_t) p->p_pgrp->pg_session->s_login,
943 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)&dummy);
91447636 944 if (!error)
e5568f75
A
945 AUDIT_ARG(text, p->p_pgrp->pg_session->s_login);
946 else if (error == ENAMETOOLONG)
1c79356b
A
947 error = EINVAL;
948 return (error);
949}
950
951
952/* Set the secrity token of the task with current euid and eguid */
91447636
A
953/*
954 * XXX This needs to change to give the task a reference and/or an opaque
955 * XXX identifier.
956 */
957int
1c79356b
A
958set_security_token(struct proc * p)
959{
960 security_token_t sec_token;
55e303ae 961 audit_token_t audit_token;
1c79356b 962
91447636
A
963 /*
964 * Don't allow a vfork child to override the parent's token settings
965 * (since they share a task). Instead, the child will just have to
966 * suffer along using the parent's token until the exec(). It's all
967 * undefined behavior anyway, right?
968 */
969 if (p->task == current_task()) {
970 uthread_t uthread;
971 uthread = (uthread_t)get_bsdthread_info(current_thread());
972 if (uthread->uu_flag & UT_VFORK)
973 return (1);
974 }
975
976 /* XXX mach_init doesn't have a p_ucred when it calls this function */
0c530ab8 977 if (IS_VALID_CRED(p->p_ucred)) {
91447636
A
978 sec_token.val[0] = kauth_cred_getuid(p->p_ucred);
979 sec_token.val[1] = p->p_ucred->cr_gid;
980 } else {
981 sec_token.val[0] = 0;
982 sec_token.val[1] = 0;
983 }
e5568f75
A
984
985 /*
986 * The current layout of the Mach audit token explicitly
987 * adds these fields. But nobody should rely on such
988 * a literal representation. Instead, the BSM library
989 * provides a function to convert an audit token into
990 * a BSM subject. Use of that mechanism will isolate
991 * the user of the trailer from future representation
992 * changes.
993 */
91447636 994 audit_token.val[0] = p->p_ucred->cr_au.ai_auid;
e5568f75 995 audit_token.val[1] = p->p_ucred->cr_uid;
91447636
A
996 audit_token.val[2] = p->p_ucred->cr_gid;
997 audit_token.val[3] = p->p_ucred->cr_ruid;
998 audit_token.val[4] = p->p_ucred->cr_rgid;
e5568f75 999 audit_token.val[5] = p->p_pid;
91447636
A
1000 audit_token.val[6] = p->p_ucred->cr_au.ai_asid;
1001 audit_token.val[7] = p->p_ucred->cr_au.ai_termid.port;
e5568f75 1002
91447636 1003 return (host_security_set_task_token(host_security_self(),
1c79356b
A
1004 p->task,
1005 sec_token,
55e303ae 1006 audit_token,
1c79356b 1007 (sec_token.val[0]) ?
55e303ae 1008 HOST_PRIV_NULL :
91447636 1009 host_priv_self()) != KERN_SUCCESS);
1c79356b 1010}
55e303ae
A
1011
1012
1013/*
91447636 1014 * Fill in a struct xucred based on a kauth_cred_t.
55e303ae
A
1015 */
1016__private_extern__
1017void
91447636 1018cru2x(kauth_cred_t cr, struct xucred *xcr)
55e303ae
A
1019{
1020
1021 bzero(xcr, sizeof(*xcr));
1022 xcr->cr_version = XUCRED_VERSION;
91447636 1023 xcr->cr_uid = kauth_cred_getuid(cr);
55e303ae
A
1024 xcr->cr_ngroups = cr->cr_ngroups;
1025 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
1026}