]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-1456.1.26.tar.gz
[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 #if CONFIG_MACF_MACH
108 #include <secuity/mac_mach_internal.h>
109 #endif
110 #endif
111
112 #include <sys/mount_internal.h>
113 #include <sys/sysproto.h>
114 #include <mach/message.h>
115 #include <mach/host_security.h>
116
117 #include <kern/host.h>
118 #include <kern/task.h> /* for current_task() */
119 #include <kern/assert.h>
120
121
122 /*
123 * Credential debugging; we can track entry into a function that might
124 * change a credential, and we can track actual credential changes that
125 * result.
126 *
127 * Note: Does *NOT* currently include per-thread credential changes
128 *
129 * We don't use kauth_cred_print() in current debugging, but it
130 * can be used if needed when debugging is active.
131 */
132 #if DEBUG_CRED
133 #define DEBUG_CRED_ENTER printf
134 #define DEBUG_CRED_CHANGE printf
135 extern void kauth_cred_print(kauth_cred_t cred);
136 #else /* !DEBUG_CRED */
137 #define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
138 #define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
139 #endif /* !DEBUG_CRED */
140
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, uthread->uu_ucred->cr_ruid)))
364 return (error);
365 if ((error = suword(uap->gidp, uthread->uu_ucred->cr_rgid)))
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
452 /* grab reference while we muck around with the credential */
453 cred = kauth_cred_get_with_ref();
454
455 if ((ngrp = uap->gidsetsize) == 0) {
456 *retval = cred->cr_ngroups;
457 kauth_cred_unref(&cred);
458 return (0);
459 }
460 if (ngrp < cred->cr_ngroups) {
461 kauth_cred_unref(&cred);
462 return (EINVAL);
463 }
464 ngrp = cred->cr_ngroups;
465 if ((error = copyout((caddr_t)cred->cr_groups,
466 uap->gidset,
467 ngrp * sizeof(gid_t)))) {
468 kauth_cred_unref(&cred);
469 return (error);
470 }
471 kauth_cred_unref(&cred);
472 *retval = ngrp;
473 return (0);
474 }
475
476
477 /*
478 * Return the per-thread/per-process supplementary groups list.
479 *
480 * XXX implement getsgroups
481 *
482 */
483
484 int
485 getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
486 {
487 return(ENOTSUP);
488 }
489
490 /*
491 * Return the per-thread/per-process whiteout groups list.
492 *
493 * XXX implement getwgroups
494 *
495 */
496
497 int
498 getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
499 {
500 return(ENOTSUP);
501 }
502
503
504 /*
505 * setsid
506 *
507 * Description: Create a new session and set the process group ID to the
508 * session ID
509 *
510 * Parameters: (void)
511 *
512 * Returns: 0 Success
513 * EPERM Permission denied
514 *
515 * Notes: If the calling process is not the process group leader; there
516 * is no existing process group with its ID, and we are not
517 * currently in vfork, then this function will create a new
518 * session, a new process group, and put the caller in the
519 * process group (as the sole member) and make it the session
520 * leader (as the sole process in the session).
521 *
522 * The existing controlling tty (if any) will be dissociated
523 * from the process, and the next non-O_NOCTTY open of a tty
524 * will establish a new controlling tty.
525 *
526 * XXX: Belongs in kern_proc.c
527 */
528 int
529 setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
530 {
531 struct pgrp * pg = PGRP_NULL;
532
533 if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
534 if (pg != PGRP_NULL)
535 pg_rele(pg);
536 return (EPERM);
537 } else {
538 /* enter pgrp works with its own pgrp refcount */
539 (void)enterpgrp(p, p->p_pid, 1);
540 *retval = p->p_pid;
541 return (0);
542 }
543 }
544
545
546 /*
547 * setpgid
548 *
549 * Description: set process group ID for job control
550 *
551 * Parameters: uap->pid Process to change
552 * uap->pgid Process group to join or create
553 *
554 * Returns: 0 Success
555 * ESRCH pid is not the caller or a child of
556 * the caller
557 * enterpgrp:ESRCH No such process
558 * EACCES Permission denied due to exec
559 * EINVAL Invalid argument
560 * EPERM The target process is not in the same
561 * session as the calling process
562 * EPERM The target process is a session leader
563 * EPERM pid and pgid are not the same, and
564 * there is no process in the calling
565 * process whose process group ID matches
566 * pgid
567 *
568 * Notes: This function will cause the target process to either join
569 * an existing process process group, or create a new process
570 * group in the session of the calling process. It cannot be
571 * used to change the process group ID of a process which is
572 * already a session leader.
573 *
574 * If the target pid is 0, the pid of the calling process is
575 * substituted as the new target; if pgid is 0, the target pid
576 * is used as the target process group ID.
577 *
578 * Legacy: This system call entry point is also used to implement the
579 * legacy library routine setpgrp(), which under POSIX
580 *
581 * XXX: Belongs in kern_proc.c
582 */
583 int
584 setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval)
585 {
586 proc_t targp = PROC_NULL; /* target process */
587 struct pgrp *pg = PGRP_NULL; /* target pgrp */
588 int error = 0;
589 int refheld = 0;
590 int samesess = 0;
591 struct session * curp_sessp = SESSION_NULL;
592 struct session * targp_sessp = SESSION_NULL;
593
594 curp_sessp = proc_session(curp);
595
596 if (uap->pid != 0 && uap->pid != curp->p_pid) {
597 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
598 if (targp != PROC_NULL)
599 refheld = 1;
600 error = ESRCH;
601 goto out;
602 }
603 refheld = 1;
604 targp_sessp = proc_session(targp);
605 if (targp_sessp != curp_sessp) {
606 error = EPERM;
607 goto out;
608 }
609 if (targp->p_flag & P_EXEC) {
610 error = EACCES;
611 goto out;
612 }
613 } else {
614 targp = curp;
615 targp_sessp = proc_session(targp);
616 }
617
618 if (SESS_LEADER(targp, targp_sessp)) {
619 error = EPERM;
620 goto out;
621 }
622 if (targp_sessp != SESSION_NULL) {
623 session_rele(targp_sessp);
624 targp_sessp = SESSION_NULL;
625 }
626
627 if (uap->pgid < 0) {
628 error = EINVAL;
629 goto out;
630 }
631 if (uap->pgid == 0)
632 uap->pgid = targp->p_pid;
633 else if (uap->pgid != targp->p_pid) {
634 if ((pg = pgfind(uap->pgid)) == 0){
635 error = EPERM;
636 goto out;
637 }
638 samesess = (pg->pg_session != curp_sessp);
639 pg_rele(pg);
640 if (samesess != 0) {
641 error = EPERM;
642 goto out;
643 }
644 }
645 error = enterpgrp(targp, uap->pgid, 0);
646 out:
647 if (targp_sessp != SESSION_NULL)
648 session_rele(targp_sessp);
649 if (curp_sessp != SESSION_NULL)
650 session_rele(curp_sessp);
651 if (refheld != 0)
652 proc_rele(targp);
653 return(error);
654 }
655
656
657 /*
658 * issetugid
659 *
660 * Description: Is current process tainted by uid or gid changes system call
661 *
662 * Parameters: (void)
663 *
664 * Returns: 0 Not tainted
665 * 1 Tainted
666 *
667 * Notes: A process is considered tainted if it was created as a retult
668 * of an execve call from an imnage that had either the SUID or
669 * SGID bit set on the executable, or if it has changed any of its
670 * real, effective, or saved user or group IDs since beginning
671 * execution.
672 */
673 int
674 issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
675 {
676 /*
677 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
678 * we use P_SUGID because we consider changing the owners as
679 * "tainting" as well.
680 * This is significant for procs that start as root and "become"
681 * a user without an exec - programs cannot know *everything*
682 * that libc *might* have put in their data segment.
683 */
684
685 *retval = (p->p_flag & P_SUGID) ? 1 : 0;
686 return (0);
687 }
688
689
690 /*
691 * setuid
692 *
693 * Description: Set user ID system call
694 *
695 * Parameters: uap->uid uid to set
696 *
697 * Returns: 0 Success
698 * suser:EPERM Permission denied
699 *
700 * Notes: If called by a privileged process, this function will set the
701 * real, effective, and saved uid to the requested value.
702 *
703 * If called from an unprivileged process, but uid is equal to the
704 * real or saved uid, then the effective uid will be set to the
705 * requested value, but the real and saved uid will not change.
706 *
707 * If the credential is changed as a result of this call, then we
708 * flag the process as having set privilege since the last exec.
709 */
710 int
711 setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
712 {
713 uid_t uid;
714 uid_t svuid = KAUTH_UID_NONE;
715 uid_t ruid = KAUTH_UID_NONE;
716 uid_t gmuid = KAUTH_UID_NONE;
717 int error;
718 kauth_cred_t my_cred, my_new_cred;
719
720
721 uid = uap->uid;
722
723 my_cred = kauth_cred_proc_ref(p);
724
725 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);
726 AUDIT_ARG(uid, uid);
727
728 if (uid != my_cred->cr_ruid && /* allow setuid(getuid()) */
729 uid != my_cred->cr_svuid && /* allow setuid(saved uid) */
730 (error = suser(my_cred, &p->p_acflag))) {
731 kauth_cred_unref(&my_cred);
732 return (error);
733 }
734 /*
735 * Everything's okay, do it.
736 */
737
738 /*
739 * If we are priviledged, then set the saved and real UID too;
740 * otherwise, just set the effective UID
741 */
742 if (suser(my_cred, &p->p_acflag) == 0) {
743 svuid = uid;
744 ruid = uid;
745 /*
746 * Transfer proc count to new user.
747 * chgproccnt uses list lock for protection
748 */
749 (void)chgproccnt(uid, 1);
750 (void)chgproccnt(my_cred->cr_ruid, -1);
751 }
752
753 /* get current credential and take a reference while we muck with it */
754 for (;;) {
755 /*
756 * Only set the gmuid if the current cred has not opt'ed out;
757 * this normally only happens when calling setgroups() instead
758 * of initgroups() to set an explicit group list, or one of the
759 * other group manipulation functions is invoked and results in
760 * a dislocation (i.e. the credential group membership changes
761 * to something other than the default list for the user, as
762 * in entering a group or leaving an exclusion group).
763 */
764 if (!(my_cred->cr_flags & CRF_NOMEMBERD))
765 gmuid = uid;
766
767 /*
768 * Set the credential with new info. If there is no change,
769 * we get back the same credential we passed in; if there is
770 * a change, we drop the reference on the credential we
771 * passed in. The subsequent compare is safe, because it is
772 * a pointer compare rather than a contents compare.
773 */
774 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
775 if (my_cred != my_new_cred) {
776
777 DEBUG_CRED_CHANGE("setuid 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);
778
779 proc_lock(p);
780 /*
781 * We need to protect for a race where another thread
782 * also changed the credential after we took our
783 * reference. If p_ucred has changed then we should
784 * restart this again with the new cred.
785 */
786 if (p->p_ucred != my_cred) {
787 proc_unlock(p);
788 kauth_cred_unref(&my_new_cred);
789 my_cred = kauth_cred_proc_ref(p);
790 /* try again */
791 continue;
792 }
793 p->p_ucred = my_new_cred;
794 OSBitOrAtomic(P_SUGID, &p->p_flag);
795 proc_unlock(p);
796 }
797 break;
798 }
799 /* Drop old proc reference or our extra reference */
800 kauth_cred_unref(&my_cred);
801
802 set_security_token(p);
803 return (0);
804 }
805
806
807 /*
808 * seteuid
809 *
810 * Description: Set effective user ID system call
811 *
812 * Parameters: uap->euid effective uid to set
813 *
814 * Returns: 0 Success
815 * suser:EPERM Permission denied
816 *
817 * Notes: If called by a privileged process, or called from an
818 * unprivileged process but euid is equal to the real or saved
819 * uid, then the effective uid will be set to the requested
820 * value, but the real and saved uid will not change.
821 *
822 * If the credential is changed as a result of this call, then we
823 * flag the process as having set privilege since the last exec.
824 */
825 int
826 seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
827 {
828 uid_t euid;
829 int error;
830 kauth_cred_t my_cred, my_new_cred;
831
832 DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
833
834 euid = uap->euid;
835 AUDIT_ARG(euid, euid);
836
837 my_cred = kauth_cred_proc_ref(p);
838
839 if (euid != my_cred->cr_ruid && euid != my_cred->cr_svuid &&
840 (error = suser(my_cred, &p->p_acflag))) {
841 kauth_cred_unref(&my_cred);
842 return (error);
843 }
844
845 /*
846 * Everything's okay, do it. Copy credentials so other references do
847 * not see our changes. get current credential and take a reference
848 * while we muck with it
849 */
850 for (;;) {
851 /*
852 * Set the credential with new info. If there is no change,
853 * we get back the same credential we passed in; if there is
854 * a change, we drop the reference on the credential we
855 * passed in. The subsequent compare is safe, because it is
856 * a pointer compare rather than a contents compare.
857 */
858 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_cred->cr_gmuid);
859
860 if (my_cred != my_new_cred) {
861
862 DEBUG_CRED_CHANGE("seteuid 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);
863
864 proc_lock(p);
865 /*
866 * We need to protect for a race where another thread
867 * also changed the credential after we took our
868 * reference. If p_ucred has changed then we
869 * should restart this again with the new cred.
870 */
871 if (p->p_ucred != my_cred) {
872 proc_unlock(p);
873 kauth_cred_unref(&my_new_cred);
874 my_cred = kauth_cred_proc_ref(p);
875 /* try again */
876 continue;
877 }
878 p->p_ucred = my_new_cred;
879 OSBitOrAtomic(P_SUGID, &p->p_flag);
880 proc_unlock(p);
881 }
882 break;
883 }
884 /* drop old proc reference or our extra reference */
885 kauth_cred_unref(&my_cred);
886
887 set_security_token(p);
888 return (0);
889 }
890
891
892 /*
893 * setreuid
894 *
895 * Description: Set real and effective user ID system call
896 *
897 * Parameters: uap->ruid real uid to set
898 * uap->euid effective uid to set
899 *
900 * Returns: 0 Success
901 * suser:EPERM Permission denied
902 *
903 * Notes: A value of -1 is a special case indicating that the uid for
904 * which that value is specified not be changed. If both values
905 * are specified as -1, no action is taken.
906 *
907 * If called by a privileged process, the real and effective uid
908 * will be set to the new value(s) specified.
909 *
910 * If called from an unprivileged process, the real uid may be
911 * set to the current value of the real uid, or to the current
912 * value of the saved uid. The effective uid may be set to the
913 * current value of any of the effective, real, or saved uid.
914 *
915 * If the newly requested real uid or effective uid does not
916 * match the saved uid, then set the saved uid to the new
917 * effective uid (potentially unrecoverably dropping saved
918 * privilege).
919 *
920 * If the credential is changed as a result of this call, then we
921 * flag the process as having set privilege since the last exec.
922 */
923 int
924 setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
925 {
926 uid_t ruid, euid;
927 int error;
928 kauth_cred_t my_cred, my_new_cred;
929
930 DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
931
932 ruid = uap->ruid;
933 euid = uap->euid;
934 if (ruid == (uid_t)-1)
935 ruid = KAUTH_UID_NONE;
936 if (euid == (uid_t)-1)
937 euid = KAUTH_UID_NONE;
938 AUDIT_ARG(euid, euid);
939 AUDIT_ARG(ruid, ruid);
940
941 my_cred = kauth_cred_proc_ref(p);
942
943 if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
944 ruid != my_cred->cr_ruid && /* allow ruid = ruid */
945 ruid != my_cred->cr_uid && /* allow ruid = euid */
946 ruid != my_cred->cr_svuid) || /* allow ruid = svuid */
947 (euid != KAUTH_UID_NONE && /* allow no change of euid */
948 euid != my_cred->cr_uid && /* allow euid = euid */
949 euid != my_cred->cr_ruid && /* allow euid = ruid */
950 euid != my_cred->cr_svuid)) && /* allow euid = svui */
951 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
952 kauth_cred_unref(&my_cred);
953 return (error);
954 }
955
956 /*
957 * Everything's okay, do it. Copy credentials so other references do
958 * not see our changes. get current credential and take a reference
959 * while we muck with it
960 */
961 for (;;) {
962 uid_t new_euid;
963 uid_t new_ruid;
964 uid_t svuid = KAUTH_UID_NONE;
965
966 new_euid = my_cred->cr_uid;
967 new_ruid = my_cred->cr_ruid;
968
969 /*
970 * Set the credential with new info. If there is no change,
971 * we get back the same credential we passed in; if there is
972 * a change, we drop the reference on the credential we
973 * passed in. The subsequent compare is safe, because it is
974 * a pointer compare rather than a contents compare.
975 */
976 if (euid == KAUTH_UID_NONE && my_cred->cr_uid != euid) {
977 /* changing the effective UID */
978 new_euid = euid;
979 OSBitOrAtomic(P_SUGID, &p->p_flag);
980 }
981 if (ruid != KAUTH_UID_NONE && my_cred->cr_ruid != ruid) {
982 /* changing the real UID; must do user accounting */
983 /* chgproccnt uses list lock for protection */
984 (void)chgproccnt(ruid, 1);
985 (void)chgproccnt(my_cred->cr_ruid, -1);
986 new_ruid = ruid;
987 OSBitOrAtomic(P_SUGID, &p->p_flag);
988 }
989 /*
990 * If the newly requested real uid or effective uid does
991 * not match the saved uid, then set the saved uid to the
992 * new effective uid. We are protected from escalation
993 * by the prechecking.
994 */
995 if (my_cred->cr_svuid != uap->ruid &&
996 my_cred->cr_svuid != uap->euid) {
997 svuid = new_euid;
998 OSBitOrAtomic(P_SUGID, &p->p_flag);
999 }
1000
1001 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_cred->cr_gmuid);
1002
1003 if (my_cred != my_new_cred) {
1004
1005 DEBUG_CRED_CHANGE("setreuid 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);
1006
1007 proc_lock(p);
1008 /*
1009 * We need to protect for a race where another thread
1010 * also changed the credential after we took our
1011 * reference. If p_ucred has changed then we should
1012 * restart this again with the new cred.
1013 */
1014 if (p->p_ucred != my_cred) {
1015 proc_unlock(p);
1016 kauth_cred_unref(&my_new_cred);
1017 my_cred = kauth_cred_proc_ref(p);
1018 /* try again */
1019 continue;
1020 }
1021 p->p_ucred = my_new_cred;
1022 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1023 proc_unlock(p);
1024 }
1025 break;
1026 }
1027 /* drop old proc reference or our extra reference */
1028 kauth_cred_unref(&my_cred);
1029
1030 set_security_token(p);
1031 return (0);
1032 }
1033
1034
1035 /*
1036 * setgid
1037 *
1038 * Description: Set group ID system call
1039 *
1040 * Parameters: uap->gid gid to set
1041 *
1042 * Returns: 0 Success
1043 * suser:EPERM Permission denied
1044 *
1045 * Notes: If called by a privileged process, this function will set the
1046 * real, effective, and saved gid to the requested value.
1047 *
1048 * If called from an unprivileged process, but gid is equal to the
1049 * real or saved gid, then the effective gid will be set to the
1050 * requested value, but the real and saved gid will not change.
1051 *
1052 * If the credential is changed as a result of this call, then we
1053 * flag the process as having set privilege since the last exec.
1054 *
1055 * As an implementation detail, the effective gid is stored as
1056 * the first element of the supplementary group list, and
1057 * therefore the effective group list may be reordered to keep
1058 * the supplementary group list unchanged.
1059 */
1060 int
1061 setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
1062 {
1063 gid_t gid;
1064 gid_t rgid = KAUTH_GID_NONE;
1065 gid_t svgid = KAUTH_GID_NONE;
1066 int error;
1067 kauth_cred_t my_cred, my_new_cred;
1068
1069 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
1070
1071 gid = uap->gid;
1072 AUDIT_ARG(gid, gid);
1073
1074 my_cred = kauth_cred_proc_ref(p);
1075
1076 if (gid != my_cred->cr_rgid && /* allow setgid(getgid()) */
1077 gid != my_cred->cr_svgid && /* allow setgid(saved gid) */
1078 (error = suser(my_cred, &p->p_acflag))) {
1079 kauth_cred_unref(&my_cred);
1080 return (error);
1081 }
1082
1083 /*
1084 * If we are priviledged, then set the saved and real GID too;
1085 * otherwise, just set the effective GID
1086 */
1087 if (suser(my_cred, &p->p_acflag) == 0) {
1088 svgid = gid;
1089 rgid = gid;
1090 }
1091
1092 /* get current credential and take a reference while we muck with it */
1093 for (;;) {
1094
1095 /*
1096 * Set the credential with new info. If there is no change,
1097 * we get back the same credential we passed in; if there is
1098 * a change, we drop the reference on the credential we
1099 * passed in. The subsequent compare is safe, because it is
1100 * a pointer compare rather than a contents compare.
1101 */
1102 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
1103 if (my_cred != my_new_cred) {
1104
1105 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);
1106
1107 proc_lock(p);
1108 /*
1109 * We need to protect for a race where another thread
1110 * also changed the credential after we took our
1111 * reference. If p_ucred has changed then we
1112 * should restart this again with the new cred.
1113 */
1114 if (p->p_ucred != my_cred) {
1115 proc_unlock(p);
1116 kauth_cred_unref(&my_new_cred);
1117 /* try again */
1118 my_cred = kauth_cred_proc_ref(p);
1119 continue;
1120 }
1121 p->p_ucred = my_new_cred;
1122 OSBitOrAtomic(P_SUGID, &p->p_flag);
1123 proc_unlock(p);
1124 }
1125 break;
1126 }
1127 /* Drop old proc reference or our extra reference */
1128 kauth_cred_unref(&my_cred);
1129
1130 set_security_token(p);
1131 return (0);
1132 }
1133
1134
1135 /*
1136 * setegid
1137 *
1138 * Description: Set effective group ID system call
1139 *
1140 * Parameters: uap->egid effective gid to set
1141 *
1142 * Returns: 0 Success
1143 * suser:EPERM
1144 *
1145 * Notes: If called by a privileged process, or called from an
1146 * unprivileged process but egid is equal to the real or saved
1147 * gid, then the effective gid will be set to the requested
1148 * value, but the real and saved gid will not change.
1149 *
1150 * If the credential is changed as a result of this call, then we
1151 * flag the process as having set privilege since the last exec.
1152 *
1153 * As an implementation detail, the effective gid is stored as
1154 * the first element of the supplementary group list, and
1155 * therefore the effective group list may be reordered to keep
1156 * the supplementary group list unchanged.
1157 */
1158 int
1159 setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1160 {
1161 gid_t egid;
1162 int error;
1163 kauth_cred_t my_cred, my_new_cred;
1164
1165 DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
1166
1167 egid = uap->egid;
1168 AUDIT_ARG(egid, egid);
1169
1170 my_cred = kauth_cred_proc_ref(p);
1171
1172 if (egid != my_cred->cr_rgid &&
1173 egid != my_cred->cr_svgid &&
1174 (error = suser(my_cred, &p->p_acflag))) {
1175 kauth_cred_unref(&my_cred);
1176 return (error);
1177 }
1178
1179 /* get current credential and take a reference while we muck with it */
1180 for (;;) {
1181 /*
1182 * Set the credential with new info. If there is no change,
1183 * we get back the same credential we passed in; if there is
1184 * a change, we drop the reference on the credential we
1185 * passed in. The subsequent compare is safe, because it is
1186 * a pointer compare rather than a contents compare.
1187 */
1188 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
1189 if (my_cred != my_new_cred) {
1190
1191 DEBUG_CRED_CHANGE("setegid(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);
1192
1193 proc_lock(p);
1194 /*
1195 * We need to protect for a race where another thread
1196 * also changed the credential after we took our
1197 * reference. If p_ucred has changed then we
1198 * should restart this again with the new cred.
1199 */
1200 if (p->p_ucred != my_cred) {
1201 proc_unlock(p);
1202 kauth_cred_unref(&my_new_cred);
1203 /* try again */
1204 my_cred = kauth_cred_proc_ref(p);
1205 continue;
1206 }
1207 p->p_ucred = my_new_cred;
1208 OSBitOrAtomic(P_SUGID, &p->p_flag);
1209 proc_unlock(p);
1210 }
1211 break;
1212 }
1213
1214 /* Drop old proc reference or our extra reference */
1215 kauth_cred_unref(&my_cred);
1216
1217 set_security_token(p);
1218 return (0);
1219 }
1220
1221 /*
1222 * setregid
1223 *
1224 * Description: Set real and effective group ID system call
1225 *
1226 * Parameters: uap->rgid real gid to set
1227 * uap->egid effective gid to set
1228 *
1229 * Returns: 0 Success
1230 * suser:EPERM Permission denied
1231 *
1232 * Notes: A value of -1 is a special case indicating that the gid for
1233 * which that value is specified not be changed. If both values
1234 * are specified as -1, no action is taken.
1235 *
1236 * If called by a privileged process, the real and effective gid
1237 * will be set to the new value(s) specified.
1238 *
1239 * If called from an unprivileged process, the real gid may be
1240 * set to the current value of the real gid, or to the current
1241 * value of the saved gid. The effective gid may be set to the
1242 * current value of any of the effective, real, or saved gid.
1243 *
1244 * If the new real and effective gid will not be equal, or the
1245 * new real or effective gid is not the same as the saved gid,
1246 * then the saved gid will be updated to reflect the new
1247 * effective gid (potentially unrecoverably dropping saved
1248 * privilege).
1249 *
1250 * If the credential is changed as a result of this call, then we
1251 * flag the process as having set privilege since the last exec.
1252 *
1253 * As an implementation detail, the effective gid is stored as
1254 * the first element of the supplementary group list, and
1255 * therefore the effective group list may be reordered to keep
1256 * the supplementary group list unchanged.
1257 */
1258 int
1259 setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1260 {
1261 gid_t rgid, egid;
1262 int error;
1263 kauth_cred_t my_cred, my_new_cred;
1264
1265 DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
1266
1267 rgid = uap->rgid;
1268 egid = uap->egid;
1269
1270 if (rgid == (uid_t)-1)
1271 rgid = KAUTH_GID_NONE;
1272 if (egid == (uid_t)-1)
1273 egid = KAUTH_GID_NONE;
1274 AUDIT_ARG(egid, egid);
1275 AUDIT_ARG(rgid, rgid);
1276
1277 my_cred = kauth_cred_proc_ref(p);
1278
1279 if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1280 rgid != my_cred->cr_rgid && /* allow rgid = rgid */
1281 rgid != my_cred->cr_gid && /* allow rgid = egid */
1282 rgid != my_cred->cr_svgid) || /* allow rgid = svgid */
1283 (egid != KAUTH_UID_NONE && /* allow no change of egid */
1284 egid != my_cred->cr_groups[0] && /* allow no change of egid */
1285 egid != my_cred->cr_gid && /* allow egid = egid */
1286 egid != my_cred->cr_rgid && /* allow egid = rgid */
1287 egid != my_cred->cr_svgid)) && /* allow egid = svgid */
1288 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1289 kauth_cred_unref(&my_cred);
1290 return (error);
1291 }
1292
1293 /* get current credential and take a reference while we muck with it */
1294 for (;;) {
1295 uid_t new_egid = my_cred->cr_gid;
1296 uid_t new_rgid = my_cred->cr_rgid;
1297 uid_t svgid = KAUTH_UID_NONE;
1298
1299
1300 /*
1301 * Set the credential with new info. If there is no change,
1302 * we get back the same credential we passed in; if there is
1303 * a change, we drop the reference on the credential we
1304 * passed in. The subsequent compare is safe, because it is
1305 * a pointer compare rather than a contents compare.
1306 */
1307 if (egid == KAUTH_UID_NONE && my_cred->cr_groups[0] != egid) {
1308 /* changing the effective GID */
1309 new_egid = egid;
1310 OSBitOrAtomic(P_SUGID, &p->p_flag);
1311 }
1312 if (rgid != KAUTH_UID_NONE && my_cred->cr_rgid != rgid) {
1313 /* changing the real GID */
1314 new_rgid = rgid;
1315 OSBitOrAtomic(P_SUGID, &p->p_flag);
1316 }
1317 /*
1318 * If the newly requested real gid or effective gid does
1319 * not match the saved gid, then set the saved gid to the
1320 * new effective gid. We are protected from escalation
1321 * by the prechecking.
1322 */
1323 if (my_cred->cr_svgid != uap->rgid &&
1324 my_cred->cr_svgid != uap->egid) {
1325 svgid = new_egid;
1326 OSBitOrAtomic(P_SUGID, &p->p_flag);
1327 }
1328
1329 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
1330 if (my_cred != my_new_cred) {
1331
1332 DEBUG_CRED_CHANGE("setregid(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);
1333
1334 proc_lock(p);
1335 /* need to protect for a race where another thread
1336 * also changed the credential after we took our
1337 * reference. If p_ucred has changed then we
1338 * should restart this again with the new cred.
1339 */
1340 if (p->p_ucred != my_cred) {
1341 proc_unlock(p);
1342 kauth_cred_unref(&my_new_cred);
1343 /* try again */
1344 my_cred = kauth_cred_proc_ref(p);
1345 continue;
1346 }
1347 p->p_ucred = my_new_cred;
1348 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1349 proc_unlock(p);
1350 }
1351 break;
1352 }
1353 /* Drop old proc reference or our extra reference */
1354 kauth_cred_unref(&my_cred);
1355
1356 set_security_token(p);
1357 return (0);
1358 }
1359
1360
1361 /*
1362 * Set the per-thread override identity. The first parameter can be the
1363 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
1364 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1365 * means "revert to the per process credential"; otherwise, if permitted,
1366 * it changes the effective, real, and saved UIDs and GIDs for the current
1367 * thread to the requested UID and single GID, and clears all other GIDs.
1368 */
1369 int
1370 settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1371 {
1372 kauth_cred_t uc;
1373 struct uthread *uthread = get_bsdthread_info(current_thread());
1374 uid_t uid;
1375 gid_t gid;
1376
1377 uid = uap->uid;
1378 gid = uap->gid;
1379 AUDIT_ARG(uid, uid);
1380 AUDIT_ARG(gid, gid);
1381
1382 if (proc_suser(p) != 0)
1383 return (EPERM);
1384
1385 if (uid == KAUTH_UID_NONE) {
1386
1387 /* must already be assuming another identity in order to revert back */
1388 if ((uthread->uu_flag & UT_SETUID) == 0)
1389 return (EPERM);
1390
1391 /* revert to delayed binding of process credential */
1392 uc = kauth_cred_proc_ref(p);
1393 kauth_cred_unref(&uthread->uu_ucred);
1394 uthread->uu_ucred = uc;
1395 uthread->uu_flag &= ~UT_SETUID;
1396 } else {
1397 kauth_cred_t my_cred, my_new_cred;
1398
1399 /* cannot already be assuming another identity */
1400 if ((uthread->uu_flag & UT_SETUID) != 0) {
1401 return (EPERM);
1402 }
1403
1404 /*
1405 * Get a new credential instance from the old if this one
1406 * changes; otherwise kauth_cred_setuidgid() returns the
1407 * same credential. We take an extra reference on the
1408 * current credential while we muck with it, so we can do
1409 * the post-compare for changes by pointer.
1410 */
1411 kauth_cred_ref(uthread->uu_ucred);
1412 my_cred = uthread->uu_ucred;
1413 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
1414 if (my_cred != my_new_cred)
1415 uthread->uu_ucred = my_new_cred;
1416 uthread->uu_flag |= UT_SETUID;
1417
1418 /* Drop old uthread reference or our extra reference */
1419 kauth_cred_unref(&my_cred);
1420 }
1421 /*
1422 * XXX should potentially set per thread security token (there is
1423 * XXX none).
1424 * XXX it is unclear whether P_SUGID should be st at this point;
1425 * XXX in theory, it is being deprecated.
1426 */
1427 return (0);
1428 }
1429
1430
1431 /*
1432 * Set the per-thread override identity. Use this system call for a thread to
1433 * assume the identity of another process or to revert back to normal identity
1434 * of the current process.
1435 *
1436 * When the "assume" argument is non zero the current thread will assume the
1437 * identity of the process represented by the pid argument.
1438 *
1439 * When the assume argument is zero we revert back to our normal identity.
1440 */
1441 int
1442 settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1443 {
1444 proc_t target_proc;
1445 struct uthread *uthread = get_bsdthread_info(current_thread());
1446 kauth_cred_t my_cred, my_target_cred, my_new_cred;
1447
1448 AUDIT_ARG(pid, uap->pid);
1449 AUDIT_ARG(value32, uap->assume);
1450
1451 if (proc_suser(p) != 0) {
1452 return (EPERM);
1453 }
1454
1455 /*
1456 * XXX should potentially set per thread security token (there is
1457 * XXX none).
1458 * XXX it is unclear whether P_SUGID should be st at this point;
1459 * XXX in theory, it is being deprecated.
1460 */
1461
1462 /*
1463 * assume argument tells us to assume the identity of the process with the
1464 * id passed in the pid argument.
1465 */
1466 if (uap->assume != 0) {
1467 /* can't do this if we have already assumed an identity */
1468 if ((uthread->uu_flag & UT_SETUID) != 0)
1469 return (EPERM);
1470
1471 target_proc = proc_find(uap->pid);
1472 /* can't assume the identity of the kernel process */
1473 if (target_proc == NULL || target_proc == kernproc) {
1474 if (target_proc!= NULL)
1475 proc_rele(target_proc);
1476 return (ESRCH);
1477 }
1478
1479 /*
1480 * Take a reference on the credential used in our target
1481 * process then use it as the identity for our current
1482 * thread. We take an extra reference on the current
1483 * credential while we muck with it, so we can do the
1484 * post-compare for changes by pointer.
1485 *
1486 * The post-compare is needed for the case that our process
1487 * credential has been changed to be identical to our thread
1488 * credential following our assumption of a per-thread one,
1489 * since the credential cache will maintain a unique instance.
1490 */
1491 kauth_cred_ref(uthread->uu_ucred);
1492 my_cred = uthread->uu_ucred;
1493 my_target_cred = kauth_cred_proc_ref(target_proc);
1494 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_cred->cr_uid, my_target_cred->cr_gid);
1495 if (my_cred != my_new_cred)
1496 uthread->uu_ucred = my_new_cred;
1497
1498 uthread->uu_flag |= UT_SETUID;
1499
1500 /* Drop old uthread reference or our extra reference */
1501 proc_rele(target_proc);
1502 kauth_cred_unref(&my_cred);
1503 kauth_cred_unref(&my_target_cred);
1504
1505 return (0);
1506 }
1507
1508 /*
1509 * Otherwise, we are reverting back to normal mode of operation where
1510 * delayed binding of the process credential sets the credential in
1511 * the thread (uu_ucred)
1512 */
1513 if ((uthread->uu_flag & UT_SETUID) == 0)
1514 return (EPERM);
1515
1516 /* revert to delayed binding of process credential */
1517 my_new_cred = kauth_cred_proc_ref(p);
1518 kauth_cred_unref(&uthread->uu_ucred);
1519 uthread->uu_ucred = my_new_cred;
1520 uthread->uu_flag &= ~UT_SETUID;
1521
1522 return (0);
1523 }
1524
1525
1526 /*
1527 * setgroups1
1528 *
1529 * Description: Internal implementation for both the setgroups and initgroups
1530 * system calls
1531 *
1532 * Parameters: gidsetsize Number of groups in set
1533 * gidset Pointer to group list
1534 * gmuid Base gid (initgroups only!)
1535 *
1536 * Returns: 0 Success
1537 * suser:EPERM Permision denied
1538 * EINVAL Invalid gidsetsize value
1539 * copyin:EFAULT Bad gidset or gidsetsize is
1540 * too large
1541 *
1542 * Notes: When called from a thread running under an assumed per-thread
1543 * identity, this function will operate against the per-thread
1544 * credential, rather than against the process credential. In
1545 * this specific case, the process credential is verified to
1546 * still be privileged at the time of the call, rather than the
1547 * per-thread credential for this operation to be permitted.
1548 *
1549 * This effectively means that setgroups/initigroups calls in
1550 * a thread running a per-thread credential should occur *after*
1551 * the settid call that created it, not before (unlike setuid,
1552 * which must be called after, since it will result in privilege
1553 * being dropped).
1554 *
1555 * When called normally (i.e. no per-thread assumed identity),
1556 * the per process credential is updated per POSIX.
1557 *
1558 * If the credential is changed as a result of this call, then we
1559 * flag the process as having set privilege since the last exec.
1560 */
1561 static int
1562 setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1563 {
1564 u_int ngrp;
1565 gid_t newgroups[NGROUPS] = { 0 };
1566 int error;
1567 kauth_cred_t my_cred, my_new_cred;
1568 struct uthread *uthread = get_bsdthread_info(current_thread());
1569
1570 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);
1571
1572 ngrp = gidsetsize;
1573 if (ngrp > NGROUPS)
1574 return (EINVAL);
1575
1576 if ( ngrp < 1 ) {
1577 ngrp = 1;
1578 } else {
1579 error = copyin(gidset,
1580 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1581 if (error) {
1582 return (error);
1583 }
1584 }
1585
1586 my_cred = kauth_cred_proc_ref(p);
1587 if ((error = suser(my_cred, &p->p_acflag))) {
1588 kauth_cred_unref(&my_cred);
1589 return (error);
1590 }
1591
1592 if ((uthread->uu_flag & UT_SETUID) != 0) {
1593 #if DEBUG_CRED
1594 int my_cred_flags = uthread->uu_ucred->cr_flags;
1595 #endif /* DEBUG_CRED */
1596 kauth_cred_unref(&my_cred);
1597
1598 /*
1599 * If this thread is under an assumed identity, set the
1600 * supplementary grouplist on the thread credential instead
1601 * of the process one. If we were the only reference holder,
1602 * the credential is updated in place, otherwise, our reference
1603 * is dropped and we get back a different cred with a reference
1604 * already held on it. Because this is per-thread, we don't
1605 * need the referencing/locking/retry required for per-process.
1606 */
1607 my_cred = uthread->uu_ucred;
1608 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1609 #if DEBUG_CRED
1610 if (my_cred != uthread->uu_ucred) {
1611 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);
1612 }
1613 #endif /* DEBUG_CRED */
1614 } else {
1615
1616 /*
1617 * get current credential and take a reference while we muck
1618 * with it
1619 */
1620 for (;;) {
1621 /*
1622 * Set the credential with new info. If there is no
1623 * change, we get back the same credential we passed
1624 * in; if there is a change, we drop the reference on
1625 * the credential we passed in. The subsequent
1626 * compare is safe, because it is a pointer compare
1627 * rather than a contents compare.
1628 */
1629 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1630 if (my_cred != my_new_cred) {
1631
1632 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);
1633
1634 proc_lock(p);
1635 /*
1636 * We need to protect for a race where another
1637 * thread also changed the credential after we
1638 * took our reference. If p_ucred has
1639 * changed then we should restart this again
1640 * with the new cred.
1641 */
1642 if (p->p_ucred != my_cred) {
1643 proc_unlock(p);
1644 kauth_cred_unref(&my_new_cred);
1645 my_cred = kauth_cred_proc_ref(p);
1646 /* try again */
1647 continue;
1648 }
1649 p->p_ucred = my_new_cred;
1650 OSBitOrAtomic(P_SUGID, &p->p_flag);
1651 proc_unlock(p);
1652 }
1653 break;
1654 }
1655 /* Drop old proc reference or our extra reference */
1656 AUDIT_ARG(groupset, my_cred->cr_groups, ngrp);
1657 kauth_cred_unref(&my_cred);
1658
1659
1660 set_security_token(p);
1661 }
1662
1663 return (0);
1664 }
1665
1666
1667 /*
1668 * initgroups
1669 *
1670 * Description: Initialize the default supplementary groups list and set the
1671 * gmuid for use by the external group resolver (if any)
1672 *
1673 * Parameters: uap->gidsetsize Number of groups in set
1674 * uap->gidset Pointer to group list
1675 * uap->gmuid Base gid
1676 *
1677 * Returns: 0 Success
1678 * setgroups1:EPERM Permision denied
1679 * setgroups1:EINVAL Invalid gidsetsize value
1680 * setgroups1:EFAULT Bad gidset or gidsetsize is
1681 *
1682 * Notes: This function opts *IN* to memberd participation
1683 *
1684 * The normal purpose of this function is for a privileged
1685 * process to indicate supplementary groups and identity for
1686 * participation in extended group membership resolution prior
1687 * to dropping privilege by assuming a specific user identity.
1688 *
1689 * It is the first half of the primary mechanism whereby user
1690 * identity is established to the system by programs such as
1691 * /usr/bin/login. The second half is the drop of uid privilege
1692 * for a specific uid corresponding to the user.
1693 *
1694 * See also: setgroups1()
1695 */
1696 int
1697 initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1698 {
1699 DEBUG_CRED_ENTER("initgroups\n");
1700
1701 return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
1702 }
1703
1704
1705 /*
1706 * setgroups
1707 *
1708 * Description: Initialize the default supplementary groups list
1709 *
1710 * Parameters: gidsetsize Number of groups in set
1711 * gidset Pointer to group list
1712 *
1713 * Returns: 0 Success
1714 * setgroups1:EPERM Permision denied
1715 * setgroups1:EINVAL Invalid gidsetsize value
1716 * setgroups1:EFAULT Bad gidset or gidsetsize is
1717 *
1718 * Notes: This functions opts *OUT* of memberd participation.
1719 *
1720 * This function exists for compatibility with POSIX. Most user
1721 * programs should use initgroups() instead to ensure correct
1722 * participation in group membership resolution when utilizing
1723 * a directory service for authentication.
1724 *
1725 * It is identical to an initgroups() call with a gmuid argument
1726 * of KAUTH_UID_NONE.
1727 *
1728 * See also: setgroups1()
1729 */
1730 int
1731 setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1732 {
1733 DEBUG_CRED_ENTER("setgroups\n");
1734
1735 return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
1736 }
1737
1738
1739 /*
1740 * Set the per-thread/per-process supplementary groups list.
1741 *
1742 * XXX implement setsgroups
1743 *
1744 */
1745
1746 int
1747 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1748 {
1749 return(ENOTSUP);
1750 }
1751
1752 /*
1753 * Set the per-thread/per-process whiteout groups list.
1754 *
1755 * XXX implement setwgroups
1756 *
1757 */
1758
1759 int
1760 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1761 {
1762 return(ENOTSUP);
1763 }
1764
1765
1766 /*
1767 * Check if gid is a member of the group set.
1768 *
1769 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1770 * XXX instead.
1771 */
1772 int
1773 groupmember(gid_t gid, kauth_cred_t cred)
1774 {
1775 int is_member;
1776
1777 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
1778 return (1);
1779 return (0);
1780 }
1781
1782
1783 /*
1784 * Test whether the specified credentials imply "super-user"
1785 * privilege; if so, and we have accounting info, set the flag
1786 * indicating use of super-powers.
1787 * Returns 0 or error.
1788 *
1789 * XXX This interface is going away; use kauth_cred_issuser() directly
1790 * XXX instead.
1791 *
1792 * Note: This interface exists to implement the "has used privilege"
1793 * bit (ASU) in the p_acflags field of the process, which is
1794 * only externalized via private sysctl and in process accounting
1795 * records. The flag is technically not required in either case.
1796 */
1797 int
1798 suser(kauth_cred_t cred, u_short *acflag)
1799 {
1800 #if DIAGNOSTIC
1801 if (!IS_VALID_CRED(cred))
1802 panic("suser");
1803 #endif
1804 if (kauth_cred_getuid(cred) == 0) {
1805 if (acflag)
1806 *acflag |= ASU;
1807 return (0);
1808 }
1809 return (EPERM);
1810 }
1811
1812
1813 /*
1814 * XXX This interface is going away; use kauth_cred_issuser() directly
1815 * XXX instead.
1816 */
1817 int
1818 is_suser(void)
1819 {
1820 proc_t p = current_proc();
1821
1822 if (!p)
1823 return (0);
1824
1825 return (proc_suser(p) == 0);
1826 }
1827
1828
1829 /*
1830 * XXX This interface is going away; use kauth_cred_issuser() directly
1831 * XXX instead.
1832 */
1833 int
1834 is_suser1(void)
1835 {
1836 proc_t p = current_proc();
1837 kauth_cred_t my_cred;
1838 int err;
1839
1840 if (!p)
1841 return (0);
1842
1843 my_cred = kauth_cred_proc_ref(p);
1844
1845 err = (suser(my_cred, &p->p_acflag) == 0 ||
1846 my_cred->cr_ruid == 0 || my_cred->cr_svuid == 0);
1847 kauth_cred_unref(&my_cred);
1848 return(err);
1849 }
1850
1851
1852 /*
1853 * getlogin
1854 *
1855 * Description: Get login name, if available.
1856 *
1857 * Parameters: uap->namebuf User buffer for return
1858 * uap->namelen User buffer length
1859 *
1860 * Returns: 0 Success
1861 * copyout:EFAULT
1862 *
1863 * Notes: Intended to obtain a string containing the user name of the
1864 * user associated with the controlling terminal for the calling
1865 * process.
1866 *
1867 * Not very useful on modern systems, due to inherent length
1868 * limitations for the static array in the session structure
1869 * which is used to store the login name.
1870 *
1871 * Permitted to return NULL
1872 *
1873 * XXX: Belongs in kern_proc.c
1874 */
1875 int
1876 getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1877 {
1878 char buffer[MAXLOGNAME+1];
1879 struct session * sessp;
1880
1881 bzero(buffer, MAXLOGNAME+1);
1882
1883 sessp = proc_session(p);
1884
1885 if (uap->namelen > MAXLOGNAME)
1886 uap->namelen = MAXLOGNAME;
1887
1888 if(sessp != SESSION_NULL) {
1889 session_lock(sessp);
1890 bcopy( sessp->s_login, buffer, uap->namelen);
1891 session_unlock(sessp);
1892 }
1893 session_rele(sessp);
1894
1895 return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
1896 }
1897
1898
1899 /*
1900 * setlogin
1901 *
1902 * Description: Set login name.
1903 *
1904 * Parameters: uap->namebuf User buffer containing name
1905 *
1906 * Returns: 0 Success
1907 * suser:EPERM Permission denied
1908 * copyinstr:EFAULT User buffer invalid
1909 * copyinstr:EINVAL Supplied name was too long
1910 *
1911 * Notes: This is a utility system call to support getlogin().
1912 *
1913 * XXX: Belongs in kern_proc.c
1914 */
1915 int
1916 setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1917 {
1918 int error;
1919 size_t dummy=0;
1920 char buffer[MAXLOGNAME+1];
1921 struct session * sessp;
1922
1923 if ((error = proc_suser(p)))
1924 return (error);
1925
1926 bzero(&buffer[0], MAXLOGNAME+1);
1927
1928
1929 error = copyinstr(uap->namebuf,
1930 (caddr_t) &buffer[0],
1931 MAXLOGNAME - 1, (size_t *)&dummy);
1932
1933 sessp = proc_session(p);
1934
1935 if (sessp != SESSION_NULL) {
1936 session_lock(sessp);
1937 bcopy(buffer, sessp->s_login, MAXLOGNAME);
1938 session_unlock(sessp);
1939 session_rele(sessp);
1940 }
1941
1942
1943 if (!error) {
1944 AUDIT_ARG(text, buffer);
1945 } else if (error == ENAMETOOLONG)
1946 error = EINVAL;
1947 return (error);
1948 }
1949
1950
1951 /* Set the secrity token of the task with current euid and eguid */
1952 /*
1953 * XXX This needs to change to give the task a reference and/or an opaque
1954 * XXX identifier.
1955 */
1956 int
1957 set_security_token(proc_t p)
1958 {
1959 security_token_t sec_token;
1960 audit_token_t audit_token;
1961 kauth_cred_t my_cred;
1962 host_priv_t host_priv;
1963
1964 /*
1965 * Don't allow a vfork child to override the parent's token settings
1966 * (since they share a task). Instead, the child will just have to
1967 * suffer along using the parent's token until the exec(). It's all
1968 * undefined behavior anyway, right?
1969 */
1970 if (p->task == current_task()) {
1971 uthread_t uthread;
1972 uthread = (uthread_t)get_bsdthread_info(current_thread());
1973 if (uthread->uu_flag & UT_VFORK)
1974 return (1);
1975 }
1976
1977 my_cred = kauth_cred_proc_ref(p);
1978 /* XXX mach_init doesn't have a p_ucred when it calls this function */
1979 if (IS_VALID_CRED(my_cred)) {
1980 sec_token.val[0] = kauth_cred_getuid(my_cred);
1981 sec_token.val[1] = my_cred->cr_gid;
1982 } else {
1983 sec_token.val[0] = 0;
1984 sec_token.val[1] = 0;
1985 }
1986
1987 /*
1988 * The current layout of the Mach audit token explicitly
1989 * adds these fields. But nobody should rely on such
1990 * a literal representation. Instead, the BSM library
1991 * provides a function to convert an audit token into
1992 * a BSM subject. Use of that mechanism will isolate
1993 * the user of the trailer from future representation
1994 * changes.
1995 */
1996 audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
1997 audit_token.val[1] = my_cred->cr_uid;
1998 audit_token.val[2] = my_cred->cr_gid;
1999 audit_token.val[3] = my_cred->cr_ruid;
2000 audit_token.val[4] = my_cred->cr_rgid;
2001 audit_token.val[5] = p->p_pid;
2002 audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
2003 audit_token.val[7] = p->p_idversion;
2004
2005 #if CONFIG_MACF_MACH
2006 mac_task_label_update_cred(my_cred, p->task);
2007 #endif
2008
2009 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
2010 #if CONFIG_MACF
2011 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
2012 host_priv = HOST_PRIV_NULL;
2013 #endif
2014 kauth_cred_unref(&my_cred);
2015
2016 return (host_security_set_task_token(host_security_self(),
2017 p->task,
2018 sec_token,
2019 audit_token,
2020 host_priv) != KERN_SUCCESS);
2021 }
2022
2023
2024 /*
2025 * Fill in a struct xucred based on a kauth_cred_t.
2026 */
2027 __private_extern__
2028 void
2029 cru2x(kauth_cred_t cr, struct xucred *xcr)
2030 {
2031
2032 bzero(xcr, sizeof(*xcr));
2033 xcr->cr_version = XUCRED_VERSION;
2034 xcr->cr_uid = kauth_cred_getuid(cr);
2035 xcr->cr_ngroups = cr->cr_ngroups;
2036 bcopy(cr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
2037 }
2038
2039 #if CONFIG_LCTX
2040
2041 /*
2042 * Set Login Context ID
2043 */
2044 /*
2045 * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
2046 * LCTX by its own locks.
2047 */
2048 int
2049 setlcid(proc_t p0, struct setlcid_args *uap, __unused int32_t *retval)
2050 {
2051 proc_t p;
2052 struct lctx *l;
2053 int error = 0;
2054 int refheld = 0;
2055
2056 AUDIT_ARG(pid, uap->pid);
2057 AUDIT_ARG(value32, uap->lcid);
2058 if (uap->pid == LCID_PROC_SELF) { /* Create/Join/Leave */
2059 p = p0;
2060 } else { /* Adopt/Orphan */
2061 p = proc_find(uap->pid);
2062 if (p == NULL)
2063 return (ESRCH);
2064 refheld = 1;
2065 }
2066
2067 #if CONFIG_MACF
2068 error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
2069 if (error)
2070 goto out;
2071 #endif
2072
2073 switch (uap->lcid) {
2074 /* Leave/Orphan */
2075 case LCID_REMOVE:
2076
2077 /* Only root may Leave/Orphan. */
2078 if (!is_suser1()) {
2079 error = EPERM;
2080 goto out;
2081 }
2082
2083 /* Process not in login context. */
2084 if (p->p_lctx == NULL) {
2085 error = ENOATTR;
2086 goto out;
2087 }
2088
2089 l = NULL;
2090
2091 break;
2092
2093 /* Create */
2094 case LCID_CREATE:
2095
2096 /* Create only valid for self! */
2097 if (uap->pid != LCID_PROC_SELF) {
2098 error = EPERM;
2099 goto out;
2100 }
2101
2102 /* Already in a login context. */
2103 if (p->p_lctx != NULL) {
2104 error = EPERM;
2105 goto out;
2106 }
2107
2108 l = lccreate();
2109 if (l == NULL) {
2110 error = ENOMEM;
2111 goto out;
2112 }
2113
2114 LCTX_LOCK(l);
2115
2116 break;
2117
2118 /* Join/Adopt */
2119 default:
2120
2121 /* Only root may Join/Adopt. */
2122 if (!is_suser1()) {
2123 error = EPERM;
2124 goto out;
2125 }
2126
2127 l = lcfind(uap->lcid);
2128 if (l == NULL) {
2129 error = ENOATTR;
2130 goto out;
2131 }
2132
2133 break;
2134 }
2135
2136 ALLLCTX_LOCK;
2137 leavelctx(p);
2138 enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
2139 ALLLCTX_UNLOCK;
2140
2141 out:
2142 if (refheld != 0)
2143 proc_rele(p);
2144 return (error);
2145 }
2146
2147 /*
2148 * Get Login Context ID
2149 */
2150 /*
2151 * MPSAFE - membership of (visible) process in a login context
2152 * protected by the all-context lock.
2153 */
2154 int
2155 getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2156 {
2157 proc_t p;
2158 int error = 0;
2159 int refheld = 0;
2160
2161 AUDIT_ARG(pid, uap->pid);
2162 if (uap->pid == LCID_PROC_SELF) {
2163 p = p0;
2164 } else {
2165 p = proc_find(uap->pid);
2166 if (p == NULL)
2167 return (ESRCH);
2168 refheld = 1;
2169 }
2170
2171 #if CONFIG_MACF
2172 error = mac_proc_check_getlcid(p0, p, uap->pid);
2173 if (error)
2174 goto out;
2175 #endif
2176 ALLLCTX_LOCK;
2177 if (p->p_lctx == NULL) {
2178 error = ENOATTR;
2179 ALLLCTX_UNLOCK;
2180 goto out;
2181 }
2182 *retval = p->p_lctx->lc_id;
2183 ALLLCTX_UNLOCK;
2184 out:
2185 if (refheld != 0)
2186 proc_rele(p);
2187
2188 return (error);
2189 }
2190 #else /* LCTX */
2191 int
2192 setlcid(proc_t p0, struct setlcid_args *uap, int32_t *retval)
2193 {
2194
2195 return (ENOSYS);
2196 }
2197
2198 int
2199 getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
2200 {
2201
2202 return (ENOSYS);
2203 }
2204 #endif /* !LCTX */