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>
45 #define pna_err(fmt, ...) \
46 os_log_error(OS_LOG_DEFAULT, "ERROR: " fmt, ## __VA_ARGS__)
48 #define MAX_PERSONAS 512
50 #define TEMP_PERSONA_ID 499
52 #define FIRST_PERSONA_ID 501
53 #define PERSONA_ID_STEP 10
55 #define PERSONA_SYSTEM_UID ((uid_t)99)
56 #define PERSONA_SYSTEM_LOGIN "system"
58 #define PERSONA_ALLOC_TOKEN (0x7a0000ae)
59 #define PERSONA_INIT_TOKEN (0x7500005e)
60 #define PERSONA_MAGIC (0x0aa55aa0)
61 #define persona_initialized(p) ((p)->pna_valid == PERSONA_MAGIC || (p)->pna_valid == PERSONA_INIT_TOKEN)
62 #define persona_valid(p) ((p)->pna_valid == PERSONA_MAGIC)
63 #define persona_mkinvalid(p) ((p)->pna_valid = ~(PERSONA_MAGIC))
65 static LIST_HEAD(personalist
, persona
) all_personas
;
66 static uint32_t g_total_personas
;
67 uint32_t g_max_personas
= MAX_PERSONAS
;
69 struct persona
*g_system_persona
= NULL
;
71 static uid_t g_next_persona_id
;
73 lck_mtx_t all_personas_lock
;
74 lck_attr_t
*persona_lck_attr
;
75 lck_grp_t
*persona_lck_grp
;
76 lck_grp_attr_t
*persona_lck_grp_attr
;
78 os_refgrp_decl(static, persona_refgrp
, "persona", NULL
);
80 static zone_t persona_zone
;
82 kauth_cred_t g_default_persona_cred
;
84 #define lock_personas() lck_mtx_lock(&all_personas_lock)
85 #define unlock_personas() lck_mtx_unlock(&all_personas_lock)
88 extern void mach_kauth_cred_uthread_update(void);
91 personas_bootstrap(void)
93 struct posix_cred pcred
;
95 persona_dbg("Initializing persona subsystem");
96 LIST_INIT(&all_personas
);
99 g_next_persona_id
= FIRST_PERSONA_ID
;
101 persona_lck_grp_attr
= lck_grp_attr_alloc_init();
103 persona_lck_grp
= lck_grp_alloc_init("personas", persona_lck_grp_attr
);
104 persona_lck_attr
= lck_attr_alloc_init();
106 lck_mtx_init(&all_personas_lock
, persona_lck_grp
, persona_lck_attr
);
108 persona_zone
= zinit(sizeof(struct persona
),
109 MAX_PERSONAS
* sizeof(struct persona
),
110 MAX_PERSONAS
, "personas");
111 assert(persona_zone
!= NULL
);
114 * setup the default credentials that a persona temporarily
115 * inherits (to work around kauth APIs)
117 bzero(&pcred
, sizeof(pcred
));
118 pcred
.cr_uid
= pcred
.cr_ruid
= pcred
.cr_svuid
= TEMP_PERSONA_ID
;
119 pcred
.cr_rgid
= pcred
.cr_svgid
= TEMP_PERSONA_ID
;
120 pcred
.cr_groups
[0] = TEMP_PERSONA_ID
;
121 pcred
.cr_ngroups
= 1;
122 pcred
.cr_flags
= CRF_NOMEMBERD
;
123 pcred
.cr_gmuid
= KAUTH_UID_NONE
;
125 g_default_persona_cred
= posix_cred_create(&pcred
);
126 if (!g_default_persona_cred
) {
127 panic("couldn't create default persona credentials!");
130 g_system_persona
= persona_alloc(PERSONA_SYSTEM_UID
,
131 PERSONA_SYSTEM_LOGIN
,
132 PERSONA_SYSTEM
, NULL
);
133 int err
= persona_init_begin(g_system_persona
);
136 persona_init_end(g_system_persona
, err
);
138 assert(g_system_persona
!= NULL
);
142 persona_alloc(uid_t id
, const char *login
, int type
, int *error
)
144 struct persona
*persona
;
148 pna_err("Must provide a login name for a new persona!");
155 if (type
<= PERSONA_INVALID
|| type
> PERSONA_TYPE_MAX
) {
156 pna_err("Invalid type: %d", type
);
163 persona
= (struct persona
*)zalloc(persona_zone
);
171 bzero(persona
, sizeof(*persona
));
173 if (hw_atomic_add(&g_total_personas
, 1) > MAX_PERSONAS
) {
174 /* too many personas! */
175 pna_err("too many active personas!");
180 strncpy(persona
->pna_login
, login
, sizeof(persona
->pna_login
) - 1);
181 persona_dbg("Starting persona allocation for: '%s'", persona
->pna_login
);
183 LIST_INIT(&persona
->pna_members
);
184 lck_mtx_init(&persona
->pna_lock
, persona_lck_grp
, persona_lck_attr
);
185 os_ref_init(&persona
->pna_refcount
, &persona_refgrp
);
188 * Setup initial (temporary) kauth_cred structure
189 * We need to do this here because all kauth calls require
190 * an existing cred structure.
192 persona
->pna_cred
= kauth_cred_create(g_default_persona_cred
);
193 if (!persona
->pna_cred
) {
194 pna_err("could not copy initial credentials!");
199 persona
->pna_type
= type
;
200 persona
->pna_id
= id
;
201 persona
->pna_valid
= PERSONA_ALLOC_TOKEN
;
204 * NOTE: this persona has not been fully initialized. A subsequent
205 * call to persona_init_begin() followed by persona_init_end() will make
206 * the persona visible to the rest of the system.
214 (void)hw_atomic_add(&g_total_personas
, -1);
215 zfree(persona_zone
, persona
);
225 * This function begins initialization of a persona. It first acquires the
226 * global persona list lock via lock_personas(), then selects an appropriate
227 * persona ID and sets up the persona's credentials. This function *must* be
228 * followed by a call to persona_init_end() which will mark the persona
232 * persona has been allocated via persona_alloc()
236 * global persona list is locked (even on error)
239 persona_init_begin(struct persona
*persona
)
243 kauth_cred_t tmp_cred
;
247 if (!persona
|| (persona
->pna_valid
!= PERSONA_ALLOC_TOKEN
)) {
251 id
= persona
->pna_id
;
255 if (id
== PERSONA_ID_NONE
) {
256 persona
->pna_id
= g_next_persona_id
;
259 persona_dbg("Beginning Initialization of %d:%d (%s)...", id
, persona
->pna_id
, persona
->pna_login
);
262 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
264 if (id
== PERSONA_ID_NONE
&& tmp
->pna_id
== persona
->pna_id
) {
267 * someone else manually claimed this ID, and we're
268 * trying to allocate an ID for the caller: try again
270 g_next_persona_id
+= PERSONA_ID_STEP
;
273 if (strncmp(tmp
->pna_login
, persona
->pna_login
, sizeof(tmp
->pna_login
)) == 0 ||
274 tmp
->pna_id
== persona
->pna_id
) {
277 * Disallow use of identical login names and re-use
278 * of previously allocated persona IDs
289 /* ensure the cred has proper UID/GID defaults */
290 kauth_cred_ref(persona
->pna_cred
);
291 tmp_cred
= kauth_cred_setuidgid(persona
->pna_cred
,
294 kauth_cred_unref(&persona
->pna_cred
);
295 if (tmp_cred
!= persona
->pna_cred
) {
296 persona
->pna_cred
= tmp_cred
;
299 if (!persona
->pna_cred
) {
304 /* it should be a member of exactly 1 group (equal to its UID) */
305 new_group
= (gid_t
)persona
->pna_id
;
307 kauth_cred_ref(persona
->pna_cred
);
308 /* opt _out_ of memberd as a default */
309 tmp_cred
= kauth_cred_setgroups(persona
->pna_cred
,
310 &new_group
, 1, KAUTH_UID_NONE
);
311 kauth_cred_unref(&persona
->pna_cred
);
312 if (tmp_cred
!= persona
->pna_cred
) {
313 persona
->pna_cred
= tmp_cred
;
316 if (!persona
->pna_cred
) {
321 /* if the kernel supplied the persona ID, increment for next time */
322 if (id
== PERSONA_ID_NONE
) {
323 g_next_persona_id
+= PERSONA_ID_STEP
;
326 persona
->pna_valid
= PERSONA_INIT_TOKEN
;
330 persona_dbg("ERROR:%d while initializing %d:%d (%s)...", err
, id
, persona
->pna_id
, persona
->pna_login
);
332 * mark the persona with an error so that persona_init_end()
333 * will *not* add it to the global list.
335 persona
->pna_id
= PERSONA_ID_NONE
;
339 * leave the global persona list locked: it will be
340 * unlocked in a call to persona_init_end()
348 * This function finalizes the persona initialization by marking it valid and
349 * adding it to the global list of personas. After unlocking the global list,
350 * the persona will be visible to the reset of the system. The function will
351 * only mark the persona valid if the input parameter 'error' is 0.
354 * persona is initialized via persona_init_begin()
355 * global persona list is locked via lock_personas()
358 * global persona list is unlocked
361 persona_init_end(struct persona
*persona
, int error
)
363 if (persona
== NULL
) {
368 * If the pna_valid member is set to the INIT_TOKEN value, then it has
369 * successfully gone through persona_init_begin(), and we can mark it
370 * valid and make it visible to the rest of the system. However, if
371 * there was an error either during initialization or otherwise, we
372 * need to decrement the global count of personas because this one
373 * will be disposed-of by the callers invocation of persona_put().
375 if (error
!= 0 || persona
->pna_valid
== PERSONA_ALLOC_TOKEN
) {
376 persona_dbg("ERROR:%d after initialization of %d (%s)", error
, persona
->pna_id
, persona
->pna_login
);
377 /* remove this persona from the global count */
378 (void)hw_atomic_add(&g_total_personas
, -1);
379 } else if (error
== 0 &&
380 persona
->pna_valid
== PERSONA_INIT_TOKEN
) {
381 persona
->pna_valid
= PERSONA_MAGIC
;
382 LIST_INSERT_HEAD(&all_personas
, persona
, pna_list
);
383 persona_dbg("Initialization of %d (%s) Complete.", persona
->pna_id
, persona
->pna_login
);
389 static struct persona
*
390 persona_get_locked(struct persona
*persona
)
392 os_ref_retain_locked(&persona
->pna_refcount
);
397 persona_get(struct persona
*persona
)
403 persona_lock(persona
);
404 ret
= persona_get_locked(persona
);
405 persona_unlock(persona
);
411 persona_put(struct persona
*persona
)
419 persona_lock(persona
);
420 if (os_ref_release_locked(&persona
->pna_refcount
) == 0) {
423 persona_unlock(persona
);
429 persona_dbg("Destroying persona %s", persona_desc(persona
, 0));
431 /* release our credential reference */
432 if (persona
->pna_cred
) {
433 kauth_cred_unref(&persona
->pna_cred
);
436 /* remove it from the global list and decrement the count */
438 persona_lock(persona
);
439 if (persona_valid(persona
)) {
440 LIST_REMOVE(persona
, pna_list
);
441 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
) {
442 panic("persona count underflow!\n");
444 persona_mkinvalid(persona
);
446 persona_unlock(persona
);
449 assert(LIST_EMPTY(&persona
->pna_members
));
450 memset(persona
, 0, sizeof(*persona
));
451 zfree(persona_zone
, persona
);
455 persona_get_id(struct persona
*persona
)
458 return persona
->pna_id
;
460 return PERSONA_ID_NONE
;
464 persona_lookup(uid_t id
)
466 struct persona
*persona
, *tmp
;
471 * simple, linear lookup for now: there shouldn't be too many
472 * of these in memory at any given time.
475 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
477 if (tmp
->pna_id
== id
&& persona_valid(tmp
)) {
478 persona
= persona_get_locked(tmp
);
490 persona_lookup_and_invalidate(uid_t id
)
492 struct persona
*persona
, *entry
, *tmp
;
497 LIST_FOREACH_SAFE(entry
, &all_personas
, pna_list
, tmp
) {
499 if (entry
->pna_id
== id
) {
500 if (persona_valid(entry
)) {
501 persona
= persona_get_locked(entry
);
502 assert(persona
!= NULL
);
503 LIST_REMOVE(persona
, pna_list
);
504 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
) {
505 panic("persona ref count underflow!\n");
507 persona_mkinvalid(persona
);
509 persona_unlock(entry
);
512 persona_unlock(entry
);
520 persona_find(const char *login
, uid_t uid
,
521 struct persona
**persona
, size_t *plen
)
530 if (uid
!= PERSONA_ID_NONE
) {
538 persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
542 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
545 if (login
&& strncmp(tmp
->pna_login
, login
, sizeof(tmp
->pna_login
)) == 0) {
548 if (uid
!= PERSONA_ID_NONE
&& uid
== tmp
->pna_id
) {
552 if (persona
&& *plen
> found
) {
553 persona
[found
] = persona_get_locked(tmp
);
559 persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
560 tmp
->pna_id
, m
, match
, (int)found
, (int)*plen
);
575 persona_proc_get(pid_t pid
)
577 struct persona
*persona
;
578 proc_t p
= proc_find(pid
);
585 persona
= persona_get(p
->p_persona
);
594 current_persona_get(void)
596 proc_t p
= current_proc();
597 struct persona
*persona
;
600 persona
= persona_get(p
->p_persona
);
607 * inherit a persona from parent to child
610 persona_proc_inherit(proc_t child
, proc_t parent
)
612 if (child
->p_persona
!= NULL
) {
613 persona_dbg("proc_inherit: child already in persona: %s",
614 persona_desc(child
->p_persona
, 0));
618 /* no persona to inherit */
619 if (parent
->p_persona
== NULL
) {
623 return persona_proc_adopt(child
, parent
->p_persona
, parent
->p_ucred
);
627 persona_proc_adopt_id(proc_t p
, uid_t id
, kauth_cred_t auth_override
)
630 struct persona
*persona
;
632 persona
= persona_lookup(id
);
637 ret
= persona_proc_adopt(p
, persona
, auth_override
);
639 /* put the reference from the lookup() */
640 persona_put(persona
);
646 typedef enum e_persona_reset_op
{
647 PROC_REMOVE_PERSONA
= 1,
648 PROC_RESET_OLD_PERSONA
= 2,
649 } persona_reset_op_t
;
652 * internal cleanup routine for proc_set_cred_internal
655 static struct persona
*
656 proc_reset_persona_internal(proc_t p
, persona_reset_op_t op
,
657 struct persona
*old_persona
,
658 struct persona
*new_persona
)
660 #if (DEVELOPMENT || DEBUG)
661 persona_lock_assert_held(new_persona
);
665 case PROC_REMOVE_PERSONA
:
666 old_persona
= p
->p_persona
;
668 case PROC_RESET_OLD_PERSONA
:
671 /* invalid arguments */
675 /* unlock the new persona (locked on entry) */
676 persona_unlock(new_persona
);
677 /* lock the old persona and the process */
678 persona_lock(old_persona
);
682 case PROC_REMOVE_PERSONA
:
683 LIST_REMOVE(p
, p_persona_list
);
686 case PROC_RESET_OLD_PERSONA
:
687 p
->p_persona
= old_persona
;
688 LIST_INSERT_HEAD(&old_persona
->pna_members
, p
, p_persona_list
);
693 persona_unlock(old_persona
);
695 /* re-lock the new persona */
696 persona_lock(new_persona
);
701 * Assumes persona is locked.
702 * On success, takes a reference to 'persona' and returns the
703 * previous persona the process had adopted. The caller is
704 * responsible to release the reference.
706 static struct persona
*
707 proc_set_cred_internal(proc_t p
, struct persona
*persona
,
708 kauth_cred_t auth_override
, int *rlim_error
)
710 struct persona
*old_persona
= NULL
;
711 kauth_cred_t my_cred
, my_new_cred
;
712 uid_t old_uid
, new_uid
;
716 * This operation must be done under the proc trans lock
717 * by the thread which took the trans lock!
719 assert(((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) &&
720 p
->p_transholder
== current_thread());
721 assert(persona
!= NULL
);
723 /* no work to do if we "re-adopt" the same persona */
724 if (p
->p_persona
== persona
) {
729 * If p is in a persona, then we need to remove 'p' from the list of
730 * processes in that persona. To do this, we need to drop the lock
731 * held on the incoming (new) persona and lock the old one.
734 old_persona
= proc_reset_persona_internal(p
, PROC_REMOVE_PERSONA
,
739 my_new_cred
= auth_override
;
741 my_new_cred
= persona
->pna_cred
;
745 panic("NULL credentials (persona:%p)", persona
);
750 kauth_cred_ref(my_new_cred
);
752 new_uid
= persona
->pna_id
;
755 * Check to see if we will hit a proc rlimit by moving the process
756 * into the persona. If so, we'll bail early before actually moving
757 * the process or changing its credentials.
760 (rlim_t
)chgproccnt(new_uid
, 0) > p
->p_rlimit
[RLIMIT_NPROC
].rlim_cur
) {
761 pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
762 p
->p_pid
, new_uid
, persona_desc(persona
, 1));
763 *rlim_error
= EACCES
;
764 (void)proc_reset_persona_internal(p
, PROC_RESET_OLD_PERSONA
,
765 old_persona
, persona
);
766 kauth_cred_unref(&my_new_cred
);
771 * Set the new credentials on the proc
774 my_cred
= kauth_cred_proc_ref(p
);
775 persona_dbg("proc_adopt PID:%d, %s -> %s",
777 persona_desc(old_persona
, 1),
778 persona_desc(persona
, 1));
780 old_uid
= kauth_cred_getruid(my_cred
);
782 if (my_cred
!= my_new_cred
) {
783 kauth_cred_t old_cred
= my_cred
;
787 * We need to protect against a race where another thread
788 * also changed the credential after we took our
789 * reference. If p_ucred has changed then we should
790 * restart this again with the new cred.
792 if (p
->p_ucred
!= my_cred
) {
793 proc_ucred_unlock(p
);
794 kauth_cred_unref(&my_cred
);
799 /* update the credential and take a ref for the proc */
800 kauth_cred_ref(my_new_cred
);
801 p
->p_ucred
= my_new_cred
;
803 /* update cred on proc (and current thread) */
804 mach_kauth_cred_uthread_update();
805 PROC_UPDATE_CREDS_ONPROC(p
);
807 /* drop the proc's old ref on the credential */
808 kauth_cred_unref(&old_cred
);
809 proc_ucred_unlock(p
);
812 /* drop this function's reference to the old cred */
813 kauth_cred_unref(&my_cred
);
816 * Update the proc count.
817 * If the UIDs are the same, then there is no work to do.
820 old_uid
= old_persona
->pna_id
;
823 if (new_uid
!= old_uid
) {
824 count
= chgproccnt(old_uid
, -1);
825 persona_dbg("Decrement %s:%d proc_count to: %d",
826 old_persona
? "Persona" : "UID", old_uid
, count
);
829 * Increment the proc count on the UID associated with
830 * the new persona. Enforce the resource limit just
833 count
= chgproccnt(new_uid
, 1);
834 persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %d",
835 new_uid
, kauth_cred_getuid(my_new_cred
), count
);
838 OSBitOrAtomic(P_ADOPTPERSONA
, &p
->p_flag
);
841 p
->p_persona
= persona_get_locked(persona
);
842 LIST_INSERT_HEAD(&persona
->pna_members
, p
, p_persona_list
);
845 kauth_cred_unref(&my_new_cred
);
851 persona_proc_adopt(proc_t p
, struct persona
*persona
, kauth_cred_t auth_override
)
854 struct persona
*old_persona
;
855 struct session
* sessp
;
861 persona_dbg("%d adopting Persona %d (%s)", proc_pid(p
),
862 persona
->pna_id
, persona_desc(persona
, 0));
864 persona_lock(persona
);
865 if (!persona
->pna_cred
|| !persona_valid(persona
)) {
866 persona_dbg("Invalid persona (%s): NULL credentials!", persona_desc(persona
, 1));
867 persona_unlock(persona
);
871 /* the persona credentials can no longer be adjusted */
872 persona
->pna_cred_locked
= 1;
875 * assume the persona: this may drop and re-acquire the persona lock!
878 old_persona
= proc_set_cred_internal(p
, persona
, auth_override
, &error
);
880 /* join the process group associated with the persona */
881 if (persona
->pna_pgid
) {
882 uid_t uid
= kauth_cred_getuid(persona
->pna_cred
);
883 persona_dbg(" PID:%d, pgid:%d%s",
884 p
->p_pid
, persona
->pna_pgid
,
885 persona
->pna_pgid
== uid
? ", new_session" : ".");
886 enterpgrp(p
, persona
->pna_pgid
, persona
->pna_pgid
== uid
);
889 /* set the login name of the session */
890 sessp
= proc_session(p
);
891 if (sessp
!= SESSION_NULL
) {
893 bcopy(persona
->pna_login
, sessp
->s_login
, MAXLOGNAME
);
894 session_unlock(sessp
);
898 persona_unlock(persona
);
900 set_security_token(p
);
903 * Drop the reference to the old persona.
906 persona_put(old_persona
);
909 persona_dbg("%s", error
== 0 ? "SUCCESS" : "FAILED");
914 persona_proc_drop(proc_t p
)
916 struct persona
*persona
= NULL
;
918 persona_dbg("PID:%d, %s -> <none>", p
->p_pid
, persona_desc(p
->p_persona
, 0));
921 * There are really no other credentials for us to assume,
922 * so we'll just continue running with the credentials
923 * we got from the persona.
927 * the locks must be taken in reverse order here, so
928 * we have to be careful not to cause deadlock
934 if (!persona_try_lock(p
->p_persona
)) {
936 mutex_pause(0); /* back-off time */
939 persona
= p
->p_persona
;
940 LIST_REMOVE(p
, p_persona_list
);
943 ruid
= kauth_cred_getruid(p
->p_ucred
);
944 puid
= kauth_cred_getuid(persona
->pna_cred
);
946 (void)chgproccnt(ruid
, 1);
947 (void)chgproccnt(puid
, -1);
953 * if the proc had a persona, then it is still locked here
954 * (preserving proper lock ordering)
958 persona_unlock(persona
);
959 persona_put(persona
);
966 persona_get_type(struct persona
*persona
)
971 return PERSONA_INVALID
;
974 persona_lock(persona
);
975 if (!persona_valid(persona
)) {
976 persona_unlock(persona
);
977 return PERSONA_INVALID
;
979 type
= persona
->pna_type
;
980 persona_unlock(persona
);
986 persona_set_cred(struct persona
*persona
, kauth_cred_t cred
)
989 kauth_cred_t my_cred
;
990 if (!persona
|| !cred
) {
994 persona_lock(persona
);
995 if (!persona_initialized(persona
)) {
999 if (persona
->pna_cred_locked
) {
1004 /* create a new cred from the passed-in cred */
1005 my_cred
= kauth_cred_create(cred
);
1007 /* ensure that the UID matches the persona ID */
1008 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
1009 persona
->pna_id
, persona
->pna_id
,
1012 /* TODO: clear the saved GID?! */
1014 /* replace the persona's cred with the new one */
1015 if (persona
->pna_cred
) {
1016 kauth_cred_unref(&persona
->pna_cred
);
1018 persona
->pna_cred
= my_cred
;
1021 persona_unlock(persona
);
1026 persona_set_cred_from_proc(struct persona
*persona
, proc_t proc
)
1029 kauth_cred_t parent_cred
, my_cred
;
1030 if (!persona
|| !proc
) {
1034 persona_lock(persona
);
1035 if (!persona_initialized(persona
)) {
1039 if (persona
->pna_cred_locked
) {
1044 parent_cred
= kauth_cred_proc_ref(proc
);
1046 /* TODO: clear the saved UID/GID! */
1048 /* create a new cred from the proc's cred */
1049 my_cred
= kauth_cred_create(parent_cred
);
1051 /* ensure that the UID matches the persona ID */
1052 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
1053 persona
->pna_id
, persona
->pna_id
,
1056 /* replace the persona's cred with the new one */
1057 if (persona
->pna_cred
) {
1058 kauth_cred_unref(&persona
->pna_cred
);
1060 persona
->pna_cred
= my_cred
;
1062 kauth_cred_unref(&parent_cred
);
1065 persona_unlock(persona
);
1070 persona_get_cred(struct persona
*persona
)
1072 kauth_cred_t cred
= NULL
;
1078 persona_lock(persona
);
1079 if (!persona_valid(persona
)) {
1083 if (persona
->pna_cred
) {
1084 kauth_cred_ref(persona
->pna_cred
);
1085 cred
= persona
->pna_cred
;
1089 persona_unlock(persona
);
1095 persona_get_uid(struct persona
*persona
)
1097 uid_t uid
= UID_MAX
;
1099 if (!persona
|| !persona
->pna_cred
) {
1103 persona_lock(persona
);
1104 if (persona_valid(persona
)) {
1105 uid
= kauth_cred_getuid(persona
->pna_cred
);
1106 assert(uid
== persona
->pna_id
);
1108 persona_unlock(persona
);
1114 persona_set_gid(struct persona
*persona
, gid_t gid
)
1117 kauth_cred_t my_cred
, new_cred
;
1119 if (!persona
|| !persona
->pna_cred
) {
1123 persona_lock(persona
);
1124 if (!persona_initialized(persona
)) {
1128 if (persona
->pna_cred_locked
) {
1133 my_cred
= persona
->pna_cred
;
1134 kauth_cred_ref(my_cred
);
1135 new_cred
= kauth_cred_setresgid(my_cred
, gid
, gid
, gid
);
1136 if (new_cred
!= my_cred
) {
1137 persona
->pna_cred
= new_cred
;
1139 kauth_cred_unref(&my_cred
);
1142 persona_unlock(persona
);
1147 persona_get_gid(struct persona
*persona
)
1149 gid_t gid
= GID_MAX
;
1151 if (!persona
|| !persona
->pna_cred
) {
1155 persona_lock(persona
);
1156 if (persona_valid(persona
)) {
1157 gid
= kauth_cred_getgid(persona
->pna_cred
);
1159 persona_unlock(persona
);
1165 persona_set_groups(struct persona
*persona
, gid_t
*groups
, unsigned ngroups
, uid_t gmuid
)
1168 kauth_cred_t my_cred
, new_cred
;
1170 if (!persona
|| !persona
->pna_cred
) {
1173 if (ngroups
> NGROUPS_MAX
) {
1177 persona_lock(persona
);
1178 if (!persona_initialized(persona
)) {
1182 if (persona
->pna_cred_locked
) {
1187 my_cred
= persona
->pna_cred
;
1188 kauth_cred_ref(my_cred
);
1189 new_cred
= kauth_cred_setgroups(my_cred
, groups
, (int)ngroups
, gmuid
);
1190 if (new_cred
!= my_cred
) {
1191 persona
->pna_cred
= new_cred
;
1193 kauth_cred_unref(&my_cred
);
1196 persona_unlock(persona
);
1201 persona_get_groups(struct persona
*persona
, unsigned *ngroups
, gid_t
*groups
, unsigned groups_sz
)
1204 if (!persona
|| !persona
->pna_cred
|| !groups
|| !ngroups
|| groups_sz
> NGROUPS
) {
1208 *ngroups
= groups_sz
;
1210 persona_lock(persona
);
1211 if (persona_valid(persona
)) {
1212 int kauth_ngroups
= (int)groups_sz
;
1213 kauth_cred_getgroups(persona
->pna_cred
, groups
, &kauth_ngroups
);
1214 *ngroups
= (unsigned)kauth_ngroups
;
1217 persona_unlock(persona
);
1223 persona_get_gmuid(struct persona
*persona
)
1225 uid_t gmuid
= KAUTH_UID_NONE
;
1227 if (!persona
|| !persona
->pna_cred
) {
1231 persona_lock(persona
);
1232 if (!persona_valid(persona
)) {
1236 posix_cred_t pcred
= posix_cred_get(persona
->pna_cred
);
1237 gmuid
= pcred
->cr_gmuid
;
1240 persona_unlock(persona
);
1245 persona_get_login(struct persona
*persona
, char login
[MAXLOGNAME
+ 1])
1248 if (!persona
|| !persona
->pna_cred
) {
1252 persona_lock(persona
);
1253 if (!persona_valid(persona
)) {
1257 strlcpy(login
, persona
->pna_login
, MAXLOGNAME
);
1261 persona_unlock(persona
);
1262 login
[MAXLOGNAME
] = 0;
1267 #else /* !CONFIG_PERSONAS */
1270 * symbol exports for kext compatibility
1274 persona_get_id(__unused
struct persona
*persona
)
1276 return PERSONA_ID_NONE
;
1280 persona_get_type(__unused
struct persona
*persona
)
1282 return PERSONA_INVALID
;
1286 persona_get_cred(__unused
struct persona
*persona
)
1292 persona_lookup(__unused uid_t id
)
1298 persona_find(__unused
const char *login
,
1300 __unused
struct persona
**persona
,
1301 __unused
size_t *plen
)
1307 current_persona_get(void)
1313 persona_get(struct persona
*persona
)
1319 persona_put(__unused
struct persona
*persona
)