]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
1301dbeea3ce53914c8d011b735e3efa51ab54ab
[apple/xnu.git] / bsd / kern / kern_prot.c
1 /*
2 * Copyright (c) 2000-2008 Apple 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 *
29 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
30 *
31 *
32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
33 * The Regents of the University of California. All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
69 *
70 *
71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
72 * support for mandatory and extensible security protections. This notice
73 * is included in support of clause 2.2 (b) of the Apple Public License,
74 * Version 2.0.
75 *
76 *
77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
78 * support for mandatory and extensible security protections. This notice
79 * is included in support of clause 2.2 (b) of the Apple Public License,
80 * Version 2.0.
81 *
82 */
83
84 /*
85 * System calls related to processes and protection
86 */
87
88 #include <sys/param.h>
89 #include <sys/acct.h>
90 #include <sys/systm.h>
91 #include <sys/ucred.h>
92 #include <sys/proc_internal.h>
93 #include <sys/user.h>
94 #include <sys/kauth.h>
95 #include <sys/timeb.h>
96 #include <sys/times.h>
97 #include <sys/malloc.h>
98
99 #include <security/audit/audit.h>
100
101 #if CONFIG_LCTX
102 #include <sys/lctx.h>
103 #endif
104
105 #if CONFIG_MACF
106 #include <security/mac_framework.h>
107 #endif
108
109 #include <sys/mount_internal.h>
110 #include <sys/sysproto.h>
111 #include <mach/message.h>
112 #include <mach/host_security.h>
113
114 #include <kern/host.h>
115 #include <kern/task.h> /* for current_task() */
116 #include <kern/assert.h>
117
118
119 /*
120 * Credential debugging; we can track entry into a function that might
121 * change a credential, and we can track actual credential changes that
122 * result.
123 *
124 * Note: Does *NOT* currently include per-thread credential changes
125 *
126 * We don't use kauth_cred_print() in current debugging, but it
127 * can be used if needed when debugging is active.
128 */
129 #if DEBUG_CRED
130 #define DEBUG_CRED_ENTER printf
131 #define DEBUG_CRED_CHANGE printf
132 extern void kauth_cred_print(kauth_cred_t cred);
133 #else /* !DEBUG_CRED */
134 #define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
135 #define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
136 #endif /* !DEBUG_CRED */
137
138 #if DEVELOPMENT || DEBUG
139 extern void task_importance_update_owner_info(task_t);
140 #endif
141
142
143 /*
144 * setprivexec
145 *
146 * Description: (dis)allow this process to hold task, thread, or execption
147 * ports of processes about to exec.
148 *
149 * Parameters: uap->flag New value for flag
150 *
151 * Returns: int Previous value of flag
152 *
153 * XXX: Belongs in kern_proc.c
154 */
155 int
156 setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
157 {
158 AUDIT_ARG(value32, uap->flag);
159 *retval = p->p_debugger;
160 p->p_debugger = (uap->flag != 0);
161 return(0);
162 }
163
164
165 /*
166 * getpid
167 *
168 * Description: get the process ID
169 *
170 * Parameters: (void)
171 *
172 * Returns: pid_t Current process ID
173 *
174 * XXX: Belongs in kern_proc.c
175 */
176 int
177 getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
178 {
179
180 *retval = p->p_pid;
181 return (0);
182 }
183
184
185 /*
186 * getppid
187 *
188 * Description: get the parent process ID
189 *
190 * Parameters: (void)
191 *
192 * Returns: pid_t Parent process ID
193 *
194 * XXX: Belongs in kern_proc.c
195 */
196 int
197 getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
198 {
199
200 *retval = p->p_ppid;
201 return (0);
202 }
203
204
205 /*
206 * getpgrp
207 *
208 * Description: get the process group ID of the calling process
209 *
210 * Parameters: (void)
211 *
212 * Returns: pid_t Process group ID
213 *
214 * XXX: Belongs in kern_proc.c
215 */
216 int
217 getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
218 {
219
220 *retval = p->p_pgrpid;
221 return (0);
222 }
223
224
225 /*
226 * getpgid
227 *
228 * Description: Get an arbitary pid's process group id
229 *
230 * Parameters: uap->pid The target pid
231 *
232 * Returns: 0 Success
233 * ESRCH No such process
234 *
235 * Notes: We are permitted to return EPERM in the case that the target
236 * process is not in the same session as the calling process,
237 * which could be a security consideration
238 *
239 * XXX: Belongs in kern_proc.c
240 */
241 int
242 getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
243 {
244 proc_t pt;
245 int refheld = 0;
246
247 pt = p;
248 if (uap->pid == 0)
249 goto found;
250
251 if ((pt = proc_find(uap->pid)) == 0)
252 return (ESRCH);
253 refheld = 1;
254 found:
255 *retval = pt->p_pgrpid;
256 if (refheld != 0)
257 proc_rele(pt);
258 return (0);
259 }
260
261
262 /*
263 * getsid
264 *
265 * Description: Get an arbitary pid's session leaders process group ID
266 *
267 * Parameters: uap->pid The target pid
268 *
269 * Returns: 0 Success
270 * ESRCH No such process
271 *
272 * Notes: We are permitted to return EPERM in the case that the target
273 * process is not in the same session as the calling process,
274 * which could be a security consideration
275 *
276 * XXX: Belongs in kern_proc.c
277 */
278 int
279 getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
280 {
281 proc_t pt;
282 int refheld = 0;
283 struct session * sessp;
284
285 pt = p;
286 if (uap->pid == 0)
287 goto found;
288
289 if ((pt = proc_find(uap->pid)) == 0)
290 return (ESRCH);
291 refheld = 1;
292 found:
293 sessp = proc_session(pt);
294 *retval = sessp->s_sid;
295 session_rele(sessp);
296
297 if (refheld != 0)
298 proc_rele(pt);
299 return (0);
300 }
301
302
303 /*
304 * getuid
305 *
306 * Description: get real user ID for caller
307 *
308 * Parameters: (void)
309 *
310 * Returns: uid_t The real uid of the caller
311 */
312 int
313 getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
314 {
315
316 *retval = kauth_getruid();
317 return (0);
318 }
319
320
321 /*
322 * geteuid
323 *
324 * Description: get effective user ID for caller
325 *
326 * Parameters: (void)
327 *
328 * Returns: uid_t The effective uid of the caller
329 */
330 int
331 geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
332 {
333
334 *retval = kauth_getuid();
335 return (0);
336 }
337
338
339 /*
340 * gettid
341 *
342 * Description: Return the per-thread override identity.
343 *
344 * Parameters: uap->uidp Address of uid_t to get uid
345 * uap->gidp Address of gid_t to get gid
346 *
347 * Returns: 0 Success
348 * ESRCH No per thread identity active
349 */
350 int
351 gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
352 {
353 struct uthread *uthread = get_bsdthread_info(current_thread());
354 int error;
355
356 /*
357 * If this thread is not running with an override identity, we can't
358 * return one to the caller, so return an error instead.
359 */
360 if (!(uthread->uu_flag & UT_SETUID))
361 return (ESRCH);
362
363 if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred))))
364 return (error);
365 if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred))))
366 return (error);
367
368 *retval = 0;
369 return (0);
370 }
371
372
373 /*
374 * getgid
375 *
376 * Description: get the real group ID for the calling process
377 *
378 * Parameters: (void)
379 *
380 * Returns: gid_t The real gid of the caller
381 */
382 int
383 getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
384 {
385
386 *retval = kauth_getrgid();
387 return (0);
388 }
389
390
391 /*
392 * getegid
393 *
394 * Description: get the effective group ID for the calling process
395 *
396 * Parameters: (void)
397 *
398 * Returns: gid_t The effective gid of the caller
399 *
400 * Notes: As an implementation detail, the effective gid is stored as
401 * the first element of the supplementary group list.
402 *
403 * This could be implemented in Libc instead because of the above
404 * detail.
405 */
406 int
407 getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
408 {
409
410 *retval = kauth_getgid();
411 return (0);
412 }
413
414
415 /*
416 * getgroups
417 *
418 * Description: get the list of supplementary groups for the calling process
419 *
420 * Parameters: uap->gidsetsize # of gid_t's in user buffer
421 * uap->gidset Pointer to user buffer
422 *
423 * Returns: 0 Success
424 * EINVAL User buffer too small
425 * copyout:EFAULT User buffer invalid
426 *
427 * Retval: -1 Error
428 * !0 # of groups
429 *
430 * Notes: The caller may specify a 0 value for gidsetsize, and we will
431 * then return how large a buffer is required (in gid_t's) to
432 * contain the answer at the time of the call. Otherwise, we
433 * return the number of gid_t's catually copied to user space.
434 *
435 * When called with a 0 gidsetsize from a multithreaded program,
436 * there is no guarantee that another thread may not change the
437 * number of supplementary groups, and therefore a subsequent
438 * call could still fail, unless the maximum possible buffer
439 * size is supplied by the user.
440 *
441 * As an implementation detail, the effective gid is stored as
442 * the first element of the supplementary group list, and will
443 * be returned by this call.
444 */
445 int
446 getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
447 {
448 int ngrp;
449 int error;
450 kauth_cred_t cred;
451 posix_cred_t pcred;
452
453 /* grab reference while we muck around with the credential */
454 cred = kauth_cred_get_with_ref();
455 pcred = posix_cred_get(cred);
456
457 if ((ngrp = uap->gidsetsize) == 0) {
458 *retval = pcred->cr_ngroups;
459 kauth_cred_unref(&cred);
460 return (0);
461 }
462 if (ngrp < pcred->cr_ngroups) {
463 kauth_cred_unref(&cred);
464 return (EINVAL);
465 }
466 ngrp = pcred->cr_ngroups;
467 if ((error = copyout((caddr_t)pcred->cr_groups,
468 uap->gidset,
469 ngrp * sizeof(gid_t)))) {
470 kauth_cred_unref(&cred);
471 return (error);
472 }
473 kauth_cred_unref(&cred);
474 *retval = ngrp;
475 return (0);
476 }
477
478
479 /*
480 * Return the per-thread/per-process supplementary groups list.
481 *
482 * XXX implement getsgroups
483 *
484 */
485
486 int
487 getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
488 {
489 return(ENOTSUP);
490 }
491
492 /*
493 * Return the per-thread/per-process whiteout groups list.
494 *
495 * XXX implement getwgroups
496 *
497 */
498
499 int
500 getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
501 {
502 return(ENOTSUP);
503 }
504
505
506 /*
507 * setsid
508 *
509 * Description: Create a new session and set the process group ID to the
510 * session ID
511 *
512 * Parameters: (void)
513 *
514 * Returns: 0 Success
515 * EPERM Permission denied
516 *
517 * Notes: If the calling process is not the process group leader; there
518 * is no existing process group with its ID, and we are not
519 * currently in vfork, then this function will create a new
520 * session, a new process group, and put the caller in the
521 * process group (as the sole member) and make it the session
522 * leader (as the sole process in the session).
523 *
524 * The existing controlling tty (if any) will be dissociated
525 * from the process, and the next non-O_NOCTTY open of a tty
526 * will establish a new controlling tty.
527 *
528 * XXX: Belongs in kern_proc.c
529 */
530 int
531 setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
532 {
533 struct pgrp * pg = PGRP_NULL;
534
535 if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
536 if (pg != PGRP_NULL)
537 pg_rele(pg);
538 return (EPERM);
539 } else {
540 /* enter pgrp works with its own pgrp refcount */
541 (void)enterpgrp(p, p->p_pid, 1);
542 *retval = p->p_pid;
543 return (0);
544 }
545 }
546
547
548 /*
549 * setpgid
550 *
551 * Description: set process group ID for job control
552 *
553 * Parameters: uap->pid Process to change
554 * uap->pgid Process group to join or create
555 *
556 * Returns: 0 Success
557 * ESRCH pid is not the caller or a child of
558 * the caller
559 * enterpgrp:ESRCH No such process
560 * EACCES Permission denied due to exec
561 * EINVAL Invalid argument
562 * EPERM The target process is not in the same
563 * session as the calling process
564 * EPERM The target process is a session leader
565 * EPERM pid and pgid are not the same, and
566 * there is no process in the calling
567 * process whose process group ID matches
568 * pgid
569 *
570 * Notes: This function will cause the target process to either join
571 * an existing process process group, or create a new process
572 * group in the session of the calling process. It cannot be
573 * used to change the process group ID of a process which is
574 * already a session leader.
575 *
576 * If the target pid is 0, the pid of the calling process is
577 * substituted as the new target; if pgid is 0, the target pid
578 * is used as the target process group ID.
579 *
580 * Legacy: This system call entry point is also used to implement the
581 * legacy library routine setpgrp(), which under POSIX
582 *
583 * XXX: Belongs in kern_proc.c
584 */
585 int
586 setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval)
587 {
588 proc_t targp = PROC_NULL; /* target process */
589 struct pgrp *pg = PGRP_NULL; /* target pgrp */
590 int error = 0;
591 int refheld = 0;
592 int samesess = 0;
593 struct session * curp_sessp = SESSION_NULL;
594 struct session * targp_sessp = SESSION_NULL;
595
596 curp_sessp = proc_session(curp);
597
598 if (uap->pid != 0 && uap->pid != curp->p_pid) {
599 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
600 if (targp != PROC_NULL)
601 refheld = 1;
602 error = ESRCH;
603 goto out;
604 }
605 refheld = 1;
606 targp_sessp = proc_session(targp);
607 if (targp_sessp != curp_sessp) {
608 error = EPERM;
609 goto out;
610 }
611 if (targp->p_flag & P_EXEC) {
612 error = EACCES;
613 goto out;
614 }
615 } else {
616 targp = curp;
617 targp_sessp = proc_session(targp);
618 }
619
620 if (SESS_LEADER(targp, targp_sessp)) {
621 error = EPERM;
622 goto out;
623 }
624 if (targp_sessp != SESSION_NULL) {
625 session_rele(targp_sessp);
626 targp_sessp = SESSION_NULL;
627 }
628
629 if (uap->pgid < 0) {
630 error = EINVAL;
631 goto out;
632 }
633 if (uap->pgid == 0)
634 uap->pgid = targp->p_pid;
635 else if (uap->pgid != targp->p_pid) {
636 if ((pg = pgfind(uap->pgid)) == 0){
637 error = EPERM;
638 goto out;
639 }
640 samesess = (pg->pg_session != curp_sessp);
641 pg_rele(pg);
642 if (samesess != 0) {
643 error = EPERM;
644 goto out;
645 }
646 }
647 error = enterpgrp(targp, uap->pgid, 0);
648 out:
649 if (targp_sessp != SESSION_NULL)
650 session_rele(targp_sessp);
651 if (curp_sessp != SESSION_NULL)
652 session_rele(curp_sessp);
653 if (refheld != 0)
654 proc_rele(targp);
655 return(error);
656 }
657
658
659 /*
660 * issetugid
661 *
662 * Description: Is current process tainted by uid or gid changes system call
663 *
664 * Parameters: (void)
665 *
666 * Returns: 0 Not tainted
667 * 1 Tainted
668 *
669 * Notes: A process is considered tainted if it was created as a retult
670 * of an execve call from an imnage that had either the SUID or
671 * SGID bit set on the executable, or if it has changed any of its
672 * real, effective, or saved user or group IDs since beginning
673 * execution.
674 */
675 int
676 issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
677 {
678 /*
679 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
680 * we use P_SUGID because we consider changing the owners as
681 * "tainting" as well.
682 * This is significant for procs that start as root and "become"
683 * a user without an exec - programs cannot know *everything*
684 * that libc *might* have put in their data segment.
685 */
686
687 *retval = (p->p_flag & P_SUGID) ? 1 : 0;
688 return (0);
689 }
690
691
692 /*
693 * setuid
694 *
695 * Description: Set user ID system call
696 *
697 * Parameters: uap->uid uid to set
698 *
699 * Returns: 0 Success
700 * suser:EPERM Permission denied
701 *
702 * Notes: If called by a privileged process, this function will set the
703 * real, effective, and saved uid to the requested value.
704 *
705 * If called from an unprivileged process, but uid is equal to the
706 * real or saved uid, then the effective uid will be set to the
707 * requested value, but the real and saved uid will not change.
708 *
709 * If the credential is changed as a result of this call, then we
710 * flag the process as having set privilege since the last exec.
711 */
712 int
713 setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
714 {
715 uid_t uid;
716 uid_t svuid = KAUTH_UID_NONE;
717 uid_t ruid = KAUTH_UID_NONE;
718 uid_t gmuid = KAUTH_UID_NONE;
719 int error;
720 kauth_cred_t my_cred, my_new_cred;
721 posix_cred_t my_pcred;
722
723
724 uid = uap->uid;
725
726 my_cred = kauth_cred_proc_ref(p);
727 my_pcred = posix_cred_get(my_cred);
728
729 DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid);
730 AUDIT_ARG(uid, uid);
731
732 if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
733 uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
734 (error = suser(my_cred, &p->p_acflag))) {
735 kauth_cred_unref(&my_cred);
736 return (error);
737 }
738 /*
739 * Everything's okay, do it.
740 */
741
742 /*
743 * If we are priviledged, then set the saved and real UID too;
744 * otherwise, just set the effective UID
745 */
746 if (suser(my_cred, &p->p_acflag) == 0) {
747 svuid = uid;
748 ruid = uid;
749 /*
750 * Transfer proc count to new user.
751 * chgproccnt uses list lock for protection
752 */
753 (void)chgproccnt(uid, 1);
754 (void)chgproccnt(my_pcred->cr_ruid, -1);
755 }
756
757 /* get current credential and take a reference while we muck with it */
758 for (;;) {
759 /*
760 * Only set the gmuid if the current cred has not opt'ed out;
761 * this normally only happens when calling setgroups() instead
762 * of initgroups() to set an explicit group list, or one of the
763 * other group manipulation functions is invoked and results in
764 * a dislocation (i.e. the credential group membership changes
765 * to something other than the default list for the user, as
766 * in entering a group or leaving an exclusion group).
767 */
768 if (!(my_pcred->cr_flags & CRF_NOMEMBERD))
769 gmuid = uid;
770
771 /*
772 * Set the credential with new info. If there is no change,
773 * we get back the same credential we passed in; if there is
774 * a change, we drop the reference on the credential we
775 * passed in. The subsequent compare is safe, because it is
776 * a pointer compare rather than a contents compare.
777 */
778 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
779 if (my_cred != my_new_cred) {
780
781 DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
782
783 proc_lock(p);
784 /*
785 * We need to protect for a race where another thread
786 * also changed the credential after we took our
787 * reference. If p_ucred has changed then we should
788 * restart this again with the new cred.
789 */
790 if (p->p_ucred != my_cred) {
791 proc_unlock(p);
792 kauth_cred_unref(&my_new_cred);
793 my_cred = kauth_cred_proc_ref(p);
794 /* try again */
795 continue;
796 }
797 p->p_ucred = my_new_cred;
798 /* update cred on proc */
799 PROC_UPDATE_CREDS_ONPROC(p);
800
801 OSBitOrAtomic(P_SUGID, &p->p_flag);
802 proc_unlock(p);
803 }
804 break;
805 }
806 /* Drop old proc reference or our extra reference */
807 kauth_cred_unref(&my_cred);
808
809 set_security_token(p);
810 return (0);
811 }
812
813
814 /*
815 * seteuid
816 *
817 * Description: Set effective user ID system call
818 *
819 * Parameters: uap->euid effective uid to set
820 *
821 * Returns: 0 Success
822 * suser:EPERM Permission denied
823 *
824 * Notes: If called by a privileged process, or called from an
825 * unprivileged process but euid is equal to the real or saved
826 * uid, then the effective uid will be set to the requested
827 * value, but the real and saved uid will not change.
828 *
829 * If the credential is changed as a result of this call, then we
830 * flag the process as having set privilege since the last exec.
831 */
832 int
833 seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
834 {
835 uid_t euid;
836 int error;
837 kauth_cred_t my_cred, my_new_cred;
838 posix_cred_t my_pcred;
839
840 DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
841
842 euid = uap->euid;
843 AUDIT_ARG(euid, euid);
844
845 my_cred = kauth_cred_proc_ref(p);
846 my_pcred = posix_cred_get(my_cred);
847
848 if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
849 (error = suser(my_cred, &p->p_acflag))) {
850 kauth_cred_unref(&my_cred);
851 return (error);
852 }
853
854 /*
855 * Everything's okay, do it. Copy credentials so other references do
856 * not see our changes. get current credential and take a reference
857 * while we muck with it
858 */
859 for (;;) {
860 /*
861 * Set the credential with new info. If there is no change,
862 * we get back the same credential we passed in; if there is
863 * a change, we drop the reference on the credential we
864 * passed in. The subsequent compare is safe, because it is
865 * a pointer compare rather than a contents compare.
866 */
867 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
868
869 if (my_cred != my_new_cred) {
870
871 DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
872
873 proc_lock(p);
874 /*
875 * We need to protect for a race where another thread
876 * also changed the credential after we took our
877 * reference. If p_ucred has changed then we
878 * should restart this again with the new cred.
879 */
880 if (p->p_ucred != my_cred) {
881 proc_unlock(p);
882 kauth_cred_unref(&my_new_cred);
883 my_cred = kauth_cred_proc_ref(p);
884 /* try again */
885 continue;
886 }
887 p->p_ucred = my_new_cred;
888 /* update cred on proc */
889 PROC_UPDATE_CREDS_ONPROC(p);
890 OSBitOrAtomic(P_SUGID, &p->p_flag);
891 proc_unlock(p);
892 }
893 break;
894 }
895 /* drop old proc reference or our extra reference */
896 kauth_cred_unref(&my_cred);
897
898 set_security_token(p);
899 return (0);
900 }
901
902
903 /*
904 * setreuid
905 *
906 * Description: Set real and effective user ID system call
907 *
908 * Parameters: uap->ruid real uid to set
909 * uap->euid effective uid to set
910 *
911 * Returns: 0 Success
912 * suser:EPERM Permission denied
913 *
914 * Notes: A value of -1 is a special case indicating that the uid for
915 * which that value is specified not be changed. If both values
916 * are specified as -1, no action is taken.
917 *
918 * If called by a privileged process, the real and effective uid
919 * will be set to the new value(s) specified.
920 *
921 * If called from an unprivileged process, the real uid may be
922 * set to the current value of the real uid, or to the current
923 * value of the saved uid. The effective uid may be set to the
924 * current value of any of the effective, real, or saved uid.
925 *
926 * If the newly requested real uid or effective uid does not
927 * match the saved uid, then set the saved uid to the new
928 * effective uid (potentially unrecoverably dropping saved
929 * privilege).
930 *
931 * If the credential is changed as a result of this call, then we
932 * flag the process as having set privilege since the last exec.
933 */
934 int
935 setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
936 {
937 uid_t ruid, euid;
938 int error;
939 kauth_cred_t my_cred, my_new_cred;
940 posix_cred_t my_pcred;
941
942 DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
943
944 ruid = uap->ruid;
945 euid = uap->euid;
946 if (ruid == (uid_t)-1)
947 ruid = KAUTH_UID_NONE;
948 if (euid == (uid_t)-1)
949 euid = KAUTH_UID_NONE;
950 AUDIT_ARG(euid, euid);
951 AUDIT_ARG(ruid, ruid);
952
953 my_cred = kauth_cred_proc_ref(p);
954 my_pcred = posix_cred_get(my_cred);
955
956 if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
957 ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
958 ruid != my_pcred->cr_uid && /* allow ruid = euid */
959 ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
960 (euid != KAUTH_UID_NONE && /* allow no change of euid */
961 euid != my_pcred->cr_uid && /* allow euid = euid */
962 euid != my_pcred->cr_ruid && /* allow euid = ruid */
963 euid != my_pcred->cr_svuid)) && /* allow euid = svui */
964 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
965 kauth_cred_unref(&my_cred);
966 return (error);
967 }
968
969 /*
970 * Everything's okay, do it. Copy credentials so other references do
971 * not see our changes. get current credential and take a reference
972 * while we muck with it
973 */
974 for (;;) {
975 uid_t new_euid;
976 uid_t new_ruid;
977 uid_t svuid = KAUTH_UID_NONE;
978
979 new_euid = my_pcred->cr_uid;
980 new_ruid = my_pcred->cr_ruid;
981
982 /*
983 * Set the credential with new info. If there is no change,
984 * we get back the same credential we passed in; if there is
985 * a change, we drop the reference on the credential we
986 * passed in. The subsequent compare is safe, because it is
987 * a pointer compare rather than a contents compare.
988 */
989 if (euid == KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
990 /* changing the effective UID */
991 new_euid = euid;
992 OSBitOrAtomic(P_SUGID, &p->p_flag);
993 }
994 if (ruid != KAUTH_UID_NONE && my_pcred->cr_ruid != ruid) {
995 /* changing the real UID; must do user accounting */
996 /* chgproccnt uses list lock for protection */
997 (void)chgproccnt(ruid, 1);
998 (void)chgproccnt(my_pcred->cr_ruid, -1);
999 new_ruid = ruid;
1000 OSBitOrAtomic(P_SUGID, &p->p_flag);
1001 }
1002 /*
1003 * If the newly requested real uid or effective uid does
1004 * not match the saved uid, then set the saved uid to the
1005 * new effective uid. We are protected from escalation
1006 * by the prechecking.
1007 */
1008 if (my_pcred->cr_svuid != uap->ruid &&
1009 my_pcred->cr_svuid != uap->euid) {
1010 svuid = new_euid;
1011 OSBitOrAtomic(P_SUGID, &p->p_flag);
1012 }
1013
1014 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
1015
1016 if (my_cred != my_new_cred) {
1017
1018 DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1019
1020 proc_lock(p);
1021 /*
1022 * We need to protect for a race where another thread
1023 * also changed the credential after we took our
1024 * reference. If p_ucred has changed then we should
1025 * restart this again with the new cred.
1026 */
1027 if (p->p_ucred != my_cred) {
1028 proc_unlock(p);
1029 kauth_cred_unref(&my_new_cred);
1030 my_cred = kauth_cred_proc_ref(p);
1031 /* try again */
1032 continue;
1033 }
1034 p->p_ucred = my_new_cred;
1035 /* update cred on proc */
1036 PROC_UPDATE_CREDS_ONPROC(p);
1037 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1038 proc_unlock(p);
1039 }
1040 break;
1041 }
1042 /* drop old proc reference or our extra reference */
1043 kauth_cred_unref(&my_cred);
1044
1045 set_security_token(p);
1046 return (0);
1047 }
1048
1049
1050 /*
1051 * setgid
1052 *
1053 * Description: Set group ID system call
1054 *
1055 * Parameters: uap->gid gid to set
1056 *
1057 * Returns: 0 Success
1058 * suser:EPERM Permission denied
1059 *
1060 * Notes: If called by a privileged process, this function will set the
1061 * real, effective, and saved gid to the requested value.
1062 *
1063 * If called from an unprivileged process, but gid is equal to the
1064 * real or saved gid, then the effective gid will be set to the
1065 * requested value, but the real and saved gid will not change.
1066 *
1067 * If the credential is changed as a result of this call, then we
1068 * flag the process as having set privilege since the last exec.
1069 *
1070 * As an implementation detail, the effective gid is stored as
1071 * the first element of the supplementary group list, and
1072 * therefore the effective group list may be reordered to keep
1073 * the supplementary group list unchanged.
1074 */
1075 int
1076 setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
1077 {
1078 gid_t gid;
1079 gid_t rgid = KAUTH_GID_NONE;
1080 gid_t svgid = KAUTH_GID_NONE;
1081 int error;
1082 kauth_cred_t my_cred, my_new_cred;
1083 posix_cred_t my_pcred;
1084
1085 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
1086
1087 gid = uap->gid;
1088 AUDIT_ARG(gid, gid);
1089
1090 my_cred = kauth_cred_proc_ref(p);
1091 my_pcred = posix_cred_get(my_cred);
1092
1093 if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
1094 gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
1095 (error = suser(my_cred, &p->p_acflag))) {
1096 kauth_cred_unref(&my_cred);
1097 return (error);
1098 }
1099
1100 /*
1101 * If we are priviledged, then set the saved and real GID too;
1102 * otherwise, just set the effective GID
1103 */
1104 if (suser(my_cred, &p->p_acflag) == 0) {
1105 svgid = gid;
1106 rgid = gid;
1107 }
1108
1109 /* get current credential and take a reference while we muck with it */
1110 for (;;) {
1111
1112 /*
1113 * Set the credential with new info. If there is no change,
1114 * we get back the same credential we passed in; if there is
1115 * a change, we drop the reference on the credential we
1116 * passed in. The subsequent compare is safe, because it is
1117 * a pointer compare rather than a contents compare.
1118 */
1119 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
1120 if (my_cred != my_new_cred) {
1121
1122 DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1123
1124 proc_lock(p);
1125 /*
1126 * We need to protect for a race where another thread
1127 * also changed the credential after we took our
1128 * reference. If p_ucred has changed then we
1129 * should restart this again with the new cred.
1130 */
1131 if (p->p_ucred != my_cred) {
1132 proc_unlock(p);
1133 kauth_cred_unref(&my_new_cred);
1134 /* try again */
1135 my_cred = kauth_cred_proc_ref(p);
1136 continue;
1137 }
1138 p->p_ucred = my_new_cred;
1139 /* update cred on proc */
1140 PROC_UPDATE_CREDS_ONPROC(p);
1141 OSBitOrAtomic(P_SUGID, &p->p_flag);
1142 proc_unlock(p);
1143 }
1144 break;
1145 }
1146 /* Drop old proc reference or our extra reference */
1147 kauth_cred_unref(&my_cred);
1148
1149 set_security_token(p);
1150 return (0);
1151 }
1152
1153
1154 /*
1155 * setegid
1156 *
1157 * Description: Set effective group ID system call
1158 *
1159 * Parameters: uap->egid effective gid to set
1160 *
1161 * Returns: 0 Success
1162 * suser:EPERM
1163 *
1164 * Notes: If called by a privileged process, or called from an
1165 * unprivileged process but egid is equal to the real or saved
1166 * gid, then the effective gid will be set to the requested
1167 * value, but the real and saved gid will not change.
1168 *
1169 * If the credential is changed as a result of this call, then we
1170 * flag the process as having set privilege since the last exec.
1171 *
1172 * As an implementation detail, the effective gid is stored as
1173 * the first element of the supplementary group list, and
1174 * therefore the effective group list may be reordered to keep
1175 * the supplementary group list unchanged.
1176 */
1177 int
1178 setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1179 {
1180 gid_t egid;
1181 int error;
1182 kauth_cred_t my_cred, my_new_cred;
1183 posix_cred_t my_pcred;
1184
1185 DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
1186
1187 egid = uap->egid;
1188 AUDIT_ARG(egid, egid);
1189
1190 my_cred = kauth_cred_proc_ref(p);
1191 my_pcred = posix_cred_get(my_cred);
1192
1193 if (egid != my_pcred->cr_rgid &&
1194 egid != my_pcred->cr_svgid &&
1195 (error = suser(my_cred, &p->p_acflag))) {
1196 kauth_cred_unref(&my_cred);
1197 return (error);
1198 }
1199
1200 /* get current credential and take a reference while we muck with it */
1201 for (;;) {
1202 /*
1203 * Set the credential with new info. If there is no change,
1204 * we get back the same credential we passed in; if there is
1205 * a change, we drop the reference on the credential we
1206 * passed in. The subsequent compare is safe, because it is
1207 * a pointer compare rather than a contents compare.
1208 */
1209 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
1210 if (my_cred != my_new_cred) {
1211
1212 DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1213
1214 proc_lock(p);
1215 /*
1216 * We need to protect for a race where another thread
1217 * also changed the credential after we took our
1218 * reference. If p_ucred has changed then we
1219 * should restart this again with the new cred.
1220 */
1221 if (p->p_ucred != my_cred) {
1222 proc_unlock(p);
1223 kauth_cred_unref(&my_new_cred);
1224 /* try again */
1225 my_cred = kauth_cred_proc_ref(p);
1226 continue;
1227 }
1228 p->p_ucred = my_new_cred;
1229 /* update cred on proc */
1230 PROC_UPDATE_CREDS_ONPROC(p);
1231 OSBitOrAtomic(P_SUGID, &p->p_flag);
1232 proc_unlock(p);
1233 }
1234 break;
1235 }
1236
1237 /* Drop old proc reference or our extra reference */
1238 kauth_cred_unref(&my_cred);
1239
1240 set_security_token(p);
1241 return (0);
1242 }
1243
1244 /*
1245 * setregid
1246 *
1247 * Description: Set real and effective group ID system call
1248 *
1249 * Parameters: uap->rgid real gid to set
1250 * uap->egid effective gid to set
1251 *
1252 * Returns: 0 Success
1253 * suser:EPERM Permission denied
1254 *
1255 * Notes: A value of -1 is a special case indicating that the gid for
1256 * which that value is specified not be changed. If both values
1257 * are specified as -1, no action is taken.
1258 *
1259 * If called by a privileged process, the real and effective gid
1260 * will be set to the new value(s) specified.
1261 *
1262 * If called from an unprivileged process, the real gid may be
1263 * set to the current value of the real gid, or to the current
1264 * value of the saved gid. The effective gid may be set to the
1265 * current value of any of the effective, real, or saved gid.
1266 *
1267 * If the new real and effective gid will not be equal, or the
1268 * new real or effective gid is not the same as the saved gid,
1269 * then the saved gid will be updated to reflect the new
1270 * effective gid (potentially unrecoverably dropping saved
1271 * privilege).
1272 *
1273 * If the credential is changed as a result of this call, then we
1274 * flag the process as having set privilege since the last exec.
1275 *
1276 * As an implementation detail, the effective gid is stored as
1277 * the first element of the supplementary group list, and
1278 * therefore the effective group list may be reordered to keep
1279 * the supplementary group list unchanged.
1280 */
1281 int
1282 setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1283 {
1284 gid_t rgid, egid;
1285 int error;
1286 kauth_cred_t my_cred, my_new_cred;
1287 posix_cred_t my_pcred;
1288
1289 DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
1290
1291 rgid = uap->rgid;
1292 egid = uap->egid;
1293
1294 if (rgid == (uid_t)-1)
1295 rgid = KAUTH_GID_NONE;
1296 if (egid == (uid_t)-1)
1297 egid = KAUTH_GID_NONE;
1298 AUDIT_ARG(egid, egid);
1299 AUDIT_ARG(rgid, rgid);
1300
1301 my_cred = kauth_cred_proc_ref(p);
1302 my_pcred = posix_cred_get(my_cred);
1303
1304 if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1305 rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
1306 rgid != my_pcred->cr_gid && /* allow rgid = egid */
1307 rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
1308 (egid != KAUTH_UID_NONE && /* allow no change of egid */
1309 egid != my_pcred->cr_groups[0] && /* allow no change of egid */
1310 egid != my_pcred->cr_gid && /* allow egid = egid */
1311 egid != my_pcred->cr_rgid && /* allow egid = rgid */
1312 egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
1313 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1314 kauth_cred_unref(&my_cred);
1315 return (error);
1316 }
1317
1318 /* get current credential and take a reference while we muck with it */
1319 for (;;) {
1320 uid_t new_egid = my_pcred->cr_gid;
1321 uid_t new_rgid = my_pcred->cr_rgid;
1322 uid_t svgid = KAUTH_UID_NONE;
1323
1324
1325 /*
1326 * Set the credential with new info. If there is no change,
1327 * we get back the same credential we passed in; if there is
1328 * a change, we drop the reference on the credential we
1329 * passed in. The subsequent compare is safe, because it is
1330 * a pointer compare rather than a contents compare.
1331 */
1332 if (egid == KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
1333 /* changing the effective GID */
1334 new_egid = egid;
1335 OSBitOrAtomic(P_SUGID, &p->p_flag);
1336 }
1337 if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) {
1338 /* changing the real GID */
1339 new_rgid = rgid;
1340 OSBitOrAtomic(P_SUGID, &p->p_flag);
1341 }
1342 /*
1343 * If the newly requested real gid or effective gid does
1344 * not match the saved gid, then set the saved gid to the
1345 * new effective gid. We are protected from escalation
1346 * by the prechecking.
1347 */
1348 if (my_pcred->cr_svgid != uap->rgid &&
1349 my_pcred->cr_svgid != uap->egid) {
1350 svgid = new_egid;
1351 OSBitOrAtomic(P_SUGID, &p->p_flag);
1352 }
1353
1354 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
1355 if (my_cred != my_new_cred) {
1356
1357 DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1358
1359 proc_lock(p);
1360 /* need to protect for a race where another thread
1361 * also changed the credential after we took our
1362 * reference. If p_ucred has changed then we
1363 * should restart this again with the new cred.
1364 */
1365 if (p->p_ucred != my_cred) {
1366 proc_unlock(p);
1367 kauth_cred_unref(&my_new_cred);
1368 /* try again */
1369 my_cred = kauth_cred_proc_ref(p);
1370 continue;
1371 }
1372 p->p_ucred = my_new_cred;
1373 /* update cred on proc */
1374 PROC_UPDATE_CREDS_ONPROC(p);
1375 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1376 proc_unlock(p);
1377 }
1378 break;
1379 }
1380 /* Drop old proc reference or our extra reference */
1381 kauth_cred_unref(&my_cred);
1382
1383 set_security_token(p);
1384 return (0);
1385 }
1386
1387
1388 /*
1389 * Set the per-thread override identity. The first parameter can be the
1390 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
1391 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1392 * means "revert to the per process credential"; otherwise, if permitted,
1393 * it changes the effective, real, and saved UIDs and GIDs for the current
1394 * thread to the requested UID and single GID, and clears all other GIDs.
1395 */
1396 int
1397 settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1398 {
1399 kauth_cred_t uc;
1400 struct uthread *uthread = get_bsdthread_info(current_thread());
1401 uid_t uid;
1402 gid_t gid;
1403
1404 uid = uap->uid;
1405 gid = uap->gid;
1406 AUDIT_ARG(uid, uid);
1407 AUDIT_ARG(gid, gid);
1408
1409 if (proc_suser(p) != 0)
1410 return (EPERM);
1411
1412 if (uid == KAUTH_UID_NONE) {
1413
1414 /* must already be assuming another identity in order to revert back */
1415 if ((uthread->uu_flag & UT_SETUID) == 0)
1416 return (EPERM);
1417
1418 /* revert to delayed binding of process credential */
1419 uc = kauth_cred_proc_ref(p);
1420 kauth_cred_unref(&uthread->uu_ucred);
1421 uthread->uu_ucred = uc;
1422 uthread->uu_flag &= ~UT_SETUID;
1423 } else {
1424 kauth_cred_t my_cred, my_new_cred;
1425
1426 /* cannot already be assuming another identity */
1427 if ((uthread->uu_flag & UT_SETUID) != 0) {
1428 return (EPERM);
1429 }
1430
1431 /*
1432 * Get a new credential instance from the old if this one
1433 * changes; otherwise kauth_cred_setuidgid() returns the
1434 * same credential. We take an extra reference on the
1435 * current credential while we muck with it, so we can do
1436 * the post-compare for changes by pointer.
1437 */
1438 kauth_cred_ref(uthread->uu_ucred);
1439 my_cred = uthread->uu_ucred;
1440 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
1441 if (my_cred != my_new_cred)
1442 uthread->uu_ucred = my_new_cred;
1443 uthread->uu_flag |= UT_SETUID;
1444
1445 /* Drop old uthread reference or our extra reference */
1446 kauth_cred_unref(&my_cred);
1447 }
1448 /*
1449 * XXX should potentially set per thread security token (there is
1450 * XXX none).
1451 * XXX it is unclear whether P_SUGID should be st at this point;
1452 * XXX in theory, it is being deprecated.
1453 */
1454 return (0);
1455 }
1456
1457
1458 /*
1459 * Set the per-thread override identity. Use this system call for a thread to
1460 * assume the identity of another process or to revert back to normal identity
1461 * of the current process.
1462 *
1463 * When the "assume" argument is non zero the current thread will assume the
1464 * identity of the process represented by the pid argument.
1465 *
1466 * When the assume argument is zero we revert back to our normal identity.
1467 */
1468 int
1469 settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1470 {
1471 proc_t target_proc;
1472 struct uthread *uthread = get_bsdthread_info(current_thread());
1473 kauth_cred_t my_cred, my_target_cred, my_new_cred;
1474 posix_cred_t my_target_pcred;
1475
1476 AUDIT_ARG(pid, uap->pid);
1477 AUDIT_ARG(value32, uap->assume);
1478
1479 if (proc_suser(p) != 0) {
1480 return (EPERM);
1481 }
1482
1483 /*
1484 * XXX should potentially set per thread security token (there is
1485 * XXX none).
1486 * XXX it is unclear whether P_SUGID should be st at this point;
1487 * XXX in theory, it is being deprecated.
1488 */
1489
1490 /*
1491 * assume argument tells us to assume the identity of the process with the
1492 * id passed in the pid argument.
1493 */
1494 if (uap->assume != 0) {
1495 /* can't do this if we have already assumed an identity */
1496 if ((uthread->uu_flag & UT_SETUID) != 0)
1497 return (EPERM);
1498
1499 target_proc = proc_find(uap->pid);
1500 /* can't assume the identity of the kernel process */
1501 if (target_proc == NULL || target_proc == kernproc) {
1502 if (target_proc!= NULL)
1503 proc_rele(target_proc);
1504 return (ESRCH);
1505 }
1506
1507 /*
1508 * Take a reference on the credential used in our target
1509 * process then use it as the identity for our current
1510 * thread. We take an extra reference on the current
1511 * credential while we muck with it, so we can do the
1512 * post-compare for changes by pointer.
1513 *
1514 * The post-compare is needed for the case that our process
1515 * credential has been changed to be identical to our thread
1516 * credential following our assumption of a per-thread one,
1517 * since the credential cache will maintain a unique instance.
1518 */
1519 kauth_cred_ref(uthread->uu_ucred);
1520 my_cred = uthread->uu_ucred;
1521 my_target_cred = kauth_cred_proc_ref(target_proc);
1522 my_target_pcred = posix_cred_get(my_target_cred);
1523 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
1524 if (my_cred != my_new_cred)
1525 uthread->uu_ucred = my_new_cred;
1526
1527 uthread->uu_flag |= UT_SETUID;
1528
1529 /* Drop old uthread reference or our extra reference */
1530 proc_rele(target_proc);
1531 kauth_cred_unref(&my_cred);
1532 kauth_cred_unref(&my_target_cred);
1533
1534 return (0);
1535 }
1536
1537 /*
1538 * Otherwise, we are reverting back to normal mode of operation where
1539 * delayed binding of the process credential sets the credential in
1540 * the thread (uu_ucred)
1541 */
1542 if ((uthread->uu_flag & UT_SETUID) == 0)
1543 return (EPERM);
1544
1545 /* revert to delayed binding of process credential */
1546 my_new_cred = kauth_cred_proc_ref(p);
1547 kauth_cred_unref(&uthread->uu_ucred);
1548 uthread->uu_ucred = my_new_cred;
1549 uthread->uu_flag &= ~UT_SETUID;
1550
1551 return (0);
1552 }
1553
1554
1555 /*
1556 * setgroups1
1557 *
1558 * Description: Internal implementation for both the setgroups and initgroups
1559 * system calls
1560 *
1561 * Parameters: gidsetsize Number of groups in set
1562 * gidset Pointer to group list
1563 * gmuid Base gid (initgroups only!)
1564 *
1565 * Returns: 0 Success
1566 * suser:EPERM Permision denied
1567 * EINVAL Invalid gidsetsize value
1568 * copyin:EFAULT Bad gidset or gidsetsize is
1569 * too large
1570 *
1571 * Notes: When called from a thread running under an assumed per-thread
1572 * identity, this function will operate against the per-thread
1573 * credential, rather than against the process credential. In
1574 * this specific case, the process credential is verified to
1575 * still be privileged at the time of the call, rather than the
1576 * per-thread credential for this operation to be permitted.
1577 *
1578 * This effectively means that setgroups/initigroups calls in
1579 * a thread running a per-thread credential should occur *after*
1580 * the settid call that created it, not before (unlike setuid,
1581 * which must be called after, since it will result in privilege
1582 * being dropped).
1583 *
1584 * When called normally (i.e. no per-thread assumed identity),
1585 * the per process credential is updated per POSIX.
1586 *
1587 * If the credential is changed as a result of this call, then we
1588 * flag the process as having set privilege since the last exec.
1589 */
1590 static int
1591 setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1592 {
1593 u_int ngrp;
1594 gid_t newgroups[NGROUPS] = { 0 };
1595 int error;
1596 kauth_cred_t my_cred, my_new_cred;
1597 struct uthread *uthread = get_bsdthread_info(current_thread());
1598
1599 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), gidsetsize, gidset, gmuid);
1600
1601 ngrp = gidsetsize;
1602 if (ngrp > NGROUPS)
1603 return (EINVAL);
1604
1605 if ( ngrp < 1 ) {
1606 ngrp = 1;
1607 } else {
1608 error = copyin(gidset,
1609 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1610 if (error) {
1611 return (error);
1612 }
1613 }
1614
1615 my_cred = kauth_cred_proc_ref(p);
1616 if ((error = suser(my_cred, &p->p_acflag))) {
1617 kauth_cred_unref(&my_cred);
1618 return (error);
1619 }
1620
1621 if ((uthread->uu_flag & UT_SETUID) != 0) {
1622 #if DEBUG_CRED
1623 int my_cred_flags = uthread->uu_ucred->cr_flags;
1624 #endif /* DEBUG_CRED */
1625 kauth_cred_unref(&my_cred);
1626
1627 /*
1628 * If this thread is under an assumed identity, set the
1629 * supplementary grouplist on the thread credential instead
1630 * of the process one. If we were the only reference holder,
1631 * the credential is updated in place, otherwise, our reference
1632 * is dropped and we get back a different cred with a reference
1633 * already held on it. Because this is per-thread, we don't
1634 * need the referencing/locking/retry required for per-process.
1635 */
1636 my_cred = uthread->uu_ucred;
1637 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1638 #if DEBUG_CRED
1639 if (my_cred != uthread->uu_ucred) {
1640 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred , uthread->uu_ucred ->cr_flags);
1641 }
1642 #endif /* DEBUG_CRED */
1643 } else {
1644
1645 /*
1646 * get current credential and take a reference while we muck
1647 * with it
1648 */
1649 for (;;) {
1650 /*
1651 * Set the credential with new info. If there is no
1652 * change, we get back the same credential we passed
1653 * in; if there is a change, we drop the reference on
1654 * the credential we passed in. The subsequent
1655 * compare is safe, because it is a pointer compare
1656 * rather than a contents compare.
1657 */
1658 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1659 if (my_cred != my_new_cred) {
1660
1661 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1662
1663 proc_lock(p);
1664 /*
1665 * We need to protect for a race where another
1666 * thread also changed the credential after we
1667 * took our reference. If p_ucred has
1668 * changed then we should restart this again
1669 * with the new cred.
1670 */
1671 if (p->p_ucred != my_cred) {
1672 proc_unlock(p);
1673 kauth_cred_unref(&my_new_cred);
1674 my_cred = kauth_cred_proc_ref(p);
1675 /* try again */
1676 continue;
1677 }
1678 p->p_ucred = my_new_cred;
1679 /* update cred on proc */
1680 PROC_UPDATE_CREDS_ONPROC(p);
1681 OSBitOrAtomic(P_SUGID, &p->p_flag);
1682 proc_unlock(p);
1683 }
1684 break;
1685 }
1686 /* Drop old proc reference or our extra reference */
1687 AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp);
1688 kauth_cred_unref(&my_cred);
1689
1690
1691 set_security_token(p);
1692 }
1693
1694 return (0);
1695 }
1696
1697
1698 /*
1699 * initgroups
1700 *
1701 * Description: Initialize the default supplementary groups list and set the
1702 * gmuid for use by the external group resolver (if any)
1703 *
1704 * Parameters: uap->gidsetsize Number of groups in set
1705 * uap->gidset Pointer to group list
1706 * uap->gmuid Base gid
1707 *
1708 * Returns: 0 Success
1709 * setgroups1:EPERM Permision denied
1710 * setgroups1:EINVAL Invalid gidsetsize value
1711 * setgroups1:EFAULT Bad gidset or gidsetsize is
1712 *
1713 * Notes: This function opts *IN* to memberd participation
1714 *
1715 * The normal purpose of this function is for a privileged
1716 * process to indicate supplementary groups and identity for
1717 * participation in extended group membership resolution prior
1718 * to dropping privilege by assuming a specific user identity.
1719 *
1720 * It is the first half of the primary mechanism whereby user
1721 * identity is established to the system by programs such as
1722 * /usr/bin/login. The second half is the drop of uid privilege
1723 * for a specific uid corresponding to the user.
1724 *
1725 * See also: setgroups1()
1726 */
1727 int
1728 initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1729 {
1730 DEBUG_CRED_ENTER("initgroups\n");
1731
1732 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
1733 }
1734
1735
1736 /*
1737 * setgroups
1738 *
1739 * Description: Initialize the default supplementary groups list
1740 *
1741 * Parameters: gidsetsize Number of groups in set
1742 * gidset Pointer to group list
1743 *
1744 * Returns: 0 Success
1745 * setgroups1:EPERM Permision denied
1746 * setgroups1:EINVAL Invalid gidsetsize value
1747 * setgroups1:EFAULT Bad gidset or gidsetsize is
1748 *
1749 * Notes: This functions opts *OUT* of memberd participation.
1750 *
1751 * This function exists for compatibility with POSIX. Most user
1752 * programs should use initgroups() instead to ensure correct
1753 * participation in group membership resolution when utilizing
1754 * a directory service for authentication.
1755 *
1756 * It is identical to an initgroups() call with a gmuid argument
1757 * of KAUTH_UID_NONE.
1758 *
1759 * See also: setgroups1()
1760 */
1761 int
1762 setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1763 {
1764 DEBUG_CRED_ENTER("setgroups\n");
1765
1766 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1767 }
1768
1769
1770 /*
1771 * Set the per-thread/per-process supplementary groups list.
1772 *
1773 * XXX implement setsgroups
1774 *
1775 */
1776
1777 int
1778 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1779 {
1780 return(ENOTSUP);
1781 }
1782
1783 /*
1784 * Set the per-thread/per-process whiteout groups list.
1785 *
1786 * XXX implement setwgroups
1787 *
1788 */
1789
1790 int
1791 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1792 {
1793 return(ENOTSUP);
1794 }
1795
1796
1797 /*
1798 * Check if gid is a member of the group set.
1799 *
1800 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1801 * XXX instead.
1802 */
1803 int
1804 groupmember(gid_t gid, kauth_cred_t cred)
1805 {
1806 int is_member;
1807
1808 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
1809 return (1);
1810 return (0);
1811 }
1812
1813
1814 /*
1815 * Test whether the specified credentials imply "super-user"
1816 * privilege; if so, and we have accounting info, set the flag
1817 * indicating use of super-powers.
1818 * Returns 0 or error.
1819 *
1820 * XXX This interface is going away; use kauth_cred_issuser() directly
1821 * XXX instead.
1822 *
1823 * Note: This interface exists to implement the "has used privilege"
1824 * bit (ASU) in the p_acflags field of the process, which is
1825 * only externalized via private sysctl and in process accounting
1826 * records. The flag is technically not required in either case.
1827 */
1828 int
1829 suser(kauth_cred_t cred, u_short *acflag)
1830 {
1831 #if DIAGNOSTIC
1832 if (!IS_VALID_CRED(cred))
1833 panic("suser");
1834 #endif
1835 if (kauth_cred_getuid(cred) == 0) {
1836 if (acflag)
1837 *acflag |= ASU;
1838 return (0);
1839 }
1840 return (EPERM);
1841 }
1842
1843
1844 /*
1845 * getlogin
1846 *
1847 * Description: Get login name, if available.
1848 *
1849 * Parameters: uap->namebuf User buffer for return
1850 * uap->namelen User buffer length
1851 *
1852 * Returns: 0 Success
1853 * copyout:EFAULT
1854 *
1855 * Notes: Intended to obtain a string containing the user name of the
1856 * user associated with the controlling terminal for the calling
1857 * process.
1858 *
1859 * Not very useful on modern systems, due to inherent length
1860 * limitations for the static array in the session structure
1861 * which is used to store the login name.
1862 *
1863 * Permitted to return NULL
1864 *
1865 * XXX: Belongs in kern_proc.c
1866 */
1867 int
1868 getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1869 {
1870 char buffer[MAXLOGNAME+1];
1871 struct session * sessp;
1872
1873 bzero(buffer, MAXLOGNAME+1);
1874
1875 sessp = proc_session(p);
1876
1877 if (uap->namelen > MAXLOGNAME)
1878 uap->namelen = MAXLOGNAME;
1879
1880 if(sessp != SESSION_NULL) {
1881 session_lock(sessp);
1882 bcopy( sessp->s_login, buffer, uap->namelen);
1883 session_unlock(sessp);
1884 }
1885 session_rele(sessp);
1886
1887 return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
1888 }
1889
1890
1891 /*
1892 * setlogin
1893 *
1894 * Description: Set login name.
1895 *
1896 * Parameters: uap->namebuf User buffer containing name
1897 *
1898 * Returns: 0 Success
1899 * suser:EPERM Permission denied
1900 * copyinstr:EFAULT User buffer invalid
1901 * copyinstr:EINVAL Supplied name was too long
1902 *
1903 * Notes: This is a utility system call to support getlogin().
1904 *
1905 * XXX: Belongs in kern_proc.c
1906 */
1907 int
1908 setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1909 {
1910 int error;
1911 size_t dummy=0;
1912 char buffer[MAXLOGNAME+1];
1913 struct session * sessp;
1914
1915 if ((error = proc_suser(p)))
1916 return (error);
1917
1918 bzero(&buffer[0], MAXLOGNAME+1);
1919
1920
1921 error = copyinstr(uap->namebuf,
1922 (caddr_t) &buffer[0],
1923 MAXLOGNAME - 1, (size_t *)&dummy);
1924
1925 sessp = proc_session(p);
1926
1927 if (sessp != SESSION_NULL) {
1928 session_lock(sessp);
1929 bcopy(buffer, sessp->s_login, MAXLOGNAME);
1930 session_unlock(sessp);
1931 session_rele(sessp);
1932 }
1933
1934
1935 if (!error) {
1936 AUDIT_ARG(text, buffer);
1937 } else if (error == ENAMETOOLONG)
1938 error = EINVAL;
1939 return (error);
1940 }
1941
1942
1943 /* Set the secrity token of the task with current euid and eguid */
1944 /*
1945 * XXX This needs to change to give the task a reference and/or an opaque
1946 * XXX identifier.
1947 */
1948 int
1949 set_security_token(proc_t p)
1950 {
1951 security_token_t sec_token;
1952 audit_token_t audit_token;
1953 kauth_cred_t my_cred;
1954 posix_cred_t my_pcred;
1955 host_priv_t host_priv;
1956
1957 /*
1958 * Don't allow a vfork child to override the parent's token settings
1959 * (since they share a task). Instead, the child will just have to
1960 * suffer along using the parent's token until the exec(). It's all
1961 * undefined behavior anyway, right?
1962 */
1963 if (p->task == current_task()) {
1964 uthread_t uthread;
1965 uthread = (uthread_t)get_bsdthread_info(current_thread());
1966 if (uthread->uu_flag & UT_VFORK)
1967 return (1);
1968 }
1969
1970 my_cred = kauth_cred_proc_ref(p);
1971 my_pcred = posix_cred_get(my_cred);
1972
1973 /* XXX mach_init doesn't have a p_ucred when it calls this function */
1974 if (IS_VALID_CRED(my_cred)) {
1975 sec_token.val[0] = kauth_cred_getuid(my_cred);
1976 sec_token.val[1] = kauth_cred_getgid(my_cred);
1977 } else {
1978 sec_token.val[0] = 0;
1979 sec_token.val[1] = 0;
1980 }
1981
1982 /*
1983 * The current layout of the Mach audit token explicitly
1984 * adds these fields. But nobody should rely on such
1985 * a literal representation. Instead, the BSM library
1986 * provides a function to convert an audit token into
1987 * a BSM subject. Use of that mechanism will isolate
1988 * the user of the trailer from future representation
1989 * changes.
1990 */
1991 audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1992 audit_token.val[1] = my_pcred->cr_uid;
1993 audit_token.val[2] = my_pcred->cr_gid;
1994 audit_token.val[3] = my_pcred->cr_ruid;
1995 audit_token.val[4] = my_pcred->cr_rgid;
1996 audit_token.val[5] = p->p_pid;
1997 audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
1998 audit_token.val[7] = p->p_idversion;
1999
2000 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
2001 #if CONFIG_MACF
2002 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
2003 host_priv = HOST_PRIV_NULL;
2004 #endif
2005 kauth_cred_unref(&my_cred);
2006
2007 #if DEVELOPMENT || DEBUG
2008 /*
2009 * Update the pid an proc name for importance base if any
2010 */
2011 task_importance_update_owner_info(p->task);
2012 #endif
2013
2014 return (host_security_set_task_token(host_security_self(),
2015 p->task,
2016 sec_token,
2017 audit_token,
2018 host_priv) != KERN_SUCCESS);
2019 }
2020
2021
2022 /*
2023 * Fill in a struct xucred based on a kauth_cred_t.
2024 */
2025 __private_extern__
2026 void
2027 cru2x(kauth_cred_t cr, struct xucred *xcr)
2028 {
2029 posix_cred_t pcr = posix_cred_get(cr);
2030
2031 bzero(xcr, sizeof(*xcr));
2032 xcr->cr_version = XUCRED_VERSION;
2033 xcr->cr_uid = kauth_cred_getuid(cr);
2034 xcr->cr_ngroups = pcr->cr_ngroups;
2035 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
2036 }
2037
2038 #if CONFIG_LCTX
2039
2040 /*
2041 * Set Login Context ID
2042 */
2043 /*
2044 * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
2045 * LCTX by its own locks.
2046 */
2047 int
2048 setlcid(proc_t p0, struct setlcid_args *uap, __unused int32_t *retval)
2049 {
2050 proc_t p;
2051 struct lctx *l;
2052 int error = 0;
2053 int refheld = 0;
2054
2055 AUDIT_ARG(pid, uap->pid);
2056 AUDIT_ARG(value32, uap->lcid);
2057 if (uap->pid == LCID_PROC_SELF) { /* Create/Join/Leave */
2058 p = p0;
2059 } else { /* Adopt/Orphan */
2060 p = proc_find(uap->pid);
2061 if (p == NULL)
2062 return (ESRCH);
2063 refheld = 1;
2064 }
2065
2066 #if CONFIG_MACF
2067 error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
2068 if (error)
2069 goto out;
2070 #endif
2071
2072 switch (uap->lcid) {
2073 /* Leave/Orphan */
2074 case LCID_REMOVE:
2075
2076 /* Only root may Leave/Orphan. */
2077 if (!kauth_cred_issuser(kauth_cred_get())) {
2078 error = EPERM;
2079 goto out;
2080 }
2081
2082 /* Process not in login context. */
2083 if (p->p_lctx == NULL) {
2084 error = ENOATTR;
2085 goto out;
2086 }
2087
2088 l = NULL;
2089
2090 break;
2091
2092 /* Create */
2093 case LCID_CREATE:
2094
2095 /* Create only valid for self! */
2096 if (uap->pid != LCID_PROC_SELF) {
2097 error = EPERM;
2098 goto out;
2099 }
2100
2101 /* Already in a login context. */
2102 if (p->p_lctx != NULL) {
2103 error = EPERM;
2104 goto out;
2105 }
2106
2107 l = lccreate();
2108 if (l == NULL) {
2109 error = ENOMEM;
2110 goto out;
2111 }
2112
2113 LCTX_LOCK(l);
2114
2115 break;
2116
2117 /* Join/Adopt */
2118 default:
2119
2120 /* Only root may Join/Adopt. */
2121 if (!kauth_cred_issuser(kauth_cred_get())) {
2122 error = EPERM;
2123 goto out;
2124 }
2125
2126 l = lcfind(uap->lcid);
2127 if (l == NULL) {
2128 error = ENOATTR;
2129 goto out;
2130 }
2131
2132 break;
2133 }
2134
2135 ALLLCTX_LOCK;
2136 leavelctx(p);
2137 enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
2138 ALLLCTX_UNLOCK;
2139
2140 out:
2141 if (refheld != 0)
2142 proc_rele(p);
2143 return (error);
2144 }
2145
2146 /*
2147 * Get Login Context ID
2148 */
2149 /*
2150 * MPSAFE - membership of (visible) process in a login context
2151 * protected by the all-context lock.
2152 */
2153 int
2154 getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2155 {
2156 proc_t p;
2157 int error = 0;
2158 int refheld = 0;
2159
2160 AUDIT_ARG(pid, uap->pid);
2161 if (uap->pid == LCID_PROC_SELF) {
2162 p = p0;
2163 } else {
2164 p = proc_find(uap->pid);
2165 if (p == NULL)
2166 return (ESRCH);
2167 refheld = 1;
2168 }
2169
2170 #if CONFIG_MACF
2171 error = mac_proc_check_getlcid(p0, p, uap->pid);
2172 if (error)
2173 goto out;
2174 #endif
2175 ALLLCTX_LOCK;
2176 if (p->p_lctx == NULL) {
2177 error = ENOATTR;
2178 ALLLCTX_UNLOCK;
2179 goto out;
2180 }
2181 *retval = p->p_lctx->lc_id;
2182 ALLLCTX_UNLOCK;
2183 out:
2184 if (refheld != 0)
2185 proc_rele(p);
2186
2187 return (error);
2188 }
2189 #else /* LCTX */
2190 int
2191 setlcid(proc_t p0, struct setlcid_args *uap, int32_t *retval)
2192 {
2193
2194 return (ENOSYS);
2195 }
2196
2197 int
2198 getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2199 {
2200
2201 return (ENOSYS);
2202 }
2203 #endif /* !LCTX */