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 static struct persona
*persona_get_locked(struct persona
*persona
)
289 if (persona
->pna_refcount
) {
290 persona
->pna_refcount
++;
296 struct persona
*persona_get(struct persona
*persona
)
301 persona_lock(persona
);
302 ret
= persona_get_locked(persona
);
303 persona_unlock(persona
);
308 void persona_put(struct persona
*persona
)
315 persona_lock(persona
);
316 if (persona
->pna_refcount
>= 0) {
317 if (--(persona
->pna_refcount
) == 0)
320 persona_unlock(persona
);
325 persona_dbg("Destroying persona %s", persona_desc(persona
, 0));
327 /* release our credential reference */
328 if (persona
->pna_cred
)
329 kauth_cred_unref(&persona
->pna_cred
);
331 /* remove it from the global list and decrement the count */
333 persona_lock(persona
);
334 if (persona_valid(persona
)) {
335 LIST_REMOVE(persona
, pna_list
);
336 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
)
337 panic("persona count underflow!\n");
338 persona_mkinvalid(persona
);
340 persona_unlock(persona
);
343 assert(LIST_EMPTY(&persona
->pna_members
));
344 memset(persona
, 0, sizeof(*persona
));
345 zfree(persona_zone
, persona
);
348 uid_t
persona_get_id(struct persona
*persona
)
351 return persona
->pna_id
;
352 return PERSONA_ID_NONE
;
355 struct persona
*persona_lookup(uid_t id
)
357 struct persona
*persona
, *tmp
;
362 * simple, linear lookup for now: there shouldn't be too many
363 * of these in memory at any given time.
366 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
368 if (tmp
->pna_id
== id
&& persona_valid(tmp
)) {
369 persona
= persona_get_locked(tmp
);
380 struct persona
*persona_lookup_and_invalidate(uid_t id
)
382 struct persona
*persona
, *entry
, *tmp
;
387 LIST_FOREACH_SAFE(entry
, &all_personas
, pna_list
, tmp
) {
389 if (entry
->pna_id
== id
) {
390 if (persona_valid(entry
)) {
391 persona
= persona_get_locked(entry
);
392 assert(persona
!= NULL
);
393 LIST_REMOVE(persona
, pna_list
);
394 if (hw_atomic_add(&g_total_personas
, -1) == UINT_MAX
)
395 panic("persona ref count underflow!\n");
396 persona_mkinvalid(persona
);
398 persona_unlock(entry
);
401 persona_unlock(entry
);
408 int persona_find(const char *login
, uid_t uid
,
409 struct persona
**persona
, size_t *plen
)
417 if (uid
!= PERSONA_ID_NONE
)
423 persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
427 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
430 if (login
&& strncmp(tmp
->pna_login
, login
, sizeof(tmp
->pna_login
)) == 0)
432 if (uid
!= PERSONA_ID_NONE
&& uid
== tmp
->pna_id
)
435 if (persona
&& *plen
> found
)
436 persona
[found
] = persona_get_locked(tmp
);
441 persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
442 tmp
->pna_id
, m
, match
, (int)found
, (int)*plen
);
454 struct persona
*persona_proc_get(pid_t pid
)
456 struct persona
*persona
;
457 proc_t p
= proc_find(pid
);
463 persona
= persona_get(p
->p_persona
);
471 struct persona
*current_persona_get(void)
473 proc_t p
= current_proc();
474 struct persona
*persona
;
477 persona
= persona_get(p
->p_persona
);
484 * inherit a persona from parent to child
486 int persona_proc_inherit(proc_t child
, proc_t parent
)
488 if (child
->p_persona
!= NULL
) {
489 persona_dbg("proc_inherit: child already in persona: %s",
490 persona_desc(child
->p_persona
, 0));
494 /* no persona to inherit */
495 if (parent
->p_persona
== NULL
)
498 return persona_proc_adopt(child
, parent
->p_persona
, parent
->p_ucred
);
501 int persona_proc_adopt_id(proc_t p
, uid_t id
, kauth_cred_t auth_override
)
504 struct persona
*persona
;
506 persona
= persona_lookup(id
);
510 ret
= persona_proc_adopt(p
, persona
, auth_override
);
512 /* put the reference from the lookup() */
513 persona_put(persona
);
519 typedef enum e_persona_reset_op
{
520 PROC_REMOVE_PERSONA
= 1,
521 PROC_RESET_OLD_PERSONA
= 2,
522 } persona_reset_op_t
;
525 * internal cleanup routine for proc_set_cred_internal
528 static struct persona
*proc_reset_persona_internal(proc_t p
, persona_reset_op_t op
,
529 struct persona
*old_persona
,
530 struct persona
*new_persona
)
532 #if (DEVELOPMENT || DEBUG)
533 persona_lock_assert_held(new_persona
);
537 case PROC_REMOVE_PERSONA
:
538 old_persona
= p
->p_persona
;
540 case PROC_RESET_OLD_PERSONA
:
543 /* invalid arguments */
547 /* unlock the new persona (locked on entry) */
548 persona_unlock(new_persona
);
549 /* lock the old persona and the process */
550 persona_lock(old_persona
);
554 case PROC_REMOVE_PERSONA
:
555 LIST_REMOVE(p
, p_persona_list
);
558 case PROC_RESET_OLD_PERSONA
:
559 p
->p_persona
= old_persona
;
560 LIST_INSERT_HEAD(&old_persona
->pna_members
, p
, p_persona_list
);
565 persona_unlock(old_persona
);
567 /* re-lock the new persona */
568 persona_lock(new_persona
);
573 * Assumes persona is locked.
574 * On success, takes a reference to 'persona' and returns the
575 * previous persona the process had adopted. The caller is
576 * responsible to release the reference.
578 static struct persona
*proc_set_cred_internal(proc_t p
, struct persona
*persona
,
579 kauth_cred_t auth_override
, int *rlim_error
)
581 struct persona
*old_persona
= NULL
;
582 kauth_cred_t my_cred
, my_new_cred
;
583 uid_t old_uid
, new_uid
;
587 * This operation must be done under the proc trans lock
588 * by the thread which took the trans lock!
590 assert(((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) &&
591 p
->p_transholder
== current_thread());
592 assert(persona
!= NULL
);
594 /* no work to do if we "re-adopt" the same persona */
595 if (p
->p_persona
== persona
)
599 * If p is in a persona, then we need to remove 'p' from the list of
600 * processes in that persona. To do this, we need to drop the lock
601 * held on the incoming (new) persona and lock the old one.
604 old_persona
= proc_reset_persona_internal(p
, PROC_REMOVE_PERSONA
,
609 my_new_cred
= auth_override
;
611 my_new_cred
= persona
->pna_cred
;
614 panic("NULL credentials (persona:%p)", persona
);
618 kauth_cred_ref(my_new_cred
);
620 new_uid
= persona
->pna_id
;
623 * Check to see if we will hit a proc rlimit by moving the process
624 * into the persona. If so, we'll bail early before actually moving
625 * the process or changing its credentials.
628 (rlim_t
)chgproccnt(new_uid
, 0) > p
->p_rlimit
[RLIMIT_NPROC
].rlim_cur
) {
629 pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
630 p
->p_pid
, new_uid
, persona_desc(persona
, 1));
631 *rlim_error
= EACCES
;
632 (void)proc_reset_persona_internal(p
, PROC_RESET_OLD_PERSONA
,
633 old_persona
, persona
);
634 kauth_cred_unref(&my_new_cred
);
639 * Set the new credentials on the proc
642 my_cred
= kauth_cred_proc_ref(p
);
643 persona_dbg("proc_adopt PID:%d, %s -> %s",
645 persona_desc(old_persona
, 1),
646 persona_desc(persona
, 1));
648 old_uid
= kauth_cred_getruid(my_cred
);
650 if (my_cred
!= my_new_cred
) {
651 kauth_cred_t old_cred
= my_cred
;
655 * We need to protect against a race where another thread
656 * also changed the credential after we took our
657 * reference. If p_ucred has changed then we should
658 * restart this again with the new cred.
660 if (p
->p_ucred
!= my_cred
) {
661 proc_ucred_unlock(p
);
662 kauth_cred_unref(&my_cred
);
667 /* update the credential and take a ref for the proc */
668 kauth_cred_ref(my_new_cred
);
669 p
->p_ucred
= my_new_cred
;
671 /* update cred on proc (and current thread) */
672 mach_kauth_cred_uthread_update();
673 PROC_UPDATE_CREDS_ONPROC(p
);
675 /* drop the proc's old ref on the credential */
676 kauth_cred_unref(&old_cred
);
677 proc_ucred_unlock(p
);
680 /* drop this function's reference to the old cred */
681 kauth_cred_unref(&my_cred
);
684 * Update the proc count.
685 * If the UIDs are the same, then there is no work to do.
688 old_uid
= old_persona
->pna_id
;
690 if (new_uid
!= old_uid
) {
691 count
= chgproccnt(old_uid
, -1);
692 persona_dbg("Decrement %s:%d proc_count to: %d",
693 old_persona
? "Persona" : "UID", old_uid
, count
);
696 * Increment the proc count on the UID associated with
697 * the new persona. Enforce the resource limit just
700 count
= chgproccnt(new_uid
, 1);
701 persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %d",
702 new_uid
, kauth_cred_getuid(my_new_cred
), count
);
705 OSBitOrAtomic(P_ADOPTPERSONA
, &p
->p_flag
);
708 p
->p_persona
= persona_get_locked(persona
);
709 LIST_INSERT_HEAD(&persona
->pna_members
, p
, p_persona_list
);
712 kauth_cred_unref(&my_new_cred
);
717 int persona_proc_adopt(proc_t p
, struct persona
*persona
, kauth_cred_t auth_override
)
720 struct persona
*old_persona
;
721 struct session
* sessp
;
726 persona_dbg("%d adopting Persona %d (%s)", proc_pid(p
),
727 persona
->pna_id
, persona_desc(persona
, 0));
729 persona_lock(persona
);
730 if (!persona
->pna_cred
|| !persona_valid(persona
)) {
731 persona_dbg("Invalid persona (%s): NULL credentials!", persona_desc(persona
, 1));
732 persona_unlock(persona
);
736 /* the persona credentials can no longer be adjusted */
737 persona
->pna_cred_locked
= 1;
740 * assume the persona: this may drop and re-acquire the persona lock!
743 old_persona
= proc_set_cred_internal(p
, persona
, auth_override
, &error
);
745 /* join the process group associated with the persona */
746 if (persona
->pna_pgid
) {
747 uid_t uid
= kauth_cred_getuid(persona
->pna_cred
);
748 persona_dbg(" PID:%d, pgid:%d%s",
749 p
->p_pid
, persona
->pna_pgid
,
750 persona
->pna_pgid
== uid
? ", new_session" : ".");
751 enterpgrp(p
, persona
->pna_pgid
, persona
->pna_pgid
== uid
);
754 /* set the login name of the session */
755 sessp
= proc_session(p
);
756 if (sessp
!= SESSION_NULL
) {
758 bcopy(persona
->pna_login
, sessp
->s_login
, MAXLOGNAME
);
759 session_unlock(sessp
);
763 persona_unlock(persona
);
765 set_security_token(p
);
768 * Drop the reference to the old persona.
771 persona_put(old_persona
);
773 persona_dbg("%s", error
== 0 ? "SUCCESS" : "FAILED");
777 int persona_proc_drop(proc_t p
)
779 struct persona
*persona
= NULL
;
781 persona_dbg("PID:%d, %s -> <none>", p
->p_pid
, persona_desc(p
->p_persona
, 0));
784 * There are really no other credentials for us to assume,
785 * so we'll just continue running with the credentials
786 * we got from the persona.
790 * the locks must be taken in reverse order here, so
791 * we have to be careful not to cause deadlock
797 if (!persona_try_lock(p
->p_persona
)) {
799 mutex_pause(0); /* back-off time */
802 persona
= p
->p_persona
;
803 LIST_REMOVE(p
, p_persona_list
);
806 ruid
= kauth_cred_getruid(p
->p_ucred
);
807 puid
= kauth_cred_getuid(persona
->pna_cred
);
809 (void)chgproccnt(ruid
, 1);
810 (void)chgproccnt(puid
, -1);
816 * if the proc had a persona, then it is still locked here
817 * (preserving proper lock ordering)
821 persona_unlock(persona
);
822 persona_put(persona
);
828 int persona_get_type(struct persona
*persona
)
833 return PERSONA_INVALID
;
835 persona_lock(persona
);
836 if (!persona_valid(persona
)) {
837 persona_unlock(persona
);
838 return PERSONA_INVALID
;
840 type
= persona
->pna_type
;
841 persona_unlock(persona
);
846 int persona_set_cred(struct persona
*persona
, kauth_cred_t cred
)
849 kauth_cred_t my_cred
;
850 if (!persona
|| !cred
)
853 persona_lock(persona
);
854 if (!persona_valid(persona
)) {
858 if (persona
->pna_cred_locked
) {
863 /* create a new cred from the passed-in cred */
864 my_cred
= kauth_cred_create(cred
);
866 /* ensure that the UID matches the persona ID */
867 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
868 persona
->pna_id
, persona
->pna_id
,
871 /* TODO: clear the saved GID?! */
873 /* replace the persona's cred with the new one */
874 if (persona
->pna_cred
)
875 kauth_cred_unref(&persona
->pna_cred
);
876 persona
->pna_cred
= my_cred
;
879 persona_unlock(persona
);
883 int persona_set_cred_from_proc(struct persona
*persona
, proc_t proc
)
886 kauth_cred_t parent_cred
, my_cred
;
887 if (!persona
|| !proc
)
890 persona_lock(persona
);
891 if (!persona_valid(persona
)) {
895 if (persona
->pna_cred_locked
) {
900 parent_cred
= kauth_cred_proc_ref(proc
);
902 /* TODO: clear the saved UID/GID! */
904 /* create a new cred from the proc's cred */
905 my_cred
= kauth_cred_create(parent_cred
);
907 /* ensure that the UID matches the persona ID */
908 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
909 persona
->pna_id
, persona
->pna_id
,
912 /* replace the persona's cred with the new one */
913 if (persona
->pna_cred
)
914 kauth_cred_unref(&persona
->pna_cred
);
915 persona
->pna_cred
= my_cred
;
917 kauth_cred_unref(&parent_cred
);
920 persona_unlock(persona
);
924 kauth_cred_t
persona_get_cred(struct persona
*persona
)
926 kauth_cred_t cred
= NULL
;
931 persona_lock(persona
);
932 if (!persona_valid(persona
))
935 if (persona
->pna_cred
) {
936 kauth_cred_ref(persona
->pna_cred
);
937 cred
= persona
->pna_cred
;
941 persona_unlock(persona
);
946 uid_t
persona_get_uid(struct persona
*persona
)
950 if (!persona
|| !persona
->pna_cred
)
953 persona_lock(persona
);
954 if (persona_valid(persona
)) {
955 uid
= kauth_cred_getuid(persona
->pna_cred
);
956 assert(uid
== persona
->pna_id
);
958 persona_unlock(persona
);
963 int persona_set_gid(struct persona
*persona
, gid_t gid
)
966 kauth_cred_t my_cred
, new_cred
;
968 if (!persona
|| !persona
->pna_cred
)
971 persona_lock(persona
);
972 if (!persona_valid(persona
)) {
976 if (persona
->pna_cred_locked
) {
981 my_cred
= persona
->pna_cred
;
982 kauth_cred_ref(my_cred
);
983 new_cred
= kauth_cred_setresgid(my_cred
, gid
, gid
, gid
);
984 if (new_cred
!= my_cred
)
985 persona
->pna_cred
= new_cred
;
986 kauth_cred_unref(&my_cred
);
989 persona_unlock(persona
);
993 gid_t
persona_get_gid(struct persona
*persona
)
997 if (!persona
|| !persona
->pna_cred
)
1000 persona_lock(persona
);
1001 if (persona_valid(persona
))
1002 gid
= kauth_cred_getgid(persona
->pna_cred
);
1003 persona_unlock(persona
);
1008 int persona_set_groups(struct persona
*persona
, gid_t
*groups
, unsigned ngroups
, uid_t gmuid
)
1011 kauth_cred_t my_cred
, new_cred
;
1013 if (!persona
|| !persona
->pna_cred
)
1015 if (ngroups
> NGROUPS_MAX
)
1018 persona_lock(persona
);
1019 if (!persona_valid(persona
)) {
1023 if (persona
->pna_cred_locked
) {
1028 my_cred
= persona
->pna_cred
;
1029 kauth_cred_ref(my_cred
);
1030 new_cred
= kauth_cred_setgroups(my_cred
, groups
, (int)ngroups
, gmuid
);
1031 if (new_cred
!= my_cred
)
1032 persona
->pna_cred
= new_cred
;
1033 kauth_cred_unref(&my_cred
);
1036 persona_unlock(persona
);
1040 int persona_get_groups(struct persona
*persona
, unsigned *ngroups
, gid_t
*groups
, unsigned groups_sz
)
1043 if (!persona
|| !persona
->pna_cred
|| !groups
|| !ngroups
|| groups_sz
> NGROUPS
)
1046 *ngroups
= groups_sz
;
1048 persona_lock(persona
);
1049 if (persona_valid(persona
)) {
1050 int kauth_ngroups
= (int)groups_sz
;
1051 kauth_cred_getgroups(persona
->pna_cred
, groups
, &kauth_ngroups
);
1052 *ngroups
= (unsigned)kauth_ngroups
;
1055 persona_unlock(persona
);
1060 uid_t
persona_get_gmuid(struct persona
*persona
)
1062 uid_t gmuid
= KAUTH_UID_NONE
;
1064 if (!persona
|| !persona
->pna_cred
)
1067 persona_lock(persona
);
1068 if (!persona_valid(persona
))
1071 posix_cred_t pcred
= posix_cred_get(persona
->pna_cred
);
1072 gmuid
= pcred
->cr_gmuid
;
1075 persona_unlock(persona
);
1079 int persona_get_login(struct persona
*persona
, char login
[MAXLOGNAME
+1])
1082 if (!persona
|| !persona
->pna_cred
)
1085 persona_lock(persona
);
1086 if (!persona_valid(persona
))
1089 strlcpy(login
, persona
->pna_login
, MAXLOGNAME
);
1093 persona_unlock(persona
);
1094 login
[MAXLOGNAME
] = 0;
1099 #else /* !CONFIG_PERSONAS */
1102 * symbol exports for kext compatibility
1105 uid_t
persona_get_id(__unused
struct persona
*persona
)
1107 return PERSONA_ID_NONE
;
1110 int persona_get_type(__unused
struct persona
*persona
)
1112 return PERSONA_INVALID
;
1115 kauth_cred_t
persona_get_cred(__unused
struct persona
*persona
)
1120 struct persona
*persona_lookup(__unused uid_t id
)
1125 int persona_find(__unused
const char *login
,
1127 __unused
struct persona
**persona
,
1128 __unused
size_t *plen
)
1133 struct persona
*current_persona_get(void)
1138 struct persona
*persona_get(struct persona
*persona
)
1143 void persona_put(__unused
struct persona
*persona
)