2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <sys/kernel.h>
29 #include <sys/kernel_types.h>
30 #include <sys/persona.h>
33 #include <kern/assert.h>
34 #include <kern/simple_lock.h>
35 #include <kern/task.h>
36 #include <kern/zalloc.h>
38 #include <sys/param.h>
39 #include <sys/proc_internal.h>
40 #include <sys/kauth.h>
41 #include <sys/proc_info.h>
42 #include <sys/resourcevar.h>
44 #define pna_info(fmt, ...) \
45 printf("%s: " fmt "\n", __func__, ## __VA_ARGS__)
47 #define pna_err(fmt, ...) \
48 printf("ERROR[%s]: " fmt "\n", __func__, ## __VA_ARGS__)
50 #define MAX_PERSONAS 512
52 #define TEMP_PERSONA_ID 499
54 #define FIRST_PERSONA_ID 501
55 #define PERSONA_ID_STEP 10
57 #define PERSONA_SYSTEM_UID ((uid_t)99)
58 #define PERSONA_SYSTEM_LOGIN "system"
60 #define PERSONA_MAGIC (0x0aa55aa0)
61 #define persona_valid(p) ((p)->pna_valid == PERSONA_MAGIC)
62 #define persona_mkinvalid(p) ((p)->pna_valid = ~(PERSONA_MAGIC))
64 static LIST_HEAD(personalist
, persona
) all_personas
;
65 static uint32_t g_total_personas
;
66 uint32_t g_max_personas
= MAX_PERSONAS
;
68 struct persona
*g_system_persona
= NULL
;
70 static uid_t g_next_persona_id
;
72 lck_mtx_t all_personas_lock
;
73 lck_attr_t
*persona_lck_attr
;
74 lck_grp_t
*persona_lck_grp
;
75 lck_grp_attr_t
*persona_lck_grp_attr
;
77 static zone_t persona_zone
;
79 kauth_cred_t g_default_persona_cred
;
81 #define lock_personas() lck_mtx_lock(&all_personas_lock)
82 #define unlock_personas() lck_mtx_unlock(&all_personas_lock)
85 extern void mach_kauth_cred_uthread_update(void);
87 void personas_bootstrap(void)
89 struct posix_cred pcred
;
91 persona_dbg("Initializing persona subsystem");
92 LIST_INIT(&all_personas
);
95 g_next_persona_id
= FIRST_PERSONA_ID
;
97 persona_lck_grp_attr
= lck_grp_attr_alloc_init();
98 lck_grp_attr_setstat(persona_lck_grp_attr
);
100 persona_lck_grp
= lck_grp_alloc_init("personas", persona_lck_grp_attr
);
101 persona_lck_attr
= lck_attr_alloc_init();
103 lck_mtx_init(&all_personas_lock
, persona_lck_grp
, persona_lck_attr
);
105 persona_zone
= zinit(sizeof(struct persona
),
106 MAX_PERSONAS
* sizeof(struct persona
),
107 MAX_PERSONAS
, "personas");
108 assert(persona_zone
!= NULL
);
111 * setup the default credentials that a persona temporarily
112 * inherits (to work around kauth APIs)
114 bzero(&pcred
, sizeof(pcred
));
115 pcred
.cr_uid
= pcred
.cr_ruid
= pcred
.cr_svuid
= TEMP_PERSONA_ID
;
116 pcred
.cr_rgid
= pcred
.cr_svgid
= TEMP_PERSONA_ID
;
117 pcred
.cr_groups
[0] = TEMP_PERSONA_ID
;
118 pcred
.cr_ngroups
= 1;
119 pcred
.cr_flags
= CRF_NOMEMBERD
;
120 pcred
.cr_gmuid
= KAUTH_UID_NONE
;
122 g_default_persona_cred
= posix_cred_create(&pcred
);
123 if (!g_default_persona_cred
)
124 panic("couldn't create default persona credentials!");
126 g_system_persona
= persona_alloc(PERSONA_SYSTEM_UID
,
127 PERSONA_SYSTEM_LOGIN
,
128 PERSONA_SYSTEM
, NULL
);
129 assert(g_system_persona
!= NULL
);
132 struct persona
*persona_alloc(uid_t id
, const char *login
, int type
, int *error
)
134 struct persona
*persona
, *tmp
;
136 kauth_cred_t tmp_cred
;
140 pna_err("Must provide a login name for a new persona!");
146 if (type
<= PERSONA_INVALID
|| type
> PERSONA_TYPE_MAX
) {
147 pna_err("Invalid type: %d", type
);
153 persona
= (struct persona
*)zalloc(persona_zone
);
160 bzero(persona
, sizeof(*persona
));
162 if (hw_atomic_add(&g_total_personas
, 1) > MAX_PERSONAS
) {
163 /* too many personas! */
164 pna_err("too many active personas!");
169 strncpy(persona
->pna_login
, login
, sizeof(persona
->pna_login
)-1);
171 LIST_INIT(&persona
->pna_members
);
172 lck_mtx_init(&persona
->pna_lock
, persona_lck_grp
, persona_lck_attr
);
173 persona
->pna_refcount
= 1;
176 * Setup initial (temporary) kauth_cred structure
177 * We need to do this here because all kauth calls require
178 * an existing cred structure.
180 persona
->pna_cred
= kauth_cred_create(g_default_persona_cred
);
181 if (!persona
->pna_cred
) {
182 pna_err("could not copy initial credentials!");
189 if (id
!= PERSONA_ID_NONE
)
190 persona
->pna_id
= id
;
192 persona
->pna_id
= g_next_persona_id
;
194 persona_dbg("Adding %d (%s) to global list...", persona
->pna_id
, persona
->pna_login
);
197 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
198 if (id
== PERSONA_ID_NONE
&& tmp
->pna_id
== id
) {
200 * someone else manually claimed this ID, and we're
201 * trying to allocate an ID for the caller: try again
203 g_next_persona_id
+= PERSONA_ID_STEP
;
206 if (strncmp(tmp
->pna_login
, login
, sizeof(tmp
->pna_login
)) == 0
207 || tmp
->pna_id
== id
) {
209 * Disallow use of identical login names and re-use
210 * of previously allocated persona IDs
219 /* ensure the cred has proper UID/GID defaults */
220 kauth_cred_ref(persona
->pna_cred
);
221 tmp_cred
= kauth_cred_setuidgid(persona
->pna_cred
,
224 kauth_cred_unref(&persona
->pna_cred
);
225 if (tmp_cred
!= persona
->pna_cred
)
226 persona
->pna_cred
= tmp_cred
;
228 if (!persona
->pna_cred
) {
233 /* it should be a member of exactly 1 group (equal to its UID) */
234 new_group
= (gid_t
)persona
->pna_id
;
236 kauth_cred_ref(persona
->pna_cred
);
237 /* opt _out_ of memberd as a default */
238 tmp_cred
= kauth_cred_setgroups(persona
->pna_cred
,
239 &new_group
, 1, KAUTH_UID_NONE
);
240 kauth_cred_unref(&persona
->pna_cred
);
241 if (tmp_cred
!= persona
->pna_cred
)
242 persona
->pna_cred
= tmp_cred
;
244 if (!persona
->pna_cred
) {
249 persona
->pna_type
= type
;
251 /* insert the, now valid, persona into the global list! */
252 persona
->pna_valid
= PERSONA_MAGIC
;
253 LIST_INSERT_HEAD(&all_personas
, persona
, pna_list
);
255 /* if the kernel supplied the persona ID, increment for next time */
256 if (id
== PERSONA_ID_NONE
)
257 g_next_persona_id
+= PERSONA_ID_STEP
;
265 persona_dbg("Login '%s' (%d) already exists",
266 login
, persona
->pna_id
);
269 persona_dbg("kauth_error for persona:%d", persona
->pna_id
);
272 persona_dbg("Unknown error:%d", err
);
280 (void)hw_atomic_add(&g_total_personas
, -1);
281 zfree(persona_zone
, persona
);
287 int persona_invalidate(struct persona
*persona
)
294 persona_lock(persona
);
296 if (!persona_valid(persona
))
297 panic("Double-invalidation of persona %p", persona
);
299 LIST_REMOVE(persona
, pna_list
);
300 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
)
301 panic("persona ref count underflow!\n");
302 persona_mkinvalid(persona
);
304 persona_unlock(persona
);
310 static struct persona
*persona_get_locked(struct persona
*persona
)
312 if (persona
->pna_refcount
) {
313 persona
->pna_refcount
++;
319 struct persona
*persona_get(struct persona
*persona
)
324 persona_lock(persona
);
325 ret
= persona_get_locked(persona
);
326 persona_unlock(persona
);
331 void persona_put(struct persona
*persona
)
338 persona_lock(persona
);
339 if (persona
->pna_refcount
>= 0) {
340 if (--(persona
->pna_refcount
) == 0)
343 persona_unlock(persona
);
348 persona_dbg("Destroying persona %s", persona_desc(persona
, 0));
350 /* release our credential reference */
351 if (persona
->pna_cred
)
352 kauth_cred_unref(&persona
->pna_cred
);
354 /* remove it from the global list and decrement the count */
356 if (persona_valid(persona
)) {
357 LIST_REMOVE(persona
, pna_list
);
358 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
)
359 panic("persona count underflow!\n");
360 persona_mkinvalid(persona
);
364 assert(LIST_EMPTY(&persona
->pna_members
));
365 memset(persona
, 0, sizeof(*persona
));
366 zfree(persona_zone
, persona
);
369 uid_t
persona_get_id(struct persona
*persona
)
372 return persona
->pna_id
;
373 return PERSONA_ID_NONE
;
376 struct persona
*persona_lookup(uid_t id
)
378 struct persona
*persona
, *tmp
;
383 * simple, linear lookup for now: there shouldn't be too many
384 * of these in memory at any given time.
387 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
389 if (tmp
->pna_id
== id
&& persona_valid(tmp
)) {
390 persona
= persona_get_locked(tmp
);
401 int persona_find(const char *login
, uid_t uid
,
402 struct persona
**persona
, size_t *plen
)
410 if (uid
!= PERSONA_ID_NONE
)
416 persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
420 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
423 if (login
&& strncmp(tmp
->pna_login
, login
, sizeof(tmp
->pna_login
)) == 0)
425 if (uid
!= PERSONA_ID_NONE
&& uid
== tmp
->pna_id
)
428 if (persona
&& *plen
> found
)
429 persona
[found
] = persona_get_locked(tmp
);
434 persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
435 tmp
->pna_id
, m
, match
, (int)found
, (int)*plen
);
447 struct persona
*persona_proc_get(pid_t pid
)
449 struct persona
*persona
;
450 proc_t p
= proc_find(pid
);
456 persona
= persona_get(p
->p_persona
);
464 struct persona
*current_persona_get(void)
466 proc_t p
= current_proc();
467 struct persona
*persona
;
470 persona
= persona_get(p
->p_persona
);
477 * inherit a persona from parent to child
479 int persona_proc_inherit(proc_t child
, proc_t parent
)
481 if (child
->p_persona
!= NULL
) {
482 persona_dbg("proc_inherit: child already in persona: %s",
483 persona_desc(child
->p_persona
, 0));
487 /* no persona to inherit */
488 if (parent
->p_persona
== NULL
)
491 return persona_proc_adopt(child
, parent
->p_persona
, parent
->p_ucred
);
494 int persona_proc_adopt_id(proc_t p
, uid_t id
, kauth_cred_t auth_override
)
497 struct persona
*persona
;
499 persona
= persona_lookup(id
);
503 ret
= persona_proc_adopt(p
, persona
, auth_override
);
505 /* put the reference from the lookup() */
506 persona_put(persona
);
512 typedef enum e_persona_reset_op
{
513 PROC_REMOVE_PERSONA
= 1,
514 PROC_RESET_OLD_PERSONA
= 2,
515 } persona_reset_op_t
;
518 * internal cleanup routine for proc_set_cred_internal
521 static struct persona
*proc_reset_persona_internal(proc_t p
, persona_reset_op_t op
,
522 struct persona
*old_persona
,
523 struct persona
*new_persona
)
525 #if (DEVELOPMENT || DEBUG)
526 persona_lock_assert_held(new_persona
);
530 case PROC_REMOVE_PERSONA
:
531 old_persona
= p
->p_persona
;
533 case PROC_RESET_OLD_PERSONA
:
536 /* invalid arguments */
540 /* unlock the new persona (locked on entry) */
541 persona_unlock(new_persona
);
542 /* lock the old persona and the process */
543 persona_lock(old_persona
);
547 case PROC_REMOVE_PERSONA
:
548 LIST_REMOVE(p
, p_persona_list
);
551 case PROC_RESET_OLD_PERSONA
:
552 p
->p_persona
= old_persona
;
553 LIST_INSERT_HEAD(&old_persona
->pna_members
, p
, p_persona_list
);
558 persona_unlock(old_persona
);
560 /* re-lock the new persona */
561 persona_lock(new_persona
);
566 * Assumes persona is locked.
567 * On success, takes a reference to 'persona' and returns the
568 * previous persona the process had adopted. The caller is
569 * responsible to release the reference.
571 static struct persona
*proc_set_cred_internal(proc_t p
, struct persona
*persona
,
572 kauth_cred_t auth_override
, int *rlim_error
)
574 struct persona
*old_persona
= NULL
;
575 kauth_cred_t my_cred
, my_new_cred
;
576 uid_t old_uid
, new_uid
;
580 * This operation must be done under the proc trans lock
581 * by the thread which took the trans lock!
583 assert(((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) &&
584 p
->p_transholder
== current_thread());
585 assert(persona
!= NULL
);
587 /* no work to do if we "re-adopt" the same persona */
588 if (p
->p_persona
== persona
)
592 * If p is in a persona, then we need to remove 'p' from the list of
593 * processes in that persona. To do this, we need to drop the lock
594 * held on the incoming (new) persona and lock the old one.
597 old_persona
= proc_reset_persona_internal(p
, PROC_REMOVE_PERSONA
,
602 my_new_cred
= auth_override
;
604 my_new_cred
= persona
->pna_cred
;
607 panic("NULL credentials (persona:%p)", persona
);
611 kauth_cred_ref(my_new_cred
);
613 new_uid
= persona
->pna_id
;
616 * Check to see if we will hit a proc rlimit by moving the process
617 * into the persona. If so, we'll bail early before actually moving
618 * the process or changing its credentials.
621 (rlim_t
)chgproccnt(new_uid
, 0) > p
->p_rlimit
[RLIMIT_NPROC
].rlim_cur
) {
622 pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
623 p
->p_pid
, new_uid
, persona_desc(persona
, 1));
624 *rlim_error
= EACCES
;
625 (void)proc_reset_persona_internal(p
, PROC_RESET_OLD_PERSONA
,
626 old_persona
, persona
);
627 kauth_cred_unref(&my_new_cred
);
632 * Set the new credentials on the proc
635 my_cred
= kauth_cred_proc_ref(p
);
636 persona_dbg("proc_adopt PID:%d, %s -> %s",
638 persona_desc(old_persona
, 1),
639 persona_desc(persona
, 1));
641 old_uid
= kauth_cred_getruid(my_cred
);
643 if (my_cred
!= my_new_cred
) {
644 kauth_cred_t old_cred
= my_cred
;
648 * We need to protect against a race where another thread
649 * also changed the credential after we took our
650 * reference. If p_ucred has changed then we should
651 * restart this again with the new cred.
653 if (p
->p_ucred
!= my_cred
) {
654 proc_ucred_unlock(p
);
655 kauth_cred_unref(&my_cred
);
660 /* update the credential and take a ref for the proc */
661 kauth_cred_ref(my_new_cred
);
662 p
->p_ucred
= my_new_cred
;
664 /* update cred on proc (and current thread) */
665 mach_kauth_cred_uthread_update();
666 PROC_UPDATE_CREDS_ONPROC(p
);
668 /* drop the proc's old ref on the credential */
669 kauth_cred_unref(&old_cred
);
670 proc_ucred_unlock(p
);
673 /* drop this function's reference to the old cred */
674 kauth_cred_unref(&my_cred
);
677 * Update the proc count.
678 * If the UIDs are the same, then there is no work to do.
681 old_uid
= old_persona
->pna_id
;
683 if (new_uid
!= old_uid
) {
684 count
= chgproccnt(old_uid
, -1);
685 persona_dbg("Decrement %s:%d proc_count to: %d",
686 old_persona
? "Persona" : "UID", old_uid
, count
);
689 * Increment the proc count on the UID associated with
690 * the new persona. Enforce the resource limit just
693 count
= chgproccnt(new_uid
, 1);
694 persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %d",
695 new_uid
, kauth_cred_getuid(my_new_cred
), count
);
698 OSBitOrAtomic(P_ADOPTPERSONA
, &p
->p_flag
);
701 p
->p_persona
= persona_get_locked(persona
);
702 LIST_INSERT_HEAD(&persona
->pna_members
, p
, p_persona_list
);
705 kauth_cred_unref(&my_new_cred
);
710 int persona_proc_adopt(proc_t p
, struct persona
*persona
, kauth_cred_t auth_override
)
713 struct persona
*old_persona
;
714 struct session
* sessp
;
719 persona_dbg("%d adopting Persona %d (%s)", proc_pid(p
),
720 persona
->pna_id
, persona_desc(persona
, 0));
722 persona_lock(persona
);
723 if (!persona
->pna_cred
|| !persona_valid(persona
)) {
724 persona_dbg("Invalid persona (%s): NULL credentials!", persona_desc(persona
, 1));
725 persona_unlock(persona
);
729 /* the persona credentials can no longer be adjusted */
730 persona
->pna_cred_locked
= 1;
733 * assume the persona: this may drop and re-acquire the persona lock!
736 old_persona
= proc_set_cred_internal(p
, persona
, auth_override
, &error
);
738 /* join the process group associated with the persona */
739 if (persona
->pna_pgid
) {
740 uid_t uid
= kauth_cred_getuid(persona
->pna_cred
);
741 persona_dbg(" PID:%d, pgid:%d%s",
742 p
->p_pid
, persona
->pna_pgid
,
743 persona
->pna_pgid
== uid
? ", new_session" : ".");
744 enterpgrp(p
, persona
->pna_pgid
, persona
->pna_pgid
== uid
);
747 /* set the login name of the session */
748 sessp
= proc_session(p
);
749 if (sessp
!= SESSION_NULL
) {
751 bcopy(persona
->pna_login
, sessp
->s_login
, MAXLOGNAME
);
752 session_unlock(sessp
);
756 persona_unlock(persona
);
758 set_security_token(p
);
761 * Drop the reference to the old persona.
764 persona_put(old_persona
);
766 persona_dbg("%s", error
== 0 ? "SUCCESS" : "FAILED");
770 int persona_proc_drop(proc_t p
)
772 struct persona
*persona
= NULL
;
774 persona_dbg("PID:%d, %s -> <none>", p
->p_pid
, persona_desc(p
->p_persona
, 0));
777 * There are really no other credentials for us to assume,
778 * so we'll just continue running with the credentials
779 * we got from the persona.
783 * the locks must be taken in reverse order here, so
784 * we have to be careful not to cause deadlock
790 if (!persona_try_lock(p
->p_persona
)) {
792 mutex_pause(0); /* back-off time */
795 persona
= p
->p_persona
;
796 LIST_REMOVE(p
, p_persona_list
);
799 ruid
= kauth_cred_getruid(p
->p_ucred
);
800 puid
= kauth_cred_getuid(persona
->pna_cred
);
802 (void)chgproccnt(ruid
, 1);
803 (void)chgproccnt(puid
, -1);
809 * if the proc had a persona, then it is still locked here
810 * (preserving proper lock ordering)
814 persona_unlock(persona
);
815 persona_put(persona
);
821 int persona_get_type(struct persona
*persona
)
826 return PERSONA_INVALID
;
828 persona_lock(persona
);
829 if (!persona_valid(persona
)) {
830 persona_unlock(persona
);
831 return PERSONA_INVALID
;
833 type
= persona
->pna_type
;
834 persona_unlock(persona
);
839 int persona_set_cred(struct persona
*persona
, kauth_cred_t cred
)
842 kauth_cred_t my_cred
;
843 if (!persona
|| !cred
)
846 persona_lock(persona
);
847 if (!persona_valid(persona
)) {
851 if (persona
->pna_cred_locked
) {
856 /* create a new cred from the passed-in cred */
857 my_cred
= kauth_cred_create(cred
);
859 /* ensure that the UID matches the persona ID */
860 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
861 persona
->pna_id
, persona
->pna_id
,
864 /* TODO: clear the saved GID?! */
866 /* replace the persona's cred with the new one */
867 if (persona
->pna_cred
)
868 kauth_cred_unref(&persona
->pna_cred
);
869 persona
->pna_cred
= my_cred
;
872 persona_unlock(persona
);
876 int persona_set_cred_from_proc(struct persona
*persona
, proc_t proc
)
879 kauth_cred_t parent_cred
, my_cred
;
880 if (!persona
|| !proc
)
883 persona_lock(persona
);
884 if (!persona_valid(persona
)) {
888 if (persona
->pna_cred_locked
) {
893 parent_cred
= kauth_cred_proc_ref(proc
);
895 /* TODO: clear the saved UID/GID! */
897 /* create a new cred from the proc's cred */
898 my_cred
= kauth_cred_create(parent_cred
);
900 /* ensure that the UID matches the persona ID */
901 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
902 persona
->pna_id
, persona
->pna_id
,
905 /* replace the persona's cred with the new one */
906 if (persona
->pna_cred
)
907 kauth_cred_unref(&persona
->pna_cred
);
908 persona
->pna_cred
= my_cred
;
910 kauth_cred_unref(&parent_cred
);
913 persona_unlock(persona
);
917 kauth_cred_t
persona_get_cred(struct persona
*persona
)
919 kauth_cred_t cred
= NULL
;
924 persona_lock(persona
);
925 if (!persona_valid(persona
))
928 if (persona
->pna_cred
) {
929 kauth_cred_ref(persona
->pna_cred
);
930 cred
= persona
->pna_cred
;
934 persona_unlock(persona
);
939 uid_t
persona_get_uid(struct persona
*persona
)
943 if (!persona
|| !persona
->pna_cred
)
946 persona_lock(persona
);
947 if (persona_valid(persona
)) {
948 uid
= kauth_cred_getuid(persona
->pna_cred
);
949 assert(uid
== persona
->pna_id
);
951 persona_unlock(persona
);
956 int persona_set_gid(struct persona
*persona
, gid_t gid
)
959 kauth_cred_t my_cred
, new_cred
;
961 if (!persona
|| !persona
->pna_cred
)
964 persona_lock(persona
);
965 if (!persona_valid(persona
)) {
969 if (persona
->pna_cred_locked
) {
974 my_cred
= persona
->pna_cred
;
975 kauth_cred_ref(my_cred
);
976 new_cred
= kauth_cred_setresgid(my_cred
, gid
, gid
, gid
);
977 if (new_cred
!= my_cred
)
978 persona
->pna_cred
= new_cred
;
979 kauth_cred_unref(&my_cred
);
982 persona_unlock(persona
);
986 gid_t
persona_get_gid(struct persona
*persona
)
990 if (!persona
|| !persona
->pna_cred
)
993 persona_lock(persona
);
994 if (persona_valid(persona
))
995 gid
= kauth_cred_getgid(persona
->pna_cred
);
996 persona_unlock(persona
);
1001 int persona_set_groups(struct persona
*persona
, gid_t
*groups
, int ngroups
, uid_t gmuid
)
1004 kauth_cred_t my_cred
, new_cred
;
1006 if (!persona
|| !persona
->pna_cred
)
1008 if (ngroups
> NGROUPS_MAX
)
1011 persona_lock(persona
);
1012 if (!persona_valid(persona
)) {
1016 if (persona
->pna_cred_locked
) {
1021 my_cred
= persona
->pna_cred
;
1022 kauth_cred_ref(my_cred
);
1023 new_cred
= kauth_cred_setgroups(my_cred
, groups
, ngroups
, gmuid
);
1024 if (new_cred
!= my_cred
)
1025 persona
->pna_cred
= new_cred
;
1026 kauth_cred_unref(&my_cred
);
1029 persona_unlock(persona
);
1033 int persona_get_groups(struct persona
*persona
, int *ngroups
, gid_t
*groups
, int groups_sz
)
1036 if (!persona
|| !persona
->pna_cred
|| !groups
|| !ngroups
)
1039 *ngroups
= groups_sz
;
1041 persona_lock(persona
);
1042 if (persona_valid(persona
)) {
1043 kauth_cred_getgroups(persona
->pna_cred
, groups
, ngroups
);
1046 persona_unlock(persona
);
1051 uid_t
persona_get_gmuid(struct persona
*persona
)
1053 uid_t gmuid
= KAUTH_UID_NONE
;
1055 if (!persona
|| !persona
->pna_cred
)
1058 persona_lock(persona
);
1059 if (!persona_valid(persona
))
1062 posix_cred_t pcred
= posix_cred_get(persona
->pna_cred
);
1063 gmuid
= pcred
->cr_gmuid
;
1066 persona_unlock(persona
);
1070 int persona_get_login(struct persona
*persona
, char login
[MAXLOGNAME
+1])
1073 if (!persona
|| !persona
->pna_cred
)
1076 persona_lock(persona
);
1077 if (!persona_valid(persona
))
1080 strlcpy(login
, persona
->pna_login
, MAXLOGNAME
);
1084 persona_unlock(persona
);
1085 login
[MAXLOGNAME
] = 0;
1090 #else /* !CONFIG_PERSONAS */
1093 * symbol exports for kext compatibility
1096 uid_t
persona_get_id(__unused
struct persona
*persona
)
1098 return PERSONA_ID_NONE
;
1101 int persona_get_type(__unused
struct persona
*persona
)
1103 return PERSONA_INVALID
;
1106 kauth_cred_t
persona_get_cred(__unused
struct persona
*persona
)
1111 struct persona
*persona_lookup(__unused uid_t id
)
1116 int persona_find(__unused
const char *login
,
1118 __unused
struct persona
**persona
,
1119 __unused
size_t *plen
)
1124 struct persona
*current_persona_get(void)
1129 struct persona
*persona_get(struct persona
*persona
)
1134 void persona_put(__unused
struct persona
*persona
)